Compare commits

...
Author SHA1 Message Date
Brody Bassett 571f84b6e7 Formatting. 2023-08-01 03:00:30 -07:00
Brody Bassett c35a4d36b0 Formatting. 2023-08-01 02:56:15 -07:00
Brody Bassett 0484571327 Formatting. 2023-08-01 02:53:31 -07:00
Brody Bassett 4c38e5a8fa Added rk examples to sample runs. 2023-08-01 02:45:08 -07:00
Brody Bassett 1a1ac1f2c2 Formatting. 2023-07-26 13:45:59 -07:00
Brody Bassett 228e84afa7 Split lines for doxygen. 2023-07-26 13:45:37 -07:00
Brody Bassett 61afeac61a Removed unused function. 2023-07-26 13:36:12 -07:00
Brody Bassett e59d31c5b1 Renamed class. 2023-07-26 13:31:40 -07:00
Brody Bassett c2b9e59f56 Updated comment. 2023-07-18 17:21:51 -07:00
Brody Bassett da82f2734e Added comments to distance. 2023-07-18 17:20:34 -07:00
Brody Bassett 445bb8e040 More comments. 2023-07-18 17:12:56 -07:00
Brody Bassett 93d3fb1a81 Added comment on point selection. 2023-07-18 17:04:29 -07:00
Brody Bassett 7cf414c969 Added comment. 2023-07-18 16:52:30 -07:00
Brody Bassett 5c595b3163 Removed superfluous comments. 2023-07-18 16:49:07 -07:00
Brody Bassett 156953730e Removed stray character. 2023-07-18 16:47:51 -07:00
Brody Bassett 9fc6ba9a02 Converted comments to doxygen. Renamed class. 2023-07-18 16:44:11 -07:00
Brody Bassett 4950a75cfa Merge branch 'master' into meshless-kernels 2023-07-18 16:10:55 -07:00
Tzanio Kolev f97a770dca Merge pull request #3217 from mfem/mesh-group-doc-dev
Grouping Mesh methods in Doxygen [mesh-group-doc-dev]
2023-07-18 12:01:18 -07:00
Tzanio Kolev 4ebb2298a3 Merge pull request #3776 from adam-sim-dev/pardiso-cmake-fix
Bug fix #cmakedefine for MFEM_USE_MKL_PARDISO
2023-07-18 11:43:16 -07:00
Veselin Dobrev dc99d97956 Merge pull request #3596 from mfem/sundials-hip
Add HIP support to SUNDIALS interface [sundials-hip]
2023-07-18 10:28:30 -07:00
adam-sim-dev a56964a553 Fix 2023-07-15 08:37:13 +08:00
adam-sim-dev 6b1c2c5f61 Bug fix #cmakedefine for MFEM_USE_MKL_PARDISO 2023-07-12 08:10:16 +08:00
Tzanio Kolev 6dde5832bc Merge pull request #3771 from mfem/getnode-host-pointer-bugfix
Fix invalid host pointer access error in GetNode
2023-07-11 15:30:48 -07:00
Brody Bassett 56b622a9a3 Update CHANGELOG. 2023-07-10 13:10:38 -07:00
Brody Bassett 4bcbddbf93 Added comments. 2023-07-10 12:52:51 -07:00
Brody Bassett ef670c8ba5 Reverted formatting. 2023-07-10 12:36:11 -07:00
Tzanio Kolev 38eeefb208 Merge pull request #3615 from adam-sim-dev/pardiso
Add Pardiso solver for SparseMatrix
2023-07-10 11:36:39 -07:00
Tzanio Kolev acd3ad1bfd Update CHANGELOG 2023-07-10 11:34:54 -07:00
Tzanio Kolev 5d39bbf1bd Merge pull request #3761 from mfem/sjg/missing-fo-fix
Fix missing `bdr_elem_fos` from  #1046
2023-07-09 15:08:44 -07:00
Tzanio Kolev a80e5a4890 Merge pull request #3764 from mfem/sjg/dof-to-quad-fixes
Fix some minor issues with GetDofToQuad for non-tensor elements
2023-07-09 15:08:15 -07:00
adam-sim-dev 3fece373b4 Set height and width 2023-07-08 06:51:06 +08:00
adam-sim-dev 3613ef6fb8 Merge branch 'master' into pardiso 2023-07-07 09:06:31 +08:00
Tom Stitt ec9fe97b5a cleaner impl 2023-07-06 12:40:03 -07:00
Tom Stitt b5a7f4f05a fix invalid host pointer access when using gpus 2023-07-06 11:53:56 -07:00
Tzanio Kolev 75d9ac4364 Merge pull request #3747 from mfem/par-restriction-mpi-hang
Fix MPI hanging in ParL2FaceRestriction::Mult
2023-07-05 09:02:44 -07:00
Tzanio Kolev a5fcdf093e Merge pull request #3750 from mfem/gslib-shadow-var
gslib shadow vars fix
2023-07-05 08:06:34 -07:00
adam-sim-dev 90ff193041 Mention PARDISO in CHANGELOG 2023-07-04 08:20:30 +08:00
adam-sim-dev 63f577af09 Remove expensive mat->IsSymmetric() check 2023-07-01 08:33:53 +08:00
Socratis Petrides 31c7a8d183 Merge branch 'master' into gslib-shadow-var 2023-06-30 12:50:47 -07:00
Socratis Petrides f60272ab0b more shadow var 2023-06-30 12:50:06 -07:00
adam-sim-dev 027bd31e46 Merge branch 'master' into pardiso 2023-06-30 11:00:13 +08:00
Tzanio Kolev f3a5836737 Merge pull request #3668 from mfem/tmop-integr-ref
TMOP - option for integrating over reference element
2023-06-29 15:54:02 -07:00
Tzanio Kolev fa2e90df2c Merge pull request #3539 from mfem/pa-mass-boundary-integ
PA for mass boundary integrator
2023-06-29 15:52:40 -07:00
Sebastian Grimberg 63ada97f64 Fix some minor issues with GetDofToQuad for non-tensor elements 2023-06-29 09:39:01 -07:00
Sebastian Grimberg 645260f2cc Fix missing bdr_elem_fos construction in BuildBdrElementToDofTable, similar to elem_fos in BuildElementToDofTable 2023-06-28 16:28:58 -07:00
Vladimir Z Tomov 70c3ecccc2 Merge branch 'master' into tmop-integr-ref 2023-06-27 11:33:16 -07:00
adam-sim-dev 991445604d Merge branch 'master' into pardiso 2023-06-27 13:30:25 +08:00
Veselin Dobrev 4204030251 Copy updates from examples/ex9p to the SUNDIALS version.
Small formatting changes.
2023-06-26 17:58:49 -07:00
Veselin Dobrev 2fafbbb2ef Merge pull request #3588 from mfem/pgridfunc-save-serial
Save a ParGridFunction in Serial
2023-06-26 15:11:36 -07:00
Will Pazner 4438077f65 Move 1D mass kernels into bilininteg_mass_kernels.cpp 2023-06-26 14:56:48 -07:00
Will Pazner 282c65869c Handle git status letters RM in branch-history 2023-06-26 13:10:17 -07:00
Will Pazner bc87b453fa Merge remote-tracking branch 'origin/master' into pa-mass-boundary-integ
# Conflicts:
#	fem/bilininteg_mass_pa.cpp
#	fem/integ/bilininteg_mass_kernels.hpp
2023-06-26 12:27:44 -07:00
Will Pazner 6470d3a7b2 Merge pull request #3526 from mfem/sjg/integs-reorg-dev
Reorganize integrator functionality in `fem/`
2023-06-26 12:12:28 -07:00
adam-sim-dev 7a24749104 Merge branch 'master' into pardiso 2023-06-25 08:29:11 +08:00
Tzanio Kolev 9cf7443241 Merge branch 'master' into meshless-kernels 2023-06-24 14:43:52 -07:00
Tzanio Kolev 784102ad13 Merge pull request #3718 from mfem/nc-mesh-explorer-dev
Adding random refinement option to mesh-explorer
2023-06-24 14:40:50 -07:00
Tzanio Kolev 24c7a06009 Fix CHANGELOG 2023-06-24 14:38:59 -07:00
Tzanio Kolev 0722214d49 Merge pull request #3735 from mfem/gslib-bug-fix-fieldinterp
Fix bug in field-interp miniapp and CMake build for findpts miniapp
2023-06-24 14:34:29 -07:00
Veselin Dobrev 8c93cb4947 Fix a bug affecting the general case when D1D != D1Dtest in
PAHcurlHdivApply3D and PAHcurlHdivApplyTranspose3D.
2023-06-23 12:21:32 -07:00
Tzanio Kolev b511127230 Merge branch 'master' into sundials-hip 2023-06-23 08:07:00 -07:00
adam-sim-dev 4e6cce9eaf Merge branch 'master' into pardiso 2023-06-23 21:27:05 +08:00
adam-sim-dev 87799f6b27 Remove MKL_MPI_WRAPPER for Pardiso 2023-06-23 20:56:45 +08:00
adam-sim-dev 55ea348f83 Fix unit test 2023-06-23 20:38:33 +08:00
adam-sim-dev 33dcd3aa07 Add Pardiso dependency to CMakeLists.txt 2023-06-23 20:38:23 +08:00
Socratis Petrides fc47e8ab1e shadow var fix 2023-06-22 12:18:25 -07:00
Will Pazner c43bc50437 Merge pull request #3745 from mfem/integs-reorg-tweaks
Some tweaks for the integrators reorg branch
2023-06-22 11:48:30 -07:00
Tzanio Kolev 19c16996d5 Merge pull request #3749 from mfem/sjg/minor-master-fix
Hotfix for bug introduced by #3065
2023-06-22 11:11:14 -07:00
Sebastian Grimberg ad1b8332ac Minor fix for bug introduced by #3065 2023-06-22 11:04:05 -07:00
Tzanio Kolev ac72adc159 Merge pull request #3065 from mfem/material-miniapp
Add mini app for the SPDE method
2023-06-22 10:23:10 -07:00
Sebastian Grimberg eac6b36d04 Further style consistency cleanup 2023-06-22 10:22:03 -07:00
Sebastian Grimberg d9965bf69a Fix apparent bug in PAHcurlHdivApplyTranspose3D 2023-06-22 10:22:03 -07:00
Sebastian Grimberg d990a2569c Consistency in template functions for PA assembly and application
Also some renaming consistency: PAHcurlHdivApply3DTranspose -> PAHcurlHdivApplyTranspose3D.
2023-06-22 10:22:00 -07:00
Tzanio Kolev ba045d2b5e Final fixes 2023-06-22 10:20:31 -07:00
Tzanio Kolev 278fc8b950 Merge branch 'master' into pardiso 2023-06-22 09:17:42 -07:00
Socratis Petrides 4057f24d6a remove duplicated line 2023-06-22 08:58:27 -07:00
Tzanio Kolev 3b240fb67a Merge pull request #3082 from mfem/sjg/mumps-solver-dev
Update MUMPS solver interface
2023-06-22 08:17:41 -07:00
Tzanio Kolev 7264045484 CHANGELOG styling 2023-06-22 08:15:57 -07:00
Tzanio Kolev a60fe54af6 Merge pull request #3728 from mfem/coord-coef-dev
Coordinate Coefficient classes [coord-coef-dev]
2023-06-22 08:12:14 -07:00
adam-sim-dev f5fd2f4d06 Fix the conflicts 2023-06-22 12:07:57 +08:00
adam-sim-dev 43cddedbf1 Fix the conflicts 2023-06-22 12:04:43 +08:00
adam-sim-dev 0e00f28b38 Fix the conflicts 2023-06-22 12:03:27 +08:00
adam-sim-dev b61be84835 Fix the conflicts and add the unit test for PardisoSolver 2023-06-22 12:00:55 +08:00
Will Pazner c4d48bf4e8 Only communicate in ParL2FaceRestriction::DoubleValuedConformingMult when type == FaceType::Interior 2023-06-21 20:20:12 -07:00
adam-sim-dev 0ade925463 Set default msglvl to 0 2023-06-22 11:15:52 +08:00
Will Pazner 80d62a5b13 Bug fix: MPI communication can hang in ParL2FaceRestriction::Mult
An early return when some ranks contain no boundary faces means that
some ranks call ParGridFunction::ExchangeFaceNbrData, but others do not.
This can cause the MPI communication to hang: all MPI ranks need to
participate in the MPI communication.
2023-06-21 20:14:18 -07:00
adam-sim-dev 7d447427cd Include pardiso header in linalg.hpp 2023-06-22 11:08:03 +08:00
adam-sim-dev 199eddd763 Merge branch 'master' into pardiso 2023-06-22 10:49:59 +08:00
adam-sim-dev 7babd6c8a4 Add unit test for PardisoSolver 2023-06-22 10:47:09 +08:00
Veselin Dobrev 7493329420 Various tweaks for PR #3526 2023-06-21 13:24:18 -07:00
Sebastian Grimberg fa5a778ecb Minor test formatting 2023-06-21 12:05:55 -07:00
Sebastian Grimberg da24b5b53b Merge branch 'master' into sjg/mumps-solver-dev 2023-06-21 12:04:14 -07:00
Will Pazner 553dc3109f Merge pull request #3083 from mfem/sjg/superlu-solver-dev
Update SuperLU_DIST solver interface
2023-06-21 12:02:07 -07:00
Sebastian Grimberg edcf6b4205 Fix bug with SuperLU_DIST built using Intel compilers where aligned malloc/calloc are used and thus alligned free should also be used (not compatible with Hypre) 2023-06-19 10:35:46 -07:00
adam-sim-dev cb9636b5b3 Merge branch 'master' into sjg/mumps-solver-dev 2023-06-18 20:11:47 +08:00
adam-sim-dev f1e3af988b Merge branch 'master' into pardiso 2023-06-18 20:10:25 +08:00
Veselin Dobrev 7ca6d4e124 Merge pull request #3679 from mfem/artv3/host_read_s_volume_dof
add missing host read in fem/restriction.cpp
2023-06-17 20:49:53 -07:00
Sebastian Grimberg b2ad17aeaa Merge branch 'master' into sjg/integs-reorg-dev 2023-06-15 17:54:57 -07:00
Mittal, Ketan 08a4f0e623 bugfix 2023-06-15 17:40:03 -07:00
Will Pazner cad9a41262 Fix undefined variable error in Serial Direct Solvers unit test 2023-06-15 11:30:44 -07:00
adam-sim-dev 480caae04b Merge branch 'master' into sjg/mumps-solver-dev 2023-06-15 21:23:13 +08:00
Socratis Petrides b62d3d8f5a conflicts with master 2023-06-14 17:45:31 -07:00
Socratis Petrides 1b2b5e202a renaming pml for doc issues 2023-06-14 17:41:06 -07:00
Tzanio Kolev 2c1d29e04a Merge branch 'master' into nc-mesh-explorer-dev 2023-06-14 09:45:29 -07:00
Tzanio Kolev c13673952f Merge pull request #3437 from mfem/hdiv-solvers-miniapp
H(div) saddle-point solvers
2023-06-14 09:38:31 -07:00
adam-sim-dev ec4f1a0213 Merge branch 'master' into pardiso 2023-06-14 21:23:33 +08:00
Stowell, Mark L 8341b50c1d Adding spherical coordinate coefficients 2023-06-13 16:46:31 -07:00
Stowell, Mark L 961ddd2e85 Adding cylindrical coordinate coefficients 2023-06-13 16:46:07 -07:00
Stowell, Mark L c8c60dc443 Adding Cartesian component coefficients 2023-06-13 16:45:26 -07:00
Stowell, Mark L 4614e6f8e0 Adding PositionVectorCoefficient 2023-06-13 16:44:24 -07:00
Will Pazner 67463f461c Update CHANGELOG 2023-06-13 16:25:15 -07:00
Will Pazner 071dd4ad68 Merge pull request #3699 from mfem/sjg/hypre-blocks-fix
Allow `HypreParMatrixFromBlocks` with empty local `HypreParMatrix` blocks
2023-06-13 16:20:28 -07:00
Sebastian Grimberg 32f9c069f7 Bug fix for SuperLU_DIST + CUDA 2023-06-13 15:50:34 -07:00
Christopher vogl 7ad4364b7b added ParGridFunjction in Serial test to CMake 2023-06-13 13:06:27 -07:00
Christopher vogl e473491d06 added call to ParGridFunction::SaveAsSerial from ParGridFunjction in Serial test 2023-06-13 13:05:52 -07:00
Sebastian Grimberg 244bf25243 Update changelog 2023-06-13 09:35:20 -07:00
Mittal, Ketan 28e8f2e820 update gitignore 2023-06-13 08:43:50 -07:00
Tzanio Kolev 0d7d017414 Merge pull request #3696 from barracuda156/ppc
Fix-ups for PowerPC and macOS
2023-06-13 07:43:47 -07:00
Tzanio Kolev 17be0222bd Merge pull request #3238 from mfem/fix-kv-difference-dev
Fix bug in comparing two doubles in knotvector comparison [fix-kv-difference-dev]
2023-06-13 07:43:23 -07:00
Mittal, Ketan 3fe1c20ac0 update unit test to save and load the gridfunction 2023-06-12 20:46:30 -07:00
Stowell, Mark L 92411eb272 Merge remote-tracking branch 'origin/master' into mesh-group-doc-dev
# Conflicts:
#	mesh/mesh.hpp
2023-06-12 10:22:45 -07:00
adam-sim-dev 945fa71e22 Merge branch 'master' into pardiso 2023-06-12 08:20:10 +08:00
Tzanio Kolev c3355ed849 Merge branch 'master' into ppc 2023-06-11 15:21:44 -07:00
Tzanio Kolev addac43e0b Merge branch 'master' into sjg/mumps-solver-dev 2023-06-11 15:10:09 -07:00
Tzanio Kolev 10cbaa95e2 Merge branch 'master' into hdiv-solvers-miniapp 2023-06-11 14:58:53 -07:00
Tzanio Kolev 8a76c6686a Merge pull request #3434 from mfem/tmopupdate-geomparam
Measuring mesh quality using geometric parameters used in TMOP
2023-06-11 14:58:03 -07:00
Tzanio Kolev 4063ca962e Small adjustments 2023-06-11 14:54:19 -07:00
Tzanio Kolev 2bbd369771 Merge branch 'master' into tmopupdate-geomparam 2023-06-11 14:36:47 -07:00
Stowell, Mark L 859490cab2 Adding CHANGELOG entry 2023-06-09 11:01:46 -07:00
Stowell, Mark L 8094cc46a7 Adding random refinement option to mesh-explorer 2023-06-09 10:56:46 -07:00
Tzanio Kolev 92c765ec9d Merge pull request #3713 from mfem/divergence-pa-fix
Transpose for `VectorDivergenceIntegrator`
2023-06-09 07:36:56 -07:00
Mittal, Ketan 0586e95b3d doxygen fix 2023-06-08 16:18:28 -07:00
Mittal, Ketan 2f411ae0e9 add unit test and make serial mesh an input for getting serial gridfunction 2023-06-08 15:26:56 -07:00
Mittal, Ketan 0bf3e290e0 reviewer comments 2023-06-08 13:23:22 -07:00
Mittal, Ketan 8c3867f9a8 Merge branch 'master' of https://github.com/mfem/mfem into pgridfunc-save-serial 2023-06-08 12:40:23 -07:00
Tzanio Kolev b5491f7630 Merge pull request #3456 from mfem/tmop-code-improve
TMOP code improvements
2023-06-07 11:52:28 -07:00
Tzanio Kolev 38a2abaa1f Merge pull request #3632 from mfem/quad-interp-1d
Fully support 1D in QuadratureInterpolator
2023-06-07 11:51:40 -07:00
Socratis Petrides e1824d8468 Merge branch 'master' into material-miniapp 2023-06-06 19:44:06 -07:00
Socratis Petrides 945bd0dbfa adding dpg in doc and fixing blocksolvers path 2023-06-06 19:43:25 -07:00
Socratis Petrides d7bb93ab77 adding doc and fixing doc warnings 2023-06-06 19:18:59 -07:00
Socratis Petrides 574beaedc5 adding rotation in 2D 2023-06-06 19:18:07 -07:00
Stowell, Mark L d20763e444 Standardizing the format of related methods 2023-06-06 14:00:04 -07:00
Stowell, Mark L 672c1dbe84 Fixing merge conflict 2023-06-06 13:46:45 -07:00
Will Pazner 3625f4d307 Implement VectorDivergenceIntegrator::AddMultTransposePA
Adds a unit test to compare with the legacy integrator
2023-06-06 13:46:29 -07:00
Stowell, Mark L 63fbd28afe Merge remote-tracking branch 'origin/master' into mesh-group-doc-dev
# Conflicts:
#	mesh/mesh.hpp
2023-06-06 13:46:00 -07:00
Will Pazner f02cbdd3dd Implement TransposeIntegrator::AssemblePA for mixed spaces 2023-06-06 13:45:31 -07:00
Brody Bassett 4c883e2674 Added comments. 2023-06-06 12:49:35 -07:00
Brody Bassett 83fed93231 Added parameter to choose distance from edge for rbf points. 2023-06-06 11:57:04 -07:00
Brody Bassett 7da7baecc2 Merge branch 'master' into meshless-kernels 2023-06-06 10:35:23 -07:00
Will Pazner e42f9894fe Merge pull request #3700 from mfem/sjg/submesh-const-fix
Minor `const` fix for `ParSubMesh`
2023-06-06 09:59:41 -07:00
Tzanio Kolev fd54059a16 Merge branch 'master' into tmop-integr-ref 2023-06-04 13:49:12 -07:00
Tzanio Kolev c324afb88c Merge branch 'master' into sjg/mumps-solver-dev 2023-06-04 13:42:10 -07:00
Tzanio Kolev c2889cccd5 Merge branch 'master' into hdiv-solvers-miniapp 2023-06-04 13:41:15 -07:00
Sebastian Grimberg 51e24f97f4 Move functions which can be moved into bilininteg_*_kernels.cpp files in order to speed up compilation 2023-06-02 15:53:41 -04:00
Sebastian Grimberg 3adc51440f Fix changelog newline 2023-06-01 15:30:33 -07:00
Sebastian Grimberg 1a614d51a2 Revert mistake from 9c0eae5e 2023-06-01 15:27:51 -07:00
barracuda156 d0c8c0194d CMakeLists: try to satisfy an odd Windows buildbot 2023-06-02 05:52:51 +08:00
Sebastian Grimberg 9c0eae5e3e Remove erroneous MFEM_HOST_DEVICE pragmas 2023-06-01 12:23:51 -07:00
Arturo Vargas a8bf222f2d Merge branch 'master' into artv3/host_read_s_volume_dof 2023-06-01 10:34:23 -07:00
Arturo Vargas 58a31067de use asconst 2023-06-01 10:33:25 -07:00
Veselin Dobrev d0e75c8d0d Merge pull request #3647 from adam-sim-dev/gitignore
Ignore config/user.cmake
2023-05-31 15:24:57 -07:00
adam-sim-dev ae3f95ea65 Merge branch 'master' into sjg/integs-reorg-dev 2023-06-01 06:16:57 +08:00
Will Pazner 0e2180981e Merge pull request #3669 from mfem/fix-gridf-coeff-eval
Fix GridFunctionCoefficient::Eval
2023-05-30 16:40:50 -07:00
Sebastian Grimberg 24cb3d35ac Minor const fix for ParSubMesh 2023-05-30 15:00:36 -07:00
Sebastian Grimberg 71fab657ec Allow HypreParMatrixFromBlocks where some processors may have empty local blocks 2023-05-30 13:35:15 -07:00
barracuda156 ef5d022ab3 Define MAP_ANONYMOUS to MAP_ANON whenever it is undefined 2023-05-28 13:07:47 +08:00
barracuda156 7e8a1d016d Makefile: fix flags for PowerPC 2023-05-28 12:42:57 +08:00
barracuda156 9da38256b9 CMakeLists: fix flags for PowerPC 2023-05-28 12:41:05 +08:00
Mark L. Stowell f1c83d85cb Merge pull request #3587 from mfem/hughcars/pncmesh-simplex-bug-fix
Fix bug with NC tetrahedra in ParNCMesh::GetFaceNeighbors
2023-05-24 09:59:37 -07:00
adam-sim-dev 23c9380bc9 Merge branch 'master' into gitignore 2023-05-23 21:23:24 +08:00
adam-sim-dev 01a7dc65f1 Merge branch 'master' into pardiso 2023-05-23 21:22:52 +08:00
Tzanio Kolev 5c79e2edb1 Merge branch 'master' into fix-kv-difference-dev 2023-05-20 13:49:03 -07:00
Arturo Vargas 81f57b3c88 add missing const 2023-05-19 10:08:44 -07:00
Arturo Vargas 1c4858ac3c add missing host read 2023-05-19 10:06:05 -07:00
Hugh Carson 58db0c0d65 Explicit include of numeric 2023-05-17 13:24:26 -04:00
Socratis Petrides af4e8a8311 Merge branch 'master' into material-miniapp 2023-05-17 10:07:37 -07:00
Hugh Carson c790cf942b Addressing review comments from @dylan-copeland 2023-05-17 08:46:11 -04:00
Hugh Carson 6e4245494a Merge remote-tracking branch 'origin/master' into hughcars/pncmesh-simplex-bug-fix 2023-05-17 08:34:02 -04:00
Jacob Lotz b8e0fc55ce Other instances of T.mesh == gf_mesh in coefficient.cpp 2023-05-16 11:22:26 +02:00
Jacob LotzandWill Pazner a54ba48cce Pazner's suggestion
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2023-05-16 10:04:00 +02:00
Brody Bassett 30d6701bb1 Merge branch 'master' into meshless-kernels 2023-05-15 11:31:40 -07:00
Brody Bassett c208b8f769 Unused variable. 2023-05-15 10:55:07 -07:00
Brody Bassett cbab91143e Fixed shadow error. 2023-05-15 10:45:38 -07:00
Sebastian Grimberg 43ae8b8b4f Merge branch 'master' into sjg/integs-reorg-dev 2023-05-14 17:15:09 -07:00
Jacob Lotz 5c7c78e719 Fix GridFunctionCoefficient::Eval 2023-05-14 21:11:00 +02:00
Tzanio Kolev 0f5d34b2b4 Merge pull request #3630 from ddement/ddement/fix_compile_gcc13
Fixes compilation errors when compiling with gcc-13 on Fedora 38
2023-05-13 19:30:10 -07:00
Tzanio Kolev 199fc18d0f Merge pull request #3586 from mfem/cubic-ea-mass-3d-performance
Cubic EAMassAssemble3D Performance
2023-05-13 19:18:24 -07:00
Hugh Carson b0f7cf909f Merge remote-tracking branch 'origin/master' into hughcars/pncmesh-simplex-bug-fix 2023-05-12 15:40:14 -04:00
Veselin Dobrev 39a46295b1 Merge pull request #3665 from mfem/mfem-actions-v2.4
Use v2.4 for MFEM GitHub Actions
2023-05-12 12:15:57 -07:00
Vladimir Z Tomov 2b50dbddb1 changes in mesh-optimizer 2023-05-11 22:41:27 -07:00
Vladimir Z Tomov e41a6bd61d added option in the miniiapp 2023-05-11 22:34:22 -07:00
Hugh Carson 9a6c94f50d Merge remote-tracking branch 'origin/master' into hughcars/pncmesh-simplex-bug-fix 2023-05-11 14:32:51 -04:00
Brody Bassett 57977fb1c9 Formatting. 2023-05-11 03:05:59 -07:00
Brody Bassett f35a9df42e Added ex18p for RK. 2023-05-11 03:05:23 -07:00
Brody Bassett 4eed46a463 Added comments. 2023-05-11 03:04:08 -07:00
Brody Bassett 2b1ed66c08 Fixed RBF parameters. 2023-05-11 01:01:23 -07:00
Will Pazner 962774d5ff Fix shadow warning in nurbs_ex1.cpp 2023-05-10 18:39:36 -07:00
Brody Bassett 151ab20545 Formatting. 2023-05-10 18:37:35 -07:00
Brody Bassett a0669dfdac Added projection for RBF. 2023-05-10 18:34:16 -07:00
Will Pazner 2d6ec80a10 Use v2.4 for MFEM GitHub Actions 2023-05-10 18:23:25 -07:00
Socratis Petrides 180b85e925 typos 2023-05-10 12:58:38 -07:00
Socratis Petrides fd9c307507 Merge branch 'master' into material-miniapp 2023-05-10 09:07:18 -07:00
Brody Bassett 961b049f34 Formatting. 2023-05-09 16:08:33 -07:00
Brody Bassett e40de76a7e Improved options. 2023-05-09 16:05:48 -07:00
Brody Bassett 63e6eca5fe Added RK to example. 2023-05-09 15:47:21 -07:00
Vladimir Z Tomov 355b6806bc option to integrate over the reference element 2023-05-08 18:49:09 -07:00
Brody Richard Bassett 783854ef0b Added RBF to example. 2023-05-08 16:15:32 -07:00
Vladimir Z Tomov f18934818f Merge branch 'master' into tmop-code-improve 2023-05-08 14:11:28 -07:00
Brody Bassett 6548ab92c2 Remove unneeded change. 2023-05-08 12:23:49 -07:00
Brody Richard Bassett 283b1f9169 Merge branch 'master' into meshless-kernels 2023-05-08 12:12:59 -07:00
Tzanio Kolev 081a860065 Merge pull request #3232 from mfem/nurbs-interp-dev
NURBS curve interpolation functions and small bug fix [nurbs-interp-dev]
2023-05-06 11:34:30 -07:00
Tzanio Kolev c71afc45d5 Merge pull request #3226 from mfem/nurbs-2drot
NURBS patch 2D rotation functions [nurbs 2drot]
2023-05-06 11:33:40 -07:00
adam-sim-dev c8711589fc Ignore config/user.cmake
This PR lets git ignore config/user.cmake
2023-05-05 08:37:36 +08:00
Tzanio Kolev 5de386b084 Merge pull request #3541 from mfem/hughcars/l2zzestimator-bug-fix
Fix bugs in L2ZZErrorEstimator
2023-05-04 08:49:31 -07:00
Tzanio Kolev 0b042e0a98 Merge pull request #3624 from mfem/tmop-update-combos
Update of TMOP combo metrics
2023-05-04 08:48:54 -07:00
Sebastian Grimberg 45577c6fd4 Merge branch 'master' into sjg/integs-reorg-dev 2023-05-03 16:43:21 -07:00
Will Pazner 7025db1cab Remove Doxygen link in HdivSaddlePointSolver 2023-05-03 12:03:19 -07:00
Will Pazner 1214189db1 Makefile fix in H(div) solvers
Don't build any of the H(div) solver miniapps unless MPI is enabled.
2023-05-03 11:44:58 -07:00
Will Pazner d83136a628 Merge remote-tracking branch 'origin/master' into hdiv-solvers-miniapp
# Conflicts:
#	makefile
#	miniapps/CMakeLists.txt
2023-05-03 11:08:53 -07:00
Will Pazner 2b3840afea Add hdiv-linear-solver miniapp directory for build and docs 2023-05-03 11:05:41 -07:00
Will Pazner eca7b9692a Add H(div) miniapp CMakeLists.txt 2023-05-03 11:05:41 -07:00
Will Pazner 409c0bc2f0 Enable tests and out-of-source build in H(div) makefile 2023-05-03 11:05:09 -07:00
Will Pazner 167f0d8380 Fix relative paths for H(div) includes 2023-05-03 11:05:09 -07:00
Will Pazner 343be11e87 Support map type VALUE in H(div) solver 2023-05-03 11:05:09 -07:00
Will Pazner 2dcbd14f93 Minor improvements in H(div) solver change of basis 2023-05-03 11:05:09 -07:00
Will Pazner 1a07e09305 Update copyright year in H(div) solvers miniapp 2023-05-03 11:05:09 -07:00
adam-sim-dev 45c3697b41 Merge branch 'master' into pardiso 2023-05-03 11:47:46 +08:00
Sebastian Grimberg 04b925149d Merge branch 'master' into sjg/superlu-solver-dev 2023-05-02 17:46:52 -07:00
Sebastian Grimberg 73ecab28a2 Merge branch 'master' into sjg/mumps-solver-dev 2023-05-02 17:46:43 -07:00
Tzanio Kolev e5231334e6 Merge pull request #3633 from mfem/gitlab-lassen-update-2023-04-29
Update the GitLab CI config for Lassen
2023-05-02 12:11:58 -07:00
Veselin Dobrev 5e724d670e Merge pull request #3569 from mfem/lininteg-domain-fix
Support Q < D in linear form device kernels
2023-05-02 12:01:02 -07:00
Ketan Mittal 04321ae65a Merge branch 'tmopupdate-geomparam' of https://github.com/mfem/mfem into tmopupdate-geomparam 2023-05-02 11:25:21 -07:00
Ketan Mittal 3a7e366075 update dox file 2023-05-02 11:25:06 -07:00
Socratis Petrides 42743b59ec conflicts with master 2023-05-01 13:21:02 -07:00
Vladimir Z Tomov f7d4dc787c minor 2023-04-30 15:01:09 -07:00
Vladimir Z Tomov 05b9bd335a Merge branch 'tmop-update-combos' into tmop-code-improve 2023-04-30 14:19:52 -07:00
Vladimir Z Tomov 813af66df5 Merge branch 'master' into tmop-code-improve 2023-04-30 14:14:44 -07:00
Vladimir Z Tomov d5d79a60cf Merge branch 'master' into tmop-update-combos 2023-04-30 13:35:00 -07:00
Vladimir Z Tomov af8789067f updated CHANGELOG 2023-04-30 10:28:16 -07:00
Veselin Dobrev 1731550125 Update mfem/uberenv hash 2023-04-29 19:55:08 -07:00
Veselin Dobrev cd2120e7d8 Update the GitLab CI config for Lassen -- the old compilers are
no longer available.
2023-04-29 15:27:56 -07:00
Ketan Mittal 46a89987a5 Merge branch 'tmop-update-combos' of https://github.com/mfem/mfem into tmop-update-combos 2023-04-28 15:29:08 -07:00
Ketan Mittal ea74881234 minor 2023-04-28 15:28:36 -07:00
Ketan Mittal 126341eefb minor 2023-04-28 11:47:28 -07:00
hughcars e7bba704db Merge branch 'master' into hughcars/l2zzestimator-bug-fix 2023-04-28 14:18:27 -04:00
Will Pazner f87e570329 Fully support 1D in QuadratureInterpolator 2023-04-28 10:14:34 -07:00
David Dement 314a32af2e Fixes comilation errors when compiling with gcc-13 on Fedora 38
When compiling with gcc-13, types such as uint64_t are not defined.
It is likely that <cstdint> is included implicitly with older compiler
versions.
2023-04-27 10:33:51 -04:00
hughcars 000c7a6722 Merge branch 'master' into hughcars/pncmesh-simplex-bug-fix 2023-04-27 08:56:03 -04:00
Vladimir Z Tomov 89684ac747 fixed sample runs 2023-04-25 22:32:27 -07:00
Veselin Dobrev f3bd409b18 Merge pull request #3510 from mfem/qfunction-use-device
Set `UseDevice(true)` by default in `QuadratureFunction`
2023-04-25 17:43:19 -07:00
Tzanio Kolev 01a576ec74 Merge pull request #3234 from mfem/dpg-miniapp
DPG miniapps
2023-04-25 11:30:37 -07:00
Tzanio Kolev 377177b248 Merge pull request #3621 from mfem/gitlab-ci-updates-2023-04
GitLab CI updates 2023-04
2023-04-25 11:17:10 -07:00
Vladimir Z Tomov 1ab56f5461 bug 2023-04-25 10:20:20 -07:00
Vladimir Z Tomov c9d033b4a9 missing call for 318H. 2023-04-25 09:05:26 -07:00
Vladimir Z Tomov c9fc951248 minor 2023-04-24 18:59:17 -07:00
Vladimir Z Tomov 776fc70763 minor 2023-04-24 18:46:31 -07:00
Vladimir Z Tomov 70c20c57c1 style 2023-04-24 18:26:28 -07:00
Vladimir Z Tomov f145235263 discrete adaptivity + NC example 2023-04-24 18:14:06 -07:00
Veselin Dobrev 187cb814ea Resolve some warnings from GCC 2023-04-24 17:56:30 -07:00
Vladimir Z Tomov 9b1442d2ea minor 2023-04-24 17:34:01 -07:00
Vladimir Z Tomov 0dd19dbbdd added metrics / comments to miniapps 2023-04-24 17:22:47 -07:00
Vladimir Z Tomov 3c41192407 fixed 3d setup in tmop-metric-maagnitude 2023-04-24 17:09:36 -07:00
Vladimir Z Tomov 61fdf7a1bc Merge branch 'master' into tmop-update-combos 2023-04-24 14:22:31 -07:00
Tobias Duswald 41ef47f9dc Use relative path to include ex33 for triple-A 2023-04-24 20:12:21 +02:00
Hugh Carson 627ea87fed Add checks for FaceElementTransformations 2023-04-24 11:00:02 -04:00
Veselin Dobrev 8979d0a6e9 In GitLab CI, distclean the MFEM directory after running the tests 2023-04-23 10:53:40 -07:00
Veselin Dobrev 313ec4f9d2 In GitLab CI, rename Quartz tests appropriately and tweak the
Quartz baseline test.
2023-04-23 09:42:37 -07:00
Veselin Dobrev fb276f7c85 In GitLab CI:
* update specs for the Quartz tests for TOSS-4
* use 'python3' when 'python' is not available
* update mfem/mfem-uberenv git hash to a commit that has TOSS-4 configs
2023-04-22 20:14:55 -07:00
Veselin Dobrev b3b307d627 In GitLab CI, use a modified way to obtain file locks because
the previous approach does not work robustly on TOSS-4.
2023-04-22 12:13:04 -07:00
Sebastian Grimberg 371660c602 Merge branch 'master' into pa-mass-boundary-integ 2023-04-20 10:01:22 -07:00
Sebastian Grimberg 2392f3e8e1 Merge branch 'master' into sjg/integs-reorg-dev 2023-04-20 09:36:26 -07:00
Adam efb04c44a0 Fix the makefile 2023-04-20 09:32:43 +08:00
Adam 2bd378b105 Add the CMake module file 2023-04-20 09:32:06 +08:00
Adam 92088543b6 Add Pardiso solver for SparseMatrix 2023-04-20 08:59:00 +08:00
Socratis Petrides e0c15bb46c Merge branch 'master' into dpg-miniapp 2023-04-19 15:58:19 -07:00
Hugh Carson 1e8ede837a Removed some autos based on reviewer feedback 2023-04-19 17:05:54 -04:00
Hugh Carson 8d36ef0206 Style fix 2023-04-19 10:53:19 -04:00
Hugh Carson 1c25aeb978 Change auto to DofTransformation 2023-04-19 09:59:04 -04:00
Vladimir Z Tomov 4cafbba417 merge error 2023-04-18 15:36:27 -07:00
hughcars 74ccc9a1c3 Merge branch 'master' into hughcars/pncmesh-simplex-bug-fix 2023-04-18 18:34:12 -04:00
hughcars 5ca0cad558 Merge branch 'master' into hughcars/l2zzestimator-bug-fix 2023-04-18 18:33:59 -04:00
Vladimir Z Tomov 747783f1cb Merge branch 'master' into tmopupdate-geomparam 2023-04-18 15:33:06 -07:00
Vladimir Z Tomov 35d0c72f1e minor 2023-04-18 15:28:03 -07:00
Socratis Petrides 0cb6fb5e5b Merge branch 'master' into material-miniapp 2023-04-18 15:16:13 -07:00
camierjs 21de4bee48 Merge master in lininteg-domain-fix 2023-04-18 14:57:33 -07:00
Tzanio Kolev 1ee0e3b365 Merge pull request #3548 from mfem/gslib-mesh-p-ref
GSLIB support for p-refined meshes.
2023-04-18 13:23:20 -07:00
Tzanio Kolev 7ef30cb389 Merge pull request #3454 from mfem/forall
Debugging lambdas in mfem::forall
2023-04-18 13:23:05 -07:00
Ketan Mittal 3dbd1dc95e resolve merge conflict 2023-04-18 11:21:31 -07:00
Socratis Petrides 8db7c1879e resolve conflicts with master 2023-04-18 11:19:06 -07:00
Sebastian Grimberg 9375c8d164 Merge branch 'master' into sjg/superlu-solver-dev 2023-04-18 11:09:40 -07:00
Sebastian Grimberg d7aa421eda Merge branch 'master' into sjg/mumps-solver-dev 2023-04-18 11:09:28 -07:00
Sebastian Grimberg 4595195d3a Merge branch 'master' into sjg/integs-reorg-dev 2023-04-18 11:09:11 -07:00
Ketan Mittal 8d575ac594 update CHANGELOG 2023-04-18 10:39:44 -07:00
camierjs 87497f501c Merge master in forall 2023-04-18 10:37:09 -07:00
Will Pazner 30ce09bf64 Merge pull request #3582 from mfem/serial-asan
[Github] Serial address sanitizer action
2023-04-18 08:46:50 -07:00
Tzanio Kolev 93393c5c58 Merge pull request #3608 from mfem/gh-actions-windows-workaround
Workaround for the random failures on Windows in GH actions
2023-04-18 08:46:28 -07:00
Veselin Dobrev e97ae62dba Fix style 2023-04-17 10:33:40 -07:00
Veselin Dobrev b6b3412fd6 Merge branch 'master' into dpg-miniapp 2023-04-17 10:27:03 -07:00
Veselin Dobrev a7d3193263 Fix test failures due to changes in PR #3579 uncovered during testing
in 'next'.
2023-04-17 10:20:41 -07:00
camierjs 33182d0b8f Merge master in serial-asan 2023-04-17 08:13:06 -07:00
camierjs 6c150900e2 Merge master in forall 2023-04-17 08:11:55 -07:00
hughcars 9f5d4740c2 Merge branch 'master' into hughcars/l2zzestimator-bug-fix 2023-04-17 08:57:30 -04:00
hughcars c64d04bee5 Merge branch 'master' into hughcars/pncmesh-simplex-bug-fix 2023-04-17 08:57:26 -04:00
Tzanio Kolev bf4f57bb5b Merge branch 'master' into cubic-ea-mass-3d-performance 2023-04-15 17:26:36 -07:00
psocratis d80f17ea2c master conflicts 2023-04-14 20:25:40 -07:00
psocratis 7e6288d2e4 subvectors fix for cuda runs 2023-04-14 20:22:44 -07:00
psocratis 733c5df082 additional blockvector wrapper with offset 2023-04-14 20:21:47 -07:00
Veselin Dobrev 32e175f916 Workaround for the random failures on Windows in GH actions 2023-04-14 16:26:00 -07:00
camierjs b8c5a62077 Merge master in serial-asan 2023-04-14 07:54:52 -07:00
Ketan Mittal cabf7c5a6d Merge branch 'tmopupdate-geomparam' of https://github.com/mfem/mfem into tmopupdate-geomparam 2023-04-13 11:36:32 -07:00
Ketan Mittal a9e9f3334d address reviewer comments 2023-04-13 11:36:21 -07:00
camierjs 7127e6d920 Merge branch 'forall' of github.com:mfem/mfem into forall 2023-04-13 09:47:41 -07:00
camierjs aa4b04d0a8 Allow back both host_kernel and device_kernel 2023-04-13 09:46:13 -07:00
Veselin Dobrev b86c18f78b Minor: fix formatting 2023-04-13 06:16:07 -07:00
Tobias Duswald d5e8c6d90a Avoid MPI::Root() and add print level 2023-04-12 10:45:14 +02:00
Tobias Duswald f08bcd11c1 Remove communicator from constructor 2023-04-12 10:22:10 +02:00
Tobias Duswald 9567458cf2 Move boundary.* contents to spde_solver.*
Better reusability
2023-04-12 10:07:37 +02:00
Sebastian Grimberg 42dd69c445 Undo another unrelated style change 2023-04-11 21:26:42 -07:00
Sebastian Grimberg d2e2b5dc45 Revert "No need for intermediate ElementRestrictionOperator abstract base class"
This reverts commit f29c92d946.
2023-04-11 21:10:10 -07:00
Socratis Petrides 88e041e92b Merge branch 'master' into hughcars/l2zzestimator-bug-fix 2023-04-11 16:14:18 -07:00
Socratis Petrides 0e4657e29e Merge branch 'master' into material-miniapp 2023-04-11 15:31:05 -07:00
Socratis Petrides fb2326b248 git ignore ParaView 2023-04-11 14:09:01 -07:00
Socratis Petrides a087f7fca0 gitignore 2023-04-11 12:03:08 -07:00
Socratis Petrides 17fde165d1 Merge branch 'master' into sjg/mumps-solver-dev 2023-04-11 12:00:40 -07:00
camierjs 95e379e5cc Revert ex1.cpp fec leak 2023-04-11 10:54:27 -07:00
camierjs 0e272e46ec Remove sanitize-recover=address option 2023-04-11 10:36:57 -07:00
Sebastian Grimberg f9c0adbdfc Fix test and style updates 2023-04-11 10:35:52 -07:00
Socratis Petrides f9217b9353 fix make test 2023-04-11 10:32:27 -07:00
Sebastian Grimberg 8a256a7064 Merge branch 'master' into sjg/superlu-solver-dev 2023-04-11 10:28:45 -07:00
camierjs ad8c8cfb98 Reorder options in workflows/mfem-sanitizer.yml 2023-04-11 10:10:28 -07:00
Sebastian Grimberg d204d7e909 Merge branch 'master' into sjg/mumps-solver-dev 2023-04-11 10:00:02 -07:00
Sebastian Grimberg 5fe0f7fbed Fix test and style updates 2023-04-11 09:59:40 -07:00
camierjs 408dfc5410 Tune ASAN_OPTIONS 2023-04-11 09:54:43 -07:00
Vladimir Z Tomov eb6a8e4bd6 Merge branch 'tmop-nc-adapt' into tmop-update-combos 2023-04-11 09:38:29 -07:00
camierjs 29585dd32e Add debug compilation flags to get stack 2023-04-11 09:31:00 -07:00
camierjs 1f57b55886 Update mfem-sanitizer.yml 2023-04-11 09:15:31 -07:00
Sebastian Grimberg 574980a149 Update CHANGELOG and CONTRIBUTING.md 2023-04-11 09:15:30 -07:00
camierjs bddd685949 Simplify mfem-sanitizer.yml 2023-04-11 09:12:47 -07:00
camierjs ea5d0e607b Update CHANGELOG with AddressSanitizer GitHub action 2023-04-11 09:06:36 -07:00
John Camier df47c292d9 Update mfem-sanitizer.yml 2023-04-11 08:16:58 -07:00
camierjs 9ba5647ecd Update sanitizer workflow yml 2023-04-11 08:13:09 -07:00
camierjs 07945840f9 Update mfem::forall CHANGELOG, bis 2023-04-11 08:05:00 -07:00
camierjs 2af61d1767 Update mfem::forall CHANGELOG 2023-04-11 08:03:33 -07:00
camierjs 8caa676581 Merge master in forall 2023-04-11 07:55:59 -07:00
camierjs df3d38b682 Merge master in serial-asan 2023-04-11 07:54:47 -07:00
hughcars 8a4e4d6b60 Merge branch 'master' into hughcars/pncmesh-simplex-bug-fix 2023-04-11 10:02:17 -04:00
Vladimir Z Tomov d2761243ba Corrections in size adaptivity for NC meshes. 2023-04-10 18:47:27 -07:00
camierjs fffb805d98 Update ASAN flags in github/workflows/mfem-sanitizer.yml 2023-04-10 18:35:04 -07:00
camierjs b694a24530 github/workflows/mfem-sanitizer.yml line 52 2023-04-10 18:32:49 -07:00
camierjs 6c30fcde5e Update github/workflows/mfem-sanitizer.yml 2023-04-10 18:30:34 -07:00
camierjs 9ab4f797a4 Try to break long lines 2023-04-10 18:22:30 -07:00
camierjs 632e345f79 Simplify miniapps/toys/snake 2023-04-10 18:18:02 -07:00
camierjs bfe1fe4831 Update/fix DLFGradAssemble3D to use one shared memory buffer 2023-04-10 18:13:14 -07:00
Socratis Petrides d070b7050f adding dir to makefile and style 2023-04-10 18:02:34 -07:00
Socratis Petrides 92a15d6526 fixing random seed generator 2023-04-10 17:59:14 -07:00
Sebastian Grimberg f75ece6427 Fix a bad style change 2023-04-10 17:08:52 -07:00
Socratis Petrides d83196e11e fix sample run path 2023-04-10 17:01:49 -07:00
Socratis Petrides 526d0877c4 fixing year in header 2023-04-10 16:54:30 -07:00
Socratis Petrides 4cf69756a9 Merge branch 'master' into material-miniapp 2023-04-10 16:39:01 -07:00
Sebastian Grimberg f29c92d946 No need for intermediate ElementRestrictionOperator abstract base class 2023-04-10 16:35:03 -07:00
Sebastian Grimberg cb962cf1db Minor refactor for common kernel 2023-04-10 16:35:03 -07:00
Sebastian Grimberg 8c44526211 Add LinearFormIntegrator and NonlinearFormIntegrators to reorganization 2023-04-10 16:35:03 -07:00
Sebastian Grimberg fd77ed5af3 Reorganize BilinearFormIntegrator files to be a bit more readable 2023-04-10 16:35:00 -07:00
Will Paznerandcamierjs 08a2d97ea1 Use more threads to reduce shared mem usage…
…in DomainLFGradIntegrator.

Co-authored-by: camierjs <camier1@llnl.gov>
2023-04-10 13:58:09 -07:00
Will Pazner 3581e69476 Fix 'end of non-void' warning 2023-04-10 13:48:49 -07:00
camierjs 617959b485 Update fem/lininteg_boundary_flux and fem/lininteg_vectorfe_domain kernels with mfem::forall 2023-04-10 11:50:51 -07:00
camierjs 7b3a094d7b Merge master in forall 2023-04-10 11:43:55 -07:00
Will Pazner 87c792899f Remove internal function from public API for ConformingFaceRestriction
The "use_signs" overload of ConformingFaceRestriction::AddMultTranspose
is not supposed to be in the public API, but because of NVCC limitations
it cannot be private or protected.

It has now been moved to a static free function
ConformingFaceRestriction_AddMultTranspose in the cpp file.
2023-04-10 09:58:14 -07:00
Will Pazner fcb7075aba Use double instead of int for signs…
…in ConformingFaceRestriction::AddMultTranspose
2023-04-10 09:26:30 -07:00
Will Pazner ffb9b75351 Remove global variable from assemble diagonal unit test 2023-04-10 09:26:18 -07:00
Will Pazner 90669b2cd6 Remove unneeded include statement 2023-04-10 09:26:18 -07:00
Ketan Mittal 337d0381ce Merge branch 'master' into tmopupdate-geomparam 2023-04-10 09:12:32 -07:00
Ketan Mittal 343891943f Merge branch 'tmopupdate-geomparam' of https://github.com/mfem/mfem into tmopupdate-geomparam 2023-04-10 09:08:54 -07:00
Ketan Mittal 41cec94d95 update copyright in the miniapp 2023-04-10 09:08:28 -07:00
camierjs c283d4b6c2 Merge master in serial-asan 2023-04-10 08:32:12 -07:00
Veselin Dobrev 7dd47b2e81 Propagate changes from #3393: rename H1_ND_RT_FaceRestriction to
ConformingFaceRestriction.
2023-04-09 21:23:23 -07:00
Veselin Dobrev 97c9ae5a7b Merge branch 'master' into pa-mass-boundary-integ 2023-04-09 18:09:06 -07:00
Tzanio Kolev 3ef59179b1 Merge branch 'master' into hughcars/l2zzestimator-bug-fix 2023-04-09 13:35:26 -07:00
Tzanio Kolev da6f7c29d4 Merge branch 'master' into material-miniapp 2023-04-09 13:34:41 -07:00
Tzanio Kolev adb8771546 Merge branch 'master' into sjg/mumps-solver-dev 2023-04-09 13:18:26 -07:00
Tzanio Kolev f016f09317 Merge branch 'master' into forall 2023-04-09 13:16:24 -07:00
Tzanio Kolev 6f66cd8536 Merge branch 'master' into gslib-mesh-p-ref 2023-04-09 13:15:36 -07:00
Tzanio Kolev 9d79f691d6 Merge branch 'master' into tmopupdate-geomparam 2023-04-09 13:14:44 -07:00
Tzanio Kolev 0052dd6faf Merge branch 'master' into hdiv-solvers-miniapp 2023-04-09 13:13:10 -07:00
Veselin Dobrev 87d1b58fb7 Add CUDA/HIP tests to the SUNDIALS examples 2023-04-08 20:28:16 -07:00
Veselin Dobrev c6a5ffd3dc Small tweaks in the memory manager.
In INSTALL, use more consistent formatting for the version
requirements for SUNDIALS.

Remove unused SUNDIALS includes from vector.?pp.
2023-04-08 19:15:43 -07:00
Cody J. Balos d0c79e5b89 fix CHANGELOG and INSTALL 2023-04-07 16:10:07 -07:00
Cody J. Balos 98a5c8bac2 style 2023-04-07 16:00:59 -07:00
Cody J. Balos cc57bdc9e9 fix SundialsNVector from NVector constructor 2023-04-07 15:45:42 -07:00
Balos, Cody, JandDavid J. Gardner 17913af713 Add HIP support in SUNDIALS interface
Co-authored-by: David J. Gardner <gardner48@llnl.gov>
2023-04-07 15:45:42 -07:00
Ketan Mittal 2c4df1fcd0 initial commit 2023-04-05 16:33:57 -07:00
Vladimir Z Tomov 5cac3050f3 device code for mu_94 2023-04-05 15:28:12 -07:00
Hugh Carson d5b8ab38a9 Fix bug if number of ranks > 2 2023-04-05 17:17:10 -04:00
Vladimir Z Tomov c5142e5900 fixed GetData() -> Read() 2023-04-05 14:07:32 -07:00
Hugh Carson 047ecbf2a4 style fixes 2023-04-05 16:44:29 -04:00
Tom Stitt 481a61d473 template-based memory type choice; stores quadratic performance 2023-04-05 13:31:28 -07:00
Hugh Carson 0f68ba5c40 Change test to check for L2 error matching on serial and parallel meshes. Only check combinations that trigger face-edge constraint. 2023-04-05 15:53:12 -04:00
Hugh Carson e208fab2dd Create unit test that triggers the face-edge constraint bug for NC tetrahedra 2023-04-05 15:53:12 -04:00
Hugh Carson e4c0d0256d Intermediate progress 2023-04-05 15:53:12 -04:00
Tom Stitt 1b15df97db need to use smem above quadratic for performance 2023-04-05 11:52:04 -07:00
Sebastian Grimberg 2d5dd2682d Merge branch 'master' into sjg/superlu-solver-dev 2023-04-05 09:47:30 -05:00
Vladimir Z Tomov b3bb8b36a9 GetData outside of macro. 2023-04-04 22:02:19 -07:00
camierjs 7c210f880a meld toward master 2023-04-04 18:13:35 -07:00
camierjs 785807fd9e Simplify mfem-sanitizer.yml config-options 2023-04-04 18:11:10 -07:00
camierjs 02fb182f99 Simplify sanitized polar-nc vs. NCMesh::GetMeshComponents leak 2023-04-04 18:05:56 -07:00
camierjs d384589ecc Simplify sanitized AddTet vs. AddElement(new Tetrahedron) 2023-04-04 17:37:33 -07:00
Vladimir Z Tomov 038d10112f device implementation for metric 338. 2023-04-04 17:18:12 -07:00
Cody J. Balos da9852ebb3 use Memory<char> in sundials memory helper alloc/dealloc since memsize is in bytes 2023-04-04 16:28:02 -07:00
Balos, Cody, JandDavid J. Gardner 3720a24afa Add HIP support in SUNDIALS interface
Co-authored-by: David J. Gardner <gardner48@llnl.gov>
2023-04-04 16:28:00 -07:00
camierjs fc640de940 Update github/workflows/mfem-sanitizer to O1 2023-04-04 14:17:07 -07:00
camierjs 307d6d0a3a Update github sanitizer serial job name and CXXFLAGS 2023-04-04 13:56:34 -07:00
camierjs 3b3b9ae311 Change config-options to speedup MFEM build 2023-04-04 13:50:54 -07:00
camierjs 0659152e93 Sanitize mesh AddElement in tests/unit/fem/test_linear_fes while still using MemAlloc 2023-04-04 13:07:33 -07:00
camierjs d9486811c0 Try reverting tests/unit/fem/test_linear_fes.cpp 2023-04-04 12:14:40 -07:00
camierjs 89315154df Sanitize miniapps/toys/snake 2023-04-04 11:32:39 -07:00
camierjs 2cc38dcf8d Revert tests/unit/fem/test_linear_fes.cpp 2023-04-04 11:26:34 -07:00
camierjs cca28f3882 Meld toward master 2023-04-04 10:39:35 -07:00
camierjs ccff93be57 Sanitize polar-nc miniapp 2023-04-04 10:34:13 -07:00
camierjs 62e0a0ee6f Switch back to ubuntu (MachOFile errors) 2023-04-03 17:53:42 -07:00
camierjs e8d218ca23 Sanitize mesh/submesh/psubmesh.cpp tests/unit/mesh/test_psubmesh.cpp 2023-04-03 17:24:38 -07:00
camierjs 39c4d9c335 Sanitize FiniteElementSpace::RefinementOperator::~RefinementOperator 2023-04-03 16:27:08 -07:00
camierjs 65e4297bad Sanitize tests/unit/mesh/test_submesh.cpp 2023-04-03 16:16:15 -07:00
camierjs 50f4080783 Sanitise PAIdentityInterp 2023-04-03 16:12:18 -07:00
camierjs 796c8b8817 Sanitize tests/unit/fem/test_linear_fes.cpp 2023-04-03 15:43:42 -07:00
camierjs 9d1578e648 Sanitize tests/unit/fem/test_datacollection.cpp 2023-04-03 15:36:28 -07:00
camierjs 6ace2b259d Sanitize tests/unit/fem/test_derefine.cpp 2023-04-03 14:25:07 -07:00
camierjs c486639876 Sanitize tests/unit/linalg/test_chebyshev.cpp 2023-04-03 14:08:04 -07:00
camierjs 1bbf8cc263 Sanitize tests/unit/fem/test_build_dof_to_arrays.cpp 2023-04-03 14:06:34 -07:00
camierjs 7660695e62 Sanitize test_1d_bilininteg, test_2d_bilininteg 2023-04-03 14:03:47 -07:00
hughcars c27d4c2db4 Merge branch 'master' into hughcars/l2zzestimator-bug-fix 2023-04-03 16:53:03 -04:00
camierjs a0e624f05f Sanitize ex25, ex25p 2023-04-03 13:50:22 -07:00
camierjs e532dd44a5 Add Wno-error as pedantic Wall Werror are arbitraty used on non-linux images 2023-04-03 13:19:01 -07:00
camierjs b7ad371e7c Sanitizer switch to Clang/LLVM (Homebrew) 2023-04-03 13:13:26 -07:00
camierjs d54144af96 Update .github/workflows/mfem-sanitizer.yml 2023-04-03 12:45:20 -07:00
camierjs a1120fb78b Switch to build-mfem@v2.3 and set required variables 2023-04-03 11:31:20 -07:00
camierjs 2159ea40fd Simplify CPPFLAGS 2023-04-03 11:07:49 -07:00
camierjs c62d94bde0 mfem-sanitizer escape CPPFLAGS 2023-04-03 11:06:19 -07:00
camierjs 6600995aa5 mfem-sanitizer seq build 2023-04-03 11:04:18 -07:00
camierjs 5081a4c306 Add .github/workflows/mfem-sanitizer.yml 2023-04-03 10:57:57 -07:00
Hugh Carson 532d88bbbc Swap second and last entries of point matrix, will reorient quadrilaterals and triangles 2023-03-30 16:47:02 -04:00
Will Pazner f7f2a8c374 Change linear form kernels to handle Q < D 2023-03-30 12:01:33 -07:00
Will Pazner f2a3786b4b Add linear form extension unit test when Q < D
Some of the device linear form kernels don't work when there are fewer
quadrature points than DOFs
2023-03-30 12:01:19 -07:00
hughcars eefac54be0 Merge branch 'master' into sjg/mumps-solver-dev 2023-03-30 12:44:55 -04:00
hughcars 6f58cd6ed4 Merge branch 'master' into sjg/superlu-solver-dev 2023-03-30 12:42:35 -04:00
Vladimir Z Tomov 1fe4705356 added metrics to pmesh-optimimzer 2023-03-29 14:30:21 -07:00
Socratis Petrides 7270e3a2fb update year in headers 2023-03-27 14:40:53 -07:00
Vladimir Z Tomov e1018b1aa4 minor 2023-03-27 12:53:01 -07:00
Vladimir Z Tomov bf9b6d90fb edit mu_328, add mu_338. 2023-03-27 12:48:52 -07:00
Vladimir Z Tomov b53b301586 added mu_90 and mu_94. 2023-03-27 12:27:38 -07:00
Vladimir Z Tomov 194198d746 added mu_318. 2023-03-27 11:32:50 -07:00
Tzanio Kolev 96c2fc6463 Merge branch 'master' into hughcars/l2zzestimator-bug-fix 2023-03-27 08:27:56 -07:00
Tzanio Kolev a715f58848 Update CHANGELOG 2023-03-25 17:57:36 -07:00
Tzanio Kolev 48a5400461 Merge branch 'master' into dpg-miniapp 2023-03-25 17:57:02 -07:00
Tzanio Kolev 0f4decfeda Merge branch 'master' into forall 2023-03-25 17:55:11 -07:00
Tzanio Kolev 3368612fe9 Merge branch 'master' into gslib-mesh-p-ref 2023-03-25 17:54:57 -07:00
camierjs dce372389b Merge master in forall 2023-03-24 07:52:56 -07:00
Ketan Mittal da035f0f48 reviewer comments 2023-03-23 13:29:43 -07:00
Tobias Duswald da5b50a6d6 Add MPI_Comm member to Sovler for WhiteNoiseInt 2023-03-21 18:29:44 +01:00
Ketan Mittal 70ebd0dd0d update method name 2023-03-20 10:33:54 -07:00
Ketan Mittal 96750ba446 make style and free memory in miniapp 2023-03-20 10:20:20 -07:00
Ketan Mittal 2210c08352 add p-ref support in Overset class 2023-03-20 10:05:06 -07:00
Ketan Mittal 514df47dd4 initial commit adding support for p-refined mesh in gslib FindPoints 2023-03-20 10:02:53 -07:00
Jacob Lotz 4b34bc4b33 Merge branch 'fix-kv-difference-dev' of github.com:mfem/mfem into fix-kv-difference-dev 2023-03-20 11:51:27 +01:00
Jacob Lotz 3d839b9df0 Multiplied smallest difference with 2 2023-03-20 11:51:02 +01:00
Jacob Lotz e16f51aaad Merge branch 'master' into fix-kv-difference-dev 2023-03-20 11:17:08 +01:00
Hugh Carson e1ece74a73 Fix bug with missing DofTransformations. Also fix bug in L2ZZErrorEstimator adding element vectors rather than setting subvectors 2023-03-15 16:59:33 -04:00
Will Pazner 1427ce691f Give runtime error if using MFBilinearFormExtension with boundary integrators 2023-03-15 10:00:12 -07:00
Will Pazner 83ac596632 Add unit test for PA mass boundary diagonal assembly 2023-03-15 09:56:53 -07:00
Will Pazner d7fb8506cb Handle boundary integrators in PA AssembleDiagonal 2023-03-15 09:56:36 -07:00
Will Pazner aad64e603d Add PAMassAssembleDiagonal1D 2023-03-15 09:56:25 -07:00
Will Pazner f53ed1f5c3 Add AddMultTransposeUnsigned to FaceRestriction 2023-03-15 09:56:05 -07:00
Will Pazner a51401492b Add unit test for BA boundary mass 2023-03-14 15:05:33 -07:00
Will Pazner 8c41441b8b Implement PA mass boundary integrator 2023-03-14 15:04:43 -07:00
Will Pazner c5e124d3e6 Add interface for PA boundary bilinear form integrators 2023-03-14 15:04:00 -07:00
Will Pazner 78196710c6 Change mfem_error to MFEM_ABORT
MFEM_ABORT is preferred because it gives more useful output.
2023-03-14 15:03:23 -07:00
John Camier 650f7281d9 Merge branch 'master' into qfunction-use-device 2023-03-14 09:06:47 -07:00
camierjs 6851f32854 Merge master in forall 2023-03-14 08:46:19 -07:00
Tobias Duswald f9c35d8b63 Fix inner structure of octet truss 2023-03-07 10:05:37 +01:00
Will Pazner 7dfe18cfd5 Call HostWrite in Vector::Load 2023-03-02 09:22:16 +01:00
Tobias Duswald 488f0ba5b1 Set better initial values for basic usage 2023-03-01 20:50:19 +01:00
Tobias Duswald 096ed7a904 Move from main to generate_random_field 2023-03-01 20:45:33 +01:00
Tobias Duswald 227194e1a5 Fix visualizer (no overlapping windows) 2023-03-01 20:21:50 +01:00
Tobias Duswald ca029c1abc Fix code smells in bounday class 2023-03-01 19:59:47 +01:00
Tobias Duswald ba74735a4c Replace for loop with std::for_each in util.cc 2023-03-01 19:51:05 +01:00
Tobias Duswald 7edde9a846 Fix code smells for transformers 2023-03-01 19:45:16 +01:00
Tobias Duswald dce5f8745f Enforce rule of zero for SPDESolver 2023-03-01 19:40:06 +01:00
Tobias Duswald 25ec9f8d5e Fix initializers of SPDESolver and code smells 2023-03-01 19:24:12 +01:00
Tobias Duswald bc599f2263 Change initializers for MaterialMetrics 2023-03-01 18:17:46 +01:00
Tobias Duswald ad364e14e9 Remove unused variables and simplify if statement 2023-03-01 16:19:38 +01:00
Tobias Duswald a223afd803 Fix boundaries and dimensions (manifolds) 2023-03-01 16:04:33 +01:00
Sebastian Grimberg feb6f44032 Merge branch 'master' into sjg/mumps-solver-dev 2023-02-28 16:24:12 -08:00
Sebastian Grimberg 7b7068472c Merge branch 'master' into sjg/superlu-solver-dev 2023-02-28 16:23:43 -08:00
Sebastian Grimberg 806ca2ff0d Change nprow_, npcol_, npdep_ to publicly visible invariants 2023-02-28 14:41:18 -08:00
Ketan Mittal 7e2d6ccc3c fix test 2023-02-27 09:58:37 -08:00
Ketan Mittal 9e8a3097aa Merge branch 'master' of https://github.com/mfem/mfem into tmopupdate-geomparam 2023-02-26 22:27:27 -08:00
Ketan Mittal f8290d14c3 make miniapp serial 2023-02-26 22:27:04 -08:00
Will Pazner 14716699fd Set UseDevice(true) by default in QuadratureFunction 2023-02-26 14:52:57 -08:00
Ketan Mittal 70ace3c7ab fix makefile and minor update to miniapp 2023-02-24 11:52:05 -08:00
Ketan Mittal e50bb7768f fix default mesh in the miniapp 2023-02-23 16:38:48 -08:00
Ketan Mittal 20630c6330 Merge branch 'tmopupdate-geomparam' of https://github.com/mfem/mfem into tmopupdate-geomparam 2023-02-21 09:56:47 -08:00
Ketan Mittal 2d331e57a1 resolve merge conflict 2023-02-21 09:56:19 -08:00
Ketan Mittal 2512cb1bb4 TODO items for new miniapp 2023-02-21 09:55:26 -08:00
camierjs 5f6fd83301 Adjust extended lambdas comment and style 2023-02-17 10:40:48 -08:00
camierjs d17338f45e Update CHANGELOG, CONTRIBUTING.md and doc/CodeDocumentation.dox 2023-02-17 10:19:43 -08:00
camierjs 9ec30c32f2 Merge branch 'forall' of github.com:mfem/mfem into forall 2023-02-17 10:15:44 -08:00
camierjs 4b461430ec make style with new mfem::forall, MFEM_HOST_DEVICE for MFEM_FORALL 2023-02-17 10:14:56 -08:00
Veselin Dobrev b9168bf515 Fix the out-of-source build with make in miniapps/dpg.
Also, fix some warnings from -Wextra and -Wshadow.
2023-02-15 15:39:18 -08:00
Tzanio Kolev eb2f700b2d Merge branch 'master' into dpg-miniapp 2023-02-14 09:52:25 -08:00
Tzanio Kolev 5540fbd729 Merge branch 'master' into tmop-code-improve 2023-02-11 14:43:19 -08:00
Tzanio Kolev 1cd062b77f Merge branch 'master' into forall 2023-02-11 14:42:13 -08:00
Vladimir Z Tomov feb4cc3561 unused var in serial 2023-02-10 10:42:04 -08:00
Vladimir Z Tomov f37fe72610 minor 2023-02-10 10:31:39 -08:00
Vladimir Z Tomov 8c5d0995e2 minor 2023-02-10 10:29:52 -08:00
Vladimir Z Tomov fd9899e0eb Removed code duplication. 2023-02-10 10:19:32 -08:00
camierjs 6e19dee026 CHANGELOG update 2023-02-09 16:50:05 -08:00
camierjs 96e70e365a Revert astyle 2023-02-09 16:47:18 -08:00
camierjs 84517f4357 Cleanup 2023-02-09 16:33:45 -08:00
camierjs cd2b1355e2 Bring back MFEM_FORALL for backward compatibility 2023-02-09 16:17:23 -08:00
Tzanio Kolev 9ea32e32f1 Merge branch 'master' into hdiv-solvers-miniapp 2023-02-09 10:20:38 -08:00
Tzanio Kolev d2ff3481eb Merge branch 'master' into tmopupdate-geomparam 2023-02-09 10:20:18 -08:00
Vladimir Z Tomov 986fda04f4 consolidated the updateAftermeshChange function. 2023-02-08 18:46:03 -08:00
Vladimir Z Tomov c301918179 Moved UpdateDiscreteTC() to the class TMOP_Integrator. 2023-02-08 18:14:52 -08:00
camierjs 018d5cfb8b Debugging lambdas in mfem::forall 2023-02-08 15:03:34 -08:00
Will Pazner a21d9b4895 Support non-nodal basis types in ChangeOfBasis_RT 2023-02-07 14:45:08 -08:00
Will Pazner 4a0a0e9d25 Handle non-nodal basis in ChangeOfBasis_L2 2023-02-07 14:29:49 -08:00
Tzanio Kolev e2b603a676 Merge branch 'master' into sjg/superlu-solver-dev 2023-02-06 11:11:31 -08:00
Tzanio Kolev 96ed6e24af Merge branch 'master' into tmopupdate-geomparam 2023-02-06 11:08:24 -08:00
Tzanio Kolev fbeb31ffd0 Merge branch 'master' into dpg-miniapp 2023-02-06 11:01:36 -08:00
Vladimir Z Tomov 6e52464aad Merge branch 'master' into tmop-code-improve 2023-02-03 15:56:24 -08:00
Socratis Petrides cd6a3fc0bd Merge branch 'master' into dpg-miniapp 2023-02-03 08:21:22 -08:00
Socratis Petrides 94182022c0 more minor edits 2023-02-02 11:42:26 -08:00
Socratis Petrides e815461511 Mark's comments 2023-02-01 15:50:36 -08:00
Will Pazner da802fc1ca Construct diagonal matrix directly on device 2023-01-31 16:55:36 -08:00
Socratis Petrides cb589a65d3 style hooke/kernels 2023-01-31 11:55:23 -08:00
Socratis Petrides 00b39c6490 Merge branch 'master' into dpg-miniapp 2023-01-30 11:34:28 -08:00
Socratis Petrides ef820a6f85 additional minor edits 2023-01-27 16:10:11 -08:00
Will Pazner 968858dec2 Better handle variable L2 coefficients in Darcy mode HdivSaddlePointSolver 2023-01-27 12:45:06 -08:00
Will Pazner 65b6aa3a86 Add DGMassInverse::MultTranspose 2023-01-27 12:16:07 -08:00
Will Pazner d41f5d8f04 Improve HdivSaddlePointSolver comments 2023-01-26 20:46:24 -08:00
Will Pazner 227a3c2c98 Add H(div) saddle-point solver miniapps
Included are grad-div and Darcy/Poisson miniapps.
2023-01-26 19:19:11 -08:00
Will Pazner 7a7355643a Parameterize lor_mms coefficients using std::function 2023-01-26 19:17:36 -08:00
Will Pazner 6d58074dd4 Make ElementRestriction low-level array accessors public 2023-01-26 19:17:15 -08:00
Socratis Petrides ce3f20150e typo 2023-01-26 14:48:44 -08:00
Socratis Petrides ff73632efb resolving changelog conflicts 2023-01-26 14:44:01 -08:00
Socratis Petrides f811107ea2 additional edits from reviews 2023-01-26 14:42:12 -08:00
Ketan Mittal ce7735ebc4 make style 2023-01-25 10:18:54 -08:00
Ketan Mittal 708b655c09 merge and resolve conflicts 2023-01-25 10:09:45 -08:00
Tobias Duswald 07a65326e8 Add sample runs to main.cc and fix numbering 2023-01-22 20:49:05 +01:00
Tobias Duswald 9eef312a07 Update README after Brendan's review
* fix typos
* add talk from MFEM workshop
* add Lindgern SPDE reference
* Format equations for GitHub markdown
2023-01-22 20:43:19 +01:00
Vladimir Z Tomov 72f51f34eb Updated the handling of PrintLevel in the miniapps. 2023-01-17 17:27:26 -08:00
Sebastian Grimberg 55cd18d8b0 make style 2023-01-12 10:52:29 -08:00
Sebastian Grimberg 8969d4544d Fix missed transpose application 2023-01-12 10:19:55 -08:00
Sebastian Grimberg 3990c48d70 Build process fixes for SuperLU 2023-01-11 14:34:47 -08:00
Stowell, Mark L 6d52f111d2 Merge remote-tracking branch 'origin/master' into mesh-group-doc-dev
# Conflicts:
#	mesh/mesh.hpp
2023-01-11 16:16:22 -05:00
Sebastian Grimberg eee300bef4 Build process fixes for MUMPS
To avoid the issue of missing definitions in config.hpp in the future, synchronize GNU make and CMake config.hpp files.
2023-01-11 08:49:08 -08:00
Socratis Petrides 9c2956c207 Merge branch 'master' into dpg-miniapp 2023-01-10 11:18:55 -08:00
Sebastian Grimberg 7451f551aa Add tests and update examples 2023-01-10 10:59:24 -08:00
Sebastian Grimberg 09ee98c2bf Update MUMPS solver interface: 64-bit index support and multiple RHS 2023-01-10 10:59:16 -08:00
Sebastian Grimberg 95e1e5e4d8 Add tests and update examples 2023-01-10 10:57:42 -08:00
Sebastian Grimberg 33b40b05d2 Update SuperLU solver: 64-bit index support and multiple RHS
Don't allow change in number of RHS for a single SuperLU solver.
2023-01-10 10:57:35 -08:00
Socratis Petrides c1493c0063 restructuring exact solution functions for better efficiency 2023-01-03 17:20:50 -08:00
Tzanio Kolev 26ec509afb Merge branch 'master' into dpg-miniapp 2022-12-28 10:18:11 -08:00
Socratis Petrides 6e55899f7f changes from code reviews 2022-12-21 14:23:59 -08:00
Socratis Petrides 532430bb73 addressing review comments 2022-12-20 16:24:05 -08:00
Socratis Petrides 1b492576e1 fix deprecated warnings 2022-12-20 13:58:27 -08:00
Socratis Petrides f733f7f20e Merge branch 'master' into dpg-miniapp 2022-12-20 12:37:17 -08:00
Socratis Petrides c0c518a15d Fix failed run by increasing integration order in the PML 2022-12-20 12:36:55 -08:00
Tzanio Kolev bb3865de93 Merge branch 'master' into dpg-miniapp 2022-12-13 11:51:12 -08:00
Socratis Petrides feb4d4168e Merge branch 'master' into dpg-miniapp 2022-11-28 15:07:52 -08:00
Socratis Petrides 7be8636bbd style 2022-11-22 16:02:58 -08:00
Socratis Petrides 23aee7d282 check if dim>1 in examples codes 2022-11-22 16:02:15 -08:00
Socratis Petrides b68d63bf64 addressing reviewers comments 2022-11-22 16:01:50 -08:00
Socratis Petrides b4b2b7fae8 Merge branch 'GradToCurl2D-fix' into dpg-miniapp 2022-11-21 20:37:09 -08:00
Socratis Petrides effb657df6 Merge branch 'GradToCurl2D-fix' into dpg-miniapp 2022-11-21 17:14:53 -08:00
Socratis Petrides 17cdb2d126 Merge branch 'master' into dpg-miniapp 2022-11-21 17:14:23 -08:00
jelotz 9c3bed148d Two typos 2022-11-07 09:40:15 +01:00
Socratis Petrides 54f37912bb fix small bug with inhomogeneous bc 2022-11-04 11:58:30 -07:00
Socratis Petrides ceab14915d fix makefile 2022-11-03 17:26:29 -07:00
jelotz 20eb64d8cf make style and more explanation on the choice of weight 2022-11-03 17:40:55 +01:00
jelotz 25f8deb432 Fixed weight problem 2022-11-03 17:37:05 +01:00
jelotz 3874ccd45d Apparantly the routine in FindMaxima did not work for 1 element. I applied a quick fix for now. Unsure if this is good enough. 2022-11-03 17:02:13 +01:00
jelotz 74e92bf60b Restructured example 2022-11-03 14:34:17 +01:00
jelotz 0313c718d8 more documentation 2022-11-03 12:16:20 +01:00
jelotz 59fbbe08fa Added documentation, some style 2022-11-03 12:08:38 +01:00
jelotz e31bfca43b Applied first set of suggestions by dylan-copeland 2022-11-03 10:27:56 +01:00
jelotz ede8ab9a0b removed extra line 2022-11-03 10:09:33 +01:00
Tobias Duswald b63c472c41 Fix for possible access to uninitialized memory 2022-10-28 11:59:16 +01:00
Tobias Duswald 3d005fd317 Fix sparsity pattern for mass and stiffness 2022-10-28 11:57:04 +01:00
Tobias Duswald 69b6a81927 Fix memory leak 2022-10-28 11:53:13 +01:00
Tobias Duswald 368cee4ca4 Rename files solvers* to sped_solver* 2022-10-28 11:48:28 +01:00
Tobias Duswald ff50cded2a Rename miniapp "materials" -> "spde" 2022-10-28 11:42:35 +01:00
Tobias Duswald 375af049b5 Move Theta and b computation to solver
Additionally update format with clang-format
2022-10-28 11:30:36 +01:00
Tobias Duswald 38af839dac Add 2D example to README 2022-10-28 10:20:03 +01:00
Tobias Duswald 93ce8503c8 Change structure of main to allow 2D meshes 2022-10-28 10:18:31 +01:00
Socratis Petrides b4301c01f2 minor comments edits 2022-10-20 15:24:13 -07:00
Socratis Petrides cea8d9f56a bug in static-cond appeared for primal dpg 2022-10-13 11:45:35 -07:00
Socratis Petrides b1a34c252c changelog 2022-10-06 17:37:38 -07:00
Socratis Petrides c9259b989f style 2022-10-06 15:36:30 -07:00
Socratis Petrides 3eef5077d5 introduce enums for dpg fespaces 2022-10-06 15:35:56 -07:00
Socratis Petrides 77a4e2d938 small fix in complex static cond 2022-10-06 15:35:34 -07:00
Socratis Petrides f1f2fd2b4f add paraview clean 2022-10-06 15:35:14 -07:00
Socratis Petrides 669c536e57 update gitignore 2022-10-05 19:50:34 -07:00
Socratis Petrides 69c5d718e6 switching to std::abs 2022-10-05 19:22:56 -07:00
Socratis Petrides 626b40807a fix paths for cmake 2022-10-05 19:00:14 -07:00
Socratis Petrides d5098095bd fix cmake test example 2022-10-05 16:41:23 -07:00
Socratis Petrides 9f663698e0 cmake dublicate target name fix 2022-10-05 15:33:41 -07:00
Tobias Duswald 5609a728ce Fix for CI 2022-10-05 20:31:28 +02:00
Tobias Duswald 084f9718f0 Fix typos 2022-10-05 19:15:54 +02:00
Tobias Duswald 6aa82047b4 Remove python visualization 2022-10-05 19:02:50 +02:00
Tobias Duswald 215ae6d2d5 Update README 2022-10-05 18:58:12 +02:00
Tobias Duswald 0540c8608c Update main script 2022-10-05 18:51:16 +02:00
Tobias Duswald c7019738ee Minor changes for boundaries in solver 2022-10-05 18:50:33 +02:00
Tobias Duswald 03eca785cf Add boundary integration for verification 2022-10-05 18:49:19 +02:00
Socratis Petrides 3e21335d46 cmake fix 2022-10-04 18:12:07 -07:00
Socratis Petrides 3bdb9c74e8 fix mesh paths 2022-10-04 18:08:16 -07:00
Socratis Petrides fa4a285e17 add missing cmakelist file 2022-10-04 18:02:08 -07:00
Socratis Petrides 1d1dc02349 fix test runs 2022-10-04 17:48:04 -07:00
psocratis 02a0046b6e applying make style to miniapps subdirs 2022-10-04 17:02:46 -07:00
psocratis 350693b78a cleaning up makefile 2022-10-04 17:02:06 -07:00
psocratis 014fa18595 rearranging directories 2022-10-04 17:01:33 -07:00
Socratis Petrides 087d840d4f rearranging some code 2022-10-03 17:47:36 -07:00
Socratis Petrides 801c1c2f70 switching to manual RAP 2022-10-03 17:36:28 -07:00
Socratis Petrides 2c91da029a another built bug 2022-10-03 17:08:53 -07:00
Socratis Petrides a3583842d8 remove unused files 2022-10-03 16:18:36 -07:00
Socratis Petrides e29a3357a7 fix serial built in static_cond 2022-10-03 16:17:17 -07:00
Socratis Petrides a336dfcd19 fixing serial built in complexstaticcond 2022-10-03 16:02:46 -07:00
Socratis Petrides 2f6fd3e90c fixing l-shape problem 2022-10-02 15:41:00 -07:00
Socratis Petrides 0ac0a2d23f makefile fix 2022-10-02 15:41:00 -07:00
Socratis Petrides 7c0f6c5aca minor-add paraview option 2022-10-02 15:41:00 -07:00
Socratis Petrides d1126cb6aa paraview option 2022-10-02 15:41:00 -07:00
Socratis Petrides 33c1c0dafe cleaning up acoustics and maxwell parallel examples 2022-10-02 15:41:00 -07:00
Socratis Petrides e5472c17d9 cleaning up pml implementation 2022-10-02 15:41:00 -07:00
Socratis Petrides 4e26c830d7 fixing printing in real examples 2022-10-02 15:41:00 -07:00
Socratis Petrides d03399f574 maxwell dpg-pml bug fixes 2022-10-02 15:41:00 -07:00
Socratis Petrides 603d02a46b add microwave mesh 2022-10-02 15:41:00 -07:00
Socratis Petrides 38cf7ab8fa merge pml maxwell implementation to pmaxwell. 2022-10-02 15:41:00 -07:00
Socratis Petrides 79377fbf74 simplify pml functions 2022-10-02 15:41:00 -07:00
Socratis Petrides 42fa6194ce fix bug in pml-adjoint graph norm in acoustics 2022-10-02 15:41:00 -07:00
Socratis Petrides acc22b1925 finalizing acoustics parallel example 2022-10-02 15:41:00 -07:00
Socratis Petrides 4ad62c7037 cleaning up pml 2022-10-02 15:41:00 -07:00
Socratis Petrides 1276a71c4d check if matrices are stored for residual computation 2022-10-02 15:41:00 -07:00
Socratis Petrides 1508dd69c8 more changes in parallel acoustics 2022-10-02 15:41:00 -07:00
Socratis Petrides 3f5abb92b7 simplify PML classes 2022-10-02 15:41:00 -07:00
Socratis Petrides d8c98a6291 fix makefile 2022-10-02 15:41:00 -07:00
Socratis Petrides a9034da4ad cleaning up acoustics and maxwell serial examples 2022-10-02 15:41:00 -07:00
Socratis Petrides 6628ba8b72 cleaning up real examples 2022-10-02 15:41:00 -07:00
Socratis Petrides 35ff0e4fc4 minor 2022-10-02 15:41:00 -07:00
Socratis Petrides 1b0b3dfd43 switch to DSmoother 2022-10-02 15:41:00 -07:00
Socratis Petrides 5ff2d6ac5c cleaning up convection-diffusion examples 2022-10-02 15:41:00 -07:00
Socratis Petrides 907c2ceca5 cleaning up diffusion examples 2022-10-02 15:41:00 -07:00
Socratis Petrides 58a311e8e3 fixing makefile to include miniapps-common lib 2022-10-02 15:41:00 -07:00
Socratis Petrides 3d7ba1e770 static_cond flag in AMR 2022-10-02 15:41:00 -07:00
Socratis Petrides e74432b53a fixing static cond flag 2022-10-02 15:41:00 -07:00
Socratis Petrides 36d0405efa parallel AMR diffusion l-shape benchmark cleanup 2022-10-02 15:41:00 -07:00
Socratis Petrides 813ed1e27a removing graph-norm from diffusion. Cleanup 2022-10-02 15:41:00 -07:00
Socratis Petrides 8415e3e692 cleanup serial diffusion example 2022-10-02 15:41:00 -07:00
Socratis Petrides 9e3428816a setting up 3 pml acoustics problems. Still needs a bit cleanup 2022-10-02 15:41:00 -07:00
Socratis Petrides deb23168a8 AMR acoustics example with pml 2022-10-02 15:41:00 -07:00
Socratis Petrides affdf1c002 amr with maxwell and pml 2022-10-02 15:40:59 -07:00
Socratis Petrides a8fa68a031 shadow variable 2022-10-02 15:40:59 -07:00
Socratis Petrides 2425dce5fa fix makefile 2022-10-02 15:40:59 -07:00
Socratis Petrides 89a8511a5d indefinite maxwell implementation 2022-10-02 15:40:59 -07:00
Socratis Petrides 6850af07db acoustics implementation 2022-10-02 15:40:59 -07:00
Socratis Petrides c7cb80f5be complex static cond 2022-10-02 15:40:59 -07:00
Socratis Petrides aaaa9356f0 adding dpg complexweakform (serial and parallel) 2022-10-02 15:40:59 -07:00
Socratis Petrides 6430763cd9 make sure triangular meshes are treated as non-conforming as well 2022-10-02 15:40:59 -07:00
Socratis Petrides 5c2415fa77 adding benchmark examples in parallel convection diffusion with AMR 2022-10-02 15:40:59 -07:00
Socratis Petrides 5805129371 convection diffusion problems 2022-10-02 15:40:59 -07:00
Socratis Petrides a6aa1fb599 fixing shadow variables 2022-10-02 15:40:59 -07:00
Socratis Petrides 64b63251d2 par diffusions l-shape benchmark 2022-10-02 15:30:14 -07:00
Socratis Petrides d011e99076 parallel DPG weak form 2022-10-02 15:30:14 -07:00
Socratis Petrides 5fc7059eb4 diffusion l-shape benchmark with AMR 2022-10-02 15:30:14 -07:00
Socratis Petrides 0b2f7aa0d6 dpg diffusion example 2022-10-02 15:30:14 -07:00
Socratis Petrides 9b3353753c dpg static cond 2022-10-02 15:30:14 -07:00
Socratis Petrides c622165124 add dpg weakform 2022-10-02 15:30:14 -07:00
Socratis Petrides abbf3b37c0 fix wrong signature 2022-10-02 15:30:14 -07:00
Socratis Petrides ee169abc65 dpg trace integrators 2022-10-02 15:30:14 -07:00
Socratis Petrides a50c5b361d Setup directory stracture 2022-10-02 15:30:13 -07:00
Jacob Lotz 96e7736d27 Error should be absolute 2022-09-29 14:56:55 +02:00
Jacob Lotz faa6b04e01 more prettify 2022-09-29 14:29:55 +02:00
Jacob Lotz d58c714a18 prettify 2022-09-29 14:24:43 +02:00
Jacob Lotz 6efb7a32b6 make style 2022-09-29 13:59:05 +02:00
Jacob Lotz d9596f2b90 Updated float comparison. Removed relative error and shortcuts.
Using a relative error does not really make sense here. We are comparing two knotvectors which should be very equal. Due to several flips of the knotvector it is possible that a round off error is induced. This should not be smaller than machine precission.
2022-09-29 13:53:41 +02:00
Jacob Lotz faedaf40af removed old debug statement 2022-09-28 18:19:57 +02:00
Jacob Lotz 267c31364b Streamlined rotation function 2022-09-28 17:35:45 +02:00
Jacob Lotz 056d48d10d removed comments 2022-09-28 16:18:08 +02:00
Jacob Lotz d399b500d2 make style 2022-09-28 14:16:29 +02:00
Jacob Lotz 15a2e635ee Improved documentation 2022-09-28 14:10:55 +02:00
Jacob Lotz f498fcb148 Improved naming 2022-09-28 12:04:48 +02:00
Jacob Lotz 56c73a0b86 small bug fix 2022-09-28 12:04:37 +02:00
Jacob Lotz cf28577291 First version of float compares 2022-09-28 11:47:03 +02:00
Jacob Lotz a409702288 Added source of curve interpolation function 2022-09-27 11:36:11 +02:00
Jacob Lotz 0d14fdb231 make style 2022-09-26 17:35:17 +02:00
Jacob Lotz 829b9283e7 Updated makefile to account for interpolation example 2022-09-26 17:26:45 +02:00
Jacob Lotz 64e723e054 Small typo fix 2022-09-26 17:26:27 +02:00
Jacob Lotz 6a1d2885df Added example/miniapp to show usage of curveinterpolation 2022-09-26 17:23:37 +02:00
Jacob Lotz be5f84955d Fix bug in degree elevate 2022-09-22 16:01:32 +02:00
Jacob Lotz 0fb6da6543 Implement two curvefitting functions FindMaxima and FintInterpolant. 2022-09-22 16:00:32 +02:00
Jacob Lotz e10bf30ac2 make style 2022-09-21 17:28:39 +02:00
Jacob Lotz 3fe56e5b4e Implementation of a rotation option for 2D NURBS patch. Similar to the 3D option. 2022-09-21 17:27:23 +02:00
Tobias Duswald 644684d80c WIP fix for lifting scheme 2022-09-20 18:32:11 +02:00
Tobias Duswald f266359d73 Add comment to helper_gf and zero initialize it 2022-09-20 18:01:59 +02:00
Tobias Duswald f10e340966 Enforce BC in combined matrix
[Bug fix]
2022-09-20 17:43:53 +02:00
Tobias Duswald 9635e8e3df Change conversion from u to b
The integer order PDE was solved iteratively
A u_1 = b
A u_2 = u_1
...
Previously we used the mass matrix to convert the GridFunction to an
appropriate RHS. We now switch to using a GridFunctionCoefficient.
2022-09-20 15:57:00 +02:00
Tobias Duswald 13cd4cae24 Make interface more specific (Par...) 2022-09-20 15:20:54 +02:00
Ketan Mittal 549111392b initial commit 2022-09-18 18:06:26 -06:00
Stowell, Mark L 9b12b4dc56 Organizing and augmenting Mesh documentation 2022-09-16 16:46:40 -07:00
Tobias Duswald 698485749a Add support for a set of boundary conditions 2022-08-26 15:36:24 -07:00
Tobias Duswald be4015d222 Attempt to fix math mode in README 2022-08-24 18:33:35 -07:00
Tobias Duswald e0f771a4c6 Add command line arg for level set 2022-08-24 18:26:25 -07:00
Tobias Duswald 02ed8641d0 Update README 2022-08-24 18:23:56 -07:00
Tobias Duswald 0c20821cfc Add LevelSetTransformer and Visualization 2022-08-24 18:19:31 -07:00
Tobias Duswald 9814864f28 Add Transformer class to get uniform field 2022-08-24 17:58:11 -07:00
Tobias Duswald 9d457ad670 Rename synthetic_materials to main (simplicity) 2022-08-23 18:36:55 -07:00
Tobias Duswald b714873261 Add copyright to files 2022-08-23 18:29:11 -07:00
Tobias Duswald 3962108b62 WIP Attempt to adapt Makefile 2022-08-23 18:18:22 -07:00
Tobias Duswald 733aaa60c1 Simplify include in Cmake build system 2022-08-23 18:17:51 -07:00
Tobias Duswald d0ed2eb707 Remove rational approximation in favor of ex33.h
Changes work with Cmake build system
2022-08-23 18:11:41 -07:00
Tobias Duswald f0693bd5ee Restructure solver for easier reuse 2022-07-29 16:13:01 -07:00
Tobias Duswald df1078ac01 Add documentation 2022-07-29 15:35:54 -07:00
Tobias Duswald 05295ed0dd Fix TDOF cout info 2022-07-29 15:33:15 -07:00
psocratis 3dd2304f5d changed vector construction 2022-07-29 04:53:27 -07:00
psocratis d733cde9a9 added makefile 2022-07-29 04:52:03 -07:00
Tobias Duswald f8fcbf7363 Add fixes and sync with RF repo 2022-07-26 19:48:40 -07:00
Tobias Duswald f7a570d084 Namespace fix 2022-07-18 16:03:01 -07:00
Tobias Duswald c65fdd13ba Fix visualization problem for GLVis 2022-07-18 15:11:31 -07:00
Tobias Duswald 29f0c58931 Remove header comments from cpp file 2022-07-18 15:09:42 -07:00
Tobias Duswald 6bc8fb1bd3 Restructure header / source 2022-07-18 14:34:02 -07:00
Tobias Duswald 98d4fe9cba Update solver to avoid repeated matrix assembly 2022-06-17 11:30:30 -07:00
Tobias Duswald 7e0b1461bb Outsource visualization to class 2022-06-09 19:52:13 -07:00
Tobias Duswald ebfc336c6c Remove debug output 2022-06-09 19:19:58 -07:00
Tobias Duswald 0af475f16d Introduce a solver class 2022-06-09 19:19:41 -07:00
Tobias Duswald 1abb180493 Copy supporting files to build folder 2022-06-09 15:31:12 -07:00
Tobias Duswald 73e146a736 Add visualization script for paraview 2022-06-09 14:33:52 -07:00
Tobias Duswald 64a7761a5f Add core mini-app 2022-06-09 14:33:52 -07:00
Tobias Duswald 154e0aec86 Add README (mini app description) 2022-06-09 14:33:52 -07:00
Tobias Duswald 5727e34e7e Add CMake for mini app 2022-06-09 14:33:52 -07:00
Tobias Duswald 08a20d5f55 Add header for utilities 2022-06-09 14:33:52 -07:00
e123740786 Copy the rational approximation from ex33
Co-authored-by: Keith <keith10@hiraku.llnl.gov>
Co-authored-by: Socratis Petrides <petrides1@llnl.gov>
2022-06-09 14:33:51 -07:00
Tobias Duswald 58cf61b20d Add classes for material topologies 2022-06-09 14:33:51 -07:00
Tobias Duswald cd01b76503 Register new mini app in CMake 2022-06-09 14:33:51 -07:00
Brody Richard Bassett 974222a4c9 Removed unused function. 2020-09-15 15:36:37 -07:00
Brody Richard Bassett 1aefb30c85 Merge branch 'master' into meshless-kernels 2020-09-15 15:30:34 -07:00
Brody Richard Bassett 1d9e2b406c Updated a few functions. 2020-08-27 13:16:36 -07:00
Brody Richard Bassett 239e8c03fe Removed changes to display-basis. 2020-08-26 15:37:10 -07:00
Brody Richard Bassett 4d122fb917 Restored examples overwritten by merge. 2020-08-26 15:35:40 -07:00
Brody Richard Bassett 37f02b1792 Added DomainGradLFIntegrator. 2020-08-26 15:29:37 -07:00
Brody Richard Bassett faee127fc3 Switched RK functions back to mono polynomials instead of Legendre. 2020-08-26 15:28:17 -07:00
Brody Richard Bassett 49534b1e01 Resolved some compilation errors. 2020-08-26 15:27:06 -07:00
Brody Richard Bassett 9ff8923e06 Finished adding compact RBFs, along with a few more kernels. 2020-08-26 15:25:53 -07:00
Brody Richard Bassett b534a29da9 Added first draft of compact support RBFs. 2020-08-26 15:24:52 -07:00
Brody Richard Bassett 227c5db7d5 Made smoothing parameter more invariant between kernels. 2020-08-26 15:23:50 -07:00
Brody Richard Bassett 7a7512ee2f Generalized the distance to be an arbitrary Lp norm. 2020-08-26 15:23:04 -07:00
Brody Richard Bassett 6e76fff419 Added a localized RBF. 2020-08-26 15:23:03 -07:00
Brody Richard Bassett 402f3bd06e Improved name for kernel fe collection. Fixed issues with thread safe version of kernels. 2020-08-26 15:23:03 -07:00
Brody Richard Bassett 2db465d846 Mirrored some of the interface from the L2_FECollection. 2020-08-26 15:23:03 -07:00
Brody Richard Bassett 3437c4b641 Updated finite elements to use nodes instead of separate matrix for positions. Added a first attempt at some face/vertix/edge information. 2020-08-26 15:23:02 -07:00
Brody Richard Bassett 4795a9ed44 Made the interface for meshless functions more user-friendly and removed memory allocation pitfalls. 2020-08-26 15:23:02 -07:00
Brody Richard Bassett a8438ce5c4 Upgraded example for kernel functions. 2020-08-26 15:23:02 -07:00
Brody Richard Bassett c846576049 Got RK derivatives working. 2020-08-26 15:22:45 -07:00
Brody Richard Bassett 5590670e11 Started switching over to native MFEM polynomials for corrections. 2020-08-26 15:21:26 -07:00
Brody Richard Bassett a87ed76081 Denoted scratch variables differently to prevent confusion with local function calls. 2020-08-26 15:21:25 -07:00
Brody Richard Bassett a42ea6f8ae Fixed issue with distance derivatives. 2020-08-26 15:21:25 -07:00
Brody Richard Bassett 5322781eec Switch from Array to C array for storage of dense matrices and vectors. 2020-08-26 15:21:07 -07:00
Brody Richard Bassett eddeb02121 Fixed 3d evaluations of polynomials and a few other bugs. 2020-08-26 15:20:05 -07:00
Brody Richard Bassett 6f81db97a9 Added more virtual destructors to kernel functions. 2020-08-26 15:16:28 -07:00
Brody Richard Bassett bafa730fd1 Changed destructors in kernel classes to be virtual. 2020-08-26 15:16:28 -07:00
Brody Richard Bassett 71df36d975 Added collection for kernel finite elements. 2020-08-26 15:16:28 -07:00
Brody Richard Bassett b034fdd364 Added a base class for kernel finite elements. Started adding a kernel FE collection. 2020-08-26 15:16:27 -07:00
Brody Richard Bassett 50f2625c94 Made the RBF automatically choose the correct dimension for the distance metric. 2020-08-26 15:16:27 -07:00
Brody Richard Bassett 20a8165db1 Added an additional distance measure. 2020-08-26 15:16:26 -07:00
Brody Richard Bassett b5216ac96e Added a few more RBFs. 2020-08-26 15:16:26 -07:00
Brody Richard Bassett 11ccbf19d2 Fixed compilation errors. 2020-08-26 15:16:26 -07:00
Brody Richard Bassett ac966979dd Finished adding the basics of radial basis functions and reproducing kernels. 2020-08-26 15:16:25 -07:00
Brody Richard Bassett 4c1e20325b Started adding radial basis functions and reproducing kernels as a finite element type. 2020-08-26 15:16:07 -07:00
320 changed files with 40675 additions and 15133 deletions
+8 -6
View File
@@ -162,7 +162,7 @@ jobs:
- name: get hypre
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os != 'windows-latest'
uses: mfem/github-actions/build-hypre@v2.2
uses: mfem/github-actions/build-hypre@v2.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
@@ -171,7 +171,7 @@ jobs:
- name: get hypre (Windows)
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os == 'windows-latest'
uses: mfem/github-actions/build-hypre@v2.2
uses: mfem/github-actions/build-hypre@v2.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
@@ -190,7 +190,7 @@ jobs:
- name: install metis
if: matrix.mpi == 'par' && matrix.os != 'windows-latest' && steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.2
uses: mfem/github-actions/build-metis@v2.4
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
@@ -217,7 +217,7 @@ jobs:
# MFEM build and test
- name: build
uses: mfem/github-actions/build-mfem@v2.3
uses: mfem/github-actions/build-mfem@v2.4
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
with:
@@ -263,13 +263,15 @@ jobs:
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os != 'ubuntu-latest'
run: |
CTEST_CONFIG="Release"
cd ${{ env.MFEM_TOP_DIR }}/build && ctest --output-on-failure -C ${CTEST_CONFIG}
cd ${{ env.MFEM_TOP_DIR }}/build && \
ctest --output-on-failure -C ${CTEST_CONFIG} || \
ctest --rerun-failed --output-on-failure -C ${CTEST_CONFIG}
shell: bash
# Code coverage (process and upload reports)
- name: codecov
if: matrix.codecov == 'YES'
uses: mfem/github-actions/upload-coverage@v2.2
uses: mfem/github-actions/upload-coverage@v2.4
with:
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
project_dir: ${{ env.MFEM_TOP_DIR }}
+3 -3
View File
@@ -57,7 +57,7 @@ jobs:
- name: Get Hypre
if: steps.hypre-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-hypre@v2.2
uses: mfem/github-actions/build-hypre@v2.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
@@ -72,14 +72,14 @@ jobs:
- name: Install Metis
if: steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.2
uses: mfem/github-actions/build-metis@v2.4
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
# MFEM build and test
- name: build-mfem
uses: mfem/github-actions/build-mfem@v2.2
uses: mfem/github-actions/build-mfem@v2.4
with:
os: ${{ runner.os }}
target: opt
+70
View File
@@ -0,0 +1,70 @@
# Copyright (c) 2010-2023, 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.
name: "Sanitizer"
permissions:
actions: write
on:
push:
branches:
- master
- next
pull_request:
workflow_dispatch:
jobs:
Serial:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: MFEM Checkout
uses: actions/checkout@v3
with:
path: mfem
- name: MFEM Build
uses: mfem/github-actions/build-mfem@v2.4
with:
os: ${{ runner.os }}
target: opt
mpi: seq
hypre-dir: unused-hypre-dir
metis-dir: unused-metis-dir
mfem-dir: mfem
build-system: make
library-only: false
config-options:
CXX="clang++-14"
CXXFLAGS="-g -O1 -std=c++11
-fsanitize=address
-fno-omit-frame-pointer
-fsanitize-address-use-after-scope"
- name: MFEM Info
working-directory: mfem
run: make info
- name: MFEM Sanitize
working-directory: mfem
run:
ASAN_OPTIONS="detect_leaks=1,
strict_init_order=1,
strict_string_checks=1,
check_initialization_order=1,
detect_stack_use_after_return=1"
make test
+20
View File
@@ -29,6 +29,7 @@ CMakeFiles/
config/_config.hpp
config/config.mk
config/sample-runs-build.log
config/user.cmake
config/user.mk
doc/CodeDocumentation.conf
doc/CodeDocumentation.html
@@ -214,6 +215,7 @@ miniapps/meshing/pmesh-fitting
miniapps/meshing/minimal-surface
miniapps/meshing/pminimal-surface
miniapps/meshing/polar-nc
miniapps/meshing/mesh-quality
miniapps/meshing/mobius-strip.mesh
miniapps/meshing/klein-bottle.mesh
miniapps/meshing/toroid-*.mesh
@@ -316,12 +318,28 @@ miniapps/solvers/ParaView
miniapps/solvers/mesh.*
miniapps/solvers/sol.*
miniapps/hdiv-linear-solver/darcy
miniapps/hdiv-linear-solver/grad_div
miniapps/parelag/MultilevelHcurlHdivSolver
miniapps/parelag/*.mesh
miniapps/multidomain/multidomain
miniapps/hooke/hooke
miniapps/dpg/diffusion
miniapps/dpg/pdiffusion
miniapps/dpg/convection-diffusion
miniapps/dpg/pconvection-diffusion
miniapps/dpg/acoustics
miniapps/dpg/pacoustics
miniapps/dpg/maxwell
miniapps/dpg/pmaxwell
miniapps/dpg/ParaView
miniapps/spde/generate_random_field
miniapps/spde/ParaView
# Unit test binary and outputs
tests/unit/output_meshes
tests/unit/unit_tests
@@ -334,6 +352,8 @@ tests/unit/tmop_pa_tests_*
tests/unit/ptmop_pa_tests_*
tests/unit/ceed_tests
tests/unit/debug_device_tests
tests/unit/parallel_in_serial.mesh
tests/unit/parallel_in_serial.gf
# Benchmark binaries
tests/benchmarks/bench_ceed
+6 -10
View File
@@ -22,12 +22,10 @@
date
echo "Waiting to acquire lock on '$PWD/autotest.lock' ..."
# try to get an exclusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# every 5 seconds; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
while ! flock -n 9; do
sleep 5
done
echo "Acquired lock on '$PWD/autotest.lock'"
date
@@ -57,12 +55,10 @@
date
echo "Waiting to acquire lock on '$PWD/autotest.lock' ..."
# try to get an exclusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# every 5 seconds; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
while ! flock -n 9; do
sleep 5
done
echo "Acquired lock on '$PWD/autotest.lock'"
date
+3 -5
View File
@@ -47,12 +47,10 @@ setup_baseline:
date
echo "Waiting to acquire lock on '$PWD/autotest.lock' ..."
# try to get an exclusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# every 5 seconds; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
while ! flock -n 9; do
sleep 5
done
echo "Acquired lock on '$PWD/autotest.lock'"
date
+7 -11
View File
@@ -35,13 +35,11 @@ setup:
(
date
echo "Waiting to acquire lock on '$PWD/mfem-data.lock' ..."
# try to get an exclusive lock on fd 9 (mfem-data.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# try to get an exclusive lock on fd 9 (mfem-data.lock) repeating the
# try every 5 seconds; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
while ! flock -n 9; do
sleep 5
done
echo "Acquired lock on '$PWD/mfem-data.lock'"
date
@@ -69,12 +67,10 @@ setup:
date
echo "Waiting to acquire lock on '$PWD/autotest.lock' ..."
# try to get an exclusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# every 5 seconds; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
while ! flock -n 9; do
sleep 5
done
echo "Acquired lock on '$PWD/autotest.lock'"
date
+3 -3
View File
@@ -14,14 +14,14 @@ stages:
- build_and_test
- report
opt_mpi_cuda_xl_16_1_1_8:
opt_mpi_cuda_xl_16_1_1_12:
variables:
SPEC: "%xl@16.1.1.8 +mpi +cuda cuda_arch=70"
SPEC: "%xl@16.1.1.12 +mpi +cuda cuda_arch=70"
extends: .build_and_test_on_lassen
opt_mpi_cuda_hypre_cuda_xl:
variables:
SPEC: "%xl@16.1.1.8 +mpi +cuda cuda_arch=70 ^hypre+cuda~shared cuda_arch=70"
SPEC: "%xl@16.1.1.12 +mpi +cuda cuda_arch=70 ^hypre+cuda~shared cuda_arch=70"
extends: .build_and_test_on_lassen
# Jobs report
+11 -9
View File
@@ -51,6 +51,8 @@ cleanup:
script:
- echo "BUILD_ROOT=${BUILD_ROOT}"
- rm -rf "${BUILD_ROOT}" || true
- echo "CI_PROJECT_DIR=${CI_PROJECT_DIR}"
- make -C "${CI_PROJECT_DIR}" distclean
report_baseline:
extends: [.on_quartz]
@@ -66,12 +68,10 @@ report_baseline:
date
echo "Waiting to acquire lock on '$PWD/autotest.lock' ..."
# try to get an exclusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# every 5 seconds; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
while ! flock -n 9; do
sleep 5
done
echo "Acquired lock on '$PWD/autotest.lock'"
date
@@ -82,12 +82,14 @@ report_baseline:
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}
# We create an autotest-email.html file, because that's how we signal that there was a diff (temporary).
if [[ -f ${rundir}/${BASELINE_TEST}.err ]]; then
cp ${rundir}/${BASELINE_TEST}.err ${rundir}/autotest-email.html
fi
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 ]] || \
[[ -f ${rundir}/${BASELINE_TEST}-${SYS_TYPE}.diff ]]; then
cp ${rundir}/pipeline.txt ${rundir}/autotest-email.html
fi
msg="GitLab CI log for ${BASELINE_TEST} on ${MACHINE_NAME} ($(date +%Y-%m-%d))"
if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
git pull && \
+14 -14
View File
@@ -27,39 +27,39 @@ allocate_resource:
timeout: 6h
# GitLab jobs for the Quartz machine at LLNL
debug_ser_gcc_6_1_0:
debug_ser_gcc_10:
variables:
SPEC: "%gcc@6.1.0 +debug~mpi"
SPEC: "%gcc@10.3.1 +debug~mpi"
extends: .build_and_test_on_quartz
debug_par_gcc_6_1_0:
debug_par_gcc_10:
variables:
SPEC: "%gcc@6.1.0 +debug+mpi"
SPEC: "%gcc@10.3.1 +debug+mpi"
extends: .build_and_test_on_quartz
opt_ser_gcc_6_1_0:
opt_ser_gcc_10:
variables:
SPEC: "%gcc@6.1.0 ~mpi"
SPEC: "%gcc@10.3.1 ~mpi"
extends: .build_and_test_on_quartz
opt_par_gcc_6_1_0:
opt_par_gcc_10:
variables:
SPEC: "%gcc@6.1.0"
SPEC: "%gcc@10.3.1"
extends: .build_and_test_on_quartz
opt_par_gcc_6_1_0_sundials:
opt_par_gcc_10_sundials:
variables:
SPEC: "%gcc@6.1.0 +sundials"
SPEC: "%gcc@10.3.1 +sundials"
extends: .build_and_test_on_quartz
opt_par_gcc_6_1_0_petsc:
opt_par_gcc_10_petsc:
variables:
SPEC: "%gcc@6.1.0 +petsc ^petsc+mumps~superlu-dist"
SPEC: "%gcc@10.3.1 +petsc ^petsc+mumps~superlu-dist"
extends: .build_and_test_on_quartz
opt_par_gcc_6_1_0_pumi:
opt_par_gcc_10_pumi:
variables:
SPEC: "%gcc@6.1.0 +pumi"
SPEC: "%gcc@10.3.1 +pumi"
extends: .build_and_test_on_quartz
# Release
+19 -32
View File
@@ -42,47 +42,34 @@ fi
# post
mkdir ${artifacts_path}
if [[ -s ${glob_err} ]]
then
echo "ERROR during ${BASELINE_TEST} execution";
echo "Here is the ${glob_err} file content";
cat ${glob_err}
cp ${glob_err} ${artifacts_path}/${glob_err}
exit 1;
elif [[ ! -f ${base_patch} && ! -f ${base_out} ]]
then
echo "Something went WRONG in ${BASELINE_TEST}:";
echo "Either ${base_patch} or ${base_out} should exists";
exit 1;
elif [[ -f ${base_patch} ]]
then
echo "${BASELINE_TEST}: Differences found, patch generated"
cp ${base_patch} ${artifacts_path}/${base_patch}
elif [[ -f ${base_out} ]]
then
echo "${BASELINE_TEST}: Differences found, replacement file generated"
cp ${base_out} ${artifacts_path}/${base_out}
fi
status=0
if [[ -f ${BASELINE_TEST}.out ]]; then
cp ${BASELINE_TEST}.out ${artifacts_path}
fi
if [[ -s ${glob_err} ]]; then
echo "ERROR during ${BASELINE_TEST} execution"
echo "Here is the ${glob_err} file content"
cat ${glob_err}
cp ${glob_err} ${artifacts_path}/${glob_err}
status=1
fi
if [[ -f ${base_patch} ]]; then
echo "${BASELINE_TEST}: Differences found, patch generated"
cp ${base_patch} ${artifacts_path}/${base_patch}
elif [[ -f ${base_out} ]]; then
echo "${BASELINE_TEST}: Differences found, replacement file generated"
cp ${base_out} ${artifacts_path}/${base_out}
fi
# base_diff won't even exist if there is no difference.
if [[ -f ${base_diff} ]]
then
if [[ -f ${base_diff} ]]; then
echo "${BASELINE_TEST}: Relevant differences (filtered diff) ..."
cat ${base_diff}
cp ${base_diff} ${artifacts_path}/${base_diff}
# We create a .err file, because that's how we signal that there was a diff.
cp ${base_diff} ${artifacts_path}/gitlab-${BASELINE_TEST}-${MACHINE_NAME}.err
status=1
fi
if [[ ! -s ${base_diff} ]]
then
if [[ $status -eq 0 ]]; then
echo "${BASELINE_TEST}: PASSED"
true
else
echo "${BASELINE_TEST}: FAILED"
false
fi
exit $status
+61 -4
View File
@@ -11,14 +11,41 @@
Version 4.5.3 (development)
===========================
New and updated examples and miniapps
-------------------------------------
- Added a new miniapp, Mesh Quality, for evaluating mesh quality using size,
skewness, and aspect-ratio computed from the Jacobian of the transformation.
- Added a new miniapp for interface and boundary fitting to implicit domains
defined using level-set functions. See miniapps/meshing/pmesh-fitting.cpp
- Added new Discontinuous Petrov-Galerkin (DPG) miniapp which includes serial
and parallel examples for diffusion, convection-diffusion, acoustics and
Maxwell equations. The miniapp includes new classes such as (Par)DPGWeakForm,
(Par)ComplexDPGWeakForm and (Complex)BlockStaticCondensation. Three new
integrators are added in support of DPG systems: TraceIntegrator,
NormalTraceIntegrator and TangentTraceIntegrator.
- Added a new H(div) solvers miniapp in miniapps/hdiv-linear-solver,
demonstrating the use of a matrix-free saddle-point solver methodology,
suitable for high-order discretizations and for GPU acceleration. Examples
illustrating the solution of Darcy and grad-div problems are included.
- Added a random refinement option to the mesh-explorer miniapp to assist users
in experimenting with nonconforming meshes.
- Moved the distance solver methods from miniapps/shifted to miniapps/common.
Meshing improvements
--------------------
- Added new methods in the Mesh class to set and get attributes on NURBS patches
and patch boundaries.
New and updated examples and miniapps
-------------------------------------
- Added a miniapp pmesh-fitting in miniapps/meshing for interface and boundary fitting to implicit domains defined using level-set functions.
- Added HIP support to the SUNDIALS interface.
- Moved the distance solver methods from miniapps/shifted to miniapps/common.
- TMOP improvement: added asymptotically-balanced compound metrics 90, 94, 328,
338. Added the tmop-metric-magnitude tool for tracking how metrics change
under geometric perturbations.
Discretization improvements
---------------------------
@@ -27,6 +54,36 @@ Discretization improvements
- VectorFEBoundaryFluxLFIntegrator is now supported on device/GPU.
- Added support for p-refined meshes in FindPointsGSLIB.
- Added radial basis functions and reproducing kernels as alternatives to
polynomial functions. These are accessed through the LocalKernelFECollection.
Linear and nonlinear solvers
----------------------------
- Updated interface to MUMPS direct solver to support multiple right-hand
sides, block low-rank compression, builds using 64-bit integers, and other
improvements.
- Added an interface to the MKL Pardiso sparse direct solver developed by Intel.
This interface provides a serial (OpenMP shared memory) version of Pardiso for
use with SparseMatrix. This complements the existing parallel (MPI distributed
memory) version already available through the CPardiso MFEM integration.
Integrations, testing and documentation
---------------------------------------
- Added an address sanitizer GitHub action for a serial build/test on Ubuntu,
based on Clang/LLVM (https://clang.llvm.org/docs/AddressSanitizer.html).
Miscellaneous
-------------
- Improved lambda body debugging with the addition of mfem::forall functions.
These functions can take the place of the MFEM_FORALL macros, which have been
preserved for backwards compatibility.
- Reorganized files for bilinear form, linear form, and nonlinear form integrators
in the fem/integ/ subdirectory.
Version 4.5.2, released on March 23, 2023
=========================================
+13 -3
View File
@@ -82,7 +82,7 @@ if (MFEM_USE_CONDUIT OR
# * find_package(PETSc REQUIRED)
set(XSDK_ENABLE_C ON)
endif()
if (MFEM_USE_STRUMPACK)
if (MFEM_USE_STRUMPACK OR MFEM_USE_MUMPS)
# Just needed to find the MPI_Fortran libraries to link with
set(XSDK_ENABLE_Fortran ON)
endif()
@@ -317,6 +317,9 @@ if (MFEM_USE_SUNDIALS)
if (MFEM_USE_CUDA)
list(APPEND SUNDIALS_COMPONENTS NVector_Cuda)
endif()
if (MFEM_USE_HIP)
list(APPEND SUNDIALS_COMPONENTS NVector_Hip)
endif()
find_package(SUNDIALS REQUIRED ${SUNDIALS_COMPONENTS})
endif()
@@ -333,6 +336,7 @@ endif()
if (MFEM_USE_MUMPS)
if (MFEM_USE_MPI)
find_package(MUMPS REQUIRED mumps_common pord)
set(MFEM_MUMPS_VERSION ${MUMPS_VERSION})
else()
message(FATAL_ERROR " *** MUMPS requires that MPI be enabled.")
endif()
@@ -466,12 +470,18 @@ if (MFEM_USE_ADIOS2)
find_package(ADIOS2 REQUIRED)
endif()
# MKL CPardiso
if (MFEM_USE_MKL_CPARDISO)
if (MFEM_USE_MPI)
find_package(MKL_CPARDISO REQUIRED MKL_SEQUENTIAL MKL_LP64 MKL_MPI_WRAPPER)
endif()
endif()
# MKL Pardiso
if (MFEM_USE_MKL_PARDISO)
find_package(MKL_PARDISO REQUIRED MKL_SEQUENTIAL MKL_LP64)
endif()
# PARELAG
if (MFEM_USE_PARELAG)
find_package(PARELAG REQUIRED)
@@ -521,8 +531,8 @@ find_package(Threads REQUIRED)
set(MFEM_TPLS OPENMP HYPRE LAPACK BLAS SuperLUDist STRUMPACK METIS SuiteSparse
SUNDIALS PETSC SLEPC MUMPS AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB
NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
ADIOS2 CUBLAS CUSPARSE MKL_CPARDISO AMGX CALIPER CODIPACK BENCHMARK PARELAG
MPI_CXX HIP HIPSPARSE MOONOLITH BLITZ ALGOIM ENZYME)
ADIOS2 CUBLAS CUSPARSE MKL_CPARDISO MKL_PARDISO AMGX CALIPER CODIPACK
BENCHMARK PARELAG MPI_CXX HIP HIPSPARSE MOONOLITH BLITZ ALGOIM ENZYME)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
+3 -1
View File
@@ -121,6 +121,7 @@ The MFEM source code has the following structure:
├── fem
│ ├── ceed
│ ├── fe
│ ├── integ
│ ├── lor
│ ├── moonolith
│ ├── qinterp
@@ -136,6 +137,7 @@ The MFEM source code has the following structure:
│ ├── common
│ ├── electromagnetics
│ ├── gslib
│ ├── hdiv-linear-solver
│ ├── hooke
│ ├── meshing
│ ├── mtop
@@ -209,7 +211,7 @@ device/host memory manager.
- The main device-relevant classes and sources are:
+ [`Device`](https://docs.mfem.org/html/device_8hpp.html)
+ [`MemoryManager`](https://docs.mfem.org/html/mem_manager_8hpp.html)
+ the [`MFEM_FORALL`](https://docs.mfem.org/html/forall_8hpp.html) macro
+ the [`mfem::forall`](https://docs.mfem.org/html/forall_8hpp.html) function
+ the [`cuda.hpp`](https://docs.mfem.org/html/cuda_8hpp.html) and [`occa.hpp`](https://docs.mfem.org/html/occa_8hpp.html) files
#### Utilities, building and documentation
+6 -2
View File
@@ -628,9 +628,13 @@ The specific libraries and their options are:
both MPI and hypre.
If MFEM_USE_CUDA is enabled, we expect that SUNDIALS is built with support
for CUDA.
URL: http://computation.llnl.gov/projects/sundials/sundials-software
If MFEM_USE_HIP is enabled, we expect that SUNDIALS is built with support
for HIP.
URL: http://computing.llnl.gov/projects/sundials/sundials-software
Options: SUNDIALS_OPT, SUNDIALS_LIB.
Versions: SUNDIALS >= 5.0.0, SUNDIALS >= 5.4.0 for CUDA support.
Versions: SUNDIALS >= 5.0.0,
SUNDIALS >= 5.4.0 for CUDA support, and
SUNDIALS >= 5.7.0 for HIP support.
- SuiteSparse (optional), used when MFEM_USE_SUITESPARSE = YES.
URL: http://faculty.cse.tamu.edu/davis/suitesparse.html
+2
View File
@@ -55,6 +55,8 @@ set(MFEM_USE_SIMD @MFEM_USE_SIMD@)
set(MFEM_USE_ADIOS2 @MFEM_USE_ADIOS2@)
set(MFEM_USE_MOONOLITH @MFEM_USE_MOONOLITH@)
set(MFEM_USE_CODIPACK @MFEM_USE_CODIPACK@)
set(MFEM_USE_MKL_CPARDISO @MFEM_USE_MKL_CPARDISO@)
set(MFEM_USE_MKL_PARDISO @MFEM_USE_MKL_PARDISO@)
set(MFEM_USE_ADFORWARD @MFEM_USE_ADFORWARD@)
set(MFEM_USE_CALIPER @MFEM_USE_CALIPER@)
set(MFEM_USE_ALGOIM @MFEM_USE_ALGOIM@)
+52 -44
View File
@@ -80,96 +80,101 @@
// Internal MFEM option: enable group/batch allocation for some small objects.
#cmakedefine MFEM_USE_MEMALLOC
// Which library functions to use in class StopWatch for measuring time.
// For a list of the available options, see INSTALL.
// If not defined, an option is selected automatically.
#cmakedefine MFEM_TIMER_TYPE @MFEM_TIMER_TYPE@
// Enable MFEM functionality based on the SUNDIALS libraries.
#cmakedefine MFEM_USE_SUNDIALS
// Enable MFEM functionality based on the SuiteSparse library.
#cmakedefine MFEM_USE_SUITESPARSE
// Enable MFEM functionality based on the SuperLU_DIST library.
#cmakedefine MFEM_USE_SUPERLU
#cmakedefine MFEM_USE_SUPERLU5
// Enable MFEM functionality based on the MUMPS library.
#cmakedefine MFEM_USE_MUMPS
#cmakedefine MFEM_MUMPS_VERSION @MFEM_MUMPS_VERSION@
// Enable MFEM functionality based on the STRUMPACK library.
#cmakedefine MFEM_USE_STRUMPACK
// Enable functionality based on the Ginkgo library
// Enable functionality based on the Ginkgo library.
#cmakedefine MFEM_USE_GINKGO
// Enable MFEM functionality based on the AmgX library
// Enable MFEM functionality based on the AmgX library.
#cmakedefine MFEM_USE_AMGX
// Enable MFEM functionality based on the GnuTLS library
// Enable secure socket streams based on the GNUTLS library.
#cmakedefine MFEM_USE_GNUTLS
// Enable MFEM functionality based on the GSLIB library
#cmakedefine MFEM_USE_GSLIB
// Enable MFEM functionality based on the NetCDF library
#cmakedefine MFEM_USE_NETCDF
// Enable MFEM functionality based on the PETSc library
#cmakedefine MFEM_USE_PETSC
// Enable MFEM functionality based on the SLEPc library
#cmakedefine MFEM_USE_SLEPC
// Enable MFEM functionality based on the Sidre library
// Enable Sidre support.
#cmakedefine MFEM_USE_SIDRE
// Enable the use of SIMD in the high performance templated classes
// Enable the use of SIMD in the high performance templated classes.
#cmakedefine MFEM_USE_SIMD
// Enable MFEM functionality based on the FMS library
// Enable FMS support.
#cmakedefine MFEM_USE_FMS
// Enable MFEM functionality based on Conduit
// Enable Conduit support.
#cmakedefine MFEM_USE_CONDUIT
// Enable MFEM functionality based on the PUMI library
// Enable functionality based on the NetCDF library (reading CUBIT files).
#cmakedefine MFEM_USE_NETCDF
// Enable functionality based on the PETSc library.
#cmakedefine MFEM_USE_PETSC
// Enable functionality based on the SLEPc library.
#cmakedefine MFEM_USE_SLEPC
// Enable functionality based on the MPFR library.
#cmakedefine MFEM_USE_MPFR
// Enable MFEM functionality based on the PUMI library.
#cmakedefine MFEM_USE_PUMI
// Enable MFEM functionality based on the Moonolith library
// Enable Moonolith-based general interpolation between finite element spaces.
#cmakedefine MFEM_USE_MOONOLITH
// Enable MFEM functionality based on the HiOp library
// Enable MFEM functionality based on the HIOP library.
#cmakedefine MFEM_USE_HIOP
// Build the GPU/CUDA-enabled version of the MFEM library.
// Enable MFEM functionality based on the GSLIB library.
#cmakedefine MFEM_USE_GSLIB
// Build the NVIDIA GPU/CUDA-enabled version of the MFEM library.
// Requires a CUDA compiler (nvcc).
#cmakedefine MFEM_USE_CUDA
// Build the HIP-enabled version of the MFEM library.
// Build the AMD GPU/HIP-enabled version of the MFEM library.
// Requires a HIP compiler (hipcc).
#cmakedefine MFEM_USE_HIP
// Enable MFEM functionality based on the RAJA library
// Enable functionality based on the RAJA library.
#cmakedefine MFEM_USE_RAJA
// Enable MFEM functionality based on the OCCA library
// Enable functionality based on the OCCA library.
#cmakedefine MFEM_USE_OCCA
// Enable MFEM functionality based on the libCEED library
// Enable functionality based on the libCEED library.
#cmakedefine MFEM_USE_CEED
// Enable MFEM functionality based on the Umpire library
#cmakedefine MFEM_USE_UMPIRE
// Enable MFEM functionality based on the ADIOS2 library
#cmakedefine MFEM_USE_ADIOS2
// Enable MFEM functionality based on the Caliper library
// Enable functionality based on the Caliper library.
#cmakedefine MFEM_USE_CALIPER
// Enable MFEM functionality based on the Algoim library
// Enable functionality based on the Algoim library.
#cmakedefine MFEM_USE_ALGOIM
// Which library functions to use in class StopWatch for measuring time.
// For a list of the available options, see INSTALL.
// If not defined, an option is selected automatically.
#define MFEM_TIMER_TYPE @MFEM_TIMER_TYPE@
// Enable functionality based on the Umpire library.
#cmakedefine MFEM_USE_UMPIRE
// Enable MFEM functionality based on the SUNDIALS libraries.
#cmakedefine MFEM_USE_SUNDIALS
// Enable IO functionality based on the ADIOS2 library.
#cmakedefine MFEM_USE_ADIOS2
// Version of HYPRE used for building MFEM.
#cmakedefine MFEM_HYPRE_VERSION @MFEM_HYPRE_VERSION@
@@ -181,13 +186,16 @@
// Enable interface to the MKL CPardiso library.
#cmakedefine MFEM_USE_MKL_CPARDISO
// Use forward mode for automatic differentiation
// Enable interface to the MKL Pardiso library.
#cmakedefine MFEM_USE_MKL_PARDISO
// Use forward mode for automatic differentiation.
#cmakedefine MFEM_USE_ADFORWARD
// Enable the use of the CoDiPack library for AD
// Enable the use of the CoDiPack library for AD.
#cmakedefine MFEM_USE_CODIPACK
// Enable MFEM functionality based on the Google Benchmark library.
// Enable functionality based on the Google Benchmark library.
#cmakedefine MFEM_USE_BENCHMARK
// Enable Enzyme for AD
@@ -0,0 +1,27 @@
# Copyright (c) 2010-2023, 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.
# Defines the following variables:
# - MKL_PARDISO_FOUND
# - MKL_PARDISO_LIBRARIES
# - MKL_PARDISO_INCLUDE_DIRS
if(NOT MKL_LIBRARY_DIR)
message(WARNING "Using default MKL library path. Double check the variable MKL_LIBRARY_DIR")
set(MKL_LIBRARY_DIR "lib/intel64")
endif()
include(MfemCmakeUtilities)
mfem_find_package(MKL_PARDISO MKL_PARDISO
MKL_PARDISO_DIR "include" mkl_pardiso.h ${MKL_LIBRARY_DIR} mkl_core
"Paths to headers required by MKL Pardiso." "Libraries required by MKL PARDISO."
ADD_COMPONENT MKL_LP64 "include" "" ${MKL_LIBRARY_DIR} mkl_intel_lp64
ADD_COMPONENT MKL_SEQUENTIAL "include" "" ${MKL_LIBRARY_DIR} mkl_sequential)
+17 -1
View File
@@ -11,8 +11,9 @@
# Sets the following variables:
# - MUMPS_FOUND
# - MUMPS_INCLUDE_DIRS
# - MUMPS_LIBRARIES
# - MUMPS_INCLUDE_DIRS
# - MUMPS_VERSION
include(MfemCmakeUtilities)
mfem_find_package(MUMPS MUMPS MUMPS_DIR
@@ -21,3 +22,18 @@ mfem_find_package(MUMPS MUMPS MUMPS_DIR
"Libraries required by MUMPS."
ADD_COMPONENT mumps_common "include" dmumps_c.h "lib" mumps_common
ADD_COMPONENT pord "include" dmumps_c.h "lib" pord)
if (MUMPS_FOUND AND (NOT MUMPS_VERSION))
try_run(MUMPS_VERSION_RUN_RESULT MUMPS_VERSION_COMPILE_RESULT
${CMAKE_CURRENT_BINARY_DIR}/config
${CMAKE_CURRENT_SOURCE_DIR}/config/get_mumps_version.cpp
CMAKE_FLAGS -DINCLUDE_DIRECTORIES:STRING=${MUMPS_INCLUDE_DIRS}
RUN_OUTPUT_VARIABLE MUMPS_VERSION_OUTPUT)
if ((MUMPS_VERSION_RUN_RESULT EQUAL 0) AND MUMPS_VERSION_OUTPUT)
string(STRIP "${MUMPS_VERSION_OUTPUT}" MUMPS_VERSION)
set(MUMPS_VERSION ${MUMPS_VERSION} CACHE STRING "MUMPS version." FORCE)
message(STATUS "Found MUMPS version ${MUMPS_VERSION}")
else()
message(FATAL_ERROR "Unable to determine MUMPS version.")
endif()
endif()
+2 -2
View File
@@ -22,8 +22,8 @@ mfem_find_package(SUNDIALS SUNDIALS SUNDIALS_DIR
"include" nvector/nvector_serial.h "lib" sundials_nvecserial
ADD_COMPONENT NVector_Cuda
"include" nvector/nvector_cuda.h "lib" sundials_nveccuda
ADD_COMPONENT NVector_ParHyp
"include" nvector/nvector_parhyp.h "lib" sundials_nvecparhyp
ADD_COMPONENT NVector_Hip
"include" nvector/nvector_hip.h "lib" sundials_nvechip
ADD_COMPONENT NVector_Parallel
"include" nvector/nvector_parallel.h "lib" sundials_nvecparallel
ADD_COMPONENT NVector_MPIPlusX
+19 -16
View File
@@ -30,10 +30,10 @@
#define MFEM_VERSION_MINOR (((MFEM_VERSION)/100)%100)
#define MFEM_VERSION_PATCH ((MFEM_VERSION)%100)
// The absolute path of the MFEM source prefix
// The absolute path of the MFEM source prefix.
// #define MFEM_SOURCE_DIR "@MFEM_SOURCE_DIR@"
// The absolute path of the MFEM installation prefix
// The absolute path of the MFEM installation prefix.
// #define MFEM_INSTALL_DIR "@MFEM_INSTALL_DIR@"
// Description of the git commit used to build MFEM.
@@ -91,7 +91,7 @@
// Enable MFEM functionality based on the SuiteSparse library.
// #define MFEM_USE_SUITESPARSE
// Enable MFEM functionality based on the SuperLU library.
// Enable MFEM functionality based on the SuperLU_DIST library.
// #define MFEM_USE_SUPERLU
// #define MFEM_USE_SUPERLU5
@@ -102,40 +102,40 @@
// Enable MFEM functionality based on the STRUMPACK library.
// #define MFEM_USE_STRUMPACK
// Enable MFEM features based on the Ginkgo library
// Enable MFEM features based on the Ginkgo library.
// #define MFEM_USE_GINKGO
// Enable MFEM functionality based on the AmgX library.
// #define MFEM_USE_AMGX
// Enable secure socket streams based on the GNUTLS library
// Enable secure socket streams based on the GNUTLS library.
// #define MFEM_USE_GNUTLS
// Enable Sidre support
// Enable Sidre support.
// #define MFEM_USE_SIDRE
// Enable the use of SIMD in the high performance templated classes
// Enable the use of SIMD in the high performance templated classes.
// #define MFEM_USE_SIMD
// Enable FMS support
// Enable FMS support.
// #define MFEM_USE_FMS
// Enable Conduit support
// Enable Conduit support.
// #define MFEM_USE_CONDUIT
// Enable functionality based on the NetCDF library (reading CUBIT files)
// Enable functionality based on the NetCDF library (reading CUBIT files).
// #define MFEM_USE_NETCDF
// Enable functionality based on the PETSc library
// Enable functionality based on the PETSc library.
// #define MFEM_USE_PETSC
// Enable functionality based on the SLEPc library
// Enable functionality based on the SLEPc library.
// #define MFEM_USE_SLEPC
// Enable functionality based on the MPFR library.
// #define MFEM_USE_MPFR
// Enable MFEM functionality based on the PUMI library
// Enable MFEM functionality based on the PUMI library.
// #define MFEM_USE_PUMI
// Enable Moonolith-based general interpolation between finite element spaces.
@@ -144,7 +144,7 @@
// Enable MFEM functionality based on the HIOP library.
// #define MFEM_USE_HIOP
// Enable MFEM functionality based on the GSLIB library
// Enable MFEM functionality based on the GSLIB library.
// #define MFEM_USE_GSLIB
// Build the NVIDIA GPU/CUDA-enabled version of the MFEM library.
@@ -186,10 +186,13 @@
// Enable interface to the MKL CPardiso library.
// #define MFEM_USE_MKL_CPARDISO
// Use forward mode for automatic differentiation
// Enable interface to the MKL Pardiso library.
// #define MFEM_USE_MKL_PARDISO
// Use forward mode for automatic differentiation.
// #define MFEM_USE_ADFORWARD
// Enable the use of the CoDiPack library for AD
// Enable the use of the CoDiPack library for AD.
// #define MFEM_USE_CODIPACK
// Enable functionality based on the Google Benchmark library.
+1
View File
@@ -57,6 +57,7 @@ MFEM_USE_UMPIRE = @MFEM_USE_UMPIRE@
MFEM_USE_SIMD = @MFEM_USE_SIMD@
MFEM_USE_ADIOS2 = @MFEM_USE_ADIOS2@
MFEM_USE_MKL_CPARDISO = @MFEM_USE_MKL_CPARDISO@
MFEM_USE_MKL_PARDISO = @MFEM_USE_MKL_PARDISO@
MFEM_USE_MOONOLITH = @MFEM_USE_MOONOLITH@
MFEM_USE_ADFORWARD = @MFEM_USE_ADFORWARD@
MFEM_USE_CODIPACK = @MFEM_USE_CODIPACK@
+10 -5
View File
@@ -60,6 +60,7 @@ option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
option(MFEM_USE_CALIPER "Enable Caliper support" OFF)
option(MFEM_USE_ALGOIM "Enable Algoim support" OFF)
option(MFEM_USE_MKL_CPARDISO "Enable MKL CPardiso" OFF)
option(MFEM_USE_MKL_PARDISO "Enable MKL Pardiso" OFF)
option(MFEM_USE_ADFORWARD "Enable forward mode for AD" OFF)
option(MFEM_USE_CODIPACK "Enable automatic differentiation (AD) using CoDiPack" OFF)
option(MFEM_USE_BENCHMARK "Enable Google Benchmark" OFF)
@@ -134,16 +135,18 @@ set(ParMETIS_DIR "${MFEM_DIR}/../parmetis-4.0.3" CACHE PATH
set(ParMETIS_REQUIRED_PACKAGES "METIS" CACHE STRING
"Additional packages required by ParMETIS.")
set(SuperLUDist_DIR "${MFEM_DIR}/../SuperLU_DIST_6.3.1" CACHE PATH
set(SuperLUDist_DIR "${MFEM_DIR}/../SuperLU_DIST_8.1.2" CACHE PATH
"Path to the SuperLU_DIST library.")
# SuperLU_DIST may also depend on "OpenMP", depending on how it was compiled.
set(SuperLUDist_REQUIRED_PACKAGES "MPI" "BLAS" "ParMETIS" CACHE STRING
set(SuperLUDist_REQUIRED_PACKAGES "MPI" "ParMETIS" "METIS"
"LAPACK" "BLAS" CACHE STRING
"Additional packages required by SuperLU_DIST.")
set(MUMPS_DIR "${MFEM_DIR}/../MUMPS_5.2.0" CACHE PATH
set(MUMPS_DIR "${MFEM_DIR}/../MUMPS_5.5.0" CACHE PATH
"Path to the MUMPS library.")
# Packages required by MUMPS, depending on how it was compiled.
set(MUMPS_REQUIRED_PACKAGES "MPI" "BLAS" "METIS" "ScaLAPACK" CACHE STRING
# MUMPS may also depend on "OpenMP", depending on how it was compiled.
set(MUMPS_REQUIRED_PACKAGES "MPI" "MPI_Fortran" "ParMETIS" "METIS"
"ScaLAPACK" "LAPACK" "BLAS" CACHE STRING
"Additional packages required by MUMPS.")
# If the MPI package does not find all required Fortran libraries:
# set(MUMPS_REQUIRED_LIBRARIES "gfortran" "mpi_mpifh" CACHE STRING
@@ -226,6 +229,8 @@ set(MKL_CPARDISO_DIR "" CACHE STRING "MKL installation path.")
set(MKL_MPI_WRAPPER_LIB "mkl_blacs_mpich_lp64" CACHE STRING "MKL MPI wrapper library")
set(MKL_LIBRARY_DIR "" CACHE STRING "Custom library subdirectory")
set(MKL_PARDISO_DIR "" CACHE STRING "MKL installation path.")
set(OCCA_DIR "${MFEM_DIR}/../occa" CACHE PATH "Path to OCCA")
set(RAJA_DIR "${MFEM_DIR}/../raja" CACHE PATH "Path to RAJA")
set(CEED_DIR "${MFEM_DIR}/../libCEED" CACHE PATH "Path to libCEED")
+15 -4
View File
@@ -160,6 +160,7 @@ MFEM_USE_UMPIRE = NO
MFEM_USE_SIMD = NO
MFEM_USE_ADIOS2 = NO
MFEM_USE_MKL_CPARDISO = NO
MFEM_USE_MKL_PARDISO = NO
MFEM_USE_MOONOLITH = NO
MFEM_USE_ADFORWARD = NO
MFEM_USE_CODIPACK = NO
@@ -266,6 +267,9 @@ endif
ifeq ($(MFEM_USE_CUDA),YES)
SUNDIALS_LIB += -lsundials_nveccuda
endif
ifeq ($(MFEM_USE_HIP),YES)
SUNDIALS_LIB += -lsundials_nvechip
endif
# If SUNDIALS was built with KLU:
# MFEM_USE_SUITESPARSE = YES
@@ -284,10 +288,10 @@ ifeq ($(MFEM_USE_SUPERLU5),YES)
SUPERLU_LIB = $(XLINKER)-rpath,$(SUPERLU_DIR)/lib -L$(SUPERLU_DIR)/lib\
-lsuperlu_dist_5.1.0
else
SUPERLU_DIR = @MFEM_DIR@/../SuperLU_DIST_6.3.1
SUPERLU_DIR = @MFEM_DIR@/../SuperLU_DIST_8.1.2
SUPERLU_OPT = -I$(SUPERLU_DIR)/include
SUPERLU_LIB = $(XLINKER)-rpath,$(SUPERLU_DIR)/lib64 -L$(SUPERLU_DIR)/lib64\
-lsuperlu_dist -lblas
-lsuperlu_dist $(LAPACK_LIB)
endif
# SCOTCH library configuration (required by STRUMPACK <= v2.1.0, optional in
@@ -311,7 +315,7 @@ MPI_FORTRAN_LIB = -lmpifort
# MPI_FORTRAN_LIB += -lgfortran
# MUMPS library configuration
MUMPS_DIR = @MFEM_DIR@/../MUMPS_5.2.0
MUMPS_DIR = @MFEM_DIR@/../MUMPS_5.5.0
MUMPS_OPT = -I$(MUMPS_DIR)/include
MUMPS_LIB = $(XLINKER)-rpath,$(MUMPS_DIR)/lib -L$(MUMPS_DIR)/lib -ldmumps\
-lmumps_common -lpord $(SCALAPACK_LIB) $(LAPACK_LIB) $(MPI_FORTRAN_LIB)
@@ -484,7 +488,6 @@ ifdef GOTCHA_DIR
CALIPER_LIB += $(XLINKER)-rpath,$(GOTCHA_DIR)/lib64 $(XLINKER)-rpath,$(GOTCHA_DIR)/lib -L$(GOTCHA_DIR)/lib64 -L$(GOTCHA_DIR)/lib -lgotcha
endif
# BLITZ library configuration
BLITZ_DIR = @MFEM_DIR@/../blitz
BLITZ_OPT = -I$(BLITZ_DIR)/include
@@ -539,6 +542,14 @@ MKL_CPARDISO_LIB = $(XLINKER)-rpath,$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR)\
-L$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR) -l$(MKL_MPI_WRAPPER)\
-lmkl_intel_lp64 -lmkl_sequential -lmkl_core
# MKL Pardiso library configuration
MKL_PARDISO_DIR ?=
MKL_LIBRARY_SUBDIR ?= lib
MKL_PARDISO_OPT = -I$(MKL_PARDISO_DIR)/include
MKL_PARDISO_LIB = $(XLINKER)-rpath,$(MKL_PARDISO_DIR)/$(MKL_LIBRARY_SUBDIR)\
-L$(MKL_PARDISO_DIR)/$(MKL_LIBRARY_SUBDIR)\
-lmkl_intel_lp64 -lmkl_sequential -lmkl_core
# PARELAG library configuration
PARELAG_DIR = @MFEM_DIR@/../parelag
PARELAG_OPT = -I$(PARELAG_DIR)/src -I$(PARELAG_DIR)/build/src
+5 -1
View File
@@ -795,6 +795,7 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/miniapps/common \
@MFEM_SOURCE_DIR@/miniapps/electromagnetics \
@MFEM_SOURCE_DIR@/miniapps/gslib \
@MFEM_SOURCE_DIR@/miniapps/hdiv-linear-solver \
@MFEM_SOURCE_DIR@/miniapps/hooke \
@MFEM_SOURCE_DIR@/miniapps/hooke/kernels \
@MFEM_SOURCE_DIR@/miniapps/hooke/materials \
@@ -810,7 +811,10 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/miniapps/shifted \
@MFEM_SOURCE_DIR@/miniapps/solvers \
@MFEM_SOURCE_DIR@/miniapps/tools \
@MFEM_SOURCE_DIR@/miniapps/toys
@MFEM_SOURCE_DIR@/miniapps/toys \
@MFEM_SOURCE_DIR@/miniapps/spde \
@MFEM_SOURCE_DIR@/miniapps/dpg \
@MFEM_SOURCE_DIR@/miniapps/dpg/util
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+6 -2
View File
@@ -39,7 +39,7 @@ namespace mfem {
* - Device
* - Memory
* - MemoryManager
* - MFEM_FORALL macro in forall.hpp
* - mfem::forall functions in forall.hpp
*
* <H3>Example codes</H3>
* - <a class="el" href="ex0_8cpp_source.html">Example 0</a>: simplest example, nodal H1 FEM for the Laplace problem
@@ -186,6 +186,7 @@ namespace mfem {
* - <a class="el" href="extruder_8cpp_source.html">Extruder</a>: extrude a low-dimensional mesh into a higher dimension
* - <a class="el" href="mesh-explorer_8cpp_source.html">Mesh Explorer</a>: visualize and manipulate meshes
* - <a class="el" href="mesh-optimizer_8cpp_source.html">Mesh Optimizer</a>: optimize high-order meshes, <a class="el" href="mesh-optimizer_8cpp_source.html">serial</a> and <a class="el" href="pmesh-optimizer_8cpp_source.html">parallel</a> versions
* - <a class="el" href="mesh-quality_8cpp_source.html">Mesh Quality</a>: visualize and check mesh quality
* - <a class="el" href="trimmer_8cpp_source.html">Trimmer</a>: trim elements from existing meshes
* - <a class="el" href="display-basis_8cpp_source.html">Display Basis</a>: visualize finite element basis functions
* - <a class="el" href="get-values_8cpp_source.html">Get Values</a>: extract field values via DataCollection classes
@@ -198,12 +199,15 @@ namespace mfem {
* - <a class="el" href="distance_8cpp_source.html">Distance</a>: finite element distance function solver
* - <a class="el" href="diffusion_8cpp_source.html">Shifted Diffusion</a>: shifted boundary diffusion solver
* - <a class="el" href="extrapolate_8cpp_source.html">Extrapolation</a>: PDE-based extrapolation of finite element functions
* - <a class="el" href="distance_8cpp_source.html">Block Solvers</a>: comparison of saddle point system solvers
* - <a class="el" href="block-solvers_8cpp_source.html">Block Solvers</a>: comparison of saddle point system solvers
* - <a class="el" href="parheat_8cpp_source.html">Optimization gradients</a>: Gradients of PDE-constrained function
* - <a class="el" href="par__example_8cpp_source.html">Parallel AD</a>: Parallel p-Laplacian example
* - <a class="el" href="seq__example_8cpp_source.html">Serial AD</a>: Serial p-Laplacian example
* - <a class="el" href="miniapps_2performance_2ex1_8cpp_source.html">HPC Example 1</a>: high-performance nodal H1 FEM for the Laplace problem
* - <a class="el" href="miniapps_2performance_2ex1p_8cpp_source.html">HPC Example 1p</a>: high-performance parallel nodal H1 FEM for the Laplace problem
* - <a class="el" href="generate__random__field_8cpp_source.html">SPDE Solvers</a>: SPDE solver random field generation
* - <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
*
* See also the <a class="el" href="https://mfem.org/examples/">examples documentation</a> online.
*/
+9
View File
@@ -161,6 +161,15 @@ if (MFEM_ENABLE_TESTING)
$<TARGET_FILE:ex11p> "-no-vis" "--superlu"
${MPIEXEC_POSTFLAGS})
endif()
# If MUMPS is enabled, add a test run that uses it.
if (MFEM_USE_MUMPS)
add_test(NAME ex25p_mumps_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex25p> "-no-vis" "--mumps-solver"
${MPIEXEC_POSTFLAGS})
endif()
endif()
# Include the examples/amgx directory if AmgX is enabled
+20 -3
View File
@@ -18,6 +18,8 @@
// ex14 -m ../data/amr-quad.mesh -r 3
// ex14 -m ../data/amr-hex.mesh
// ex14 -m ../data/fichera-amr.mesh
// ex14 -m ../data/inline-quad.mesh -r 2 -rk
// ex14 -m ../data/star.mesh -r 0 -o 3 -rk
//
// Description: This example code demonstrates the use of MFEM to define a
// discontinuous Galerkin (DG) finite element discretization of
@@ -43,10 +45,11 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/star.mesh";
int ref_levels = -1;
int order = 1;
bool rk = false;
double sigma = -1.0;
double kappa = -1.0;
double eta = 0.0;
bool visualization = 1;
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -54,7 +57,9 @@ int main(int argc, char *argv[])
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) >= 0.");
"Finite element order (polynomial degree) >= 0 OR reproducing kernel order.");
args.AddOption(&rk, "-rk", "--rk", "-no-rk", "--no-rk",
"Use reproducing kernel functions");
args.AddOption(&sigma, "-s", "--sigma",
"One of the three DG penalty parameters, typically +1/-1."
" See the documentation of class DGDiffusionIntegrator.");
@@ -75,6 +80,10 @@ int main(int argc, char *argv[])
{
kappa = (order+1)*(order+1);
}
if (rk && sigma < 0.0)
{
sigma = 1.0;
}
args.PrintOptions(cout);
// 2. Read the mesh from the given mesh file. We can handle triangular,
@@ -104,7 +113,15 @@ int main(int argc, char *argv[])
// 4. Define a finite element space on the mesh. Here we use discontinuous
// finite elements of the specified order >= 0.
FiniteElementCollection *fec = new DG_FECollection(order, dim);
FiniteElementCollection *fec;
if (rk)
{
fec = new LocalKernelFECollection(dim, 4, 6, order, 1.01 + order, 0.0);
}
else
{
fec = new DG_FECollection(order, dim);
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
cout << "Number of unknowns: " << fespace->GetVSize() << endl;
+18 -1
View File
@@ -17,6 +17,8 @@
// mpirun -np 4 ex14p -m ../data/inline-segment.mesh -rs 5
// mpirun -np 4 ex14p -m ../data/amr-quad.mesh -rs 3
// mpirun -np 4 ex14p -m ../data/amr-hex.mesh
// mpirun -np 4 ex14p -m ../data/star.mesh -rs 1 -o 2 -rk
// mpirun -np 4 ex14p -m ../data/amr-quad.mesh -rs 2 -rk
//
// Description: This example code demonstrates the use of MFEM to define a
// discontinuous Galerkin (DG) finite element discretization of
@@ -81,6 +83,7 @@ int main(int argc, char *argv[])
int ser_ref_levels = -1;
int par_ref_levels = 2;
int order = 1;
bool rk = false;
double sigma = -1.0;
double kappa = -1.0;
double eta = 0.0;
@@ -96,6 +99,8 @@ int main(int argc, char *argv[])
"Number of times to refine the mesh uniformly in parallel.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) >= 0.");
args.AddOption(&rk, "-rk", "--rk", "-no-rk", "--no-rk",
"Use reproducing kernel functions");
args.AddOption(&sigma, "-s", "--sigma",
"One of the three DG penalty parameters, typically +1/-1."
" See the documentation of class DGDiffusionIntegrator.");
@@ -119,6 +124,10 @@ int main(int argc, char *argv[])
{
kappa = (order+1)*(order+1);
}
if (rk && sigma < 0.0)
{
sigma = 1.0;
}
if (myid == 0)
{
args.PrintOptions(cout);
@@ -163,7 +172,15 @@ int main(int argc, char *argv[])
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use discontinuous finite elements of the specified order >= 0.
FiniteElementCollection *fec = new DG_FECollection(order, dim);
FiniteElementCollection *fec;
if (rk)
{
fec = new LocalKernelFECollection(dim, 4, 6, order, 1.01 + order, 0.0);
}
else
{
fec = new DG_FECollection(order, dim);
}
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_BigInt size = fespace->GlobalTrueVSize();
if (myid == 0)
+18 -4
View File
@@ -9,6 +9,8 @@
// ex18 -p 1 -r 0 -o 5 -s 6
// ex18 -p 2 -r 1 -o 1 -s 3
// ex18 -p 2 -r 0 -o 3 -s 3
// ex18 -p 1 -r 1 -o 3 -s 4 -rk
// ex18 -p 2 -r 0 -o 3 -s 3 -rk
//
// Description: This example code solves the compressible Euler system of
// equations, a model nonlinear hyperbolic PDE, with a
@@ -65,6 +67,7 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/periodic-square.mesh";
int ref_levels = 1;
int order = 3;
bool rk = false;
int ode_solver_type = 4;
double t_final = 2.0;
double dt = -0.01;
@@ -84,6 +87,8 @@ int main(int argc, char *argv[])
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&rk, "-rk", "--rk", "-no-rk", "--no-rk",
"Use reproducing kernel functions");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6.");
@@ -139,13 +144,21 @@ int main(int argc, char *argv[])
// 5. Define the discontinuous DG finite element space of the given
// polynomial order on the refined mesh.
DG_FECollection fec(order, dim);
FiniteElementCollection *fec;
if (rk)
{
fec = new LocalKernelFECollection(dim, 5, 7, order, 2.01 + order, 1.0);
}
else
{
fec = new DG_FECollection(order, dim);
}
// Finite element space for a scalar (thermodynamic quantity)
FiniteElementSpace fes(&mesh, &fec);
FiniteElementSpace fes(&mesh, fec);
// Finite element space for a mesh-dim vector quantity (momentum)
FiniteElementSpace dfes(&mesh, &fec, dim, Ordering::byNODES);
FiniteElementSpace dfes(&mesh, fec, dim, Ordering::byNODES);
// Finite element space for all variables together (total thermodynamic state)
FiniteElementSpace vfes(&mesh, &fec, num_equation, Ordering::byNODES);
FiniteElementSpace vfes(&mesh, fec, num_equation, Ordering::byNODES);
// This example depends on this ordering of the space.
MFEM_ASSERT(fes.GetOrdering() == Ordering::byNODES, "");
@@ -304,6 +317,7 @@ int main(int argc, char *argv[])
// Free the used memory.
delete ode_solver;
delete fec;
return 0;
}
+18 -4
View File
@@ -9,6 +9,8 @@
// mpirun -np 4 ex18p -p 1 -rs 1 -rp 1 -o 5 -s 6
// mpirun -np 4 ex18p -p 2 -rs 1 -rp 1 -o 1 -s 3
// mpirun -np 4 ex18p -p 2 -rs 1 -rp 1 -o 3 -s 3
// mpirun -np 4 ex18p -p 1 -rs 1 -rp 0 -o 3 -s 4 -rk
// mpirun -np 4 ex18p -p 2 -rs 1 -rp 0 -o 3 -s 3 -rk
//
// Description: This example code solves the compressible Euler system of
// equations, a model nonlinear hyperbolic PDE, with a
@@ -70,6 +72,7 @@ int main(int argc, char *argv[])
int ser_ref_levels = 0;
int par_ref_levels = 1;
int order = 3;
bool rk = false;
int ode_solver_type = 4;
double t_final = 2.0;
double dt = -0.01;
@@ -93,6 +96,8 @@ int main(int argc, char *argv[])
" partitioning.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&rk, "-rk", "--rk", "-no-rk", "--no-rk",
"Use reproducing kernel functions");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6.");
@@ -161,13 +166,21 @@ int main(int argc, char *argv[])
// 7. Define the discontinuous DG finite element space of the given
// polynomial order on the refined mesh.
DG_FECollection fec(order, dim);
FiniteElementCollection *fec;
if (rk)
{
fec = new LocalKernelFECollection(dim, 5, 7, order, 2.01 + order, 1.0);
}
else
{
fec = new DG_FECollection(order, dim);
}
// Finite element space for a scalar (thermodynamic quantity)
ParFiniteElementSpace fes(&pmesh, &fec);
ParFiniteElementSpace fes(&pmesh, fec);
// Finite element space for a mesh-dim vector quantity (momentum)
ParFiniteElementSpace dfes(&pmesh, &fec, dim, Ordering::byNODES);
ParFiniteElementSpace dfes(&pmesh, fec, dim, Ordering::byNODES);
// Finite element space for all variables together (total thermodynamic state)
ParFiniteElementSpace vfes(&pmesh, &fec, num_equation, Ordering::byNODES);
ParFiniteElementSpace vfes(&pmesh, fec, num_equation, Ordering::byNODES);
// This example depends on this ordering of the space.
MFEM_ASSERT(fes.GetOrdering() == Ordering::byNODES, "");
@@ -375,6 +388,7 @@ int main(int argc, char *argv[])
// Free the used memory.
delete ode_solver;
delete fec;
return 0;
}
+33 -36
View File
@@ -32,6 +32,7 @@
// We recommend viewing Example 22 before viewing this example.
#include "mfem.hpp"
#include <memory>
#include <fstream>
#include <iostream>
@@ -44,7 +45,7 @@ using namespace std;
using namespace mfem;
// Class for setting up a simple Cartesian PML region
class CartesianPML
class PML
{
private:
Mesh *mesh;
@@ -69,7 +70,7 @@ private:
public:
// Constructor
CartesianPML(Mesh *mesh_,Array2D<double> length_);
PML(Mesh *mesh_,Array2D<double> length_);
// Return Computational Domain Boundary
Array2D<double> GetCompDomainBdr() {return comp_dom_bdr;}
@@ -91,12 +92,12 @@ public:
class PMLDiagMatrixCoefficient : public VectorCoefficient
{
private:
CartesianPML * pml = nullptr;
void (*Function)(const Vector &, CartesianPML *, Vector &);
PML * pml = nullptr;
void (*Function)(const Vector &, PML *, Vector &);
public:
PMLDiagMatrixCoefficient(int dim, void(*F)(const Vector &, CartesianPML *,
PMLDiagMatrixCoefficient(int dim, void(*F)(const Vector &, PML *,
Vector &),
CartesianPML * pml_)
PML * pml_)
: VectorCoefficient(dim), pml(pml_), Function(F)
{}
@@ -125,13 +126,13 @@ void source(const Vector &x, Vector & f);
// Functions for computing the necessary coefficients after PML stretching.
// J is the Jacobian matrix of the stretching function
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector &D);
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector &D);
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector &D);
void detJ_JT_J_inv_Re(const Vector &x, PML * pml, Vector &D);
void detJ_JT_J_inv_Im(const Vector &x, PML * pml, Vector &D);
void detJ_JT_J_inv_abs(const Vector &x, PML * pml, Vector &D);
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector &D);
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector &D);
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector &D);
void detJ_inv_JT_J_Re(const Vector &x, PML * pml, Vector &D);
void detJ_inv_JT_J_Im(const Vector &x, PML * pml, Vector &D);
void detJ_inv_JT_J_abs(const Vector &x, PML * pml, Vector &D);
Array2D<double> comp_domain_bdr;
Array2D<double> domain_bdr;
@@ -267,7 +268,7 @@ int main(int argc, char *argv[])
length = 0.25;
break;
}
CartesianPML * pml = new CartesianPML(mesh,length);
PML * pml = new PML(mesh,length);
comp_domain_bdr = pml->GetCompDomainBdr();
domain_bdr = pml->GetDomainBdr();
@@ -467,16 +468,14 @@ int main(int argc, char *argv[])
offsets[2] = fespace->GetTrueVSize();
offsets.PartialSum();
Operator *pc_r = nullptr;
Operator *pc_i = nullptr;
std::unique_ptr<Operator> pc_r;
std::unique_ptr<Operator> pc_i;
double s = (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0;
if (pa)
{
// Jacobi Smoother
OperatorJacobiSmoother *d00 = new OperatorJacobiSmoother(prec, ess_tdof_list);
ScaledOperator *d11 = new ScaledOperator(d00, s);
pc_r = d00;
pc_i = d11;
pc_r.reset(new OperatorJacobiSmoother(prec, ess_tdof_list));
pc_i.reset(new ScaledOperator(pc_r.get(), s));
}
else
{
@@ -485,15 +484,13 @@ int main(int argc, char *argv[])
prec.FormSystemMatrix(ess_tdof_list, PCOpAh);
// Gauss-Seidel Smoother
GSSmoother *gs00 = new GSSmoother(*PCOpAh.As<SparseMatrix>());
ScaledOperator *gs11 = new ScaledOperator(gs00, s);
pc_r = gs00;
pc_i = gs11;
pc_r.reset(new GSSmoother(*PCOpAh.As<SparseMatrix>()));
pc_i.reset(new ScaledOperator(pc_r.get(), s));
}
BlockDiagonalPreconditioner BlockDP(offsets);
BlockDP.SetDiagonalBlock(0, pc_r);
BlockDP.SetDiagonalBlock(1, pc_i);
BlockDP.SetDiagonalBlock(0, pc_r.get());
BlockDP.SetDiagonalBlock(1, pc_i.get());
GMRESSolver gmres;
gmres.SetPrintLevel(1);
@@ -807,7 +804,7 @@ void E_bdr_data_Im(const Vector &x, Vector &E)
}
}
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector &D)
void detJ_JT_J_inv_Re(const Vector &x, PML * pml, Vector &D)
{
vector<complex<double>> dxs(dim);
complex<double> det(1.0, 0.0);
@@ -824,7 +821,7 @@ void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector &D)
}
}
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector &D)
void detJ_JT_J_inv_Im(const Vector &x, PML * pml, Vector &D)
{
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
@@ -841,7 +838,7 @@ void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector &D)
}
}
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector &D)
void detJ_JT_J_inv_abs(const Vector &x, PML * pml, Vector &D)
{
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
@@ -858,7 +855,7 @@ void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector &D)
}
}
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector &D)
void detJ_inv_JT_J_Re(const Vector &x, PML * pml, Vector &D)
{
vector<complex<double>> dxs(dim);
complex<double> det(1.0, 0.0);
@@ -883,7 +880,7 @@ void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector &D)
}
}
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector &D)
void detJ_inv_JT_J_Im(const Vector &x, PML * pml, Vector &D)
{
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
@@ -907,7 +904,7 @@ void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector &D)
}
}
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector &D)
void detJ_inv_JT_J_abs(const Vector &x, PML * pml, Vector &D)
{
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
@@ -931,14 +928,14 @@ void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector &D)
}
}
CartesianPML::CartesianPML(Mesh *mesh_, Array2D<double> length_)
PML::PML(Mesh *mesh_, Array2D<double> length_)
: mesh(mesh_), length(length_)
{
dim = mesh->Dimension();
SetBoundaries();
}
void CartesianPML::SetBoundaries()
void PML::SetBoundaries()
{
comp_dom_bdr.SetSize(dim, 2);
dom_bdr.SetSize(dim, 2);
@@ -953,7 +950,7 @@ void CartesianPML::SetBoundaries()
}
}
void CartesianPML::SetAttributes(Mesh *mesh_)
void PML::SetAttributes(Mesh *mesh_)
{
// Initialize bdr attributes
for (int i = 0; i < mesh_->GetNBE(); ++i)
@@ -1002,8 +999,8 @@ void CartesianPML::SetAttributes(Mesh *mesh_)
mesh_->SetAttributes();
}
void CartesianPML::StretchFunction(const Vector &x,
vector<complex<double>> &dxs)
void PML::StretchFunction(const Vector &x,
vector<complex<double>> &dxs)
{
complex<double> zi = complex<double>(0., 1.);
+34 -38
View File
@@ -44,7 +44,7 @@ using namespace std;
using namespace mfem;
// Class for setting up a simple Cartesian PML region
class CartesianPML
class PML
{
private:
Mesh *mesh;
@@ -69,7 +69,7 @@ private:
public:
// Constructor
CartesianPML(Mesh *mesh_,Array2D<double> length_);
PML(Mesh *mesh_,Array2D<double> length_);
// Return Computational Domain Boundary
Array2D<double> GetCompDomainBdr() {return comp_dom_bdr;}
@@ -91,12 +91,12 @@ public:
class PMLDiagMatrixCoefficient : public VectorCoefficient
{
private:
CartesianPML * pml = nullptr;
void (*Function)(const Vector &, CartesianPML *, Vector &);
PML * pml = nullptr;
void (*Function)(const Vector &, PML *, Vector &);
public:
PMLDiagMatrixCoefficient(int dim, void(*F)(const Vector &, CartesianPML *,
PMLDiagMatrixCoefficient(int dim, void(*F)(const Vector &, PML *,
Vector &),
CartesianPML * pml_)
PML * pml_)
: VectorCoefficient(dim), pml(pml_), Function(F)
{}
@@ -125,13 +125,13 @@ void source(const Vector &x, Vector & f);
// Functions for computing the necessary coefficients after PML stretching.
// J is the Jacobian matrix of the stretching function
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector & D);
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector & D);
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector & D);
void detJ_JT_J_inv_Re(const Vector &x, PML * pml, Vector & D);
void detJ_JT_J_inv_Im(const Vector &x, PML * pml, Vector & D);
void detJ_JT_J_inv_abs(const Vector &x, PML * pml, Vector & D);
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector & D);
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector & D);
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector & D);
void detJ_inv_JT_J_Re(const Vector &x, PML * pml, Vector & D);
void detJ_inv_JT_J_Im(const Vector &x, PML * pml, Vector & D);
void detJ_inv_JT_J_abs(const Vector &x, PML * pml, Vector & D);
Array2D<double> comp_domain_bdr;
Array2D<double> domain_bdr;
@@ -295,7 +295,7 @@ int main(int argc, char *argv[])
length = 0.25;
break;
}
CartesianPML * pml = new CartesianPML(mesh,length);
PML * pml = new PML(mesh,length);
comp_domain_bdr = pml->GetCompDomainBdr();
domain_bdr = pml->GetDomainBdr();
@@ -478,11 +478,11 @@ int main(int argc, char *argv[])
if (!pa && mumps_solver)
{
HypreParMatrix *A = Ah.As<ComplexHypreParMatrix>()->GetSystemMatrix();
MUMPSSolver mumps;
MUMPSSolver mumps(A->GetComm());
mumps.SetPrintLevel(0);
mumps.SetMatrixSymType(MUMPSSolver::MatType::UNSYMMETRIC);
mumps.SetOperator(*A);
mumps.Mult(B,X);
mumps.Mult(B, X);
delete A;
}
#endif
@@ -524,16 +524,14 @@ int main(int argc, char *argv[])
offsets[2] = fespace->GetTrueVSize();
offsets.PartialSum();
Operator *pc_r = nullptr;
Operator *pc_i = nullptr;
std::unique_ptr<Operator> pc_r;
std::unique_ptr<Operator> pc_i;
int s = (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0;
if (pa)
{
// Jacobi Smoother
OperatorJacobiSmoother *d00 = new OperatorJacobiSmoother(prec, ess_tdof_list);
ScaledOperator *d11 = new ScaledOperator(d00, s);
pc_r = d00;
pc_i = d11;
pc_r.reset(new OperatorJacobiSmoother(prec, ess_tdof_list));
pc_i.reset(new ScaledOperator(pc_r.get(), s));
}
else
{
@@ -541,15 +539,13 @@ int main(int argc, char *argv[])
prec.FormSystemMatrix(ess_tdof_list, PCOpAh);
// Hypre AMS
HypreAMS *ams00 = new HypreAMS(*PCOpAh.As<HypreParMatrix>(), fespace);
ScaledOperator *ams11 = new ScaledOperator(ams00, s);
pc_r = ams00;
pc_i = ams11;
pc_r.reset(new HypreAMS(*PCOpAh.As<HypreParMatrix>(), fespace));
pc_i.reset(new ScaledOperator(pc_r.get(), s));
}
BlockDiagonalPreconditioner BlockDP(offsets);
BlockDP.SetDiagonalBlock(0, pc_r);
BlockDP.SetDiagonalBlock(1, pc_i);
BlockDP.SetDiagonalBlock(0, pc_r.get());
BlockDP.SetDiagonalBlock(1, pc_i.get());
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetPrintLevel(1);
@@ -884,7 +880,7 @@ void E_bdr_data_Im(const Vector &x, Vector &E)
}
}
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector & D)
void detJ_JT_J_inv_Re(const Vector &x, PML * pml, Vector & D)
{
vector<complex<double>> dxs(dim);
complex<double> det(1.0, 0.0);
@@ -901,7 +897,7 @@ void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector & D)
}
}
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector & D)
void detJ_JT_J_inv_Im(const Vector &x, PML * pml, Vector & D)
{
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
@@ -918,7 +914,7 @@ void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector & D)
}
}
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector & D)
void detJ_JT_J_inv_abs(const Vector &x, PML * pml, Vector & D)
{
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
@@ -935,7 +931,7 @@ void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector & D)
}
}
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector & D)
void detJ_inv_JT_J_Re(const Vector &x, PML * pml, Vector & D)
{
vector<complex<double>> dxs(dim);
complex<double> det(1.0, 0.0);
@@ -960,7 +956,7 @@ void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector & D)
}
}
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector & D)
void detJ_inv_JT_J_Im(const Vector &x, PML * pml, Vector & D)
{
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
@@ -984,7 +980,7 @@ void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector & D)
}
}
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector & D)
void detJ_inv_JT_J_abs(const Vector &x, PML * pml, Vector & D)
{
vector<complex<double>> dxs(dim);
complex<double> det = 1.0;
@@ -1008,14 +1004,14 @@ void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector & D)
}
}
CartesianPML::CartesianPML(Mesh *mesh_, Array2D<double> length_)
PML::PML(Mesh *mesh_, Array2D<double> length_)
: mesh(mesh_), length(length_)
{
dim = mesh->Dimension();
SetBoundaries();
}
void CartesianPML::SetBoundaries()
void PML::SetBoundaries()
{
comp_dom_bdr.SetSize(dim, 2);
dom_bdr.SetSize(dim, 2);
@@ -1030,7 +1026,7 @@ void CartesianPML::SetBoundaries()
}
}
void CartesianPML::SetAttributes(ParMesh *pmesh)
void PML::SetAttributes(ParMesh *pmesh)
{
// Initialize bdr attributes
for (int i = 0; i < pmesh->GetNBE(); ++i)
@@ -1080,8 +1076,8 @@ void CartesianPML::SetAttributes(ParMesh *pmesh)
pmesh->SetAttributes();
}
void CartesianPML::StretchFunction(const Vector &x,
vector<complex<double>> &dxs)
void PML::StretchFunction(const Vector &x,
vector<complex<double>> &dxs)
{
complex<double> zi = complex<double>(0., 1.);
+4
View File
@@ -536,8 +536,10 @@ int main(int argc, char *argv[])
if (!sout)
{
if (Mpi::Root())
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
}
visualization = false;
if (Mpi::Root())
{
@@ -552,8 +554,10 @@ int main(int argc, char *argv[])
sout << "pause\n";
sout << flush;
if (Mpi::Root())
{
cout << "GLVis visualization paused."
<< " Press space (in the GLVis window) to resume it.\n";
}
}
}
+34 -2
View File
@@ -68,11 +68,43 @@ if (MFEM_ENABLE_TESTING)
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
# Add CUDA/HIP tests.
set(DEVICE_EXAMPLES
# serial examples with device support:
ex9
# parallel examples with device support:
ex9p)
set(MFEM_TEST_DEVICE)
if (MFEM_USE_CUDA)
set(MFEM_TEST_DEVICE "cuda")
elseif (MFEM_USE_HIP)
set(MFEM_TEST_DEVICE "hip")
endif()
if (MFEM_TEST_DEVICE)
foreach(TEST_NAME ${DEVICE_EXAMPLES})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(THIS_TEST_OPTIONS "-no-vis" "-d" "${MFEM_TEST_DEVICE}")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${PFX}${TEST_NAME}_${MFEM_TEST_DEVICE}_ser
COMMAND ${PFX}${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${PFX}${TEST_NAME}_${MFEM_TEST_DEVICE}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${PFX}${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif(MFEM_TEST_DEVICE)
endif(MFEM_ENABLE_TESTING)
+1 -2
View File
@@ -12,8 +12,7 @@ use of MFEM features based on the SUNDIALS suite of time integration and
non-linear solvers.
To build these examples, make sure that MFEM is configured with the option
"MFEM_USE_SUNDIALS = YES", see the top-level INSTALL file for details (version
2.7 or higher of SUNDIALS is required).
"MFEM_USE_SUNDIALS = YES", see the top-level INSTALL file for details.
We recommend comparing the original example codes with the corresponding files
in the current directory.
+5 -4
View File
@@ -280,15 +280,16 @@ int main(int argc, char *argv[])
k.SetAssemblyLevel(AssemblyLevel::FULL);
}
m.AddDomainIntegrator(new MassIntegrator);
k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
constexpr double alpha = -1.0;
k.AddDomainIntegrator(new ConvectionIntegrator(velocity, alpha));
k.AddInteriorFaceIntegrator(
new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
new NonconservativeDGTraceIntegrator(velocity, alpha));
k.AddBdrFaceIntegrator(
new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
new NonconservativeDGTraceIntegrator(velocity, alpha));
LinearForm b(&fes);
b.AddBdrFaceIntegrator(
new BoundaryFlowIntegrator(inflow, velocity, -1.0, -0.5));
new BoundaryFlowIntegrator(inflow, velocity, alpha));
m.Assemble();
int skip_zeros = 0;
+114 -22
View File
@@ -63,6 +63,66 @@ double inflow_function(const Vector &x);
// Mesh bounding box
Vector bb_min, bb_max;
// Type of preconditioner for implicit time integrator
enum class PrecType : int
{
ILU = 0,
AIR = 1
};
#if MFEM_HYPRE_VERSION >= 21800
// Algebraic multigrid preconditioner for advective problems based on
// approximate ideal restriction (AIR). Most effective when matrix is
// first scaled by DG block inverse, and AIR applied to scaled matrix.
// See https://doi.org/10.1137/17M1144350.
class AIR_prec : public Solver
{
private:
const HypreParMatrix *A;
// Copy of A scaled by block-diagonal inverse
HypreParMatrix A_s;
HypreBoomerAMG *AIR_solver;
int blocksize;
public:
AIR_prec(int blocksize_) : AIR_solver(NULL), blocksize(blocksize_) { }
void SetOperator(const Operator &op)
{
width = op.Width();
height = op.Height();
A = dynamic_cast<const HypreParMatrix *>(&op);
MFEM_VERIFY(A != NULL, "AIR_prec requires a HypreParMatrix.")
// Scale A by block-diagonal inverse
BlockInverseScale(A, &A_s, NULL, NULL, blocksize,
BlockInverseScaleJob::MATRIX_ONLY);
delete AIR_solver;
AIR_solver = new HypreBoomerAMG(A_s);
AIR_solver->SetAdvectiveOptions(1, "", "FA");
AIR_solver->SetPrintLevel(0);
AIR_solver->SetMaxLevels(50);
}
virtual void Mult(const Vector &x, Vector &y) const
{
// Scale the rhs by block inverse and solve system
HypreParVector z_s;
BlockInverseScale(A, NULL, &x, &z_s, blocksize,
BlockInverseScaleJob::RHS_ONLY);
AIR_solver->Mult(z_s, y);
}
~AIR_prec()
{
delete AIR_solver;
}
};
#endif
class DG_Solver : public Solver
{
private:
@@ -70,24 +130,37 @@ private:
SparseMatrix M_diag;
HypreParMatrix *A;
GMRESSolver linear_solver;
BlockILU prec;
Solver *prec;
double dt;
public:
DG_Solver(HypreParMatrix &M_, HypreParMatrix &K_, const FiniteElementSpace &fes)
DG_Solver(HypreParMatrix &M_, HypreParMatrix &K_, const FiniteElementSpace &fes,
PrecType prec_type)
: M(M_),
K(K_),
A(NULL),
linear_solver(M.GetComm()),
prec(fes.GetFE(0)->GetDof(),
BlockILU::Reordering::MINIMUM_DISCARDED_FILL),
dt(-1.0)
{
int block_size = fes.GetFE(0)->GetDof();
if (prec_type == PrecType::ILU)
{
prec = new BlockILU(block_size,
BlockILU::Reordering::MINIMUM_DISCARDED_FILL);
}
else if (prec_type == PrecType::AIR)
{
#if MFEM_HYPRE_VERSION >= 21800
prec = new AIR_prec(block_size);
#else
MFEM_ABORT("Must have MFEM_HYPRE_VERSION >= 21800 to use AIR.\n");
#endif
}
linear_solver.iterative_mode = false;
linear_solver.SetRelTol(1e-9);
linear_solver.SetAbsTol(0.0);
linear_solver.SetMaxIter(100);
linear_solver.SetPrintLevel(0);
linear_solver.SetPreconditioner(prec);
linear_solver.SetPreconditioner(*prec);
M.GetDiag(M_diag);
}
@@ -120,10 +193,12 @@ public:
~DG_Solver()
{
delete prec;
delete A;
}
};
/** A time-dependent operator for the right-hand side of the ODE. The DG weak
form of du/dt = -v.grad(u) is M du/dt = K u + b, where M and K are the mass
and advection matrices, and b describes the flow on the boundary. This can
@@ -141,7 +216,8 @@ private:
mutable Vector z;
public:
FE_Evolution(ParBilinearForm &M_, ParBilinearForm &K_, const Vector &b_);
FE_Evolution(ParBilinearForm &M_, ParBilinearForm &K_, const Vector &b_,
PrecType prec_type);
virtual void Mult(const Vector &x, Vector &y) const;
virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k);
@@ -178,6 +254,11 @@ int main(int argc, char *argv[])
bool adios2 = false;
bool binary = false;
int vis_steps = 5;
#if MFEM_HYPRE_VERSION >= 21800
PrecType prec_type = PrecType::AIR;
#else
PrecType prec_type = PrecType::ILU;
#endif
// Relative and absolute tolerances for CVODE and ARKODE.
const double reltol = 1e-2, abstol = 1e-2;
@@ -218,6 +299,8 @@ int main(int argc, char *argv[])
"Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
"Time step.");
args.AddOption((int *)&prec_type, "-pt", "--prec-type", "Preconditioner for "
"implicit solves. 0 for ILU, 1 for pAIR-AMG.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -238,13 +321,13 @@ int main(int argc, char *argv[])
args.Parse();
if (!args.Good())
{
if (myid == 0)
if (Mpi::Root())
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
if (Mpi::Root())
{
args.PrintOptions(cout);
}
@@ -252,7 +335,7 @@ int main(int argc, char *argv[])
// check for valid ODE solver option
if (ode_solver_type < 1 || ode_solver_type > 9)
{
if (myid == 0)
if (Mpi::Root())
{
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
}
@@ -260,7 +343,7 @@ int main(int argc, char *argv[])
}
Device device(device_config);
if (myid == 0) { device.Print(); }
if (Mpi::Root()) { device.Print(); }
// 3. Read the serial mesh from the given mesh file on all processors. We can
// handle geometrically periodic meshes in this code.
@@ -297,7 +380,7 @@ int main(int argc, char *argv[])
ParFiniteElementSpace *fes = new ParFiniteElementSpace(pmesh, &fec);
HYPRE_BigInt global_vSize = fes->GlobalTrueVSize();
if (myid == 0)
if (Mpi::Root())
{
cout << "Number of unknowns: " << global_vSize << endl;
}
@@ -328,15 +411,16 @@ int main(int argc, char *argv[])
}
m->AddDomainIntegrator(new MassIntegrator);
k->AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
constexpr double alpha = -1.0;
k->AddDomainIntegrator(new ConvectionIntegrator(velocity, alpha));
k->AddInteriorFaceIntegrator(
new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
new NonconservativeDGTraceIntegrator(velocity, alpha));
k->AddBdrFaceIntegrator(
new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
new NonconservativeDGTraceIntegrator(velocity, alpha));
ParLinearForm *b = new ParLinearForm(fes);
b->AddBdrFaceIntegrator(
new BoundaryFlowIntegrator(inflow, velocity, -1.0, -0.5));
new BoundaryFlowIntegrator(inflow, velocity, alpha));
int skip_zeros = 0;
m->Assemble();
@@ -435,11 +519,13 @@ int main(int argc, char *argv[])
sout.open(vishost, visport);
if (!sout)
{
if (myid == 0)
if (Mpi::Root())
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
}
visualization = false;
if (myid == 0)
if (Mpi::Root())
{
cout << "GLVis visualization disabled.\n";
}
@@ -451,15 +537,17 @@ int main(int argc, char *argv[])
sout << "solution\n" << *pmesh << *u;
sout << "pause\n";
sout << flush;
if (myid == 0)
if (Mpi::Root())
{
cout << "GLVis visualization paused."
<< " Press space (in the GLVis window) to resume it.\n";
}
}
}
// 9. Define the time-dependent evolution operator describing the ODE
// right-hand side, and define the ODE solver used for time integration.
FE_Evolution adv(*m, *k, *B);
FE_Evolution adv(*m, *k, *B, prec_type);
double t = 0.0;
adv.SetTime(t);
@@ -511,7 +599,7 @@ int main(int argc, char *argv[])
if (done || ti % vis_steps == 0)
{
if (myid == 0)
if (Mpi::Root())
{
cout << "time step: " << ti << ", time: " << t << endl;
if (cvode) { cvode->PrintInfo(); }
@@ -590,7 +678,7 @@ int main(int argc, char *argv[])
// Implementation of class FE_Evolution
FE_Evolution::FE_Evolution(ParBilinearForm &M_, ParBilinearForm &K_,
const Vector &b_)
const Vector &b_, PrecType prec_type)
: TimeDependentOperator(M_.Height()),
b(b_),
M_solver(M_.ParFESpace()->GetComm()),
@@ -617,7 +705,7 @@ FE_Evolution::FE_Evolution(ParBilinearForm &M_, ParBilinearForm &K_,
HypreSmoother *hypre_prec = new HypreSmoother(M_mat, HypreSmoother::Jacobi);
M_prec = hypre_prec;
dg_solver = new DG_Solver(M_mat, K_mat, *M_.FESpace());
dg_solver = new DG_Solver(M_mat, K_mat, *M_.FESpace(), prec_type);
}
else
{
@@ -633,6 +721,10 @@ FE_Evolution::FE_Evolution(ParBilinearForm &M_, ParBilinearForm &K_,
M_solver.SetPrintLevel(0);
}
// Solve the equation:
// u_t = M^{-1}(Ku + b),
// by solving associated linear system
// (M - dt*K) d = K*u + b
void FE_Evolution::ImplicitSolve(const double dt, const Vector &x, Vector &k)
{
K->Mult(x, z);
+24
View File
@@ -23,6 +23,8 @@ MFEM_LIB_FILE = mfem_is_not_built
SEQ_EXAMPLES = ex9 ex10 ex16
PAR_EXAMPLES = ex9p ex10p ex16p
SEQ_DEVICE_EXAMPLES = ex9
PAR_DEVICE_EXAMPLES = ex9p
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
else
@@ -54,10 +56,22 @@ include $(MFEM_TEST_MK)
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
SERIAL_NAME := Serial SUNDIALS example
PARALLEL_NAME := Parallel SUNDIALS example
SERIAL_CUDA_NAME := Serial SUNDIALS CUDA example
PARALLEL_CUDA_NAME := Parallel SUNDIALS CUDA example
SERIAL_HIP_NAME := Serial SUNDIALS HIP example
PARALLEL_HIP_NAME := Parallel SUNDIALS HIP example
%-test-par: %
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME))
%-test-seq: %
@$(call mfem-test,$<,, $(SERIAL_NAME))
%-test-par-cuda: %
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_CUDA_NAME),-d cuda)
%-test-seq-cuda: %
@$(call mfem-test,$<,, $(SERIAL_CUDA_NAME),-d cuda)
%-test-par-hip: %
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_HIP_NAME),-d hip)
%-test-seq-hip: %
@$(call mfem-test,$<,, $(SERIAL_HIP_NAME),-d hip)
# Testing: Specific execution options:
# Example 9: test CVODE with CV_ADAMS (non-stiff implicit) time stepping
@@ -68,6 +82,16 @@ ex9-test-seq: ex9
@$(call mfem-test,$<,, $(SERIAL_NAME),$(EX9_ARGS))
ex9p-test-par: ex9p
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME),$(EX9P_ARGS))
ex9-test-seq-cuda: ex9
@$(call mfem-test,$<,, $(SERIAL_CUDA_NAME),-d cuda $(EX9_ARGS))
ex9p-test-par-cuda: ex9p
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_CUDA_NAME),-d cuda \
$(EX9P_ARGS))
ex9-test-seq-hip: ex9
@$(call mfem-test,$<,, $(SERIAL_HIP_NAME),-d hip $(EX9_ARGS))
ex9p-test-par-hip: ex9p
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_HIP_NAME),-d hip \
$(EX9P_ARGS))
# Example 10: test CVODE with CV_BDF (stiff implicit) time stepping
EX10_COMMON_ARGS := -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -tf 6 -vs 10
EX10_ARGS := $(EX10_COMMON_ARGS) -r 2
+6 -4
View File
@@ -67,6 +67,7 @@ int main(int argc, char *argv[])
int slu_colperm = 4;
int slu_rowperm = 1;
int slu_iterref = 2;
int slu_npdep = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -85,9 +86,11 @@ int main(int argc, char *argv[])
"6-ZOLTAN");
args.AddOption(&slu_rowperm, "-rp", "--rowperm",
"SuperLU Row Permutation Method: 0-NOROWPERM, 1-LargeDiag");
args.AddOption(&slu_iterref, "-rp", "--rowperm",
args.AddOption(&slu_iterref, "-ir", "--iterref",
"SuperLU Iterative Refinement: 0-NOREFINE, 1-Single, "
"2-Double, 3-Extra");
args.AddOption(&slu_npdep, "-npdep", "--npdepth",
"Depth of 3D parition for SuperLU (>= 7.2.0)");
args.Parse();
if (!args.Good())
@@ -214,7 +217,7 @@ int main(int argc, char *argv[])
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
// 13. Solve the linear system A X = B utilizing SuperLU.
SuperLUSolver *superlu = new SuperLUSolver(MPI_COMM_WORLD);
SuperLUSolver *superlu = new SuperLUSolver(MPI_COMM_WORLD, slu_npdep);
Operator *SLU_A = new SuperLURowLocMatrix(*A.As<HypreParMatrix>());
superlu->SetPrintStatistics(true);
superlu->SetSymmetricPattern(false);
@@ -281,10 +284,9 @@ int main(int argc, char *argv[])
superlu->SetOperator(*SLU_A);
superlu->SetPrintStatistics(true);
superlu->Mult(B, X);
superlu->DismantleGrid();
delete SLU_A;
delete superlu;
delete SLU_A;
// 14. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
+45 -30
View File
@@ -13,28 +13,44 @@ set(SRCS
bilinearform.cpp
bilinearform_ext.cpp
bilininteg.cpp
bilininteg_br2.cpp
bilininteg_convection_mf.cpp
bilininteg_convection_pa.cpp
bilininteg_convection_ea.cpp
bilininteg_dgtrace_pa.cpp
bilininteg_dgtrace_ea.cpp
bilininteg_diffusion_mf.cpp
bilininteg_diffusion_pa.cpp
bilininteg_diffusion_ea.cpp
bilininteg_divergence.cpp
bilininteg_hcurl.cpp
bilininteg_hdiv.cpp
bilininteg_vectorfe.cpp
bilininteg_gradient.cpp
bilininteg_mass_mf.cpp
bilininteg_mass_pa.cpp
bilininteg_mass_ea.cpp
bilininteg_transpose_ea.cpp
bilininteg_vecdiffusion.cpp
bilininteg_vecdiffusion_mf.cpp
bilininteg_vecmass.cpp
bilininteg_vecmass_mf.cpp
integ/bilininteg_br2.cpp
integ/bilininteg_convection_mf.cpp
integ/bilininteg_convection_pa.cpp
integ/bilininteg_convection_ea.cpp
integ/bilininteg_curlcurl_pa.cpp
integ/bilininteg_dgtrace_pa.cpp
integ/bilininteg_dgtrace_ea.cpp
integ/bilininteg_diffusion_mf.cpp
integ/bilininteg_diffusion_pa.cpp
integ/bilininteg_diffusion_ea.cpp
integ/bilininteg_divdiv_pa.cpp
integ/bilininteg_gradient_pa.cpp
integ/bilininteg_interp_pa.cpp
integ/bilininteg_mass_mf.cpp
integ/bilininteg_mass_pa.cpp
integ/bilininteg_mass_ea.cpp
integ/bilininteg_mixedcurl_pa.cpp
integ/bilininteg_mixedvecgrad_pa.cpp
integ/bilininteg_transpose_ea.cpp
integ/bilininteg_vecdiffusion_mf.cpp
integ/bilininteg_vecdiffusion_pa.cpp
integ/bilininteg_vecdiv_pa.cpp
integ/bilininteg_vecmass_mf.cpp
integ/bilininteg_vecmass_pa.cpp
integ/bilininteg_vectorfediv_pa.cpp
integ/bilininteg_vectorfemass_pa.cpp
integ/bilininteg_diffusion_kernels.cpp
integ/bilininteg_hcurl_kernels.cpp
integ/bilininteg_hdiv_kernels.cpp
integ/bilininteg_hcurlhdiv_kernels.cpp
integ/bilininteg_mass_kernels.cpp
integ/lininteg_boundary.cpp
integ/lininteg_boundary_flux.cpp
integ/lininteg_domain.cpp
integ/lininteg_domain_grad.cpp
integ/lininteg_domain_vectorfe.cpp
integ/nonlininteg_vecconvection_pa.cpp
integ/nonlininteg_vecconvection_mf.cpp
coefficient.cpp
complex_fem.cpp
convergence.cpp
@@ -52,6 +68,7 @@ set(SRCS
fe/fe_nd.cpp
fe/fe_nurbs.cpp
fe/fe_pos.cpp
fe/fe_rbf.cpp
fe/fe_rt.cpp
fe/fe_ser.cpp
fe_coll.cpp
@@ -74,11 +91,6 @@ set(SRCS
linearform.cpp
linearform_ext.cpp
lininteg.cpp
lininteg_boundary.cpp
lininteg_boundary_flux.cpp
lininteg_domain.cpp
lininteg_domain_grad.cpp
lininteg_vectorfe_domain.cpp
lor/lor.cpp
lor/lor_ads.cpp
lor/lor_ams.cpp
@@ -91,8 +103,6 @@ set(SRCS
nonlinearform_ext.cpp
nonlininteg.cpp
fespacehierarchy.cpp
nonlininteg_vectorconvection.cpp
nonlininteg_vectorconvection_mf.cpp
qfunction.cpp
qinterp/det.cpp
qinterp/eval_by_nodes.cpp
@@ -143,7 +153,11 @@ set(HDRS
bilinearform.hpp
bilinearform_ext.hpp
bilininteg.hpp
bilininteg_mass_pa.hpp
integ/bilininteg_diffusion_kernels.hpp
integ/bilininteg_hcurl_kernels.hpp
integ/bilininteg_hdiv_kernels.hpp
integ/bilininteg_hcurlhdiv_kernels.hpp
integ/bilininteg_mass_kernels.hpp
coefficient.hpp
complex_fem.hpp
convergence.hpp
@@ -162,6 +176,7 @@ set(HDRS
fe/fe_nd.hpp
fe/fe_nurbs.hpp
fe/fe_pos.hpp
fe/fe_rbf.hpp
fe/fe_rt.hpp
fe/fe_ser.hpp
fe_coll.hpp
+86 -48
View File
@@ -56,6 +56,9 @@ void MFBilinearFormExtension::Assemble()
{
integrators[i]->AssembleMF(*a->FESpace());
}
MFEM_VERIFY(a->GetBBFI()->Size() == 0, "AddBoundaryIntegrator is not "
"currently supported in MFBilinearFormExtension");
}
void MFBilinearFormExtension::AssembleDiagonal(Vector &y) const
@@ -275,7 +278,9 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
int_face_Y.UseDevice(true); // ensure 'int_face_Y = 0.0' is done on device
}
if (bdr_face_restrict_lex == NULL && a->GetBFBFI()->Size() > 0)
const bool has_bdr_integs = (a->GetBFBFI()->Size() > 0 ||
a->GetBBFI()->Size() > 0);
if (bdr_face_restrict_lex == NULL && has_bdr_integs)
{
bdr_face_restrict_lex = trial_fes->GetFaceRestriction(
ElementDofOrdering::LEXICOGRAPHIC,
@@ -292,27 +297,27 @@ void PABilinearFormExtension::Assemble()
SetupRestrictionOperators(L2FaceValues::DoubleValued);
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int integratorCount = integrators.Size();
for (int i = 0; i < integratorCount; ++i)
for (BilinearFormIntegrator *integ : integrators)
{
integrators[i]->AssemblePA(*a->FESpace());
integ->AssemblePA(*a->FESpace());
}
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
"Partial assembly does not support AddBoundaryIntegrator yet.");
Array<BilinearFormIntegrator*> &bdr_integrators = *a->GetBBFI();
for (BilinearFormIntegrator *integ : bdr_integrators)
{
integ->AssemblePABoundary(*a->FESpace());
}
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int intFaceIntegratorCount = intFaceIntegrators.Size();
for (int i = 0; i < intFaceIntegratorCount; ++i)
for (BilinearFormIntegrator *integ : intFaceIntegrators)
{
intFaceIntegrators[i]->AssemblePAInteriorFaces(*a->FESpace());
integ->AssemblePAInteriorFaces(*a->FESpace());
}
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int boundFaceIntegratorCount = bdrFaceIntegrators.Size();
for (int i = 0; i < boundFaceIntegratorCount; ++i)
for (BilinearFormIntegrator *integ : bdrFaceIntegrators)
{
bdrFaceIntegrators[i]->AssemblePABoundaryFaces(*a->FESpace());
integ->AssemblePABoundaryFaces(*a->FESpace());
}
}
@@ -323,20 +328,27 @@ void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
const int iSz = integrators.Size();
if (elem_restrict && !DeviceCanUseCeed())
{
localY = 0.0;
for (int i = 0; i < iSz; ++i)
if (iSz > 0)
{
integrators[i]->AssembleDiagonalPA(localY);
}
const ElementRestriction* H1elem_restrict =
dynamic_cast<const ElementRestriction*>(elem_restrict);
if (H1elem_restrict)
{
H1elem_restrict->MultTransposeUnsigned(localY, y);
localY = 0.0;
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AssembleDiagonalPA(localY);
}
const ElementRestriction* H1elem_restrict =
dynamic_cast<const ElementRestriction*>(elem_restrict);
if (H1elem_restrict)
{
H1elem_restrict->MultTransposeUnsigned(localY, y);
}
else
{
elem_restrict->MultTranspose(localY, y);
}
}
else
{
elem_restrict->MultTranspose(localY, y);
y = 0.0;
}
}
else
@@ -348,6 +360,18 @@ void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
integrators[i]->AssembleDiagonalPA(y);
}
}
Array<BilinearFormIntegrator*> &bdr_integs = *a->GetBBFI();
const int n_bdr_integs = bdr_integs.Size();
if (bdr_face_restrict_lex && n_bdr_integs > 0)
{
bdr_face_Y = 0.0;
for (int i = 0; i < n_bdr_integs; ++i)
{
bdr_integs[i]->AssembleDiagonalPA(bdr_face_Y);
}
bdr_face_restrict_lex->AddMultTransposeUnsigned(bdr_face_Y, y);
}
}
void PABilinearFormExtension::Update()
@@ -397,13 +421,20 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
}
else
{
elem_restrict->Mult(x, localX);
localY = 0.0;
for (int i = 0; i < iSz; ++i)
if (iSz)
{
integrators[i]->AddMultPA(localX, localY);
elem_restrict->Mult(x, localX);
localY = 0.0;
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AddMultPA(localX, localY);
}
elem_restrict->MultTranspose(localY, y);
}
else
{
y = 0.0;
}
elem_restrict->MultTranspose(localY, y);
}
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
@@ -422,17 +453,24 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
}
}
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (bdr_face_restrict_lex && bFISz>0)
Array<BilinearFormIntegrator*> &bdr_integs = *a->GetBBFI();
Array<BilinearFormIntegrator*> &bdr_face_integs = *a->GetBFBFI();
const int n_bdr_integs = bdr_integs.Size();
const int n_bdr_face_integs = bdr_face_integs.Size();
const bool has_bdr_integs = (n_bdr_face_integs > 0 || n_bdr_integs > 0);
if (bdr_face_restrict_lex && has_bdr_integs)
{
bdr_face_restrict_lex->Mult(x, bdr_face_X);
if (bdr_face_X.Size()>0)
{
bdr_face_Y = 0.0;
for (int i = 0; i < bFISz; ++i)
for (int i = 0; i < n_bdr_integs; ++i)
{
bdrFaceIntegrators[i]->AddMultPA(bdr_face_X, bdr_face_Y);
bdr_integs[i]->AddMultPA(bdr_face_X, bdr_face_Y);
}
for (int i = 0; i < n_bdr_face_integs; ++i)
{
bdr_face_integs[i]->AddMultPA(bdr_face_X, bdr_face_Y);
}
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
}
@@ -596,7 +634,7 @@ void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
auto X = Reshape(useRestrict?localX.Read():x.Read(), NDOFS, ne);
auto Y = Reshape(useRestrict?localY.ReadWrite():y.ReadWrite(), NDOFS, ne);
auto A = Reshape(ea_data.Read(), NDOFS, NDOFS, ne);
MFEM_FORALL(glob_j, ne*NDOFS,
mfem::forall(ne*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
{
const int e = glob_j/NDOFS;
const int j = glob_j%NDOFS;
@@ -631,7 +669,7 @@ void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
if (!factorize_face_terms)
{
auto A_int = Reshape(ea_data_int.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
mfem::forall(nf_int*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
@@ -650,7 +688,7 @@ void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
});
}
auto A_ext = Reshape(ea_data_ext.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
mfem::forall(nf_int*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
@@ -687,7 +725,7 @@ void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
auto X = Reshape(bdr_face_X.Read(), NDOFS, nf_bdr);
auto Y = Reshape(bdr_face_Y.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
MFEM_FORALL(glob_j, nf_bdr*NDOFS,
mfem::forall(nf_bdr*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
@@ -724,7 +762,7 @@ void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
auto X = Reshape(useRestrict?localX.Read():x.Read(), NDOFS, ne);
auto Y = Reshape(useRestrict?localY.ReadWrite():y.ReadWrite(), NDOFS, ne);
auto A = Reshape(ea_data.Read(), NDOFS, NDOFS, ne);
MFEM_FORALL(glob_j, ne*NDOFS,
mfem::forall(ne*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
{
const int e = glob_j/NDOFS;
const int j = glob_j%NDOFS;
@@ -759,7 +797,7 @@ void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
if (!factorize_face_terms)
{
auto A_int = Reshape(ea_data_int.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
mfem::forall(nf_int*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
@@ -778,7 +816,7 @@ void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
});
}
auto A_ext = Reshape(ea_data_ext.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
mfem::forall(nf_int*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
@@ -815,7 +853,7 @@ void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
auto X = Reshape(bdr_face_X.Read(), NDOFS, nf_bdr);
auto Y = Reshape(bdr_face_Y.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
MFEM_FORALL(glob_j, nf_bdr*NDOFS,
mfem::forall(nf_bdr*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
@@ -1030,13 +1068,13 @@ void FABilinearFormExtension::DGMult(const Vector &x, Vector &y) const
const int local_size = a->FESpace()->GetVSize();
auto dg_x_ptr = dg_x.Write();
auto x_ptr = x.Read();
MFEM_FORALL(i,local_size,
mfem::forall(local_size, [=] MFEM_HOST_DEVICE (int i)
{
dg_x_ptr[i] = x_ptr[i];
});
const int shared_size = shared_x.Size();
auto shared_x_ptr = shared_x.Read();
MFEM_FORALL(i,shared_size,
mfem::forall(shared_size, [=] MFEM_HOST_DEVICE (int i)
{
dg_x_ptr[local_size+i] = shared_x_ptr[i];
});
@@ -1047,7 +1085,7 @@ void FABilinearFormExtension::DGMult(const Vector &x, Vector &y) const
// DG Restriction
auto dg_y_ptr = dg_y.Read();
auto y_ptr = y.ReadWrite();
MFEM_FORALL(i,local_size,
mfem::forall(local_size, [=] MFEM_HOST_DEVICE (int i)
{
y_ptr[i] += dg_y_ptr[i];
});
@@ -1091,13 +1129,13 @@ void FABilinearFormExtension::DGMultTranspose(const Vector &x, Vector &y) const
const int local_size = a->FESpace()->GetVSize();
auto dg_x_ptr = dg_x.Write();
auto x_ptr = x.Read();
MFEM_FORALL(i,local_size,
mfem::forall(local_size, [=] MFEM_HOST_DEVICE (int i)
{
dg_x_ptr[i] = x_ptr[i];
});
const int shared_size = shared_x.Size();
auto shared_x_ptr = shared_x.Read();
MFEM_FORALL(i,shared_size,
mfem::forall(shared_size, [=] MFEM_HOST_DEVICE (int i)
{
dg_x_ptr[local_size+i] = shared_x_ptr[i];
});
@@ -1108,7 +1146,7 @@ void FABilinearFormExtension::DGMultTranspose(const Vector &x, Vector &y) const
// DG Restriction
auto dg_y_ptr = dg_y.Read();
auto y_ptr = y.ReadWrite();
MFEM_FORALL(i,local_size,
mfem::forall(local_size, [=] MFEM_HOST_DEVICE (int i)
{
y_ptr[i] += dg_y_ptr[i];
});
@@ -1446,7 +1484,7 @@ void PADiscreteLinearOperatorExtension::Assemble()
}
auto tm = test_multiplicity.ReadWrite();
MFEM_FORALL(i, test_multiplicity.Size(),
mfem::forall(test_multiplicity.Size(), [=] MFEM_HOST_DEVICE (int i)
{
tm[i] = 1.0 / tm[i];
});
@@ -1498,7 +1536,7 @@ void PADiscreteLinearOperatorExtension::AddMultTranspose(
MFEM_VERIFY(x.Size() == test_multiplicity.Size(), "Input vector of wrong size");
auto xs = xscaled.ReadWrite();
auto tm = test_multiplicity.Read();
MFEM_FORALL(i, x.Size(),
mfem::forall(x.Size(), [=] MFEM_HOST_DEVICE (int i)
{
xs[i] *= tm[i];
});
+261 -35
View File
@@ -22,41 +22,47 @@ namespace mfem
void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&)
{
mfem_error ("BilinearFormIntegrator::AssemblePA(fes)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssemblePA(fes)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&,
const FiniteElementSpace&)
{
mfem_error ("BilinearFormIntegrator::AssemblePA(fes, fes)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssemblePA(fes, fes)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssemblePABoundary(const FiniteElementSpace&)
{
MFEM_ABORT("BilinearFormIntegrator::AssemblePABoundary(fes)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssemblePAInteriorFaces(const FiniteElementSpace&)
{
mfem_error ("BilinearFormIntegrator::AssemblePAInteriorFaces(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssemblePAInteriorFaces(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssemblePABoundaryFaces(const FiniteElementSpace&)
{
mfem_error ("BilinearFormIntegrator::AssemblePABoundaryFaces(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssemblePABoundaryFaces(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleDiagonalPA(Vector &)
{
mfem_error ("BilinearFormIntegrator::AssembleDiagonalPA(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssembleDiagonalPA(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &emat,
const bool add)
{
mfem_error ("BilinearFormIntegrator::AssembleEA(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssembleEA(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
@@ -65,8 +71,8 @@ void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
Vector &ea_data_ext,
const bool add)
{
mfem_error ("BilinearFormIntegrator::AssembleEAInteriorFaces(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssembleEAInteriorFaces(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace
@@ -74,8 +80,8 @@ void BilinearFormIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace
Vector &ea_data_bdr,
const bool add)
{
mfem_error ("BilinearFormIntegrator::AssembleEABoundaryFaces(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssembleEABoundaryFaces(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleDiagonalPA_ADAt(const Vector &, Vector &)
@@ -86,62 +92,62 @@ void BilinearFormIntegrator::AssembleDiagonalPA_ADAt(const Vector &, Vector &)
void BilinearFormIntegrator::AddMultPA(const Vector &, Vector &) const
{
mfem_error ("BilinearFormIntegrator::MultAssembled(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::MultAssembled(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AddMultTransposePA(const Vector &, Vector &) const
{
mfem_error ("BilinearFormIntegrator::AddMultTransposePA(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AddMultTransposePA(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleMF(const FiniteElementSpace &fes)
{
mfem_error ("BilinearFormIntegrator::AssembleMF(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssembleMF(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AddMultMF(const Vector &, Vector &) const
{
mfem_error ("BilinearFormIntegrator::AddMultMF(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AddMultMF(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AddMultTransposeMF(const Vector &, Vector &) const
{
mfem_error ("BilinearFormIntegrator::AddMultTransposeMF(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AddMultTransposeMF(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleDiagonalMF(Vector &)
{
mfem_error ("BilinearFormIntegrator::AssembleDiagonalMF(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssembleDiagonalMF(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleElementMatrix (
const FiniteElement &el, ElementTransformation &Trans,
DenseMatrix &elmat )
{
mfem_error ("BilinearFormIntegrator::AssembleElementMatrix(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssembleElementMatrix(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleElementMatrix2 (
const FiniteElement &el1, const FiniteElement &el2,
ElementTransformation &Trans, DenseMatrix &elmat )
{
mfem_error ("BilinearFormIntegrator::AssembleElementMatrix2(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssembleElementMatrix2(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleFaceMatrix (
const FiniteElement &el1, const FiniteElement &el2,
FaceElementTransformations &Trans, DenseMatrix &elmat)
{
mfem_error ("BilinearFormIntegrator::AssembleFaceMatrix(...)\n"
" is not implemented for this class.");
MFEM_ABORT("BilinearFormIntegrator::AssembleFaceMatrix(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleFaceMatrix(
@@ -153,6 +159,16 @@ void BilinearFormIntegrator::AssembleFaceMatrix(
" Integrator class.");
}
void BilinearFormIntegrator::AssembleTraceFaceMatrix (int elem,
const FiniteElement &trial_face_fe,
const FiniteElement &test_fe1,
FaceElementTransformations &Trans,
DenseMatrix &elmat)
{
MFEM_ABORT("AssembleTraceFaceMatrix (DPG form) is not implemented for this"
" Integrator class.");
}
void BilinearFormIntegrator::AssembleElementVector(
const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun,
Vector &elvect)
@@ -2633,7 +2649,7 @@ void VectorFEMassIntegrator::AssembleElementMatrix2(
}
else
{
mfem_error("VectorFEMassIntegrator::AssembleElementMatrix2(...)\n"
MFEM_ABORT("VectorFEMassIntegrator::AssembleElementMatrix2(...)\n"
" is not implemented for given trial and test bases.");
}
}
@@ -3997,6 +4013,216 @@ void NormalTraceJumpIntegrator::AssembleFaceMatrix(
}
}
void TraceIntegrator::AssembleTraceFaceMatrix(int elem,
const FiniteElement &trial_face_fe,
const FiniteElement &test_fe,
FaceElementTransformations & Trans,
DenseMatrix &elmat)
{
MFEM_VERIFY(test_fe.GetMapType() == FiniteElement::VALUE,
"TraceIntegrator::AssembleTraceFaceMatrix: Test space should be H1");
MFEM_VERIFY(trial_face_fe.GetMapType() == FiniteElement::INTEGRAL,
"TraceIntegrator::AssembleTraceFaceMatrix: Trial space should be RT trace");
int i, j, face_ndof, ndof;
int order;
face_ndof = trial_face_fe.GetDof();
ndof = test_fe.GetDof();
face_shape.SetSize(face_ndof);
shape.SetSize(ndof);
elmat.SetSize(ndof, face_ndof);
elmat = 0.0;
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
order = test_fe.GetOrder();
order += trial_face_fe.GetOrder();
ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
int iel = Trans.Elem1->ElementNo;
if (iel != elem)
{
MFEM_VERIFY(elem == Trans.Elem2->ElementNo, "Elem != Trans.Elem2->ElementNo");
}
double scale = 1.0;
if (iel != elem) { scale = -1.; }
for (int p = 0; p < ir->GetNPoints(); p++)
{
const IntegrationPoint &ip = ir->IntPoint(p);
// Set the integration point in the face and the neighboring elements
Trans.SetAllIntPoints(&ip);
// Trace finite element shape function
trial_face_fe.CalcPhysShape(Trans,face_shape);
// Finite element shape function
ElementTransformation * eltrans = (iel == elem) ? Trans.Elem1 : Trans.Elem2;
test_fe.CalcPhysShape(*eltrans, shape);
face_shape *= Trans.Weight()*ip.weight*scale;
for (i = 0; i < ndof; i++)
{
for (j = 0; j < face_ndof; j++)
{
elmat(i, j) += shape(i) * face_shape(j);
}
}
}
}
void NormalTraceIntegrator::AssembleTraceFaceMatrix(int elem,
const FiniteElement &trial_face_fe,
const FiniteElement &test_fe,
FaceElementTransformations &Trans,
DenseMatrix &elmat)
{
int i, j, face_ndof, ndof, dim;
int order;
MFEM_VERIFY(test_fe.GetMapType() == FiniteElement::H_DIV,
"NormalTraceIntegrator::AssembleTraceFaceMatrix: Test space should be RT");
MFEM_VERIFY(trial_face_fe.GetMapType() == FiniteElement::VALUE,
"NormalTraceIntegrator::AssembleTraceFaceMatrix: Trial space should be H1 (trace)");
face_ndof = trial_face_fe.GetDof();
ndof = test_fe.GetDof();
dim = test_fe.GetDim();
face_shape.SetSize(face_ndof);
normal.SetSize(dim);
shape.SetSize(ndof,dim);
shape_n.SetSize(ndof);
elmat.SetSize(ndof, face_ndof);
elmat = 0.0;
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
order = test_fe.GetOrder();
order += trial_face_fe.GetOrder();
ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
int iel = Trans.Elem1->ElementNo;
if (iel != elem)
{
MFEM_VERIFY(elem == Trans.Elem2->ElementNo, "Elem != Trans.Elem2->ElementNo");
}
double scale = 1.0;
if (iel != elem) { scale = -1.; }
for (int p = 0; p < ir->GetNPoints(); p++)
{
const IntegrationPoint &ip = ir->IntPoint(p);
Trans.SetAllIntPoints(&ip);
trial_face_fe.CalcPhysShape(Trans, face_shape);
CalcOrtho(Trans.Jacobian(),normal);
ElementTransformation * etrans = (iel == elem) ? Trans.Elem1 : Trans.Elem2;
test_fe.CalcVShape(*etrans, shape);
shape.Mult(normal, shape_n);
face_shape *= ip.weight*scale;
for (i = 0; i < ndof; i++)
{
for (j = 0; j < face_ndof; j++)
{
elmat(i, j) += shape_n(i) * face_shape(j);
}
}
}
}
void TangentTraceIntegrator::AssembleTraceFaceMatrix(int elem,
const FiniteElement &trial_face_fe,
const FiniteElement &test_fe,
FaceElementTransformations & Trans,
DenseMatrix &elmat)
{
MFEM_VERIFY(test_fe.GetMapType() == FiniteElement::H_CURL,
"TangentTraceIntegrator::AssembleTraceFaceMatrix: Test space should be ND");
int face_ndof, ndof, dim;
int order;
dim = test_fe.GetDim();
if (dim == 3)
{
std::string msg =
"Trial space should be ND face trace and test space should be a ND vector field in 3D ";
MFEM_VERIFY(trial_face_fe.GetMapType() == FiniteElement::H_CURL &&
trial_face_fe.GetDim() == 2 && test_fe.GetDim() == 3, msg);
}
else
{
std::string msg =
"Trial space should be H1 edge trace and test space should be a ND vector field in 2D";
MFEM_VERIFY(trial_face_fe.GetMapType() == FiniteElement::VALUE &&
trial_face_fe.GetDim() == 1 && test_fe.GetDim() == 2, msg);
}
face_ndof = trial_face_fe.GetDof();
ndof = test_fe.GetDof();
int dimc = (dim == 3) ? 3 : 1;
face_shape.SetSize(face_ndof,dimc);
shape_n.SetSize(ndof,dimc);
shape.SetSize(ndof,dim);
normal.SetSize(dim);
DenseMatrix face_shape_n(face_ndof,dimc);
elmat.SetSize(ndof, face_ndof);
elmat = 0.0;
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
order = test_fe.GetOrder();
order += trial_face_fe.GetOrder();
ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
int iel = Trans.Elem1->ElementNo;
if (iel != elem)
{
MFEM_VERIFY(elem == Trans.Elem2->ElementNo, "Elem != Trans.Elem2->ElementNo");
}
double scale = 1.0;
if (iel != elem) { scale = -1.; }
for (int p = 0; p < ir->GetNPoints(); p++)
{
const IntegrationPoint &ip = ir->IntPoint(p);
// Set the integration point in the face and the neighboring elements
Trans.SetAllIntPoints(&ip);
// Trace finite element shape function
if (dim == 3)
{
trial_face_fe.CalcVShape(Trans,face_shape);
}
else
{
face_shape.GetColumnReference(0,temp);
trial_face_fe.CalcPhysShape(Trans,temp);
}
CalcOrtho(Trans.Jacobian(),normal);
ElementTransformation * eltrans = (iel == elem) ? Trans.Elem1 : Trans.Elem2;
test_fe.CalcVShape(*eltrans, shape);
// rotate
cross_product(normal, shape, shape_n);
const double w = scale*ip.weight;
AddMult_a_ABt(w,shape_n, face_shape, elmat);
}
}
void NormalInterpolator::AssembleElementMatrix2(
const FiniteElement &dom_fe, const FiniteElement &ran_fe,
+109 -16
View File
@@ -61,6 +61,8 @@ public:
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes);
virtual void AssemblePABoundary(const FiniteElementSpace &fes);
virtual void AssemblePAInteriorFaces(const FiniteElementSpace &fes);
virtual void AssemblePABoundaryFaces(const FiniteElementSpace &fes);
@@ -159,6 +161,15 @@ public:
FaceElementTransformations &Trans,
DenseMatrix &elmat);
/** Abstract method used for assembling TraceFaceIntegrators for
DPG weak formulations. */
virtual void AssembleTraceFaceMatrix(int elem,
const FiniteElement &trial_face_fe,
const FiniteElement &test_fe,
FaceElementTransformations &Trans,
DenseMatrix &elmat);
/// @brief Perform the local action of the BilinearFormIntegrator.
/// Note that the default implementation in the base class is general but not
/// efficient.
@@ -292,6 +303,12 @@ public:
bfi->AssemblePA(fes);
}
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes)
{
bfi->AssemblePA(test_fes, trial_fes); // Reverse test and trial
}
virtual void AssemblePAInteriorFaces(const FiniteElementSpace &fes)
{
bfi->AssemblePAInteriorFaces(fes);
@@ -2183,8 +2200,9 @@ protected:
// PA extension
const FiniteElementSpace *fespace;
Vector pa_data;
const DofToQuad *maps; ///< Not owned
const GeometricFactors *geom; ///< Not owned
const DofToQuad *maps; ///< Not owned
const GeometricFactors *geom; ///< Not owned
const FaceGeometricFactors *face_geom; ///< Not owned
int dim, ne, nq, dofs1D, quad1D;
public:
@@ -2211,6 +2229,8 @@ public:
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssemblePABoundary(const FiniteElementSpace &fes);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
const bool add);
@@ -3301,6 +3321,87 @@ public:
DenseMatrix &elmat);
};
/** Integrator for the DPG form: < v, w > over a face (the interface) where
the trial variable v is defined on the interface
(H^-1/2 i.e., v:=un normal trace of H(div))
and the test variable w is in an H1-conforming space. */
class TraceIntegrator : public BilinearFormIntegrator
{
private:
Vector face_shape, shape;
public:
TraceIntegrator() { }
void AssembleTraceFaceMatrix(int elem,
const FiniteElement &trial_face_fe,
const FiniteElement &test_fe,
FaceElementTransformations &Trans,
DenseMatrix &elmat);
};
/** Integrator for the form: < v, w.n > over a face (the interface) where
the trial variable v is defined on the interface (H^1/2, i.e., trace of H1)
and the test variable w is in an H(div)-conforming space. */
class NormalTraceIntegrator : public BilinearFormIntegrator
{
private:
Vector face_shape, normal, shape_n;
DenseMatrix shape;
public:
NormalTraceIntegrator() { }
virtual void AssembleTraceFaceMatrix(int ielem,
const FiniteElement &trial_face_fe,
const FiniteElement &test_fe,
FaceElementTransformations &Trans,
DenseMatrix &elmat);
};
/** Integrator for the form: < v, w × n > over a face (the interface)
* In 3D the trial variable v is defined on the interface (H^-1/2(curl), trace of H(curl))
* In 2D it's defined on the interface (H^1/2, trace of H1)
* The test variable w is in an H(curl)-conforming space. */
class TangentTraceIntegrator : public BilinearFormIntegrator
{
private:
DenseMatrix face_shape, shape, shape_n;
Vector normal;
Vector temp;
void cross_product(const Vector & x, const DenseMatrix & Y, DenseMatrix & Z)
{
int dim = x.Size();
MFEM_VERIFY(Y.Width() == dim, "Size missmatch");
int dimc = dim == 3 ? dim : 1;
int h = Y.Height();
Z.SetSize(h,dimc);
if (dim == 3)
{
for (int i = 0; i<h; i++)
{
Z(i,0) = x(2) * Y(i,1) - x(1) * Y(i,2);
Z(i,1) = x(0) * Y(i,2) - x(2) * Y(i,0);
Z(i,2) = x(1) * Y(i,0) - x(0) * Y(i,1);
}
}
else
{
for (int i = 0; i<h; i++)
{
Z(i,0) = x(1) * Y(i,0) - x(0) * Y(i,1);
}
}
}
public:
TangentTraceIntegrator() { }
void AssembleTraceFaceMatrix(int elem,
const FiniteElement &trial_face_fe,
const FiniteElement &test_fe,
FaceElementTransformations &Trans,
DenseMatrix &elmat);
};
/** Abstract class to serve as a base for local interpolators to be used in the
DiscreteLinearOperator class. */
class DiscreteInterpolator : public BilinearFormIntegrator { };
@@ -3336,7 +3437,7 @@ public:
private:
/// 1D finite element that generates and owns the 1D DofToQuad maps below
FiniteElement * dofquad_fe;
FiniteElement *dofquad_fe;
bool B_id; // is the B basis operator (maps_C_C) the identity?
const DofToQuad *maps_C_C; // one-d map with Lobatto rows, Lobatto columns
@@ -3351,6 +3452,8 @@ private:
class IdentityInterpolator : public DiscreteInterpolator
{
public:
IdentityInterpolator(): dofquad_fe(NULL) { }
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
const FiniteElement &ran_fe,
ElementTransformation &Trans,
@@ -3365,9 +3468,11 @@ public:
virtual void AddMultPA(const Vector &x, Vector &y) const;
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
virtual ~IdentityInterpolator() { delete dofquad_fe; }
private:
/// 1D finite element that generates and owns the 1D DofToQuad maps below
FiniteElement * dofquad_fe;
FiniteElement *dofquad_fe;
const DofToQuad *maps_C_C; // one-d map with Lobatto rows, Lobatto columns
const DofToQuad *maps_O_C; // one-d map with Legendre rows, Lobatto columns
@@ -3522,17 +3627,5 @@ protected:
VectorCoefficient *VQ;
};
// PA Diffusion Assemble 2D kernel
template<const int T_SDIM>
void PADiffusionSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d);
}
#endif
File diff suppressed because it is too large Load Diff
-736
View File
@@ -1,736 +0,0 @@
// Copyright (c) 2010-2023, 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 "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "qfunction.hpp"
#include "ceed/integrators/mass/mass.hpp"
#include "bilininteg_mass_pa.hpp"
using namespace std;
namespace mfem
{
// PA Mass Integrator
// PA Mass Assemble kernel
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
Device::GetDeviceMemoryType() : pa_mt;
// Assuming the same element type
fespace = &fes;
Mesh *mesh = fes.GetMesh();
if (mesh->GetNE() == 0) { return; }
const FiniteElement &el = *fes.GetFE(0);
ElementTransformation *T0 = mesh->GetElementTransformation(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, *T0);
if (DeviceCanUseCeed())
{
delete ceedOp;
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedPAMassIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::PAMassIntegrator(fes, *ir, Q);
}
return;
}
int map_type = el.GetMapType();
dim = mesh->Dimension();
ne = fes.GetMesh()->GetNE();
nq = ir->GetNPoints();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::DETERMINANTS, mt);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(ne*nq, mt);
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(Q, qs, CoefficientStorage::COMPRESSED);
if (dim==1) { MFEM_ABORT("Not supported yet... stay tuned!"); }
if (dim==2)
{
const int NE = ne;
const int Q1D = quad1D;
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
const auto J = Reshape(geom->detJ.Read(), Q1D,Q1D,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D, NE);
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double detJ = J(qx,qy,e);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
v(qx,qy,e) = W(qx,qy) * coeff * (by_val ? detJ : 1.0/detJ);
}
}
});
}
if (dim==3)
{
const int NE = ne;
const int Q1D = quad1D;
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(geom->detJ.Read(), Q1D,Q1D,Q1D,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D,Q1D,NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double detJ = J(qx,qy,qz,e);
const double coeff = const_c ? C(0,0,0,0) : C(qx,qy,qz,e);
v(qx,qy,qz,e) = W(qx,qy,qz) * coeff * (by_val ? detJ : 1.0/detJ);
}
}
}
});
}
}
template<int T_D1D = 0, int T_Q1D = 0>
static void PAMassAssembleDiagonal2D(const int NE,
const Array<double> &b,
const Vector &d,
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 <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto D = Reshape(d.Read(), Q1D, Q1D, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL(e, NE,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double QD[MQ1][MD1];
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dy = 0; dy < D1D; ++dy)
{
QD[qx][dy] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
QD[qx][dy] += B(qy, dy) * B(qy, dy) * D(qx, qy, e);
}
}
}
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
for (int qx = 0; qx < Q1D; ++qx)
{
Y(dx,dy,e) += B(qx, dx) * B(qx, dx) * QD[qx][dy];
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
static void SmemPAMassAssembleDiagonal2D(const int NE,
const Array<double> &b_,
const Vector &d_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= MD1, "");
MFEM_VERIFY(Q1D <= MQ1, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D, Q1D, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
{
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 NBZ = T_NBZ ? T_NBZ : 1;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
MFEM_SHARED double B[MQ1][MD1];
MFEM_SHARED double QDZ[NBZ][MQ1][MD1];
double (*QD)[MD1] = (double (*)[MD1])(QDZ + tidz);
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
B[q][d] = b(q,d);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
QD[qx][dy] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
QD[qx][dy] += B[qy][dy] * B[qy][dy] * D(qx, qy, e);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
for (int qx = 0; qx < Q1D; ++qx)
{
// might need absolute values on next line
Y(dx,dy,e) += B[qx][dx] * B[qx][dx] * QD[qx][dy];
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void PAMassAssembleDiagonal3D(const int NE,
const Array<double> &b,
const Vector &d,
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 <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto D = Reshape(d.Read(), Q1D, Q1D, Q1D, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL(e, NE,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double QQD[MQ1][MQ1][MD1];
double QDD[MQ1][MD1][MD1];
for (int qx = 0; qx < Q1D; ++qx)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int dz = 0; dz < D1D; ++dz)
{
QQD[qx][qy][dz] = 0.0;
for (int qz = 0; qz < Q1D; ++qz)
{
QQD[qx][qy][dz] += B(qz, dz) * B(qz, dz) * D(qx, qy, qz, e);
}
}
}
}
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dz = 0; dz < D1D; ++dz)
{
for (int dy = 0; dy < D1D; ++dy)
{
QDD[qx][dy][dz] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
QDD[qx][dy][dz] += B(qy, dy) * B(qy, dy) * QQD[qx][qy][dz];
}
}
}
}
for (int dz = 0; dz < D1D; ++dz)
{
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
double t = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
t += B(qx, dx) * B(qx, dx) * QDD[qx][dy][dz];
}
Y(dx, dy, dz, e) += t;
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void SmemPAMassAssembleDiagonal3D(const int NE,
const Array<double> &b_,
const Vector &d_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= MD1, "");
MFEM_VERIFY(Q1D <= MQ1, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D, Q1D, Q1D, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
{
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 : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
MFEM_SHARED double B[MQ1][MD1];
MFEM_SHARED double QQD[MQ1][MQ1][MD1];
MFEM_SHARED double QDD[MQ1][MD1][MD1];
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
B[q][d] = b(q,d);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dz,z,D1D)
{
QQD[qx][qy][dz] = 0.0;
for (int qz = 0; qz < Q1D; ++qz)
{
QQD[qx][qy][dz] += B[qz][dz] * B[qz][dz] * D(qx, qy, qz, e);
}
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
QDD[qx][dy][dz] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
QDD[qx][dy][dz] += B[qy][dy] * B[qy][dy] * QQD[qx][qy][dz];
}
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double t = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
t += B[qx][dx] * B[qx][dx] * QDD[qx][dy][dz];
}
Y(dx, dy, dz, e) += t;
}
}
}
});
}
static void PAMassAssembleDiagonal(const int dim, const int D1D,
const int Q1D, const int NE,
const Array<double> &B,
const Vector &D,
Vector &Y)
{
if (dim == 2)
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPAMassAssembleDiagonal2D<2,2,16>(NE,B,D,Y);
case 0x33: return SmemPAMassAssembleDiagonal2D<3,3,16>(NE,B,D,Y);
case 0x44: return SmemPAMassAssembleDiagonal2D<4,4,8>(NE,B,D,Y);
case 0x55: return SmemPAMassAssembleDiagonal2D<5,5,8>(NE,B,D,Y);
case 0x66: return SmemPAMassAssembleDiagonal2D<6,6,4>(NE,B,D,Y);
case 0x77: return SmemPAMassAssembleDiagonal2D<7,7,4>(NE,B,D,Y);
case 0x88: return SmemPAMassAssembleDiagonal2D<8,8,2>(NE,B,D,Y);
case 0x99: return SmemPAMassAssembleDiagonal2D<9,9,2>(NE,B,D,Y);
default: return PAMassAssembleDiagonal2D(NE,B,D,Y,D1D,Q1D);
}
}
else if (dim == 3)
{
switch ((D1D << 4 ) | Q1D)
{
case 0x23: return SmemPAMassAssembleDiagonal3D<2,3>(NE,B,D,Y);
case 0x24: return SmemPAMassAssembleDiagonal3D<2,4>(NE,B,D,Y);
case 0x26: return SmemPAMassAssembleDiagonal3D<2,6>(NE,B,D,Y);
case 0x34: return SmemPAMassAssembleDiagonal3D<3,4>(NE,B,D,Y);
case 0x35: return SmemPAMassAssembleDiagonal3D<3,5>(NE,B,D,Y);
case 0x45: return SmemPAMassAssembleDiagonal3D<4,5>(NE,B,D,Y);
case 0x48: return SmemPAMassAssembleDiagonal3D<4,8>(NE,B,D,Y);
case 0x56: return SmemPAMassAssembleDiagonal3D<5,6>(NE,B,D,Y);
case 0x67: return SmemPAMassAssembleDiagonal3D<6,7>(NE,B,D,Y);
case 0x78: return SmemPAMassAssembleDiagonal3D<7,8>(NE,B,D,Y);
case 0x89: return SmemPAMassAssembleDiagonal3D<8,9>(NE,B,D,Y);
default: return PAMassAssembleDiagonal3D(NE,B,D,Y,D1D,Q1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
void MassIntegrator::AssembleDiagonalPA(Vector &diag)
{
if (DeviceCanUseCeed())
{
ceedOp->GetDiagonal(diag);
}
else
{
PAMassAssembleDiagonal(dim, dofs1D, quad1D, ne, maps->B, pa_data, diag);
}
}
#ifdef MFEM_USE_OCCA
// OCCA PA Mass Apply 2D kernel
static void OccaPAMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &Bt,
const Vector &D,
const Vector &X,
Vector &Y)
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
const occa::memory o_D = OccaMemoryRead(D.GetMemory(), D.Size());
const occa::memory o_X = OccaMemoryRead(X.GetMemory(), X.Size());
occa::memory o_Y = OccaMemoryReadWrite(Y.GetMemory(), Y.Size());
const occa_id_t id = std::make_pair(D1D,Q1D);
if (!Device::Allows(Backend::OCCA_CUDA))
{
static occa_kernel_t OccaMassApply2D_cpu;
if (OccaMassApply2D_cpu.find(id) == OccaMassApply2D_cpu.end())
{
const occa::kernel MassApply2D_CPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"MassApply2D_CPU", props);
OccaMassApply2D_cpu.emplace(id, MassApply2D_CPU);
}
OccaMassApply2D_cpu.at(id)(NE, o_B, o_Bt, o_D, o_X, o_Y);
}
else
{
static occa_kernel_t OccaMassApply2D_gpu;
if (OccaMassApply2D_gpu.find(id) == OccaMassApply2D_gpu.end())
{
const occa::kernel MassApply2D_GPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"MassApply2D_GPU", props);
OccaMassApply2D_gpu.emplace(id, MassApply2D_GPU);
}
OccaMassApply2D_gpu.at(id)(NE, o_B, o_Bt, o_D, o_X, o_Y);
}
}
// OCCA PA Mass Apply 3D kernel
static void OccaPAMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &Bt,
const Vector &D,
const Vector &X,
Vector &Y)
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
const occa::memory o_D = OccaMemoryRead(D.GetMemory(), D.Size());
const occa::memory o_X = OccaMemoryRead(X.GetMemory(), X.Size());
occa::memory o_Y = OccaMemoryReadWrite(Y.GetMemory(), Y.Size());
const occa_id_t id = std::make_pair(D1D,Q1D);
if (!Device::Allows(Backend::OCCA_CUDA))
{
static occa_kernel_t OccaMassApply3D_cpu;
if (OccaMassApply3D_cpu.find(id) == OccaMassApply3D_cpu.end())
{
const occa::kernel MassApply3D_CPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"MassApply3D_CPU", props);
OccaMassApply3D_cpu.emplace(id, MassApply3D_CPU);
}
OccaMassApply3D_cpu.at(id)(NE, o_B, o_Bt, o_D, o_X, o_Y);
}
else
{
static occa_kernel_t OccaMassApply3D_gpu;
if (OccaMassApply3D_gpu.find(id) == OccaMassApply3D_gpu.end())
{
const occa::kernel MassApply3D_GPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"MassApply3D_GPU", props);
OccaMassApply3D_gpu.emplace(id, MassApply3D_GPU);
}
OccaMassApply3D_gpu.at(id)(NE, o_B, o_Bt, o_D, o_X, o_Y);
}
}
#endif // MFEM_USE_OCCA
template<int T_D1D = 0, int T_Q1D = 0>
static void PAMassApply2D(const int NE,
const Array<double> &b_,
const Array<double> &bt_,
const Vector &d_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= MAX_D1D, "");
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= MAX_Q1D, "");
const auto B = b_.Read();
const auto Bt = bt_.Read();
const auto D = d_.Read();
const auto X = x_.Read();
auto Y = y_.ReadWrite();
MFEM_FORALL(e, NE,
{
internal::PAMassApply2D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
});
}
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
static void SmemPAMassApply2D(const int NE,
const Array<double> &b_,
const Array<double> &bt_,
const Vector &d_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_CONTRACT_VAR(bt_);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= MD1, "");
MFEM_VERIFY(Q1D <= MQ1, "");
const auto b = b_.Read();
const auto D = d_.Read();
const auto x = x_.Read();
auto Y = y_.ReadWrite();
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
{
internal::SmemPAMassApply2D_Element<T_D1D,T_Q1D,T_NBZ>(e, NE, b, D, x, Y, d1d, q1d);
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void PAMassApply3D(const int NE,
const Array<double> &b_,
const Array<double> &bt_,
const Vector &d_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= MAX_D1D, "");
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= MAX_Q1D, "");
const auto B = b_.Read();
const auto Bt = bt_.Read();
const auto D = d_.Read();
const auto X = x_.Read();
auto Y = y_.ReadWrite();
MFEM_FORALL(e, NE,
{
internal::PAMassApply3D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void SmemPAMassApply3D(const int NE,
const Array<double> &b_,
const Array<double> &bt_,
const Vector &d_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_CONTRACT_VAR(bt_);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int M1Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int M1D = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= M1D, "");
MFEM_VERIFY(Q1D <= M1Q, "");
auto b = b_.Read();
auto d = d_.Read();
auto x = x_.Read();
auto y = y_.ReadWrite();
MFEM_FORALL_3D(e, NE, Q1D, Q1D, 1,
{
internal::SmemPAMassApply3D_Element<T_D1D,T_Q1D>(e, NE, b, d, x, y, d1d, q1d);
});
}
static void PAMassApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &Bt,
const Vector &D,
const Vector &X,
Vector &Y)
{
#ifdef MFEM_USE_OCCA
if (DeviceCanUseOcca())
{
if (dim == 2)
{
return OccaPAMassApply2D(D1D,Q1D,NE,B,Bt,D,X,Y);
}
if (dim == 3)
{
return OccaPAMassApply3D(D1D,Q1D,NE,B,Bt,D,X,Y);
}
MFEM_ABORT("OCCA PA Mass Apply unknown kernel!");
}
#endif // MFEM_USE_OCCA
const int id = (D1D << 4) | Q1D;
if (dim == 2)
{
switch (id)
{
case 0x22: return SmemPAMassApply2D<2,2,16>(NE,B,Bt,D,X,Y);
case 0x24: return SmemPAMassApply2D<2,4,16>(NE,B,Bt,D,X,Y);
case 0x33: return SmemPAMassApply2D<3,3,16>(NE,B,Bt,D,X,Y);
case 0x34: return SmemPAMassApply2D<3,4,16>(NE,B,Bt,D,X,Y);
case 0x35: return SmemPAMassApply2D<3,5,16>(NE,B,Bt,D,X,Y);
case 0x36: return SmemPAMassApply2D<3,6,16>(NE,B,Bt,D,X,Y);
case 0x44: return SmemPAMassApply2D<4,4,8>(NE,B,Bt,D,X,Y);
case 0x46: return SmemPAMassApply2D<4,6,8>(NE,B,Bt,D,X,Y);
case 0x48: return SmemPAMassApply2D<4,8,4>(NE,B,Bt,D,X,Y);
case 0x55: return SmemPAMassApply2D<5,5,8>(NE,B,Bt,D,X,Y);
case 0x57: return SmemPAMassApply2D<5,7,8>(NE,B,Bt,D,X,Y);
case 0x58: return SmemPAMassApply2D<5,8,2>(NE,B,Bt,D,X,Y);
case 0x66: return SmemPAMassApply2D<6,6,4>(NE,B,Bt,D,X,Y);
case 0x77: return SmemPAMassApply2D<7,7,4>(NE,B,Bt,D,X,Y);
case 0x88: return SmemPAMassApply2D<8,8,2>(NE,B,Bt,D,X,Y);
case 0x99: return SmemPAMassApply2D<9,9,2>(NE,B,Bt,D,X,Y);
default: return PAMassApply2D(NE,B,Bt,D,X,Y,D1D,Q1D);
}
}
else if (dim == 3)
{
switch (id)
{
case 0x22: return SmemPAMassApply3D<2,2>(NE,B,Bt,D,X,Y);
case 0x23: return SmemPAMassApply3D<2,3>(NE,B,Bt,D,X,Y);
case 0x24: return SmemPAMassApply3D<2,4>(NE,B,Bt,D,X,Y);
case 0x26: return SmemPAMassApply3D<2,6>(NE,B,Bt,D,X,Y);
case 0x34: return SmemPAMassApply3D<3,4>(NE,B,Bt,D,X,Y);
case 0x35: return SmemPAMassApply3D<3,5>(NE,B,Bt,D,X,Y);
case 0x36: return SmemPAMassApply3D<3,6>(NE,B,Bt,D,X,Y);
case 0x37: return SmemPAMassApply3D<3,7>(NE,B,Bt,D,X,Y);
case 0x45: return SmemPAMassApply3D<4,5>(NE,B,Bt,D,X,Y);
case 0x46: return SmemPAMassApply3D<4,6>(NE,B,Bt,D,X,Y);
case 0x48: return SmemPAMassApply3D<4,8>(NE,B,Bt,D,X,Y);
case 0x56: return SmemPAMassApply3D<5,6>(NE,B,Bt,D,X,Y);
case 0x58: return SmemPAMassApply3D<5,8>(NE,B,Bt,D,X,Y);
case 0x67: return SmemPAMassApply3D<6,7>(NE,B,Bt,D,X,Y);
case 0x78: return SmemPAMassApply3D<7,8>(NE,B,Bt,D,X,Y);
case 0x89: return SmemPAMassApply3D<8,9>(NE,B,Bt,D,X,Y);
case 0x9A: return SmemPAMassApply3D<9,10>(NE,B,Bt,D,X,Y);
default: return PAMassApply3D(NE,B,Bt,D,X,Y,D1D,Q1D);
}
}
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
MFEM_ABORT("Unknown kernel.");
}
void MassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (DeviceCanUseCeed())
{
ceedOp->AddMult(x, y);
}
else
{
PAMassApply(dim, dofs1D, quad1D, ne, maps->B, maps->Bt, pa_data, x, y);
}
}
void MassIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const
{
// Mass integrator is symmetric
AddMultPA(x, y);
}
} // namespace mfem
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -288,7 +288,7 @@ void InitCoefficientWithIndices(mfem::Coefficient *Q, mfem::Mesh &mesh,
auto in = Reshape(qFun.Read(), nq, ne);
auto d_indices = Read(m_indices, nelem);
auto out = Reshape(ceedCoeff->coeff.Write(), nq, nelem);
MFEM_FORALL(i, nelem * nq,
mfem::forall(nelem * nq, [=] MFEM_HOST_DEVICE (int i)
{
const int q = i%nq;
const int sub_e = i/nq;
@@ -378,7 +378,7 @@ void InitCoefficientWithIndices(mfem::VectorCoefficient *VQ, mfem::Mesh &mesh,
auto in = Reshape(qFun.Read(), dim, nq, ne);
auto d_indices = Read(m_indices, nelem);
auto out = Reshape(ceedCoeff->coeff.Write(), dim, nq, nelem);
MFEM_FORALL(i, nelem * nq,
mfem::forall(nelem * nq, [=] MFEM_HOST_DEVICE (int i)
{
const int q = i%nq;
const int sub_e = i/nq;
+2 -2
View File
@@ -519,7 +519,7 @@ int CeedVectorPointwiseMult(CeedVector a, const CeedVector b)
ierr = CeedVectorGetArray(a, mem, &a_data); CeedChk(ierr);
ierr = CeedVectorGetArrayRead(b, mem, &b_data); CeedChk(ierr);
MFEM_VERIFY(int(length) == length, "length overflow");
MFEM_FORALL(i, length,
mfem::forall(length, [=] MFEM_HOST_DEVICE (int i)
{a_data[i] *= b_data[i];});
ierr = CeedVectorRestoreArray(a, &a_data); CeedChk(ierr);
@@ -593,7 +593,7 @@ void AlgebraicInterpolation::MultTranspose(const mfem::Vector& x,
&multiplicitydata); PCeedChk(ierr);
ierr = CeedVectorGetArrayWrite(fine_work, mem, &workdata); PCeedChk(ierr);
MFEM_VERIFY((int)length == length, "length overflow");
MFEM_FORALL(i, length,
mfem::forall(length, [=] MFEM_HOST_DEVICE (int i)
{workdata[i] = in_ptr[i] * multiplicitydata[i];});
ierr = CeedVectorRestoreArrayRead(fine_multiplicity_r,
&multiplicitydata);
+55 -5
View File
@@ -144,11 +144,54 @@ double FunctionCoefficient::Eval(ElementTransformation & T,
}
}
double CartesianCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
T.Transform(ip, transip);
return transip[comp];
}
double CylindricalRadialCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
T.Transform(ip, transip);
return sqrt(transip[0] * transip[0] + transip[1] * transip[1]);
}
double CylindricalAzimuthalCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
T.Transform(ip, transip);
return atan2(transip[1], transip[0]);
}
double SphericalRadialCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
T.Transform(ip, transip);
return sqrt(transip * transip);
}
double SphericalAzimuthalCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
T.Transform(ip, transip);
return atan2(transip[1], transip[0]);
}
double SphericalPolarCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
T.Transform(ip, transip);
return atan2(sqrt(transip[0] * transip[0] + transip[1] * transip[1]),
transip[2]);
}
double GridFunctionCoefficient::Eval (ElementTransformation &T,
const IntegrationPoint &ip)
{
Mesh *gf_mesh = GridF->FESpace()->GetMesh();
if (T.mesh == gf_mesh)
if (T.mesh->GetNE() == gf_mesh->GetNE())
{
return GridF->GetValue(T, ip, Component);
}
@@ -313,6 +356,13 @@ void PWVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
V = 0.0;
}
void PositionVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
V.SetSize(vdim);
T.Transform(ip, V);
}
void VectorFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
@@ -396,7 +446,7 @@ void VectorGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
if (T.mesh == gf_mesh)
if (T.mesh->GetNE() == gf_mesh->GetNE())
{
GridFunc->GetVectorValue(T, ip, V);
}
@@ -444,7 +494,7 @@ void GradientGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
if (T.mesh == gf_mesh)
if (T.mesh->GetNE() == gf_mesh->GetNE())
{
GridFunc->GetGradient(T, V);
}
@@ -485,7 +535,7 @@ void CurlGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
if (T.mesh == gf_mesh)
if (T.mesh->GetNE() == gf_mesh->GetNE())
{
GridFunc->GetCurl(T, V);
}
@@ -507,7 +557,7 @@ double DivergenceGridFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
if (T.mesh == gf_mesh)
if (T.mesh->GetNE() == gf_mesh->GetNE())
{
return GridFunc->GetDivergence(T);
}
+134
View File
@@ -258,6 +258,124 @@ public:
const IntegrationPoint &ip);
};
/// A common base class for returning individual components of the domain's
/// Cartesian coordinates.
class CartesianCoefficient : public Coefficient
{
protected:
int comp;
mutable Vector transip;
/// @a comp_ index of the desired component (0 -> x, 1 -> y, 2 -> z)
CartesianCoefficient(int comp_) : comp(comp_), transip(3) {}
public:
/// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
/// Scalar coefficient which returns the x-component of the evaluation point
class CartesianXCoefficient : public CartesianCoefficient
{
public:
CartesianXCoefficient() : CartesianCoefficient(0) {}
};
/// Scalar coefficient which returns the y-component of the evaluation point
class CartesianYCoefficient : public CartesianCoefficient
{
public:
CartesianYCoefficient() : CartesianCoefficient(1) {}
};
/// Scalar coefficient which returns the z-component of the evaluation point
class CartesianZCoefficient : public CartesianCoefficient
{
public:
CartesianZCoefficient() : CartesianCoefficient(2) {}
};
/// Scalar coefficient which returns the radial distance from the axis of
/// the evaluation point in the cylindrical coordinate system
class CylindricalRadialCoefficient : public Coefficient
{
private:
mutable Vector transip;
public:
CylindricalRadialCoefficient() : transip(3) {}
/// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
/// Scalar coefficient which returns the angular position or azimuth (often
/// denoted by theta) of the evaluation point in the cylindrical coordinate
/// system
class CylindricalAzimuthalCoefficient : public Coefficient
{
private:
mutable Vector transip;
public:
CylindricalAzimuthalCoefficient() : transip(3) {}
/// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
/// Scalar coefficient which returns the height or altitude of
/// the evaluation point in the cylindrical coordinate system
typedef CartesianZCoefficient CylindricalZCoefficient;
/// Scalar coefficient which returns the radial distance from the origin of
/// the evaluation point in the spherical coordinate system
class SphericalRadialCoefficient : public Coefficient
{
private:
mutable Vector transip;
public:
SphericalRadialCoefficient() : transip(3) {}
/// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
/// Scalar coefficient which returns the azimuthal angle (often denoted by phi)
/// of the evaluation point in the spherical coordinate system
class SphericalAzimuthalCoefficient : public Coefficient
{
private:
mutable Vector transip;
public:
SphericalAzimuthalCoefficient() : transip(3) {}
/// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
/// Scalar coefficient which returns the polar angle (often denoted by theta)
/// of the evaluation point in the spherical coordinate system
class SphericalPolarCoefficient : public Coefficient
{
private:
mutable Vector transip;
public:
SphericalPolarCoefficient() : transip(3) {}
/// Evaluate the coefficient at @a ip.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
class GridFunction;
/// Coefficient defined by a GridFunction. This coefficient is mesh dependent.
@@ -600,6 +718,22 @@ public:
using VectorCoefficient::Eval;
};
/// A vector coefficient which returns the physical location of the
/// evaluation point in the Cartesian coordinate system.
class PositionVectorCoefficient : public VectorCoefficient
{
public:
PositionVectorCoefficient(int dim) : VectorCoefficient(dim) {}
using VectorCoefficient::Eval;
/// Evaluate the vector coefficient at @a ip.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
virtual ~PositionVectorCoefficient() { }
};
/// A general vector function coefficient
class VectorFunctionCoefficient : public VectorCoefficient
{
+2 -2
View File
@@ -497,7 +497,7 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
auto d_X_r = X_r.Read();
auto d_X_i = X_i.Read();
auto d_idx = ess_tdof_list.Read();
MFEM_FORALL(i, n,
mfem::forall(n, [=] MFEM_HOST_DEVICE (int i)
{
const int j = d_idx[i];
d_B_r[j] = d_X_r[j];
@@ -1230,7 +1230,7 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
auto d_X_r = X_r.Read();
auto d_X_i = X_i.Read();
auto d_idx = ess_tdof_list.Read();
MFEM_FORALL(i, n,
mfem::forall(n, [=] MFEM_HOST_DEVICE (int i)
{
const int j = d_idx[i];
d_B_r[j] = d_X_r[j];
+2 -2
View File
@@ -107,7 +107,7 @@ void DGMassInverse::Update()
{
M->Assemble();
M->AssembleDiagonal(diag_inv);
internal::MakeReciprocal(diag_inv.Size(), diag_inv.ReadWrite());
diag_inv.Reciprocal();
}
DGMassInverse::~DGMassInverse()
@@ -168,7 +168,7 @@ void DGMassInverse::DGMassCGIteration(const Vector &b_, Vector &u_) const
constexpr int NB = Q1D ? Q1D : 1; // block size
MFEM_FORALL_2D(e, NE, NB, NB, 1,
mfem::forall_2D(NE, NB, NB, [=] MFEM_HOST_DEVICE (int e)
{
constexpr int NB = Q1D ? Q1D : 1; // redefine here for some compilers
+4 -2
View File
@@ -87,6 +87,8 @@ public:
///
/// If @ref iterative_mode is @a true, @a u is used as an initial guess.
void Mult(const Vector &b, Vector &u) const;
/// Same as Mult() since the mass matrix is symmetric.
void MultTranspose(const Vector &b, Vector &u) const { Mult(b, u); }
/// Not implemented. Aborts.
void SetOperator(const Operator &op);
/// Set the relative tolerance.
@@ -101,8 +103,8 @@ public:
~DGMassInverse();
/// @brief Solve the system M b = u. <b>Not part of the public interface.</b>
/// @note This member function must be public because it contains an
/// MFEM_FORALL kernel (nvcc limitation)
/// @note This member function must be public because it defines an
/// extended lambda used in an mfem::forall kernel (nvcc limitation)
template<int DIM, int D1D = 0, int Q1D = 0>
void DGMassCGIteration(const Vector &b_, Vector &u_) const;
};
+1 -6
View File
@@ -12,9 +12,9 @@
#ifndef MFEM_DGMASSINV_KERNELS_HPP
#define MFEM_DGMASSINV_KERNELS_HPP
#include "bilininteg_mass_pa.hpp"
#include "../linalg/kernels.hpp"
#include "kernels.hpp"
#include "integ/bilininteg_mass_kernels.hpp"
namespace mfem
{
@@ -22,11 +22,6 @@ namespace mfem
namespace internal
{
void MakeReciprocal(int n, double *x)
{
MFEM_FORALL(i, n, x[i] = 1.0/x[i]; );
}
template <int DIM, int D1D, int Q1D>
MFEM_HOST_DEVICE inline
void DGMassApply(const int e,
+1
View File
@@ -26,5 +26,6 @@
#include "fe/fe_nurbs.hpp"
#include "fe/fe_pos.hpp"
#include "fe/fe_ser.hpp"
#include "fe/fe_rbf.hpp"
#endif
+8 -3
View File
@@ -401,7 +401,7 @@ const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &ir,
}
}
}
else
else if (range_type == VECTOR)
{
d2q->B.SetSize(nqpt*dim*dof);
d2q->Bt.SetSize(dof*nqpt*dim);
@@ -419,6 +419,10 @@ const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &ir,
}
}
}
else
{
// Skip B and Bt for unknown range type
}
switch (deriv_type)
{
case GRAD:
@@ -472,7 +476,7 @@ const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &ir,
{
for (int j = 0; j < dof; j++)
{
d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = curlshape(j, d);
d2q->G[i+nqpt*(d+cdim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = curlshape(j, d);
}
}
}
@@ -480,7 +484,8 @@ const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &ir,
}
case NONE:
default:
MFEM_ABORT("invalid finite element derivative type");
// Skip G and Gt for unknown derivative type
break;
}
dof2quad_array.Append(d2q);
return *d2q;
+6 -6
View File
@@ -1026,9 +1026,6 @@ private:
static Array2D<int> binom;
static void CalcMono(const int p, const double x, double *u);
static void CalcMono(const int p, const double x, double *u, double *d);
static void CalcChebyshev(const int p, const double x, double *u);
static void CalcChebyshev(const int p, const double x, double *u, double *d);
static void CalcChebyshev(const int p, const double x, double *u, double *d,
@@ -1165,6 +1162,9 @@ public:
static void CalcLegendre(const int p, const double x, double *u);
static void CalcLegendre(const int p, const double x, double *u, double *d);
static void CalcMono(const int p, const double x, double *u);
static void CalcMono(const int p, const double x, double *u, double *d);
~Poly_1D();
};
@@ -1288,9 +1288,9 @@ public:
const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode) const override
{
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
return GetTensorDofToQuad(*this, ir, mode, basis1d, true,
dof2quad_array);
return (mode == DofToQuad::FULL) ?
FiniteElement::GetDofToQuad(ir, mode) :
GetTensorDofToQuad(*this, ir, mode, basis1d, true, dof2quad_array);
}
const DofToQuad &GetDofToQuadOpen(const IntegrationRule &ir,
+1470
View File
File diff suppressed because it is too large Load Diff
+596
View File
@@ -0,0 +1,596 @@
// Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_FE_RBF
#define MFEM_FE_RBF
#include "fe_base.hpp"
namespace mfem
{
/** @brief Pure virtual class for dimensionless radial basis functions (RBFs).
Many RBFs are shaped like a Gaussian and are used here as an alternative
to polynomials in RBF and RK elements. The input for these
is a dimensionless radius r = ||x|| / h, where ||x|| is a distance and
h is the smoothing parameter, which controls the gradient of the RBF.
For reference: https://doi.org/10.1017/S0962492900000015 */
class RBFKernel
{
public:
static const double GlobalRadius; // functions with r>=GR are considered global
RBFKernel() { };
virtual ~RBFKernel() { }
/// Evaluate the dimensionless RBF
virtual double BaseFunction(double r) const = 0;
/// Evaluate the derivative of the dimensionless RBF with respect to r
virtual double BaseDerivative(double r) const = 0;
/// Evaluate the second derivative of the dimensionless RBF with respect to r
virtual double BaseDerivative2(double r) const = 0;
/// The support radius, outside of which the function is zero if the function has compact support
virtual double Radius() const { return GlobalRadius; }
/// Does function have compact support?
virtual bool CompactSupport() const { return false; }
/** #brief This normalizes the smoothing parameter h such that h doesn't
need to be changed based on the choice of basis function */
virtual double HNorm() const = 0;
};
/// Gaussian RBF, exp(-r^2)
class GaussianRBF : public RBFKernel
{
// hNorm minimizes integral of Gaussian minus Wendland kernel over r=0,1
static const double hNorm;
public:
GaussianRBF() { };
virtual ~GaussianRBF() { }
virtual double BaseFunction(double r) const;
virtual double BaseDerivative(double r) const;
virtual double BaseDerivative2(double r) const;
virtual double HNorm() const { return hNorm; }
};
/// Multiquadric RBF, sqrt(1+r^2)
class MultiquadricRBF : public RBFKernel
{
// Same as inverse multiquadric
static const double hNorm;
public:
MultiquadricRBF() { };
virtual ~MultiquadricRBF() { }
virtual double BaseFunction(double r) const;
virtual double BaseDerivative(double r) const;
virtual double BaseDerivative2(double r) const;
virtual double HNorm() const { return hNorm; }
};
/// Inverse multiquadric RBF, 1/sqrt(1+r^2)
class InvMultiquadricRBF : public RBFKernel
{
// hNorm minimizes integral of Gaussian minus InvMQ kernel over r=0,0.5
static const double hNorm;
public:
InvMultiquadricRBF() { };
virtual ~InvMultiquadricRBF() { }
virtual double BaseFunction(double r) const;
virtual double BaseDerivative(double r) const;
virtual double BaseDerivative2(double r) const;
virtual double HNorm() const { return hNorm; }
};
/** @brief Identitcal to the Gaussian RBF, but subtracted by a factor
such that the function is exactly zero at the chosen radius */
class CompactGaussianRBF : public RBFKernel
{
static const double hNorm;
const double radius;
double multK, shiftK;
public:
CompactGaussianRBF(const double rad = 5.0);
virtual ~CompactGaussianRBF() { }
virtual double BaseFunction(double r) const;
virtual double BaseDerivative(double r) const;
virtual double BaseDerivative2(double r) const;
virtual double Radius() const { return radius; }
virtual double HNorm() const { return hNorm; }
virtual bool CompactSupport() const { return true; }
};
/// Identical to the Gaussian, but truncated (set to zero) at the chosen radius
class TruncatedGaussianRBF : public RBFKernel
{
static const double hNorm;
const double radius;
public:
TruncatedGaussianRBF(const double rad = 5.0)
: radius(rad) { }
virtual ~TruncatedGaussianRBF() { }
virtual double BaseFunction(double r) const;
virtual double BaseDerivative(double r) const;
virtual double BaseDerivative2(double r) const;
virtual double Radius() const { return radius; }
virtual double HNorm() const { return hNorm; }
virtual bool CompactSupport() const { return true; }
};
/// Wendland 11 RBF, (1-r)^3 * (1+3r) if r < 1
class Wendland11RBF : public RBFKernel
{
static const double radius;
public:
Wendland11RBF() { }
virtual ~Wendland11RBF() { }
virtual double BaseFunction(double r) const;
virtual double BaseDerivative(double r) const;
virtual double BaseDerivative2(double r) const;
virtual double Radius() const { return radius; }
virtual double HNorm() const { return 1.0 / radius; }
virtual bool CompactSupport() const { return true; }
};
/// Wendland 31 RBF, (1-r)^4 * (1+4r) if r < 1
class Wendland31RBF : public RBFKernel
{
static const double radius;
public:
Wendland31RBF() { };
virtual ~Wendland31RBF() { }
virtual double BaseFunction(double r) const;
virtual double BaseDerivative(double r) const;
virtual double BaseDerivative2(double r) const;
virtual double Radius() const { return radius; }
virtual double HNorm() const { return 1.0 / radius; }
virtual bool CompactSupport() const { return true; }
};
/// Wendland 33 RBF, (1-r)^8 * (1+8r+25r^2+32r^3) if r < 1
class Wendland33RBF : public RBFKernel
{
static const double radius;
public:
Wendland33RBF() { };
virtual ~Wendland33RBF() { }
virtual double BaseFunction(double r) const;
virtual double BaseDerivative(double r) const;
virtual double BaseDerivative2(double r) const;
virtual double Radius() const { return radius; }
virtual double HNorm() const { return 1.0 / radius; }
virtual bool CompactSupport() const { return true; }
};
/// Class for storing and creating the various RBFs
class RBFType
{
public:
/// Represent each type of function for input/output
enum
{
Gaussian = 0,
Multiquadric = 1,
InvMultiquadric = 2,
TruncatedGaussian = 3,
CompactGaussian = 4,
Wendland11 = 5,
Wendland31 = 6,
Wendland33 = 7,
NumRBFTypes = 8
};
/// Return the requested RBF
static RBFKernel *GetRBF(const int rbfType)
{
switch (rbfType)
{
case RBFType::Gaussian:
return new GaussianRBF();
case RBFType::Multiquadric:
return new MultiquadricRBF();
case RBFType::InvMultiquadric:
return new InvMultiquadricRBF();
case RBFType::TruncatedGaussian:
return new TruncatedGaussianRBF();
case RBFType::CompactGaussian:
return new CompactGaussianRBF();
case RBFType::Wendland11:
return new Wendland11RBF();
case RBFType::Wendland31:
return new Wendland31RBF();
case RBFType::Wendland33:
return new Wendland33RBF();
}
MFEM_ABORT("unknown RBF type");
return NULL;
}
/// Abort if rbfType is invalid
static int Check(const int rbfType)
{
MFEM_VERIFY(0 <= rbfType && rbfType < NumRBFTypes,
"unknown RBF type: " << rbfType);
return rbfType;
}
/// Convert rbf int to identifier for storage
static char GetChar(const int rbfType)
{
static const char ident[] = { 'G', 'M', 'I',
'T', 'C',
'1', '3', '6'
};
return ident[Check(rbfType)];
}
/// Convert identifier to rbf int
static int GetType(const char rbfIdent)
{
switch (rbfIdent)
{
case 'G': return Gaussian;
case 'M': return Multiquadric;
case 'I': return InvMultiquadric;
case 'T': return TruncatedGaussian;
case 'C': return CompactGaussian;
case '1': return Wendland11;
case '3': return Wendland31;
case '6': return Wendland33;
}
MFEM_ABORT("unknown RBF identifier: " << rbfIdent);
return -1;
}
};
/// Dimensionless distance metrics, whose output is the input for RBFs
class DistanceMetric
{
protected:
int dim;
public:
/** @brief Create a distance metric
@param D Reference space dimension */
DistanceMetric(int D) { dim = D; }
virtual ~DistanceMetric() { }
/// Set the reference dimension
virtual void SetDim(int D) { dim = D; }
/// Given a vector of length D, return a physical distance
virtual void Distance(const Vector &x,
double &r) const = 0;
/** @brief Given a vector of length D, return the gradient of the
distance with respect to the original coordinates */
virtual void DDistance(const Vector &x,
Vector &dr) const = 0;
/** @brief Given a vector of length D, return the Hessian of the
distance with respect to the original coordinates */
virtual void DDDistance(const Vector &x,
DenseMatrix &ddr) const = 0;
/// Create an Lp distance metric for the requested dimension and norm
static DistanceMetric *GetDistance(int dim, int pnorm);
};
/// Dimensionless distance with r = |x| + |y| + ...
class L1Distance : public DistanceMetric
{
public:
L1Distance(int D) : DistanceMetric(D) { };
virtual ~L1Distance() { }
virtual void Distance(const Vector &x,
double &r) const;
virtual void DDistance(const Vector &x,
Vector &dr) const;
virtual void DDDistance(const Vector &x,
DenseMatrix &ddr) const;
};
/// Dimensionless distance with r = (x^2 + y^2 + ...)^(1/2)
class L2Distance : public DistanceMetric
{
public:
L2Distance(int D) : DistanceMetric(D) { };
virtual ~L2Distance() { }
virtual void Distance(const Vector &x,
double &r) const;
virtual void DDistance(const Vector &x,
Vector &dr) const;
virtual void DDDistance(const Vector &x,
DenseMatrix &ddr) const;
};
/// Dimensionless distance with r = (x^p + y^p + ...)^(1/p)
class LpDistance : public DistanceMetric
{
const int p;
const double pinv;
public:
LpDistance(int D, int pnorm)
: DistanceMetric(D),
p(pnorm),
pinv(1. / static_cast<double>(p))
{ };
virtual ~LpDistance() { }
virtual void Distance(const Vector &x,
double &r) const;
virtual void DDistance(const Vector &x,
Vector &dr) const;
virtual void DDDistance(const Vector &x,
DenseMatrix &ddr) const;
};
/** @brief Pure virtual class for a finite element with radial basis functions
instead of polynomials inside each element */
class KernelFiniteElement : public ScalarFiniteElement
{
private:
// Choose whether to interpolate or project when Project is called
bool interpolate = false;
public:
KernelFiniteElement(int D, Geometry::Type G, int Do, int O, int F)
: ScalarFiniteElement(D, G, Do, O, F) { }
virtual ~KernelFiniteElement() { }
/// Converts integration rule to vector
virtual void IntRuleToVec(const IntegrationPoint &ip,
Vector &vec) const;
/// Is base RBF compact?
virtual bool IsCompact() const = 0;
/// Return base kernel
virtual const RBFKernel *Kernel() const = 0;
/** @brief Return whether shape function is a tensor product, used in providing indices for compact support */
virtual bool TensorIndexed() const { return false; }
/** @brief Get range of indices (start and end for each dimension) that
that are nonzero for compact support for the given integration point */
virtual void GetTensorIndices(const Vector &ip,
int (&indices)[3][2]) const
{ MFEM_ABORT("GetTensorIndices(...)"); }
/** @brief Return total number of points in each dimension for tensor-
indexed points */
virtual void GetTensorNumPoints(int (&tNumPoints)[3]) const
{ MFEM_ABORT("GetTensorNumPoints(...)"); }
using FiniteElement::Project;
virtual void Project(Coefficient &coeff, ElementTransformation &Trans,
Vector &dofs) const;
virtual void Project(VectorCoefficient &vc, ElementTransformation &Trans,
Vector &dofs) const;
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
DenseMatrix &I) const;
virtual void GetLocalInterpolation(ElementTransformation &Trans,
DenseMatrix &I) const
{ ScalarLocalInterpolation(Trans, I, *this); }
virtual void GetTransferMatrix(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &I) const
{ CheckScalarFE(fe).ScalarLocalInterpolation(Trans, I, *this); }
};
/** @brief Finite element using base radial basis functions without
polynomial corrections. */
class RBFFiniteElement : public KernelFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable double r_scr, df_scr, ddf_scr;
mutable Vector x_scr, y_scr, dy_scr, dr_scr;
mutable DenseMatrix ddr_scr;
mutable int cInd[3][2];
#endif
bool isCompact;
int dimPoints[3];
int numPointsD;
double delta; // Distance between points
double h;
double hPhys; // Shape parameter times distance between points times HNorm
double hPhysInv; // Inverse hPhys
double radPhys; // Radius adjusted by h
double faceFactor;
const RBFKernel *rbf;
const DistanceMetric *distance;
void InitializeGeometry();
// Get the dimensionless distance from x to the center of the RBF indexed i
virtual void DistanceVec(const int i,
const Vector &x,
Vector &y) const;
public:
/** @brief Construct RBFFiniteElement
@param D Reference space dimension
@param numPointsD Number of points across the element in each dimension
@param rbfType Type of radial basis function, from RBFType
@param distNorm Norm used for distance, usually 2 = Euclidean distance
@param intOrder Number of integration points per RBF point in each dimension
@param h Shape parameter, approximately equal to the number of points in the support radius in one dimension
@param faceFactor 1.0 = points end on face, 0.0 = points end at dx/2 from face
*/
RBFFiniteElement(const int D,
const int numPointsD,
const int rbfType,
const int distNorm,
const int intOrder,
const double h,
const double faceFactor);
virtual ~RBFFiniteElement() { delete rbf; delete distance; }
virtual bool TensorIndexed() const { return true; }
virtual void GetCompactIndices(const Vector &ip,
int (&indices)[3][2]) const;
virtual void GetGlobalIndices(const Vector &ip,
int (&indices)[3][2]) const;
virtual void GetTensorIndices(const Vector &ip,
int (&indices)[3][2]) const;
virtual void GetTensorNumPoints(int (&tNumPoints)[3]) const
{
tNumPoints[0] = dimPoints[0];
tNumPoints[1] = dimPoints[1];
tNumPoints[2] = dimPoints[2];
}
virtual bool IsCompact() const { return isCompact; }
virtual const RBFKernel *Kernel() const { return rbf; }
virtual void CalcShape(const IntegrationPoint &ip,
Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &hess) const;
};
/** @brief Reproducing kernel finite element, which includes polynomial
corrections to the standard radial basis function finite element
to guarantee a chosen order of accuracy */
class RKFiniteElement : public KernelFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable double f_scr;
mutable Vector x_scr, y_scr, g_scr, c_scr, s_scr, p_scr, df_scr;
mutable DenseMatrix q_scr, dq_scr, M_scr;
mutable Vector dc_scr[3], dp_scr[3];
mutable DenseMatrix dM_scr[3];
mutable DenseMatrixInverse Minv_scr;
mutable int cInd[3][2];
mutable int dimPoints[3];
#endif
int polyOrd, numPoly, numPoly1d;
KernelFiniteElement *baseFE;
// Get the vector of polynomials for the corrections, evaluated at x
virtual void GetPoly(const Vector &x,
Vector &p) const;
virtual void GetDPoly(const Vector &x,
Vector &p,
Vector (&dp)[3]) const;
/* Helper functions that return pieces of the RK evaluation
W_{RK,i} = P_i^T C_i W_{RBF,i}, where
P_i = [1, x, y, z, ...] is the polynomial vector evaluated at the point i,
M_i = P_i P_i^T W_{RBF,i} is a matrix used in calculating the corrections,
C_i = M_i^{-1} G are the RK corrections,
G = [1, 0, 0, ...] is a convencience vector */
virtual void GetG(Vector &g) const;
virtual void GetM(const Vector &baseShape,
const IntegrationPoint &ip,
DenseMatrix &M) const;
virtual void GetDM(const Vector &baseShape,
const DenseMatrix &baseDeriv,
const IntegrationPoint &ip,
DenseMatrix &M,
DenseMatrix (&dM)[3]) const;
virtual void AddToM(const Vector &p,
const double &f,
DenseMatrix &M) const;
virtual void AddToDM(const Vector &p,
const Vector (&dp)[3],
const double &f,
const Vector &df,
DenseMatrix (&dM)[3]) const;
// Given the corrections and base values, calculate the RK value at the ip
virtual void CalculateValues(const Vector &c,
const Vector &baseShape,
const IntegrationPoint &ip,
Vector &shape) const;
virtual void CalculateDValues(const Vector &c,
const Vector (&dc)[3],
const Vector &baseShape,
const DenseMatrix &baseDShape,
const IntegrationPoint &ip,
DenseMatrix &dshape) const;
// The corrections make the distance dimensionless, so no smoothing parameter
virtual void DistanceVec(const int i,
const Vector &x,
Vector &y) const;
public:
/** @brief Construct RBFFiniteElement
@param D Reference space dimension
@param numPointsD Number of points across the element in each dimension
@param rbfType Type of radial basis function, from RBFType
@param distNorm Norm used for distance, usually 2 = Euclidean distance
@param order Order of polynomial correction, >= 0
@param intOrder Number of integration points per RBF point in each dimension
@param h Shape parameter, approximately equal to the number of points in the support radius in one dimension
@param faceFactor 1.0 = points end on face, 0.0 = points end at dx/2 from face
*/
RKFiniteElement(const int D,
const int numPointsD,
const int rbfType,
const int distNorm,
const int order,
const int intOrder,
const double h,
const double faceFactor);
virtual ~RKFiniteElement() { delete baseFE; }
virtual bool IsCompact() const { return baseFE->IsCompact(); }
virtual const RBFKernel *Kernel() const { return baseFE->Kernel(); }
static int GetNumPoly(int polyOrd, int dim);
virtual void CalcShape(const IntegrationPoint &ip,
Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
} // end namespace mfem
#endif
+210
View File
@@ -347,6 +347,36 @@ FiniteElementCollection *FiniteElementCollection::New(const char *name)
fec = new NURBSFECollection();
}
}
else if (!strncmp(name, "RBF", 3) || !strncmp(name, "RK", 2))
{
// Example: RK4_G_2_V_2D_0020_1.00_4.01
// (RK order 4, Gaussian, L2 dist, Value map, 2 dimensions,
// 20 points across element, face factor 1.0, smoothing length of 4.01)
const int dim = atoi(name + 10);
const int numPoints = atoi(name + 13);
const double h = atof(name + 23);
const double faceFactor = atof(name + 18);
const int rbfType = RBFType::GetType(name[4]);
const int distNorm = atoi(name + 6);
const int mapType = (name[8] == 'V'
? FiniteElement::VALUE
: FiniteElement::INTEGRAL);
const int intOrder = 2; // keep this fixed for now
if (!strncmp(name, "RK", 2))
{
int order = atoi(name + 2);
fec = new LocalKernelFECollection(dim, numPoints, rbfType,
order, h, faceFactor,
intOrder, distNorm, mapType);
}
else
{
fec = new LocalKernelFECollection(dim, numPoints, rbfType,
-1, h, faceFactor,
intOrder, distNorm, mapType);
}
}
else
{
MFEM_ABORT("unknown FiniteElementCollection: " << name);
@@ -3510,4 +3540,184 @@ FiniteElementCollection *NURBSFECollection::GetTraceCollection() const
return NULL;
}
LocalKernelFECollection::LocalKernelFECollection(const int dim,
const int numPointsD,
const int rbfType,
const int order,
const double h,
const double faceFactor,
const int intOrder,
const int distNorm,
const int mapType)
{
const char *mapStr = NULL;
switch (mapType)
{
case FiniteElement::VALUE: mapStr = "V"; break;
case FiniteElement::INTEGRAL: mapStr = "I"; break;
default:
MFEM_ABORT("invalid mapType: " << mapType);
}
if (order == -1)
{
snprintf(d_name, 32, "RBF_%c_%d_%s_%dD_%04d_%1.2f_%.2f",
(int)RBFType::GetChar(rbfType), distNorm,
mapStr, dim, numPointsD, faceFactor, h);
}
else if (order >= 0)
{
snprintf(d_name, 32, "RK%d_%c_%d_%s_%dD_%04d_%1.2f_%.2f", order,
(int)RBFType::GetChar(rbfType), distNorm,
mapStr, dim, numPointsD, faceFactor, h);
}
else
{
MFEM_ABORT("invalid order: " << order);
}
for (int g = 0; g < Geometry::NumGeom; ++g)
{
L2_Elements[g] = NULL;
Tr_Elements[g] = NULL;
}
for (int i = 0; i < 2; i++)
{
SegDofOrd[i] = NULL;
}
OtherDofOrd = NULL;
if (dim == 0)
{
L2_Elements[Geometry::POINT] = new PointFiniteElement;
}
else if (dim == 1)
{
if (order == -1)
{
L2_Elements[Geometry::SEGMENT]
= new RBFFiniteElement(1, numPointsD, rbfType, distNorm,
intOrder, h, faceFactor);
}
else
{
L2_Elements[Geometry::SEGMENT]
= new RKFiniteElement(1, numPointsD, rbfType, distNorm,
order, intOrder, h, faceFactor);
}
L2_Elements[Geometry::SEGMENT]->SetMapType(mapType);
Tr_Elements[Geometry::POINT] = new PointFiniteElement;
}
else if (dim == 2)
{
if (order == -1)
{
L2_Elements[Geometry::SQUARE]
= new RBFFiniteElement(2, numPointsD, rbfType, distNorm,
intOrder, h, faceFactor);
Tr_Elements[Geometry::SEGMENT]
= new RBFFiniteElement(1, numPointsD, rbfType, distNorm,
intOrder, h, faceFactor);
}
else
{
L2_Elements[Geometry::SQUARE]
= new RKFiniteElement(2, numPointsD, rbfType, distNorm,
order, intOrder, h, faceFactor);
Tr_Elements[Geometry::SEGMENT]
= new RKFiniteElement(1, numPointsD, rbfType, distNorm,
order, intOrder, h, faceFactor);
}
L2_Elements[Geometry::SQUARE]->SetMapType(mapType);
}
else if (dim == 3)
{
if (order == -1)
{
L2_Elements[Geometry::CUBE]
= new RBFFiniteElement(3, numPointsD, rbfType, distNorm,
intOrder, h, faceFactor);
Tr_Elements[Geometry::SQUARE]
= new RBFFiniteElement(2, numPointsD, rbfType, distNorm,
intOrder, h, faceFactor);
}
else
{
L2_Elements[Geometry::CUBE]
= new RKFiniteElement(3, numPointsD, rbfType, distNorm,
order, intOrder, h, faceFactor);
Tr_Elements[Geometry::SQUARE]
= new RKFiniteElement(2, numPointsD, rbfType, distNorm,
order, intOrder, h, faceFactor);
}
L2_Elements[Geometry::CUBE]->SetMapType(mapType);
}
if (dim == 1)
{
SegDofOrd[0] = new int[2*numPointsD];
SegDofOrd[1] = SegDofOrd[0] + numPointsD;
for (int i = 0; i < numPointsD; ++i)
{
SegDofOrd[0][i] = i;
SegDofOrd[1][i] = numPointsD - i - 1;
}
}
else
{
const int geomType = TensorBasisElement::GetTensorProductGeometry(dim);
const int dof = L2_Elements[geomType]->GetDof();
OtherDofOrd = new int[dof];
for (int i = 0; i < dof; ++i)
{
OtherDofOrd[i] = i;
}
}
}
LocalKernelFECollection::~LocalKernelFECollection()
{
delete [] OtherDofOrd;
delete [] SegDofOrd[0];
for (int i = 0; i < Geometry::NumGeom; ++i)
{
delete L2_Elements[i];
}
}
const FiniteElement *
LocalKernelFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
return L2_Elements[GeomType];
}
const FiniteElement *
LocalKernelFECollection::TraceFiniteElementForGeometry(Geometry::Type GeomType)
const
{
return Tr_Elements[GeomType];
}
int LocalKernelFECollection::DofForGeometry(Geometry::Type GeomType) const
{
if (L2_Elements[GeomType])
{
return L2_Elements[GeomType]->GetDof();
}
return 0;
}
const int *LocalKernelFECollection::DofOrderForOrientation(
Geometry::Type GeomType,
int Or) const
{
if (GeomType == Geometry::SEGMENT)
{
return (Or > 0) ? SegDofOrd[0] : SegDofOrd[1];
}
else
{
return (Or == 0) ? OtherDofOrd : NULL;
}
}
} // namespace mfem
+59 -1
View File
@@ -1305,6 +1305,64 @@ public:
virtual int GetContType() const { return DISCONTINUOUS; }
};
}
/** @brief Radial basis function collection.
Instead of using polynomials as a basis, these methods use
Gaussian-like functions centered at chosen points. Reproducing
kernels augment the radial basis functions so that the resultant
basis can exactly represent functions of a chosen polynomial degree. */
class LocalKernelFECollection : public FiniteElementCollection
{
private:
int maxDim;
char d_name[32];
ScalarFiniteElement *Tr_Elements[Geometry::NumGeom];
ScalarFiniteElement *L2_Elements[Geometry::NumGeom];
int *SegDofOrd[2]; // for rotating segment dofs in 1D
int *OtherDofOrd;
public:
/** @brief Create a radial basis function (RBF) or reproducing kernel (RK)
finite element collection.
@param D Reference space dimension
@param numPointsD Number of points across the element in each dimension
@param rbfType Type of radial basis function, from RBFType
@param order Order of polynomial correction, >= 0 for RK or -1 for
RBF
@param h Shape parameter, approximately equal to the number of
points in the support radius in one dimension, should
generally be > order
@param distNorm Norm used for distance, usually 2 = Euclidean distance
@param intOrder Number of integration points per RBF point in each
dimension
@param faceFactor 1.0 = points end on face, 0.0 = points end at dx/2
from face
*/
LocalKernelFECollection(const int D,
const int numPointsD,
const int rbfType,
const int order,
const double h,
const double faceFactor = 0.0,
const int intOrder = 2,
const int distNorm = 2,
const int mapType = FiniteElement::VALUE);
virtual ~LocalKernelFECollection();
virtual const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const;
virtual const FiniteElement *
TraceFiniteElementForGeometry(Geometry::Type GeomType) const;
virtual int DofForGeometry(Geometry::Type GeomType) const;
virtual const int * DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char * Name() const { return d_name; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
} // namespace mfem
#endif
+21
View File
@@ -385,21 +385,38 @@ void FiniteElementSpace::BuildBdrElementToDofTable() const
if (bdr_elem_dof) { return; }
Table *bel_dof = new Table;
Table *bel_fos = (mesh->Dimension() == 3) ? (new Table) : NULL;
Array<int> dofs;
int F, Fo;
bel_dof->MakeI(mesh->GetNBE());
if (bel_fos) { bel_fos->MakeI(mesh->GetNBE()); }
for (int i = 0; i < mesh->GetNBE(); i++)
{
GetBdrElementDofs(i, dofs);
bel_dof->AddColumnsInRow(i, dofs.Size());
if (bel_fos)
{
bel_fos->AddAColumnInRow(i);
}
}
bel_dof->MakeJ();
if (bel_fos) { bel_fos->MakeJ(); }
for (int i = 0; i < mesh->GetNBE(); i++)
{
GetBdrElementDofs(i, dofs);
bel_dof->AddConnections(i, (int *)dofs, dofs.Size());
if (bel_fos)
{
mesh->GetBdrElementFace(i, &F, &Fo);
bel_fos->AddConnection(i, Fo);
}
}
bel_dof->ShiftUpI();
if (bel_fos) { bel_fos->ShiftUpI(); }
bdr_elem_dof = bel_dof;
bdr_elem_fos = bel_fos;
}
void FiniteElementSpace::BuildFaceToDofTable() const
@@ -1542,6 +1559,10 @@ FiniteElementSpace::RefinementOperator::~RefinementOperator()
{
delete old_elem_dof;
delete old_elem_fos;
for (int i=0; i<old_DoFTrans.Size(); i++)
{
delete old_DoFTrans[i];
}
}
void FiniteElementSpace::RefinementOperator
+3 -1
View File
@@ -994,7 +994,9 @@ public:
/// @brief Returns indices of degrees of freedom for the @a i'th element.
/// The returned indices are offsets into an @ref ldof vector with @b vdim
/// not necessarily equal to 1. See also GetElementDofs().
/// not necessarily equal to 1. The returned indexes are always ordered
/// byNODES, irrespective of whether the space is byNODES or byVDIM.
/// See also GetElementDofs().
///
/// @note In many cases the returned DofTransformation object will be NULL.
/// In other cases see the documentation of the DofTransformation class for
+28 -10
View File
@@ -397,8 +397,6 @@ void GridFunction::GetNodalValues(int i, Array<double> &nval, int vdim) const
{
Array<int> vdofs;
int k;
DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
const FiniteElement *FElem = fes->GetFE(i);
const IntegrationRule *ElemVert =
@@ -419,7 +417,7 @@ void GridFunction::GetNodalValues(int i, Array<double> &nval, int vdim) const
Vector shape(dof);
if (FElem->GetMapType() == FiniteElement::VALUE)
{
for (k = 0; k < n; k++)
for (int k = 0; k < n; k++)
{
FElem->CalcShape(ElemVert->IntPoint(k), shape);
nval[k] = shape * (&loc_data[dof * vdim]);
@@ -428,7 +426,7 @@ void GridFunction::GetNodalValues(int i, Array<double> &nval, int vdim) const
else
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
for (k = 0; k < n; k++)
for (int k = 0; k < n; k++)
{
Tr->SetIntPoint(&ElemVert->IntPoint(k));
FElem->CalcPhysShape(*Tr, shape);
@@ -440,7 +438,7 @@ void GridFunction::GetNodalValues(int i, Array<double> &nval, int vdim) const
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
DenseMatrix vshape(dof, FElem->GetDim());
for (k = 0; k < n; k++)
for (int k = 0; k < n; k++)
{
Tr->SetIntPoint(&ElemVert->IntPoint(k));
FElem->CalcVShape(*Tr, vshape);
@@ -2401,7 +2399,11 @@ void GridFunction::ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff,
loc_mass);
vals.SetSize(fe->GetDof());
fe->ProjectDelta(j, vals);
fes->GetElementVDofs(i, vdofs);
const DofTransformation* const doftrans = fes->GetElementVDofs(i, vdofs);
if (doftrans)
{
doftrans->TransformPrimal(vals);
}
SetSubVector(vdofs, vals);
loc_mass_vals.SetSize(vals.Size());
loc_mass.Mult(vals, loc_mass_vals);
@@ -2755,7 +2757,11 @@ void GridFunction::ProjectBdrCoefficientNormal(
CalcOrtho(T->Jacobian(), nor);
lvec(j) = (vc * nor);
}
fes->GetBdrElementDofs(i, dofs);
const DofTransformation* const doftrans = fes->GetBdrElementDofs(i, dofs);
if (doftrans)
{
doftrans->TransformPrimal(lvec);
}
SetSubVector(dofs, lvec);
}
#endif
@@ -4031,11 +4037,19 @@ double ZZErrorEstimator(BilinearFormIntegrator &blfi,
{
if (with_subdomains && ufes->GetAttribute(i) != s) { continue; }
ufes->GetElementVDofs(i, udofs);
ffes->GetElementVDofs(i, fdofs);
const DofTransformation* const utrans = ufes->GetElementVDofs(i, udofs);
const DofTransformation* const ftrans = ffes->GetElementVDofs(i, fdofs);
u.GetSubVector(udofs, ul);
flux.GetSubVector(fdofs, fla);
if (utrans)
{
utrans->InvTransformPrimal(ul);
}
if (ftrans)
{
ftrans->InvTransformPrimal(fla);
}
Transf = ufes->GetElementTransformation(i);
blfi.ComputeElementFlux(*ufes->GetFE(i), *Transf, ul,
@@ -4330,8 +4344,12 @@ double LSZZErrorEstimator(BilinearFormIntegrator &blfi, // input
flux_order));
int num_integration_pts = ir->GetNPoints();
ufes->GetElementVDofs(ielem, udofs);
const DofTransformation* const utrans = ufes->GetElementVDofs(ielem, udofs);
u.GetSubVector(udofs, ul);
if (utrans)
{
utrans->InvTransformPrimal(ul);
}
Transf = ufes->GetElementTransformation(ielem);
FiniteElement *dummy = nullptr;
blfi.ComputeElementFlux(*ufes->GetFE(ielem), *Transf, ul,
+4
View File
@@ -684,6 +684,10 @@ public:
/// Transform by the Space UpdateMatrix (e.g., on Mesh change).
virtual void Update();
/** Return update counter, similar to Mesh::GetSequence(). Used to
check if it is up to date with the space. */
long GetSequence() const { return fes_sequence; }
FiniteElementSpace *FESpace() { return fes; }
const FiniteElementSpace *FESpace() const { return fes; }
+63 -29
View File
@@ -108,8 +108,7 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
const int npt_max)
{
MFEM_VERIFY(m.GetNodes() != NULL, "Mesh nodes are required.");
MFEM_VERIFY(!(m.GetNodes()->FESpace()->IsVariableOrder()),
"Variable order mesh is not currently supported.");
const int meshOrder = m.GetNodes()->FESpace()->GetMaxElementOrder();
// call FreeData if FindPointsGSLIB::Setup has been called already
if (setupflag) { FreeData(); }
@@ -117,30 +116,36 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
crystal_init(cr, gsl_comm);
mesh = &m;
dim = mesh->Dimension();
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
unsigned dof1D = fe->GetOrder() + 1;
unsigned dof1D = meshOrder + 1;
SetupSplitMeshes();
if (dim == 2)
{
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
ir_split[0] = new IntegrationRule(3*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], fe->GetOrder());
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
ir_split[1] = new IntegrationRule(pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
}
else if (dim == 3)
{
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
ir_split[0] = new IntegrationRule(pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
ir_split[1] = new IntegrationRule(4*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], fe->GetOrder());
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
if (ir_split[2]) { delete ir_split[2]; ir_split[2] = NULL; }
ir_split[2] = new IntegrationRule(3*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[2], ir_split[2], fe->GetOrder());
SetupIntegrationRuleForSplitMesh(mesh_split[2], ir_split[2], meshOrder);
if (ir_split[3]) { delete ir_split[3]; ir_split[3] = NULL; }
ir_split[3] = new IntegrationRule(8*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[3], ir_split[3], fe->GetOrder());
SetupIntegrationRuleForSplitMesh(mesh_split[3], ir_split[3], meshOrder);
}
GetNodalValues(mesh->GetNodes(), gsl_mesh);
@@ -179,7 +184,7 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos,
gsl_ref.SetSize(points_cnt * dim);
gsl_dist.SetSize(points_cnt);
auto xvFill = [&](const double *xv_base[], unsigned xv_stride[], int dim)
auto xvFill = [&](const double *xv_base[], unsigned xv_stride[])
{
for (int d = 0; d < dim; d++)
{
@@ -199,7 +204,7 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos,
{
const double *xv_base[2];
unsigned xv_stride[2];
xvFill(xv_base, xv_stride, dim);
xvFill(xv_base, xv_stride);
findpts_2(gsl_code.GetData(), sizeof(unsigned int),
gsl_proc.GetData(), sizeof(unsigned int),
gsl_elem.GetData(), sizeof(unsigned int),
@@ -211,7 +216,7 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos,
{
const double *xv_base[3];
unsigned xv_stride[3];
xvFill(xv_base, xv_stride, dim);
xvFill(xv_base, xv_stride);
findpts_3(gsl_code.GetData(), sizeof(unsigned int),
gsl_proc.GetData(), sizeof(unsigned int),
gsl_elem.GetData(), sizeof(unsigned int),
@@ -333,9 +338,14 @@ void FindPointsGSLIB::SetupSplitMeshes()
(*gf_rst_map[0])(j+k*npt) = quad_v[j][k];
}
}
mesh_split[1] = new Mesh(Mesh::MakeCartesian2D(1, 1,
Element::QUADRILATERAL));
}
else if (mesh->Dimension() == 3)
{
mesh_split[0] = new Mesh(Mesh::MakeCartesian3D(1, 1, 1,
Element::HEXAHEDRON));
// Tetrahedron
{
int Nvert = 15;
@@ -565,11 +575,12 @@ void FindPointsGSLIB::GetNodalValues(const GridFunction *gf_in,
const GridFunction *nodes = gf_in;
const FiniteElementSpace *fes = nodes->FESpace();
const int NE = mesh->GetNE();
const int vdim = gf_in->FESpace()->GetVDim();
const int vdim = fes->GetVDim();
IntegrationRule *ir_split_temp = NULL;
const int dof_1D = nodes->FESpace()->GetFE(0)->GetOrder()+1;
const int maxOrder = fes->GetMaxElementOrder();
const int dof_1D = maxOrder+1;
const int pts_el = std::pow(dof_1D, dim);
const int pts_cnt = NE_split_total * pts_el;
node_vals.SetSize(vdim * pts_cnt);
@@ -579,7 +590,7 @@ void FindPointsGSLIB::GetNodalValues(const GridFunction *gf_in,
for (int e = 0; e < NE; e++)
{
const FiniteElement *fe = nodes->FESpace()->GetFE(e);
const FiniteElement *fe = fes->GetFE(e);
const Geometry::Type gt = fe->GetGeomType();
bool el_to_split = true;
if (gt == Geometry::TRIANGLE)
@@ -598,16 +609,22 @@ void FindPointsGSLIB::GetNodalValues(const GridFunction *gf_in,
{
ir_split_temp = ir_split[3];
}
else if (gt == Geometry::SQUARE || gt == Geometry::CUBE)
else if (gt == Geometry::SQUARE)
{
el_to_split = false;
ir_split_temp = ir_split[1];
el_to_split = gf_in->FESpace()->IsVariableOrder();
}
else if (gt == Geometry::CUBE)
{
ir_split_temp = ir_split[0];
el_to_split = gf_in->FESpace()->IsVariableOrder();
}
else
{
MFEM_ABORT("Unsupported geometry type.");
}
if (el_to_split) // Triangle/Tet/Prism
if (el_to_split) // Triangle/Tet/Prism or Quads/Hex but variable order
{
// Fill gsl_mesh with location of split points.
Vector locval(vdim);
@@ -622,7 +639,7 @@ void FindPointsGSLIB::GetNodalValues(const GridFunction *gf_in,
gsl_mesh_pt_index++;
}
}
else // Quad/Hex
else // Quad/Hex and constant polynomial order
{
const int dof_cnt_split = fe->GetDof();
@@ -803,8 +820,8 @@ void FindPointsGSLIB::MapRefPosAndElemIndices()
void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
Vector &field_out)
{
const int gf_order = field_in.FESpace()->GetFE(0)->GetOrder(),
mesh_order = mesh->GetNodalFESpace()->GetFE(0)->GetOrder();
const int gf_order = field_in.FESpace()->GetMaxElementOrder(),
mesh_order = mesh->GetNodalFESpace()->GetMaxElementOrder();
const FiniteElementCollection *fec_in = field_in.FESpace()->FEColl();
const H1_FECollection *fec_h1 = dynamic_cast<const H1_FECollection *>(fec_in);
@@ -812,7 +829,8 @@ void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
if (fec_h1 && gf_order == mesh_order &&
fec_h1->GetBasisType() == BasisType::GaussLobatto &&
!field_in.FESpace()->IsVariableOrder())
field_in.FESpace()->IsVariableOrder() ==
mesh->GetNodalFESpace()->IsVariableOrder())
{
InterpolateH1(field_in, field_out);
return;
@@ -886,12 +904,21 @@ void FindPointsGSLIB::InterpolateH1(const GridFunction &field_in,
Vector &field_out)
{
FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
if (field_in.FESpace()->IsVariableOrder())
{
for (int e = 0; e < ind_fes.GetMesh()->GetNE(); e++)
{
ind_fes.SetElementOrder(e, field_in.FESpace()->GetElementOrder(e));
}
ind_fes.Update(false);
}
GridFunction field_in_scalar(&ind_fes);
Vector node_vals;
const int ncomp = field_in.FESpace()->GetVDim(),
points_fld = field_in.Size() / ncomp,
points_cnt = gsl_code.Size();
points_fld = field_in.Size() / ncomp;
MFEM_VERIFY(points_cnt == gsl_code.Size(),
"FindPointsGSLIB::InterpolateH1: Inconsistent size of gsl_code");
field_out.SetSize(points_cnt*ncomp);
field_out = default_interp_value;
@@ -1111,8 +1138,7 @@ void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
const int npt_max)
{
MFEM_VERIFY(m.GetNodes() != NULL, "Mesh nodes are required.");
MFEM_VERIFY(!(m.GetNodes()->FESpace()->IsVariableOrder()),
"Variable order mesh is not currently supported.");
const int meshOrder = m.GetNodes()->FESpace()->GetMaxElementOrder();
// FreeData if OversetFindPointsGSLIB::Setup has been called already
if (setupflag) { FreeData(); }
@@ -1128,21 +1154,29 @@ void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
{
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
ir_split[0] = new IntegrationRule(3*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], fe->GetOrder());
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
ir_split[1] = new IntegrationRule(pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
}
else if (dim == 3)
{
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
ir_split[0] = new IntegrationRule(pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
ir_split[1] = new IntegrationRule(4*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], fe->GetOrder());
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
if (ir_split[2]) { delete ir_split[2]; ir_split[2] = NULL; }
ir_split[2] = new IntegrationRule(3*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[2], ir_split[2], fe->GetOrder());
SetupIntegrationRuleForSplitMesh(mesh_split[2], ir_split[2], meshOrder);
if (ir_split[3]) { delete ir_split[3]; ir_split[3] = NULL; }
ir_split[3] = new IntegrationRule(8*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[3], ir_split[3], fe->GetOrder());
SetupIntegrationRuleForSplitMesh(mesh_split[3], ir_split[3], meshOrder);
}
GetNodalValues(mesh->GetNodes(), gsl_mesh);
+3 -1
View File
@@ -57,7 +57,9 @@ public:
protected:
Mesh *mesh;
Array<Mesh *> mesh_split; // Meshes used to split simplices.
Array<IntegrationRule *> ir_split; // IntegrationRules for simplex->Quad/Hex
// IntegrationRules for simplex->Quad/Hex and to project to highest polynomial
// order in-case of p-refinement.
Array<IntegrationRule *> ir_split;
Array<FiniteElementSpace *>
fes_rst_map; // FESpaces to map info Quad/Hex->Simplex
Array<GridFunction *> gf_rst_map; // GridFunctions to map info Quad/Hex->Simplex
@@ -9,8 +9,8 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "bilininteg.hpp"
#include "pfespace.hpp"
#include "../bilininteg.hpp"
#include "../pfespace.hpp"
#include <algorithm>
namespace mfem
@@ -9,9 +9,9 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
namespace mfem
{
@@ -34,7 +34,7 @@ static void EAConvectionAssemble1D(const int NE,
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto A = Reshape(eadata.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
mfem::forall_2D(NE, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -86,7 +86,7 @@ static void EAConvectionAssemble2D(const int NE,
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, NE);
auto A = Reshape(eadata.ReadWrite(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
mfem::forall_2D(NE, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -163,7 +163,7 @@ static void EAConvectionAssemble3D(const int NE,
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 3, NE);
auto A = Reshape(eadata.ReadWrite(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
mfem::forall_3D(NE, D1D, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -9,12 +9,9 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/integrators/convection/convection.hpp"
using namespace std;
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../ceed/integrators/convection/convection.hpp"
namespace mfem
{
@@ -9,18 +9,15 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "qfunction.hpp"
#include "ceed/integrators/convection/convection.hpp"
#include "quadinterpolator.hpp"
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "../ceed/integrators/convection/convection.hpp"
namespace mfem
{
// PA Convection Integrator
// PA Convection Assemble 2D kernel
static void PAConvectionSetup2D(const int NQ,
const int NE,
@@ -41,7 +38,7 @@ static void PAConvectionSetup2D(const int NQ,
Reshape(vel.Read(), DIM,NQ,NE);
auto y = Reshape(op.Write(), NQ,DIM,NE);
MFEM_FORALL(q_global, NE*NQ,
mfem::forall(NE*NQ, [=] MFEM_HOST_DEVICE (int q_global)
{
const int e = q_global / NQ;
const int q = q_global % NQ;
@@ -78,7 +75,7 @@ static void PAConvectionSetup3D(const int NQ,
Reshape(vel.Read(), 3,1,1) :
Reshape(vel.Read(), 3,NQ,NE);
auto y = Reshape(op.Write(), NQ,3,NE);
MFEM_FORALL(q_global, NE*NQ,
mfem::forall(NE*NQ, [=] MFEM_HOST_DEVICE (int q_global)
{
const int e = q_global / NQ;
const int q = q_global % NQ;
@@ -135,6 +132,61 @@ static void PAConvectionSetup(const int dim,
}
}
void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
Device::GetDeviceMemoryType() : pa_mt;
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement &el = *fes.GetFE(0);
ElementTransformation &Trans = *fes.GetElementTransformation(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, Trans);
if (DeviceCanUseCeed())
{
delete ceedOp;
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedPAConvectionIntegrator(*this, fes, Q, alpha);
}
else
{
ceedOp = new ceed::PAConvectionIntegrator(fes, *ir, Q, alpha);
}
return;
}
const int dims = el.GetDim();
const int symmDims = dims;
nq = ir->GetNPoints();
dim = mesh->Dimension();
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mt);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(symmDims * nq * ne, mt);
QuadratureSpace qs(*mesh, *ir);
CoefficientVector vel(*Q, qs, CoefficientStorage::COMPRESSED);
PAConvectionSetup(dim, nq, ne, ir->GetWeights(), geom->J,
vel, alpha, pa_data);
}
void ConvectionIntegrator::AssembleDiagonalPA(Vector &diag)
{
if (DeviceCanUseCeed())
{
ceedOp->GetDiagonal(diag);
}
else
{
MFEM_ABORT("AssembleDiagonalPA not yet implemented for"
" ConvectionIntegrator.");
}
}
// PA Convection Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0> static
void PAConvectionApply2D(const int ne,
@@ -159,7 +211,7 @@ void PAConvectionApply2D(const int ne,
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, NE);
auto x = Reshape(x_.Read(), D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -279,7 +331,7 @@ void SmemPAConvectionApply2D(const int ne,
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, NE);
auto x = Reshape(x_.Read(), D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
{
const int tidz = MFEM_THREAD_ID(z);
const int D1D = T_D1D ? T_D1D : d1d;
@@ -406,7 +458,7 @@ void PAConvectionApply3D(const int ne,
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, 3, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -587,7 +639,7 @@ void SmemPAConvectionApply3D(const int ne,
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, 3, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -791,7 +843,7 @@ void PAConvectionApplyT2D(const int ne,
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, NE);
auto x = Reshape(x_.Read(), D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -907,7 +959,7 @@ void SmemPAConvectionApplyT2D(const int ne,
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, NE);
auto x = Reshape(x_.Read(), D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
{
const int tidz = MFEM_THREAD_ID(z);
const int D1D = T_D1D ? T_D1D : d1d;
@@ -1029,7 +1081,7 @@ void PAConvectionApplyT3D(const int ne,
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, 3, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -1205,7 +1257,7 @@ void SmemPAConvectionApplyT3D(const int ne,
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, 3, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -1375,48 +1427,6 @@ void SmemPAConvectionApplyT3D(const int ne,
});
}
void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
Device::GetDeviceMemoryType() : pa_mt;
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement &el = *fes.GetFE(0);
ElementTransformation &Trans = *fes.GetElementTransformation(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, Trans);
if (DeviceCanUseCeed())
{
delete ceedOp;
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedPAConvectionIntegrator(*this, fes, Q, alpha);
}
else
{
ceedOp = new ceed::PAConvectionIntegrator(fes, *ir, Q, alpha);
}
return;
}
const int dims = el.GetDim();
const int symmDims = dims;
nq = ir->GetNPoints();
dim = mesh->Dimension();
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mt);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(symmDims * nq * ne, mt);
QuadratureSpace qs(*mesh, *ir);
CoefficientVector vel(*Q, qs, CoefficientStorage::COMPRESSED);
PAConvectionSetup(dim, nq, ne, ir->GetWeights(), geom->J,
vel, alpha, pa_data);
}
static void PAConvectionApply(const int dim,
const int D1D,
const int Q1D,
@@ -1521,7 +1531,6 @@ static void PAConvectionApplyT(const int dim,
MFEM_ABORT("Unknown kernel.");
}
// PA Convection Apply kernel
void ConvectionIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (DeviceCanUseCeed())
@@ -1536,7 +1545,6 @@ void ConvectionIntegrator::AddMultPA(const Vector &x, Vector &y) const
}
}
// PA Convection Apply transpose kernel
void ConvectionIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const
{
if (DeviceCanUseCeed())
@@ -1552,17 +1560,4 @@ void ConvectionIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const
}
}
void ConvectionIntegrator::AssembleDiagonalPA(Vector &diag)
{
if (DeviceCanUseCeed())
{
ceedOp->GetDiagonal(diag);
}
else
{
MFEM_ABORT("AssembleDiagonalPA not yet implemented for"
" ConvectionIntegrator.");
}
}
} // namespace mfem
+205
View File
@@ -0,0 +1,205 @@
// Copyright (c) 2010-2023, 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 "../qfunction.hpp"
#include "bilininteg_hcurl_kernels.hpp"
namespace mfem
{
void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement *fel = fes.GetFE(0);
const VectorTensorFiniteElement *el =
dynamic_cast<const VectorTensorFiniteElement*>(fel);
MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*el, *el,
*mesh->GetElementTransformation(0));
const int dims = el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(qs, CoefficientStorage::SYMMETRIC);
if (Q) { coeff.Project(*Q); }
else if (MQ) { coeff.ProjectTranspose(*MQ); }
else if (DQ) { coeff.Project(*DQ); }
else { coeff.SetConstant(1.0); }
const int coeff_dim = coeff.GetVDim();
symmetric = (coeff_dim != dim*dim);
const int sym_dims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int ndata = (dim == 2) ? 1 : (symmetric ? sym_dims : dim*dim);
pa_data.SetSize(ndata * nq * ne, Device::GetMemoryType());
if (el->GetDerivType() != mfem::FiniteElement::CURL)
{
MFEM_ABORT("Unknown kernel.");
}
if (dim == 3)
{
internal::PACurlCurlSetup3D(quad1D, coeff_dim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
internal::PACurlCurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J, coeff,
pa_data);
}
}
void CurlCurlIntegrator::AssembleDiagonalPA(Vector& diag)
{
if (dim == 3)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
const int ID = (dofs1D << 4) | quad1D;
switch (ID)
{
case 0x23:
return internal::SmemPACurlCurlAssembleDiagonal3D<2,3>(
dofs1D,
quad1D,
symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
case 0x34:
return internal::SmemPACurlCurlAssembleDiagonal3D<3,4>(
dofs1D,
quad1D,
symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
case 0x45:
return internal::SmemPACurlCurlAssembleDiagonal3D<4,5>(
dofs1D,
quad1D,
symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
case 0x56:
return internal::SmemPACurlCurlAssembleDiagonal3D<5,6>(
dofs1D,
quad1D,
symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
default:
return internal::SmemPACurlCurlAssembleDiagonal3D(
dofs1D, quad1D,
symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
}
}
else
{
internal::PACurlCurlAssembleDiagonal3D(dofs1D, quad1D, symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
}
}
else if (dim == 2)
{
internal::PACurlCurlAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->G, pa_data, diag);
}
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
void CurlCurlIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
const int ID = (dofs1D << 4) | quad1D;
switch (ID)
{
case 0x23:
return internal::SmemPACurlCurlApply3D<2,3>(
dofs1D, quad1D,
symmetric, ne,
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
case 0x34:
return internal::SmemPACurlCurlApply3D<3,4>(
dofs1D, quad1D,
symmetric, ne,
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
case 0x45:
return internal::SmemPACurlCurlApply3D<4,5>(
dofs1D, quad1D,
symmetric, ne,
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
case 0x56:
return internal::SmemPACurlCurlApply3D<5,6>(
dofs1D, quad1D,
symmetric, ne,
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
default:
return internal::SmemPACurlCurlApply3D(
dofs1D, quad1D, symmetric, ne,
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
}
}
else
{
internal::PACurlCurlApply3D(dofs1D, quad1D, symmetric, ne, mapsO->B, mapsC->B,
mapsO->Bt, mapsC->Bt, mapsC->G, mapsC->Gt,
pa_data, x, y);
}
}
else if (dim == 2)
{
internal::PACurlCurlApply2D(dofs1D, quad1D, ne, mapsO->B, mapsO->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
} // namespace mfem
@@ -9,9 +9,9 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
namespace mfem
{
@@ -26,7 +26,7 @@ static void EADGTraceAssemble1DInt(const int NF,
auto D = Reshape(padata.Read(), 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), 2, NF);
MFEM_FORALL(f, NF,
mfem::forall(NF, [=] MFEM_HOST_DEVICE (int f)
{
double val_int0, val_int1, val_ext01, val_ext10;
val_int0 = D(0, 0, f);
@@ -58,7 +58,7 @@ static void EADGTraceAssemble1DBdr(const int NF,
{
auto D = Reshape(padata.Read(), 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), NF);
MFEM_FORALL(f, NF,
mfem::forall(NF, [=] MFEM_HOST_DEVICE (int f)
{
if (add)
{
@@ -89,7 +89,7 @@ static void EADGTraceAssemble2DInt(const int NF,
auto D = Reshape(padata.Read(), Q1D, 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), D1D, D1D, 2, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
mfem::forall_2D(NF, D1D, D1D, [=] MFEM_HOST_DEVICE (int f)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -143,7 +143,7 @@ static void EADGTraceAssemble2DBdr(const int NF,
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), D1D, D1D, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
mfem::forall_2D(NF, D1D, D1D, [=] MFEM_HOST_DEVICE (int f)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -187,7 +187,7 @@ static void EADGTraceAssemble3DInt(const int NF,
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, D1D, D1D, 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), D1D, D1D, D1D, D1D, 2, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
mfem::forall_2D(NF, D1D, D1D, [=] MFEM_HOST_DEVICE (int f)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -283,7 +283,7 @@ static void EADGTraceAssemble3DBdr(const int NF,
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), D1D, D1D, D1D, D1D, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
mfem::forall_2D(NF, D1D, D1D, [=] MFEM_HOST_DEVICE (int f)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -9,16 +9,15 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "qfunction.hpp"
#include "restriction.hpp"
using namespace std;
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "../restriction.hpp"
namespace mfem
{
// PA DG Trace Integrator
static void PADGTraceSetup2D(const int Q1D,
const int NF,
@@ -44,7 +43,7 @@ static void PADGTraceSetup2D(const int Q1D,
auto W = w.Read();
auto qd = Reshape(op.Write(), Q1D, 2, 2, NF);
MFEM_FORALL(tid, Q1D*NF,
mfem::forall(Q1D*NF, [=] MFEM_HOST_DEVICE (int tid)
{
const int f = tid / Q1D;
const int q = tid % Q1D;
@@ -87,7 +86,7 @@ static void PADGTraceSetup3D(const int Q1D,
auto W = w.Read();
auto qd = Reshape(op.Write(), Q1D, Q1D, 2, 2, NF);
MFEM_FORALL(tid, Q1D*Q1D*NF,
mfem::forall(Q1D*Q1D*NF, [=] MFEM_HOST_DEVICE (int tid)
{
int f = tid / (Q1D * Q1D);
int q2 = (tid / Q1D) % Q1D;
@@ -99,7 +98,7 @@ static void PADGTraceSetup3D(const int Q1D,
const double v1 = const_v ? V(1,0,0,0) : V(1,q1,q2,f);
const double v2 = const_v ? V(2,0,0,0) : V(2,q1,q2,f);
const double dot = n(q1,q2,0,f) * v0 + n(q1,q2,1,f) * v1 +
/* */ n(q1,q2,2,f) * v2;
n(q1,q2,2,f) * v2;
const double abs = dot > 0.0 ? dot : -dot;
const double w = W[q1+q2*Q1D]*r*d(q1,q2,f);
qd(q1,q2,0,0,f) = w*( alpha/2 * dot + beta * abs );
@@ -267,7 +266,7 @@ void PADGTraceApply2D(const int NF,
auto x = Reshape(x_.Read(), D1D, VDIM, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, VDIM, 2, NF);
MFEM_FORALL(f, NF,
mfem::forall(NF, [=] MFEM_HOST_DEVICE (int f)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
@@ -358,7 +357,7 @@ void PADGTraceApply3D(const int NF,
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, 2, NF);
MFEM_FORALL(f, NF,
mfem::forall(NF, [=] MFEM_HOST_DEVICE (int f)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
@@ -503,7 +502,7 @@ void SmemPADGTraceApply3D(const int NF,
auto x = Reshape(x_.Read(), D1D, D1D, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NF);
MFEM_FORALL_2D(f, NF, Q1D, Q1D, NBZ,
mfem::forall_2D_batch(NF, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE (int f)
{
const int tidz = MFEM_THREAD_ID(z);
const int D1D = T_D1D ? T_D1D : d1d;
@@ -668,7 +667,7 @@ void PADGTraceApplyTranspose2D(const int NF,
auto x = Reshape(x_.Read(), D1D, VDIM, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, VDIM, 2, NF);
MFEM_FORALL(f, NF,
mfem::forall(NF, [=] MFEM_HOST_DEVICE (int f)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
@@ -764,7 +763,7 @@ void PADGTraceApplyTranspose3D(const int NF,
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, 2, NF);
MFEM_FORALL(f, NF,
mfem::forall(NF, [=] MFEM_HOST_DEVICE (int f)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
@@ -920,7 +919,7 @@ void SmemPADGTraceApplyTranspose3D(const int NF,
auto x = Reshape(x_.Read(), D1D, D1D, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NF);
MFEM_FORALL_2D(f, NF, Q1D, Q1D, NBZ,
mfem::forall_2D_batch(NF, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE (int f)
{
const int tidz = MFEM_THREAD_ID(z);
const int D1D = T_D1D ? T_D1D : d1d;
@@ -9,9 +9,9 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
namespace mfem
{
@@ -33,7 +33,7 @@ static void EADiffusionAssemble1D(const int NE,
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto A = Reshape(eadata.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
mfem::forall_2D(NE, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -85,7 +85,7 @@ static void EADiffusionAssemble2D(const int NE,
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 3, NE);
auto A = Reshape(eadata.ReadWrite(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
mfem::forall_2D(NE, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -162,7 +162,7 @@ static void EADiffusionAssemble3D(const int NE,
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 6, NE);
auto A = Reshape(eadata.ReadWrite(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
mfem::forall_3D(NE, D1D, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
+578
View File
@@ -0,0 +1,578 @@
// Copyright (c) 2010-2023, 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 "bilininteg_diffusion_kernels.hpp"
namespace mfem
{
namespace internal
{
template<>
void PADiffusionSetup2D<2>(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d);
template<>
void PADiffusionSetup2D<3>(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d);
void PADiffusionSetup(const int dim,
const int sdim,
const int D1D,
const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &W,
const Vector &J,
const Vector &C,
Vector &D)
{
if (dim == 1) { MFEM_ABORT("dim==1 not supported in PADiffusionSetup"); }
if (dim == 2)
{
#ifdef MFEM_USE_OCCA
if (DeviceCanUseOcca())
{
OccaPADiffusionSetup2D(D1D, Q1D, NE, W, J, C, D);
return;
}
#else
MFEM_CONTRACT_VAR(D1D);
#endif // MFEM_USE_OCCA
if (sdim == 2) { PADiffusionSetup2D<2>(Q1D, coeffDim, NE, W, J, C, D); }
if (sdim == 3) { PADiffusionSetup2D<3>(Q1D, coeffDim, NE, W, J, C, D); }
}
if (dim == 3)
{
#ifdef MFEM_USE_OCCA
if (DeviceCanUseOcca())
{
OccaPADiffusionSetup3D(D1D, Q1D, NE, W, J, C, D);
return;
}
#endif // MFEM_USE_OCCA
PADiffusionSetup3D(Q1D, coeffDim, NE, W, J, C, D);
}
}
template<>
void PADiffusionSetup2D<2>(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
{
const bool symmetric = (coeffDim != 4);
const bool const_c = c.Size() == 1;
MFEM_VERIFY(coeffDim < 3 ||
!const_c, "Constant matrix coefficient not supported");
const auto W = Reshape(w.Read(), Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,2,2,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1) :
Reshape(c.Read(), coeffDim,Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D, symmetric ? 3 : 4, NE);
mfem::forall_2D(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double J11 = J(qx,qy,0,0,e);
const double J21 = J(qx,qy,1,0,e);
const double J12 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double w_detJ = W(qx,qy) / ((J11*J22)-(J21*J12));
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient
{
// First compute entries of R = MJ^{-T}, without det J factor.
const double M11 = C(0,qx,qy,e);
const double M12 = C(1,qx,qy,e);
const double M21 = symmetric ? M12 : C(2,qx,qy,e);
const double M22 = symmetric ? C(2,qx,qy,e) : C(3,qx,qy,e);
const double R11 = M11*J22 - M12*J12;
const double R21 = M21*J22 - M22*J12;
const double R12 = -M11*J21 + M12*J11;
const double R22 = -M21*J21 + M22*J11;
// Now set y to J^{-1}R.
D(qx,qy,0,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
D(qx,qy,1,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
D(qx,qy,2,e) = w_detJ * (symmetric ? (-J21*R12 + J11*R22) :
(J22*R12 - J12*R22)); // 2,2 or 1,2
if (!symmetric)
{
D(qx,qy,3,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
}
}
else // Vector or scalar coefficient
{
const double C1 = const_c ? C(0,0,0,0) : C(0,qx,qy,e);
const double C2 = const_c ? C(0,0,0,0) :
(coeffDim == 2 ? C(1,qx,qy,e) : C(0,qx,qy,e));
D(qx,qy,0,e) = w_detJ * (C2*J12*J12 + C1*J22*J22); // 1,1
D(qx,qy,1,e) = -w_detJ * (C2*J12*J11 + C1*J22*J21); // 1,2
D(qx,qy,2,e) = w_detJ * (C2*J11*J11 + C1*J21*J21); // 2,2
}
}
}
});
}
template<>
void PADiffusionSetup2D<3>(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
{
MFEM_VERIFY(coeffDim == 1, "Matrix and vector coefficients not supported");
constexpr int DIM = 2;
constexpr int SDIM = 3;
const bool const_c = c.Size() == 1;
const auto W = Reshape(w.Read(), Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,SDIM,DIM,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
Reshape(c.Read(), Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
mfem::forall_2D(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double wq = W(qx,qy);
const double J11 = J(qx,qy,0,0,e);
const double J21 = J(qx,qy,1,0,e);
const double J31 = J(qx,qy,2,0,e);
const double J12 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double J32 = J(qx,qy,2,1,e);
const double E = J11*J11 + J21*J21 + J31*J31;
const double G = J12*J12 + J22*J22 + J32*J32;
const double F = J11*J12 + J21*J22 + J31*J32;
const double iw = 1.0 / sqrt(E*G - F*F);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
const double alpha = wq * coeff * iw;
D(qx,qy,0,e) = alpha * G; // 1,1
D(qx,qy,1,e) = -alpha * F; // 1,2
D(qx,qy,2,e) = alpha * E; // 2,2
}
}
});
}
void PADiffusionSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
{
const bool symmetric = (coeffDim != 9);
const bool const_c = c.Size() == 1;
MFEM_VERIFY(coeffDim < 6 ||
!const_c, "Constant matrix coefficient not supported");
const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1,1) :
Reshape(c.Read(), coeffDim,Q1D,Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D,Q1D, symmetric ? 6 : 9, NE);
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double J11 = J(qx,qy,qz,0,0,e);
const double J21 = J(qx,qy,qz,1,0,e);
const double J31 = J(qx,qy,qz,2,0,e);
const double J12 = J(qx,qy,qz,0,1,e);
const double J22 = J(qx,qy,qz,1,1,e);
const double J32 = J(qx,qy,qz,2,1,e);
const double J13 = J(qx,qy,qz,0,2,e);
const double J23 = J(qx,qy,qz,1,2,e);
const double J33 = J(qx,qy,qz,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
J21 * (J12 * J33 - J32 * J13) +
J31 * (J12 * J23 - J22 * J13);
const double w_detJ = W(qx,qy,qz) / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
{
// Compute entries of R = MJ^{-T} = M adj(J)^T, without det J.
const double M11 = C(0, qx,qy,qz, e);
const double M12 = C(1, qx,qy,qz, e);
const double M13 = C(2, qx,qy,qz, e);
const double M21 = (!symmetric) ? C(3, qx,qy,qz, e) : M12;
const double M22 = (!symmetric) ? C(4, qx,qy,qz, e) : C(3, qx,qy,qz, e);
const double M23 = (!symmetric) ? C(5, qx,qy,qz, e) : C(4, qx,qy,qz, e);
const double M31 = (!symmetric) ? C(6, qx,qy,qz, e) : M13;
const double M32 = (!symmetric) ? C(7, qx,qy,qz, e) : M23;
const double M33 = (!symmetric) ? C(8, qx,qy,qz, e) : C(5, qx,qy,qz, e);
const double R11 = M11*A11 + M12*A12 + M13*A13;
const double R12 = M11*A21 + M12*A22 + M13*A23;
const double R13 = M11*A31 + M12*A32 + M13*A33;
const double R21 = M21*A11 + M22*A12 + M23*A13;
const double R22 = M21*A21 + M22*A22 + M23*A23;
const double R23 = M21*A31 + M22*A32 + M23*A33;
const double R31 = M31*A11 + M32*A12 + M33*A13;
const double R32 = M31*A21 + M32*A22 + M33*A23;
const double R33 = M31*A31 + M32*A32 + M33*A33;
// Now set D to J^{-1} R = adj(J) R
D(qx,qy,qz,0,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
const double D12 = w_detJ * (A11*R12 + A12*R22 + A13*R32);
D(qx,qy,qz,1,e) = D12; // 1,2
D(qx,qy,qz,2,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
const double D22 = w_detJ * (A21*R12 + A22*R22 + A23*R32);
const double D23 = w_detJ * (A21*R13 + A22*R23 + A23*R33);
const double D33 = w_detJ * (A31*R13 + A32*R23 + A33*R33);
D(qx,qy,qz,4,e) = symmetric ? D23 : D22; // 2,3 or 2,2
D(qx,qy,qz,5,e) = symmetric ? D33 : D23; // 3,3 or 2,3
if (symmetric)
{
D(qx,qy,qz,3,e) = D22; // 2,2
}
else
{
D(qx,qy,qz,3,e) = w_detJ * (A21*R11 + A22*R21 + A23*R31); // 2,1
D(qx,qy,qz,6,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
D(qx,qy,qz,7,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
D(qx,qy,qz,8,e) = D33; // 3,3
}
}
else // Vector or scalar coefficient version
{
const double C1 = const_c ? C(0,0,0,0,0) : C(0,qx,qy,qz,e);
const double C2 = const_c ? C(0,0,0,0,0) :
(coeffDim == 3 ? C(1,qx,qy,qz,e) : C(0,qx,qy,qz,e));
const double C3 = const_c ? C(0,0,0,0,0) :
(coeffDim == 3 ? C(2,qx,qy,qz,e) : C(0,qx,qy,qz,e));
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
D(qx,qy,qz,0,e) = w_detJ * (C1*A11*A11 + C2*A12*A12 + C3*A13*A13); // 1,1
D(qx,qy,qz,1,e) = w_detJ * (C1*A11*A21 + C2*A12*A22 + C3*A13*A23); // 2,1
D(qx,qy,qz,2,e) = w_detJ * (C1*A11*A31 + C2*A12*A32 + C3*A13*A33); // 3,1
D(qx,qy,qz,3,e) = w_detJ * (C1*A21*A21 + C2*A22*A22 + C3*A23*A23); // 2,2
D(qx,qy,qz,4,e) = w_detJ * (C1*A21*A31 + C2*A22*A32 + C3*A23*A33); // 3,2
D(qx,qy,qz,5,e) = w_detJ * (C1*A31*A31 + C2*A32*A32 + C3*A33*A33); // 3,3
}
}
}
}
});
}
#ifdef MFEM_USE_OCCA
void OccaPADiffusionSetup2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &W,
const Vector &J,
const Vector &C,
Vector &op)
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_W = OccaMemoryRead(W.GetMemory(), W.Size());
const occa::memory o_J = OccaMemoryRead(J.GetMemory(), J.Size());
const occa::memory o_C = OccaMemoryRead(C.GetMemory(), C.Size());
occa::memory o_op = OccaMemoryWrite(op.GetMemory(), op.Size());
const bool const_c = C.Size() == 1;
const occa_id_t id = std::make_pair(D1D,Q1D);
static occa_kernel_t OccaDiffSetup2D_ker;
if (OccaDiffSetup2D_ker.find(id) == OccaDiffSetup2D_ker.end())
{
const occa::kernel DiffusionSetup2D =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionSetup2D", props);
OccaDiffSetup2D_ker.emplace(id, DiffusionSetup2D);
}
OccaDiffSetup2D_ker.at(id)(NE, o_W, o_J, o_C, o_op, const_c);
}
void OccaPADiffusionSetup3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &W,
const Vector &J,
const Vector &C,
Vector &op)
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_W = OccaMemoryRead(W.GetMemory(), W.Size());
const occa::memory o_J = OccaMemoryRead(J.GetMemory(), J.Size());
const occa::memory o_C = OccaMemoryRead(C.GetMemory(), C.Size());
occa::memory o_op = OccaMemoryWrite(op.GetMemory(), op.Size());
const bool const_c = C.Size() == 1;
const occa_id_t id = std::make_pair(D1D,Q1D);
static occa_kernel_t OccaDiffSetup3D_ker;
if (OccaDiffSetup3D_ker.find(id) == OccaDiffSetup3D_ker.end())
{
const occa::kernel DiffusionSetup3D =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionSetup3D", props);
OccaDiffSetup3D_ker.emplace(id, DiffusionSetup3D);
}
OccaDiffSetup3D_ker.at(id)(NE, o_W, o_J, o_C, o_op, const_c);
}
#endif // MFEM_USE_OCCA
void PADiffusionAssembleDiagonal(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symm,
const Array<double> &B,
const Array<double> &G,
const Vector &D,
Vector &Y)
{
if (dim == 2)
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPADiffusionDiagonal2D<2,2,8>(NE,symm,B,G,D,Y);
case 0x33: return SmemPADiffusionDiagonal2D<3,3,8>(NE,symm,B,G,D,Y);
case 0x44: return SmemPADiffusionDiagonal2D<4,4,4>(NE,symm,B,G,D,Y);
case 0x55: return SmemPADiffusionDiagonal2D<5,5,4>(NE,symm,B,G,D,Y);
case 0x66: return SmemPADiffusionDiagonal2D<6,6,2>(NE,symm,B,G,D,Y);
case 0x77: return SmemPADiffusionDiagonal2D<7,7,2>(NE,symm,B,G,D,Y);
case 0x88: return SmemPADiffusionDiagonal2D<8,8,1>(NE,symm,B,G,D,Y);
case 0x99: return SmemPADiffusionDiagonal2D<9,9,1>(NE,symm,B,G,D,Y);
default: return PADiffusionDiagonal2D(NE,symm,B,G,D,Y,D1D,Q1D);
}
}
else if (dim == 3)
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPADiffusionDiagonal3D<2,2>(NE,symm,B,G,D,Y);
case 0x23: return SmemPADiffusionDiagonal3D<2,3>(NE,symm,B,G,D,Y);
case 0x34: return SmemPADiffusionDiagonal3D<3,4>(NE,symm,B,G,D,Y);
case 0x45: return SmemPADiffusionDiagonal3D<4,5>(NE,symm,B,G,D,Y);
case 0x46: return SmemPADiffusionDiagonal3D<4,6>(NE,symm,B,G,D,Y);
case 0x56: return SmemPADiffusionDiagonal3D<5,6>(NE,symm,B,G,D,Y);
case 0x67: return SmemPADiffusionDiagonal3D<6,7>(NE,symm,B,G,D,Y);
case 0x78: return SmemPADiffusionDiagonal3D<7,8>(NE,symm,B,G,D,Y);
case 0x89: return SmemPADiffusionDiagonal3D<8,9>(NE,symm,B,G,D,Y);
case 0x9A: return SmemPADiffusionDiagonal3D<9,10>(NE,symm,B,G,D,Y);
default: return PADiffusionDiagonal3D(NE,symm,B,G,D,Y,D1D,Q1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
void PADiffusionApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symm,
const Array<double> &B,
const Array<double> &G,
const Array<double> &Bt,
const Array<double> &Gt,
const Vector &D,
const Vector &X,
Vector &Y)
{
#ifdef MFEM_USE_OCCA
if (DeviceCanUseOcca())
{
if (dim == 2)
{
OccaPADiffusionApply2D(D1D,Q1D,NE,B,G,Bt,Gt,D,X,Y);
return;
}
if (dim == 3)
{
OccaPADiffusionApply3D(D1D,Q1D,NE,B,G,Bt,Gt,D,X,Y);
return;
}
MFEM_ABORT("OCCA PADiffusionApply unknown kernel!");
}
#endif // MFEM_USE_OCCA
const int id = (D1D << 4) | Q1D;
if (dim == 2)
{
switch (id)
{
case 0x22: return SmemPADiffusionApply2D<2,2,16>(NE,symm,B,G,D,X,Y);
case 0x33: return SmemPADiffusionApply2D<3,3,16>(NE,symm,B,G,D,X,Y);
case 0x44: return SmemPADiffusionApply2D<4,4,8>(NE,symm,B,G,D,X,Y);
case 0x55: return SmemPADiffusionApply2D<5,5,8>(NE,symm,B,G,D,X,Y);
case 0x66: return SmemPADiffusionApply2D<6,6,4>(NE,symm,B,G,D,X,Y);
case 0x77: return SmemPADiffusionApply2D<7,7,4>(NE,symm,B,G,D,X,Y);
case 0x88: return SmemPADiffusionApply2D<8,8,2>(NE,symm,B,G,D,X,Y);
case 0x99: return SmemPADiffusionApply2D<9,9,2>(NE,symm,B,G,D,X,Y);
default: return PADiffusionApply2D(NE,symm,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
}
}
if (dim == 3)
{
switch (id)
{
case 0x22: return SmemPADiffusionApply3D<2,2>(NE,symm,B,G,D,X,Y);
case 0x23: return SmemPADiffusionApply3D<2,3>(NE,symm,B,G,D,X,Y);
case 0x34: return SmemPADiffusionApply3D<3,4>(NE,symm,B,G,D,X,Y);
case 0x45: return SmemPADiffusionApply3D<4,5>(NE,symm,B,G,D,X,Y);
case 0x46: return SmemPADiffusionApply3D<4,6>(NE,symm,B,G,D,X,Y);
case 0x56: return SmemPADiffusionApply3D<5,6>(NE,symm,B,G,D,X,Y);
case 0x58: return SmemPADiffusionApply3D<5,8>(NE,symm,B,G,D,X,Y);
case 0x67: return SmemPADiffusionApply3D<6,7>(NE,symm,B,G,D,X,Y);
case 0x78: return SmemPADiffusionApply3D<7,8>(NE,symm,B,G,D,X,Y);
case 0x89: return SmemPADiffusionApply3D<8,9>(NE,symm,B,G,D,X,Y);
default: return PADiffusionApply3D(NE,symm,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
}
}
MFEM_ABORT("Unknown kernel: 0x"<<std::hex << id << std::dec);
}
#ifdef MFEM_USE_OCCA
void OccaPADiffusionApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &G,
const Array<double> &Bt,
const Array<double> &Gt,
const Vector &D,
const Vector &X,
Vector &Y)
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
const occa::memory o_G = OccaMemoryRead(G.GetMemory(), G.Size());
const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
const occa::memory o_Gt = OccaMemoryRead(Gt.GetMemory(), Gt.Size());
const occa::memory o_D = OccaMemoryRead(D.GetMemory(), D.Size());
const occa::memory o_X = OccaMemoryRead(X.GetMemory(), X.Size());
occa::memory o_Y = OccaMemoryReadWrite(Y.GetMemory(), Y.Size());
const occa_id_t id = std::make_pair(D1D,Q1D);
if (!Device::Allows(Backend::OCCA_CUDA))
{
static occa_kernel_t OccaDiffApply2D_cpu;
if (OccaDiffApply2D_cpu.find(id) == OccaDiffApply2D_cpu.end())
{
const occa::kernel DiffusionApply2D_CPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionApply2D_CPU", props);
OccaDiffApply2D_cpu.emplace(id, DiffusionApply2D_CPU);
}
OccaDiffApply2D_cpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
}
else
{
static occa_kernel_t OccaDiffApply2D_gpu;
if (OccaDiffApply2D_gpu.find(id) == OccaDiffApply2D_gpu.end())
{
const occa::kernel DiffusionApply2D_GPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionApply2D_GPU", props);
OccaDiffApply2D_gpu.emplace(id, DiffusionApply2D_GPU);
}
OccaDiffApply2D_gpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
}
}
void OccaPADiffusionApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &G,
const Array<double> &Bt,
const Array<double> &Gt,
const Vector &D,
const Vector &X,
Vector &Y)
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
const occa::memory o_G = OccaMemoryRead(G.GetMemory(), G.Size());
const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
const occa::memory o_Gt = OccaMemoryRead(Gt.GetMemory(), Gt.Size());
const occa::memory o_D = OccaMemoryRead(D.GetMemory(), D.Size());
const occa::memory o_X = OccaMemoryRead(X.GetMemory(), X.Size());
occa::memory o_Y = OccaMemoryReadWrite(Y.GetMemory(), Y.Size());
const occa_id_t id = std::make_pair(D1D,Q1D);
if (!Device::Allows(Backend::OCCA_CUDA))
{
static occa_kernel_t OccaDiffApply3D_cpu;
if (OccaDiffApply3D_cpu.find(id) == OccaDiffApply3D_cpu.end())
{
const occa::kernel DiffusionApply3D_CPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionApply3D_CPU", props);
OccaDiffApply3D_cpu.emplace(id, DiffusionApply3D_CPU);
}
OccaDiffApply3D_cpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
}
else
{
static occa_kernel_t OccaDiffApply3D_gpu;
if (OccaDiffApply3D_gpu.find(id) == OccaDiffApply3D_gpu.end())
{
const occa::kernel DiffusionApply3D_GPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionApply3D_GPU", props);
OccaDiffApply3D_gpu.emplace(id, DiffusionApply3D_GPU);
}
OccaDiffApply3D_gpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
}
}
#endif // MFEM_USE_OCCA
} // namespace internal
} // namespace mfem
@@ -9,189 +9,42 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "qfunction.hpp"
#include "ceed/integrators/diffusion/diffusion.hpp"
#ifndef MFEM_BILININTEG_DIFFUSION_KERNELS_HPP
#define MFEM_BILININTEG_DIFFUSION_KERNELS_HPP
using namespace std;
#include "../../config/config.hpp"
#include "../../general/array.hpp"
#include "../../general/forall.hpp"
#include "../../linalg/dtensor.hpp"
#include "../../linalg/vector.hpp"
#include "../bilininteg.hpp"
namespace mfem
{
// PA Diffusion Integrator
// OCCA 2D Assemble kernel
#ifdef MFEM_USE_OCCA
static void OccaPADiffusionSetup2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &W,
const Vector &J,
const Vector &C,
Vector &op)
namespace internal
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_W = OccaMemoryRead(W.GetMemory(), W.Size());
const occa::memory o_J = OccaMemoryRead(J.GetMemory(), J.Size());
const occa::memory o_C = OccaMemoryRead(C.GetMemory(), C.Size());
occa::memory o_op = OccaMemoryWrite(op.GetMemory(), op.Size());
const bool const_c = C.Size() == 1;
const occa_id_t id = std::make_pair(D1D,Q1D);
static occa_kernel_t OccaDiffSetup2D_ker;
if (OccaDiffSetup2D_ker.find(id) == OccaDiffSetup2D_ker.end())
{
const occa::kernel DiffusionSetup2D =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionSetup2D", props);
OccaDiffSetup2D_ker.emplace(id, DiffusionSetup2D);
}
OccaDiffSetup2D_ker.at(id)(NE, o_W, o_J, o_C, o_op, const_c);
}
static void OccaPADiffusionSetup3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &W,
const Vector &J,
const Vector &C,
Vector &op)
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_W = OccaMemoryRead(W.GetMemory(), W.Size());
const occa::memory o_J = OccaMemoryRead(J.GetMemory(), J.Size());
const occa::memory o_C = OccaMemoryRead(C.GetMemory(), C.Size());
occa::memory o_op = OccaMemoryWrite(op.GetMemory(), op.Size());
const bool const_c = C.Size() == 1;
const occa_id_t id = std::make_pair(D1D,Q1D);
static occa_kernel_t OccaDiffSetup3D_ker;
if (OccaDiffSetup3D_ker.find(id) == OccaDiffSetup3D_ker.end())
{
const occa::kernel DiffusionSetup3D =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionSetup3D", props);
OccaDiffSetup3D_ker.emplace(id, DiffusionSetup3D);
}
OccaDiffSetup3D_ker.at(id)(NE, o_W, o_J, o_C, o_op, const_c);
}
#endif // MFEM_USE_OCCA
void PADiffusionSetup(const int dim,
const int sdim,
const int D1D,
const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &W,
const Vector &J,
const Vector &C,
Vector &D);
template<>
void PADiffusionSetup2D<2>(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
{
const bool symmetric = (coeffDim != 4);
const bool const_c = c.Size() == 1;
MFEM_VERIFY(coeffDim < 3 ||
!const_c, "Constant matrix coefficient not supported");
const auto W = Reshape(w.Read(), Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,2,2,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1) :
Reshape(c.Read(), coeffDim,Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D, symmetric ? 3 : 4, NE);
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double J11 = J(qx,qy,0,0,e);
const double J21 = J(qx,qy,1,0,e);
const double J12 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double w_detJ = W(qx,qy) / ((J11*J22)-(J21*J12));
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient
{
// First compute entries of R = MJ^{-T}, without det J factor.
const double M11 = C(0,qx,qy,e);
const double M12 = C(1,qx,qy,e);
const double M21 = symmetric ? M12 : C(2,qx,qy,e);
const double M22 = symmetric ? C(2,qx,qy,e) : C(3,qx,qy,e);
const double R11 = M11*J22 - M12*J12;
const double R21 = M21*J22 - M22*J12;
const double R12 = -M11*J21 + M12*J11;
const double R22 = -M21*J21 + M22*J11;
// Now set y to J^{-1}R.
D(qx,qy,0,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
D(qx,qy,1,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
D(qx,qy,2,e) = w_detJ * (symmetric ? (-J21*R12 + J11*R22) :
(J22*R12 - J12*R22)); // 2,2 or 1,2
if (!symmetric)
{
D(qx,qy,3,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
}
}
else // Vector or scalar coefficient
{
const double C1 = const_c ? C(0,0,0,0) : C(0,qx,qy,e);
const double C2 = const_c ? C(0,0,0,0) :
(coeffDim == 2 ? C(1,qx,qy,e) : C(0,qx,qy,e));
D(qx,qy,0,e) = w_detJ * (C2*J12*J12 + C1*J22*J22); // 1,1
D(qx,qy,1,e) = -w_detJ * (C2*J12*J11 + C1*J22*J21); // 1,2
D(qx,qy,2,e) = w_detJ * (C2*J11*J11 + C1*J21*J21); // 2,2
}
}
}
});
}
// PA Diffusion Assemble 2D kernel with 3D node coords
template<>
void PADiffusionSetup2D<3>(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
{
MFEM_VERIFY(coeffDim == 1, "Matrix and vector coefficients not supported");
constexpr int DIM = 2;
constexpr int SDIM = 3;
const bool const_c = c.Size() == 1;
const auto W = Reshape(w.Read(), Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,SDIM,DIM,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
Reshape(c.Read(), Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double wq = W(qx,qy);
const double J11 = J(qx,qy,0,0,e);
const double J21 = J(qx,qy,1,0,e);
const double J31 = J(qx,qy,2,0,e);
const double J12 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double J32 = J(qx,qy,2,1,e);
const double E = J11*J11 + J21*J21 + J31*J31;
const double G = J12*J12 + J22*J22 + J32*J32;
const double F = J11*J12 + J21*J22 + J31*J32;
const double iw = 1.0 / sqrt(E*G - F*F);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
const double alpha = wq * coeff * iw;
D(qx,qy,0,e) = alpha * G; // 1,1
D(qx,qy,1,e) = -alpha * F; // 1,2
D(qx,qy,2,e) = alpha * E; // 2,2
}
}
});
}
// PA Diffusion Assemble 2D kernel
template<int T_SDIM>
void PADiffusionSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d);
// PA Diffusion Assemble 3D kernel
void PADiffusionSetup3D(const int Q1D,
@@ -200,217 +53,41 @@ void PADiffusionSetup3D(const int Q1D,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
{
const bool symmetric = (coeffDim != 9);
const bool const_c = c.Size() == 1;
MFEM_VERIFY(coeffDim < 6 ||
!const_c, "Constant matrix coefficient not supported");
const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1,1) :
Reshape(c.Read(), coeffDim,Q1D,Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D,Q1D, symmetric ? 6 : 9, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double J11 = J(qx,qy,qz,0,0,e);
const double J21 = J(qx,qy,qz,1,0,e);
const double J31 = J(qx,qy,qz,2,0,e);
const double J12 = J(qx,qy,qz,0,1,e);
const double J22 = J(qx,qy,qz,1,1,e);
const double J32 = J(qx,qy,qz,2,1,e);
const double J13 = J(qx,qy,qz,0,2,e);
const double J23 = J(qx,qy,qz,1,2,e);
const double J33 = J(qx,qy,qz,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double w_detJ = W(qx,qy,qz) / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
Vector &d);
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
{
// Compute entries of R = MJ^{-T} = M adj(J)^T, without det J.
const double M11 = C(0, qx,qy,qz, e);
const double M12 = C(1, qx,qy,qz, e);
const double M13 = C(2, qx,qy,qz, e);
const double M21 = (!symmetric) ? C(3, qx,qy,qz, e) : M12;
const double M22 = (!symmetric) ? C(4, qx,qy,qz, e) : C(3, qx,qy,qz, e);
const double M23 = (!symmetric) ? C(5, qx,qy,qz, e) : C(4, qx,qy,qz, e);
const double M31 = (!symmetric) ? C(6, qx,qy,qz, e) : M13;
const double M32 = (!symmetric) ? C(7, qx,qy,qz, e) : M23;
const double M33 = (!symmetric) ? C(8, qx,qy,qz, e) : C(5, qx,qy,qz, e);
const double R11 = M11*A11 + M12*A12 + M13*A13;
const double R12 = M11*A21 + M12*A22 + M13*A23;
const double R13 = M11*A31 + M12*A32 + M13*A33;
const double R21 = M21*A11 + M22*A12 + M23*A13;
const double R22 = M21*A21 + M22*A22 + M23*A23;
const double R23 = M21*A31 + M22*A32 + M23*A33;
const double R31 = M31*A11 + M32*A12 + M33*A13;
const double R32 = M31*A21 + M32*A22 + M33*A23;
const double R33 = M31*A31 + M32*A32 + M33*A33;
// Now set D to J^{-1} R = adj(J) R
D(qx,qy,qz,0,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
const double D12 = w_detJ * (A11*R12 + A12*R22 + A13*R32);
D(qx,qy,qz,1,e) = D12; // 1,2
D(qx,qy,qz,2,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
const double D22 = w_detJ * (A21*R12 + A22*R22 + A23*R32);
const double D23 = w_detJ * (A21*R13 + A22*R23 + A23*R33);
const double D33 = w_detJ * (A31*R13 + A32*R23 + A33*R33);
D(qx,qy,qz,4,e) = symmetric ? D23 : D22; // 2,3 or 2,2
D(qx,qy,qz,5,e) = symmetric ? D33 : D23; // 3,3 or 2,3
if (symmetric)
{
D(qx,qy,qz,3,e) = D22; // 2,2
}
else
{
D(qx,qy,qz,3,e) = w_detJ * (A21*R11 + A22*R21 + A23*R31); // 2,1
D(qx,qy,qz,6,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
D(qx,qy,qz,7,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
D(qx,qy,qz,8,e) = D33; // 3,3
}
}
else // Vector or scalar coefficient version
{
const double C1 = const_c ? C(0,0,0,0,0) : C(0,qx,qy,qz,e);
const double C2 = const_c ? C(0,0,0,0,0) :
(coeffDim == 3 ? C(1,qx,qy,qz,e) : C(0,qx,qy,qz,e));
const double C3 = const_c ? C(0,0,0,0,0) :
(coeffDim == 3 ? C(2,qx,qy,qz,e) : C(0,qx,qy,qz,e));
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
D(qx,qy,qz,0,e) = w_detJ * (C1*A11*A11 + C2*A12*A12 + C3*A13*A13); // 1,1
D(qx,qy,qz,1,e) = w_detJ * (C1*A11*A21 + C2*A12*A22 + C3*A13*A23); // 2,1
D(qx,qy,qz,2,e) = w_detJ * (C1*A11*A31 + C2*A12*A32 + C3*A13*A33); // 3,1
D(qx,qy,qz,3,e) = w_detJ * (C1*A21*A21 + C2*A22*A22 + C3*A23*A23); // 2,2
D(qx,qy,qz,4,e) = w_detJ * (C1*A21*A31 + C2*A22*A32 + C3*A23*A33); // 3,2
D(qx,qy,qz,5,e) = w_detJ * (C1*A31*A31 + C2*A32*A32 + C3*A33*A33); // 3,3
}
}
}
}
});
}
static void PADiffusionSetup(const int dim,
const int sdim,
const int D1D,
const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &W,
const Vector &J,
const Vector &C,
Vector &D)
{
if (dim == 1) { MFEM_ABORT("dim==1 not supported in PADiffusionSetup"); }
if (dim == 2)
{
#ifdef MFEM_USE_OCCA
if (DeviceCanUseOcca())
{
OccaPADiffusionSetup2D(D1D, Q1D, NE, W, J, C, D);
return;
}
#else
MFEM_CONTRACT_VAR(D1D);
// OCCA 2D Assemble kernel
void OccaPADiffusionSetup2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &W,
const Vector &J,
const Vector &C,
Vector &op);
// OCCA 3D Assemble kernel
void OccaPADiffusionSetup3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &W,
const Vector &J,
const Vector &C,
Vector &op);
#endif // MFEM_USE_OCCA
if (sdim == 2) { PADiffusionSetup2D<2>(Q1D, coeffDim, NE, W, J, C, D); }
if (sdim == 3) { PADiffusionSetup2D<3>(Q1D, coeffDim, NE, W, J, C, D); }
}
if (dim == 3)
{
#ifdef MFEM_USE_OCCA
if (DeviceCanUseOcca())
{
OccaPADiffusionSetup3D(D1D, Q1D, NE, W, J, C, D);
return;
}
#endif // MFEM_USE_OCCA
PADiffusionSetup3D(Q1D, coeffDim, NE, W, J, C, D);
}
}
void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
Device::GetDeviceMemoryType() : pa_mt;
// Assuming the same element type
fespace = &fes;
Mesh *mesh = fes.GetMesh();
if (mesh->GetNE() == 0) { return; }
const FiniteElement &el = *fes.GetFE(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
if (DeviceCanUseCeed())
{
delete ceedOp;
MFEM_VERIFY(!VQ && !MQ,
"Only scalar coefficient supported for DiffusionIntegrator"
" with libCEED");
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedPADiffusionIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::PADiffusionIntegrator(fes, *ir, Q);
}
return;
}
const int dims = el.GetDim();
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mt);
const int sdim = mesh->SpaceDimension();
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(qs, CoefficientStorage::COMPRESSED);
if (MQ) { coeff.ProjectTranspose(*MQ); }
else if (VQ) { coeff.Project(*VQ); }
else if (Q) { coeff.Project(*Q); }
else { coeff.SetConstant(1.0); }
const int coeff_dim = coeff.GetVDim();
symmetric = (coeff_dim != dims*dims);
const int pa_size = symmetric ? symmDims : dims*dims;
pa_data.SetSize(pa_size * nq * ne, mt);
PADiffusionSetup(dim, sdim, dofs1D, quad1D, coeff_dim, ne, ir->GetWeights(),
geom->J, coeff, pa_data);
}
void PADiffusionAssembleDiagonal(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symm,
const Array<double> &B,
const Array<double> &G,
const Vector &D,
Vector &Y);
// PA Diffusion Diagonal 2D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void PADiffusionDiagonal2D(const int NE,
inline void PADiffusionDiagonal2D(const int NE,
const bool symmetric,
const Array<double> &b,
const Array<double> &g,
@@ -429,7 +106,7 @@ static void PADiffusionDiagonal2D(const int NE,
// store necessary entries
auto D = Reshape(d.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -476,7 +153,7 @@ static void PADiffusionDiagonal2D(const int NE,
// Shared memory PA Diffusion Diagonal 2D kernel
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
static void SmemPADiffusionDiagonal2D(const int NE,
inline void SmemPADiffusionDiagonal2D(const int NE,
const bool symmetric,
const Array<double> &b_,
const Array<double> &g_,
@@ -496,7 +173,7 @@ static void SmemPADiffusionDiagonal2D(const int NE,
auto g = Reshape(g_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
{
const int tidz = MFEM_THREAD_ID(z);
const int D1D = T_D1D ? T_D1D : d1d;
@@ -569,8 +246,9 @@ static void SmemPADiffusionDiagonal2D(const int NE,
});
}
// PA Diffusion Diagonal 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void PADiffusionDiagonal3D(const int NE,
inline void PADiffusionDiagonal3D(const int NE,
const bool symmetric,
const Array<double> &b,
const Array<double> &g,
@@ -590,7 +268,7 @@ static void PADiffusionDiagonal3D(const int NE,
auto G = Reshape(g.Read(), Q1D, D1D);
auto Q = Reshape(d.Read(), Q1D*Q1D*Q1D, symmetric ? 6 : 9, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -614,8 +292,8 @@ static void PADiffusionDiagonal3D(const int NE,
{
const int q = qx + (qy + qz * Q1D) * Q1D;
const int ksym = j >= i ?
3 - (3-i)*(2-i)/2 + j:
3 - (3-j)*(2-j)/2 + i;
3 - (3-i)*(2-i)/2 + j:
3 - (3-j)*(2-j)/2 + i;
const int k = symmetric ? ksym : (i*DIM) + j;
const double O = Q(q,k,e);
const double Bz = B(qz,dz);
@@ -671,7 +349,7 @@ static void PADiffusionDiagonal3D(const int NE,
// Shared memory PA Diffusion Diagonal 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void SmemPADiffusionDiagonal3D(const int NE,
inline void SmemPADiffusionDiagonal3D(const int NE,
const bool symmetric,
const Array<double> &b_,
const Array<double> &g_,
@@ -691,7 +369,7 @@ static void SmemPADiffusionDiagonal3D(const int NE,
auto g = Reshape(g_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D*Q1D*Q1D, symmetric ? 6 : 9, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
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;
@@ -788,169 +466,48 @@ static void SmemPADiffusionDiagonal3D(const int NE,
});
}
static void PADiffusionAssembleDiagonal(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symm,
const Array<double> &B,
const Array<double> &G,
const Vector &D,
Vector &Y)
{
if (dim == 2)
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPADiffusionDiagonal2D<2,2,8>(NE,symm,B,G,D,Y);
case 0x33: return SmemPADiffusionDiagonal2D<3,3,8>(NE,symm,B,G,D,Y);
case 0x44: return SmemPADiffusionDiagonal2D<4,4,4>(NE,symm,B,G,D,Y);
case 0x55: return SmemPADiffusionDiagonal2D<5,5,4>(NE,symm,B,G,D,Y);
case 0x66: return SmemPADiffusionDiagonal2D<6,6,2>(NE,symm,B,G,D,Y);
case 0x77: return SmemPADiffusionDiagonal2D<7,7,2>(NE,symm,B,G,D,Y);
case 0x88: return SmemPADiffusionDiagonal2D<8,8,1>(NE,symm,B,G,D,Y);
case 0x99: return SmemPADiffusionDiagonal2D<9,9,1>(NE,symm,B,G,D,Y);
default: return PADiffusionDiagonal2D(NE,symm,B,G,D,Y,D1D,Q1D);
}
}
else if (dim == 3)
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPADiffusionDiagonal3D<2,2>(NE,symm,B,G,D,Y);
case 0x23: return SmemPADiffusionDiagonal3D<2,3>(NE,symm,B,G,D,Y);
case 0x34: return SmemPADiffusionDiagonal3D<3,4>(NE,symm,B,G,D,Y);
case 0x45: return SmemPADiffusionDiagonal3D<4,5>(NE,symm,B,G,D,Y);
case 0x46: return SmemPADiffusionDiagonal3D<4,6>(NE,symm,B,G,D,Y);
case 0x56: return SmemPADiffusionDiagonal3D<5,6>(NE,symm,B,G,D,Y);
case 0x67: return SmemPADiffusionDiagonal3D<6,7>(NE,symm,B,G,D,Y);
case 0x78: return SmemPADiffusionDiagonal3D<7,8>(NE,symm,B,G,D,Y);
case 0x89: return SmemPADiffusionDiagonal3D<8,9>(NE,symm,B,G,D,Y);
case 0x9A: return SmemPADiffusionDiagonal3D<9,10>(NE,symm,B,G,D,Y);
default: return PADiffusionDiagonal3D(NE,symm,B,G,D,Y,D1D,Q1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
void DiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
{
if (DeviceCanUseCeed())
{
ceedOp->GetDiagonal(diag);
}
else
{
if (pa_data.Size()==0) { AssemblePA(*fespace); }
PADiffusionAssembleDiagonal(dim, dofs1D, quad1D, ne, symmetric,
maps->B, maps->G, pa_data, diag);
}
}
void PADiffusionApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symm,
const Array<double> &B,
const Array<double> &G,
const Array<double> &Bt,
const Array<double> &Gt,
const Vector &D,
const Vector &X,
Vector &Y);
#ifdef MFEM_USE_OCCA
// OCCA PA Diffusion Apply 2D kernel
static void OccaPADiffusionApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &G,
const Array<double> &Bt,
const Array<double> &Gt,
const Vector &D,
const Vector &X,
Vector &Y)
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
const occa::memory o_G = OccaMemoryRead(G.GetMemory(), G.Size());
const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
const occa::memory o_Gt = OccaMemoryRead(Gt.GetMemory(), Gt.Size());
const occa::memory o_D = OccaMemoryRead(D.GetMemory(), D.Size());
const occa::memory o_X = OccaMemoryRead(X.GetMemory(), X.Size());
occa::memory o_Y = OccaMemoryReadWrite(Y.GetMemory(), Y.Size());
const occa_id_t id = std::make_pair(D1D,Q1D);
if (!Device::Allows(Backend::OCCA_CUDA))
{
static occa_kernel_t OccaDiffApply2D_cpu;
if (OccaDiffApply2D_cpu.find(id) == OccaDiffApply2D_cpu.end())
{
const occa::kernel DiffusionApply2D_CPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionApply2D_CPU", props);
OccaDiffApply2D_cpu.emplace(id, DiffusionApply2D_CPU);
}
OccaDiffApply2D_cpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
}
else
{
static occa_kernel_t OccaDiffApply2D_gpu;
if (OccaDiffApply2D_gpu.find(id) == OccaDiffApply2D_gpu.end())
{
const occa::kernel DiffusionApply2D_GPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionApply2D_GPU", props);
OccaDiffApply2D_gpu.emplace(id, DiffusionApply2D_GPU);
}
OccaDiffApply2D_gpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
}
}
void OccaPADiffusionApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &G,
const Array<double> &Bt,
const Array<double> &Gt,
const Vector &D,
const Vector &X,
Vector &Y);
// OCCA PA Diffusion Apply 3D kernel
static void OccaPADiffusionApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &G,
const Array<double> &Bt,
const Array<double> &Gt,
const Vector &D,
const Vector &X,
Vector &Y)
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
const occa::memory o_G = OccaMemoryRead(G.GetMemory(), G.Size());
const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
const occa::memory o_Gt = OccaMemoryRead(Gt.GetMemory(), Gt.Size());
const occa::memory o_D = OccaMemoryRead(D.GetMemory(), D.Size());
const occa::memory o_X = OccaMemoryRead(X.GetMemory(), X.Size());
occa::memory o_Y = OccaMemoryReadWrite(Y.GetMemory(), Y.Size());
const occa_id_t id = std::make_pair(D1D,Q1D);
if (!Device::Allows(Backend::OCCA_CUDA))
{
static occa_kernel_t OccaDiffApply3D_cpu;
if (OccaDiffApply3D_cpu.find(id) == OccaDiffApply3D_cpu.end())
{
const occa::kernel DiffusionApply3D_CPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionApply3D_CPU", props);
OccaDiffApply3D_cpu.emplace(id, DiffusionApply3D_CPU);
}
OccaDiffApply3D_cpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
}
else
{
static occa_kernel_t OccaDiffApply3D_gpu;
if (OccaDiffApply3D_gpu.find(id) == OccaDiffApply3D_gpu.end())
{
const occa::kernel DiffusionApply3D_GPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"DiffusionApply3D_GPU", props);
OccaDiffApply3D_gpu.emplace(id, DiffusionApply3D_GPU);
}
OccaDiffApply3D_gpu.at(id)(NE, o_B, o_G, o_Bt, o_Gt, o_D, o_X, o_Y);
}
}
void OccaPADiffusionApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &G,
const Array<double> &Bt,
const Array<double> &Gt,
const Vector &D,
const Vector &X,
Vector &Y);
#endif // MFEM_USE_OCCA
// PA Diffusion Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void PADiffusionApply2D(const int NE,
inline void PADiffusionApply2D(const int NE,
const bool symmetric,
const Array<double> &b_,
const Array<double> &g_,
@@ -973,7 +530,7 @@ static void PADiffusionApply2D(const int NE,
auto D = Reshape(d_.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
auto X = Reshape(x_.Read(), D1D, D1D, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -1072,7 +629,7 @@ static void PADiffusionApply2D(const int NE,
// Shared memory PA Diffusion Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
static void SmemPADiffusionApply2D(const int NE,
inline void SmemPADiffusionApply2D(const int NE,
const bool symmetric,
const Array<double> &b_,
const Array<double> &g_,
@@ -1094,7 +651,7 @@ static void SmemPADiffusionApply2D(const int NE,
auto D = Reshape(d_.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
auto x = Reshape(x_.Read(), D1D, D1D, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE(int e)
{
const int tidz = MFEM_THREAD_ID(z);
const int D1D = T_D1D ? T_D1D : d1d;
@@ -1230,7 +787,7 @@ static void SmemPADiffusionApply2D(const int NE,
// PA Diffusion Apply 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void PADiffusionApply3D(const int NE,
inline void PADiffusionApply3D(const int NE,
const bool symmetric,
const Array<double> &b,
const Array<double> &g,
@@ -1252,7 +809,7 @@ static void PADiffusionApply3D(const int NE,
auto D = Reshape(d_.Read(), Q1D*Q1D*Q1D, symmetric ? 6 : 9, NE);
auto X = Reshape(x_.Read(), D1D, D1D, D1D, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -1421,8 +978,9 @@ static void PADiffusionApply3D(const int NE,
});
}
// Shared memory PA Diffusion Apply 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void SmemPADiffusionApply3D(const int NE,
inline void SmemPADiffusionApply3D(const int NE,
const bool symmetric,
const Array<double> &b_,
const Array<double> &g_,
@@ -1443,7 +1001,7 @@ static void SmemPADiffusionApply3D(const int NE,
auto d = Reshape(d_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -1643,99 +1201,8 @@ static void SmemPADiffusionApply3D(const int NE,
});
}
static void PADiffusionApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symm,
const Array<double> &B,
const Array<double> &G,
const Array<double> &Bt,
const Array<double> &Gt,
const Vector &D,
const Vector &X,
Vector &Y)
{
#ifdef MFEM_USE_OCCA
if (DeviceCanUseOcca())
{
if (dim == 2)
{
OccaPADiffusionApply2D(D1D,Q1D,NE,B,G,Bt,Gt,D,X,Y);
return;
}
if (dim == 3)
{
OccaPADiffusionApply3D(D1D,Q1D,NE,B,G,Bt,Gt,D,X,Y);
return;
}
MFEM_ABORT("OCCA PADiffusionApply unknown kernel!");
}
#endif // MFEM_USE_OCCA
const int id = (D1D << 4) | Q1D;
if (dim == 2)
{
switch (id)
{
case 0x22: return SmemPADiffusionApply2D<2,2,16>(NE,symm,B,G,D,X,Y);
case 0x33: return SmemPADiffusionApply2D<3,3,16>(NE,symm,B,G,D,X,Y);
case 0x44: return SmemPADiffusionApply2D<4,4,8>(NE,symm,B,G,D,X,Y);
case 0x55: return SmemPADiffusionApply2D<5,5,8>(NE,symm,B,G,D,X,Y);
case 0x66: return SmemPADiffusionApply2D<6,6,4>(NE,symm,B,G,D,X,Y);
case 0x77: return SmemPADiffusionApply2D<7,7,4>(NE,symm,B,G,D,X,Y);
case 0x88: return SmemPADiffusionApply2D<8,8,2>(NE,symm,B,G,D,X,Y);
case 0x99: return SmemPADiffusionApply2D<9,9,2>(NE,symm,B,G,D,X,Y);
default: return PADiffusionApply2D(NE,symm,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
}
}
if (dim == 3)
{
switch (id)
{
case 0x22: return SmemPADiffusionApply3D<2,2>(NE,symm,B,G,D,X,Y);
case 0x23: return SmemPADiffusionApply3D<2,3>(NE,symm,B,G,D,X,Y);
case 0x34: return SmemPADiffusionApply3D<3,4>(NE,symm,B,G,D,X,Y);
case 0x45: return SmemPADiffusionApply3D<4,5>(NE,symm,B,G,D,X,Y);
case 0x46: return SmemPADiffusionApply3D<4,6>(NE,symm,B,G,D,X,Y);
case 0x56: return SmemPADiffusionApply3D<5,6>(NE,symm,B,G,D,X,Y);
case 0x58: return SmemPADiffusionApply3D<5,8>(NE,symm,B,G,D,X,Y);
case 0x67: return SmemPADiffusionApply3D<6,7>(NE,symm,B,G,D,X,Y);
case 0x78: return SmemPADiffusionApply3D<7,8>(NE,symm,B,G,D,X,Y);
case 0x89: return SmemPADiffusionApply3D<8,9>(NE,symm,B,G,D,X,Y);
default: return PADiffusionApply3D(NE,symm,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
}
}
MFEM_ABORT("Unknown kernel: 0x"<<std::hex << id << std::dec);
}
// PA Diffusion Apply kernel
void DiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (DeviceCanUseCeed())
{
ceedOp->AddMult(x, y);
}
else
{
PADiffusionApply(dim, dofs1D, quad1D, ne, symmetric,
maps->B, maps->G, maps->Bt, maps->Gt,
pa_data, x, y);
}
}
void DiffusionIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const
{
if (symmetric)
{
AddMultPA(x, y);
}
else
{
MFEM_ABORT("DiffusionIntegrator::AddMultTransposePA only implemented in "
"the symmetric case.")
}
}
} // namespace internal
} // namespace mfem
#endif
@@ -9,12 +9,9 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/integrators/diffusion/diffusion.hpp"
using namespace std;
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../ceed/integrators/diffusion/diffusion.hpp"
namespace mfem
{
+118
View File
@@ -0,0 +1,118 @@
// Copyright (c) 2010-2023, 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 "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "../ceed/integrators/diffusion/diffusion.hpp"
#include "bilininteg_diffusion_kernels.hpp"
namespace mfem
{
void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
Device::GetDeviceMemoryType() : pa_mt;
// Assuming the same element type
fespace = &fes;
Mesh *mesh = fes.GetMesh();
if (mesh->GetNE() == 0) { return; }
const FiniteElement &el = *fes.GetFE(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
if (DeviceCanUseCeed())
{
delete ceedOp;
MFEM_VERIFY(!VQ && !MQ,
"Only scalar coefficient supported for DiffusionIntegrator"
" with libCEED");
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedPADiffusionIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::PADiffusionIntegrator(fes, *ir, Q);
}
return;
}
const int dims = el.GetDim();
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mt);
const int sdim = mesh->SpaceDimension();
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(qs, CoefficientStorage::COMPRESSED);
if (MQ) { coeff.ProjectTranspose(*MQ); }
else if (VQ) { coeff.Project(*VQ); }
else if (Q) { coeff.Project(*Q); }
else { coeff.SetConstant(1.0); }
const int coeff_dim = coeff.GetVDim();
symmetric = (coeff_dim != dims*dims);
const int pa_size = symmetric ? symmDims : dims*dims;
pa_data.SetSize(pa_size * nq * ne, mt);
internal::PADiffusionSetup(dim, sdim, dofs1D, quad1D, coeff_dim, ne,
ir->GetWeights(), geom->J, coeff, pa_data);
}
void DiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
{
if (DeviceCanUseCeed())
{
ceedOp->GetDiagonal(diag);
}
else
{
if (pa_data.Size()==0) { AssemblePA(*fespace); }
internal::PADiffusionAssembleDiagonal(dim, dofs1D, quad1D, ne, symmetric,
maps->B, maps->G, pa_data, diag);
}
}
void DiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (DeviceCanUseCeed())
{
ceedOp->AddMult(x, y);
}
else
{
internal::PADiffusionApply(dim, dofs1D, quad1D, ne, symmetric,
maps->B, maps->G, maps->Bt, maps->Gt,
pa_data, x, y);
}
}
void DiffusionIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const
{
if (symmetric)
{
AddMultPA(x, y);
}
else
{
MFEM_ABORT("DiffusionIntegrator::AddMultTransposePA only implemented in "
"the symmetric case.")
}
}
} // namespace mfem
+98
View File
@@ -0,0 +1,98 @@
// Copyright (c) 2010-2023, 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 "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "bilininteg_hdiv_kernels.hpp"
namespace mfem
{
void DivDivIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement *fel = fes.GetFE(0);
const VectorTensorFiniteElement *el =
dynamic_cast<const VectorTensorFiniteElement*>(fel);
MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir = IntRule ? IntRule : &MassIntegrator::GetRule
(*el, *el, *mesh->GetElementTransformation(0));
const int dims = el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(nq * ne, Device::GetMemoryType());
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(Q, qs, CoefficientStorage::FULL);
if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 3)
{
internal::PADivDivSetup3D(quad1D, ne, ir->GetWeights(), geom->J, coeff,
pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 2)
{
internal::PADivDivSetup2D(quad1D, ne, ir->GetWeights(), geom->J, coeff,
pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
void DivDivIntegrator::AssembleDiagonalPA(Vector& diag)
{
if (dim == 3)
{
internal::PADivDivAssembleDiagonal3D(dofs1D, quad1D, ne,
mapsO->B, mapsC->G, pa_data, diag);
}
else
{
internal::PADivDivAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->G, pa_data, diag);
}
}
void DivDivIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
internal::PADivDivApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->G,
mapsO->Bt, mapsC->Gt, pa_data, x, y);
else if (dim == 2)
internal::PADivDivApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->G,
mapsO->Bt, mapsC->Gt, pa_data, x, y);
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
} // namespace mfem
@@ -9,18 +9,14 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "qfunction.hpp"
using namespace std;
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
namespace mfem
{
// PA Gradient Integrator
/* Description of the *SetupND functions
Inputs are as follows
\b Q1D number of quadrature points in one dimension.
@@ -62,8 +58,8 @@ namespace mfem
The shared memory (Smem) versions of the kernels differ from the regular
versions in the following properties.
\b MFEM_FORALL is using only one level of parallelism.
\b MFEM_FORALL_ND uses an additional level of parallelism
\b mfem::forall is using only one level of parallelism.
\b mfem::forall_ND uses an additional level of parallelism
\b MFEM_FOREACH_THREAD
These macros allow automatic mapping of manually defined blocks to
@@ -87,7 +83,7 @@ static void PAGradientSetup2D(const int Q1D,
const auto C = const_c ? Reshape(c.Read(), 1,1) :
Reshape(c.Read(), NQ, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
for (int q = 0; q < NQ; ++q)
{
@@ -122,7 +118,7 @@ static void PAGradientSetup3D(const int Q1D,
const auto C = const_c ? Reshape(c.Read(), 1,1) :
Reshape(c.Read(), NQ,NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
for (int q = 0; q < NQ; ++q)
{
@@ -242,7 +238,7 @@ static void PAGradientApply2D(const int NE,
auto op = Reshape(op_.Read(), Q1D*Q1D, 2,2, NE);
auto x = Reshape(x_.Read(), TR_D1D, TR_D1D, NE);
auto y = Reshape(y_.ReadWrite(), TE_D1D, TE_D1D, 2, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
@@ -372,7 +368,7 @@ static void PAGradientApply3D(const int NE,
auto op = Reshape(op_.Read(), Q1D*Q1D*Q1D, 3,3, NE);
auto x = Reshape(x_.Read(), TR_D1D, TR_D1D, TR_D1D, NE);
auto y = Reshape(y_.ReadWrite(), TE_D1D, TE_D1D, TE_D1D, 3, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
@@ -572,7 +568,8 @@ static void SmemPAGradientApply3D(const int NE,
auto x = Reshape(x_.Read(), TR_D1D, TR_D1D, TR_D1D, NE);
auto y = Reshape(y_.ReadWrite(), TE_D1D, TE_D1D, TE_D1D, 3, NE);
MFEM_FORALL_3D(e, NE, (Q1D>8)?8:Q1D, (Q1D>8)?8:Q1D, (Q1D>8)?8:Q1D,
mfem::forall_3D(NE, (Q1D>8)?8:Q1D, (Q1D>8)?8:Q1D, (Q1D>8)?8:Q1D,
[=] MFEM_HOST_DEVICE (int e)
{
const int tidz = MFEM_THREAD_ID(z);
const int D1DR = T_TR_D1D ? T_TR_D1D : tr_d1d;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+578
View File
@@ -0,0 +1,578 @@
// Copyright (c) 2010-2023, 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 "bilininteg_hcurlhdiv_kernels.hpp"
namespace mfem
{
namespace internal
{
// PA H(curl) x H(div) mass assemble 2D kernel, with factor
// dF^{-1} C dF for a vector or matrix coefficient C.
// If transpose, use dF^T C dF^{-T} for H(div) x H(curl).
void PAHcurlHdivMassSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const bool transpose,
const Array<double> &w_,
const Vector &j,
Vector &coeff_,
Vector &op)
{
const bool symmetric = (coeffDim != 4);
auto W = Reshape(w_.Read(), Q1D, Q1D);
auto J = Reshape(j.Read(), Q1D, Q1D, 2, 2, NE);
auto coeff = Reshape(coeff_.Read(), coeffDim, Q1D, Q1D, NE);
auto y = Reshape(op.Write(), 4, Q1D, Q1D, NE);
const int i11 = 0;
const int i12 = transpose ? 2 : 1;
const int i21 = transpose ? 1 : 2;
const int i22 = 3;
mfem::forall_2D(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double J11 = J(qx,qy,0,0,e);
const double J21 = J(qx,qy,1,0,e);
const double J12 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double w_detJ = W(qx,qy) / ((J11*J22) - (J21*J12));
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient version
{
// First compute entries of R = MJ
const double M11 = coeff(i11,qx,qy,e);
const double M12 = (!symmetric) ? coeff(i12,qx,qy,e) : coeff(1,qx,qy,e);
const double M21 = (!symmetric) ? coeff(i21,qx,qy,e) : M12;
const double M22 = (!symmetric) ? coeff(i22,qx,qy,e) : coeff(2,qx,qy,e);
// J^{-1} M^T
const double R11 = ( J22*M11 - J12*M12); // 1,1
const double R12 = ( J22*M21 - J12*M22); // 1,2
const double R21 = (-J21*M11 + J11*M12); // 2,1
const double R22 = (-J21*M21 + J11*M22); // 2,2
// (RJ)^T
y(i11,qx,qy,e) = w_detJ * (R11*J11 + R12*J21); // 1,1
y(i21,qx,qy,e) = w_detJ * (R11*J12 + R12*J22); // 1,2 (transpose)
y(i12,qx,qy,e) = w_detJ * (R21*J11 + R22*J21); // 2,1 (transpose)
y(i22,qx,qy,e) = w_detJ * (R21*J12 + R22*J22); // 2,2
}
else if (coeffDim == 2) // Vector coefficient version
{
const double D1 = coeff(0,qx,qy,e);
const double D2 = coeff(1,qx,qy,e);
const double R11 = D1*J11;
const double R12 = D1*J12;
const double R21 = D2*J21;
const double R22 = D2*J22;
y(i11,qx,qy,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
y(i21,qx,qy,e) = w_detJ * ( J22*R12 - J12*R22); // 1,2 (transpose)
y(i12,qx,qy,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1 (transpose)
y(i22,qx,qy,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
}
}
}
});
}
// PA H(curl) x H(div) mass assemble 3D kernel, with factor
// dF^{-1} C dF for a vector or matrix coefficient C.
// If transpose, use dF^T C dF^{-T} for H(div) x H(curl).
void PAHcurlHdivMassSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const bool transpose,
const Array<double> &w_,
const Vector &j,
Vector &coeff_,
Vector &op)
{
const bool symmetric = (coeffDim != 9);
auto W = Reshape(w_.Read(), Q1D, Q1D, Q1D);
auto J = Reshape(j.Read(), Q1D, Q1D, Q1D, 3, 3, NE);
auto coeff = Reshape(coeff_.Read(), coeffDim, Q1D, Q1D, Q1D, NE);
auto y = Reshape(op.Write(), 9, Q1D, Q1D, Q1D, NE);
const int i11 = 0;
const int i12 = transpose ? 3 : 1;
const int i13 = transpose ? 6 : 2;
const int i21 = transpose ? 1 : 3;
const int i22 = 4;
const int i23 = transpose ? 7 : 5;
const int i31 = transpose ? 2 : 6;
const int i32 = transpose ? 5 : 7;
const int i33 = 8;
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double J11 = J(qx,qy,qz,0,0,e);
const double J21 = J(qx,qy,qz,1,0,e);
const double J31 = J(qx,qy,qz,2,0,e);
const double J12 = J(qx,qy,qz,0,1,e);
const double J22 = J(qx,qy,qz,1,1,e);
const double J32 = J(qx,qy,qz,2,1,e);
const double J13 = J(qx,qy,qz,0,2,e);
const double J23 = J(qx,qy,qz,1,2,e);
const double J33 = J(qx,qy,qz,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
J21 * (J12 * J33 - J32 * J13) +
J31 * (J12 * J23 - J22 * J13);
const double w_detJ = W(qx,qy,qz) / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
{
// First compute entries of R = M^T J
const double M11 = (!symmetric) ? coeff(i11,qx,qy,qz,e) : coeff(0,qx,qy,qz,e);
const double M12 = (!symmetric) ? coeff(i12,qx,qy,qz,e) : coeff(1,qx,qy,qz,e);
const double M13 = (!symmetric) ? coeff(i13,qx,qy,qz,e) : coeff(2,qx,qy,qz,e);
const double M21 = (!symmetric) ? coeff(i21,qx,qy,qz,e) : M12;
const double M22 = (!symmetric) ? coeff(i22,qx,qy,qz,e) : coeff(3,qx,qy,qz,e);
const double M23 = (!symmetric) ? coeff(i23,qx,qy,qz,e) : coeff(4,qx,qy,qz,e);
const double M31 = (!symmetric) ? coeff(i31,qx,qy,qz,e) : M13;
const double M32 = (!symmetric) ? coeff(i32,qx,qy,qz,e) : M23;
const double M33 = (!symmetric) ? coeff(i33,qx,qy,qz,e) : coeff(5,qx,qy,qz,e);
const double R11 = M11*J11 + M21*J21 + M31*J31;
const double R12 = M11*J12 + M21*J22 + M31*J32;
const double R13 = M11*J13 + M21*J23 + M31*J33;
const double R21 = M12*J11 + M22*J21 + M32*J31;
const double R22 = M12*J12 + M22*J22 + M32*J32;
const double R23 = M12*J13 + M22*J23 + M32*J33;
const double R31 = M13*J11 + M23*J21 + M33*J31;
const double R32 = M13*J12 + M23*J22 + M33*J32;
const double R33 = M13*J13 + M23*J23 + M33*J33;
// y = (J^{-1} M^T J)^T
y(i11,qx,qy,qz,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
y(i21,qx,qy,qz,e) = w_detJ * (A11*R12 + A12*R22 + A13*R32); // 1,2
y(i31,qx,qy,qz,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
y(i12,qx,qy,qz,e) = w_detJ * (A21*R11 + A22*R21 + A23*R31); // 2,1
y(i22,qx,qy,qz,e) = w_detJ * (A21*R12 + A22*R22 + A23*R32); // 2,2
y(i32,qx,qy,qz,e) = w_detJ * (A21*R13 + A22*R23 + A23*R33); // 2,3
y(i13,qx,qy,qz,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
y(i23,qx,qy,qz,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
y(i33,qx,qy,qz,e) = w_detJ * (A31*R13 + A32*R23 + A33*R33); // 3,3
}
else if (coeffDim == 3) // Vector coefficient version
{
const double D1 = coeff(0,qx,qy,qz,e);
const double D2 = coeff(1,qx,qy,qz,e);
const double D3 = coeff(2,qx,qy,qz,e);
// detJ J^{-1} DJ = adj(J) DJ
// transpose
y(i11,qx,qy,qz,e) = w_detJ * (D1*A11*J11 + D2*A12*J21 + D3*A13*J31); // 1,1
y(i21,qx,qy,qz,e) = w_detJ * (D1*A11*J12 + D2*A12*J22 + D3*A13*J32); // 1,2
y(i31,qx,qy,qz,e) = w_detJ * (D1*A11*J13 + D2*A12*J23 + D3*A13*J33); // 1,3
y(i12,qx,qy,qz,e) = w_detJ * (D1*A21*J11 + D2*A22*J21 + D3*A23*J31); // 2,1
y(i22,qx,qy,qz,e) = w_detJ * (D1*A21*J12 + D2*A22*J22 + D3*A23*J32); // 2,2
y(i32,qx,qy,qz,e) = w_detJ * (D1*A21*J13 + D2*A22*J23 + D3*A23*J33); // 2,3
y(i13,qx,qy,qz,e) = w_detJ * (D1*A31*J11 + D2*A32*J21 + D3*A33*J31); // 3,1
y(i23,qx,qy,qz,e) = w_detJ * (D1*A31*J12 + D2*A32*J22 + D3*A33*J32); // 3,2
y(i33,qx,qy,qz,e) = w_detJ * (D1*A31*J13 + D2*A32*J23 + D3*A33*J33); // 3,3
}
}
}
}
});
}
// Mass operator for H(curl) and H(div) functions, using Piola transformations
// u = dF^{-T} \hat{u} in H(curl), v = (1 / det dF) dF \hat{v} in H(div).
void PAHcurlHdivMassApply2D(const int D1D,
const int D1Dtest,
const int Q1D,
const int NE,
const bool scalarCoeff,
const bool trialHcurl,
const bool transpose,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_)
{
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 2;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
auto Bot = Reshape(Bot_.Read(), D1Dtest-1, Q1D);
auto Bct = Reshape(Bct_.Read(), D1Dtest, Q1D);
auto op = Reshape(op_.Read(), scalarCoeff ? 1 : 4, Q1D, Q1D, NE);
auto x = Reshape(x_.Read(), 2*(D1D-1)*D1D, NE);
auto y = Reshape(y_.ReadWrite(), 2*(D1Dtest-1)*D1Dtest, NE);
const int i12 = transpose ? 2 : 1;
const int i21 = transpose ? 1 : 2;
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
double mass[MAX_Q1D][MAX_Q1D][VDIM];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
for (int c = 0; c < VDIM; ++c)
{
mass[qy][qx][c] = 0.0;
}
}
}
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y trial components
{
const int D1Dy = trialHcurl ? ((c == 1) ? D1D - 1 : D1D) :
((c == 1) ? D1D : D1D - 1);
const int D1Dx = trialHcurl ? ((c == 0) ? D1D - 1 : D1D) :
((c == 0) ? D1D : D1D - 1);
for (int dy = 0; dy < D1Dy; ++dy)
{
double massX[MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] = 0.0;
}
for (int dx = 0; dx < D1Dx; ++dx)
{
const double t = x(dx + (dy * D1Dx) + osc, e);
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] += t * (trialHcurl ? ((c == 0) ? Bo(qx,dx) : Bc(qx,dx)) :
((c == 0) ? Bc(qx,dx) : Bo(qx,dx)));
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = trialHcurl ? ((c == 1) ? Bo(qy,dy) : Bc(qy,dy)) :
((c == 1) ? Bc(qy,dy) : Bo(qy,dy));
for (int qx = 0; qx < Q1D; ++qx)
{
mass[qy][qx][c] += massX[qx] * wy;
}
}
}
osc += D1Dx * D1Dy;
} // loop (c) over components
// Apply D operator.
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const double O11 = op(0,qx,qy,e);
const double O12 = scalarCoeff ? 0.0 : op(i12,qx,qy,e);
const double O21 = scalarCoeff ? 0.0 : op(i21,qx,qy,e);
const double O22 = scalarCoeff ? O11 : op(3,qx,qy,e);
const double massX = mass[qy][qx][0];
const double massY = mass[qy][qx][1];
mass[qy][qx][0] = (O11*massX)+(O12*massY);
mass[qy][qx][1] = (O21*massX)+(O22*massY);
}
}
osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y test components
{
const int D1Dy = trialHcurl ? ((c == 1) ? D1Dtest : D1Dtest - 1) :
((c == 1) ? D1Dtest - 1 : D1Dtest);
const int D1Dx = trialHcurl ? ((c == 0) ? D1Dtest : D1Dtest - 1) :
((c == 0) ? D1Dtest - 1 : D1Dtest);
for (int qy = 0; qy < Q1D; ++qy)
{
double massX[HDIV_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0.0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] += mass[qy][qx][c] * (trialHcurl ?
((c == 0) ? Bct(dx,qx) : Bot(dx,qx)) :
((c == 0) ? Bot(dx,qx) : Bct(dx,qx)));
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
const double wy = trialHcurl ? ((c == 1) ? Bct(dy,qy) : Bot(dy,qy)) :
((c == 1) ? Bot(dy,qy) : Bct(dy,qy));
for (int dx = 0; dx < D1Dx; ++dx)
{
y(dx + (dy * D1Dx) + osc, e) += massX[dx] * wy;
}
}
}
osc += D1Dx * D1Dy;
} // loop c
}); // end of element loop
}
// Mass operator for H(curl) and H(div) functions, using Piola transformations
// u = dF^{-T} \hat{u} in H(curl), v = (1 / det dF) dF \hat{v} in H(div).
void PAHcurlHdivMassApply3D(const int D1D,
const int D1Dtest,
const int Q1D,
const int NE,
const bool scalarCoeff,
const bool trialHcurl,
const bool transpose,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_)
{
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
auto Bot = Reshape(Bot_.Read(), D1Dtest-1, Q1D);
auto Bct = Reshape(Bct_.Read(), D1Dtest, Q1D);
auto op = Reshape(op_.Read(), scalarCoeff ? 1 : 9, Q1D, Q1D, Q1D, NE);
auto x = Reshape(x_.Read(), 3*(D1D-1)*D1D*(trialHcurl ? D1D : D1D-1), NE);
auto y = Reshape(y_.ReadWrite(), 3*(D1Dtest-1)*D1Dtest*
(trialHcurl ? D1Dtest-1 : D1Dtest), NE);
const int i12 = transpose ? 3 : 1;
const int i13 = transpose ? 6 : 2;
const int i21 = transpose ? 1 : 3;
const int i23 = transpose ? 7 : 5;
const int i31 = transpose ? 2 : 6;
const int i32 = transpose ? 5 : 7;
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
double mass[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)
{
for (int c = 0; c < VDIM; ++c)
{
mass[qz][qy][qx][c] = 0.0;
}
}
}
}
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z trial components
{
const int D1Dz = trialHcurl ? ((c == 2) ? D1D - 1 : D1D) :
((c == 2) ? D1D : D1D - 1);
const int D1Dy = trialHcurl ? ((c == 1) ? D1D - 1 : D1D) :
((c == 1) ? D1D : D1D - 1);
const int D1Dx = trialHcurl ? ((c == 0) ? D1D - 1 : D1D) :
((c == 0) ? D1D : D1D - 1);
for (int dz = 0; dz < D1Dz; ++dz)
{
double massXY[MAX_Q1D][MAX_Q1D];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
massXY[qy][qx] = 0.0;
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
double massX[MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] = 0.0;
}
for (int dx = 0; dx < D1Dx; ++dx)
{
const double t = x(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] += t * (trialHcurl ? ((c == 0) ? Bo(qx,dx) : Bc(qx,dx)) :
((c == 0) ? Bc(qx,dx) : Bo(qx,dx)));
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = trialHcurl ? ((c == 1) ? Bo(qy,dy) : Bc(qy,dy)) :
((c == 1) ? Bc(qy,dy) : Bo(qy,dy));
for (int qx = 0; qx < Q1D; ++qx)
{
const double wx = massX[qx];
massXY[qy][qx] += wx * wy;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
const double wz = trialHcurl ? ((c == 2) ? Bo(qz,dz) : Bc(qz,dz)) :
((c == 2) ? Bc(qz,dz) : Bo(qz,dz));
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
mass[qz][qy][qx][c] += massXY[qy][qx] * wz;
}
}
}
}
osc += D1Dx * D1Dy * D1Dz;
} // loop (c) over components
// Apply D operator.
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const double O11 = op(0,qx,qy,qz,e);
const double O12 = scalarCoeff ? 0.0 : op(i12,qx,qy,qz,e);
const double O13 = scalarCoeff ? 0.0 : op(i13,qx,qy,qz,e);
const double O21 = scalarCoeff ? 0.0 : op(i21,qx,qy,qz,e);
const double O22 = scalarCoeff ? O11 : op(4,qx,qy,qz,e);
const double O23 = scalarCoeff ? 0.0 : op(i23,qx,qy,qz,e);
const double O31 = scalarCoeff ? 0.0 : op(i31,qx,qy,qz,e);
const double O32 = scalarCoeff ? 0.0 : op(i32,qx,qy,qz,e);
const double O33 = scalarCoeff ? O11 : op(8,qx,qy,qz,e);
const double massX = mass[qz][qy][qx][0];
const double massY = mass[qz][qy][qx][1];
const double massZ = mass[qz][qy][qx][2];
mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
mass[qz][qy][qx][1] = (O21*massX)+(O22*massY)+(O23*massZ);
mass[qz][qy][qx][2] = (O31*massX)+(O32*massY)+(O33*massZ);
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
double massXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z test components
{
const int D1Dz = trialHcurl ? ((c == 2) ? D1Dtest : D1Dtest - 1) :
((c == 2) ? D1Dtest - 1 : D1Dtest);
const int D1Dy = trialHcurl ? ((c == 1) ? D1Dtest : D1Dtest - 1) :
((c == 1) ? D1Dtest - 1 : D1Dtest);
const int D1Dx = trialHcurl ? ((c == 0) ? D1Dtest : D1Dtest - 1) :
((c == 0) ? D1Dtest - 1 : D1Dtest);
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] = 0.0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
double massX[HDIV_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0.0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] += mass[qz][qy][qx][c] * (trialHcurl ?
((c == 0) ? Bct(dx,qx) : Bot(dx,qx)) :
((c == 0) ? Bot(dx,qx) : Bct(dx,qx)));
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
const double wy = trialHcurl ? ((c == 1) ? Bct(dy,qy) : Bot(dy,qy)) :
((c == 1) ? Bot(dy,qy) : Bct(dy,qy));
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] += massX[dx] * wy;
}
}
}
for (int dz = 0; dz < D1Dz; ++dz)
{
const double wz = trialHcurl ? ((c == 2) ? Bct(dz,qz) : Bot(dz,qz)) :
((c == 2) ? Bot(dz,qz) : Bct(dz,qz));
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) +=
massXY[dy][dx] * wz;
}
}
}
osc += D1Dx * D1Dy * D1Dz;
} // loop c
} // loop qz
}); // end of element loop
}
} // namespace internal
} // namespace mfem
+818
View File
@@ -0,0 +1,818 @@
// Copyright (c) 2010-2023, 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_HCURLHDIV_KERNELS_HPP
#define MFEM_BILININTEG_HCURLHDIV_KERNELS_HPP
#include "../../config/config.hpp"
#include "../../general/array.hpp"
#include "../../general/forall.hpp"
#include "../../linalg/dtensor.hpp"
#include "../../linalg/vector.hpp"
#include "../bilininteg.hpp"
namespace mfem
{
namespace internal
{
// PA H(curl)-H(div) Mass Apply 2D kernel
void PAHcurlHdivMassSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const bool transpose,
const Array<double> &w_,
const Vector &j,
Vector &coeff_,
Vector &op);
// PA H(curl)-H(div) Mass Assemble 3D kernel
void PAHcurlHdivMassSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const bool transpose,
const Array<double> &w_,
const Vector &j,
Vector &coeff_,
Vector &op);
// PA H(curl)-H(div) Mass Apply 2D kernel
void PAHcurlHdivMassApply2D(const int D1D,
const int D1Dtest,
const int Q1D,
const int NE,
const bool scalarCoeff,
const bool trialHcurl,
const bool transpose,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_);
// PA H(curl)-H(div) Mass Apply 3D kernel
void PAHcurlHdivMassApply3D(const int D1D,
const int D1Dtest,
const int Q1D,
const int NE,
const bool scalarCoeff,
const bool trialHcurl,
const bool transpose,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &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,
const int d1dtest,
const int q1d,
const int NE,
const Array<double> &bo,
const Array<double> &bc,
const Array<double> &bot,
const Array<double> &bct,
const Array<double> &gc,
const Vector &pa_data,
const Vector &x,
Vector &y)
{
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_D1D_TEST ||
d1dtest <= HCURL_MAX_D1D, "Error: d1dtest > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int D1Dtest = T_D1D_TEST ? T_D1D_TEST : d1dtest;
const int Q1D = T_Q1D ? T_Q1D : q1d;
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(bc.Read(), Q1D, D1D);
auto Bot = Reshape(bot.Read(), D1Dtest-1, Q1D);
auto Bct = Reshape(bct.Read(), D1Dtest, Q1D);
auto Gc = Reshape(gc.Read(), Q1D, D1D);
auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, 6, NE);
auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
auto Y = Reshape(y.ReadWrite(), 3*(D1Dtest-1)*(D1Dtest-1)*D1Dtest, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
// Using Piola transformations (\nabla\times u) F = 1/det(dF) dF \hat{\nabla}\times\hat{u}
// for u in H(curl) and w = (1 / det (dF)) dF \hat{w} for w in H(div), we get
// (\nabla\times u) \cdot w = 1/det(dF)^2 \hat{\nabla}\times\hat{u}^T dF^T dF \hat{w}
// If c = 0, \hat{\nabla}\times\hat{u} reduces to [0, (u_0)_{x_2}, -(u_0)_{x_1}]
// If c = 1, \hat{\nabla}\times\hat{u} reduces to [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
// If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
constexpr int VDIM = 3;
constexpr int MD1D = T_D1D ? T_D1D :
HCURL_MAX_D1D; // Assuming HDIV_MAX_D1D <= HCURL_MAX_D1D
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int D1Dtest = T_D1D_TEST ? T_D1D_TEST : d1dtest;
const int Q1D = T_Q1D ? T_Q1D : q1d;
double curl[MQ1D][MQ1D][MQ1D][VDIM];
// curl[qz][qy][qx] will be computed as the vector curl at each quadrature point.
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
for (int c = 0; c < VDIM; ++c)
{
curl[qz][qy][qx][c] = 0.0;
}
}
}
}
// We treat x, y, z components separately for optimization specific to each.
int osc = 0;
{
// x component
const int D1Dz = D1D;
const int D1Dy = D1D;
const int D1Dx = D1D - 1;
for (int dz = 0; dz < D1Dz; ++dz)
{
double gradXY[MQ1D][MQ1D][2];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
for (int d = 0; d < 2; ++d)
{
gradXY[qy][qx][d] = 0.0;
}
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
double massX[MQ1D];
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] = 0.0;
}
for (int dx = 0; dx < D1Dx; ++dx)
{
const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] += t * Bo(qx,dx);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = Bc(qy,dy);
const double wDy = Gc(qy,dy);
for (int qx = 0; qx < Q1D; ++qx)
{
const double wx = massX[qx];
gradXY[qy][qx][0] += wx * wDy;
gradXY[qy][qx][1] += wx * wy;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
const double wz = Bc(qz,dz);
const double wDz = Gc(qz,dz);
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
// \hat{\nabla}\times\hat{u} is [0, (u_0)_{x_2}, -(u_0)_{x_1}]
curl[qz][qy][qx][1] += gradXY[qy][qx][1] * wDz; // (u_0)_{x_2}
curl[qz][qy][qx][2] -= gradXY[qy][qx][0] * wz; // -(u_0)_{x_1}
}
}
}
}
osc += D1Dx * D1Dy * D1Dz;
}
{
// y component
const int D1Dz = D1D;
const int D1Dy = D1D - 1;
const int D1Dx = D1D;
for (int dz = 0; dz < D1Dz; ++dz)
{
double gradXY[MQ1D][MQ1D][2];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
for (int d = 0; d < 2; ++d)
{
gradXY[qy][qx][d] = 0.0;
}
}
}
for (int dx = 0; dx < D1Dx; ++dx)
{
double massY[MQ1D];
for (int qy = 0; qy < Q1D; ++qy)
{
massY[qy] = 0.0;
}
for (int dy = 0; dy < D1Dy; ++dy)
{
const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
for (int qy = 0; qy < Q1D; ++qy)
{
massY[qy] += t * Bo(qy,dy);
}
}
for (int qx = 0; qx < Q1D; ++qx)
{
const double wx = Bc(qx,dx);
const double wDx = Gc(qx,dx);
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = massY[qy];
gradXY[qy][qx][0] += wDx * wy;
gradXY[qy][qx][1] += wx * wy;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
const double wz = Bc(qz,dz);
const double wDz = Gc(qz,dz);
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
// \hat{\nabla}\times\hat{u} is [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
curl[qz][qy][qx][0] -= gradXY[qy][qx][1] * wDz; // -(u_1)_{x_2}
curl[qz][qy][qx][2] += gradXY[qy][qx][0] * wz; // (u_1)_{x_0}
}
}
}
}
osc += D1Dx * D1Dy * D1Dz;
}
{
// z component
const int D1Dz = D1D - 1;
const int D1Dy = D1D;
const int D1Dx = D1D;
for (int dx = 0; dx < D1Dx; ++dx)
{
double gradYZ[MQ1D][MQ1D][2];
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int d = 0; d < 2; ++d)
{
gradYZ[qz][qy][d] = 0.0;
}
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
double massZ[MQ1D];
for (int qz = 0; qz < Q1D; ++qz)
{
massZ[qz] = 0.0;
}
for (int dz = 0; dz < D1Dz; ++dz)
{
const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
for (int qz = 0; qz < Q1D; ++qz)
{
massZ[qz] += t * Bo(qz,dz);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = Bc(qy,dy);
const double wDy = Gc(qy,dy);
for (int qz = 0; qz < Q1D; ++qz)
{
const double wz = massZ[qz];
gradYZ[qz][qy][0] += wz * wy;
gradYZ[qz][qy][1] += wz * wDy;
}
}
}
for (int qx = 0; qx < Q1D; ++qx)
{
const double wx = Bc(qx,dx);
const double wDx = Gc(qx,dx);
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qz = 0; qz < Q1D; ++qz)
{
// \hat{\nabla}\times\hat{u} is [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
curl[qz][qy][qx][0] += gradYZ[qz][qy][1] * wx; // (u_2)_{x_1}
curl[qz][qy][qx][1] -= gradYZ[qz][qy][0] * wDx; // -(u_2)_{x_0}
}
}
}
}
}
// Apply D operator.
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const double O11 = op(qx,qy,qz,0,e);
const double O12 = op(qx,qy,qz,1,e);
const double O13 = op(qx,qy,qz,2,e);
const double O22 = op(qx,qy,qz,3,e);
const double O23 = op(qx,qy,qz,4,e);
const double O33 = op(qx,qy,qz,5,e);
const double c1 = (O11 * curl[qz][qy][qx][0]) + (O12 * curl[qz][qy][qx][1]) +
(O13 * curl[qz][qy][qx][2]);
const double c2 = (O12 * curl[qz][qy][qx][0]) + (O22 * curl[qz][qy][qx][1]) +
(O23 * curl[qz][qy][qx][2]);
const double c3 = (O13 * curl[qz][qy][qx][0]) + (O23 * curl[qz][qy][qx][1]) +
(O33 * curl[qz][qy][qx][2]);
curl[qz][qy][qx][0] = c1;
curl[qz][qy][qx][1] = c2;
curl[qz][qy][qx][2] = c3;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
double massXY[MD1D][MD1D];
osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
{
const int D1Dz = (c == 2) ? D1Dtest : D1Dtest - 1;
const int D1Dy = (c == 1) ? D1Dtest : D1Dtest - 1;
const int D1Dx = (c == 0) ? D1Dtest : D1Dtest - 1;
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] = 0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
double massX[MD1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] += curl[qz][qy][qx][c] *
((c == 0) ? Bct(dx,qx) : Bot(dx,qx));
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
const double wy = (c == 1) ? Bct(dy,qy) : Bot(dy,qy);
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] += massX[dx] * wy;
}
}
}
for (int dz = 0; dz < D1Dz; ++dz)
{
const double wz = (c == 2) ? Bct(dz,qz) : Bot(dz,qz);
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) +=
massXY[dy][dx] * wz;
}
}
}
osc += D1Dx * D1Dy * D1Dz;
} // loop c
} // loop qz
}); // end of element loop
}
// PA H(curl)-H(div) Curl Apply Transpose 3D kernel
template<int T_D1D = 0, int T_D1D_TEST = 0, int T_Q1D = 0>
inline void PAHcurlHdivApplyTranspose3D(const int d1d,
const int d1dtest,
const int q1d,
const int NE,
const Array<double> &bo,
const Array<double> &bc,
const Array<double> &bot,
const Array<double> &bct,
const Array<double> &gct,
const Vector &pa_data,
const Vector &x,
Vector &y)
{
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_D1D_TEST ||
d1dtest <= HCURL_MAX_D1D, "Error: d1dtest > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int D1Dtest = T_D1D_TEST ? T_D1D_TEST : d1dtest;
const int Q1D = T_Q1D ? T_Q1D : q1d;
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(bc.Read(), Q1D, D1D);
auto Bot = Reshape(bot.Read(), D1Dtest-1, Q1D);
auto Bct = Reshape(bct.Read(), D1Dtest, Q1D);
auto Gct = Reshape(gct.Read(), D1D, Q1D);
auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, 6, NE);
auto X = Reshape(x.Read(), 3*(D1Dtest-1)*(D1Dtest-1)*D1Dtest, NE);
auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
// Using Piola transformations (\nabla\times u) F = 1/det(dF) dF \hat{\nabla}\times\hat{u}
// for u in H(curl) and w = (1 / det (dF)) dF \hat{w} for w in H(div), we get
// (\nabla\times u) \cdot w = 1/det(dF)^2 \hat{\nabla}\times\hat{u}^T dF^T dF \hat{w}
// If c = 0, \hat{\nabla}\times\hat{u} reduces to [0, (u_0)_{x_2}, -(u_0)_{x_1}]
// If c = 1, \hat{\nabla}\times\hat{u} reduces to [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
// If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
constexpr int VDIM = 3;
constexpr int MD1D = T_D1D ? T_D1D :
HCURL_MAX_D1D; // Assuming HDIV_MAX_D1D <= HCURL_MAX_D1D
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int D1Dtest = T_D1D_TEST ? T_D1D_TEST : d1dtest;
const int Q1D = T_Q1D ? T_Q1D : q1d;
double mass[MQ1D][MQ1D][MQ1D][VDIM];
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
for (int c = 0; c < VDIM; ++c)
{
mass[qz][qy][qx][c] = 0.0;
}
}
}
}
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
{
const int D1Dz = (c == 2) ? D1Dtest : D1Dtest - 1;
const int D1Dy = (c == 1) ? D1Dtest : D1Dtest - 1;
const int D1Dx = (c == 0) ? D1Dtest : D1Dtest - 1;
for (int dz = 0; dz < D1Dz; ++dz)
{
double massXY[MQ1D][MQ1D];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
massXY[qy][qx] = 0.0;
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
double massX[MQ1D];
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] = 0.0;
}
for (int dx = 0; dx < D1Dx; ++dx)
{
const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] += t * ((c == 0) ? Bc(qx,dx) : Bo(qx,dx));
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = (c == 1) ? Bc(qy,dy) : Bo(qy,dy);
for (int qx = 0; qx < Q1D; ++qx)
{
const double wx = massX[qx];
massXY[qy][qx] += wx * wy;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
const double wz = (c == 2) ? Bc(qz,dz) : Bo(qz,dz);
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
mass[qz][qy][qx][c] += massXY[qy][qx] * wz;
}
}
}
}
osc += D1Dx * D1Dy * D1Dz;
} // loop (c) over components
// Apply D operator.
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const double O11 = op(qx,qy,qz,0,e);
const double O12 = op(qx,qy,qz,1,e);
const double O13 = op(qx,qy,qz,2,e);
const double O22 = op(qx,qy,qz,3,e);
const double O23 = op(qx,qy,qz,4,e);
const double O33 = op(qx,qy,qz,5,e);
const double massX = mass[qz][qy][qx][0];
const double massY = mass[qz][qy][qx][1];
const double massZ = mass[qz][qy][qx][2];
mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
mass[qz][qy][qx][1] = (O12*massX)+(O22*massY)+(O23*massZ);
mass[qz][qy][qx][2] = (O13*massX)+(O23*massY)+(O33*massZ);
}
}
}
// x component
osc = 0;
{
const int D1Dz = D1D;
const int D1Dy = D1D;
const int D1Dx = D1D - 1;
for (int qz = 0; qz < Q1D; ++qz)
{
double gradXY12[MD1D][MD1D];
double gradXY21[MD1D][MD1D];
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
gradXY12[dy][dx] = 0.0;
gradXY21[dy][dx] = 0.0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
double massX[MD1D][2];
for (int dx = 0; dx < D1Dx; ++dx)
{
for (int n = 0; n < 2; ++n)
{
massX[dx][n] = 0.0;
}
}
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
const double wx = Bot(dx,qx);
massX[dx][0] += wx * mass[qz][qy][qx][1];
massX[dx][1] += wx * mass[qz][qy][qx][2];
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
const double wy = Bct(dy,qy);
const double wDy = Gct(dy,qy);
for (int dx = 0; dx < D1Dx; ++dx)
{
gradXY21[dy][dx] += massX[dx][0] * wy;
gradXY12[dy][dx] += massX[dx][1] * wDy;
}
}
}
for (int dz = 0; dz < D1Dz; ++dz)
{
const double wz = Bct(dz,qz);
const double wDz = Gct(dz,qz);
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
// \hat{\nabla}\times\hat{u} is [0, (u_0)_{x_2}, -(u_0)_{x_1}]
// (u_0)_{x_2} * (op * curl)_1 - (u_0)_{x_1} * (op * curl)_2
Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc,
e) += (gradXY21[dy][dx] * wDz) - (gradXY12[dy][dx] * wz);
}
}
}
} // loop qz
osc += D1Dx * D1Dy * D1Dz;
}
// y component
{
const int D1Dz = D1D;
const int D1Dy = D1D - 1;
const int D1Dx = D1D;
for (int qz = 0; qz < Q1D; ++qz)
{
double gradXY02[MD1D][MD1D];
double gradXY20[MD1D][MD1D];
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
gradXY02[dy][dx] = 0.0;
gradXY20[dy][dx] = 0.0;
}
}
for (int qx = 0; qx < Q1D; ++qx)
{
double massY[MD1D][2];
for (int dy = 0; dy < D1Dy; ++dy)
{
massY[dy][0] = 0.0;
massY[dy][1] = 0.0;
}
for (int qy = 0; qy < Q1D; ++qy)
{
for (int dy = 0; dy < D1Dy; ++dy)
{
const double wy = Bot(dy,qy);
massY[dy][0] += wy * mass[qz][qy][qx][2];
massY[dy][1] += wy * mass[qz][qy][qx][0];
}
}
for (int dx = 0; dx < D1Dx; ++dx)
{
const double wx = Bct(dx,qx);
const double wDx = Gct(dx,qx);
for (int dy = 0; dy < D1Dy; ++dy)
{
gradXY02[dy][dx] += massY[dy][0] * wDx;
gradXY20[dy][dx] += massY[dy][1] * wx;
}
}
}
for (int dz = 0; dz < D1Dz; ++dz)
{
const double wz = Bct(dz,qz);
const double wDz = Gct(dz,qz);
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
// \hat{\nabla}\times\hat{u} is [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
// -(u_1)_{x_2} * (op * curl)_0 + (u_1)_{x_0} * (op * curl)_2
Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc,
e) += (-gradXY20[dy][dx] * wDz) + (gradXY02[dy][dx] * wz);
}
}
}
} // loop qz
osc += D1Dx * D1Dy * D1Dz;
}
// z component
{
const int D1Dz = D1D - 1;
const int D1Dy = D1D;
const int D1Dx = D1D;
for (int qx = 0; qx < Q1D; ++qx)
{
double gradYZ01[MD1D][MD1D];
double gradYZ10[MD1D][MD1D];
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dz = 0; dz < D1Dz; ++dz)
{
gradYZ01[dz][dy] = 0.0;
gradYZ10[dz][dy] = 0.0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
double massZ[MD1D][2];
for (int dz = 0; dz < D1Dz; ++dz)
{
for (int n = 0; n < 2; ++n)
{
massZ[dz][n] = 0.0;
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
for (int dz = 0; dz < D1Dz; ++dz)
{
const double wz = Bot(dz,qz);
massZ[dz][0] += wz * mass[qz][qy][qx][0];
massZ[dz][1] += wz * mass[qz][qy][qx][1];
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
const double wy = Bct(dy,qy);
const double wDy = Gct(dy,qy);
for (int dz = 0; dz < D1Dz; ++dz)
{
gradYZ01[dz][dy] += wy * massZ[dz][1];
gradYZ10[dz][dy] += wDy * massZ[dz][0];
}
}
}
for (int dx = 0; dx < D1Dx; ++dx)
{
const double wx = Bct(dx,qx);
const double wDx = Gct(dx,qx);
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dz = 0; dz < D1Dz; ++dz)
{
// \hat{\nabla}\times\hat{u} is [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
// (u_2)_{x_1} * (op * curl)_0 - (u_2)_{x_0} * (op * curl)_1
Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc,
e) += (gradYZ10[dz][dy] * wx) - (gradYZ01[dz][dy] * wDx);
}
}
}
} // loop qx
}
}); // end of element loop
}
} // namespace internal
} // namespace mfem
#endif
File diff suppressed because it is too large Load Diff
+715
View File
@@ -0,0 +1,715 @@
// Copyright (c) 2010-2023, 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_HDIV_KERNELS_HPP
#define MFEM_BILININTEG_HDIV_KERNELS_HPP
#include "../../config/config.hpp"
#include "../../general/array.hpp"
#include "../../general/forall.hpp"
#include "../../linalg/dtensor.hpp"
#include "../../linalg/vector.hpp"
#include "../bilininteg.hpp"
// Piola transformation in H(div): w = (1 / det (dF)) dF \hat{w}
// div w = (1 / det (dF)) \hat{div} \hat{w}
namespace mfem
{
namespace internal
{
// PA H(div) Mass Assemble 2D kernel
void PAHdivMassSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff_,
Vector &op);
// PA H(div) Mass Assemble 3D kernel
void PAHdivMassSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff_,
Vector &op);
// PA H(div) Mass Diagonal 2D kernel
void PAHdivMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Vector &op_,
Vector &diag_);
// PA H(div) Mass Diagonal 3D kernel
void PAHdivMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Vector &op_,
Vector &diag_);
void PAHdivMassApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo,
const Array<double> &Bc,
const Array<double> &Bot,
const Array<double> &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<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_);
// PA H(div) Mass Apply 3D kernel
void PAHdivMassApply3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_);
// 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<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_CONTRACT_VAR(Bot_);
MFEM_CONTRACT_VAR(Bct_);
static constexpr int VDIM = 2;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const auto bo = Reshape(Bo_.Read(), Q1D, D1D-1);
const auto bc = Reshape(Bc_.Read(), Q1D, D1D);
const auto D = Reshape(op_.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
const auto x = Reshape(x_.Read(), D1D*(D1D-1), VDIM, NE);
auto y = y_.ReadWrite();
mfem::forall_3D(NE, Q1D, Q1D, VDIM, [=] 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 MQ1 = T_Q1D ? T_Q1D : HDIV_MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : HDIV_MAX_D1D;
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
MFEM_SHARED double smo[MQ1*(MD1-1)];
DeviceMatrix Bo(smo, D1D-1, Q1D);
MFEM_SHARED double smc[MQ1*MD1];
DeviceMatrix Bc(smc, D1D, Q1D);
MFEM_SHARED double sm0[VDIM*MDQ*MDQ];
MFEM_SHARED double sm1[VDIM*MDQ*MDQ];
DeviceMatrix X(sm0, D1D*(D1D-1), VDIM);
DeviceCube QD(sm1, Q1D, D1D, VDIM);
DeviceCube QQ(sm0, Q1D, Q1D, VDIM);
// Load X, Bo and Bc into shared memory
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
if (qx < D1D && dy < (D1D-1)) { X(qx + dy*D1D,vd) = x(qx+dy*D1D,vd,e); }
if (tidz == 0)
{
if (dy < (D1D-1)) { Bo(dy,qx) = bo(qx,dy); }
Bc(dy,qx) = bc(qx,dy);
}
}
}
}
MFEM_SYNC_THREAD;
// Apply B operator
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
const int ny = (vd == 1) ? D1D : D1D-1;
DeviceCube Xxy(X, nx, ny, VDIM);
DeviceMatrix Bx = (vd == 0) ? Bc : Bo;
MFEM_FOREACH_THREAD(dy,y,ny)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double dq = 0.0;
for (int dx = 0; dx < nx; ++dx)
{
dq += Xxy(dx,dy,vd) * Bx(dx,qx);
}
QD(qx,dy,vd) = dq;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int ny = (vd == 1) ? D1D : D1D-1;
DeviceMatrix By = (vd == 1) ? Bc : Bo;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double qq = 0.0;
for (int dy = 0; dy < ny; ++dy)
{
qq += QD(qx,dy,vd) * By(dy,qy);
}
QQ(qx,qy,vd) = qq;
}
}
}
MFEM_SYNC_THREAD;
// Apply D operator
if (tidz == 0)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const double Qx = QQ(qx,qy,0);
const double Qy = QQ(qx,qy,1);
const double D11 = D(qx,qy,0,e);
const double D12 = D(qx,qy,1,e);
const double D21 = symmetric ? D12 : D(qx,qy,2,e);
const double D22 = symmetric ? D(qx,qy,2,e) : D(qx,qy,3,e);
QQ(qx,qy,0) = D11*Qx + D12*Qy;
QQ(qx,qy,1) = D21*Qx + D22*Qy;
}
}
}
MFEM_SYNC_THREAD;
// Apply Bt operator
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
DeviceMatrix Btx = (vd == 0) ? Bc : Bo;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,nx)
{
double qd = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
qd += QQ(qx,qy,vd) * Btx(dx,qx);
}
QD(dx,qy,vd) = qd;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
const int ny = (vd == 1) ? D1D : D1D-1;
DeviceMatrix Bty = (vd == 1) ? Bc : Bo;
DeviceTensor<4> Yxy(y, nx, ny, VDIM, NE);
MFEM_FOREACH_THREAD(dy,y,ny)
{
MFEM_FOREACH_THREAD(dx,x,nx)
{
double dd = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
dd += QD(dx,qy,vd) * Bty(dy,qy);
}
Yxy(dx,dy,vd,e) += dd;
}
}
}
MFEM_SYNC_THREAD;
});
}
// 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<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_CONTRACT_VAR(Bot_);
MFEM_CONTRACT_VAR(Bct_);
static constexpr int VDIM = 3;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const auto bo = Reshape(Bo_.Read(), Q1D, D1D-1);
const auto bc = Reshape(Bc_.Read(), Q1D, D1D);
const auto D = Reshape(op_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
const auto x = Reshape(x_.Read(), D1D*(D1D-1)*(D1D-1), VDIM, NE);
auto y = y_.ReadWrite();
mfem::forall_3D(NE, Q1D, Q1D, VDIM, [=] 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 MQ1 = T_Q1D ? T_Q1D : HDIV_MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : HDIV_MAX_D1D;
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
MFEM_SHARED double smo[MQ1*(MD1-1)];
DeviceMatrix Bo(smo, D1D-1, Q1D);
MFEM_SHARED double smc[MQ1*MD1];
DeviceMatrix Bc(smc, D1D, Q1D);
MFEM_SHARED double sm0[VDIM*MDQ*MDQ*MDQ];
MFEM_SHARED double sm1[VDIM*MDQ*MDQ*MDQ];
DeviceMatrix X(sm0, D1D*(D1D-1)*(D1D-1), VDIM);
DeviceTensor<4> QDD(sm1, Q1D, D1D, D1D, VDIM);
DeviceTensor<4> QQD(sm0, Q1D, Q1D, D1D, VDIM);
DeviceTensor<4> QQQ(sm1, Q1D, Q1D, Q1D, VDIM);
DeviceTensor<4> DQQ(sm0, D1D, Q1D, Q1D, VDIM);
DeviceTensor<4> DDQ(sm1, D1D, D1D, Q1D, VDIM);
// Load X into shared memory
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
MFEM_FOREACH_THREAD(dz,y,D1D-1)
{
MFEM_FOREACH_THREAD(dy,x,D1D-1)
{
MFEM_UNROLL(MD1)
for (int dx = 0; dx < D1D; ++dx)
{
X(dx+(dy+dz*(D1D-1))*D1D,vd) = x(dx+(dy+dz*(D1D-1))*D1D,vd,e);
}
}
}
}
// Load Bo and Bc into shared memory
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D-1)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
Bo(d,q) = bo(q,d);
}
}
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
Bc(d,q) = bc(q,d);
}
}
}
MFEM_SYNC_THREAD;
// Apply B operator
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
const int ny = (vd == 1) ? D1D : D1D-1;
const int nz = (vd == 2) ? D1D : D1D-1;
DeviceTensor<4> Xxyz(X, nx, ny, nz, VDIM);
DeviceMatrix Bx = (vd == 0) ? Bc : Bo;
MFEM_FOREACH_THREAD(dy,y,ny)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { u[dz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dx = 0; dx < nx; ++dx)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz)
{
u[dz] += Xxyz(dx,dy,dz,vd) * Bx(dx,qx);
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { QDD(qx,dy,dz,vd) = u[dz]; }
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int ny = (vd == 1) ? D1D : D1D-1;
const int nz = (vd == 2) ? D1D : D1D-1;
DeviceMatrix By = (vd == 1) ? Bc : Bo;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { u[dz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dy = 0; dy < ny; ++dy)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz)
{
u[dz] += QDD(qx,dy,dz,vd) * By(dy,qy);
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { QQD(qx,qy,dz,vd) = u[dz]; }
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nz = (vd == 2) ? D1D : D1D-1;
DeviceMatrix Bz = (vd == 2) ? Bc : Bo;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += QQD(qx,qy,dz,vd) * Bz(dz,qz);
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { QQQ(qx,qy,qz,vd) = u[qz]; }
}
}
}
MFEM_SYNC_THREAD;
// Apply D operator
if (tidz == 0)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
const double Qx = QQQ(qx,qy,qz,0);
const double Qy = QQQ(qx,qy,qz,1);
const double Qz = QQQ(qx,qy,qz,2);
const double D11 = D(qx,qy,qz,0,e);
const double D12 = D(qx,qy,qz,1,e);
const double D13 = D(qx,qy,qz,2,e);
const double D21 = symmetric ? D12 : D(qx,qy,qz,3,e);
const double D22 = symmetric ? D(qx,qy,qz,3,e) : D(qx,qy,qz,4,e);
const double D23 = symmetric ? D(qx,qy,qz,4,e) : D(qx,qy,qz,5,e);
const double D31 = symmetric ? D13 : D(qx,qy,qz,6,e);
const double D32 = symmetric ? D23 : D(qx,qy,qz,7,e);
const double D33 = symmetric ? D(qx,qy,qz,5,e) : D(qx,qy,qz,8,e);
QQQ(qx,qy,qz,0) = D11*Qx + D12*Qy + D13*Qz;
QQQ(qx,qy,qz,1) = D21*Qx + D22*Qy + D23*Qz;
QQQ(qx,qy,qz,2) = D31*Qx + D32*Qy + D33*Qz;
}
}
}
}
MFEM_SYNC_THREAD;
// Apply Bt operator
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
DeviceMatrix Btx = (vd == 0) ? Bc : Bo;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,nx)
{
double u[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qx = 0; qx < Q1D; ++qx)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += QQQ(qx,qy,qz,vd) * Btx(dx,qx);
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { DQQ(dx,qy,qz,vd) = u[qz]; }
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
const int ny = (vd == 1) ? D1D : D1D-1;
DeviceMatrix Bty = (vd == 1) ? Bc : Bo;
MFEM_FOREACH_THREAD(dy,y,ny)
{
MFEM_FOREACH_THREAD(dx,x,nx)
{
double u[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qy = 0; qy < Q1D; ++qy)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += DQQ(dx,qy,qz,vd) * Bty(dy,qy);
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { DDQ(dx,dy,qz,vd) = u[qz]; }
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
const int ny = (vd == 1) ? D1D : D1D-1;
const int nz = (vd == 2) ? D1D : D1D-1;
DeviceTensor<5> Yxyz(y, nx, ny, nz, VDIM, NE);
DeviceMatrix Btz = (vd == 2) ? Bc : Bo;
MFEM_FOREACH_THREAD(dy,y,ny)
{
MFEM_FOREACH_THREAD(dx,x,nx)
{
double u[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { u[dz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz)
{
u[dz] += DDQ(dx,dy,qz,vd) * Btz(dz,qz);
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { Yxyz(dx,dy,dz,vd,e) += u[dz]; }
}
}
}
MFEM_SYNC_THREAD;
});
}
// PA H(div) div-div Assemble 2D kernel
void PADivDivSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff_,
Vector &op);
// PA H(div) div-div Assemble 3D kernel
void PADivDivSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff_,
Vector &op);
// PA H(div) div-div Diagonal 2D kernel
void PADivDivAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &Bo_,
const Array<double> &Gc_,
const Vector &op_,
Vector &diag_);
// PA H(div) div-div Diagonal 3D kernel
void PADivDivAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &Bo_,
const Array<double> &Gc_,
const Vector &op_,
Vector &diag_);
// PA H(div) div-div Apply 2D kernel
void PADivDivApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &Bo_,
const Array<double> &Gc_,
const Array<double> &Bot_,
const Array<double> &Gct_,
const Vector &op_,
const Vector &x_,
Vector &y_);
// PA H(div) div-div Apply 3D kernel
void PADivDivApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &Bo_,
const Array<double> &Gc_,
const Array<double> &Bot_,
const Array<double> &Gct_,
const Vector &op_,
const Vector &x_,
Vector &y_);
// PA H(div)-L2 Assemble 2D kernel
void PAHdivL2Setup2D(const int Q1D,
const int NE,
const Array<double> &w,
Vector &coeff_,
Vector &op);
// PA H(div)-L2 Assemble 3D kernel
void PAHdivL2Setup3D(const int Q1D,
const int NE,
const Array<double> &w,
Vector &coeff_,
Vector &op);
// PA H(div)-L2 Diagonal 2D kernel
void PAHdivL2AssembleDiagonal_ADAt_2D(const int D1D,
const int Q1D,
const int L2D1D,
const int NE,
const Array<double> &L2Bo_,
const Array<double> &Gct_,
const Array<double> &Bot_,
const Vector &op_,
const Vector &D_,
Vector &diag_);
// PA H(div)-L2 Diagonal 3D kernel
void PAHdivL2AssembleDiagonal_ADAt_3D(const int D1D,
const int Q1D,
const int L2D1D,
const int NE,
const Array<double> &L2Bo_,
const Array<double> &Gct_,
const Array<double> &Bot_,
const Vector &op_,
const Vector &D_,
Vector &diag_);
// PA H(div)-L2 Apply 2D kernel
void PAHdivL2Apply2D(const int D1D,
const int Q1D,
const int L2D1D,
const int NE,
const Array<double> &Bo_,
const Array<double> &Gc_,
const Array<double> &L2Bot_,
const Vector &op_,
const Vector &x_,
Vector &y_);
// PA H(div)-L2 Apply Transpose 2D kernel
void PAHdivL2ApplyTranspose2D(const int D1D,
const int Q1D,
const int L2D1D,
const int NE,
const Array<double> &L2Bo_,
const Array<double> &Gct_,
const Array<double> &Bot_,
const Vector &op_,
const Vector &x_,
Vector &y_);
// PA H(div)-L2 Apply 3D kernel
void PAHdivL2Apply3D(const int D1D,
const int Q1D,
const int L2D1D,
const int NE,
const Array<double> &Bo_,
const Array<double> &Gc_,
const Array<double> &L2Bot_,
const Vector &op_,
const Vector &x_,
Vector &y_);
// PA H(div)-L2 Apply Transpose 3D kernel
void PAHdivL2ApplyTranspose3D(const int D1D,
const int Q1D,
const int L2D1D,
const int NE,
const Array<double> &L2Bo_,
const Array<double> &Gct_,
const Array<double> &Bot_,
const Vector &op_,
const Vector &x_,
Vector &y_);
} // namespace internal
} // namespace mfem
#endif
File diff suppressed because it is too large Load Diff
@@ -9,9 +9,9 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
namespace mfem
{
@@ -32,7 +32,7 @@ static void EAMassAssemble1D(const int NE,
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto M = Reshape(eadata.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
mfem::forall_2D(NE, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -82,7 +82,7 @@ static void EAMassAssemble2D(const int NE,
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, NE);
auto M = Reshape(eadata.ReadWrite(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
mfem::forall_2D(NE, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -154,20 +154,51 @@ static void EAMassAssemble3D(const int NE,
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, NE);
auto M = Reshape(eadata.ReadWrite(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
mfem::forall_3D(NE, D1D, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
constexpr int DQ = T_D1D * T_Q1D;
// For quadratic and lower it's better to use registers but for higher-order you start to
// spill and it's better to use shared memory
constexpr bool USE_REG = DQ != 0 && DQ <= 12;
constexpr int MD1r = USE_REG ? MD1 : 1;
constexpr int MQ1r = USE_REG ? MQ1 : 1;
constexpr int MD1s = USE_REG ? 1 : MD1;
constexpr int MQ1s = USE_REG ? 1 : MQ1;
MFEM_SHARED double s_B[MQ1s][MD1s];
double r_B[MQ1r][MD1r];
double (*l_B)[MD1] = nullptr;
if (USE_REG)
{
for (int q = 0; q < Q1D; q++)
for (int d = 0; d < D1D; d++)
{
r_B[q][d] = B(q,d);
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
l_B = (double (*)[MD1])r_B;
}
else
{
if (MFEM_THREAD_ID(z) == 0)
{
MFEM_FOREACH_THREAD(d,x,D1D)
{
MFEM_FOREACH_THREAD(q,y,Q1D)
{
s_B[q][d] = B(q,d);
}
}
}
l_B = (double (*)[MD1])s_B;
}
MFEM_SHARED double s_D[MQ1][MQ1][MQ1];
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
@@ -199,9 +230,9 @@ static void EAMassAssemble3D(const int NE,
{
for (int k3 = 0; k3 < Q1D; ++k3)
{
val += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* r_B[k3][i3] * r_B[k3][j3]
val += l_B[k1][i1] * l_B[k1][j1]
* l_B[k2][i2] * l_B[k2][j2]
* l_B[k3][i3] * l_B[k3][j3]
* s_D[k1][k2][k3];
}
}
+333
View File
@@ -0,0 +1,333 @@
// Copyright (c) 2010-2023, 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 "bilininteg_mass_kernels.hpp"
namespace mfem
{
namespace internal
{
// PA Mass Diagonal 1D kernel
static void PAMassAssembleDiagonal1D(const int NE,
const Array<double> &b,
const Vector &d,
Vector &y,
const int D1D,
const int Q1D)
{
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto D = Reshape(d.Read(), Q1D, NE);
auto Y = Reshape(y.ReadWrite(), D1D, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
for (int dx = 0; dx < D1D; ++dx)
{
Y(dx, e) = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
Y(dx, e) += B(qx, dx) * B(qx, dx) * D(qx, e);
}
}
});
}
void PAMassAssembleDiagonal(const int dim, const int D1D,
const int Q1D, const int NE,
const Array<double> &B,
const Vector &D,
Vector &Y)
{
if (dim == 1)
{
return PAMassAssembleDiagonal1D(NE,B,D,Y,D1D,Q1D);
}
else if (dim == 2)
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPAMassAssembleDiagonal2D<2,2,16>(NE,B,D,Y);
case 0x33: return SmemPAMassAssembleDiagonal2D<3,3,16>(NE,B,D,Y);
case 0x44: return SmemPAMassAssembleDiagonal2D<4,4,8>(NE,B,D,Y);
case 0x55: return SmemPAMassAssembleDiagonal2D<5,5,8>(NE,B,D,Y);
case 0x66: return SmemPAMassAssembleDiagonal2D<6,6,4>(NE,B,D,Y);
case 0x77: return SmemPAMassAssembleDiagonal2D<7,7,4>(NE,B,D,Y);
case 0x88: return SmemPAMassAssembleDiagonal2D<8,8,2>(NE,B,D,Y);
case 0x99: return SmemPAMassAssembleDiagonal2D<9,9,2>(NE,B,D,Y);
default: return PAMassAssembleDiagonal2D(NE,B,D,Y,D1D,Q1D);
}
}
else if (dim == 3)
{
switch ((D1D << 4 ) | Q1D)
{
case 0x23: return SmemPAMassAssembleDiagonal3D<2,3>(NE,B,D,Y);
case 0x24: return SmemPAMassAssembleDiagonal3D<2,4>(NE,B,D,Y);
case 0x26: return SmemPAMassAssembleDiagonal3D<2,6>(NE,B,D,Y);
case 0x34: return SmemPAMassAssembleDiagonal3D<3,4>(NE,B,D,Y);
case 0x35: return SmemPAMassAssembleDiagonal3D<3,5>(NE,B,D,Y);
case 0x45: return SmemPAMassAssembleDiagonal3D<4,5>(NE,B,D,Y);
case 0x48: return SmemPAMassAssembleDiagonal3D<4,8>(NE,B,D,Y);
case 0x56: return SmemPAMassAssembleDiagonal3D<5,6>(NE,B,D,Y);
case 0x67: return SmemPAMassAssembleDiagonal3D<6,7>(NE,B,D,Y);
case 0x78: return SmemPAMassAssembleDiagonal3D<7,8>(NE,B,D,Y);
case 0x89: return SmemPAMassAssembleDiagonal3D<8,9>(NE,B,D,Y);
default: return PAMassAssembleDiagonal3D(NE,B,D,Y,D1D,Q1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
#ifdef MFEM_USE_OCCA
void OccaPAMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &Bt,
const Vector &D,
const Vector &X,
Vector &Y)
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
const occa::memory o_D = OccaMemoryRead(D.GetMemory(), D.Size());
const occa::memory o_X = OccaMemoryRead(X.GetMemory(), X.Size());
occa::memory o_Y = OccaMemoryReadWrite(Y.GetMemory(), Y.Size());
const occa_id_t id = std::make_pair(D1D,Q1D);
if (!Device::Allows(Backend::OCCA_CUDA))
{
static occa_kernel_t OccaMassApply2D_cpu;
if (OccaMassApply2D_cpu.find(id) == OccaMassApply2D_cpu.end())
{
const occa::kernel MassApply2D_CPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"MassApply2D_CPU", props);
OccaMassApply2D_cpu.emplace(id, MassApply2D_CPU);
}
OccaMassApply2D_cpu.at(id)(NE, o_B, o_Bt, o_D, o_X, o_Y);
}
else
{
static occa_kernel_t OccaMassApply2D_gpu;
if (OccaMassApply2D_gpu.find(id) == OccaMassApply2D_gpu.end())
{
const occa::kernel MassApply2D_GPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"MassApply2D_GPU", props);
OccaMassApply2D_gpu.emplace(id, MassApply2D_GPU);
}
OccaMassApply2D_gpu.at(id)(NE, o_B, o_Bt, o_D, o_X, o_Y);
}
}
void OccaPAMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &Bt,
const Vector &D,
const Vector &X,
Vector &Y)
{
occa::properties props;
props["defines/D1D"] = D1D;
props["defines/Q1D"] = Q1D;
const occa::memory o_B = OccaMemoryRead(B.GetMemory(), B.Size());
const occa::memory o_Bt = OccaMemoryRead(Bt.GetMemory(), Bt.Size());
const occa::memory o_D = OccaMemoryRead(D.GetMemory(), D.Size());
const occa::memory o_X = OccaMemoryRead(X.GetMemory(), X.Size());
occa::memory o_Y = OccaMemoryReadWrite(Y.GetMemory(), Y.Size());
const occa_id_t id = std::make_pair(D1D,Q1D);
if (!Device::Allows(Backend::OCCA_CUDA))
{
static occa_kernel_t OccaMassApply3D_cpu;
if (OccaMassApply3D_cpu.find(id) == OccaMassApply3D_cpu.end())
{
const occa::kernel MassApply3D_CPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"MassApply3D_CPU", props);
OccaMassApply3D_cpu.emplace(id, MassApply3D_CPU);
}
OccaMassApply3D_cpu.at(id)(NE, o_B, o_Bt, o_D, o_X, o_Y);
}
else
{
static occa_kernel_t OccaMassApply3D_gpu;
if (OccaMassApply3D_gpu.find(id) == OccaMassApply3D_gpu.end())
{
const occa::kernel MassApply3D_GPU =
mfem::OccaDev().buildKernel("occa://mfem/fem/occa.okl",
"MassApply3D_GPU", props);
OccaMassApply3D_gpu.emplace(id, MassApply3D_GPU);
}
OccaMassApply3D_gpu.at(id)(NE, o_B, o_Bt, o_D, o_X, o_Y);
}
}
#endif // MFEM_USE_OCCA
MFEM_HOST_DEVICE inline
void PAMassApply1D_Element(const int e,
const int NE,
const double *b_,
const double *bt_,
const double *d_,
const double *x_,
double *y_,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = d1d;
const int Q1D = q1d;
auto B = ConstDeviceMatrix(b_, Q1D, D1D);
auto Bt = ConstDeviceMatrix(bt_, D1D, Q1D);
auto D = ConstDeviceMatrix(d_, Q1D, NE);
auto X = ConstDeviceMatrix(x_, D1D, NE);
auto Y = DeviceMatrix(y_, D1D, NE);
constexpr int max_Q1D = MAX_Q1D;
double XQ[max_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
XQ[qx] = 0.0;
}
for (int dx = 0; dx < D1D; ++dx)
{
const double s = X(dx,e);
for (int qx = 0; qx < Q1D; ++qx)
{
XQ[qx] += B(qx,dx)*s;
}
}
for (int qx = 0; qx < Q1D; ++qx)
{
const double q = XQ[qx]*D(qx,e);
for (int dx = 0; dx < D1D; ++dx)
{
Y(dx,e) += Bt(dx,qx) * q;
}
}
}
// PA Mass Apply 1D kernel
static void PAMassApply1D(const int NE,
const Array<double> &b_,
const Array<double> &bt_,
const Vector &d_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_VERIFY(d1d <= MAX_D1D, "");
MFEM_VERIFY(q1d <= MAX_Q1D, "");
const auto B = b_.Read();
const auto Bt = bt_.Read();
const auto D = d_.Read();
const auto X = x_.Read();
auto Y = y_.ReadWrite();
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
internal::PAMassApply1D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
});
}
void PAMassApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &Bt,
const Vector &D,
const Vector &X,
Vector &Y)
{
#ifdef MFEM_USE_OCCA
if (DeviceCanUseOcca())
{
if (dim == 2)
{
return OccaPAMassApply2D(D1D,Q1D,NE,B,Bt,D,X,Y);
}
if (dim == 3)
{
return OccaPAMassApply3D(D1D,Q1D,NE,B,Bt,D,X,Y);
}
MFEM_ABORT("OCCA PA Mass Apply unknown kernel!");
}
#endif // MFEM_USE_OCCA
const int id = (D1D << 4) | Q1D;
if (dim == 1)
{
return PAMassApply1D(NE,B,Bt,D,X,Y,D1D,Q1D);
}
else if (dim == 2)
{
switch (id)
{
case 0x22: return SmemPAMassApply2D<2,2,16>(NE,B,Bt,D,X,Y);
case 0x24: return SmemPAMassApply2D<2,4,16>(NE,B,Bt,D,X,Y);
case 0x33: return SmemPAMassApply2D<3,3,16>(NE,B,Bt,D,X,Y);
case 0x34: return SmemPAMassApply2D<3,4,16>(NE,B,Bt,D,X,Y);
case 0x35: return SmemPAMassApply2D<3,5,16>(NE,B,Bt,D,X,Y);
case 0x36: return SmemPAMassApply2D<3,6,16>(NE,B,Bt,D,X,Y);
case 0x44: return SmemPAMassApply2D<4,4,8>(NE,B,Bt,D,X,Y);
case 0x46: return SmemPAMassApply2D<4,6,8>(NE,B,Bt,D,X,Y);
case 0x48: return SmemPAMassApply2D<4,8,4>(NE,B,Bt,D,X,Y);
case 0x55: return SmemPAMassApply2D<5,5,8>(NE,B,Bt,D,X,Y);
case 0x57: return SmemPAMassApply2D<5,7,8>(NE,B,Bt,D,X,Y);
case 0x58: return SmemPAMassApply2D<5,8,2>(NE,B,Bt,D,X,Y);
case 0x66: return SmemPAMassApply2D<6,6,4>(NE,B,Bt,D,X,Y);
case 0x77: return SmemPAMassApply2D<7,7,4>(NE,B,Bt,D,X,Y);
case 0x88: return SmemPAMassApply2D<8,8,2>(NE,B,Bt,D,X,Y);
case 0x99: return SmemPAMassApply2D<9,9,2>(NE,B,Bt,D,X,Y);
default: return PAMassApply2D(NE,B,Bt,D,X,Y,D1D,Q1D);
}
}
else if (dim == 3)
{
switch (id)
{
case 0x22: return SmemPAMassApply3D<2,2>(NE,B,Bt,D,X,Y);
case 0x23: return SmemPAMassApply3D<2,3>(NE,B,Bt,D,X,Y);
case 0x24: return SmemPAMassApply3D<2,4>(NE,B,Bt,D,X,Y);
case 0x26: return SmemPAMassApply3D<2,6>(NE,B,Bt,D,X,Y);
case 0x34: return SmemPAMassApply3D<3,4>(NE,B,Bt,D,X,Y);
case 0x35: return SmemPAMassApply3D<3,5>(NE,B,Bt,D,X,Y);
case 0x36: return SmemPAMassApply3D<3,6>(NE,B,Bt,D,X,Y);
case 0x37: return SmemPAMassApply3D<3,7>(NE,B,Bt,D,X,Y);
case 0x45: return SmemPAMassApply3D<4,5>(NE,B,Bt,D,X,Y);
case 0x46: return SmemPAMassApply3D<4,6>(NE,B,Bt,D,X,Y);
case 0x48: return SmemPAMassApply3D<4,8>(NE,B,Bt,D,X,Y);
case 0x56: return SmemPAMassApply3D<5,6>(NE,B,Bt,D,X,Y);
case 0x58: return SmemPAMassApply3D<5,8>(NE,B,Bt,D,X,Y);
case 0x67: return SmemPAMassApply3D<6,7>(NE,B,Bt,D,X,Y);
case 0x78: return SmemPAMassApply3D<7,8>(NE,B,Bt,D,X,Y);
case 0x89: return SmemPAMassApply3D<8,9>(NE,B,Bt,D,X,Y);
case 0x9A: return SmemPAMassApply3D<9,10>(NE,B,Bt,D,X,Y);
default: return PAMassApply3D(NE,B,Bt,D,X,Y,D1D,Q1D);
}
}
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
MFEM_ABORT("Unknown kernel.");
}
} // namespace internal
} // namespace mfem
@@ -9,12 +9,15 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_BILININTEG_MASS_PA_HPP
#define MFEM_BILININTEG_MASS_PA_HPP
#ifndef MFEM_BILININTEG_MASS_KERNELS_HPP
#define MFEM_BILININTEG_MASS_KERNELS_HPP
#include "../config/config.hpp"
#include "../general/forall.hpp"
#include "../linalg/dtensor.hpp"
#include "../../config/config.hpp"
#include "../../general/array.hpp"
#include "../../general/forall.hpp"
#include "../../linalg/dtensor.hpp"
#include "../../linalg/vector.hpp"
#include "../bilininteg.hpp"
namespace mfem
{
@@ -22,6 +25,315 @@ namespace mfem
namespace internal
{
void PAMassAssembleDiagonal(const int dim, const int D1D,
const int Q1D, const int NE,
const Array<double> &B,
const Vector &D,
Vector &Y);
// PA Mass Diagonal 2D kernel
template<int T_D1D = 0, int T_Q1D = 0>
inline void PAMassAssembleDiagonal2D(const int NE,
const Array<double> &b,
const Vector &d,
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 <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto D = Reshape(d.Read(), Q1D, Q1D, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double QD[MQ1][MD1];
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dy = 0; dy < D1D; ++dy)
{
QD[qx][dy] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
QD[qx][dy] += B(qy, dy) * B(qy, dy) * D(qx, qy, e);
}
}
}
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
for (int qx = 0; qx < Q1D; ++qx)
{
Y(dx,dy,e) += B(qx, dx) * B(qx, dx) * QD[qx][dy];
}
}
}
});
}
// Shared memory PA Mass Diagonal 2D kernel
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
inline void SmemPAMassAssembleDiagonal2D(const int NE,
const Array<double> &b_,
const Vector &d_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= MD1, "");
MFEM_VERIFY(Q1D <= MQ1, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D, Q1D, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] 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 NBZ = T_NBZ ? T_NBZ : 1;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
MFEM_SHARED double B[MQ1][MD1];
MFEM_SHARED double QDZ[NBZ][MQ1][MD1];
double (*QD)[MD1] = (double (*)[MD1])(QDZ + tidz);
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
B[q][d] = b(q,d);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
QD[qx][dy] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
QD[qx][dy] += B[qy][dy] * B[qy][dy] * D(qx, qy, e);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
for (int qx = 0; qx < Q1D; ++qx)
{
// might need absolute values on next line
Y(dx,dy,e) += B[qx][dx] * B[qx][dx] * QD[qx][dy];
}
}
}
});
}
// PA Mass Diagonal 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
inline void PAMassAssembleDiagonal3D(const int NE,
const Array<double> &b,
const Vector &d,
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 <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto D = Reshape(d.Read(), Q1D, Q1D, Q1D, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, D1D, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double QQD[MQ1][MQ1][MD1];
double QDD[MQ1][MD1][MD1];
for (int qx = 0; qx < Q1D; ++qx)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int dz = 0; dz < D1D; ++dz)
{
QQD[qx][qy][dz] = 0.0;
for (int qz = 0; qz < Q1D; ++qz)
{
QQD[qx][qy][dz] += B(qz, dz) * B(qz, dz) * D(qx, qy, qz, e);
}
}
}
}
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dz = 0; dz < D1D; ++dz)
{
for (int dy = 0; dy < D1D; ++dy)
{
QDD[qx][dy][dz] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
QDD[qx][dy][dz] += B(qy, dy) * B(qy, dy) * QQD[qx][qy][dz];
}
}
}
}
for (int dz = 0; dz < D1D; ++dz)
{
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
double t = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
t += B(qx, dx) * B(qx, dx) * QDD[qx][dy][dz];
}
Y(dx, dy, dz, e) += t;
}
}
}
});
}
// Shared memory PA Mass Diagonal 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAMassAssembleDiagonal3D(const int NE,
const Array<double> &b_,
const Vector &d_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= MD1, "");
MFEM_VERIFY(Q1D <= MQ1, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D, Q1D, Q1D, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, 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 : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
MFEM_SHARED double B[MQ1][MD1];
MFEM_SHARED double QQD[MQ1][MQ1][MD1];
MFEM_SHARED double QDD[MQ1][MD1][MD1];
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
B[q][d] = b(q,d);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dz,z,D1D)
{
QQD[qx][qy][dz] = 0.0;
for (int qz = 0; qz < Q1D; ++qz)
{
QQD[qx][qy][dz] += B[qz][dz] * B[qz][dz] * D(qx, qy, qz, e);
}
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
QDD[qx][dy][dz] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
QDD[qx][dy][dz] += B[qy][dy] * B[qy][dy] * QQD[qx][qy][dz];
}
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double t = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
t += B[qx][dx] * B[qx][dx] * QDD[qx][dy][dz];
}
Y(dx, dy, dz, e) += t;
}
}
}
});
}
void PAMassApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &Bt,
const Vector &D,
const Vector &X,
Vector &Y);
#ifdef MFEM_USE_OCCA
// OCCA PA Mass Apply 2D kernel
void OccaPAMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &Bt,
const Vector &D,
const Vector &X,
Vector &Y);
// OCCA PA Mass Apply 3D kernel
void OccaPAMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &Bt,
const Vector &D,
const Vector &X,
Vector &Y);
#endif // MFEM_USE_OCCA
template <bool ACCUMULATE = true>
MFEM_HOST_DEVICE inline
void PAMassApply2D_Element(const int e,
@@ -625,6 +937,116 @@ void SmemPAMassApply3D_Element(const int e,
MFEM_SYNC_THREAD;
}
// PA Mass Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0>
inline void PAMassApply2D(const int NE,
const Array<double> &b_,
const Array<double> &bt_,
const Vector &d_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= MAX_D1D, "");
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= MAX_Q1D, "");
const auto B = b_.Read();
const auto Bt = bt_.Read();
const auto D = d_.Read();
const auto X = x_.Read();
auto Y = y_.ReadWrite();
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
internal::PAMassApply2D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
});
}
// Shared memory PA Mass Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
inline void SmemPAMassApply2D(const int NE,
const Array<double> &b_,
const Array<double> &bt_,
const Vector &d_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_CONTRACT_VAR(bt_);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= MD1, "");
MFEM_VERIFY(Q1D <= MQ1, "");
const auto b = b_.Read();
const auto D = d_.Read();
const auto x = x_.Read();
auto Y = y_.ReadWrite();
mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
{
internal::SmemPAMassApply2D_Element<T_D1D,T_Q1D,T_NBZ>(e, NE, b, D, x, Y, d1d,
q1d);
});
}
// PA Mass Apply 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
inline void PAMassApply3D(const int NE,
const Array<double> &b_,
const Array<double> &bt_,
const Vector &d_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= MAX_D1D, "");
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= MAX_Q1D, "");
const auto B = b_.Read();
const auto Bt = bt_.Read();
const auto D = d_.Read();
const auto X = x_.Read();
auto Y = y_.ReadWrite();
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
internal::PAMassApply3D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
});
}
// Shared memory PA Mass Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAMassApply3D(const int NE,
const Array<double> &b_,
const Array<double> &bt_,
const Vector &d_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_CONTRACT_VAR(bt_);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int M1Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int M1D = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= M1D, "");
MFEM_VERIFY(Q1D <= M1Q, "");
auto b = b_.Read();
auto d = d_.Read();
auto x = x_.Read();
auto y = y_.ReadWrite();
mfem::forall_2D(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
internal::SmemPAMassApply3D_Element<T_D1D,T_Q1D>(e, NE, b, d, x, y, d1d, q1d);
});
}
} // namespace internal
} // namespace mfem
@@ -9,12 +9,9 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/integrators/mass/mass.hpp"
using namespace std;
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../ceed/integrators/mass/mass.hpp"
namespace mfem
{
+222
View File
@@ -0,0 +1,222 @@
// Copyright (c) 2010-2023, 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 "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "../ceed/integrators/mass/mass.hpp"
#include "bilininteg_mass_kernels.hpp"
namespace mfem
{
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
Device::GetDeviceMemoryType() : pa_mt;
// Assuming the same element type
fespace = &fes;
Mesh *mesh = fes.GetMesh();
if (mesh->GetNE() == 0) { return; }
const FiniteElement &el = *fes.GetFE(0);
ElementTransformation *T0 = mesh->GetElementTransformation(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, *T0);
if (DeviceCanUseCeed())
{
delete ceedOp;
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedPAMassIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::PAMassIntegrator(fes, *ir, Q);
}
return;
}
int map_type = el.GetMapType();
dim = mesh->Dimension();
ne = fes.GetMesh()->GetNE();
nq = ir->GetNPoints();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::DETERMINANTS, mt);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(ne*nq, mt);
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(Q, qs, CoefficientStorage::COMPRESSED);
if (dim==1) { MFEM_ABORT("Not supported yet... stay tuned!"); }
if (dim==2)
{
const int NE = ne;
const int Q1D = quad1D;
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
const auto J = Reshape(geom->detJ.Read(), Q1D,Q1D,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D, NE);
mfem::forall_2D(NE,Q1D,Q1D, [=] MFEM_HOST_DEVICE (int e)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double detJ = J(qx,qy,e);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
v(qx,qy,e) = W(qx,qy) * coeff * (by_val ? detJ : 1.0/detJ);
}
}
});
}
if (dim==3)
{
const int NE = ne;
const int Q1D = quad1D;
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(geom->detJ.Read(), Q1D,Q1D,Q1D,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D,Q1D,NE);
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double detJ = J(qx,qy,qz,e);
const double coeff = const_c ? C(0,0,0,0) : C(qx,qy,qz,e);
v(qx,qy,qz,e) = W(qx,qy,qz) * coeff * (by_val ? detJ : 1.0/detJ);
}
}
}
});
}
}
void MassIntegrator::AssemblePABoundary(const FiniteElementSpace &fes)
{
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
Device::GetDeviceMemoryType() : pa_mt;
// Assuming the same element type
fespace = &fes;
Mesh *mesh = fes.GetMesh();
if (mesh->GetNBE() == 0) { return; }
const FiniteElement &el = *fes.GetBE(0);
ElementTransformation *T0 = mesh->GetBdrElementTransformation(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, *T0);
int map_type = el.GetMapType();
dim = el.GetDim(); // Dimension of the boundary element, *not* the mesh
ne = fes.GetMesh()->GetNBE();
nq = ir->GetNPoints();
face_geom = mesh->GetFaceGeometricFactors(*ir, GeometricFactors::DETERMINANTS,
FaceType::Boundary, mt);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(ne*nq, mt);
FaceQuadratureSpace qs(*mesh, *ir, FaceType::Boundary);
CoefficientVector coeff(Q, qs, CoefficientStorage::COMPRESSED);
const int NE = ne;
const int Q1D = quad1D;
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
if (dim==1)
{
const auto W = Reshape(ir->GetWeights().Read(), Q1D);
const auto J = Reshape(face_geom->detJ.Read(), Q1D, NE);
const auto C = const_c ? Reshape(coeff.Read(), 1, 1) :
Reshape(coeff.Read(), Q1D, NE);
auto v = Reshape(pa_data.Write(), Q1D, NE);
mfem::forall_2D(NE, Q1D, 1, [=] MFEM_HOST_DEVICE (int e)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const double detJ = J(qx,e);
const double coeff = const_c ? C(0,0) : C(qx,e);
v(qx,e) = W(qx) * coeff * (by_val ? detJ : 1.0/detJ);
}
});
}
else if (dim==2)
{
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
const auto J = Reshape(face_geom->detJ.Read(), Q1D,Q1D,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D, NE);
mfem::forall_2D(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double detJ = J(qx,qy,e);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
v(qx,qy,e) = W(qx,qy) * coeff * (by_val ? detJ : 1.0/detJ);
}
}
});
}
else
{
MFEM_ABORT("Not supported.");
}
}
void MassIntegrator::AssembleDiagonalPA(Vector &diag)
{
if (DeviceCanUseCeed())
{
ceedOp->GetDiagonal(diag);
}
else
{
internal::PAMassAssembleDiagonal(dim, dofs1D, quad1D, ne, maps->B, pa_data,
diag);
}
}
void MassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (DeviceCanUseCeed())
{
ceedOp->AddMult(x, y);
}
else
{
internal::PAMassApply(dim, dofs1D, quad1D, ne, maps->B, maps->Bt, pa_data, x,
y);
}
}
void MassIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const
{
// Mass integrator is symmetric
AddMultPA(x, y);
}
} // namespace mfem
+423
View File
@@ -0,0 +1,423 @@
// Copyright (c) 2010-2023, 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 "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "bilininteg_hcurl_kernels.hpp"
#include "bilininteg_hcurlhdiv_kernels.hpp"
namespace mfem
{
void MixedScalarCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes)
{
// Assumes tensor-product elements
Mesh *mesh = trial_fes.GetMesh();
const FiniteElement *fel = trial_fes.GetFE(0); // In H(curl)
const FiniteElement *eltest = test_fes.GetFE(0); // In scalar space
const VectorTensorFiniteElement *el =
dynamic_cast<const VectorTensorFiniteElement*>(fel);
MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
if (el->GetDerivType() != mfem::FiniteElement::CURL)
{
MFEM_ABORT("Unknown kernel.");
}
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*eltest, *eltest,
*mesh->GetElementTransformation(0));
const int dims = el->GetDim();
MFEM_VERIFY(dims == 2, "");
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2, "");
ne = test_fes.GetNE();
mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
if (el->GetOrder() == eltest->GetOrder())
{
dofs1Dtest = dofs1D;
}
else
{
dofs1Dtest = dofs1D - 1;
}
pa_data.SetSize(nq * ne, Device::GetMemoryType());
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(Q, qs, CoefficientStorage::FULL);
if (dim == 2)
{
internal::PAHcurlL2Setup2D(quad1D, ne, ir->GetWeights(), coeff, pa_data);
}
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
void MixedScalarCurlIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 2)
{
internal::PAHcurlL2Apply2D(dofs1D, dofs1Dtest, quad1D, ne, mapsO->B,
mapsO->Bt, mapsC->Bt, mapsC->G, pa_data,
x, y);
}
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
void MixedScalarCurlIntegrator::AddMultTransposePA(const Vector &x,
Vector &y) const
{
if (dim == 2)
{
internal::PAHcurlL2ApplyTranspose2D(dofs1D, dofs1Dtest, quad1D, ne, mapsO->B,
mapsO->Bt, mapsC->B, mapsC->Gt, pa_data,
x, y);
}
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
void MixedVectorCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes)
{
// Assumes tensor-product elements, with vector test and trial spaces.
Mesh *mesh = trial_fes.GetMesh();
const FiniteElement *trial_fel = trial_fes.GetFE(0);
const FiniteElement *test_fel = test_fes.GetFE(0);
const VectorTensorFiniteElement *trial_el =
dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
const VectorTensorFiniteElement *test_el =
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
*mesh->GetElementTransformation(0));
const int dims = trial_el->GetDim();
MFEM_VERIFY(dims == 3, "");
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 3, "");
MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
ne = trial_fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &trial_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &trial_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
mapsCtest = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsOtest = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
dofs1Dtest = mapsCtest->ndof;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
testType = test_el->GetDerivType();
trialType = trial_el->GetDerivType();
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
coeffDim = (DQ ? 3 : 1);
const bool curlSpaces = (testType == mfem::FiniteElement::CURL &&
trialType == mfem::FiniteElement::CURL);
const int ndata = curlSpaces ? (coeffDim == 1 ? 1 : 9) : symmDims;
pa_data.SetSize(ndata * nq * ne, Device::GetMemoryType());
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(qs, CoefficientStorage::FULL);
if (Q) { coeff.Project(*Q); }
else if (DQ) { coeff.Project(*DQ); }
else { coeff.SetConstant(1.0); }
if (testType == mfem::FiniteElement::CURL &&
trialType == mfem::FiniteElement::CURL && dim == 3)
{
if (coeffDim == 1)
{
internal::PAHcurlL2Setup3D(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
}
else
{
internal::PAHcurlHdivMassSetup3D(quad1D, coeffDim, ne, false, ir->GetWeights(),
geom->J, coeff, pa_data);
}
}
else if (testType == mfem::FiniteElement::DIV &&
trialType == mfem::FiniteElement::CURL && dim == 3 &&
test_fel->GetOrder() == trial_fel->GetOrder())
{
internal::PACurlCurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
void MixedVectorCurlIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (testType == mfem::FiniteElement::CURL &&
trialType == mfem::FiniteElement::CURL && dim == 3)
{
const int ndata = coeffDim == 1 ? 1 : 9;
if (Device::Allows(Backend::DEVICE_MASK))
{
const int ID = (dofs1D << 4) | quad1D;
switch (ID)
{
case 0x23:
return internal::SmemPAHcurlL2Apply3D<2,3>(
dofs1D, quad1D, ndata, ne,
mapsO->B, mapsC->B, mapsC->G,
pa_data, x, y);
case 0x34:
return internal::SmemPAHcurlL2Apply3D<3,4>(
dofs1D, quad1D, ndata, ne,
mapsO->B, mapsC->B, mapsC->G,
pa_data, x, y);
case 0x45:
return internal::SmemPAHcurlL2Apply3D<4,5>(
dofs1D, quad1D, ndata, ne,
mapsO->B, mapsC->B, mapsC->G,
pa_data, x, y);
case 0x56:
return internal::SmemPAHcurlL2Apply3D<5,6>(
dofs1D, quad1D, ndata, ne,
mapsO->B, mapsC->B, mapsC->G,
pa_data, x, y);
default:
return internal::SmemPAHcurlL2Apply3D(
dofs1D, quad1D, ndata, ne,
mapsO->B, mapsC->B, mapsC->G,
pa_data, x, y);
}
}
else
{
internal::PAHcurlL2Apply3D(dofs1D, quad1D, ndata, ne, mapsO->B, mapsC->B,
mapsO->Bt, mapsC->Bt, mapsC->G, pa_data, x, y);
}
}
else if (testType == mfem::FiniteElement::DIV &&
trialType == mfem::FiniteElement::CURL && dim == 3)
{
internal::PAHcurlHdivApply3D(dofs1D, dofs1Dtest, quad1D, ne, mapsO->B,
mapsC->B, mapsOtest->Bt, mapsCtest->Bt, mapsC->G,
pa_data, x, y);
}
else
{
MFEM_ABORT("Unsupported dimension or space!");
}
}
void MixedVectorCurlIntegrator::AddMultTransposePA(const Vector &x,
Vector &y) const
{
if (testType == mfem::FiniteElement::DIV &&
trialType == mfem::FiniteElement::CURL && dim == 3)
{
internal::PAHcurlHdivApplyTranspose3D(dofs1D, dofs1Dtest, quad1D, ne, mapsO->B,
mapsC->B, mapsOtest->Bt, mapsCtest->Bt,
mapsC->Gt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unsupported dimension or space!");
}
}
void MixedVectorWeakCurlIntegrator::AssemblePA(const FiniteElementSpace
&trial_fes,
const FiniteElementSpace &test_fes)
{
// Assumes tensor-product elements, with vector test and trial spaces.
Mesh *mesh = trial_fes.GetMesh();
const FiniteElement *trial_fel = trial_fes.GetFE(0);
const FiniteElement *test_fel = test_fes.GetFE(0);
const VectorTensorFiniteElement *trial_el =
dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
const VectorTensorFiniteElement *test_el =
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
*mesh->GetElementTransformation(0));
const int dims = trial_el->GetDim();
MFEM_VERIFY(dims == 3, "");
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 3, "");
MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
ne = trial_fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
testType = test_el->GetDerivType();
trialType = trial_el->GetDerivType();
const bool curlSpaces = (testType == mfem::FiniteElement::CURL &&
trialType == mfem::FiniteElement::CURL);
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
coeffDim = DQ ? 3 : 1;
const int ndata = curlSpaces ? (DQ ? 9 : 1) : symmDims;
pa_data.SetSize(ndata * nq * ne, Device::GetMemoryType());
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(qs, CoefficientStorage::FULL);
if (Q) { coeff.Project(*Q); }
else if (DQ) { coeff.Project(*DQ); }
else { coeff.SetConstant(1.0); }
if (trialType == mfem::FiniteElement::CURL && dim == 3)
{
if (coeffDim == 1)
{
internal::PAHcurlL2Setup3D(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
}
else
{
internal::PAHcurlHdivMassSetup3D(quad1D, coeffDim, ne, false, ir->GetWeights(),
geom->J, coeff, pa_data);
}
}
else if (trialType == mfem::FiniteElement::DIV && dim == 3 &&
test_el->GetOrder() == trial_el->GetOrder())
{
internal::PACurlCurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
void MixedVectorWeakCurlIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (testType == mfem::FiniteElement::CURL &&
trialType == mfem::FiniteElement::CURL && dim == 3)
{
const int ndata = coeffDim == 1 ? 1 : 9;
if (Device::Allows(Backend::DEVICE_MASK))
{
const int ID = (dofs1D << 4) | quad1D;
switch (ID)
{
case 0x23:
return internal::SmemPAHcurlL2ApplyTranspose3D<2,3>(
dofs1D, quad1D, ndata,
ne, mapsO->B, mapsC->B,
mapsC->G, pa_data, x, y);
case 0x34:
return internal::SmemPAHcurlL2ApplyTranspose3D<3,4>(
dofs1D, quad1D, ndata,
ne, mapsO->B, mapsC->B,
mapsC->G, pa_data, x, y);
case 0x45:
return internal::SmemPAHcurlL2ApplyTranspose3D<4,5>(
dofs1D, quad1D, ndata,
ne, mapsO->B, mapsC->B,
mapsC->G, pa_data, x, y);
case 0x56:
return internal::SmemPAHcurlL2ApplyTranspose3D<5,6>(
dofs1D, quad1D, ndata,
ne, mapsO->B, mapsC->B,
mapsC->G, pa_data, x, y);
default:
return internal::SmemPAHcurlL2ApplyTranspose3D(
dofs1D, quad1D, ndata, ne,
mapsO->B, mapsC->B,
mapsC->G, pa_data, x, y);
}
}
else
{
internal::PAHcurlL2ApplyTranspose3D(dofs1D, quad1D, ndata, ne, mapsO->B,
mapsC->B, mapsO->Bt, mapsC->Bt, mapsC->Gt,
pa_data, x, y);
}
}
else if (testType == mfem::FiniteElement::CURL &&
trialType == mfem::FiniteElement::DIV && dim == 3)
{
internal::PAHcurlHdivApplyTranspose3D(dofs1D, dofs1D, quad1D, ne, mapsO->B,
mapsC->B, mapsO->Bt, mapsC->Bt,
mapsC->Gt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unsupported dimension or space!");
}
}
void MixedVectorWeakCurlIntegrator::AddMultTransposePA(const Vector &x,
Vector &y) const
{
if (testType == mfem::FiniteElement::CURL &&
trialType == mfem::FiniteElement::DIV && dim == 3)
{
internal::PAHcurlHdivApply3D(dofs1D, dofs1D, quad1D, ne, mapsO->B,
mapsC->B, mapsO->Bt, mapsC->Bt, mapsC->G,
pa_data, x, y);
}
else
{
MFEM_ABORT("Unsupported dimension or space!");
}
}
} // namespace mfem
+757
View File
@@ -0,0 +1,757 @@
// Copyright (c) 2010-2023, 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 "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "bilininteg_diffusion_kernels.hpp"
namespace mfem
{
// Apply to x corresponding to DOFs in H^1 (trial), whose gradients are
// integrated against H(curl) test functions corresponding to y.
static void PAHcurlH1Apply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &bc,
const Array<double> &gc,
const Array<double> &bot,
const Array<double> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
auto Bc = Reshape(bc.Read(), Q1D, D1D);
auto Gc = Reshape(gc.Read(), Q1D, D1D);
auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
auto Bct = Reshape(bct.Read(), D1D, Q1D);
auto op = Reshape(pa_data.Read(), Q1D, Q1D, 3, NE);
auto X = Reshape(x.Read(), D1D, D1D, NE);
auto Y = Reshape(y.ReadWrite(), 2*(D1D-1)*D1D, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
double mass[MAX_Q1D][MAX_Q1D][VDIM];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
for (int c = 0; c < VDIM; ++c)
{
mass[qy][qx][c] = 0.0;
}
}
}
for (int dy = 0; dy < D1D; ++dy)
{
double gradX[MAX_Q1D][2];
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] = 0.0;
gradX[qx][1] = 0.0;
}
for (int dx = 0; dx < D1D; ++dx)
{
const double s = X(dx,dy,e);
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] += s * Bc(qx,dx);
gradX[qx][1] += s * Gc(qx,dx);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = Bc(qy,dy);
const double wDy = Gc(qy,dy);
for (int qx = 0; qx < Q1D; ++qx)
{
const double wx = gradX[qx][0];
const double wDx = gradX[qx][1];
mass[qy][qx][0] += wDx * wy;
mass[qy][qx][1] += wx * wDy;
}
}
}
// Apply D operator.
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const double O11 = op(qx,qy,0,e);
const double O12 = op(qx,qy,1,e);
const double O22 = op(qx,qy,2,e);
const double massX = mass[qy][qx][0];
const double massY = mass[qy][qx][1];
mass[qy][qx][0] = (O11*massX)+(O12*massY);
mass[qy][qx][1] = (O12*massX)+(O22*massY);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y components
{
const int D1Dy = (c == 1) ? D1D - 1 : D1D;
const int D1Dx = (c == 0) ? D1D - 1 : D1D;
double massX[MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] += mass[qy][qx][c] * ((c == 0) ? Bot(dx,qx) : Bct(dx,qx));
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
const double wy = (c == 1) ? Bot(dy,qy) : Bct(dy,qy);
for (int dx = 0; dx < D1Dx; ++dx)
{
Y(dx + (dy * D1Dx) + osc, e) += massX[dx] * wy;
}
}
osc += D1Dx * D1Dy;
} // loop c
}
}); // end of element loop
}
// Apply to x corresponding to DOFs in H(curl), integrated
// against gradients of H^1 functions corresponding to y.
static void PAHcurlH1ApplyTranspose2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &bc,
const Array<double> &bo,
const Array<double> &bct,
const Array<double> &gct,
const Vector &pa_data,
const Vector &x,
Vector &y)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
auto Bc = Reshape(bc.Read(), Q1D, D1D);
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
auto Bt = Reshape(bct.Read(), D1D, Q1D);
auto Gt = Reshape(gct.Read(), D1D, Q1D);
auto op = Reshape(pa_data.Read(), Q1D, Q1D, 3, NE);
auto X = Reshape(x.Read(), 2*(D1D-1)*D1D, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
double mass[MAX_Q1D][MAX_Q1D][VDIM];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
for (int c = 0; c < VDIM; ++c)
{
mass[qy][qx][c] = 0.0;
}
}
}
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y components
{
const int D1Dy = (c == 1) ? D1D - 1 : D1D;
const int D1Dx = (c == 0) ? D1D - 1 : D1D;
for (int dy = 0; dy < D1Dy; ++dy)
{
double massX[MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] = 0.0;
}
for (int dx = 0; dx < D1Dx; ++dx)
{
const double t = X(dx + (dy * D1Dx) + osc, e);
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] += t * ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
for (int qx = 0; qx < Q1D; ++qx)
{
mass[qy][qx][c] += massX[qx] * wy;
}
}
}
osc += D1Dx * D1Dy;
} // loop (c) over components
// Apply D operator.
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const double O11 = op(qx,qy,0,e);
const double O12 = op(qx,qy,1,e);
const double O22 = op(qx,qy,2,e);
const double massX = mass[qy][qx][0];
const double massY = mass[qy][qx][1];
mass[qy][qx][0] = (O11*massX)+(O12*massY);
mass[qy][qx][1] = (O12*massX)+(O22*massY);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
double gradX[MAX_D1D][2];
for (int dx = 0; dx < D1D; ++dx)
{
gradX[dx][0] = 0;
gradX[dx][1] = 0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
const double gX = mass[qy][qx][0];
const double gY = mass[qy][qx][1];
for (int dx = 0; dx < D1D; ++dx)
{
const double wx = Bt(dx,qx);
const double wDx = Gt(dx,qx);
gradX[dx][0] += gX * wDx;
gradX[dx][1] += gY * wx;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
const double wy = Bt(dy,qy);
const double wDy = Gt(dy,qy);
for (int dx = 0; dx < D1D; ++dx)
{
Y(dx,dy,e) += ((gradX[dx][0] * wy) + (gradX[dx][1] * wDy));
}
}
}
}); // end of element loop
}
// Apply to x corresponding to DOFs in H^1 (trial), whose gradients are
// integrated against H(curl) test functions corresponding to y.
static void PAHcurlH1Apply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &bc,
const Array<double> &gc,
const Array<double> &bot,
const Array<double> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y)
{
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
auto Bc = Reshape(bc.Read(), Q1D, D1D);
auto Gc = Reshape(gc.Read(), Q1D, D1D);
auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
auto Bct = Reshape(bct.Read(), D1D, Q1D);
auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, 6, NE);
auto X = Reshape(x.Read(), D1D, D1D, D1D, NE);
auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
double mass[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)
{
for (int c = 0; c < VDIM; ++c)
{
mass[qz][qy][qx][c] = 0.0;
}
}
}
}
for (int dz = 0; dz < D1D; ++dz)
{
double gradXY[MAX_Q1D][MAX_Q1D][3];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
gradXY[qy][qx][0] = 0.0;
gradXY[qy][qx][1] = 0.0;
gradXY[qy][qx][2] = 0.0;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
double gradX[MAX_Q1D][2];
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] = 0.0;
gradX[qx][1] = 0.0;
}
for (int dx = 0; dx < D1D; ++dx)
{
const double s = X(dx,dy,dz,e);
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] += s * Bc(qx,dx);
gradX[qx][1] += s * Gc(qx,dx);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = Bc(qy,dy);
const double wDy = Gc(qy,dy);
for (int qx = 0; qx < Q1D; ++qx)
{
const double wx = gradX[qx][0];
const double wDx = gradX[qx][1];
gradXY[qy][qx][0] += wDx * wy;
gradXY[qy][qx][1] += wx * wDy;
gradXY[qy][qx][2] += wx * wy;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
const double wz = Bc(qz,dz);
const double wDz = Gc(qz,dz);
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
mass[qz][qy][qx][0] += gradXY[qy][qx][0] * wz;
mass[qz][qy][qx][1] += gradXY[qy][qx][1] * wz;
mass[qz][qy][qx][2] += gradXY[qy][qx][2] * wDz;
}
}
}
}
// Apply D operator.
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const double O11 = op(qx,qy,qz,0,e);
const double O12 = op(qx,qy,qz,1,e);
const double O13 = op(qx,qy,qz,2,e);
const double O22 = op(qx,qy,qz,3,e);
const double O23 = op(qx,qy,qz,4,e);
const double O33 = op(qx,qy,qz,5,e);
const double massX = mass[qz][qy][qx][0];
const double massY = mass[qz][qy][qx][1];
const double massZ = mass[qz][qy][qx][2];
mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
mass[qz][qy][qx][1] = (O12*massX)+(O22*massY)+(O23*massZ);
mass[qz][qy][qx][2] = (O13*massX)+(O23*massY)+(O33*massZ);
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
double massXY[MAX_D1D][MAX_D1D];
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;
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] = 0.0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
double massX[MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] += mass[qz][qy][qx][c] * ((c == 0) ? Bot(dx,qx) : Bct(dx,qx));
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
const double wy = (c == 1) ? Bot(dy,qy) : Bct(dy,qy);
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] += massX[dx] * wy;
}
}
}
for (int dz = 0; dz < D1Dz; ++dz)
{
const double wz = (c == 2) ? Bot(dz,qz) : Bct(dz,qz);
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += massXY[dy][dx] * wz;
}
}
}
osc += D1Dx * D1Dy * D1Dz;
} // loop c
} // loop qz
}); // end of element loop
}
// Apply to x corresponding to DOFs in H(curl), integrated
// against gradients of H^1 functions corresponding to y.
static void PAHcurlH1ApplyTranspose3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &bc,
const Array<double> &bo,
const Array<double> &bct,
const Array<double> &gct,
const Vector &pa_data,
const Vector &x,
Vector &y)
{
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
auto Bc = Reshape(bc.Read(), Q1D, D1D);
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
auto Bt = Reshape(bct.Read(), D1D, Q1D);
auto Gt = Reshape(gct.Read(), D1D, Q1D);
auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, 6, NE);
auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, D1D, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
double mass[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)
{
for (int c = 0; c < VDIM; ++c)
{
mass[qz][qy][qx][c] = 0.0;
}
}
}
}
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;
for (int dz = 0; dz < D1Dz; ++dz)
{
double massXY[MAX_Q1D][MAX_Q1D];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
massXY[qy][qx] = 0.0;
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
double massX[MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] = 0.0;
}
for (int dx = 0; dx < D1Dx; ++dx)
{
const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] += t * ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
for (int qx = 0; qx < Q1D; ++qx)
{
const double wx = massX[qx];
massXY[qy][qx] += wx * wy;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
const double wz = (c == 2) ? Bo(qz,dz) : Bc(qz,dz);
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
mass[qz][qy][qx][c] += massXY[qy][qx] * wz;
}
}
}
}
osc += D1Dx * D1Dy * D1Dz;
} // loop (c) over components
// Apply D operator.
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const double O11 = op(qx,qy,qz,0,e);
const double O12 = op(qx,qy,qz,1,e);
const double O13 = op(qx,qy,qz,2,e);
const double O22 = op(qx,qy,qz,3,e);
const double O23 = op(qx,qy,qz,4,e);
const double O33 = op(qx,qy,qz,5,e);
const double massX = mass[qz][qy][qx][0];
const double massY = mass[qz][qy][qx][1];
const double massZ = mass[qz][qy][qx][2];
mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
mass[qz][qy][qx][1] = (O12*massX)+(O22*massY)+(O23*massZ);
mass[qz][qy][qx][2] = (O13*massX)+(O23*massY)+(O33*massZ);
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
double gradXY[MAX_D1D][MAX_D1D][3];
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
gradXY[dy][dx][0] = 0;
gradXY[dy][dx][1] = 0;
gradXY[dy][dx][2] = 0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
double gradX[MAX_D1D][3];
for (int dx = 0; dx < D1D; ++dx)
{
gradX[dx][0] = 0;
gradX[dx][1] = 0;
gradX[dx][2] = 0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
const double gX = mass[qz][qy][qx][0];
const double gY = mass[qz][qy][qx][1];
const double gZ = mass[qz][qy][qx][2];
for (int dx = 0; dx < D1D; ++dx)
{
const double wx = Bt(dx,qx);
const double wDx = Gt(dx,qx);
gradX[dx][0] += gX * wDx;
gradX[dx][1] += gY * wx;
gradX[dx][2] += gZ * wx;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
const double wy = Bt(dy,qy);
const double wDy = Gt(dy,qy);
for (int dx = 0; dx < D1D; ++dx)
{
gradXY[dy][dx][0] += gradX[dx][0] * wy;
gradXY[dy][dx][1] += gradX[dx][1] * wDy;
gradXY[dy][dx][2] += gradX[dx][2] * wy;
}
}
}
for (int dz = 0; dz < D1D; ++dz)
{
const double wz = Bt(dz,qz);
const double wDz = Gt(dz,qz);
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
Y(dx,dy,dz,e) +=
((gradXY[dy][dx][0] * wz) +
(gradXY[dy][dx][1] * wz) +
(gradXY[dy][dx][2] * wDz));
}
}
}
} // loop qz
}); // end of element loop
}
void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
&trial_fes,
const FiniteElementSpace &test_fes)
{
// Assumes tensor-product elements, with a vector test space and H^1 trial space.
Mesh *mesh = trial_fes.GetMesh();
const FiniteElement *trial_fel = trial_fes.GetFE(0);
const FiniteElement *test_fel = test_fes.GetFE(0);
const NodalTensorFiniteElement *trial_el =
dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
MFEM_VERIFY(trial_el != NULL, "Only NodalTensorFiniteElement is supported!");
const VectorTensorFiniteElement *test_el =
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
*mesh->GetElementTransformation(0));
const int dims = trial_el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
ne = trial_fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(Q, qs, CoefficientStorage::FULL);
// Use the same setup functions as VectorFEMassIntegrator.
if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
internal::PADiffusionSetup3D(quad1D, 1, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
internal::PADiffusionSetup2D<2>(quad1D, 1, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
void MixedVectorGradientIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
{
PAHcurlH1Apply3D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
}
else if (dim == 2)
{
PAHcurlH1Apply2D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
void MixedVectorGradientIntegrator::AddMultTransposePA(const Vector &x,
Vector &y) const
{
if (dim == 3)
{
PAHcurlH1ApplyTranspose3D(dofs1D, quad1D, ne, mapsC->B, mapsO->B,
mapsC->Bt, mapsC->Gt, pa_data, x, y);
}
else if (dim == 2)
{
PAHcurlH1ApplyTranspose2D(dofs1D, quad1D, ne, mapsC->B, mapsO->B,
mapsC->Bt, mapsC->Gt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
} // namespace mfem
@@ -9,8 +9,8 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
namespace mfem
{
@@ -27,7 +27,7 @@ void TransposeIntegrator::AssembleEA(const FiniteElementSpace &fes,
const int dofs = fes.GetFE(0)->GetDof();
auto A = Reshape(ea_data_tmp.Read(), dofs, dofs, ne);
auto AT = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
MFEM_FORALL(e, ne,
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
{
for (int i = 0; i < dofs; i++)
{
@@ -46,7 +46,7 @@ void TransposeIntegrator::AssembleEA(const FiniteElementSpace &fes,
if (ne == 0) { return; }
const int dofs = fes.GetFE(0)->GetDof();
auto A = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
MFEM_FORALL(e, ne,
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
{
for (int i = 0; i < dofs; i++)
{
@@ -80,7 +80,7 @@ void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
auto AT_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
MFEM_FORALL(f, nf,
mfem::forall(nf, [=] MFEM_HOST_DEVICE (int f)
{
for (int i = 0; i < faceDofs; i++)
{
@@ -105,7 +105,7 @@ void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
auto A_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
auto A_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
MFEM_FORALL(f, nf,
mfem::forall(nf, [=] MFEM_HOST_DEVICE (int f)
{
for (int i = 0; i < faceDofs; i++)
{
@@ -149,7 +149,7 @@ void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
MFEM_FORALL(f, nf,
mfem::forall(nf, [=] MFEM_HOST_DEVICE (int f)
{
for (int i = 0; i < faceDofs; i++)
{
@@ -167,7 +167,7 @@ void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
auto A_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
MFEM_FORALL(f, nf,
mfem::forall(nf, [=] MFEM_HOST_DEVICE (int f)
{
for (int i = 0; i < faceDofs; i++)
{
@@ -9,12 +9,9 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/integrators/diffusion/diffusion.hpp"
using namespace std;
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../ceed/integrators/diffusion/diffusion.hpp"
namespace mfem
{
@@ -9,19 +9,15 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "qfunction.hpp"
#include "ceed/integrators/diffusion/diffusion.hpp"
using namespace std;
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "../ceed/integrators/diffusion/diffusion.hpp"
namespace mfem
{
// PA Vector Diffusion Integrator
// PA Diffusion Assemble 2D kernel
static void PAVectorDiffusionSetup2D(const int Q1D,
const int NE,
@@ -41,7 +37,7 @@ static void PAVectorDiffusionSetup2D(const int Q1D,
Reshape(c.Read(), NQ, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
for (int q = 0; q < NQ; ++q)
{
@@ -77,7 +73,7 @@ static void PAVectorDiffusionSetup3D(const int Q1D,
Reshape(c.Read(), NQ,NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
for (int q = 0; q < NQ; ++q)
{
@@ -91,8 +87,8 @@ static void PAVectorDiffusionSetup3D(const int Q1D,
const double J23 = J(q,1,2,e);
const double J33 = J(q,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
J21 * (J12 * J33 - J32 * J13) +
J31 * (J12 * J23 - J22 * J13);
const double C1 = const_c ? C(0,0) : C(q,e);
@@ -197,7 +193,7 @@ void VectorDiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
const auto C = const_c ? Reshape(coeff.Read(), 1,1) :
Reshape(coeff.Read(), NQ,ne);
MFEM_FORALL(e, ne,
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
{
for (int q = 0; q < NQ; ++q)
{
@@ -226,6 +222,209 @@ void VectorDiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
}
}
template<int T_D1D = 0, int T_Q1D = 0>
static void PAVectorDiffusionDiagonal2D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &d,
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 <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
// note the different shape for D, this is a (symmetric) matrix so we only
// store necessary entries
auto D = Reshape(d.Read(), Q1D*Q1D, 3, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, 2, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
// gradphi \cdot Q \gradphi has four terms
double QD0[MQ1][MD1];
double QD1[MQ1][MD1];
double QD2[MQ1][MD1];
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dy = 0; dy < D1D; ++dy)
{
QD0[qx][dy] = 0.0;
QD1[qx][dy] = 0.0;
QD2[qx][dy] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
const int q = qx + qy * Q1D;
const double D0 = D(q,0,e);
const double D1 = D(q,1,e);
const double D2 = D(q,2,e);
QD0[qx][dy] += B(qy, dy) * B(qy, dy) * D0;
QD1[qx][dy] += B(qy, dy) * G(qy, dy) * D1;
QD2[qx][dy] += G(qy, dy) * G(qy, dy) * D2;
}
}
}
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
double temp = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
temp += G(qx, dx) * G(qx, dx) * QD0[qx][dy];
temp += G(qx, dx) * B(qx, dx) * QD1[qx][dy];
temp += B(qx, dx) * G(qx, dx) * QD1[qx][dy];
temp += B(qx, dx) * B(qx, dx) * QD2[qx][dy];
}
Y(dx,dy,0,e) += temp;
Y(dx,dy,1,e) += temp;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void PAVectorDiffusionDiagonal3D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &d,
Vector &y,
const int d1d = 0,
const int q1d = 0)
{
constexpr int DIM = 3;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= MD1, "");
MFEM_VERIFY(Q1D <= MQ1, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Q = Reshape(d.Read(), Q1D*Q1D*Q1D, 6, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, D1D, 3, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double QQD[MQ1][MQ1][MD1];
double QDD[MQ1][MD1][MD1];
for (int i = 0; i < DIM; ++i)
{
for (int j = 0; j < DIM; ++j)
{
// first tensor contraction, along z direction
for (int qx = 0; qx < Q1D; ++qx)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int dz = 0; dz < D1D; ++dz)
{
QQD[qx][qy][dz] = 0.0;
for (int qz = 0; qz < Q1D; ++qz)
{
const int q = qx + (qy + qz * Q1D) * Q1D;
const int k = j >= i ?
3 - (3-i)*(2-i)/2 + j:
3 - (3-j)*(2-j)/2 + i;
const double O = Q(q,k,e);
const double Bz = B(qz,dz);
const double Gz = G(qz,dz);
const double L = i==2 ? Gz : Bz;
const double R = j==2 ? Gz : Bz;
QQD[qx][qy][dz] += L * O * R;
}
}
}
}
// second tensor contraction, along y direction
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dz = 0; dz < D1D; ++dz)
{
for (int dy = 0; dy < D1D; ++dy)
{
QDD[qx][dy][dz] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
const double By = B(qy,dy);
const double Gy = G(qy,dy);
const double L = i==1 ? Gy : By;
const double R = j==1 ? Gy : By;
QDD[qx][dy][dz] += L * QQD[qx][qy][dz] * R;
}
}
}
}
// third tensor contraction, along x direction
for (int dz = 0; dz < D1D; ++dz)
{
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
double temp = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
const double Bx = B(qx,dx);
const double Gx = G(qx,dx);
const double L = i==0 ? Gx : Bx;
const double R = j==0 ? Gx : Bx;
temp += L * QDD[qx][dy][dz] * R;
}
Y(dx, dy, dz, 0, e) += temp;
Y(dx, dy, dz, 1, e) += temp;
Y(dx, dy, dz, 2, e) += temp;
}
}
}
}
}
});
}
static void PAVectorDiffusionAssembleDiagonal(const int dim,
const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &G,
const Vector &op,
Vector &y)
{
if (dim == 2)
{
return PAVectorDiffusionDiagonal2D(NE, B, G, op, y, D1D, Q1D);
}
else if (dim == 3)
{
return PAVectorDiffusionDiagonal3D(NE, B, G, op, y, D1D, Q1D);
}
MFEM_ABORT("Dimension not implemented.");
}
void VectorDiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
{
if (DeviceCanUseCeed())
{
ceedOp->GetDiagonal(diag);
}
else
{
PAVectorDiffusionAssembleDiagonal(dim, dofs1D, quad1D, ne,
maps->B, maps->G,
pa_data, diag);
}
}
// PA Diffusion Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0, int T_VDIM = 0> static
void PAVectorDiffusionApply2D(const int NE,
@@ -252,7 +451,7 @@ void PAVectorDiffusionApply2D(const int NE,
auto D = Reshape(d_.Read(), Q1D*Q1D, 3, NE);
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -373,7 +572,7 @@ void PAVectorDiffusionApply3D(const int NE,
auto op = Reshape(op_.Read(), Q1D*Q1D*Q1D, 6, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, VDIM, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, VDIM, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -581,212 +780,4 @@ void VectorDiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
}
}
template<int T_D1D = 0, int T_Q1D = 0>
static void PAVectorDiffusionDiagonal2D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &d,
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 <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
// note the different shape for D, this is a (symmetric) matrix so we only
// store necessary entries
auto D = Reshape(d.Read(), Q1D*Q1D, 3, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, 2, NE);
MFEM_FORALL(e, NE,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
// gradphi \cdot Q \gradphi has four terms
double QD0[MQ1][MD1];
double QD1[MQ1][MD1];
double QD2[MQ1][MD1];
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dy = 0; dy < D1D; ++dy)
{
QD0[qx][dy] = 0.0;
QD1[qx][dy] = 0.0;
QD2[qx][dy] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
const int q = qx + qy * Q1D;
const double D0 = D(q,0,e);
const double D1 = D(q,1,e);
const double D2 = D(q,2,e);
QD0[qx][dy] += B(qy, dy) * B(qy, dy) * D0;
QD1[qx][dy] += B(qy, dy) * G(qy, dy) * D1;
QD2[qx][dy] += G(qy, dy) * G(qy, dy) * D2;
}
}
}
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
double temp = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
temp += G(qx, dx) * G(qx, dx) * QD0[qx][dy];
temp += G(qx, dx) * B(qx, dx) * QD1[qx][dy];
temp += B(qx, dx) * G(qx, dx) * QD1[qx][dy];
temp += B(qx, dx) * B(qx, dx) * QD2[qx][dy];
}
Y(dx,dy,0,e) += temp;
Y(dx,dy,1,e) += temp;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void PAVectorDiffusionDiagonal3D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &d,
Vector &y,
const int d1d = 0,
const int q1d = 0)
{
constexpr int DIM = 3;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
MFEM_VERIFY(D1D <= MD1, "");
MFEM_VERIFY(Q1D <= MQ1, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Q = Reshape(d.Read(), Q1D*Q1D*Q1D, 6, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, D1D, 3, NE);
MFEM_FORALL(e, NE,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double QQD[MQ1][MQ1][MD1];
double QDD[MQ1][MD1][MD1];
for (int i = 0; i < DIM; ++i)
{
for (int j = 0; j < DIM; ++j)
{
// first tensor contraction, along z direction
for (int qx = 0; qx < Q1D; ++qx)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int dz = 0; dz < D1D; ++dz)
{
QQD[qx][qy][dz] = 0.0;
for (int qz = 0; qz < Q1D; ++qz)
{
const int q = qx + (qy + qz * Q1D) * Q1D;
const int k = j >= i ?
3 - (3-i)*(2-i)/2 + j:
3 - (3-j)*(2-j)/2 + i;
const double O = Q(q,k,e);
const double Bz = B(qz,dz);
const double Gz = G(qz,dz);
const double L = i==2 ? Gz : Bz;
const double R = j==2 ? Gz : Bz;
QQD[qx][qy][dz] += L * O * R;
}
}
}
}
// second tensor contraction, along y direction
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dz = 0; dz < D1D; ++dz)
{
for (int dy = 0; dy < D1D; ++dy)
{
QDD[qx][dy][dz] = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
const double By = B(qy,dy);
const double Gy = G(qy,dy);
const double L = i==1 ? Gy : By;
const double R = j==1 ? Gy : By;
QDD[qx][dy][dz] += L * QQD[qx][qy][dz] * R;
}
}
}
}
// third tensor contraction, along x direction
for (int dz = 0; dz < D1D; ++dz)
{
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
double temp = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
const double Bx = B(qx,dx);
const double Gx = G(qx,dx);
const double L = i==0 ? Gx : Bx;
const double R = j==0 ? Gx : Bx;
temp += L * QDD[qx][dy][dz] * R;
}
Y(dx, dy, dz, 0, e) += temp;
Y(dx, dy, dz, 1, e) += temp;
Y(dx, dy, dz, 2, e) += temp;
}
}
}
}
}
});
}
static void PAVectorDiffusionAssembleDiagonal(const int dim,
const int D1D,
const int Q1D,
const int NE,
const Array<double> &B,
const Array<double> &G,
const Vector &op,
Vector &y)
{
if (dim == 2)
{
return PAVectorDiffusionDiagonal2D(NE, B, G, op, y, D1D, Q1D);
}
else if (dim == 3)
{
return PAVectorDiffusionDiagonal3D(NE, B, G, op, y, D1D, Q1D);
}
MFEM_ABORT("Dimension not implemented.");
}
void VectorDiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
{
if (DeviceCanUseCeed())
{
ceedOp->GetDiagonal(diag);
}
else
{
PAVectorDiffusionAssembleDiagonal(dim,
dofs1D,
quad1D,
ne,
maps->B,
maps->G,
pa_data,
diag);
}
}
} // namespace mfem
@@ -9,17 +9,13 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
using namespace std;
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
namespace mfem
{
// PA Divergence Integrator
// PA Divergence Assemble 2D kernel
static void PADivergenceSetup2D(const int Q1D,
const int NE,
@@ -33,7 +29,7 @@ static void PADivergenceSetup2D(const int Q1D,
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
auto y = Reshape(op.Write(), NQ, 2, 2, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
for (int q = 0; q < NQ; ++q)
{
@@ -62,7 +58,7 @@ static void PADivergenceSetup3D(const int Q1D,
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
auto y = Reshape(op.Write(), NQ, 3, 3, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
for (int q = 0; q < NQ; ++q)
{
@@ -183,7 +179,7 @@ static void PADivergenceApply2D(const int NE,
auto op = Reshape(op_.Read(), Q1D*Q1D, 2,2, NE);
auto x = Reshape(x_.Read(), TR_D1D, TR_D1D, 2, NE);
auto y = Reshape(y_.ReadWrite(), TE_D1D, TE_D1D, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
@@ -321,7 +317,7 @@ static void PADivergenceApplyTranspose2D(const int NE,
auto op = Reshape(op_.Read(), Q1D*Q1D, 2,2, NE);
auto x = Reshape(x_.Read(), TE_D1D, TE_D1D, NE);
auto y = Reshape(y_.ReadWrite(), TR_D1D, TR_D1D, 2, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
@@ -437,7 +433,7 @@ static void PADivergenceApply3D(const int NE,
auto op = Reshape(op_.Read(), Q1D*Q1D*Q1D, 3,3, NE);
auto x = Reshape(x_.Read(), TR_D1D, TR_D1D, TR_D1D, 3, NE);
auto y = Reshape(y_.ReadWrite(), TE_D1D, TE_D1D, TE_D1D, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
@@ -620,7 +616,7 @@ static void PADivergenceApplyTranspose3D(const int NE,
auto op = Reshape(op_.Read(), Q1D*Q1D*Q1D, 3,3, NE);
auto x = Reshape(x_.Read(), TE_D1D, TE_D1D, TE_D1D, NE);
auto y = Reshape(y_.ReadWrite(), TR_D1D, TR_D1D, TR_D1D, 3, NE);
MFEM_FORALL(e, NE,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
@@ -801,7 +797,7 @@ static void SmemPADivergenceApply3D(const int NE,
auto x = Reshape(x_.Read(), TR_D1D, TR_D1D, TR_D1D, 3, NE);
auto y = Reshape(y_.ReadWrite(), TE_D1D, TE_D1D, TE_D1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
constexpr int VDIM = 3;
const int tidz = MFEM_THREAD_ID(z);
@@ -1040,11 +1036,25 @@ static void PADivergenceApply(const int dim,
{
if (dim == 2)
{
return PADivergenceApply2D(NE,B,G,Bt,op,x,y,TR_D1D,TE_D1D,Q1D);
if (transpose)
{
return PADivergenceApplyTranspose2D(NE,B,G,Bt,op,x,y,TR_D1D,TE_D1D,Q1D);
}
else
{
return PADivergenceApply2D(NE,B,G,Bt,op,x,y,TR_D1D,TE_D1D,Q1D);
}
}
if (dim == 3)
{
return PADivergenceApply3D(NE,B,G,Bt,op,x,y,TR_D1D,TE_D1D,Q1D);
if (transpose)
{
return PADivergenceApplyTranspose3D(NE,B,G,Bt,op,x,y,TR_D1D,TE_D1D,Q1D);
}
else
{
return PADivergenceApply3D(NE,B,G,Bt,op,x,y,TR_D1D,TE_D1D,Q1D);
}
}
MFEM_ABORT("Unknown kernel.");
}

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