Compare commits

...
Author SHA1 Message Date
Tom Stitt cf1c58ee1c Merge remote-tracking branch 'origin/hypre-runtime-compute-policy' into apps-dev 2023-10-27 09:22:16 -07:00
Tom Stitt 02579a1d23 Merge remote-tracking branch 'origin/feature/askinner/hdiv-saddle-point-solver' into apps-dev 2023-10-27 09:22:12 -07:00
Tom Stitt 66d9ead7b1 Merge remote-tracking branch 'origin/master' into hypre-runtime-compute-policy 2023-10-27 09:03:44 -07:00
Tzanio Kolev da351da0e3 Merge pull request #3932 from mfem/hughcars/square-aggregation-dev
Add square option to AggregrateError for derefinement
2023-10-25 19:50:06 -07:00
Tzanio Kolev fba3262eb9 Merge pull request #3912 from mfem/globalvec-minor-fix
Minor fix in `HypreParVector::GlobalVector()`
2023-10-25 19:49:28 -07:00
Tzanio Kolev b9d950aa9a Merge pull request #3917 from mfem/sjg/file-permissions-fix
Fix file permissions
2023-10-25 19:49:06 -07:00
Tzanio Kolev bc0153079a Merge pull request #3930 from mfem/sundials-matgetid-fix
fix typo for MatGetID
2023-10-24 07:58:59 -07:00
Aaron Skinner 2ebe366a38 Patches provided by Will Pazner, necessary for saddle point solver to work 2023-10-23 14:06:00 -07:00
Tzanio Kolev 2e3edffa1b Merge pull request #3774 from mfem/sjg/fecoll-vdim-fix
Add `FiniteElementCollection::GetVDim` in order to fix a bug with AMS when using `ND_R1D_FECollection` or `ND_R2D_FECollection`
2023-10-21 14:57:01 -07:00
Hugh Carson 291c9bce21 Merge branch 'master' into hughcars/square-aggregation-dev 2023-10-20 16:14:20 -04:00
Tzanio Kolev a6a31ff1f7 Merge pull request #3869 from mfem/lf-constructor-fix
Copy all marker arrays when constructing LinearForm with integrators from another LinearForm [lf-constructor-fix]
2023-10-20 11:17:47 -07:00
Tzanio Kolev b5e67a7ee6 Merge pull request #3908 from mfem/sjg/intrules-order-fix
Fix integration rule order for prisms for failing check
2023-10-20 11:16:45 -07:00
Hugh Carson 4fc694b72d make style 2023-10-20 10:15:38 -04:00
Hugh Carson d47b4349a6 Square the initial correctly 2023-10-20 10:14:38 -04:00
Hugh Carson c5542b8b28 make style 2023-10-20 09:39:20 -04:00
Hugh Carson acbf109a23 Fix errors from review 2023-10-20 09:37:44 -04:00
Sebastian Grimberg 8e5c8e0148 Fix bug where auxiliary space order was too low for AMS in 1D 2023-10-19 12:31:15 -07:00
hughcars f95a285c3f Merge branch 'master' into hughcars/square-aggregation-dev 2023-10-18 14:42:04 -04:00
Tzanio Kolev 25b98cc8ab Merge pull request #3910 from mfem/typos
Typos
2023-10-17 18:16:47 -07:00
Hugh Carson f23de626fe Add option to accumulate error via square 2023-10-16 14:36:29 -04:00
Will Pazner 2035b22945 Merge pull request #3903 from mfem/sjg/kdtree-fix-gcc-13
Fix missing <cstdint> include for new GCC versions
2023-10-16 10:27:25 -07:00
Julian Andrej ac31d70c95 fix typo for MatGetID 2023-10-13 12:48:27 -07:00
stefanhenneking d37b743d71 minor fix in GlobalVector 2023-10-05 12:40:24 -05:00
Brendan Keith 77dc5cff7b fix typos 2023-10-04 21:19:56 -04:00
Sebastian Grimberg 88d182e6c5 Fix file permissions 2023-10-04 08:55:58 -07:00
Andreas Schafelner 2e2f30b9df Copy the pointers to the interior face integs. 2023-10-04 08:00:24 +02:00
Sebastian Grimberg 5ad603eba1 Merge branch 'master' into sjg/fecoll-vdim-fix 2023-10-03 08:04:24 -07:00
Sebastian Grimberg aedf61d97e Fix integration rule order for prisms for failing MFEM_VERIFY 2023-10-02 19:49:18 -07:00
Sebastian Grimberg 2e77bdde72 Revert "Add missing <cstdint> for ParMesh and NCMesh files as well"
This reverts commit 2fb67e5cb5.
2023-10-02 13:06:34 -07:00
Sebastian Grimberg 2fb67e5cb5 Add missing <cstdint> for ParMesh and NCMesh files as well 2023-10-02 13:06:26 -07:00
Sebastian Grimberg 19f30e814d Fix missing <cstdint> include for new GCC versions 2023-10-02 13:06:26 -07:00
Will Pazner c0867ca009 Merge pull request #3902 from mfem/sjg/github-ci-fix
Free up disk space to resolve CI errors in test builds
2023-10-02 12:29:44 -07:00
Sebastian Grimberg b8fb0faba9 Pin version of easimon/maximize-build-space workflow 2023-10-02 08:38:42 -07:00
Sebastian Grimberg 7fe7c9ef2a Only run disk space cleaner on Ubuntu 2023-09-29 07:10:57 -07:00
Sebastian Grimberg 8fa61fa729 Fix YAML file indentation for CI workflow files 2023-09-29 07:07:00 -07:00
Sebastian Grimberg ffc7c2429c Free up disk space to resolve CI errors in test builds 2023-09-29 07:05:26 -07:00
Sebastian Grimberg 947a0d7393 Merge branch 'master' into sjg/fecoll-vdim-fix 2023-09-28 14:43:53 -04:00
Tzanio Kolev 89caa3ac6d Merge pull request #3900 from mfem/new-dev-version-4.6.1
Update version numbers to 4.6.1 -- a new development version
2023-09-28 10:14:52 -07:00
Veselin Dobrev 0e5adc7a7c Update version numbers to 4.6.1 -- a new development version 2023-09-28 10:02:16 -07:00
Tzanio Kolev 69fbae732d Merge pull request #3841 from mfem/mfem-4.6-dev
Final changes for mfem-4.6
2023-09-27 14:17:30 -07:00
Tzanio Kolev 8600da6132 Merge branch 'mfem-4.6-dev' of github.com:mfem/mfem into mfem-4.6-dev 2023-09-27 10:05:12 -07:00
Tzanio Kolev 79c20c20ce Fixes for nvcc 2023-09-27 10:04:45 -07:00
Veselin Dobrev a37cdb880c Merge branch 'master' into mfem-4.6-dev 2023-09-27 09:44:31 -07:00
Veselin Dobrev 29603ec34e Merge pull request #3843 from mfem/sjg/par-tet-mesh-fix
Fix regression bugs associated with parallel tetrahedral meshes from #2920
2023-09-27 09:41:33 -07:00
Tzanio Kolev ff9892579d Speed-up testing of nurbs_patch_ex1 2023-09-27 09:24:45 -07:00
Tzanio Kolev 73708f6583 CHANGELOG rewording 2023-09-27 08:51:55 -07:00
Tzanio Kolev 4d4696e4bd Updated CHANGELOG 2023-09-27 08:49:08 -07:00
Tzanio Kolev 5beb289dc8 Merge branch 'master' into mfem-4.6-dev 2023-09-27 08:38:44 -07:00
Tzanio Kolev 6a9b3b5433 Merge pull request #3325 from mfem/kdtree
Kdtree
2023-09-27 08:37:07 -07:00
Tzanio Kolev a5f437cf40 Merge pull request #3894 from mfem/intrules-order-fix
Fix the order initialization of some lazy-constructed integration rules
2023-09-27 08:36:22 -07:00
Veselin Dobrev 464c44689a Fix HIP build issue from PR 3662 (it was not tested with HIP!) 2023-09-26 23:35:19 -07:00
Veselin Dobrev 709f7c8405 Run 'make style' 2023-09-26 14:10:02 -07:00
Veselin Dobrev a2ee2da080 Merge branch 'master' into mfem-4.6-dev 2023-09-26 13:59:47 -07:00
Mark L. Stowell b74430bfce Merge pull request #3667 from mfem/fespace-delete-l2f
Fix potential UniformRefinement segfault
2023-09-26 13:16:44 -07:00
Mark L. Stowell b682477fd4 Merge branch 'master' into fespace-delete-l2f 2023-09-26 13:15:08 -07:00
blaz b3745da37e Merge branch 'kdtree' of github.com:mfem/mfem into kdtree 2023-09-26 13:05:42 -07:00
blaz 046a93babc style changes 2023-09-26 13:05:07 -07:00
Boyan LazarovandTzanio Kolev d007267e90 Update miniapps/tools/nodal-transfer.cpp
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2023-09-26 12:11:47 -07:00
Boyan LazarovandTzanio Kolev 67bfd4b188 Update CHANGELOG
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2023-09-26 12:11:36 -07:00
Boyan LazarovandTzanio Kolev 2bf967ae3e Update miniapps/tools/nodal-transfer.cpp
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2023-09-26 12:11:19 -07:00
Veselin Dobrev 67b1d10200 Merge pull request #3662 from mfem/vector-sum-gpu
Vector::Sum on device
2023-09-26 12:08:52 -07:00
Mark L. Stowell e381583f07 Merge branch 'master' into fespace-delete-l2f 2023-09-26 11:42:30 -07:00
blaz ecca887d3f Merge branch 'master' into kdtree 2023-09-26 11:42:08 -07:00
blaz 890df6291d final fixes 2023-09-26 11:32:05 -07:00
blaz 79e7d8b431 Merge branch 'sjg/kdtree' into kdtree 2023-09-26 11:09:11 -07:00
Tzanio Kolev 2c31ce6ace Merge pull request #3896 from mfem/sjg/docker-ci-fix-2
Another attempt to fix Docker builds in CI
2023-09-26 11:02:17 -07:00
Veselin DobrevandWill Pazner a7042fc866 Update fem/intrules.cpp
Reviewer suggestion

Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2023-09-26 10:29:25 -07:00
Tzanio Kolev 23f1b902e5 CHANGELOG rewording 2023-09-26 09:52:17 -07:00
Tzanio Kolev f18c31f9c9 Merge branch 'master' into sjg/kdtree 2023-09-26 09:32:34 -07:00
Will Pazner 4584142974 Update CHANGELOG 2023-09-26 09:28:29 -07:00
Will Pazner 9529062888 Remove unused template parameters 2023-09-26 09:28:08 -07:00
Tzanio Kolev 5c7fb27a42 Merge branch 'master' into kdtree 2023-09-26 09:18:17 -07:00
Sebastian Grimberg 8f7953389a Merge branch 'master' into sjg/fecoll-vdim-fix 2023-09-26 08:42:18 -07:00
Tzanio Kolev afcca4036c Clean-up pass through new examples and miniapps 2023-09-26 08:36:59 -07:00
Sebastian Grimberg cf44dca835 Revert WIP 42bf7887 after testing completed 2023-09-26 07:10:12 -07:00
Sebastian Grimberg 60be5ca073 Another attempt to resolve Docker CI builds, using easimon/maximize-build-space instead of rse-ops/actions-cleaner 2023-09-26 06:58:25 -07:00
Sebastian Grimberg 42bf788749 WIP: Test out container build CI workflow in PR 2023-09-26 06:51:08 -07:00
Tzanio Kolev 2ac34161ea Merge branch 'master' into mfem-4.6-dev 2023-09-26 05:54:06 -07:00
Tzanio Kolev 8eee277b98 Merge pull request #3722 from mfem/max-q1d-d1d-cpu
Increase MAX_D1D, MAX_Q1D, etc. when target is CPU
2023-09-26 05:40:18 -07:00
Tzanio Kolev d4b8975a86 Merge pull request #3797 from mfem/tic-toc
Minor StopWatch changes
2023-09-26 05:39:45 -07:00
Veselin Dobrev ff0ea61aad Fix unused variable warning in non-debug mode 2023-09-25 17:12:27 -07:00
Tzanio Kolev ce649af7e3 Merge pull request #3880 from mfem/sjg/docker-ci-fix
Fix Docker builds in CI
2023-09-25 16:17:01 -07:00
Veselin Dobrev 1395b526b2 Separate tests into sections for separate testing and reporting 2023-09-25 15:52:36 -07:00
Veselin Dobrev 2fd40f22bf Fix the initialization of the order of some integration rules that
are lazy-constructed. Add a simply unit test to check for that.

Reported-by: Aaron Skinner <aaronskinner@users.noreply.github.com>
2023-09-25 15:31:17 -07:00
Tzanio Kolev 0913a510d2 Typos and fixes 2023-09-25 13:59:15 -07:00
Will Pazner c80186ceca Remove unused template parameters 2023-09-25 13:03:21 -07:00
Will Pazner b89295dec7 Simplify expressions (SMEM is false in the conditional) 2023-09-25 13:03:14 -07:00
Sebastian Grimberg 08c3a12b9e Fix regression bugs associated with parallel tetrahedral meshes from #2920 2023-09-25 12:38:00 -07:00
Will Pazner e99e753e96 Fix D1D/Q1D typo 2023-09-25 12:18:40 -07:00
Will Pazner 47f69b7b2b Formatting 2023-09-25 12:17:20 -07:00
Will Pazner 408bec38d4 Fix typos (Q1D was mistakenly replaced by D1D) 2023-09-25 12:10:20 -07:00
Tzanio Kolev de9171ceb5 Merge branch 'master' into mfem-4.6-dev
Conflicts:
	CHANGELOG
2023-09-25 12:05:20 -07:00
Tzanio Kolev 555fe133a0 Updated CHANGELOG for mfem-4.6 2023-09-25 12:00:35 -07:00
Mark L. Stowell 28e7d2301d Merge branch 'master' into fespace-delete-l2f 2023-09-25 11:18:58 -07:00
Veselin Dobrev e9b52d4556 Merge pull request #3400 from mfem/efem-topopt
Topology optimization
2023-09-25 11:17:09 -07:00
Veselin Dobrev 7cdbe94131 Merge pull request #3570 from mfem/face-qfunction-coefficient
Fix face quadrature function coefficient evaluation
2023-09-25 11:15:08 -07:00
Mark L. Stowell ee26296db2 Merge branch 'master' into fespace-delete-l2f 2023-09-25 11:13:00 -07:00
Tzanio Kolev 743ba622dd Merge branch 'master' into mfem-4.6-dev 2023-09-25 11:09:08 -07:00
Veselin Dobrev 4482235f80 Merge pull request #3600 from mfem/ad_fix
Fix for using std:: in the dual numbers
2023-09-25 11:06:35 -07:00
Tzanio Kolev 6d81b467c2 Merge pull request #3792 from mfem/pa-markers
Support markers with partial assembly
2023-09-24 19:03:54 -07:00
Tzanio Kolev 89c8ff0281 Merge pull request #3821 from mfem/restriction-transpose-bugfix
Fix bug in FiniteElementSpace::GetRestrictionTransposeOperator
2023-09-24 19:00:27 -07:00
Tzanio Kolev 6fd19e578e Merge pull request #3768 from mfem/stefanozampini/petschip
Support PETSc + HIP
2023-09-24 18:58:02 -07:00
Tzanio Kolev 6dd0d056f4 MFEM in Homebrew 2023-09-24 18:15:52 -07:00
Brendan KeithandVeselin Dobrev a3f0f89512 Update examples/ex37p.cpp
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2023-09-19 14:25:12 -04:00
Sebastian Grimberg 8c0cdd51c2 Use https://github.com/rse-ops/actions-cleaner to free up space for Docker builds 2023-09-19 10:29:31 -07:00
Veselin Dobrev 21eed0fdf3 In the PETSc CMake file, add all rc_* files 2023-09-19 09:28:41 -07:00
Tzanio Kolev d063a4a02e Merge pull request #3857 from mfem/fix-connect-boundaries3d
Fix check in NURBSExtension::ConnectBoundaries3D [fix-connect-boundaries3d]
2023-09-19 05:36:22 -07:00
Tzanio Kolev 8a9ca13855 Merge pull request #3871 from mfem/psubmesh-test-fix
ParSubMesh bug fixes
2023-09-19 05:36:06 -07:00
Veselin Dobrev f2f96b1737 In the PETSc examples CMake file, add tests that were missing compared
to the GNU makefile.
2023-09-18 14:56:13 -07:00
Brendan Keith 7357444a84 update tests for example 37 2023-09-18 17:05:09 -04:00
Sebastian Grimberg 0a704c61ba Move KDTreeNodalProjection into fem/kdtree.hpp and fem/kdtree.cpp, and some other final style consistency changes 2023-09-18 10:28:25 -07:00
Will Pazner 86ec2bfa8d In 1D ParSubMesh, make sure group_stria and group_squad are initialized 2023-09-14 15:07:50 -07:00
Will Pazner d1ffbfb046 Fixes to ParSubMesh boundary unit test 2023-09-14 15:07:50 -07:00
Will Pazner 15107fac43 Merge remote-tracking branch 'origin/master' into max-q1d-d1d-cpu
# Conflicts:
#	fem/qinterp/grad_by_nodes.cpp
#	fem/qinterp/grad_by_vdim.cpp
#	fem/qinterp/grad_phys_by_nodes.cpp
#	fem/qinterp/grad_phys_by_vdim.cpp
2023-09-14 10:40:26 -07:00
Tzanio Kolev 664dfa2f62 Merge pull request #3827 from mfem/quadinterp-surface-phys-deriv
Support surface meshes in QuadratureInterpolator physical derivatives
2023-09-14 09:29:12 -07:00
Tzanio Kolev 91378528ab Merge pull request #3803 from mfem/fix-nurbs-eldof-table
Fix GenerateElementDofTable for parallel periodic nurbs  [fix-nurbs-eldof-table]
2023-09-14 09:25:23 -07:00
Tzanio Kolev 67579a973c Merge pull request #3859 from mfem/csl/bilinearform-vdofs-fix
Fix unfilled vdofs in BilinearForm::Assemble when element matrices are pre-computed
2023-09-14 09:24:17 -07:00
Will Pazner bb2ae08dd8 Merge remote-tracking branch 'origin/master' into restriction-transpose-bugfix 2023-09-13 13:21:15 -07:00
Andreas Schafelner a3e9ea0a66 Added copying the other marker arrays. 2023-09-13 11:15:18 +02:00
Will Pazner 6b5db0c503 Add linalg kernels::CalcLeftInverse 2023-09-12 11:55:15 -07:00
Will Pazner 7284dc092f Remove un-needed include 2023-09-12 11:54:58 -07:00
Sebastian Grimberg ba0f9bba88 Rename GetInterpDim -> GetRangeDim 2023-09-12 10:55:42 -07:00
Brendan Keith c1ca14ffd6 Merge branch 'master' into efem-topopt 2023-09-12 13:34:11 -04:00
Veselin Dobrev 584e5e6aeb Merge pull request #3614 from mfem/hiop-callback
Class for HiOp-specific interfaces
2023-09-12 09:27:33 -07:00
Veselin Dobrev 5199786617 Merge pull request #3461 from mfem/submesh-bdr-attr
Fix boundary attributes for 2D sub-meshes
2023-09-12 09:26:28 -07:00
Sebastian Grimberg a2557a37b2 Rename FiniteElementCollection::GetVDim (and FiniteElement::GetVDim) to GetInterpDim to avoid conflict with FiniteElementSpace::GetVDim 2023-09-11 12:03:11 -07:00
Sebastian Grimberg c8798d22bd Merge branch 'master' into sjg/fecoll-vdim-fix 2023-09-11 11:47:55 -07:00
blaz 2cb2fcd61c fixed different signedness: ‘int’ and ‘long unsigned int’ 2023-09-10 23:20:00 -07:00
blaz e922ec6de6 style 2023-09-10 22:56:09 -07:00
blaz 15fcaa5fde fixed compilation issue 2023-09-10 22:53:28 -07:00
blaz b5a9129c90 templated the nodal transfer class 2023-09-10 20:44:13 -07:00
Tzanio Kolev 71b056fd5d Merge branch 'master' into mfem-4.6-dev 2023-09-10 13:12:52 -07:00
Tzanio Kolev 3358309208 Merge branch 'master' into stefanozampini/petschip 2023-09-10 12:57:45 -07:00
blaz 921997412b Merge branch 'master' into kdtree 2023-09-08 20:10:04 -07:00
Veselin DobrevandSatish Balay b8108379d7 In INSTALL, small tweak in the PETSc section.
Co-authored-by: Satish Balay <balay@users.noreply.github.com>
2023-09-07 13:58:28 -07:00
Veselin Dobrev a0d8349dda In INSTALL, specify a minimum PETSc version for PETSc+HIP support.
Added CUDA/HIP to the labels (shown when running 'make test') of the
PETSc examples that use one of these devices.
2023-09-07 13:26:19 -07:00
Chak Shing Lee 0788205d88 fix unfilled vdofs in BilinearForm::Assemble when element matrices have been precomputed 2023-09-06 11:04:21 -07:00
Jacob Lotz 80891b26a3 Merge branch 'master' into fix-nurbs-eldof-table 2023-09-06 14:18:20 +02:00
JacobLotz c5f703a30b add test / sample run 2023-09-06 11:29:04 +02:00
JacobLotz 07189adb6d Fix knotvector index 2023-09-06 10:04:31 +02:00
Tzanio Kolev 64c8725594 Merge pull request #3831 from mfem/sjg/cuda-flags-cmake-fix
Fix `CMAKE_CUDA_FLAGS` flags for CMake build
2023-09-05 08:58:27 -07:00
Tzanio Kolev b57486e027 Merge pull request #3682 from mfem/tmop-lim-fit
TMOP - option to specify target positions for some nodes
2023-09-03 14:26:19 -07:00
Tzanio Kolev 5e0140e877 Merge pull request #3613 from mfem/getfe-fix
Remove NULL return in GetFE
2023-09-03 14:25:58 -07:00
Brendan Keith b5888d4b0f add incremental exit tolerance, update comments, make variable and functions names align more closely with the paper 2023-08-30 22:56:04 -04:00
Brendan Keith cda97a67bf Merge branch 'efem-topopt' of github.com:mfem/mfem into efem-topopt 2023-08-30 16:08:50 -04:00
Jacob Lotz c7722ef0f8 fix make testing 2023-08-30 15:50:09 +02:00
Jacob Lotz 181b5d5641 add tests and sample run 2023-08-30 14:38:05 +02:00
Jacob Lotz d651672f16 Copy mesh and add boundary numbering 2023-08-30 14:25:28 +02:00
Jacob Lotz 25568d690f Add periodic boundaries to parallel miniapp 2023-08-30 13:48:59 +02:00
Jacob Lotz 062217b9a9 Merge branch 'master' into fix-nurbs-eldof-table 2023-08-30 09:39:35 +02:00
Tom Stitt 4115a9ad5d handle more HYPRE_USING_{GPU,HIP,CUDA} 2023-08-29 21:16:35 -07:00
Brendan Keith c157638b00 Merge branch 'master' into efem-topopt 2023-08-29 19:14:50 -04:00
Brendan Keith b5ceaca56c minor 2023-08-29 13:59:48 -04:00
Brendan Keith 329cfb998c Update comments in the code. Estimate error in the L1 norm 2023-08-29 13:57:28 -04:00
Tzanio Kolev 1ccb31fde6 Merge pull request #3833 from mfem/actions-add-debug-tests
In GitHub actions, enable testing of debug builds under Ubuntu
2023-08-27 11:29:27 -07:00
Mittal, Ketan 1a0246734b merge with master and resolve conflicts 2023-08-25 17:41:40 -07:00
Tom Stitt a8cb5babce add support for runtime hypre compute policy 2023-08-25 14:36:14 -07:00
Brendan Keith 65ad6dcde4 Remove ResetFEM() 2023-08-25 17:14:14 -04:00
Brendan Keith d17320661b style 2023-08-25 17:00:45 -04:00
Brendan Keith ebddeb7597 delete pfes to avoid memory leak (properly) 2023-08-25 16:14:05 -04:00
Brendan Keith 89bfa3eda4 Merge branch 'efem-topopt' of github.com:mfem/mfem into efem-topopt 2023-08-25 14:21:20 -04:00
Brendan Keith cff7444f0a delete pfes to avoid memory leak 2023-08-25 14:21:11 -04:00
Mittal, Ketan a279b4592b reviewer comment 2023-08-24 20:11:01 -07:00
Mittal, Ketan 40b61f789e Merge branch 'master' of https://github.com/mfem/mfem into getfe-fix 2023-08-24 20:10:42 -07:00
Veselin Dobrev 82bd2cbf4c Initial changes for the v4.6 release 2023-08-24 13:44:12 -07:00
Brendan Keith d4d479ca7b Merge branch 'master' into efem-topopt 2023-08-24 13:29:38 -04:00
Veselin DobrevandWill Pazner 0933014721 Apply suggestions from code review
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2023-08-23 21:14:31 -07:00
Brendan Keith fc8477a265 remove clipping function, update sample runs, and change default mesh density 2023-08-23 18:20:02 -04:00
Tzanio Kolev c9e63c6292 Merge pull request #3557 from mfem/mpi_h1lor
Parallel H1 HO <-> LOR Transfer Operator
2023-08-22 15:53:34 -07:00
Tzanio Kolev 05442e17dc Merge pull request #3088 from mfem/nurbsquad
NURBS patch quadrature
2023-08-22 15:53:13 -07:00
Tzanio Kolev 27235c38ef Merge pull request #3404 from mfem/nurbs-auto-knot2edge-dev
Nurbs auto knot2edge and free patch orientation dev [nurbs-auto-knot2edge-dev]
2023-08-22 15:51:28 -07:00
Tzanio Kolev 5fc6ae6201 Merge pull request #3822 from mfem/qf-save-vtu
QuadratureFunction::SaveVTU fixes
2023-08-22 15:50:45 -07:00
Will Pazner 315065b727 Merge pull request #3789 from mfem/hughcars/gslib-shadow-variable
Fix shadow variable warning
2023-08-23 03:27:05 +09:00
Will Pazner 51adfe2785 Merge pull request #3829 from mfem/submesh-transfer-fix
Update `(Par)TransferMap` to support data on GPU by copying it to CPU
2023-08-23 03:26:53 +09:00
Brendan Keith 8519f3432f PR checklist 2023-08-21 14:33:35 -04:00
Brendan Keith cda099923d added paraview options 2023-08-21 11:34:06 -04:00
Brendan Keith 454a96e3b7 Merge branch 'master' into efem-topopt 2023-08-21 10:56:33 -04:00
Veselin Dobrev 7c6af8cab8 More changes to suppress gcc warnings when building with -Og and
older gcc versions.
2023-08-19 16:08:16 -07:00
Veselin Dobrev 397abc4190 Changes to suppress gcc warnings when building with -Og 2023-08-18 02:03:18 -07:00
Veselin Dobrev 680ccf0f2d In GitHub actions, add flag -Og for the debug builds that are tested
(under Ubuntu) to speed up the tests.
2023-08-17 20:30:49 -07:00
Veselin Dobrev e42f2cc32e Small CMake tweaks to fix faulty merge into 'next' (after re-merge) 2023-08-17 19:52:54 -07:00
Veselin Dobrev e4c0b956e8 In GitHub actions, enable testing of debug builds under Ubuntu 2023-08-17 19:26:04 -07:00
Sebastian Grimberg 135dfa983a Merge branch 'master' into sjg/fecoll-vdim-fix 2023-08-17 12:18:07 -07:00
Sebastian Grimberg 1844c93b14 Fix CMAKE_CUDA_FLAGS flags for CMake build 2023-08-17 10:28:30 -07:00
Vladimir Z Tomov 1d1443cb1a glvis option to fix autotest. 2023-08-16 09:31:08 -07:00
Mark L. Stowell a15866e212 Merge pull request #3709 from mfem/hughcars/prism-ncmesh-bug
Bug fixes for NC prism meshes
2023-08-15 20:10:57 -07:00
Vladimir Z Tomov 9baadbe00e gitignore 2023-08-15 14:04:15 -07:00
Mark L. Stowell 4222287b02 Merge branch 'master' into hughcars/prism-ncmesh-bug 2023-08-15 13:39:40 -07:00
Mark L. Stowell d46c2cd5a7 Merge pull request #3676 from mfem/hughcars/variable-length-arrays-of-length-zero-bug
Fix heap overflow from variable length arrays
2023-08-15 13:36:30 -07:00
Mark L. Stowell 5a2d286e0c Merge branch 'master' into hughcars/prism-ncmesh-bug 2023-08-15 11:30:57 -07:00
Mark L. Stowell d15f9136c5 Merge branch 'master' into hughcars/variable-length-arrays-of-length-zero-bug 2023-08-15 11:30:27 -07:00
Veselin Dobrev 5d50d96a7b Update (Par)TransferMap to support data on GPU by copying it to CPU.
This fixes issues when running ex34, ex34p, ex35p with device backends.
2023-08-14 18:39:07 -07:00
Vladimir Z Tomov edf209a78c better doxygen 2023-08-14 17:27:22 -07:00
Vladimir Z Tomov eb1a95acfd changelog. 2023-08-14 16:45:00 -07:00
Vladimir Z Tomov bee28f59f5 rename to fit-node-position.
added to makefile, CMakeLists.
2023-08-14 16:38:59 -07:00
Will Pazner 4d94ce5ac8 Add more QuadratureInterpolator unit tests 2023-08-14 17:44:14 +09:00
Will Pazner a0f5bd4e44 Support sdim != dim (surface meshes) in QuadratureInterpolator::PhysDerivatives 2023-08-14 17:44:12 +09:00
Will Pazner 84a101a745 Add 1D meshes embedded in 2D and 3D 2023-08-14 17:28:34 +09:00
Tzanio Kolev cbad53d9f9 Merge branch 'master' into nurbsquad 2023-08-12 09:43:54 -07:00
Tzanio Kolev bebdead740 Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-08-12 09:40:19 -07:00
Tzanio Kolev 1a5207f856 Merge pull request #3659 from mfem/nurbs-interp-fix-make
fix make file of nurbs-interp-dev [nurbs-interp-fix-make]
2023-08-12 06:53:42 -07:00
Tzanio Kolev be82bb8e6b Merge pull request #3798 from mfem/svd
SVD modified to solve linear systems
2023-08-12 06:52:48 -07:00
Tzanio Kolev 0c7fee782f Merge pull request #3817 from mfem/face-bdr-map-2d
Generalize Mesh::GetFaceToBdrElMap
2023-08-12 06:52:32 -07:00
Tzanio Kolev 0ba4fdc591 Merge pull request #3810 from mfem/opt-std-string
Support std::string in OptionsParser
2023-08-12 06:52:12 -07:00
Tzanio Kolev 300af9c231 Merge pull request #3769 from researchapps/update/docker-build-instructions
fix config/docker image instructions and dockerfiles
2023-08-12 06:51:52 -07:00
Vladimir Z Tomov 4a4b0062f8 verify compaatible ordering. 2023-08-11 18:42:48 -07:00
Vladimir Z Tomov aee4575404 Support of byVDIM ordering of the spaces + bug fix in CalcSurfaceFitErrors. 2023-08-11 18:22:57 -07:00
Brendan Keith 7bec37fe5b adjust glvis output and comments 2023-08-11 17:46:48 -04:00
Vladimir Z Tomov 834205ac04 Improved the tmop-lim-fit: allowed slipping on the non-marked boundaries. 2023-08-11 14:42:52 -07:00
Brendan Keith 37a7e5466b fix comments in ex37 2023-08-11 16:29:41 -04:00
Brendan Keith be168f4b78 fixing white space mistake 2023-08-11 16:24:55 -04:00
Brendan Keith 99af756462 update files 2023-08-11 16:12:42 -04:00
Brendan Keith 7f87b66763 deal with merge conflicts 2023-08-10 22:10:38 -04:00
Brendan Keith d68a188884 rename examples 2023-08-10 21:58:28 -04:00
Will Pazner df8b9928f8 Save QFields with correct name in VTU format 2023-08-09 22:04:47 -07:00
Will Pazner 3ad69e8e65 Support FaceQuadratureSpace in QuadratureFunction::SaveVTU 2023-08-09 22:04:17 -07:00
Will Pazner 8d19530dbb Use unique_ptr for owned restriction and prolongation operators 2023-08-09 14:53:24 -07:00
Will Pazner 809087f0c8 Check for null cR in GetConformingRestriction 2023-08-09 13:53:17 -07:00
Vladimir Z Tomov 057e25657e Fixed errors that Ketan pointed out. 2023-08-09 13:44:49 -07:00
Will Pazner 05c8569587 Fix memory leak for parallel nonconforming GetRestrictionTransposeOperator 2023-08-09 13:29:37 -07:00
Will Pazner 6432ff4d87 Add a unit test for FiniteElementSpace::GetRestrictionTransposeOperator 2023-08-09 12:57:12 -07:00
Will Pazner 94fb0f94c5 Fix shadow warning 2023-08-09 12:34:22 -07:00
Will Pazner f986b2022b Minor Doxygen formatting 2023-08-09 12:09:18 -07:00
Eric B. Chin 8806eec449 add doxygen comments 2023-08-09 11:55:31 -07:00
Will Pazner c1779a49cb Fix shadow warning 2023-08-09 11:37:17 -07:00
Will Pazner 472f2b83d2 Small changes to dual vector transfer in lor-transfer miniapps 2023-08-09 11:22:45 -07:00
Will Pazner d4d1eadb1a Avoid GetRestrictionTransposeOperator in L2ProjectionH1Space
See the bug fixed in PR #3821
2023-08-09 11:21:21 -07:00
Will Pazner 1a10217ba4 Move L2ProjectionH1Space::AllocR from private to protected 2023-08-09 11:20:21 -07:00
Will Pazner 65921a4dda make style 2023-08-09 11:20:01 -07:00
Will Pazner 1cf0ffbe03 Remove virtual destructor from L2ProjectionH1Space 2023-08-09 11:17:55 -07:00
Will Pazner 32432c2c19 Revert "add amr option to lor-transfer"
This reverts commit 3e1a24c35c.
2023-08-09 11:16:43 -07:00
Will Pazner c34e4b34f4 Bug fix in FiniteElementSpace::GetRestrictionTransposeOperator
The transpose of the restriction operator is not the prolongation operator (even
in serial). This can be seen, for example, on AMR meshes.

Also fixes a similar bug in BilinearForm::GetOutputRestrictionTranspose.
2023-08-09 11:10:28 -07:00
Vladimir Z Tomov 2fc92344bc Merge branch 'master' into tmop-lim-fit 2023-08-08 17:50:20 -07:00
Eric B. Chin 3e1a24c35c add amr option to lor-transfer 2023-08-08 14:49:26 -07:00
EB Chin aeacd50a40 fix dual field parallel transfers 2023-08-08 12:40:43 -07:00
Will Pazner edc138ebd5 Handle cases RA and RA in branch-history 2023-08-08 11:31:28 -07:00
Will Pazner c72b2aa658 Merge pull request #3787 from mfem/hughcars/fix-assigned-unused-var-warning
Fix warning from assigned and unused variables
2023-08-08 11:25:20 -07:00
Eric B. Chin 134af6f08f Merge pull request #3815 from mfem/mpi_h1lor_edits
Proposed changes to #3557
2023-08-08 09:48:13 -07:00
Will Pazner c2ed725739 Generalize Mesh::GetFaceToBdrElMap 2023-08-08 09:13:31 -07:00
JacobLotz 971eb7bb5f update changelog 2023-08-08 08:53:18 +02:00
Will Pazner c4dc57ffd2 Always perform copy in L2ProjectionH1Space GetTDofs and SetTDofs 2023-08-07 13:34:08 -07:00
Will Pazner 89f7d276ef Remove unused variables 2023-08-07 13:26:32 -07:00
Will Pazner cddbd24df3 Simplify mass computation in lor-transfer miniapps 2023-08-07 13:26:24 -07:00
Will Pazner 39714f039a Merge ParL2ProjectionH1Space with L2ProjectionH1Space 2023-08-07 13:26:06 -07:00
Will Pazner e42147f3a7 Simplify ParL2ProjectionH1Space 2023-08-07 11:14:40 -07:00
Jacob Lotz 79c1749e81 Merge branch 'master' into fix-nurbs-eldof-table 2023-08-07 10:29:37 +02:00
Tzanio Kolev f2f79aad84 Merge pull request #3804 from mfem/tmop-pa-3d-min-size-check-dev
Add Minimum Size Check to DiscreteAdaptTC::ComputeAllElementTargets Kernel [tmop-pa-3d-min-size-check-dev]
2023-08-06 14:01:22 -07:00
Will Pazner 62dc04c5ca Use std::string in ex0 and ex0p 2023-08-04 14:53:19 -07:00
Will Pazner fa101bcb05 Use std::string& instead of const char* in mesh API 2023-08-04 14:53:19 -07:00
Jacob Lotz 1eb679b9e1 Merge branch 'master' into nurbs-interp-fix-make 2023-08-04 09:37:03 +02:00
Will Pazner c770c80bf7 Allow std::string in OptionsParser 2023-08-03 19:42:44 -07:00
Eric B. Chin 100de86cfa add new miniapp and new feature 2023-08-01 22:14:22 -07:00
Eric B. Chin 7d2e402a08 fix style 2023-08-01 22:06:07 -07:00
Eric B. Chin c0dab30375 rename variables 2023-08-01 22:00:26 -07:00
EB Chin fdd1c6c8b4 simplify tdof method 2023-08-01 13:20:31 -07:00
Michael C Tyler Stees 1c3884f18a This commit updates the DiscreteAdaptTC::ComputeAllElementTargets kernel in tmop_pa_da3.cpp to use a given minimum size if one was provided. 2023-08-01 10:16:45 -07:00
JacobLotz 74caaf1c36 Fix parallel periodic nurbs issue 2023-08-01 17:04:31 +02:00
JacobLotz d70cb175e7 Small style improvement 2023-08-01 08:39:54 +02:00
Dylan Copeland 7c62434ef3 Minor 2023-07-31 20:50:34 -07:00
Dylan Copeland e18279782d Merge branch 'master' of github.com:mfem/mfem into nurbsquad 2023-07-31 20:17:42 -07:00
Dylan Copeland 90c13f0634 Fixing tests. 2023-07-31 18:44:53 -07:00
Backer 21889e22e4 Merge branch 'svd' of https://github.com/mfem/mfem into svd 2023-07-31 16:59:22 -07:00
Backer b9a3d1fffe Reverted the chage for the astyle binary in makefile 2023-07-31 16:58:43 -07:00
Backer b77c106d72 Style changes by make style 2023-07-31 16:58:09 -07:00
Dylan Copeland 994cdacff4 Reverting bug introduced in last commit. 2023-07-31 16:02:17 -07:00
Dylan Copeland c52da3dd57 Improved documentation. Changed NNLS verbosity to 0 in diffusion integrator. Added testing to miniapp makefile. Fixed some memory leaks. Decreased miniapp solver tolerance. 2023-07-31 15:12:34 -07:00
J-Pi 7c9f9b262d Merge branch 'master' into svd 2023-07-31 15:01:59 -07:00
Backer a759f32692 Made the style better 2023-07-31 14:51:53 -07:00
Backer 79b2967464 Tried to fix the style. 2023-07-31 14:27:40 -07:00
Backer d6aab14ec1 Corrected some more typos resulting in failed checks 2023-07-31 14:24:21 -07:00
Backer 69302c3ce7 Corrected typos resulting in failed checks 2023-07-31 14:16:44 -07:00
Backer 75e5bb2a7f Corrected typos resulting in failed checks 2023-07-31 14:04:34 -07:00
Backer 56eef31eb8 Merge branch 'svd' of https://github.com/mfem/mfem into svd 2023-07-31 12:42:14 -07:00
Backer abe702f5b8 Added documentation for the DenseMatrixSVD class. MArked the old constructors as deprecated as discussed with Vladimir. 2023-07-31 12:36:32 -07:00
Sebastian Grimberg c6521a189c Resolve issue from merge for AMS with lowest order RT_Trace_FECollection 2023-07-31 08:52:13 -07:00
JacobLotz 8a5b30ff71 fix issues after merge/solving conflicts 2023-07-31 17:41:51 +02:00
Jacob Lotz a9eb6ecc1a Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-07-31 16:56:24 +02:00
Sebastian Grimberg 530cd440d8 Merge branch 'master' into sjg/fecoll-vdim-fix 2023-07-30 18:18:10 -07:00
Tzanio Kolev 541f10f9b4 Merge pull request #3379 from mfem/submesh-nd-dev
SubMesh for Nedelec and Raviart-Thomas Bases
2023-07-29 16:44:54 -07:00
Eric B. Chin 98d96e5c99 Merge branch 'mpi_h1lor' of github.com:mfem/mfem into mpi_h1lor 2023-07-29 15:30:59 -07:00
Eric B. Chin f121373467 bugfixes 2023-07-29 15:30:51 -07:00
Tzanio Kolev 428f051e1c Merge branch 'master' into svd 2023-07-28 08:45:55 -07:00
Tzanio Kolev 117069efd4 Merge branch 'master' into stefanozampini/petschip 2023-07-28 08:42:58 -07:00
Tzanio Kolev bc441dab14 Merge branch 'master' into mpi_h1lor 2023-07-28 08:41:03 -07:00
Stowell, Mark L c00a10a54a Merge remote-tracking branch 'origin/master' into submesh-nd-dev
# Conflicts:
#	examples/CMakeLists.txt
#	examples/makefile
2023-07-28 08:39:57 -07:00
Stowell, Mark L 1e66469f5e Adding device examples as suggested by @v-dobrev 2023-07-28 08:37:02 -07:00
Tzanio Kolev d99c02cc82 Merge pull request #3398 from mfem/efem
Proximal Galerkin method for the obstacle problem
2023-07-27 18:46:40 -07:00
J-Pi d919149e5f Merge branch 'master' into svd 2023-07-27 16:36:29 -07:00
Backer 1ee6e88934 Added two constructers to the DenseMatrixSVD and to if to the DenseMatrixSVD::Eval so that it canbeused to solve a linear system. 2023-07-27 14:40:16 -07:00
Will Pazner 9f397bb6ce Merge pull request #3788 from mfem/sjg/libceed-hash-fix
Remove dependency on `ceed/hash.h` for newer libCEED versions
2023-07-27 13:55:52 -07:00
Will Pazner b4e7aecafe Use unique_ptr in StopWatch
This is a bug fix because previously StopWatch had the default copy constructor,
which results in a double free.
2023-07-27 10:53:40 -07:00
Will Pazner 448b2b1b2d Remove unneeded tic_toc.hpp include 2023-07-27 10:19:09 -07:00
Will Pazner ce7c02b1b1 Add StopWatch::Restart 2023-07-27 10:19:09 -07:00
Will Pazner 45613102e9 Edit Doxygen comments in StopWatch 2023-07-27 10:19:07 -07:00
Will Pazner 3776e6b2c2 Handle boundary elements that don't correspond to boundary faces in PA markers
This can happen when there are "interior" boundary elements, e.g. with periodic
meshes or for other visualization purposes.
2023-07-26 13:31:37 -07:00
Will Pazner 838a8a3dd3 Add unit test for PA with markers 2023-07-26 12:10:55 -07:00
Will Pazner f3227ebe89 Take into account markers in PA bilinear forms 2023-07-26 12:10:55 -07:00
Will Pazner 411a706e24 Add BilinearForm::GetDBFI_Marker 2023-07-26 12:00:05 -07:00
Brendan Keith 78859001fa Merge branch 'master' into efem 2023-07-25 06:55:48 -06:00
Brendan Keith e80c85b6bd arXiv info 2023-07-24 21:30:24 -06:00
Hugh Carson 76905b7496 Fix shadow variable warning 2023-07-21 14:50:41 -04:00
Sebastian Grimberg 3b9df69c78 Remove dependency on ceed/hash.h for newer libCEED versions 2023-07-21 11:17:58 -07:00
Hugh Carson afacf2f16d Fix warning from assigned and unused variables 2023-07-21 14:05:57 -04:00
Sebastian Grimberg 2ab8692165 Address PR feedback 2023-07-19 09:50:47 -07:00
Stefano Zampini 28aa4ebe26 PETSc: work with strict-petscerror configuration 2023-07-19 17:23:30 +02:00
Stefano Zampini d5a143ce0a Set device flag from x when not copying it 2023-07-19 17:00:45 +02:00
Stefano Zampini 6a9058665e Fix cleaning of PETSc rc_files 2023-07-19 17:00:45 +02:00
Stefano Zampini ef160a3fd0 Update CHANGELOG 2023-07-19 17:00:42 +02:00
Stefano Zampini 1d9865c681 PETSc: fix for HAVE_DEVICE true and no MFEM DEVICE 2023-07-19 16:59:49 +02:00
Stefano Zampini a003249bc6 PETSc examples makefile: clean rc_files 2023-07-19 16:59:48 +02:00
stefanozampini 2e987d7744 PetscMatrix: bind to cpu if device is now allowed 2023-07-19 16:59:48 +02:00
stefanozampini f280f02493 Disable SLEPC + HIP test 2023-07-19 16:59:48 +02:00
stefanozampini 1cb8697ad1 PETSc: add support for HIP 2023-07-19 16:59:48 +02:00
stefanozampini bae1d521ec PetscPCGSolver: wrap must be true! 2023-07-19 16:59:48 +02:00
Stowell, Mark L 69d174194e Reverting sample run to using single quotes 2023-07-18 11:18:37 -07:00
Brendan Keith a83cb7ada9 deal with makefile conflict 2023-07-14 17:20:49 -04:00
Brendan Keith 980956624b change obstacle problem example name to ex36 2023-07-14 17:15:27 -04:00
Stowell, Mark L 1b76a2ee5e Adding Hex test to test_ncmesh 2023-07-14 12:24:06 -07:00
Hugh Carson 5d2f112d1e Remove unneeded meshes 2023-07-14 11:50:38 -04:00
Hugh Carson a35c335bd7 Merge remote-tracking branch 'origin/master' into hughcars/prism-ncmesh-bug 2023-07-14 11:20:40 -04:00
Hugh Carson 5848987cf7 Add in variant switch for alternative wedge constructions 2023-07-14 11:20:24 -04:00
Eric B. Chin 2aa15a7ef0 address review comments 2023-07-13 17:54:33 -07:00
Stowell, Mark L 7417766c5e Normalizing error, automating mesh construction, and adding tetrahedron tests 2023-07-13 13:21:30 -07:00
Brendan Keith 906c2b7d4b PR Checklist: Update doc/CodeDocumentation.dox 2023-07-13 09:32:58 -04:00
Brendan Keith 9cffa519bd minor: extra white space 2023-07-13 08:22:04 -04:00
Brendan Keith 4630c8740d style 2023-07-13 07:23:27 -04:00
Brendan Keith a335d011a3 comments that I missed 2023-07-13 07:22:58 -04:00
Vladimir Z Tomov 22aae443b9 Merge branch 'master' into hiop-callback 2023-07-12 17:27:54 -07:00
Brendan Keith 8e324347fd remove unused variable 2023-07-12 17:13:10 -04:00
Brendan Keith 6ff57a8536 addressed final comments 2023-07-12 16:02:02 -04:00
Brendan Keith 68ead49c29 style 2023-07-12 14:58:31 -04:00
Brendan Keith 2239958635 Merge branch 'efem' of github.com:mfem/mfem into efem 2023-07-12 14:58:04 -04:00
Brendan Keith 4694446565 address all but two of Socratis's comments 2023-07-12 14:57:58 -04:00
Brendan Keith de44392452 Merge branch 'master' into efem 2023-07-11 23:13:23 -04:00
Mark L. Stowell 9ef9f3c271 Merge branch 'master' into hughcars/variable-length-arrays-of-length-zero-bug 2023-07-11 16:38:23 -07:00
Mittal, Ketan 037031bae6 minor 2023-07-11 13:15:53 -07:00
Mittal, Ketan fc13314a10 update CHANGELOG, fespace.hpp, and abort message to indicate change in behavior of GetFE 2023-07-11 13:05:48 -07:00
Mittal, Ketan f0a5e74bab Merge branch 'master' of https://github.com/mfem/mfem into getfe-fix 2023-07-11 12:23:08 -07:00
Sebastian Grimberg cfeb3e51b6 make style 2023-07-11 12:13:13 -07:00
Sebastian Grimberg 6afb81b41c Fix AMS for trace FE spaces 2023-07-11 12:11:45 -07:00
Brendan Keith b4d97133f9 rename disk-nurbs-unit.mesh to disc-nurbs-unit.mesh to match spelling of disc-nurbs.mesh 2023-07-11 15:06:42 -04:00
Brendan Keith bd24892a91 rename mesh file and check that sample runs are named properly 2023-07-11 14:34:40 -04:00
Vladimir Z Tomov 91199ccb6c Merge branch 'master' into tmop-lim-fit 2023-07-11 11:18:30 -07:00
Sebastian Grimberg e034066a09 Fix bug for AMS solver when vector dimension is not equal to space dimension, as is the case for the ND_R1D_FECollection or ND_R2D_FECollection classes 2023-07-11 09:56:12 -07:00
Sebastian Grimberg 9ac053ce28 Formatting consistency and use of override for FiniteElementCollection methods 2023-07-11 09:55:35 -07:00
Sebastian Grimberg 5946cd62fd Add FiniteElementCollection::GetVDim which returns the vector dimension for vector-valued finite elements 2023-07-11 09:55:35 -07:00
Hugh Carson 72bfdbc906 Merge remote-tracking branch 'origin/master' into hughcars/prism-ncmesh-bug 2023-07-10 15:22:52 -04:00
Hugh Carson a93c20c5ad Merge remote-tracking branch 'origin/master' into hughcars/variable-length-arrays-of-length-zero-bug 2023-07-10 15:22:26 -04:00
Eric B. Chin 2103b7ea8c Merge branch 'master' into mpi_h1lor 2023-07-08 17:43:15 -07:00
Stowell, Mark L c286f60ad0 Testing alternate means of providing options requiring multiple values 2023-07-07 13:18:28 -07:00
Stowell, Mark L 053762e0fa Removing duplicate option flags 2023-07-07 11:38:51 -07:00
Jacob Lotz c2deaeed46 Merge branch 'master' into nurbs-interp-fix-make 2023-07-07 11:37:06 +02:00
JacobLotz 3883d47caa Revert "Remove CurveInt"
This reverts commit 40fefd264e.
2023-07-07 09:41:45 +02:00
blaz 65193feefb adressing the PR questions 2023-07-05 23:06:49 -07:00
hughcars fb41dc55a8 Merge branch 'master' into hughcars/variable-length-arrays-of-length-zero-bug 2023-07-05 16:05:26 -04:00
hughcars e07747c246 Merge branch 'master' into hughcars/prism-ncmesh-bug 2023-07-05 16:04:49 -04:00
Jacob Lotz 75e6cfc574 Merge branch 'master' into nurbs-interp-fix-make 2023-07-04 13:02:44 +02:00
Jacob Lotz 575c63a564 Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-07-04 12:49:29 +02:00
JacobLotz 40fefd264e Remove CurveInt 2023-07-04 12:48:46 +02:00
JacobLotz 340f0b8d51 Use meshes from source 2023-07-04 11:26:21 +02:00
JacobLotz c2d4f28f87 Fix testing 2 2023-07-04 09:41:11 +02:00
JacobLotz 3418bd94d3 Fix testing 1 2023-07-04 09:01:28 +02:00
JacobLotz e92d16f165 Move two-* from data to miniapps/nurbs 2023-07-03 18:10:58 +02:00
blaz 78e758bbbb compliance with mfem checks 2023-07-02 17:26:02 -07:00
blaz 6ea9dc4113 style 2023-07-02 17:04:16 -07:00
blaz f1e73e4d2f Merge branch 'master' into kdtree 2023-07-02 16:39:24 -07:00
blaz 9d87ea3ee0 Merge branch 'kdtree' of https://github.com/mfem/mfem into kdtree 2023-07-02 16:36:23 -07:00
blaz 1c39ef9958 style 2023-07-02 16:36:02 -07:00
vsoch 3e2de8dfbe fix config/docker image instructions and dockerfiles
Problem: the current base image does not finish installing mfem,
and the instructions do not clearly lay out the use cases for using
the two containers.
Solution: update the builds and better delineate the different use
cases and usage instructions in the README.

Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2023-07-01 15:48:21 -06:00
Stowell, Mark L 03117fbad2 Adding missing pattern to make clean 2023-06-30 13:06:19 -07:00
Stowell, Mark L 2ccb26a873 Fixing shared quad face orientations in ParSubMesh 2023-06-29 16:21:47 -07:00
Stowell, Mark L 9ac27039d7 Adding hex-only mesh to ex35p for partial assembly tests 2023-06-29 16:21:19 -07:00
Stowell, Mark L 9b7d78096e Adding test case with tensor product elements for partial assembly test runs 2023-06-29 16:10:32 -07:00
Will Pazner 04d34e4de1 Fix bug in PAMassAssembleDiagonal1D 2023-06-29 16:00:35 -07:00
Will Pazner 912e4c6001 Update 1D mass kernels with DofQuadLimits 2023-06-29 15:57:12 -07:00
Will Pazner 54ed63d76e Merge remote-tracking branch 'origin/master' into max-q1d-d1d-cpu 2023-06-29 15:54:19 -07:00
Stowell, Mark L 62595993a9 Removing debugging output 2023-06-29 15:14:49 -07:00
Stowell, Mark L b2b95cd074 Adding serial version of example 34 2023-06-29 15:06:53 -07:00
Stowell, Mark L f404944335 Adding new example output files to gitignore 2023-06-29 14:58:51 -07:00
Will Pazner 04ef6d2187 Change value of MAX_INTERP_1D and MAX_DET_1D on CPU
Use value of MAX_D1D for these two limits.

On Windows, this will reduce the value to prevent stack overflow.
2023-06-29 14:19:37 -07:00
Will Pazner 2d3eb3dc97 Fix issue with MAX_DET_1D in Det3D 2023-06-29 14:18:11 -07:00
Stowell, Mark L 72fe430b9d Clearing MPI hangs in print statements 2023-06-29 14:12:12 -07:00
Will Pazner 24a12cb57d Introduce MAX_INTERP_1D and MAX_DET_1D
These are limits in DofQuadLimits and DeviceDofQuadLimits, used for
interpolation, differentiation, and determinant calculations in
QuadratureInterpolator.
2023-06-29 13:52:06 -07:00
Will Pazner e383bb979e Change usage of MAX_D1D, MAX_Q1D in QuadratureInterpolator 2023-06-29 13:03:32 -07:00
Will Pazner 5c06c96c31 Add Doxygen docs for DofQuadLimits and DeviceDofQuadLimits 2023-06-29 12:22:52 -07:00
Will Pazner 2a46b2893a Fix some instances of DofQuadLimits that should have been DeviceDofQuadLimits 2023-06-29 10:35:24 -07:00
Will Pazner 78de80e89a Reduce MAX_D1D, MAX_Q1D on Windows 2023-06-28 21:42:47 -07:00
Will Pazner 49f8aa209e Handle git status letters RM in branch-history 2023-06-28 21:42:26 -07:00
Will Pazner 8d26195d4d Reduce CPU MAX_D1D, MAX_Q1D
Try to fix AppVeyor Windows stack overflow
2023-06-28 15:44:38 -07:00
Will Pazner 4dfc90a462 Use DofQuadLimits in H(div) solvers miniapp 2023-06-28 12:52:21 -07:00
Will Pazner 20747046bd Make DeviceDofQuadLimits::Get return const object 2023-06-28 12:23:07 -07:00
Will Pazner 124af9ad61 Fix wrong use of DofQuadLimits in host code 2023-06-28 12:18:43 -07:00
Will Pazner 24527b8a59 Use DofQuadLimits in kernels 2023-06-28 12:08:55 -07:00
Will Pazner 9f4bf49945 Merge remote-tracking branch 'origin/master' into max-q1d-d1d-cpu
# Conflicts:
#	fem/bilininteg_hcurl.cpp
#	fem/bilininteg_mass_pa.cpp
#	fem/bilininteg_vectorfe.cpp
#	fem/integ/bilininteg_hdiv_kernels.cpp
#	fem/integ/bilininteg_vecdiffusion_pa.cpp
#	fem/integ/bilininteg_vecmass_pa.cpp
2023-06-28 12:08:47 -07:00
Will Pazner 7c4986546b Introduce DofQuadLimits struct
In kernel code, DeviceDofQuadLimits will give the relevant limits depending on
whether execution is on CUDA/HIP GPU or CPU.

In host code, DeviceDofQuadLimits::Get() will return the limits according to the
backend configuration of the Device object
2023-06-28 11:48:11 -07:00
Vladimir Z Tomov 84a2de8dec Merge branch 'master' into tmop-lim-fit 2023-06-27 12:16:26 -07:00
hughcars b5e65b187d Merge branch 'master' into hughcars/prism-ncmesh-bug 2023-06-26 09:27:57 -04:00
hughcars 3b57334da0 Merge branch 'master' into hughcars/variable-length-arrays-of-length-zero-bug 2023-06-26 09:27:34 -04:00
Tzanio Kolev acf49d4035 Merge branch 'master' into mpi_h1lor 2023-06-24 14:20:56 -07:00
Dylan Copeland 864677cdcb Documentation and minor interface changes. 2023-06-23 19:16:02 -07:00
Dylan Copeland ba91fb564b Reduced the number of dimensions in the array reducedIDs. Eliminated NNLSSolver constructor arguments and made set functions for the parameters. Changed interface for AssemblePatchMatrix to take a FiniteElementSpace. 2023-06-23 18:29:00 -07:00
hughcars d9d674b82e Merge branch 'master' into hughcars/prism-ncmesh-bug 2023-06-23 17:53:57 -04:00
hughcars c17092c5c7 Merge branch 'master' into hughcars/variable-length-arrays-of-length-zero-bug 2023-06-23 17:53:03 -04:00
Dylan Copeland e7fb674fa3 Renamed NURBSPatchRule as NURBSMeshRules. Removed options for NURBSMeshRules, so that it only supports patch-wise tensor-product rules. Changed bool integrator options to an enum. Reduced the number of dimensions in the reducedWeights array. 2023-06-23 12:02:00 -07:00
Socratis Petrides 2c81fdc849 more mem leaks 2023-06-22 16:27:27 -07:00
Stowell, Mark L 8fc3e8038b Adding new examples to PAR_EXAMPLES 2023-06-22 15:09:17 -07:00
Socratis Petrides c5726ea7a9 fix memleak 2023-06-22 13:04:00 -07:00
Dylan Copeland adcc8a53b8 Merge branch 'master' of https://github.com/mfem/mfem into nurbsquad 2023-06-22 12:47:47 -07:00
Dylan Copeland f9167a6752 Initializing variable. 2023-06-22 12:46:51 -07:00
Tzanio Kolev 3e8e94845f Merge branch 'master' into submesh-nd-dev 2023-06-22 11:53:09 -07:00
Tzanio Kolev b3d4f575b1 Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-06-22 11:34:09 -07:00
Socratis Petrides a5d4a999fa Merge branch 'master' into efem-topopt 2023-06-22 11:11:58 -07:00
Socratis Petrides d1e9849dfa Merge branch 'master' into efem-topopt 2023-06-22 11:03:30 -07:00
Socratis Petrides f204a664c0 fixing autotest issues for ex35[p].cpp 2023-06-22 10:32:59 -07:00
Socratis Petrides 86043d6f87 fix shadow failures ex34[p].cpp 2023-06-22 10:26:42 -07:00
Socratis Petrides 66036bf6a3 Merge branch 'master' into efem-topopt 2023-06-21 18:03:03 -07:00
Socratis Petrides ac88636c85 Merge branch 'master' into efem 2023-06-21 18:02:45 -07:00
Dylan Copeland fa81db96ba Removing static condensation option in nurbs_patch_ex1. Removing inefficient integrators. 2023-06-21 17:28:07 -07:00
hughcars 3e1bb914c5 Merge branch 'master' into hughcars/variable-length-arrays-of-length-zero-bug 2023-06-19 11:50:07 -04:00
Hugh Carson 0ca88cb295 Remove some empty lines 2023-06-19 11:31:12 -04:00
Hugh Carson 2419e6211e Merge remote-tracking branch 'origin/master' into hughcars/prism-ncmesh-bug 2023-06-19 11:30:58 -04:00
Brendan Keith 421fbae3ce Merge branch 'efem' of github.com:mfem/mfem into efem 2023-06-16 10:28:26 -04:00
Brendan Keith 7bb7f56aa6 remove unused code 2023-06-16 09:02:22 -04:00
Brendan Keith 85d79fc406 Merge branch 'master' into efem 2023-06-15 18:13:47 -04:00
Brendan Keith f3cea2df36 minor 2023-06-15 17:53:49 -04:00
Brendan Keith 7e7059ddd7 other memory leaks 2023-06-15 16:34:04 -04:00
Brendan Keith d87c4c7d43 remove shadowing and fix memory leaks 2023-06-15 15:49:05 -04:00
Brendan Keith aa272ca065 Merge branch 'efem' of github.com:mfem/mfem into efem 2023-06-15 12:27:43 -04:00
hughcars 7f4cce4a0a Merge branch 'master' into hughcars/prism-ncmesh-bug 2023-06-14 11:43:07 -04:00
hughcars 4016cceb6a Merge branch 'master' into hughcars/variable-length-arrays-of-length-zero-bug 2023-06-14 11:41:34 -04:00
Mittal, Ketan c4336e8c6c refactor abort to specify if invalid element index or empty partition 2023-06-13 08:53:51 -07:00
Mittal, Ketan 228e4e5564 Merge branch 'master' of https://github.com/mfem/mfem into getfe-fix 2023-06-13 08:48:16 -07:00
Will Pazner 4794f058cf Make MAX_D1D, MAX_Q1D constexpr 2023-06-12 13:32:08 -07:00
Will Pazner 041310858e Increase MAX_D1D, MAX_Q1D, etc. when target is CPU 2023-06-12 13:32:08 -07:00
Tzanio Kolev 1a6a3ac5d7 Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-06-11 16:45:21 -07:00
Tzanio Kolev d22c68dbd8 Merge branch 'master' into nurbsquad
Conflicts:
	CHANGELOG
2023-06-11 16:37:24 -07:00
Tzanio Kolev f1881e75df make style 2023-06-11 15:58:53 -07:00
Tzanio Kolev c068471192 Merge branch 'master' into nurbs-interp-fix-make 2023-06-11 15:34:35 -07:00
Tzanio Kolev 502ad09e67 Small adjustments 2023-06-11 15:33:43 -07:00
Tzanio Kolev e2963ad817 Merge branch 'master' into nurbs-interp-fix-make 2023-06-11 15:32:59 -07:00
Tzanio Kolev 3240afbbdd Merge branch 'master' into submesh-nd-dev 2023-06-11 15:08:11 -07:00
Tzanio Kolev d8232d3c61 Merge branch 'master' into efem 2023-06-11 15:05:14 -07:00
Stowell, Mark L 2968bde368 Adding CHANGELOG entries 2023-06-06 09:58:58 -07:00
Stowell, Mark L 1d3182ee11 Expanding description of StatelessDofTransformation 2023-06-06 09:48:52 -07:00
Hugh Carson a389cd5257 Fix warning 2023-06-05 12:36:58 -04:00
Hugh Carson 6d0b9d81c2 Change relative paths to match those from the build directory rather than the source directory 2023-06-05 09:50:00 -04:00
Hugh Carson 06daad4e03 Remove unneeded refined mesh 2023-06-05 09:37:23 -04:00
Hugh Carson 8009bcb192 Style fixes 2023-06-05 09:36:25 -04:00
Hugh Carson c82b9b33fc Provisional tests 2023-06-05 09:26:19 -04:00
Hugh Carson 886b04a5f3 Fix set unused warnings, and remove unneeded new 2023-06-05 09:26:19 -04:00
Hugh Carson 07b5787f5b Adding some overrides, range loops, and some comments. Also small refactor of group and owner array building. 2023-06-05 09:26:19 -04:00
Hugh Carson c4cd39a785 Move the simplest prism meshes to the data folder. 2023-06-05 09:26:19 -04:00
Hugh Carson a7be74494c Adding pair of quadratic prism meshes causing issues 2023-06-05 09:26:19 -04:00
Hugh Carson 525a083a78 Fix for handling dof -> entity map containing entities with zero dofs (P2 tris, no dof, and P2 quads, 1 dof) 2023-06-05 09:26:19 -04:00
Hugh Carson 5a4190c392 Fix for handling dof sent with negative index 2023-06-05 09:26:19 -04:00
Hugh Carson e4ba44bcb7 Fixing bug where variable length arrays of length zero are being deaddressed, resulting in heap overflow and/or not failing nullptr checks 2023-06-05 09:26:19 -04:00
Tzanio Kolev 5a494f1bbf Merge branch 'master' into tmop-lim-fit 2023-06-04 13:49:17 -07:00
Tzanio Kolev 9067e0b5ce Merge branch 'master' into kdtree 2023-06-04 13:42:57 -07:00
Hugh Carson 93dcb69132 Fix for handling dof sent with negative index 2023-05-24 15:10:26 -04:00
Hugh Carson b9de68ea8c Fixing bug where variable length arrays of length zero are being deaddressed, resulting in heap overflow and/or not failing nullptr checks 2023-05-24 15:10:26 -04:00
Mittal, Ketan 311accf5eb Merge branch 'master' of https://github.com/mfem/mfem into getfe-fix 2023-05-23 19:09:30 -07:00
Mittal, Ketan ad61527aff remove null return from GetFE 2023-05-23 19:09:03 -07:00
Will PaznerandVeselin Dobrev 661f6a1268 Simplify expression in cuda and hip dot kernel
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2023-05-23 11:51:10 -07:00
Vladimir Z Tomov e75f24ff76 minor 2023-05-19 14:24:54 -07:00
Vladimir Z Tomov 72a1d09920 minor 2023-05-18 23:16:34 -07:00
Stowell, Mark L c727426338 Removing saved files from new examples 2023-05-18 20:19:13 -07:00
Stowell, Mark L 34a5ecffdb Merge remote-tracking branch 'origin/master' into submesh-nd-dev 2023-05-18 20:18:36 -07:00
Stowell, Mark L 7b5a641ee9 Avoiding use of variable name err 2023-05-18 20:09:00 -07:00
Vladimir Z Tomov 03be75de97 minor 2023-05-18 19:32:16 -07:00
Stowell, Mark L f15e5e8a9a Cleaning up comments and sample runs in ex35p 2023-05-18 17:33:25 -07:00
Stowell, Mark L 753eb6e3df make style 2023-05-18 14:11:36 -07:00
Vladimir Z Tomov ec77e3988a missing computation 2023-05-18 11:52:13 -07:00
Stowell, Mark L 90dfb5dd4f Renaming new examples and updating comments in ex34p.cpp 2023-05-18 11:09:00 -07:00
Vladimir Z Tomov ccadddc9f5 Merge branch 'master' into tmop-lim-fit 2023-05-17 23:03:48 -07:00
Jacob Lotz 8adb531554 fix .gitignore and memleak 2023-05-17 15:02:25 +02:00
Jacob Lotz 11f3d34963 Merge branch 'nurbs-auto-knot2edge-dev' of github.com:mfem/mfem into nurbs-auto-knot2edge-dev 2023-05-16 17:34:14 +02:00
Jacob Lotz f561f1d069 Fix memleak after 1D impl 2023-05-16 17:33:45 +02:00
Jacob Lotz 6376dc1bb9 Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-05-16 11:34:13 +02:00
Jacob Lotz 1bcd411837 Merge branch 'master' into nurbs-interp-fix-make 2023-05-15 10:59:29 +02:00
Will Pazner 26a242252d HIP and debug device versions of Vector::Sum 2023-05-12 12:34:16 -07:00
Will Pazner 87981b9e37 CUDA implementation of Vector::Sum 2023-05-12 12:34:16 -07:00
Will Pazner c9aae953f0 Clear L2F mapping in FiniteElementSpace::Destroy
This fixes a segfault e.g. after uniformly refining a mesh for which
face geometric factors have been computed.
2023-05-12 12:33:17 -07:00
Stowell, Mark L 5dcbf90487 Merge remote-tracking branch 'origin/master' into submesh-nd-dev 2023-05-11 11:36:20 -07:00
Stowell, Mark L 64d24c1466 Changes proposed in PR #3611 2023-05-10 16:36:59 -07:00
Socratis Petrides 41ecb12a40 Merge branch 'master' into efem 2023-05-10 12:59:50 -07:00
JacobLotz 31ed77c025 make style 2023-05-10 16:51:55 +02:00
JacobLotz a124640f43 Make style and some documentation 2023-05-10 12:30:48 +02:00
JacobLotz 9ca0124b99 Working 1D 2023-05-10 12:18:36 +02:00
JacobLotz 29d17b7174 fix 1 issue 2023-05-10 09:23:11 +02:00
JacobLotz ceab44d9fd improved naming of check 2023-05-09 18:13:50 +02:00
JacobLotz d8d5adb62b looking for bug 1 2023-05-09 18:02:45 +02:00
JacobLotz aad2c99e48 more 1D and prettified 2023-05-09 17:24:24 +02:00
JacobLotz 5630c8aefc fixes for 1d nurbs 2023-05-09 16:01:08 +02:00
Jacob Lotz 80cf146882 Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-05-09 15:06:00 +02:00
JacobLotz c6c2381171 Updated testing in makefile as well. 2023-05-09 14:57:41 +02:00
JacobLotz c7e8d7f99a Updated changelog 2023-05-09 14:28:11 +02:00
JacobLotz 1b8d520eb9 added visit option 2023-05-09 13:50:53 +02:00
JacobLotz d2af3ac8f4 fix make file 2023-05-09 13:25:51 +02:00
Vladimir Z Tomov eda2e7b798 added SolutionCallback. 2023-05-07 23:26:56 -07:00
Vladimir Z Tomov 594528e224 revert the temporary commit 2023-05-07 23:06:40 -07:00
Brendan Keith 6c93b09cdd fixing github error 2023-05-03 14:14:29 -04:00
Stowell, Mark L d83990b998 Merge remote-tracking branch 'origin/master' into submesh-nd-dev 2023-05-01 15:44:47 -07:00
Brendan Keith 4d2356c039 merge 2023-05-01 13:46:36 -04:00
Stowell, Mark L 091ca904e9 Adding 2D mesh support in port example 2023-04-30 10:24:48 -07:00
Stowell, Mark L c19ea4c790 Adding boundary Point elements to 1D meshes consistent with boundaries in 2 and 3D meshes 2023-04-30 10:24:23 -07:00
Stowell, Mark L 88357c646f Adding 2D test meshes 2023-04-30 10:23:01 -07:00
Dylan Copeland 8a5a0d038c Fixing another memory leak. 2023-04-24 21:11:39 -07:00
Stowell, Mark L 957ca37778 Adding or expanding documentation 2023-04-24 11:13:24 -07:00
Dylan Copeland 3331d6d9b6 Fixing memory leaks. 2023-04-24 11:07:53 -07:00
Stowell, Mark L 118d7f4e56 Switching to the new stateless doftrans where appropriate 2023-04-24 10:05:13 -07:00
Stowell, Mark L ddb18d33df Rewrite of DofTransformation and related classes to create versions without stored face orientations 2023-04-24 10:04:13 -07:00
Dylan Copeland 47241bd101 Merge branch 'master' of github.com:mfem/mfem into nurbsquad 2023-04-24 09:13:11 -07:00
Vladimir Z Tomov c3572785df temporary example use of IterateCallback 2023-04-23 11:29:41 -07:00
Stowell, Mark L 7ce21b6206 Revert "Moving DofTransformation access to FiniteElementSpace"
This reverts commit 1a46b6a343.
2023-04-22 11:27:06 -07:00
Stowell, Mark L 3ebf45d3ed Adding 2D test cases to Hypre preconditioner unit test 2023-04-22 11:25:45 -07:00
Stowell, Mark L 53d6fcb2e7 Changing name of face orientation inversion method 2023-04-22 11:25:02 -07:00
Stowell, Mark L 68889f9563 Updating copyright dates in new files 2023-04-19 15:24:34 -07:00
Stowell, Mark L 1a46b6a343 Moving DofTransformation access to FiniteElementSpace 2023-04-19 15:13:53 -07:00
Stowell, Mark L 65494eef22 Merge remote-tracking branch 'origin/master' into submesh-nd-dev 2023-04-19 14:45:37 -07:00
Vladimir Z Tomov 43a6e4c059 simply exposed iterate_callback in a hiop-specific abstract class. 2023-04-18 13:05:25 -07:00
Stowell, Mark L 6315081134 make style 2023-04-17 16:13:23 -07:00
Stowell, Mark L 49c93a5cba Merge remote-tracking branch 'origin/master' into submesh-nd-dev
# Conflicts:
#	fem/fe/fe_base.hpp
#	fem/fespace.hpp
2023-04-17 14:09:04 -07:00
blaz 0800b05355 clean the mesh and the gf files 2023-04-17 09:56:31 -07:00
blaz 789255ed1e .gitignore 2023-04-17 09:47:23 -07:00
blaz b4c0a9aa6d .gitignore 2023-04-16 18:55:39 -07:00
blaz 6fc1871d63 fix shift_test 2023-04-16 10:42:38 -07:00
blaz 2a29eb3d2d .gitignore 2023-04-16 10:29:14 -07:00
blaz 81e3a246de .gitignore 2023-04-16 08:51:08 -07:00
blaz 629eb3a3d7 gitignore 2023-04-15 23:58:31 -07:00
blaz fbd8279072 style 2023-04-15 23:07:47 -07:00
blaz cf24c2aa83 add vis option 2023-04-15 23:05:49 -07:00
blaz a3aa9cf16f gitignore 2023-04-14 23:20:54 -07:00
blaz c2b8a82f80 cmake 2023-04-14 23:13:56 -07:00
blaz b297b3a9de fixed headers 2023-04-14 22:39:40 -07:00
blaz 9a2ea3696e style 2023-04-14 22:34:01 -07:00
blaz 53deb75f8b Merge branch 'master' into kdtree 2023-04-14 22:30:15 -07:00
blaz f565bf1713 reviewers requested changes 2023-04-14 22:22:20 -07:00
Stowell, Mark L cf2cb9545e Supporting RT spaces in SubMesh to SubMesh transfers (on boundaries) 2023-04-14 16:34:09 -07:00
Stowell, Mark L ae20699aaf Adding Nedelec elements to sub-mesh unit tests 2023-04-14 10:49:15 -07:00
Stowell, Mark L a9f5c688f4 Fix to skip face orientation check in 1D meshes 2023-04-14 10:48:46 -07:00
Stowell, Mark L ffb6dd72eb Supporting face orientations in 2D sub-meshes produced either as FromDomain or FromBoundary 2023-04-12 16:47:42 -07:00
Stowell, Mark L f05d325148 Reverting test code in submesh_utils 2023-04-12 16:46:23 -07:00
Stowell, Mark L e6b458d1ec Removing old debugging statement from unit test 2023-04-12 14:09:15 -07:00
Stowell, Mark L 87bbeaf84b Adding orientation composition methods and a unit test 2023-04-12 14:06:42 -07:00
Dohyun Kim 14db96ad56 Merge branch 'master' into efem-topopt 2023-04-12 12:43:17 -04:00
Dohyun Kim a0fc494c8d Merge remote-tracking branch 'origin/master' into efem-topopt 2023-04-12 12:42:33 -04:00
Dohyun Kim 66290dcc0b discrete space description 2023-04-12 12:40:46 -04:00
Dohyun Kim f10fa85cb7 update algorithm preamble 2023-04-12 12:39:13 -04:00
Dohyun Kim ae42201eb8 Parallel version updated, too. 2023-04-12 12:28:10 -04:00
Dohyun Kim c9a57881d2 update successive difference measure using DiffMappedGF 2023-04-12 12:28:00 -04:00
Dohyun Kim db3114f372 Default initialization update and include difference between mapped functions.
DiffMappedGridFunctionCoefficient is useful when we want to compute rho-rho_old
2023-04-12 12:27:05 -04:00
Dohyun Kim 9255047c9c update comments and add warning to projection 2023-04-12 11:46:09 -04:00
Jacob Lotz 42feb99ddc Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-04-12 17:39:55 +02:00
Dohyun Kim 8db4ef625b rho = sigmoid(psi) and update psi instead of rho 2023-04-12 11:32:16 -04:00
blaz f40c4ae90d style 2023-04-11 23:34:45 -07:00
blaz 8672527898 Fix using std:: in dual numbers 2023-04-11 23:27:29 -07:00
Socratis Petrides 0f2edd7787 Merge branch 'master' into efem 2023-04-11 16:15:49 -07:00
Stowell, Mark L 70e1e015cf Small change for const-correctness 2023-04-11 14:28:51 -07:00
Stowell, Mark L 59803409fc Adding face orientation corrections to serial transfer map 2023-04-11 14:28:24 -07:00
Dylan Copeland 261c252e28 Copyright year. 2023-04-10 19:45:40 -07:00
Dylan Copeland 6a09060d1a Merge branch 'master' of https://github.com/mfem/mfem into nurbsquad 2023-04-10 19:41:08 -07:00
Stowell, Mark L 60223bf9a2 Adding SubMesh -> SubMesh support for ND spaces 2023-04-10 17:05:39 -07:00
Brendan Keith 0e2f072414 merge 2023-04-09 21:19:08 -05:00
Brendan Keith 501f822a58 remove ex32.cpp from CMakeLists 2023-04-09 21:17:01 -05:00
Tzanio Kolev 05f7c9f498 Merge branch 'master' into efem 2023-04-09 13:11:37 -07:00
Tzanio Kolev fbf9839a3e Merge branch 'master' into mpi_h1lor 2023-04-09 13:07:38 -07:00
Stowell, Mark L b577ab48f9 Modifying TransferMap objects to support DofTransformations 2023-04-07 15:03:14 -07:00
Stowell, Mark L 4e9ed7fc51 Caching relative face orientations in SubMesh objects 2023-04-07 15:02:02 -07:00
Stowell, Mark L 3a9060060d Simplifying use of DofTransformation in SubMesh context 2023-04-07 14:58:17 -07:00
Stowell, Mark L 0cbc41c189 Adding negative dof support to serial transfer map and parallel submesh -> submesh block 2023-04-06 17:13:15 -07:00
Ketan Mittal 0f390f131b minor refactor 2023-03-31 07:20:13 -07:00
Ketan Mittal d78c9eb624 fix psubmesh for dim = spacedim 2023-03-30 16:21:58 -07:00
Ketan Mittal 94d401b0b2 restore logic for dim=spacedim case 2023-03-30 16:15:56 -07:00
Stowell, Mark L 38628a826d Initial cleanup of example 2023-03-30 15:54:52 -07:00
Stowell, Mark L 0dcccd489f make style 2023-03-30 15:54:30 -07:00
Stowell, Mark L 0ef605e1d0 Shared faces must be sorted with triangular faces first 2023-03-30 14:35:30 -07:00
Will Pazner f24c43c396 Fix face quadrature function coefficient evaluation 2023-03-30 12:30:33 -07:00
Will Pazner 605ed8b8a2 Add unit tests for face quadrature function coefficients 2023-03-30 12:29:53 -07:00
Will Pazner de4c7baa4d Change coefficient tests to use tag [Coefficient] 2023-03-30 12:29:25 -07:00
Stowell, Mark L 9546cffb84 Reining in the new attribute numbers 2023-03-29 15:25:27 -07:00
Stowell, Mark L 193404e9c9 Adding debug output to GetTriOrientation similar to what is produced by GetQuadOrientation 2023-03-29 15:20:28 -07:00
Stowell, Mark L f3ca7ac546 Adding submesh examples using "FromBoundary" and "FromDomain" 2023-03-29 15:19:23 -07:00
EB Chin e21949b16b update copyright date 2023-03-24 20:58:00 -07:00
EB Chin ddc27a60df Merge branch 'master' into mpi_h1lor 2023-03-24 20:55:18 -07:00
Eric B. Chin 36e3062378 make style 2023-03-24 13:47:06 -07:00
EB Chin 102d4ad3f8 fix output 2023-03-24 13:44:44 -07:00
EB Chin 3ef4611c1f Merge branch 'mpi_h1lor' of github.com:mfem/mfem into mpi_h1lor 2023-03-24 13:39:58 -07:00
EB Chin b81b023ea5 simplify parallel get/set dofs 2023-03-24 13:35:57 -07:00
Eric B. Chin 35938b691a astyle changes 2023-03-24 12:58:02 -07:00
EB Chin ada5c8f4e9 update docs 2023-03-24 12:55:34 -07:00
EB Chin 16fede3622 reorganize and consolidate parallel vs serial 2023-03-24 12:34:15 -07:00
Eric B. Chin ebdfac0dd7 fix dual example 2023-03-24 08:39:52 -07:00
EB Chin a89d24843f separate methods for parallel; example refinement 2023-03-23 22:53:18 -07:00
EB Chin 05f18737a0 initial example 2023-03-21 09:18:43 -07:00
EB Chin b06b1c0006 initial support for parallel h1 fields 2023-03-20 13:12:53 -07:00
Stowell, Mark L 85a06dcc1d Edge orientation fix 2023-03-13 18:54:05 -07:00
Stowell, Mark L 8e2fc5672b Merge remote-tracking branch 'origin/master' into submesh-nd-dev 2023-03-13 13:25:46 -07:00
Ido Akkerman 6b8865705e Merge branch 'nurbsquad' of https://github.com/mfem/mfem into nurbsquad 2023-03-07 09:07:51 +01:00
Ido Akkerman ebcb6cc603 Streamlining interface with NURBSExtension 2023-03-07 09:04:27 +01:00
Dylan Copeland dee6d806dd Adding MFEM_VERIFY with error message to catch the case of a patchwise integrator on a non-NURBS mesh. 2023-03-06 10:12:36 -08:00
Dylan Copeland 0b5be406aa Merge branch 'master' of github.com:mfem/mfem into nurbsquad 2023-03-06 09:39:13 -08:00
Brendan Keith 83a6c88345 Use the correct space to visualize the filtered density. Adjust default discretization orders in order to run with order = 1. Update sample runs. 2023-03-01 10:52:47 -05:00
Dylan Copeland 10e5ac4403 NNLS system normalization is now optional. 2023-02-27 11:47:05 -08:00
Dylan Copeland f645886ada Putting NNLS instance in ifdef MFEM_USE_LAPACK. 2023-02-22 16:06:58 -08:00
Dylan Copeland 2a974948a6 Merge branch 'master' of github.com:mfem/mfem into nurbsquad 2023-02-22 14:55:17 -08:00
Dylan Copeland e8e6b1b159 Adding unit test for NNLS and an error message when insufficient integration points are used in NNLS. 2023-02-22 14:54:41 -08:00
Dylan Copeland d52d1fea0a Refactored NNLS as a class derived from Solver. 2023-02-22 12:28:50 -08:00
Tzanio Kolev c2e028c916 Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-02-14 10:05:01 -08:00
Ketan Mittal 0560039149 bdr attributes for 2D meshes 2023-02-11 15:21:53 -08:00
JacobLotz c18c204279 Fix typo and added extra line 2023-02-10 10:25:15 +01:00
JacobLotz 80a4407f74 Updated refinement documentation in nurbs_ex1.cpp 2023-02-09 13:24:33 +01:00
JacobLotz a4a5f784ab Moved RefineNURBSFromFile to mesh.cpp 2023-02-09 11:49:45 +01:00
Brendan Keith bf7194ec2b final comments 2023-02-08 18:47:58 -05:00
Brendan Keith 6e1204897a more comments 2023-02-08 18:35:46 -05:00
JacobLotz 8d3c5ee11c Updated documentation 2023-02-08 21:45:56 +01:00
JacobLotz b8da9d0448 missed a j 2023-02-08 21:32:36 +01:00
JacobLotz 431d3ea432 Improved counter for while loop, MFEM_ASSERT -> MFEM_VERIFY 2023-02-08 21:28:59 +01:00
Dylan Copeland 5ddc41f07e Putting casting back to avoid compiler warning. 2023-02-08 12:13:12 -08:00
JacobLotz 8d4b3657aa fix typos 2023-02-08 21:12:05 +01:00
Dylan Copeland ebbd6dee0c More documentation. 2023-02-08 12:08:36 -08:00
Brendan Keith e58f42e0b9 merge master and address Boyan's comments 2023-02-08 14:29:34 -05:00
JacobLotz d585f60011 Forced specific refinement for 3D cases 2023-02-08 10:08:54 +01:00
JacobLotz 39c661388e typo 2023-02-07 14:25:11 +01:00
JacobLotz f1eb3267bb make style 2023-02-07 14:18:45 +01:00
JacobLotz 0cde0fd1bb Added documentation, while loop and mfem_error 2023-02-07 14:18:06 +01:00
Dylan Copeland 57483a1921 Adding documentation. 2023-02-06 15:28:54 -08:00
Dylan Copeland 60b82f2fe4 Removed unused variables. 2023-02-03 20:42:25 -08:00
Dylan Copeland 1eab3a2193 Merge branch 'master' of github.com:mfem/mfem into nurbsquad 2023-02-03 19:53:25 -08:00
JacobLotz 8becbfbb7d Added 3D examples and tests 2023-02-03 17:19:01 +01:00
JacobLotz 2ae4b1914a Fix spelling 2023-02-03 15:53:17 +01:00
JacobLotz 813e99a41b Changed name extended -> comprehensive 2023-01-31 13:42:09 +01:00
JacobLotz 15af16215a fix typos in mesh descriptions 2023-01-31 11:34:20 +01:00
JacobLotz bc76844900 Added sample runs to nurbs miniapp and added test including auto edge 2 2023-01-31 11:26:49 +01:00
JacobLotz 8f0d944b26 Added sample runs to nurbs miniapp and added test including auto edge 2023-01-31 11:25:16 +01:00
JacobLotz ea283d2ac7 Merge branch 'nurbs-auto-knot2edge-dev' of github.com:mfem/mfem into nurbs-auto-knot2edge-dev 2023-01-31 11:23:32 +01:00
JacobLotz 242b2c4f91 Added extra test including auto edge to knot. Also sample runs to miniapps/nurbs/nurbs_ex1.cpp. 2023-01-31 11:18:43 +01:00
Brendan Keith f6858fc76f update cmake 2023-01-25 17:40:29 -05:00
Brendan Keith 4b1ca0b0f2 update cmake 2023-01-25 17:38:11 -05:00
Tzanio Kolev 15deef3206 Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-01-21 14:57:45 -08:00
Stowell, Mark L 3bada4f3c4 Merge remote-tracking branch 'origin/master' into submesh-nd-dev 2023-01-11 17:05:34 -05:00
Stowell, Mark L 37047e14ff Handling empty face orientations (not sure why this started to be a problem...) 2023-01-11 17:04:04 -05:00
Stowell, Mark L 6323419a79 Reordering GLVis output 2023-01-11 09:18:21 -05:00
Stowell, Mark L 72547abdf2 Adjusting sample runs 2023-01-11 09:17:56 -05:00
Stowell, Mark L 70d0187925 Removing outdated code 2023-01-11 09:17:41 -05:00
Stowell, Mark L 4d840d935e Adding SuperLU solver option 2023-01-11 09:15:34 -05:00
Jacob Lotz abc7074b3a Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-01-11 10:32:22 +01:00
Jacob Lotz 18c0719ba2 Merge branch 'master' into nurbs-auto-knot2edge-dev 2023-01-10 12:01:45 +01:00
Stowell, Mark L 20051bbb67 Parallel debugging info 2023-01-09 15:10:58 -05:00
Brendan Keith 21fe9724d5 update comments 2023-01-09 14:37:05 -05:00
Brendan Keith 7f17342db3 fix unused private field variable error 2023-01-09 13:23:56 -05:00
Brendan Keith 2a54d86f7b update CHANGELOG 2023-01-09 11:25:51 -05:00
Brendan Keith 1414918b17 Merge branch 'efem' into efem-topopt 2023-01-09 11:22:45 -05:00
Brendan Keith 0ac7df2dd3 Merge branch 'efem' of github.com:mfem/mfem into efem 2023-01-09 11:22:14 -05:00
Brendan Keith cc010ace32 Merge branch 'master' into efem 2023-01-09 11:21:35 -05:00
Brendan Keith 8facb48485 minor 2023-01-09 11:20:37 -05:00
Tzanio Kolev b5265064a6 Merge branch 'master' into efem 2023-01-09 07:31:45 -08:00
Stowell, Mark L 97fef25220 Merge remote-tracking branch 'origin/master' into submesh-nd-dev 2023-01-09 10:06:32 -05:00
jelotz cc8cebaa99 fix reinit of variable 2023-01-09 15:14:41 +01:00
jelotz de262c4134 fix reinit of variable 2023-01-09 15:11:46 +01:00
jelotz c0c3618627 make style of just improved documentation 2023-01-09 15:02:24 +01:00
jelotz e1c2bf47d5 fix documentation 2023-01-09 15:00:22 +01:00
jelotz 5403f28eca More reinit fix 2023-01-09 14:48:14 +01:00
jelotz f5cd5b4117 fix reinitialisation of variables 2023-01-09 14:44:03 +01:00
Brendan Keith 37d43d3b65 shift Hessian spectrum using mass matrix when p=1 to make it easier for GMRES 2023-01-08 23:18:23 -05:00
Brendan Keith 8c44b0e583 update CHANGELOG 2023-01-08 22:18:45 -05:00
Brendan Keith 6611a9ec28 update sol_sock definition 2023-01-08 22:15:21 -05:00
Brendan Keith ea655cb10a minor 2023-01-08 22:07:21 -05:00
Brendan Keith 2d46bbd94f added serial code for ex35 2023-01-08 21:40:02 -05:00
Brendan Keith 7e8812bc07 comment ex35 2023-01-08 21:19:27 -05:00
Tzanio Kolev 9cc92e72c2 Merge branch 'master' into nurbsquad 2023-01-08 14:57:17 -08:00
Brendan Keith 30f8b1d876 style 2023-01-07 10:50:26 -05:00
Brendan Keith 7c6b6cc6b7 initial files 2023-01-07 10:50:08 -05:00
Brendan Keith 3d5a3a94f6 minor 2023-01-07 10:19:17 -05:00
Brendan Keith 0555904e50 removed final warnings and edited makefile 2023-01-07 10:10:30 -05:00
Brendan Keith d9f78ace79 Fix spelling of Thomas's name :/ 2023-01-06 19:11:53 -05:00
Brendan Keith 6c05690950 update spelling 2023-01-06 19:01:28 -05:00
Brendan Keith 7a83cd1d4b style 2023-01-06 18:55:36 -05:00
Brendan Keith e0ce4bfa67 updated serial code 2023-01-06 18:55:00 -05:00
Brendan Keith da1b6d1d34 fix print statements in ex34p.cpp 2023-01-06 18:22:22 -05:00
Brendan Keith 5d9f23cfd5 first draft of ex34p 2023-01-06 14:40:00 -05:00
Dylan Copeland 820ececea0 Run tests only if built with lapack. 2022-12-30 15:01:46 -08:00
Dylan Copeland b113b19cd6 Minor 2022-12-30 14:37:50 -08:00
Dylan Copeland 7885381cd8 Adding sample runs. Updating CHANGELOG. Cleaning up NNLS. 2022-12-30 14:21:36 -08:00
Dylan Copeland 6286897c16 Fixing more compiler warnings. 2022-12-29 18:06:25 -08:00
Dylan Copeland c779c2ec8d Fixing mac warnings. 2022-12-29 13:03:56 -08:00
Dylan Copeland a5391d125f Fixing pedantic compiler warnings. 2022-12-29 12:38:06 -08:00
Dylan Copeland 550904ab55 Fixing an issue with dgeqrf in NNLS. Fixing a bug for element-wise integration. Eliminating reduced rule computation in the PA case. 2022-12-28 21:47:17 -08:00
Tzanio Kolev d1bd5c6d95 Merge branch 'master' into nurbsquad 2022-12-28 11:06:41 -08:00
Dylan Copeland 7f63fba18c Moved NURBS patch integration to its own file. 2022-12-27 20:00:41 -08:00
Dylan Copeland 5ac9aa4a47 Improved efficiency of DiffusionIntegrator::AssemblePatchMatrix_fullQuadrature. Improved the interface. 2022-12-27 19:29:11 -08:00
Dylan Copeland 11b8330ae3 Documentation. Assignment operator for Array3D. 2022-12-27 14:11:33 -08:00
Dylan Copeland 58ca949331 Reverting ex1. 2022-12-23 11:49:46 -08:00
Dylan Copeland 4c27a6c252 Moved ex1 to miniapps/nurbs and cleaned it up. 2022-12-23 11:39:46 -08:00
Dylan Copeland 25b23be5e8 Merge branch 'master' of github.com:mfem/mfem into nurbsquad 2022-12-22 10:51:37 -08:00
Dylan Copeland 05151e52eb Added input parameters to choose between full and reduced quadrature. Removed patch DenseMatrix option. 2022-12-22 10:50:25 -08:00
Stowell, Mark L 8210a1291a Adding support for negative vdofs in submesh maps 2022-12-21 11:26:08 -08:00
Stowell, Mark L fbe85dc4df Adding some debugging output to example code 2022-12-20 16:43:12 -08:00
Stowell, Mark L be945311bd Merge remote-tracking branch 'origin/ams-empty-part' into submesh-nd-dev 2022-12-15 13:51:00 -08:00
Stowell, Mark L c9b0823944 Merge remote-tracking branch 'origin/bugfix/submesh-bdr-l2' into submesh-nd-dev 2022-12-12 16:51:13 -08:00
Stowell, Mark L e1097a9b2f Resolving issues with ex8p 2022-12-11 11:21:24 -08:00
Stowell, Mark L 710a83f1ce Fixing unit test in serial 2022-12-11 10:30:57 -08:00
Stowell, Mark L f62745a3ba Adding unit test with empty partitions 2022-12-10 15:54:08 -08:00
Stowell, Mark L 932f299036 Tweak HypreAMS and HypreADS to handle empty partitions 2022-12-10 15:52:18 -08:00
Stowell, Mark L 1715a000e7 Adding port BC example using ParSubMesh 2022-12-10 10:14:05 -08:00
Stowell, Mark L fd90338e6c Modifying ParTransfermap to handle negative DoFs 2022-12-10 10:13:27 -08:00
Dylan Copeland d27e88109d Fixing some build issues. 2022-12-05 21:42:34 -08:00
Dylan Copeland e9a5bf3c8f Merge branch 'master' of github.com:mfem/mfem into nurbsquad 2022-12-05 20:29:03 -08:00
Dylan Copeland b58e1e09d3 Implemented operator PA for NURBS patches in AddMultPatchPA, for DiffusionIntegrator. Refactored some setup into functions. 2022-12-05 20:06:31 -08:00
blaz 2b89bfb934 style 2022-11-23 14:14:21 -08:00
blaz abdb76f9a5 added no-vis option 2022-11-23 14:05:00 -08:00
blaz 2efb0f4933 make 2022-11-21 22:57:52 -08:00
blaz 523bb28c54 style 2022-11-21 21:30:15 -08:00
blaz 7c913a1672 fixes 2022-11-21 20:40:24 -08:00
blaz 04debcf761 modfified and documented miniapp 2022-11-21 20:23:06 -08:00
blaz 01d6b73b7c style 2022-11-14 13:27:27 -08:00
blaz ba68679bee removed the old development 2022-11-14 10:20:47 -08:00
blaz 71822e6469 Merge branch 'master' into kdtree 2022-11-14 10:19:37 -08:00
blaz 09302f4cb0 kdtree test implementation 2022-11-14 10:12:47 -08:00
Dylan Copeland 40e3d14449 More optimizations. 2022-10-18 12:25:18 -07:00
Dylan Copeland f5469f73b7 Added NNLS solver for DenseMatrix. Implemented reduced 1D patch rules computed by NNLS. Modified ex1 to compare timing of patch- and element-assembly. 2022-10-07 13:45:11 -07:00
Jacob Lotz 8b1df3016d Removed patch orientation part of CheckPatches completely. Patch orientation is not important anymore 2022-10-05 16:12:25 +02:00
Jacob Lotz 1bfce790ae Uncommented part of CheckPatches 2022-10-05 15:42:31 +02:00
Jacob Lotz e39b7498fc fix Generate knot 2 edge mapping 2022-10-05 15:38:23 +02:00
Jacob Lotz 838cc607b6 Test cases added and clean up 2022-10-03 16:01:10 +02:00
Jacob Lotz fddc4fb9e1 More naming updates 2022-10-03 14:31:04 +02:00
Jacob Lotz 06a49e3e42 Improved naming and prettify KnotInsert 2022-10-03 14:24:50 +02:00
Jacob Lotz 5577701da0 Small bug fixes due to testing. 2D KnotInsert and DegreeElevate works 2022-10-03 10:42:18 +02:00
Jacob Lotz 10b486fe47 Copied edge2knot mapping. Implementation should now be complete. Also make style.
To do:
- Testing
- Remove/adapt CheckPatches: maybe knotvector check is useful?
2022-09-30 16:12:06 +02:00
Jacob Lotz a0d1e57794 Commented out check in CheckPatches. When the implementation is succesfull the orientation/combination/glueing of the patches is much more flexible and this check is not required anymore. This check can then be removed entirely. 2022-09-30 15:49:00 +02:00
Jacob Lotz d370ba7ff3 removed debug statements 2022-09-30 15:39:53 +02:00
Jacob Lotz 99338fd4de Fix 2 bugs, one in constructor where the wrong function is called. One in splitting the order comparison as kv->difference cannot compare knotvectors of different orders. All nurbs miniapps test now succesful 2022-09-30 15:37:37 +02:00
Jacob Lotz d7573ec13b Start implementation extended array of knotvectors. A lot of tests failing... 2022-09-30 15:17:06 +02:00
Jacob Lotz 555dec9d2c Add debug statements 2022-09-30 13:08:22 +02:00
Jacob Lotz cee9e87fde Added KVExt2KV which updates the unique set of knotvectors. Also make style 2022-09-30 13:04:15 +02:00
Jacob Lotz 2380adc193 Fixed naming ussue and added function to verify that both sets of knotvectors are equal 2022-09-30 10:51:39 +02:00
Jacob Lotz 57397e0373 Adds a function which creates an extended set of KnotVectors 2022-09-30 10:26:42 +02:00
Jacob Lotz 5f0b9d52ff Adding a function which checks the direction of the knotvectors 2022-09-30 09:52:03 +02:00
Jacob Lotz cd36c676eb Adding testcase 2022-09-29 17:10:36 +02:00
Dylan Copeland 901a2143b7 Replacing DenseMatrix assembly of patch matrices with SparseMatrix row assembly. 2022-09-06 11:35:24 -07:00
Dylan Copeland 780f383762 Implemented SparseMatrix patch assembly for the transpose (assuming symmetric matrix). 2022-09-02 21:22:54 -07:00
Dylan Copeland 77a58cd1ab Minor improvements. 2022-09-02 15:00:51 -07:00
Dylan Copeland debdaff7b2 Optimized the sum factorization loops in AssemblePatchMatrix. 2022-09-02 14:41:49 -07:00
Dylan Copeland 161163a160 Generalizing for non-unit knot spans. 2022-08-24 15:08:37 -07:00
Dylan Copeland 913c80e05f Debugged the beam-hex-nurbs.mesh example (after DegreeElevate). 2022-08-24 13:58:56 -07:00
Dylan Copeland 1afe29794a Fixing some bugs. 2022-08-17 21:05:58 -07:00
Dylan Copeland b03e51fdac Adding the option for patch-wise matrix assembly on NURBS meshes, with a DiffusionIntegrator example using sum factorization similar to PA. Currently it runs with incorrect results. 2022-08-17 12:11:33 -07:00
Dylan Copeland 12c9aa6207 Added the capability to set element rules that are used instead of the patch rules. 2022-07-13 13:00:45 -07:00
Dylan Copeland 08353d2c4f Some refactoring and documentation. 2022-07-08 10:43:39 -07:00
Dylan Copeland a96b9f873b Implemented element-wise IntegrationRules based on patch 1D rules, with an example in ex1. 2022-06-28 18:07:42 -07:00
Dylan Copeland 6723095508 Adding the capability, with an example, to set a different IntegrationRule on each patch. 2022-06-27 15:23:01 -07:00
Dylan Copeland 6dd313d466 Beginning to implement NURBS patch quadrature rules. 2022-06-22 11:05:10 -07:00
blaz 73c91489de Initial version with external data 2022-06-17 13:45:11 -07:00
blaz 5845a45d5b First commit for a KDTree implementation 2022-05-06 11:40:07 -07:00
Vladimir Z Tomov f09e08bb8f tri/tet/hex sample runs. 2022-03-31 20:21:45 -07:00
Vladimir Z Tomov 4b1709a418 More complicated test. 2022-03-29 15:21:44 -07:00
Vladimir Z Tomov 5429f7af4a Fixed the fitting error computation. 2022-03-28 16:24:36 -07:00
Vladimir Z Tomov c9accc9abe AssembleElementGrad. 2022-03-25 14:27:02 -07:00
Vladimir Z Tomov 331111c3d3 GetElementVector for limited fitting. 2022-03-24 15:42:05 -07:00
Vladimir Z Tomov d93891f6c1 Data structured and elementEnergy for new fitting. 2022-03-24 13:46:41 -07:00
255 changed files with 21687 additions and 3453 deletions
@@ -1,7 +1,6 @@
name: "Docker"
on:
# Always have a base image ready to go - this is a nightly build
schedule:
- cron: 0 3 * * *
@@ -26,7 +25,6 @@ jobs:
strategy:
fail-fast: false
matrix:
# Dockerfiles to build, a matrix supports future expanded builds
container: [["config/docker/Dockerfile.base", "ghcr.io/mfem/mfem-ubuntu-base"],
["config/docker/Dockerfile", "ghcr.io/mfem/mfem-ubuntu"]]
@@ -34,15 +32,20 @@ jobs:
runs-on: ubuntu-latest
name: Build
steps:
- name: Run Actions Cleaner
uses: easimon/maximize-build-space@v8
with:
overprovision-lvm: 'true'
remove-dotnet: 'true'
remove-android: 'true'
remove-haskell: 'true'
remove-codeql: 'true'
remove-docker-images: 'true'
- name: Checkout
uses: actions/checkout@v3
- name: Make Space For Build
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
# It's easier to reference named variables than indexes of the matrix
# It's easier to reference named variables than indexes of the matrix
- name: Set Environment
env:
dockerfile: ${{ matrix.container[0] }}
+168 -157
View File
@@ -65,13 +65,16 @@ jobs:
# - Add a new combination.
# 'build-system: cmake' and 'hypre-target: int64'
#
# note: we will gather coverage info for any non-debug run except the
# Note: we will gather coverage info for any non-debug run except the
# CMake build.
include:
- target: dbg
codecov: NO
- target: opt
codecov: YES
- os: ubuntu-latest
target: dbg
config-opts: 'CPPFLAGS+=-Og'
- os: windows-latest
codecov: NO
- os: windows-latest
@@ -98,181 +101,189 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
# This external action allows to interrupt a workflow already running on
# the same branch to save resource
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
# This external action allows to interrupt a workflow already running on
# the same branch to save resources.
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
# Checkout MFEM in "mfem" subdirectory. Final path:
# /home/runner/work/mfem/mfem/mfem
# Note: Done now to access "install-hypre" and "install-metis" actions.
- name: checkout mfem
uses: actions/checkout@v3
with:
path: ${{ env.MFEM_TOP_DIR }}
# Fetch the complete history for codecov to access commits ID
fetch-depth: 0
# Fix 'No space left on device' errors for Ubuntu builds.
- name: Run Actions Cleaner
if: matrix.os == 'ubuntu-latest'
uses: easimon/maximize-build-space@v8
with:
overprovision-lvm: 'true'
remove-android: 'true'
# Only get MPI if defined for the job.
# TODO: It would be nice to have only one step, e.g. with a dedicated
# action, but I (@adrienbernede) don't see how at the moment.
- name: get MPI (Linux)
if: matrix.mpi == 'par' && matrix.os == 'ubuntu-latest'
run: |
sudo apt-get install mpich libmpich-dev
# Checkout MFEM in "mfem" subdirectory. Final path:
# /home/runner/work/mfem/mfem/mfem
# Note: Done now to access "install-hypre" and "install-metis" actions.
- name: checkout mfem
uses: actions/checkout@v3
with:
path: ${{ env.MFEM_TOP_DIR }}
# Fetch the complete history for codecov to access commits ID
fetch-depth: 0
- name: get lcov (Linux)
if: matrix.codecov == 'YES' && matrix.os == 'ubuntu-latest'
run: |
sudo apt-get install lcov
# Only get MPI if defined for the job.
# TODO: It would be nice to have only one step, e.g. with a dedicated
# action, but I (@adrienbernede) don't see how at the moment.
- name: get MPI (Linux)
if: matrix.mpi == 'par' && matrix.os == 'ubuntu-latest'
run: |
sudo apt-get install mpich libmpich-dev
# Keep the following section in case we need it again in the future,
# see: https://github.com/mfem/mfem/pull/3385#discussion_r1058013032
# - name: Set up Homebrew
# if: ( matrix.mpi == 'par' || matrix.codecov == 'YES' ) && matrix.os == 'macos-latest'
# uses: Homebrew/actions/setup-homebrew@master
- name: get lcov (Linux)
if: matrix.codecov == 'YES' && matrix.os == 'ubuntu-latest'
run: |
sudo apt-get install lcov
- name: get MPI (MacOS)
if: matrix.mpi == 'par' && matrix.os == 'macos-latest'
run: |
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install openmpi
# Keep the following section in case we need it again in the future,
# see: https://github.com/mfem/mfem/pull/3385#discussion_r1058013032
# - name: Set up Homebrew
# if: ( matrix.mpi == 'par' || matrix.codecov == 'YES' ) && matrix.os == 'macos-latest'
# uses: Homebrew/actions/setup-homebrew@master
- name: get lcov (MacOS)
if: matrix.codecov == 'YES' && matrix.os == 'macos-latest'
run: |
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install lcov
- name: get MPI (MacOS)
if: matrix.mpi == 'par' && matrix.os == 'macos-latest'
run: |
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install openmpi
- name: get MPI (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
uses: mpi4py/setup-mpi@v1.1.4
- name: get lcov (MacOS)
if: matrix.codecov == 'YES' && matrix.os == 'macos-latest'
run: |
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install lcov
# Get Hypre through cache, or build it.
# Install will only run on cache miss.
- name: cache hypre
id: hypre-cache
if: matrix.mpi == 'par'
uses: actions/cache@v3
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-v2.2
- name: get MPI (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
uses: mpi4py/setup-mpi@v1.1.4
- 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.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: make
# Get Hypre through cache, or build it.
# Install will only run on cache miss.
- name: cache hypre
id: hypre-cache
if: matrix.mpi == 'par'
uses: actions/cache@v3
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-v2.2
- 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.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: cmake
- 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.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: make
# Get Metis through cache, or build it.
# Install will only run on cache miss.
- name: cache metis
id: metis-cache
if: matrix.mpi == 'par' && matrix.os != 'windows-latest'
uses: actions/cache@v3
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
- 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.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: cmake
- 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.4
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
# Get Metis through cache, or build it.
# Install will only run on cache miss.
- name: cache metis
id: metis-cache
if: matrix.mpi == 'par' && matrix.os != 'windows-latest'
uses: actions/cache@v3
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
- name: cache vcpkg (Windows)
id: vcpkg-cache
if: matrix.os == 'windows-latest'
uses: actions/cache@v3
with:
path: vcpkg_cache
key: ${{ runner.os }}-${{ matrix.mpi }}-vcpkg-v1
- 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.4
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
- name: prepare vcpkg binary cache location (Windows)
if: matrix.os == 'windows-latest' && steps.vcpkg-cache.outputs.cache-hit != 'true'
run: |
mkdir -p vcpkg_cache
- name: cache vcpkg (Windows)
id: vcpkg-cache
if: matrix.os == 'windows-latest'
uses: actions/cache@v3
with:
path: vcpkg_cache
key: ${{ runner.os }}-${{ matrix.mpi }}-vcpkg-v1
- name: install metis (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
run: |
vcpkg install metis-mfem --triplet=x64-windows-static --overlay-ports=${{ env.MFEM_TOP_DIR }}/config/vcpkg/ports
- name: prepare vcpkg binary cache location (Windows)
if: matrix.os == 'windows-latest' && steps.vcpkg-cache.outputs.cache-hit != 'true'
run: |
mkdir -p vcpkg_cache
# MFEM build and test
- name: build
uses: mfem/github-actions/build-mfem@v2.4
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
with:
os: ${{ matrix.os }}
target: ${{ matrix.target }}
codecov: ${{ matrix.codecov }}
mpi: ${{ matrix.mpi }}
build-system: ${{ matrix.build-system }}
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
mfem-dir: ${{ env.MFEM_TOP_DIR }}
config-options: ${{ matrix.config-opts }}
library-only: ${{ matrix.target == 'dbg' }}
- name: install metis (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
run: |
vcpkg install metis-mfem --triplet=x64-windows-static --overlay-ports=${{ env.MFEM_TOP_DIR }}/config/vcpkg/ports
# Run checks (and only checks) on debug targets
- name: checks
if: matrix.build-system == 'make' && matrix.target == 'dbg'
run: |
cd ${{ env.MFEM_TOP_DIR }} && make check
# MFEM build and test
- name: build
uses: mfem/github-actions/build-mfem@v2.4
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
with:
os: ${{ matrix.os }}
target: ${{ matrix.target }}
codecov: ${{ matrix.codecov }}
mpi: ${{ matrix.mpi }}
build-system: ${{ matrix.build-system }}
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
mfem-dir: ${{ env.MFEM_TOP_DIR }}
config-options: ${{ matrix.config-opts }}
library-only: ${{ matrix.target == 'dbg' && matrix.os != 'ubuntu-latest' }}
# Note: 'tests' include the unit tests
- name: tests
if: matrix.build-system == 'make' && matrix.target == 'opt'
run: |
cd ${{ env.MFEM_TOP_DIR }} && make test
# Run checks (and only checks) on debug targets
- name: checks
if: matrix.build-system == 'make' && matrix.target == 'dbg'
run: |
cd ${{ env.MFEM_TOP_DIR }} && make check
- name: cmake checks
if: matrix.build-system == 'cmake' && matrix.target == 'dbg'
run: |
CTEST_CONFIG="Debug"
cd ${{ env.MFEM_TOP_DIR }} && cmake --build build --target check --config ${CTEST_CONFIG}
shell: bash
# Note: 'tests' include the unit tests
- name: tests
if: matrix.build-system == 'make' && (matrix.target == 'opt' || matrix.os == 'ubuntu-latest')
run: |
cd ${{ env.MFEM_TOP_DIR }} && make test
- name: cmake unit tests (Ubuntu)
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os == 'ubuntu-latest'
run: |
CTEST_CONFIG="Release"
[[ ${{ matrix.target }} == 'dbg' ]] && CTEST_CONFIG="Debug"
cd ${{ env.MFEM_TOP_DIR }}/build/tests/unit && ctest --output-on-failure -C ${CTEST_CONFIG}
shell: bash
- name: cmake checks
if: matrix.build-system == 'cmake' && matrix.target == 'dbg'
run: |
CTEST_CONFIG="Debug"
cd ${{ env.MFEM_TOP_DIR }} && cmake --build build --target check --config ${CTEST_CONFIG}
shell: bash
- name: cmake tests
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} || \
ctest --rerun-failed --output-on-failure -C ${CTEST_CONFIG}
shell: bash
- name: cmake unit tests (Ubuntu)
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os == 'ubuntu-latest'
run: |
CTEST_CONFIG="Release"
[[ ${{ matrix.target }} == 'dbg' ]] && CTEST_CONFIG="Debug"
cd ${{ env.MFEM_TOP_DIR }}/build/tests/unit && ctest --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.4
with:
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
project_dir: ${{ env.MFEM_TOP_DIR }}
directories: "fem general linalg mesh"
- name: cmake tests
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} || \
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.4
with:
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
project_dir: ${{ env.MFEM_TOP_DIR }}
directories: "fem general linalg mesh"
+27 -28
View File
@@ -13,10 +13,10 @@ name: "Static Analysis"
on:
push:
branches: [ "master", "next"]
branches: ["master", "next"]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master" ]
branches: ["master"]
jobs:
analyze:
@@ -35,36 +35,35 @@ jobs:
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
+55 -55
View File
@@ -34,67 +34,67 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: checkout MFEM
uses: actions/checkout@v3
with:
path: mfem
- name: checkout MFEM
uses: actions/checkout@v3
with:
path: mfem
- name: Get MPI (Linux)
run: |
sudo apt-get install mpich libmpich-dev
- name: Get MPI (Linux)
run: |
sudo apt-get install mpich libmpich-dev
- name: Cache Hypre Install
id: hypre-cache
uses: actions/cache@v3
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.2
- name: Cache Hypre Install
id: hypre-cache
uses: actions/cache@v3
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.2
- name: Get Hypre
if: steps.hypre-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-hypre@v2.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: int32
- name: Get Hypre
if: steps.hypre-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-hypre@v2.4
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: int32
- name: Cache Metis Install
id: metis-cache
uses: actions/cache@v3
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
- name: Cache Metis Install
id: metis-cache
uses: actions/cache@v3
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
- name: Install Metis
if: steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.4
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
- name: Install Metis
if: steps.metis-cache.outputs.cache-hit != 'true'
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.4
with:
os: ${{ runner.os }}
target: opt
codecov: NO
mpi: par
build-system: make
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
mfem-dir: mfem
# MFEM build and test
- name: build-mfem
uses: mfem/github-actions/build-mfem@v2.4
with:
os: ${{ runner.os }}
target: opt
codecov: NO
mpi: par
build-system: make
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
mfem-dir: mfem
- name: test (no clean)
run: |
cd mfem && make test-noclean
- name: test (no clean)
run: |
cd mfem && make test-noclean
- name: gitignore
run: |
cd mfem/tests/scripts
./runtest gitignore
- name: gitignore
run: |
cd mfem/tests/scripts
./runtest gitignore
+37 -37
View File
@@ -27,44 +27,44 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- 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 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 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 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
- 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
+70 -70
View File
@@ -33,49 +33,49 @@ jobs:
(github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: checkout mfem
uses: actions/checkout@v3
- name: checkout mfem
uses: actions/checkout@v3
- name: copyright check
id: copyright
run: |
./config/githooks/pre-push --copyright
- name: copyright check
id: copyright
run: |
./config/githooks/pre-push --copyright
continue-on-error: true
continue-on-error: true
- name: license check
id: license
run: |
./config/githooks/pre-push --license
continue-on-error: true
- name: license check
id: license
run: |
./config/githooks/pre-push --license
continue-on-error: true
- name: release check
id: release
run: |
./config/githooks/pre-push --release
continue-on-error: true
- name: release check
id: release
run: |
./config/githooks/pre-push --release
continue-on-error: true
- name: wrap-up
if: |
steps.copyright.outcome != 'success' ||
steps.license.outcome != 'success' ||
steps.release.outcome != 'success'
run: |
if [[ "${{ steps.copyright.outcome }}" != "success" ]]; then
echo "copyright check failed, unroll log for details"
fi
if [[ "${{ steps.license.outcome }}" != "success" ]]; then
echo "license check failed, unroll log for details"
fi
if [[ "${{ steps.release.outcome }}" != "success" ]]; then
echo "release check failed, unroll log for details"
fi
exit 1
- name: wrap-up
if: |
steps.copyright.outcome != 'success' ||
steps.license.outcome != 'success' ||
steps.release.outcome != 'success'
run: |
if [[ "${{ steps.copyright.outcome }}" != "success" ]]; then
echo "copyright check failed, unroll log for details"
fi
if [[ "${{ steps.license.outcome }}" != "success" ]]; then
echo "license check failed, unroll log for details"
fi
if [[ "${{ steps.release.outcome }}" != "success" ]]; then
echo "release check failed, unroll log for details"
fi
exit 1
code-style:
runs-on: ubuntu-latest
@@ -83,16 +83,16 @@ jobs:
(github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v3
- name: checkout mfem
uses: actions/checkout@v3
- name: get astyle
run: |
sudo apt-get install astyle
- name: get astyle
run: |
sudo apt-get install astyle
- name: style check
run: |
./config/githooks/pre-push --style
- name: style check
run: |
./config/githooks/pre-push --style
documentation:
runs-on: ubuntu-latest
@@ -100,22 +100,22 @@ jobs:
(github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v3
- name: checkout mfem
uses: actions/checkout@v3
- name: get doxygen and graphviz
run: |
sudo apt-get install doxygen graphviz
- name: get doxygen and graphviz
run: |
sudo apt-get install doxygen graphviz
- name: update doxygen config file
run: |
cd doc
doxygen -u CodeDocumentation.conf.in
- name: update doxygen config file
run: |
cd doc
doxygen -u CodeDocumentation.conf.in
- name: build documentation
run: |
cd tests/scripts
./runtest documentation
- name: build documentation
run: |
cd tests/scripts
./runtest documentation
branch-history:
if: |
@@ -125,16 +125,16 @@ jobs:
github.event.pull_request.head.repo.full_name != github.repository)
runs-on: ubuntu-latest
steps:
- name: checkout mfem
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: checkout mfem
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: branch-history
run: |
# We override origin to make sure we point to the main repo.
# This is to have consistent test results on PRs from forks.
git remote remove origin
git remote add origin https://github.com/mfem/mfem.git
git checkout -b gh-actions-branch-history
./config/githooks/pre-push --history
- name: branch-history
run: |
# We override origin to make sure we point to the main repo.
# This is to have consistent test results on PRs from forks.
git remote remove origin
git remote add origin https://github.com/mfem/mfem.git
git checkout -b gh-actions-branch-history
./config/githooks/pre-push --history
+16
View File
@@ -113,6 +113,12 @@ examples/ex25p-*.*
examples/ex28_*
examples/ex28p_*
examples/flux.*
examples/dsol.*
examples/cond.*
examples/cond_j.*
examples/cond_mesh.*
examples/port_mesh.*
examples/port_mode.*
examples/amgx/ex1
examples/amgx/ex1p
@@ -207,6 +213,7 @@ miniapps/meshing/twist
miniapps/meshing/mesh-explorer
miniapps/meshing/shaper
miniapps/meshing/extruder
miniapps/meshing/fit-node-position
miniapps/meshing/trimmer
miniapps/meshing/reflector
miniapps/meshing/mesh-optimizer
@@ -259,11 +266,15 @@ miniapps/navier/*_output
miniapps/nurbs/nurbs_ex1
miniapps/nurbs/nurbs_ex1p
miniapps/nurbs/nurbs_ex11p
miniapps/nurbs/nurbs_patch_ex1
miniapps/nurbs/nurbs_curveint
miniapps/nurbs/refined.mesh
miniapps/nurbs/mesh.*
miniapps/nurbs/sol.*
miniapps/nurbs/mode_*
miniapps/nurbs/Example1*
miniapps/nurbs/sin-fit.mesh
miniapps/nurbs/CurveInt
miniapps/performance/ex1
miniapps/performance/ex1p
@@ -286,9 +297,14 @@ miniapps/tools/display-basis
miniapps/tools/load-dc
miniapps/tools/convert-dc
miniapps/tools/lor-transfer
miniapps/tools/plor-transfer
miniapps/tools/get-values
miniapps/tools/check-tmop-metric
miniapps/tools/tmop-metric-magnitude
miniapps/tools/nodal-transfer
miniapps/tools/ParaView
miniapps/tools/gridfunc_*
miniapps/tools/mesh_*
miniapps/toys/automata
miniapps/toys/life
+106 -47
View File
@@ -8,79 +8,138 @@
https://mfem.org
Version 4.5.3 (development)
Version 4.6.1 (development)
===========================
Version 4.6, released on September 27, 2023
===========================================
- MFEM is now available in Homebrew and can be installed on a Mac with just
"brew install mfem". See https://formulae.brew.sh/formula/mfem.
Meshing improvements
--------------------
- Added asymptotically-balanced TMOP compound metrics 90, 94, 328, 338. A new
tool, tmop-metric-magnitude, can be used to track how metrics change under
geometric perturbations. See miniapps/tools.
- Several NURBS meshing improvements:
* Support for free connectivity of NURBS patches allowing for more complex
patch configurations such as C-meshes.
* New methods to set and get attributes on NURBS patches and patch boundaries.
* The edge to knot map for NURBS meshes can be determined automatically. It is
no longer needed to specify this in the NURBS mesh.
* Added curve interpolation method for NURBS.
* See miniapps/nurbs for example meshes and miniapps.
Discretization improvements
---------------------------
- SubMesh and ParSubMesh have been extended to support the transfer of
Nedelec and Raviart-Thomas finite element spaces.
- Added support for partial assembly on NURBS patches, and NURBS-patch sparse
matrix assembly. Patch matrix assembly includes the option to use reduced
approximate integration rules, computed by the newly implemented non-negative
least-squares (NNLS) solver.
- Support for parallel transfer of H1 fields using the low-order refined (LOR)
transfer operators in L2ProjectionGridTransfer
- Added KDTree class for 2D/3D set of points, which is then utilized in the new
KDTreeNodalProjection class to project a function defined on an arbitrary set
of points onto an MFEM grid function. This functionality is demonstrated in
the nodal-transfer miniapp. The current implementation is serial only. Further
extensions can include search in arbitrary dimensional spaces.
- Added support for p-refined meshes in GSLIB-FindPoints.
- Device kernels can now access device-specific DOF and quadrature limits using
the DofQuadLimits structure, allowing increased limits when executing on CPU.
The limits for the runtime selected device can be accessed in host code using
DeviceDofQuadLimits::Get(). The global constants MAX_D1D and MAX_Q1D are no
longer available.
- Face restriction operators for Nedelec and Raviart-Thomas finite element
spaces are now supported through the ConformingFaceRestriction class.
- VectorFEBoundaryFluxLFIntegrator is now supported on device/GPU.
Linear and nonlinear solvers
----------------------------
- Updated the MUMPS interface 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.
The 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.
- Added HIP support to the PETSc and SUNDIALS interfaces.
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 a new H(div) solver miniapp 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. See miniapps/hdiv-linear-solver.
- 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.
NormalTraceIntegrator and TangentTraceIntegrator. See miniapps/dpg.
- 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 new miniapp that implements the SPDE method for generating Gaussian
random fields of Matern covariance. The resulting random field can be used,
e.g., to model material uncertainties. See miniapps/spde.
- Added a new parallel LOR transfer miniapp, plor-transfer, which mirrors the
functionality of the serial LOR transfer miniapp. See miniapps/tools.
- New serial miniapp, nodal-transfer, demonstrating the use of KDTree to map a
parallel grid function to a different parallel partitioning of the same mesh.
- Added 3 additional TMOP miniapps in miniapps/meshing:
* Mesh-Quality evaluates quality using size, skewness, and aspect-ratio
computed from the Jacobian of the transformation.
* Mesh-Fitting can be used for interface and boundary fitting to implicit
domains defined using level-set functions.
* Fit-Node-Position fits selected mesh nodes to specified positions, while
maintaining overall mesh quality.
- Added 4 new example codes:
* Example 34/34p solves a simple magnetostatic problem where source terms and
boundary conditions are transferred with SubMesh objects.
* Example 35p implements H1, H(curl) and H(div) variants of a damped harmonic
oscillator with field transfer using SubMesh objects.
* Example 36/36p demonstrates the solution of the obstacle problem with a new
finite element method (proximal Galerkin).
* Example 37/37p demonstrates topology optimization with MFEM.
- 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.
- Added HIP support to the SUNDIALS interface.
- 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
---------------------------
- Face restriction operators for Nedelec and Raviart-Thomas finite element
spaces are now supported through the ConformingFaceRestriction class.
- VectorFEBoundaryFluxLFIntegrator is now supported on device/GPU.
- Added support for p-refined meshes in FindPointsGSLIB.
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.
- Added an address sanitizer GitHub action for a serial build/test on Ubuntu,
based on Clang/LLVM (https://clang.llvm.org/docs/AddressSanitizer.html).
- Reorganized files for bilinear form, linear form, and nonlinear form integrators
in the fem/integ/ subdirectory.
- FiniteElementSpace::GetFE has been updated to abort instead of returning NULL for
an empty partition.
- Various other simplifications, extensions, and bugfixes in the code.
Version 4.5.2, released on March 23, 2023
=========================================
+2 -2
View File
@@ -57,7 +57,7 @@ project(mfem NONE)
# Current version of MFEM, see also `makefile`.
# mfem_VERSION = (string)
# MFEM_VERSION = (int) [automatically derived from mfem_VERSION]
set(${PROJECT_NAME}_VERSION 4.5.3)
set(${PROJECT_NAME}_VERSION 4.6.1)
# Prohibit in-source build
if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR})
@@ -138,7 +138,7 @@ if (MFEM_USE_CUDA)
set(CUDA_FLAGS "-ccbin=${CMAKE_CXX_COMPILER} ${CUDA_FLAGS}")
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CMAKE_CXX_COMPILER})
endif()
set(CMAKE_CUDA_FLAGS ${CMAKE_CUDA_FLAGS} ${CUDA_FLAGS})
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} ${CUDA_FLAGS}")
set(CUSPARSE_FOUND TRUE)
set(CUSPARSE_LIBRARIES "cusparse")
set(CUBLAS_FOUND TRUE)
+2
View File
@@ -135,6 +135,7 @@ The MFEM source code has the following structure:
│ ├── adjoint
│ ├── autodiff
│ ├── common
│ ├── dpg
│ ├── electromagnetics
│ ├── gslib
│ ├── hdiv-linear-solver
@@ -148,6 +149,7 @@ The MFEM source code has the following structure:
│ ├── performance
│ ├── shifted
│ ├── solvers
│ ├── spde
│ ├── tools
│ └── toys
└── tests
+5 -2
View File
@@ -699,12 +699,15 @@ The specific libraries and their options are:
PETSc has been cloned on the same level as mfem and hypre:
./configure --download-fblaslapack=yes --download-scalapack=yes \
--download-mumps=yes --download-suitesparse=yes \
--with-hypre-dir=../hypre-2.10.0b/src/hypre \
--with-hypre-dir=../hypre/src/hypre \
--with-shared-libraries=0
When building PETSc with HIP, one may need to add a flag like -std=c2x to
CFLAGS to allow proper parsing of the hipsparse header under C.
URL: https://www.mcs.anl.gov/petsc
Options: PETSC_OPT, PETSC_LIB.
Versions: PETSc >= 3.8.0 (PETSc build without CUDA)
Versions: PETSc >= 3.8.0 (PETSc build without CUDA/HIP)
PETSc >= 3.15.0 (PETSc built with CUDA)
PETSc >= 3.19.0 (PETSc built with HIP, older versions may work too)
- SLEPc (optional), used when MFEM_USE_SLEPC = YES. SLEPc depends on PETSc and
uses some of the PETSc options when compiled.
-2
View File
@@ -19,9 +19,7 @@ RUN apt-get update && \
apt-get install -y libcurl4-openssl-dev libssl-dev
ENV PATH=$PATH:/opt/mfem-view/bin
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/mfem-view/lib:/opt/mfem-view/lib64
ENV DEBIAN_FRONTEND=noninteractive
# The user will see the view on shell into the container
WORKDIR /opt/mfem-view
ENTRYPOINT ["/bin/bash"]
+6 -6
View File
@@ -34,14 +34,14 @@ RUN cd /opt/mfem-env && \
. /opt/spack/share/spack/setup-env.sh && \
spack env activate . && \
spack develop --path /code mfem@master+examples+miniapps && \
spack add mfem@master+examples+miniapps # && \
# spack install
spack add mfem@master+examples+miniapps && \
spack install
# ensure mfem always on various paths
#RUN cd /opt/mfem-env && \
# spack env activate --sh -d . >> /etc/profile.d/z10_spack_environment.sh
RUN cd /opt/mfem-env && \
spack env activate --sh -d . >> /etc/profile.d/z10_spack_environment.sh
# Present the software install when we shell in
# The view is at /opt/mfem-env/.spack-env/view
#WORKDIR /opt/software
#ENTRYPOINT ["/bin/bash", "--rcfile", "/etc/profile", "-l", "-c"]
WORKDIR /opt/software
ENTRYPOINT ["/bin/bash", "--rcfile", "/etc/profile", "-l", "-c"]
+108 -46
View File
@@ -7,21 +7,31 @@ You can use this image for a demo of using mfem! 🎉️
Updated containers are built and deployed on merges to the main branch and releases.
If you want to request a build on demand, you can [manually run the workflow](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow) thanks to the workflow dispatch event.
### Usage
## Usage
Here is how to build the container. Note that we build so it belongs to the same
namespace as the repository here. "ghcr.io" means "GitHub Container Registry" and
We provide two containers, which you can either build or use directly from
[GitHub packages](https://github.com/orgs/mfem/packages?repo_name=mfem).
- `ghcr.io/mfem/mfem-ubuntu-base`: a "build from scratch" for mfem
- `ghcr.io/mfem/mfem-ubuntu`: a quick build that uses the base container
In the above, "ghcr.io" means "GitHub Container Registry" and
is the [GitHub packages](https://github.com/features/packages) registry that supports
Docker images and other OCI artifacts. From the root of the repository:
Docker images and other OCI artifacts.
### Ubuntu
> Use or build this container for a multi-stage, slimmer base to develop on top of mfem
Note that this container is provided on GitHub packages [here](https://github.com/mfem/mfem/pkgs/container/mfem-ubuntu)
so you don't need to build it. However, if you want to, you can do the following:
```bash
$ docker build -f config/docker/Dockerfile -t ghcr.io/mfem/mfem-ubuntu .
$ docker build -f config/docker/Dockerfile.base -t ghcr.io/mfem/mfem-ubuntu-base .
```
### Shell Ubuntu
To shell into the container:
Note that this will pull the base image. If you want to rebuild it, see [ubuntu base](#ubuntu-base)
below. Once you have built (or prefer to pull) you can shell into the container as follows:
```bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu
@@ -37,39 +47,13 @@ bin etc include lib libexec sbin share var
- Examples are in share/mfem/examples
- Examples are in share/mfem/miniapps
You can read more about interaction with these examples and miniapps below.
### Shell Ubuntu Base
To shell into the container:
Using this container, if you want to develop a tool that _uses_ mfem, you can find the libraries / includes in:
```bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base bash
```
Off the bat, you can see mfem libraries are in your path so you can jump into development:
```bash
env | grep mfem
```
```bash
PKG_CONFIG_PATH=/opt/mfem-env/.spack-env/view/lib/pkgconfig:/opt/mfem-env/.spack-env/view/share/pkgconfig:/opt/mfem-env/.spack-env/view/lib64/pkgconfig
PWD=/opt/mfem-env
MANPATH=/opt/mfem-env/.spack-env/view/share/man:/opt/mfem-env/.spack-env/view/man:
CMAKE_PREFIX_PATH=/opt/mfem-env/.spack-env/view
SPACK_ENV=/opt/mfem-env
ACLOCAL_PATH=/opt/mfem-env/.spack-env/view/share/aclocal
LD_LIBRARY_PATH=/opt/mfem-env/.spack-env/view/lib:/opt/mfem-env/.spack-env/view/lib64
PATH=/opt/mfem-env/.spack-env/view/bin:/opt/view/bin:/opt/spack/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
```
#### Examples and MiniApps
If you want to develop a tool that _uses_ mfem, you can find the built libraries in:
```
$ ls /opt/mfem-env/.spack-env/view/
bin etc include lib libexec sbin share var
$ ls include/ | grep mfem
mfem
mfem-performance.hpp
mfem.hpp
```
And yes, this is the working directory when you shell into the container!
@@ -79,6 +63,16 @@ You can find the examples here:
```bash
cd share/mfem/examples
```
Try quickly setting the `LD_LIBRARY_PATH` so we can see the shared libraries
we need:
```bash
export LD_LIBRARY_PATH=/opt/mfem-view/lib:$LD_LIBRARY_PATH
```
And then run:
```bash
$ ./ex0
Options used:
@@ -97,7 +91,6 @@ Number of unknowns: 101
Average reduction factor = 0.140201
```
Try running a few, and look at the associated .cpp file for the source code!
You can also explore the "mini apps," also in share/mfem, but under miniapps.
```bash
@@ -130,18 +123,87 @@ Rule:
Applying rule...done.
```
Have fun!
Have fun! As a reminder, this container is ideal for developing your own
applications that might use mfem, or having a nice environment to test out
examples.
#### Your own App
If you want to develop with your own code base
(and mfem as is in the container) you can bind to somewhere else in the container (e.g., src)
### Ubuntu Base
> Use this build for a development environment with spack and mfem
This container is also [provided on GitHub packages](https://github.com/mfem/mfem/pkgs/container/mfem-ubuntu-base),
however you can build it locally too:
```bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base -v $PWD:/src bash
$ docker build -f config/docker/Dockerfile.base -t ghcr.io/mfem/mfem-ubuntu-base .
```
To shell into the container:
```bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base bash
```
Change directory to the mfem environment, setup spack, and activate the environment:
```bash
source /opt/spack/share/spack/setup-env.sh
cd /opt/mfem-env/
spack env activate .
```
Note that this environment is installing to the view at `/opt/view`. Since the environment
knows to install mfem from `/code` this means that you could make changes in the container (or bind
`/code` to your container) and then update spack:
```bash
# Note that concretization takes a hot minute!
$ spack install
```
And if you want to load mfem:
```bash
$ spack load mfem
$ env | grep mfem
```
In this development container, you can find the examples and miniapps alongside
mfem under `/code`:
```bash
cd /code/examples
```
```bash
$ ./ex0
```
```console
Options used:
--mesh ../data/star.mesh
--order 1
Number of unknowns: 101
Iteration : 0 (B r, r) = 0.184259
Iteration : 1 (B r, r) = 0.102754
Iteration : 2 (B r, r) = 0.00558141
Iteration : 3 (B r, r) = 1.5247e-05
Iteration : 4 (B r, r) = 1.13807e-07
Iteration : 5 (B r, r) = 6.27231e-09
Iteration : 6 (B r, r) = 3.76268e-11
Iteration : 7 (B r, r) = 6.07423e-13
Iteration : 8 (B r, r) = 4.10615e-15
Average reduction factor = 0.140201
```
This container is likely ideal for someone that wants to develop mfem itself.
For other use cases, we recommend using the slimmer image. As an example,
if you want to develop with your own code base (and mfem as is in the container)
you can bind to somewhere else in the container (e.g., src)
```bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base -v $PWD:/code bash
```
In the above, we can pretend your project is in the present working directory (PWD) and we are
binding to source. You can then use the mfem in the container for development, and if you
want to distribute your library or app in a container, you can use the mfem container as the base.
+37
View File
@@ -0,0 +1,37 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
1
elements
4
1 1 0 1
1 1 1 2
1 1 2 3
1 1 3 4
boundary
2
1 0 0
2 0 4
vertices
5
2
0 0
0.25 0.25
0.50 0.50
0.75 0.75
1 1
+37
View File
@@ -0,0 +1,37 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
1
elements
4
1 1 0 1
1 1 1 2
1 1 2 3
1 1 3 4
boundary
2
1 0 0
2 0 4
vertices
5
3
0 0 0
0.25 0.25 0.25
0.50 0.50 0.50
0.75 0.75 0.75
1 1 1
+48
View File
@@ -0,0 +1,48 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
2
elements
6
1 3 0 1 4 3
1 3 2 3 6 5
1 2 3 4 8
1 2 4 7 8
1 2 7 6 8
1 2 6 3 8
boundary
8
1 1 0 1
2 1 1 4
3 1 4 7
4 1 7 6
5 1 6 5
6 1 5 2
7 1 2 3
8 1 3 0
vertices
9
2
0.5 0
1 0
0 0.5
0.5 0.5
1 0.5
0 1
0.5 1
1 1
0.75 0.75
+44
View File
@@ -0,0 +1,44 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
2
elements
3
1 3 0 1 4 3
1 3 2 3 6 5
1 3 3 4 7 6
boundary
8
1 1 0 1
2 1 1 4
3 1 4 7
4 1 7 6
5 1 6 5
6 1 5 2
7 1 2 3
8 1 3 0
vertices
8
2
0.5 0
1 0
0 0.5
0.5 0.5
1 0.5
0 1
0.5 1
1 1
+322
View File
@@ -0,0 +1,322 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
# PYRAMID = 7
#
dimension
2
elements
26
1 2 1 18 0
1 3 1 3 19 18
2 3 3 6 20 19
1 3 6 9 21 20
2 3 9 12 22 21
1 3 12 15 23 22
2 2 23 15 24
1 2 1 4 3
2 3 4 7 6 3
1 3 7 10 9 6
2 3 10 13 12 9
1 3 13 16 15 12
2 3 16 25 24 15
1 3 2 5 4 1
1 3 5 8 7 4
1 3 8 11 10 7
1 3 11 14 13 10
1 3 14 17 16 13
1 2 25 16 17
1 3 18 19 27 26
2 3 19 20 28 27
1 3 20 21 29 28
2 3 21 22 30 29
1 3 22 23 31 30
2 3 23 24 32 31
1 3 24 25 33 32
boundary
18
1 1 28 27
2 1 30 29
3 1 32 31
4 1 0 1
4 1 1 2
4 1 2 5
4 1 5 8
4 1 8 11
4 1 11 14
4 1 14 17
4 1 17 25
4 1 25 33
4 1 33 32
4 1 31 30
4 1 29 28
4 1 27 26
4 1 26 18
4 1 18 0
vertices
34
nodes
FiniteElementSpace
FiniteElementCollection: H1_2D_P3
VDim: 2
Ordering: 1
0 0
0.53125 0
1 0
0.53125 0.09375
0.5625 0.09375
1 0.09375
0.53125 0.21875
0.6875 0.21875
1 0.1875
0.53125 0.25
0.71875 0.25
1 0.25
0.53125 0.375
0.84375 0.375
1 0.34375
0.53125 0.40625
0.875 0.40625
1 0.40625
0 0.53125
0.09375 0.53125
0.21875 0.53125
0.25 0.53125
0.375 0.53125
0.40625 0.53125
0.53125 0.53125
1 0.53125
0 1
0.09375 1
0.21875 1
0.25 1
0.375 1
0.40625 1
0.53125 1
1 1
0.33175106835972 0.094168845750364
0.094168845750364 0.33175106835972
-5.1759634627347e-17 0.14683388869532
6.5255471622478e-17 0.38441611130468
0.14683388869532 6.0713766400335e-17
0.38441611130468 8.2458945395444e-19
0.53125 0.025911862710939
0.53125 0.067838137289061
0.34721731046049 0.13433915461926
0.13433915461926 0.34721731046049
0.025911862710939 0.53125
0.067838137289061 0.53125
0.53125 0.12829915028125
0.53125 0.18420084971875
0.39979807890035 0.24774225329947
0.24774225329947 0.39979807890035
0.12829915028125 0.53125
0.18420084971875 0.53125
0.53125 0.22738728757031
0.53125 0.24136271242969
0.41294327101031 0.27609302796952
0.27609302796952 0.41294327101031
0.22738728757031 0.53125
0.24136271242969 0.53125
0.53125 0.28454915028125
0.53125 0.34045084971875
0.46552403945017 0.38949612664974
0.38949612664974 0.46552403945017
0.28454915028125 0.53125
0.34045084971875 0.53125
0.53125 0.38363728757031
0.53125 0.39761271242969
0.47866923156014 0.41784690131979
0.41784690131979 0.47866923156014
0.38363728757031 0.53125
0.39761271242969 0.53125
0.53125 0.44079915028125
0.53125 0.49670084971875
0.44079915028125 0.53125
0.49670084971875 0.53125
0.53988728757031 0.025911862710939
0.55386271242969 0.067838137289061
0.53988728757031 0.09375
0.55386271242969 0.09375
0.59704915028125 0.12829915028125
0.65295084971875 0.18420084971875
0.57443643785157 0.21875
0.64431356214843 0.21875
0.69613728757031 0.22738728757031
0.71011271242969 0.24136271242969
0.58307372542188 0.25
0.66692627457812 0.25
0.75329915028125 0.28454915028125
0.80920084971875 0.34045084971875
0.61762287570313 0.375
0.75737712429687 0.375
0.85238728757031 0.38363728757031
0.86636271242969 0.39761271242969
0.62626016327344 0.40625
0.77998983672656 0.40625
0.90954915028125 0.44079915028125
0.96545084971875 0.49670084971875
0.6608093135547 0.53125
0.8704406864453 0.53125
1 0.025911862710939
1 0.067838137289061
0.68342202598438 0.09375
0.87907797401562 0.09375
0.6608093135547 0
0.8704406864453 0
1 0.11966186271094
1 0.16158813728906
0.77387287570313 0.21011271242969
0.91362712429687 0.19613728757031
1 0.20477457514063
1 0.23272542485937
0.79648558813282 0.25
0.92226441186718 0.25
1 0.27591186271094
1 0.31783813728906
0.88693643785157 0.36636271242969
0.95681356214843 0.35238728757031
1 0.36102457514063
1 0.38897542485937
0.90954915028125 0.40625
0.96545084971875 0.40625
1 0.44079915028125
1 0.49670084971875
0.09375 0.6608093135547
0.09375 0.8704406864453
0.025911862710939 1
0.067838137289061 1
0 0.6608093135547
0 0.8704406864453
0.21875 0.6608093135547
0.21875 0.8704406864453
0.12829915028125 1
0.18420084971875 1
0.25 0.6608093135547
0.25 0.8704406864453
0.22738728757031 1
0.24136271242969 1
0.375 0.6608093135547
0.375 0.8704406864453
0.28454915028125 1
0.34045084971875 1
0.40625 0.6608093135547
0.40625 0.8704406864453
0.38363728757031 1
0.39761271242969 1
0.53125 0.6608093135547
0.53125 0.8704406864453
0.44079915028125 1
0.49670084971875 1
1 0.6608093135547
1 0.8704406864453
0.6608093135547 1
0.8704406864453 1
0.14782497614169 0.14782497614169
0.3364183509774 0.10629113008478
0.3439701728879 0.12590539815918
0.10629113008478 0.3364183509774
0.12590539815918 0.3439701728879
0.36175027742635 0.16568300020856
0.38526511193449 0.21639840771017
0.16568300020856 0.36175027742635
0.21639840771017 0.38526511193449
0.40343132064181 0.2555782146968
0.40931002926885 0.2682570665722
0.2555782146968 0.40343132064181
0.2682570665722 0.40931002926885
0.42747623797617 0.30743687355882
0.45099107248431 0.35815228106044
0.30743687355882 0.42747623797617
0.35815228106044 0.45099107248431
0.46915728119164 0.39733208804706
0.47503598981867 0.41001093992246
0.39733208804706 0.46915728119164
0.41001093992246 0.47503598981867
0.47232443490112 0.47232443490112
0.54166666666667 0.0625
0.57886271242969 0.12829915028125
0.61931356214843 0.18420084971875
0.54943643785157 0.12829915028125
0.56488728757031 0.18420084971875
0.65056356214843 0.22738728757031
0.66067627457812 0.24136271242969
0.57682372542188 0.22738728757031
0.58068643785157 0.24136271242969
0.69192627457812 0.28454915028125
0.73237712429687 0.34045084971875
0.59262287570313 0.28454915028125
0.60807372542188 0.34045084971875
0.76362712429687 0.38363728757031
0.77373983672656 0.39761271242969
0.62001016327344 0.38363728757031
0.62387287570313 0.39761271242969
0.80498983672656 0.44079915028125
0.8454406864453 0.49670084971875
0.6358093135547 0.44079915028125
0.65126016327344 0.49670084971875
0.87282797401562 0.025911862710939
0.8766906864453 0.067838137289061
0.6670593135547 0.025911862710939
0.67717202598438 0.067838137289061
0.88862712429687 0.12204915028125
0.90407797401562 0.16783813728906
0.70842202598438 0.12591186271094
0.74887287570313 0.17795084971875
0.91601441186718 0.21102457514063
0.91987712429687 0.23511271242969
0.78012287570313 0.22113728757031
0.79023558813282 0.23897542485937
0.93181356214843 0.27829915028125
0.94726441186718 0.32408813728906
0.82148558813282 0.28216186271094
0.86193643785157 0.33420084971875
0.95920084971875 0.36727457514063
0.96306356214843 0.39136271242969
0.89318643785157 0.37738728757031
0.90329915028125 0.39522542485937
0.95833333333333 0.44791666666667
0.025911862710939 0.6608093135547
0.067838137289061 0.6608093135547
0.025911862710939 0.8704406864453
0.067838137289061 0.8704406864453
0.12829915028125 0.6608093135547
0.18420084971875 0.6608093135547
0.12829915028125 0.8704406864453
0.18420084971875 0.8704406864453
0.22738728757031 0.6608093135547
0.24136271242969 0.6608093135547
0.22738728757031 0.8704406864453
0.24136271242969 0.8704406864453
0.28454915028125 0.6608093135547
0.34045084971875 0.6608093135547
0.28454915028125 0.8704406864453
0.34045084971875 0.8704406864453
0.38363728757031 0.6608093135547
0.39761271242969 0.6608093135547
0.38363728757031 0.8704406864453
0.39761271242969 0.8704406864453
0.44079915028125 0.6608093135547
0.49670084971875 0.6608093135547
0.44079915028125 0.8704406864453
0.49670084971875 0.8704406864453
0.6608093135547 0.6608093135547
0.8704406864453 0.6608093135547
0.6608093135547 0.8704406864453
0.8704406864453 0.8704406864453
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = "MFEM"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = v4.5.3
PROJECT_NUMBER = v4.6.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
+7
View File
@@ -105,6 +105,13 @@ namespace mfem {
* - <a class="el" href="ex32p_8cpp_source.html">Example 32p</a>: parallel anisotropic Maxwell eigensolver
* - <a class="el" href="ex33_8cpp_source.html">Example 33</a>: nodal H1 FEM for the fractional Laplacian problem
* - <a class="el" href="ex33p_8cpp_source.html">Example 33p</a>: parallel nodal H1 FEM for the fractional Laplacian problem
* - <a class="el" href="ex34_8cpp_source.html">Example 34</a>: multi-domain magnetostatics
* - <a class="el" href="ex34p_8cpp_source.html">Example 34p</a>: parallel multi-domain magnetostatics
* - <a class="el" href="ex35p_8cpp_source.html">Example 35p</a>: parallel multi-domain damped harmonic oscillators
* - <a class="el" href="ex36_8cpp_source.html">Example 36</a>: Proximal Galerkin FEM for the obstacle problem
* - <a class="el" href="ex36p_8cpp_source.html">Example 36p</a>: parallel Proximal Galerkin FEM for the obstacle problem
* - <a class="el" href="ex37_8cpp_source.html">Example 37</a>: Topology optimization
* - <a class="el" href="ex37p_8cpp_source.html">Example 37p</a>: parallel topology optimization
*
* <H4>AmgX Examples</H4>
* - Variants of Examples
+12 -2
View File
@@ -40,6 +40,9 @@ list(APPEND ALL_EXE_SRCS
ex30.cpp
ex31.cpp
ex33.cpp
ex34.cpp
ex36.cpp
ex37.cpp
)
if (MFEM_USE_MPI)
@@ -77,6 +80,10 @@ if (MFEM_USE_MPI)
ex31p.cpp
ex32p.cpp
ex33p.cpp
ex34p.cpp
ex35p.cpp
ex36p.cpp
ex37p.cpp
)
endif()
@@ -102,6 +109,8 @@ if (MFEM_ENABLE_TESTING)
list(APPEND THIS_TEST_OPTIONS "-e" "1")
elseif(${TEST_NAME} MATCHES "ex27p*")
list(APPEND THIS_TEST_OPTIONS "-dg")
elseif(${TEST_NAME} MATCHES "ex37p*")
list(APPEND THIS_TEST_OPTIONS "-mi" "3")
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
@@ -119,9 +128,10 @@ if (MFEM_ENABLE_TESTING)
# Add CUDA/HIP tests.
set(DEVICE_EXAMPLES
# serial examples with device support:
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
# parallel examples with device support:
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p)
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p
ex34p ex35p)
set(MFEM_TEST_DEVICE)
if (MFEM_USE_CUDA)
set(MFEM_TEST_DEVICE "cuda")
+1 -1
View File
@@ -22,7 +22,7 @@ using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Parse command line options.
const char *mesh_file = "../data/star.mesh";
string mesh_file = "../data/star.mesh";
int order = 1;
OptionsParser args(argc, argv);
+1 -1
View File
@@ -26,7 +26,7 @@ int main(int argc, char *argv[])
Hypre::Init();
// 2. Parse command line options.
const char *mesh_file = "../data/star.mesh";
string mesh_file = "../data/star.mesh";
int order = 1;
OptionsParser args(argc, argv);
+15
View File
@@ -100,6 +100,21 @@ int main(int argc, char *argv[])
Device device(device_config);
if (myid == 0) { device.Print(); }
if (mfem::Device::Allows(mfem::Backend::DEVICE_MASK))
{
HYPRE_SetMemoryLocation(HYPRE_MEMORY_DEVICE);
HYPRE_SetExecutionPolicy(HYPRE_EXEC_DEVICE);
HYPRE_DeviceInitialize();
}
else
{
HYPRE_SetMemoryLocation(HYPRE_MEMORY_HOST);
HYPRE_SetExecutionPolicy(HYPRE_EXEC_HOST);
}
auto loc = mfem::GetHypreMemoryLocation();
auto exec = mfem::GetHypreExecutionPolicy();
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
+621
View File
@@ -0,0 +1,621 @@
// MFEM Example 34
//
// Compile with: make ex34
//
// Sample runs: ex34 -o 2
// ex34 -o 2 -pa -hex
//
// Device sample runs:
// ex34 -o 2 -pa -hex -d cuda
// ex34 -o 2 -no-pa -d cuda
//
// Description: This example code solves a simple magnetostatic problem
// curl curl A = J where the current density J is computed on a
// subset of the domain as J = -sigma grad phi. We discretize the
// vector potential with Nedelec finite elements, the scalar
// potential with Lagrange finite elements, and the current
// density with Raviart-Thomas finite elements.
//
// The example demonstrates the use of a SubMesh to compute the
// scalar potential and its associated current density which is
// then transferred to the original mesh and used as a source
// function.
//
// Note that this example takes certain liberties with the
// current density which is not necessarily divergence free
// as it should be. This was done to focus on the use of the
// SubMesh to transfer information between a full mesh and a
// sub-domain. A more rigorous implementation might employ an
// H(div) saddle point solver to obtain a divergence free J on
// the SubMesh. It would then also need to ensure that the r.h.s.
// of curl curl A = J does in fact lie in the range of the weak
// curl operator by performing a divergence cleaning procedure
// before the solve. After divergence cleaning the delta
// parameter would probably not be needed.
//
// This example is designed to make use of a specific mesh which
// has a known configuration of elements and boundary attributes.
// Other meshes could be used but extra care would be required to
// properly define the SubMesh and the necessary boundaries.
//
// We recommend viewing examples 1 and 3 before viewing this
// example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
static bool pa_ = false;
static bool algebraic_ceed_ = false;
void ComputeCurrentDensityOnSubMesh(int order,
const Array<int> &phi0_attr,
const Array<int> &phi1_attr,
const Array<int> &jn_zero_attr,
GridFunction &j_cond);
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../data/fichera-mixed.mesh";
Array<int> cond_attr;
Array<int> submesh_elems;
Array<int> sym_plane_attr;
Array<int> phi0_attr;
Array<int> phi1_attr;
Array<int> jn_zero_attr;
int ref_levels = 1;
int order = 1;
double delta_const = 1e-6;
bool mixed = true;
bool static_cond = false;
const char *device_config = "cpu";
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&delta_const, "-mc", "--magnetic-cond",
"Magnetic Conductivity");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&mixed, "-mixed", "--mixed-mesh", "-hex",
"--hex-mesh", "Mixed mesh of hexahedral mesh.");
args.AddOption(&pa_, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
#ifdef MFEM_USE_CEED
args.AddOption(&algebraic_ceed_, "-a", "--algebraic", "-no-a", "--no-algebraic",
"Use algebraic Ceed solver");
#endif
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
if (!mixed || pa_)
{
mesh_file = "../data/fichera.mesh";
}
if (submesh_elems.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0)
{
submesh_elems.SetSize(5);
submesh_elems[0] = 0;
submesh_elems[1] = 2;
submesh_elems[2] = 3;
submesh_elems[3] = 4;
submesh_elems[4] = 9;
}
else if (strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
submesh_elems.SetSize(7);
submesh_elems[0] = 10;
submesh_elems[1] = 14;
submesh_elems[2] = 34;
submesh_elems[3] = 36;
submesh_elems[4] = 37;
submesh_elems[5] = 38;
submesh_elems[6] = 39;
}
}
if (sym_plane_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
sym_plane_attr.SetSize(8);
sym_plane_attr[0] = 9;
sym_plane_attr[1] = 10;
sym_plane_attr[2] = 11;
sym_plane_attr[3] = 12;
sym_plane_attr[4] = 13;
sym_plane_attr[5] = 14;
sym_plane_attr[6] = 15;
sym_plane_attr[7] = 16;
}
}
if (phi0_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
phi0_attr.Append(2);
}
}
if (phi1_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
phi1_attr.Append(23);
}
}
if (jn_zero_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
jn_zero_attr.Append(25);
}
for (int i=0; i<sym_plane_attr.Size(); i++)
{
jn_zero_attr.Append(sym_plane_attr[i]);
}
}
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
if (!mixed || pa_)
{
mesh.UniformRefinement();
if (ref_levels > 0)
{
ref_levels--;
}
}
int submesh_attr = -1;
if (cond_attr.Size() == 0 && submesh_elems.Size() > 0)
{
int max_attr = mesh.attributes.Max();
submesh_attr = max_attr + 1;
for (int i=0; i<submesh_elems.Size(); i++)
{
mesh.SetAttribute(submesh_elems[i], submesh_attr);
}
mesh.SetAttributes();
if (cond_attr.Size() == 0)
{
cond_attr.Append(submesh_attr);
}
}
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement.
{
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
}
// 5b. Extract a submesh covering a portion of the domain
SubMesh mesh_cond(SubMesh::CreateFromDomain(mesh, cond_attr));
// 6. Define a suitable finite element space on the SubMesh and compute
// the current density as an H(div) field.
RT_FECollection fec_cond_rt(order - 1, dim);
FiniteElementSpace fes_cond_rt(&mesh_cond, &fec_cond_rt);
GridFunction j_cond(&fes_cond_rt);
ComputeCurrentDensityOnSubMesh(order, phi0_attr, phi1_attr, jn_zero_attr,
j_cond);
// 6a. Save the SubMesh and associated current density in parallel. This
// output can be viewed later using GLVis:
// "glvis -np <np> -m cond_mesh -g cond_j"
{
ostringstream mesh_name, cond_name;
mesh_name << "cond.mesh";
cond_name << "cond_j.gf";
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
mesh_cond.Print(mesh_ofs);
ofstream cond_ofs(cond_name.str().c_str());
cond_ofs.precision(8);
j_cond.Save(cond_ofs);
}
// 6b. Send the current density, computed on the SubMesh, to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream port_sock(vishost, visport);
port_sock.precision(8);
port_sock << "solution\n" << mesh_cond << j_cond
<< "window_title 'Conductor J'"
<< "window_geometry 400 0 400 350" << flush;
}
// 7. Define a parallel finite element space on the full mesh. Here we use
// the H(curl) finite elements for the vector potential and H(div) for the
// current density.
ND_FECollection fec_nd(order, dim);
RT_FECollection fec_rt(order - 1, dim);
FiniteElementSpace fespace_nd(&mesh, &fec_nd);
FiniteElementSpace fespace_rt(&mesh, &fec_rt);
GridFunction j_full(&fespace_rt);
j_full = 0.0;
mesh_cond.Transfer(j_cond, j_full);
// 7a. Send the transferred current density to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << mesh << j_full
<< "window_title 'J Full'"
<< "window_geometry 400 430 400 350" << flush;
}
// 8. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined by
// marking all the boundary attributes except for those on a symmetry
// plane as essential (Dirichlet) and converting them to a list of true
// dofs.
Array<int> ess_tdof_list;
Array<int> ess_bdr;
if (mesh.bdr_attributes.Size())
{
ess_bdr.SetSize(mesh.bdr_attributes.Max());
ess_bdr = 1;
for (int i=0; i<sym_plane_attr.Size(); i++)
{
ess_bdr[sym_plane_attr[i]-1] = 0;
}
fespace_nd.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 9. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (J,W_i) where J is given by the function H(div) field transferred
// from the SubMesh and W_i are the basis functions in the finite
// element fespace.
VectorGridFunctionCoefficient jCoef(&j_full);
LinearForm b(&fespace_nd);
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(jCoef));
b.Assemble();
// 10. Define the solution vector x as a parallel finite element grid
// function corresponding to fespace. Initialize x to zero.
GridFunction x(&fespace_nd);
x = 0.0;
// 11. Set up the parallel bilinear form corresponding to the EM diffusion
// operator curl muinv curl + delta I, by adding the curl-curl and the
// mass domain integrators. For standard magnetostatics equations choose
// delta << 1. Larger values of delta should make the linear system
// easier to solve at the expense of resembling a diffusive quasistatic
// magnetic field. A reasonable balance must be found whenever the mesh
// or problem setup is altered.
ConstantCoefficient muinv(1.0);
ConstantCoefficient delta(delta_const);
BilinearForm a(&fespace_nd);
if (pa_) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a.AddDomainIntegrator(new CurlCurlIntegrator(muinv));
a.AddDomainIntegrator(new VectorFEMassIntegrator(delta));
// 12. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a.EnableStaticCondensation(); }
a.Assemble();
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
// 13. Solve the system AX=B
if (pa_) // Jacobi preconditioning in partial assembly mode
{
cout << "\nSolving for magnetic vector potential "
<< "using CG with a Jacobi preconditioner" << endl;
OperatorJacobiSmoother M(a, ess_tdof_list);
PCG(*A, M, B, X, 1, 1000, 1e-12, 0.0);
}
else
{
#ifndef MFEM_USE_SUITESPARSE
cout << "\nSolving for magnetic vector potential "
<< "using CG with a Gauss-Seidel preconditioner" << endl;
// 13a. Define a simple symmetric Gauss-Seidel preconditioner and use
// it to solve the system Ax=b with PCG.
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 1, 500, 1e-12, 0.0);
#else
cout << "\nSolving for magnetic vector potential "
<< "using UMFPack" << endl;
// 13a. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the
// system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(*A);
umf_solver.Mult(B, X);
#endif
}
// 14. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a.RecoverFEMSolution(X, b, x);
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "refined.mesh";
sol_name << "sol.gf";
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
mesh.Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << mesh << x
<< "window_title 'Vector Potential'"
<< "window_geometry 800 0 400 350" << flush;
}
// 17. Compute the magnetic flux as the curl of the solution
DiscreteLinearOperator curl(&fespace_nd, &fespace_rt);
curl.AddDomainInterpolator(new CurlInterpolator);
curl.Assemble();
curl.Finalize();
GridFunction dx(&fespace_rt);
curl.Mult(x, dx);
// 18. Save the curl of the solution in parallel. This output can be viewed
// later using GLVis: "glvis -np <np> -m mesh -g dsol".
{
ostringstream dsol_name;
dsol_name << "dsol.gf";
ofstream dsol_ofs(dsol_name.str().c_str());
dsol_ofs.precision(8);
dx.Save(dsol_ofs);
}
// 19. Send the curl of the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << mesh << dx
<< "window_title 'Magnetic Flux'"
<< "window_geometry 1200 0 400 350" << flush;
}
// 20. Clean exit
return 0;
}
void ComputeCurrentDensityOnSubMesh(int order,
const Array<int> &phi0_attr,
const Array<int> &phi1_attr,
const Array<int> &jn_zero_attr,
GridFunction &j_cond)
{
// Extract the finite element space and mesh on which j_cond is defined
FiniteElementSpace &fes_cond_rt = *j_cond.FESpace();
Mesh &mesh_cond = *fes_cond_rt.GetMesh();
int dim = mesh_cond.Dimension();
// Define a parallel finite element space on the SubMesh. Here we use the H1
// finite elements for the electrostatic potential.
H1_FECollection fec_h1(order, dim);
FiniteElementSpace fes_cond_h1(&mesh_cond, &fec_h1);
// Define the conductivity coefficient and the boundaries associated with the
// fixed potentials phi0 and phi1 which will drive the current.
ConstantCoefficient sigmaCoef(1.0);
Array<int> ess_bdr_phi(mesh_cond.bdr_attributes.Max());
Array<int> ess_bdr_j(mesh_cond.bdr_attributes.Max());
Array<int> ess_bdr_tdof_phi;
ess_bdr_phi = 0;
ess_bdr_j = 0;
for (int i=0; i<phi0_attr.Size(); i++)
{
ess_bdr_phi[phi0_attr[i]-1] = 1;
}
for (int i=0; i<phi1_attr.Size(); i++)
{
ess_bdr_phi[phi1_attr[i]-1] = 1;
}
for (int i=0; i<jn_zero_attr.Size(); i++)
{
ess_bdr_j[jn_zero_attr[i]-1] = 1;
}
fes_cond_h1.GetEssentialTrueDofs(ess_bdr_phi, ess_bdr_tdof_phi);
// Setup the bilinear form corresponding to -Div(sigma Grad phi)
BilinearForm a_h1(&fes_cond_h1);
a_h1.AddDomainIntegrator(new DiffusionIntegrator(sigmaCoef));
a_h1.Assemble();
// Set the r.h.s. to zero
LinearForm b_h1(&fes_cond_h1);
b_h1 = 0.0;
// Setup the boundary conditions on phi
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
GridFunction phi_h1(&fes_cond_h1);
phi_h1 = 0.0;
Array<int> bdr0(mesh_cond.bdr_attributes.Max()); bdr0 = 0;
for (int i=0; i<phi0_attr.Size(); i++)
{
bdr0[phi0_attr[i]-1] = 1;
}
phi_h1.ProjectBdrCoefficient(zero, bdr0);
Array<int> bdr1(mesh_cond.bdr_attributes.Max()); bdr1 = 0;
for (int i=0; i<phi1_attr.Size(); i++)
{
bdr1[phi1_attr[i]-1] = 1;
}
phi_h1.ProjectBdrCoefficient(one, bdr1);
{
OperatorPtr A;
Vector B, X;
a_h1.FormLinearSystem(ess_bdr_tdof_phi, phi_h1, b_h1, A, X, B);
// Solve the linear system
if (!pa_)
{
#ifndef MFEM_USE_SUITESPARSE
cout << "\nSolving for electric potential using PCG "
<< "with a Gauss-Seidel preconditioner" << endl;
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 1, 200, 1e-12, 0.0);
#else
cout << "\nSolving for electric potential using UMFPack" << endl;
// If MFEM was compiled with SuiteSparse,
// use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(*A);
umf_solver.Mult(B, X);
#endif
}
else
{
cout << "\nSolving for electric potential using CG" << endl;
if (UsesTensorBasis(fes_cond_h1))
{
if (algebraic_ceed_)
{
ceed::AlgebraicSolver M(a_h1, ess_bdr_tdof_phi);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
else
{
OperatorJacobiSmoother M(a_h1, ess_bdr_tdof_phi);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
}
else
{
CG(*A, B, X, 1, 400, 1e-12, 0.0);
}
}
a_h1.RecoverFEMSolution(X, b_h1, phi_h1);
}
{
char vishost[] = "localhost";
int visport = 19916;
socketstream port_sock(vishost, visport);
port_sock.precision(8);
port_sock << "solution\n" << mesh_cond << phi_h1
<< "window_title 'Conductor Potential'"
<< "window_geometry 0 0 400 350" << flush;
}
// Solve for the current density J = -sigma Grad phi with boundary conditions
// J.n = 0 on the walls of the conductor but not on the ports where phi=0 and
// phi=1.
// J will be computed in H(div) so we need an RT mass matrix
BilinearForm m_rt(&fes_cond_rt);
m_rt.AddDomainIntegrator(new VectorFEMassIntegrator);
m_rt.Assemble();
// Assemble the (sigma Grad phi) operator
MixedBilinearForm d_h1(&fes_cond_h1, &fes_cond_rt);
d_h1.AddDomainIntegrator(new MixedVectorGradientIntegrator(sigmaCoef));
d_h1.Assemble();
// Compute the r.h.s, b_rt = sigma E = -sigma Grad phi
LinearForm b_rt(&fes_cond_rt);
d_h1.Mult(phi_h1, b_rt);
b_rt *= -1.0;
// Apply the necessary boundary conditions and solve for J in H(div)
cout << "\nSolving for current density in H(Div) "
<< "using diagonally scaled CG" << endl;
cout << "Size of linear system: "
<< fes_cond_rt.GetTrueVSize() << endl;
Array<int> ess_bdr_tdof_rt;
OperatorPtr M;
Vector B, X;
fes_cond_rt.GetEssentialTrueDofs(ess_bdr_j, ess_bdr_tdof_rt);
j_cond = 0.0;
m_rt.FormLinearSystem(ess_bdr_tdof_rt, j_cond, b_rt, M, X, B);
CGSolver cg;
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
cg.SetOperator(*M);
cg.Mult(B, X);
m_rt.RecoverFEMSolution(X, b_rt, j_cond);
}
+648
View File
@@ -0,0 +1,648 @@
// MFEM Example 34 - Parallel Version
//
// Compile with: make ex34p
//
// Sample runs: mpirun -np 4 ex34p -o 2
// mpirun -np 4 ex34p -o 2 -hex -pa
//
// Device sample runs:
// mpirun -np 4 ex34p -o 2 -hex -pa -d cuda
// mpirun -np 4 ex34p -o 2 -no-pa -d cuda
//
// Description: This example code solves a simple magnetostatic problem
// curl curl A = J where the current density J is computed on a
// subset of the domain as J = -sigma grad phi. We discretize the
// vector potential with Nedelec finite elements, the scalar
// potential with Lagrange finite elements, and the current
// density with Raviart-Thomas finite elements.
//
// The example demonstrates the use of a SubMesh to compute the
// scalar potential and its associated current density which is
// then transferred to the original mesh and used as a source
// function.
//
// Note that this example takes certain liberties with the
// current density which is not necessarily divergence free
// as it should be. This was done to focus on the use of the
// SubMesh to transfer information between a full mesh and a
// sub-domain. A more rigorous implementation might employ an
// H(div) saddle point solver to obtain a divergence free J on
// the SubMesh. It would then also need to ensure that the r.h.s.
// of curl curl A = J does in fact lie in the range of the weak
// curl operator by performing a divergence cleaning procedure
// before the solve. After divergence cleaning the delta
// parameter would probably not be needed.
//
// This example is designed to make use of a specific mesh which
// has a known configuration of elements and boundary attributes.
// Other meshes could be used but extra care would be required to
// properly define the SubMesh and the necessary boundaries.
//
// We recommend viewing examples 1 and 3 before viewing this
// example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
void ComputeCurrentDensityOnSubMesh(int order,
const Array<int> &phi0_attr,
const Array<int> &phi1_attr,
const Array<int> &jn_zero_attr,
ParGridFunction &j_cond);
int main(int argc, char *argv[])
{
// 1. Initialize MPI and HYPRE.
Mpi::Init(argc, argv);
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
// 2. Parse command-line options.
const char *mesh_file = "../data/fichera-mixed.mesh";
Array<int> cond_attr;
Array<int> submesh_elems;
Array<int> sym_plane_attr;
Array<int> phi0_attr;
Array<int> phi1_attr;
Array<int> jn_zero_attr;
int ser_ref_levels = 1;
int par_ref_levels = 1;
int order = 1;
double delta_const = 1e-6;
bool mixed = true;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
#ifdef MFEM_USE_AMGX
bool useAmgX = false;
#endif
OptionsParser args(argc, argv);
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
"Number of times to refine the mesh uniformly in parallel.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&delta_const, "-mc", "--magnetic-cond",
"Magnetic Conductivity");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&mixed, "-mixed", "--mixed-mesh", "-hex",
"--hex-mesh", "Mixed mesh of hexahedral mesh.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
#ifdef MFEM_USE_AMGX
args.AddOption(&useAmgX, "-amgx", "--useAmgX", "-no-amgx",
"--no-useAmgX",
"Enable or disable AmgX in MatrixFreeAMS.");
#endif
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
if (!mixed || pa)
{
mesh_file = "../data/fichera.mesh";
}
if (submesh_elems.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0)
{
submesh_elems.SetSize(5);
submesh_elems[0] = 0;
submesh_elems[1] = 2;
submesh_elems[2] = 3;
submesh_elems[3] = 4;
submesh_elems[4] = 9;
}
else if (strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
submesh_elems.SetSize(7);
submesh_elems[0] = 10;
submesh_elems[1] = 14;
submesh_elems[2] = 34;
submesh_elems[3] = 36;
submesh_elems[4] = 37;
submesh_elems[5] = 38;
submesh_elems[6] = 39;
}
}
if (sym_plane_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
sym_plane_attr.SetSize(8);
sym_plane_attr[0] = 9;
sym_plane_attr[1] = 10;
sym_plane_attr[2] = 11;
sym_plane_attr[3] = 12;
sym_plane_attr[4] = 13;
sym_plane_attr[5] = 14;
sym_plane_attr[6] = 15;
sym_plane_attr[7] = 16;
}
}
if (phi0_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
phi0_attr.Append(2);
}
}
if (phi1_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
phi1_attr.Append(23);
}
}
if (jn_zero_attr.Size() == 0)
{
if (strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0)
{
jn_zero_attr.Append(25);
}
for (int i=0; i<sym_plane_attr.Size(); i++)
{
jn_zero_attr.Append(sym_plane_attr[i]);
}
}
// 3. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
if (!mixed || pa)
{
mesh->UniformRefinement();
if (ser_ref_levels > 0)
{
ser_ref_levels--;
}
else
{
par_ref_levels--;
}
}
int submesh_attr = -1;
if (cond_attr.Size() == 0 && submesh_elems.Size() > 0)
{
int max_attr = mesh->attributes.Max();
submesh_attr = max_attr + 1;
for (int i=0; i<submesh_elems.Size(); i++)
{
mesh->SetAttribute(submesh_elems[i], submesh_attr);
}
mesh->SetAttributes();
if (cond_attr.Size() == 0)
{
cond_attr.Append(submesh_attr);
}
}
// 5. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement.
{
int ref_levels = ser_ref_levels;
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
delete mesh;
{
for (int l = 0; l < par_ref_levels; l++)
{
pmesh.UniformRefinement();
}
}
// 6b. Extract a submesh covering a portion of the domain
ParSubMesh pmesh_cond(ParSubMesh::CreateFromDomain(pmesh, cond_attr));
// 7. Define a suitable finite element space on the SubMesh and compute
// the current density as an H(div) field.
RT_FECollection fec_cond_rt(order - 1, dim);
ParFiniteElementSpace fes_cond_rt(&pmesh_cond, &fec_cond_rt);
ParGridFunction j_cond(&fes_cond_rt);
ComputeCurrentDensityOnSubMesh(order, phi0_attr, phi1_attr, jn_zero_attr,
j_cond);
// 7a. Save the SubMesh and associated current density in parallel. This
// output can be viewed later using GLVis:
// "glvis -np <np> -m cond_mesh -g cond_j"
{
ostringstream mesh_name, cond_name;
mesh_name << "cond_mesh." << setfill('0') << setw(6) << myid;
cond_name << "cond_j." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh_cond.Print(mesh_ofs);
ofstream cond_ofs(cond_name.str().c_str());
cond_ofs.precision(8);
j_cond.Save(cond_ofs);
}
// 7b. Send the current density, computed on the SubMesh, to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream port_sock(vishost, visport);
port_sock << "parallel " << num_procs << " " << myid << "\n";
port_sock.precision(8);
port_sock << "solution\n" << pmesh_cond << j_cond
<< "window_title 'Conductor J'"
<< "window_geometry 400 0 400 350" << flush;
}
// 8. Define a parallel finite element space on the full mesh. Here we use
// the H(curl) finite elements for the vector potential and H(div) for the
// current density.
ND_FECollection fec_nd(order, dim);
RT_FECollection fec_rt(order - 1, dim);
ParFiniteElementSpace fespace_nd(&pmesh, &fec_nd);
ParFiniteElementSpace fespace_rt(&pmesh, &fec_rt);
ParGridFunction j_full(&fespace_rt);
j_full = 0.0;
pmesh_cond.Transfer(j_cond, j_full);
// 8a. Send the transferred current density to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << j_full
<< "window_title 'J Full'"
<< "window_geometry 400 430 400 350" << flush;
}
// 9. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes except for those on a symmetry
// plane as essential (Dirichlet) and converting them to a list of
// true dofs.
Array<int> ess_tdof_list;
Array<int> ess_bdr;
if (pmesh.bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh.bdr_attributes.Max());
ess_bdr = 1;
for (int i=0; i<sym_plane_attr.Size(); i++)
{
ess_bdr[sym_plane_attr[i]-1] = 0;
}
fespace_nd.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 10. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (J,W_i) where J is given by the function H(div) field transferred
// from the SubMesh and W_i are the basis functions in the finite
// element fespace.
VectorGridFunctionCoefficient jCoef(&j_full);
ParLinearForm b(&fespace_nd);
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(jCoef));
b.Assemble();
// 11. Define the solution vector x as a parallel finite element grid
// function corresponding to fespace. Initialize x to zero.
ParGridFunction x(&fespace_nd);
x = 0.0;
// 12. Set up the parallel bilinear form corresponding to the EM diffusion
// operator curl muinv curl + delta I, by adding the curl-curl and the
// mass domain integrators. For standard magnetostatics equations choose
// delta << 1. Larger values of delta should make the linear system
// easier to solve at the expense of resembling a diffusive quasistatic
// magnetic field. A reasonable balance must be found whenever the mesh
// or problem setup is altered.
ConstantCoefficient muinv(1.0);
ConstantCoefficient delta(delta_const);
ParBilinearForm a(&fespace_nd);
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a.AddDomainIntegrator(new CurlCurlIntegrator(muinv));
a.AddDomainIntegrator(new VectorFEMassIntegrator(delta));
// 13. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a.EnableStaticCondensation(); }
a.Assemble();
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
if (myid == 0)
{
cout << "\nSolving for magnetic vector potential "
<< "using CG with AMS" << endl;
}
// 14. Solve the system AX=B using PCG with an AMS preconditioner.
if (pa)
{
#ifdef MFEM_USE_AMGX
MatrixFreeAMS ams(a, *A, fespace_nd, &muinv, &delta, NULL, ess_bdr,
useAmgX);
#else
MatrixFreeAMS ams(a, *A, fespace_nd, &muinv, &delta, NULL, ess_bdr);
#endif
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(1000);
cg.SetPrintLevel(1);
cg.SetOperator(*A);
cg.SetPreconditioner(ams);
cg.Mult(B, X);
}
else
{
if (myid == 0)
{
cout << "Size of linear system: "
<< A.As<HypreParMatrix>()->GetGlobalNumRows() << endl;
}
ParFiniteElementSpace *prec_fespace =
(a.StaticCondensationIsEnabled() ? a.SCParFESpace() : &fespace_nd);
HypreAMS ams(*A.As<HypreParMatrix>(), prec_fespace);
HyprePCG pcg(*A.As<HypreParMatrix>());
pcg.SetTol(1e-12);
pcg.SetMaxIter(500);
pcg.SetPrintLevel(2);
pcg.SetPreconditioner(ams);
pcg.Mult(B, X);
}
// 15. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a.RecoverFEMSolution(X, b, x);
// 16. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh.Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << x
<< "window_title 'Vector Potential'"
<< "window_geometry 800 0 400 350" << flush;
}
// 18. Compute the magnetic flux as the curl of the solution
ParDiscreteLinearOperator curl(&fespace_nd, &fespace_rt);
curl.AddDomainInterpolator(new CurlInterpolator);
curl.Assemble();
curl.Finalize();
ParGridFunction dx(&fespace_rt);
curl.Mult(x, dx);
// 19. Save the curl of the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g dsol".
{
ostringstream dsol_name;
dsol_name << "dsol." << setfill('0') << setw(6) << myid;
ofstream dsol_ofs(dsol_name.str().c_str());
dsol_ofs.precision(8);
dx.Save(dsol_ofs);
}
// 20. Send the curl of the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << dx
<< "window_title 'Magnetic Flux'"
<< "window_geometry 1200 0 400 350" << flush;
}
// 21. Clean exit
return 0;
}
void ComputeCurrentDensityOnSubMesh(int order,
const Array<int> &phi0_attr,
const Array<int> &phi1_attr,
const Array<int> &jn_zero_attr,
ParGridFunction &j_cond)
{
// Extract the finite element space and mesh on which j_cond is defined
ParFiniteElementSpace &fes_cond_rt = *j_cond.ParFESpace();
ParMesh &pmesh_cond = *fes_cond_rt.GetParMesh();
int myid = fes_cond_rt.GetMyRank();
int dim = pmesh_cond.Dimension();
// Define a parallel finite element space on the SubMesh. Here we use the
// H1 finite elements for the electrostatic potential.
H1_FECollection fec_h1(order, dim);
ParFiniteElementSpace fes_cond_h1(&pmesh_cond, &fec_h1);
// Define the conductivity coefficient and the boundaries associated with the
// fixed potentials phi0 and phi1 which will drive the current.
ConstantCoefficient sigmaCoef(1.0);
Array<int> ess_bdr_phi(pmesh_cond.bdr_attributes.Max());
Array<int> ess_bdr_j(pmesh_cond.bdr_attributes.Max());
Array<int> ess_bdr_tdof_phi;
ess_bdr_phi = 0;
ess_bdr_j = 0;
for (int i=0; i<phi0_attr.Size(); i++)
{
ess_bdr_phi[phi0_attr[i]-1] = 1;
}
for (int i=0; i<phi1_attr.Size(); i++)
{
ess_bdr_phi[phi1_attr[i]-1] = 1;
}
for (int i=0; i<jn_zero_attr.Size(); i++)
{
ess_bdr_j[jn_zero_attr[i]-1] = 1;
}
fes_cond_h1.GetEssentialTrueDofs(ess_bdr_phi, ess_bdr_tdof_phi);
// Setup the bilinear form corresponding to -Div(sigma Grad phi)
ParBilinearForm a_h1(&fes_cond_h1);
a_h1.AddDomainIntegrator(new DiffusionIntegrator(sigmaCoef));
a_h1.Assemble();
// Set the r.h.s. to zero
ParLinearForm b_h1(&fes_cond_h1);
b_h1 = 0.0;
// Setup the boundary conditions on phi
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
ParGridFunction phi_h1(&fes_cond_h1);
phi_h1 = 0.0;
Array<int> bdr0(pmesh_cond.bdr_attributes.Max()); bdr0 = 0;
for (int i=0; i<phi0_attr.Size(); i++)
{
bdr0[phi0_attr[i]-1] = 1;
}
phi_h1.ProjectBdrCoefficient(zero, bdr0);
Array<int> bdr1(pmesh_cond.bdr_attributes.Max()); bdr1 = 0;
for (int i=0; i<phi1_attr.Size(); i++)
{
bdr1[phi1_attr[i]-1] = 1;
}
phi_h1.ProjectBdrCoefficient(one, bdr1);
// Solve the linear system using algebraic multigrid
{
if (myid == 0)
{
cout << "\nSolving for electric potential "
<< "using CG with AMG" << endl;
}
OperatorPtr A;
Vector B, X;
a_h1.FormLinearSystem(ess_bdr_tdof_phi, phi_h1, b_h1, A, X, B);
HypreBoomerAMG prec;
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
cg.SetPreconditioner(prec);
cg.SetOperator(*A);
cg.Mult(B, X);
a_h1.RecoverFEMSolution(X, b_h1, phi_h1);
}
{
int num_procs = fes_cond_h1.GetNRanks();
char vishost[] = "localhost";
int visport = 19916;
socketstream port_sock(vishost, visport);
port_sock << "parallel " << num_procs << " " << myid << "\n";
port_sock.precision(8);
port_sock << "solution\n" << pmesh_cond << phi_h1
<< "window_title 'Conductor Potential'"
<< "window_geometry 0 0 400 350" << flush;
}
// Solve for the current density J = -sigma Grad phi with boundary conditions
// J.n = 0 on the walls of the conductor but not on the ports where phi=0 and
// phi=1.
// J will be computed in H(div) so we need an RT mass matrix
ParBilinearForm m_rt(&fes_cond_rt);
m_rt.AddDomainIntegrator(new VectorFEMassIntegrator);
m_rt.Assemble();
// Assemble the (sigma Grad phi) operator
ParMixedBilinearForm d_h1(&fes_cond_h1, &fes_cond_rt);
d_h1.AddDomainIntegrator(new MixedVectorGradientIntegrator(sigmaCoef));
d_h1.Assemble();
// Compute the r.h.s, b_rt = sigma E = -sigma Grad phi
ParLinearForm b_rt(&fes_cond_rt);
d_h1.Mult(phi_h1, b_rt);
b_rt *= -1.0;
// Apply the necessary boundary conditions and solve for J in H(div)
HYPRE_BigInt glb_size_rt = fes_cond_rt.GlobalTrueVSize();
if (myid == 0)
{
cout << "\nSolving for current density in H(Div) "
<< "using diagonally scaled CG" << endl;
cout << "Size of linear system: "
<< glb_size_rt << endl;
}
Array<int> ess_bdr_tdof_rt;
OperatorPtr M;
Vector B, X;
fes_cond_rt.GetEssentialTrueDofs(ess_bdr_j, ess_bdr_tdof_rt);
j_cond = 0.0;
m_rt.FormLinearSystem(ess_bdr_tdof_rt, j_cond, b_rt, M, X, B);
HypreDiagScale prec;
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
cg.SetPreconditioner(prec);
cg.SetOperator(*M);
cg.Mult(B, X);
m_rt.RecoverFEMSolution(X, b_rt, j_cond);
}
+815
View File
@@ -0,0 +1,815 @@
// MFEM Example 35 - Parallel Version
//
// Compile with: make ex35p
//
// Sample runs: mpirun -np 4 ex35p -p 0 -o 2
// mpirun -np 4 ex35p -p 0 -o 2 -pbc '22 23 24' -em 0
// mpirun -np 4 ex35p -p 1 -o 1 -rp 2
// mpirun -np 4 ex35p -p 1 -o 2
// mpirun -np 4 ex35p -p 2 -o 1 -rp 2 -c 15
//
// Device sample runs:
//
// Description: This example code demonstrates the use of MFEM to define and
// solve simple complex-valued linear systems. It implements three
// variants of a damped harmonic oscillator:
//
// 1) A scalar H1 field
// -Div(a Grad u) - omega^2 b u + i omega c u = 0
//
// 2) A vector H(Curl) field
// Curl(a Curl u) - omega^2 b u + i omega c u = 0
//
// 3) A vector H(Div) field
// -Grad(a Div u) - omega^2 b u + i omega c u = 0
//
// In each case the field is driven by a forced oscillation, with
// angular frequency omega, imposed at the boundary or a portion
// of the boundary. The spatial variation of the boundary
// condition is computed as an eigenmode of an appropriate
// operator defined on a portion of the boundary i.e. a port
// boundary condition.
//
// In electromagnetics the coefficients are typically named the
// permeability, mu = 1/a, permittivity, epsilon = b, and
// conductivity, sigma = c. The user can specify these constants
// using either set of names.
//
// This example demonstrates how to transfer fields computed on a
// boundary generated SubMesh to the full mesh and apply them as
// boundary conditions. The default mesh and corresponding
// boundary attributes were chosen to verify proper behavior on
// both triangular and quadrilateral faces of tetrahedral,
// wedge-shaped, and hexahedral elements.
//
// The example also demonstrates how to display a time-varying
// solution as a sequence of fields sent to a single GLVis socket.
//
// We recommend viewing examples 11, 13, and 22 before viewing
// this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
static double mu_ = 1.0;
static double epsilon_ = 1.0;
static double sigma_ = 2.0;
void SetPortBC(int prob, int dim, int mode, ParGridFunction &port_bc);
int main(int argc, char *argv[])
{
// 1. Initialize MPI and HYPRE.
Mpi::Init(argc, argv);
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
// 2. Parse command-line options.
const char *mesh_file = "../data/fichera-mixed.mesh";
int ser_ref_levels = 1;
int par_ref_levels = 1;
int order = 1;
Array<int> port_bc_attr;
int prob = 0;
int mode = 1;
double freq = -1.0;
double omega = 2.0 * M_PI;
double a_coef = 0.0;
bool herm_conv = true;
bool slu_solver = false;
bool visualization = 1;
bool mixed = true;
bool pa = false;
const char *device_config = "cpu";
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
"Number of times to refine the mesh uniformly in parallel.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: H_1, 1: H(Curl), or 2: H(Div) "
"damped harmonic oscillator.");
args.AddOption(&mode, "-em", "--eigenmode",
"Choose the index of the port eigenmode.");
args.AddOption(&a_coef, "-a", "--stiffness-coef",
"Stiffness coefficient (spring constant or 1/mu).");
args.AddOption(&epsilon_, "-b", "--mass-coef",
"Mass coefficient (or epsilon).");
args.AddOption(&sigma_, "-c", "--damping-coef",
"Damping coefficient (or sigma).");
args.AddOption(&mu_, "-mu", "--permeability",
"Permeability of free space (or 1/(spring constant)).");
args.AddOption(&epsilon_, "-eps", "--permittivity",
"Permittivity of free space (or mass constant).");
args.AddOption(&sigma_, "-sigma", "--conductivity",
"Conductivity (or damping constant).");
args.AddOption(&freq, "-f", "--frequency",
"Frequency (in Hz).");
args.AddOption(&port_bc_attr, "-pbc", "--port-bc-attr",
"Attributes of port boundary condition");
args.AddOption(&herm_conv, "-herm", "--hermitian", "-no-herm",
"--no-hermitian", "Use convention for Hermitian operators.");
#ifdef MFEM_USE_SUPERLU
args.AddOption(&slu_solver, "-slu", "--superlu", "-no-slu",
"--no-superlu", "Use the SuperLU Solver.");
#endif
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&mixed, "-mixed", "--mixed-mesh", "-hex",
"--hex-mesh", "Mixed mesh of hexahedral mesh.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (!mixed || pa)
{
mesh_file = "../data/fichera.mesh";
}
if ( a_coef != 0.0 )
{
mu_ = 1.0 / a_coef;
}
if ( freq > 0.0 )
{
omega = 2.0 * M_PI * freq;
}
if (port_bc_attr.Size() == 0 &&
(strcmp(mesh_file, "../data/fichera-mixed.mesh") == 0 ||
strcmp(mesh_file, "../data/fichera.mesh") == 0))
{
port_bc_attr.SetSize(4);
port_bc_attr[0] = 7;
port_bc_attr[1] = 8;
port_bc_attr[2] = 11;
port_bc_attr[3] = 12;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
MFEM_VERIFY(prob >= 0 && prob <=2,
"Unrecognized problem type: " << prob);
ComplexOperator::Convention conv =
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
// 3. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 5. Refine the serial mesh on all processors to increase the resolution.
for (int l = 0; l < ser_ref_levels; l++)
{
mesh->UniformRefinement();
}
// 6a. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
delete mesh;
for (int l = 0; l < par_ref_levels; l++)
{
pmesh.UniformRefinement();
}
// 6b. Extract a submesh covering a portion of the boundary
ParSubMesh pmesh_port(ParSubMesh::CreateFromBoundary(pmesh, port_bc_attr));
// 7a. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange, Nedelec, or Raviart-Thomas finite elements
// of the specified order.
if (dim == 1 && prob != 0 )
{
if (myid == 0)
{
cout << "Switching to problem type 0, H1 basis functions, "
<< "for 1 dimensional mesh." << endl;
}
prob = 0;
}
FiniteElementCollection *fec = NULL;
switch (prob)
{
case 0: fec = new H1_FECollection(order, dim); break;
case 1: fec = new ND_FECollection(order, dim); break;
case 2: fec = new RT_FECollection(order - 1, dim); break;
default: break; // This should be unreachable
}
ParFiniteElementSpace fespace(&pmesh, fec);
HYPRE_BigInt size = fespace.GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7b. Define a parallel finite element space on the sub-mesh. Here we
// use continuous Lagrange, Nedelec, or L2 finite elements of
// the specified order.
FiniteElementCollection *fec_port = NULL;
switch (prob)
{
case 0: fec_port = new H1_FECollection(order, dim-1); break;
case 1:
if (dim == 3)
{
fec_port = new ND_FECollection(order, dim-1);
}
else
{
fec_port = new L2_FECollection(order - 1, dim-1,
BasisType::GaussLegendre,
FiniteElement::INTEGRAL);
}
break;
case 2: fec_port = new L2_FECollection(order - 1, dim-1,
BasisType::GaussLegendre,
FiniteElement::INTEGRAL); break;
default: break; // This should be unreachable
}
ParFiniteElementSpace fespace_port(&pmesh_port, fec_port);
HYPRE_BigInt size_port = fespace_port.GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element port BC unknowns: " << size_port
<< endl;
}
// 8a. Define a parallel grid function on the SubMesh which will contain
// the field to be applied as a port boundary condition.
ParGridFunction port_bc(&fespace_port);
port_bc = 0.0;
SetPortBC(prob, dim, mode, port_bc);
// 8b. Save the SubMesh and associated port boundary condition in parallel.
// This output can be viewed later using GLVis:
// "glvis -np <np> -m port_mesh -g port_mode"
{
ostringstream mesh_name, port_name;
mesh_name << "port_mesh." << setfill('0') << setw(6) << myid;
port_name << "port_mode." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh_port.Print(mesh_ofs);
ofstream port_ofs(port_name.str().c_str());
port_ofs.precision(8);
port_bc.Save(port_ofs);
}
// 8c. Send the port bc, computed on the SubMesh, to a GLVis server.
if (visualization && dim == 3)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream port_sock(vishost, visport);
port_sock << "parallel " << num_procs << " " << myid << "\n";
port_sock.precision(8);
port_sock << "solution\n" << pmesh_port << port_bc
<< "window_title 'Port BC'"
<< "window_geometry 0 0 400 350" << flush;
}
// 9. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// using an eigenmode of the appropriate type computed on the SubMesh.
Array<int> ess_tdof_list;
Array<int> ess_bdr;
if (pmesh.bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh.bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 10. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system.
ParComplexLinearForm b(&fespace, conv);
b.Vector::operator=(0.0);
// 11a. Define the solution vector u as a parallel complex finite element
// grid function corresponding to fespace. Initialize u to equal zero.
ParComplexGridFunction u(&fespace);
u = 0.0;
pmesh_port.Transfer(port_bc, u.real());
// 11b. Send the transferred port bc field to a GLVis server.
{
ParGridFunction full_bc(&fespace);
ParTransferMap port_to_full(port_bc, full_bc);
full_bc = 0.0;
port_to_full.Transfer(port_bc, full_bc);
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream full_sock(vishost, visport);
full_sock << "parallel " << num_procs << " " << myid << "\n";
full_sock.precision(8);
full_sock << "solution\n" << pmesh << full_bc
<< "window_title 'Transferred BC'"
<< "window_geometry 400 0 400 350"<< flush;
}
}
// 12. Set up the parallel sesquilinear form a(.,.) on the finite element
// space corresponding to the damped harmonic oscillator operator of the
// appropriate type:
//
// 0) A scalar H1 field
// -Div(a Grad) - omega^2 b + i omega c
//
// 1) A vector H(Curl) field
// Curl(a Curl) - omega^2 b + i omega c
//
// 2) A vector H(Div) field
// -Grad(a Div) - omega^2 b + i omega c
//
ConstantCoefficient stiffnessCoef(1.0/mu_);
ConstantCoefficient massCoef(-omega * omega * epsilon_);
ConstantCoefficient lossCoef(omega * sigma_);
ConstantCoefficient negMassCoef(omega * omega * epsilon_);
ParSesquilinearForm a(&fespace, conv);
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
switch (prob)
{
case 0:
a.AddDomainIntegrator(new DiffusionIntegrator(stiffnessCoef),
NULL);
a.AddDomainIntegrator(new MassIntegrator(massCoef),
new MassIntegrator(lossCoef));
break;
case 1:
a.AddDomainIntegrator(new CurlCurlIntegrator(stiffnessCoef),
NULL);
a.AddDomainIntegrator(new VectorFEMassIntegrator(massCoef),
new VectorFEMassIntegrator(lossCoef));
break;
case 2:
a.AddDomainIntegrator(new DivDivIntegrator(stiffnessCoef),
NULL);
a.AddDomainIntegrator(new VectorFEMassIntegrator(massCoef),
new VectorFEMassIntegrator(lossCoef));
break;
default: break; // This should be unreachable
}
// 13. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, etc.
a.Assemble();
OperatorHandle A;
Vector B, U;
a.FormLinearSystem(ess_tdof_list, u, b, A, U, B);
if (myid == 0)
{
cout << "Size of linear system: "
<< 2 * size << endl << endl;
}
if (!slu_solver)
{
// 14a. Set up the parallel bilinear form for the preconditioner
// corresponding to the appropriate operator
//
// 0) A scalar H1 field
// -Div(a Grad) - omega^2 b + i omega c
//
// 1) A vector H(Curl) field
// Curl(a Curl) + omega^2 b + i omega c
//
// 2) A vector H(Div) field
// -Grad(a Div) - omega^2 b + i omega c
ParBilinearForm pcOp(&fespace);
if (pa) { pcOp.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
switch (prob)
{
case 0:
pcOp.AddDomainIntegrator(new DiffusionIntegrator(stiffnessCoef));
pcOp.AddDomainIntegrator(new MassIntegrator(massCoef));
pcOp.AddDomainIntegrator(new MassIntegrator(lossCoef));
break;
case 1:
pcOp.AddDomainIntegrator(new CurlCurlIntegrator(stiffnessCoef));
pcOp.AddDomainIntegrator(new VectorFEMassIntegrator(negMassCoef));
pcOp.AddDomainIntegrator(new VectorFEMassIntegrator(lossCoef));
break;
case 2:
pcOp.AddDomainIntegrator(new DivDivIntegrator(stiffnessCoef));
pcOp.AddDomainIntegrator(new VectorFEMassIntegrator(massCoef));
pcOp.AddDomainIntegrator(new VectorFEMassIntegrator(lossCoef));
break;
default: break; // This should be unreachable
}
pcOp.Assemble();
// 14b. Define and apply a parallel FGMRES solver for AU=B with a block
// diagonal preconditioner based on the appropriate multigrid
// preconditioner from hypre.
Array<int> blockTrueOffsets;
blockTrueOffsets.SetSize(3);
blockTrueOffsets[0] = 0;
blockTrueOffsets[1] = A->Height() / 2;
blockTrueOffsets[2] = A->Height() / 2;
blockTrueOffsets.PartialSum();
BlockDiagonalPreconditioner BDP(blockTrueOffsets);
Operator * pc_r = NULL;
Operator * pc_i = NULL;
if (pa)
{
pc_r = new OperatorJacobiSmoother(pcOp, ess_tdof_list);
}
else
{
OperatorHandle PCOp;
pcOp.FormSystemMatrix(ess_tdof_list, PCOp);
switch (prob)
{
case 0:
pc_r = new HypreBoomerAMG(*PCOp.As<HypreParMatrix>());
break;
case 1:
pc_r = new HypreAMS(*PCOp.As<HypreParMatrix>(), &fespace);
break;
case 2:
if (dim == 2 )
{
pc_r = new HypreAMS(*PCOp.As<HypreParMatrix>(), &fespace);
}
else
{
pc_r = new HypreADS(*PCOp.As<HypreParMatrix>(), &fespace);
}
break;
default: break; // This should be unreachable
}
}
pc_i = new ScaledOperator(pc_r,
(conv == ComplexOperator::HERMITIAN) ?
-1.0:1.0);
BDP.SetDiagonalBlock(0, pc_r);
BDP.SetDiagonalBlock(1, pc_i);
BDP.owns_blocks = 1;
FGMRESSolver fgmres(MPI_COMM_WORLD);
fgmres.SetPreconditioner(BDP);
fgmres.SetOperator(*A.Ptr());
fgmres.SetRelTol(1e-6);
fgmres.SetMaxIter(1000);
fgmres.SetPrintLevel(1);
fgmres.Mult(B, U);
}
#ifdef MFEM_USE_SUPERLU
else
{
// 14. Solve using a direct solver
// Transform to monolithic HypreParMatrix
HypreParMatrix *A_hyp = A.As<ComplexHypreParMatrix>()->GetSystemMatrix();
SuperLURowLocMatrix SA(*A_hyp);
SuperLUSolver superlu(MPI_COMM_WORLD);
superlu.SetPrintStatistics(true);
superlu.SetSymmetricPattern(false);
superlu.SetColumnPermutation(superlu::PARMETIS);
superlu.SetOperator(SA);
superlu.Mult(B, U);
delete A_hyp;
}
#endif
// 15. Recover the parallel grid function corresponding to U. This is the
// local finite element solution on each processor.
a.RecoverFEMSolution(U, b, u);
// 16. Save the refined mesh and the solution in parallel. This output can be
// viewed later using GLVis: "glvis -np <np> -m mesh -g sol_r" or
// "glvis -np <np> -m mesh -g sol_i".
{
ostringstream mesh_name, sol_r_name, sol_i_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_r_name << "sol_r." << setfill('0') << setw(6) << myid;
sol_i_name << "sol_i." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh.Print(mesh_ofs);
ofstream sol_r_ofs(sol_r_name.str().c_str());
ofstream sol_i_ofs(sol_i_name.str().c_str());
sol_r_ofs.precision(8);
sol_i_ofs.precision(8);
u.real().Save(sol_r_ofs);
u.imag().Save(sol_i_ofs);
}
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock_r(vishost, visport);
sol_sock_r << "parallel " << num_procs << " " << myid << "\n";
sol_sock_r.precision(8);
sol_sock_r << "solution\n" << pmesh << u.real()
<< "window_title 'Solution: Real Part'"
<< "window_geometry 800 0 400 350" << flush;
MPI_Barrier(MPI_COMM_WORLD);
socketstream sol_sock_i(vishost, visport);
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i.precision(8);
sol_sock_i << "solution\n" << pmesh << u.imag()
<< "window_title 'Solution: Imaginary Part'"
<< "window_geometry 1200 0 400 350" << flush;
}
if (visualization)
{
ParGridFunction u_t(&fespace);
u_t = u.real();
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << u_t
<< "window_title 'Harmonic Solution (t = 0.0 T)'"
<< "window_geometry 0 432 600 450"
<< "pause\n" << flush;
if (myid == 0)
cout << "GLVis visualization paused."
<< " Press space (in the GLVis window) to resume it.\n";
int num_frames = 32;
int i = 0;
while (sol_sock)
{
double t = (double)(i % num_frames) / num_frames;
ostringstream oss;
oss << "Harmonic Solution (t = " << t << " T)";
add(cos( 2.0 * M_PI * t), u.real(),
sin(-2.0 * M_PI * t), u.imag(), u_t);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock << "solution\n" << pmesh << u_t
<< "window_title '" << oss.str() << "'" << flush;
i++;
}
}
// 18. Free the used memory.
delete fec_port;
delete fec;
return 0;
}
/**
Solves the eigenvalue problem -Div(Grad x) = lambda x with homogeneous
Dirichlet boundary conditions on the boundary of the domain. Returns mode
number "mode" (counting from zero) in the ParGridFunction "x".
*/
void ScalarWaveGuide(int mode, ParGridFunction &x)
{
int nev = std::max(mode + 2, 5);
int seed = 75;
ParFiniteElementSpace &fespace = *x.ParFESpace();
ParMesh &pmesh = *fespace.GetParMesh();
Array<int> ess_bdr;
if (pmesh.bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh.bdr_attributes.Max());
ess_bdr = 1;
}
ParBilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator);
a.Assemble();
a.EliminateEssentialBCDiag(ess_bdr, 1.0);
a.Finalize();
ParBilinearForm m(&fespace);
m.AddDomainIntegrator(new MassIntegrator);
m.Assemble();
// shift the eigenvalue corresponding to eliminated dofs to a large value
m.EliminateEssentialBCDiag(ess_bdr, numeric_limits<double>::min());
m.Finalize();
HypreParMatrix *A = a.ParallelAssemble();
HypreParMatrix *M = m.ParallelAssemble();
HypreBoomerAMG amg(*A);
amg.SetPrintLevel(0);
HypreLOBPCG lobpcg(MPI_COMM_WORLD);
lobpcg.SetNumModes(nev);
lobpcg.SetRandomSeed(seed);
lobpcg.SetPreconditioner(amg);
lobpcg.SetMaxIter(200);
lobpcg.SetTol(1e-8);
lobpcg.SetPrecondUsageMode(1);
lobpcg.SetPrintLevel(1);
lobpcg.SetMassMatrix(*M);
lobpcg.SetOperator(*A);
lobpcg.Solve();
x = lobpcg.GetEigenvector(mode);
delete A;
delete M;
}
/**
Solves the eigenvalue problem -Curl(Curl x) = lambda x with homogeneous
Dirichlet boundary conditions, on the tangential component of x, on the
boundary of the domain. Returns mode number "mode" (counting from zero) in
the ParGridFunction "x".
*/
void VectorWaveGuide(int mode, ParGridFunction &x)
{
int nev = std::max(mode + 2, 5);
ParFiniteElementSpace &fespace = *x.ParFESpace();
ParMesh &pmesh = *fespace.GetParMesh();
Array<int> ess_bdr;
if (pmesh.bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh.bdr_attributes.Max());
ess_bdr = 1;
}
ParBilinearForm a(&fespace);
a.AddDomainIntegrator(new CurlCurlIntegrator);
a.Assemble();
a.EliminateEssentialBCDiag(ess_bdr, 1.0);
a.Finalize();
ParBilinearForm m(&fespace);
m.AddDomainIntegrator(new VectorFEMassIntegrator);
m.Assemble();
// shift the eigenvalue corresponding to eliminated dofs to a large value
m.EliminateEssentialBCDiag(ess_bdr, numeric_limits<double>::min());
m.Finalize();
HypreParMatrix *A = a.ParallelAssemble();
HypreParMatrix *M = m.ParallelAssemble();
HypreAMS ams(*A,&fespace);
ams.SetPrintLevel(0);
ams.SetSingularProblem();
HypreAME ame(MPI_COMM_WORLD);
ame.SetNumModes(nev);
ame.SetPreconditioner(ams);
ame.SetMaxIter(100);
ame.SetTol(1e-8);
ame.SetPrintLevel(1);
ame.SetMassMatrix(*M);
ame.SetOperator(*A);
ame.Solve();
x = ame.GetEigenvector(mode);
delete A;
delete M;
}
/**
Solves the eigenvalue problem -Div(Grad x) = lambda x with homogeneous
Neumann boundary conditions on the boundary of the domain. Returns mode
number "mode" (counting from zero) in the ParGridFunction "x_l2". Note that
mode 0 is a constant field so higher mode numbers are often more
interesting. The eigenmode is solved using continuous H1 basis of the
appropriate order and then projected onto the L2 basis and returned.
*/
void PseudoScalarWaveGuide(int mode, ParGridFunction &x_l2)
{
int nev = std::max(mode + 2, 5);
int seed = 75;
ParFiniteElementSpace &fespace_l2 = *x_l2.ParFESpace();
ParMesh &pmesh = *fespace_l2.GetParMesh();
int order_l2 = fespace_l2.FEColl()->GetOrder();
H1_FECollection fec(order_l2+1, pmesh.Dimension());
ParFiniteElementSpace fespace(&pmesh, &fec);
ParGridFunction x(&fespace);
x = 0.0;
GridFunctionCoefficient xCoef(&x);
if (mode == 0)
{
x = 1.0;
x_l2.ProjectCoefficient(xCoef);
return;
}
ParBilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator);
a.AddDomainIntegrator(new MassIntegrator); // Shift eigenvalues by 1
a.Assemble();
a.Finalize();
ParBilinearForm m(&fespace);
m.AddDomainIntegrator(new MassIntegrator);
m.Assemble();
m.Finalize();
HypreParMatrix *A = a.ParallelAssemble();
HypreParMatrix *M = m.ParallelAssemble();
HypreBoomerAMG amg(*A);
amg.SetPrintLevel(0);
HypreLOBPCG lobpcg(MPI_COMM_WORLD);
lobpcg.SetNumModes(nev);
lobpcg.SetRandomSeed(seed);
lobpcg.SetPreconditioner(amg);
lobpcg.SetMaxIter(200);
lobpcg.SetTol(1e-8);
lobpcg.SetPrecondUsageMode(1);
lobpcg.SetPrintLevel(1);
lobpcg.SetMassMatrix(*M);
lobpcg.SetOperator(*A);
lobpcg.Solve();
x = lobpcg.GetEigenvector(mode);
x_l2.ProjectCoefficient(xCoef);
delete A;
delete M;
}
// Compute eigenmode "mode" of either a Dirichlet or Neumann Laplacian or of a
// Dirichlet curl curl operator based on the problem type and dimension of the
// domain.
void SetPortBC(int prob, int dim, int mode, ParGridFunction &port_bc)
{
switch (prob)
{
case 0:
ScalarWaveGuide(mode, port_bc);
break;
case 1:
if (dim == 3)
{
VectorWaveGuide(mode, port_bc);
}
else
{
PseudoScalarWaveGuide(mode, port_bc);
}
break;
case 2:
PseudoScalarWaveGuide(mode, port_bc);
break;
}
}
+459
View File
@@ -0,0 +1,459 @@
// MFEM Example 36
//
// Compile with: make ex36
//
// Sample runs: ex36 -o 2
// ex36 -o 2 -r 4
//
// Description: This example code demonstrates the use of MFEM to solve the
// bound-constrained energy minimization problem
//
// minimize ||∇u||² subject to u ≥ ϕ in H¹₀.
//
// This is known as the obstacle problem, and it is a simple
// mathematical model for contact mechanics.
//
// In this example, the obstacle ϕ is a half-sphere centered
// at the origin of a circular domain Ω. After solving to a
// specified tolerance, the numerical solution is compared to
// a closed-form exact solution to assess accuracy.
//
// The problem is discretized and solved using the proximal
// Galerkin finite element method, introduced by Keith and
// Surowiec [1].
//
// This example highlights the ability of MFEM to deliver high-
// order solutions to variation inequality problems and
// showcases how to set up and solve nonlinear mixed methods.
//
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
double spherical_obstacle(const Vector &pt);
double exact_solution_obstacle(const Vector &pt);
void exact_solution_gradient_obstacle(const Vector &pt, Vector &grad);
class LogarithmGridFunctionCoefficient : public Coefficient
{
protected:
GridFunction *u; // grid function
Coefficient *obstacle;
double min_val;
public:
LogarithmGridFunctionCoefficient(GridFunction &u_, Coefficient &obst_,
double min_val_=-36)
: u(&u_), obstacle(&obst_), min_val(min_val_) { }
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
};
class ExponentialGridFunctionCoefficient : public Coefficient
{
protected:
GridFunction *u;
Coefficient *obstacle;
double min_val;
double max_val;
public:
ExponentialGridFunctionCoefficient(GridFunction &u_, Coefficient &obst_,
double min_val_=0.0, double max_val_=1e6)
: u(&u_), obstacle(&obst_), min_val(min_val_), max_val(max_val_) { }
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
};
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
int order = 1;
int max_it = 10;
int ref_levels = 3;
double alpha = 1.0;
double tol = 1e-5;
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&ref_levels, "-r", "--refs",
"Number of h-refinements.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of iterations");
args.AddOption(&tol, "-tol", "--tol",
"Stopping criteria based on the difference between"
"successive solution updates");
args.AddOption(&alpha, "-step", "--step",
"Step size alpha");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the mesh from the mesh file.
const char *mesh_file = "../data/disc-nurbs.mesh";
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
// 3. Postprocess the mesh.
// 3A. Refine the mesh to increase the resolution.
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
// 3B. Interpolate the geometry after refinement to control geometry error.
// NOTE: Minimum second-order interpolation is used to improve the accuracy.
int curvature_order = max(order,2);
mesh.SetCurvature(curvature_order);
// 3C. Rescale the domain to a unit circle (radius = 1).
GridFunction *nodes = mesh.GetNodes();
double scale = 2*sqrt(2);
*nodes /= scale;
// 4. Define the necessary finite element spaces on the mesh.
H1_FECollection H1fec(order+1, dim);
FiniteElementSpace H1fes(&mesh, &H1fec);
L2_FECollection L2fec(order-1, dim);
FiniteElementSpace L2fes(&mesh, &L2fec);
cout << "Number of H1 finite element unknowns: "
<< H1fes.GetTrueVSize() << endl;
cout << "Number of L2 finite element unknowns: "
<< L2fes.GetTrueVSize() << endl;
Array<int> offsets(3);
offsets[0] = 0;
offsets[1] = H1fes.GetVSize();
offsets[2] = L2fes.GetVSize();
offsets.PartialSum();
BlockVector x(offsets), rhs(offsets);
x = 0.0; rhs = 0.0;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
Array<int> ess_bdr;
if (mesh.bdr_attributes.Size())
{
ess_bdr.SetSize(mesh.bdr_attributes.Max());
ess_bdr = 1;
}
// 6. Define an initial guess for the solution.
auto IC_func = [](const Vector &x)
{
double r0 = 1.0;
double rr = 0.0;
for (int i=0; i<x.Size(); i++)
{
rr += x(i)*x(i);
}
return r0*r0 - rr;
};
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
// 7. Define the solution vectors as a finite element grid functions
// corresponding to the fespaces.
GridFunction u_gf, delta_psi_gf;
u_gf.MakeRef(&H1fes,x,offsets[0]);
delta_psi_gf.MakeRef(&L2fes,x,offsets[1]);
delta_psi_gf = 0.0;
GridFunction u_old_gf(&H1fes);
GridFunction psi_old_gf(&L2fes);
GridFunction psi_gf(&L2fes);
u_old_gf = 0.0;
psi_old_gf = 0.0;
// 8. Define the function coefficients for the solution and use them to
// initialize the initial guess
FunctionCoefficient exact_coef(exact_solution_obstacle);
VectorFunctionCoefficient exact_grad_coef(dim,exact_solution_gradient_obstacle);
FunctionCoefficient IC_coef(IC_func);
ConstantCoefficient f(0.0);
FunctionCoefficient obstacle(spherical_obstacle);
u_gf.ProjectCoefficient(IC_coef);
u_old_gf = u_gf;
// 9. Initialize the slack variable ψₕ = ln(uₕ)
LogarithmGridFunctionCoefficient ln_u(u_gf, obstacle);
psi_gf.ProjectCoefficient(ln_u);
psi_old_gf = psi_gf;
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock;
if (visualization)
{
sol_sock.open(vishost,visport);
sol_sock.precision(8);
}
// 10. Iterate
int k;
int total_iterations = 0;
double increment_u = 0.1;
for (k = 0; k < max_it; k++)
{
GridFunction u_tmp(&H1fes);
u_tmp = u_old_gf;
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
int j;
for ( j = 0; j < 10; j++)
{
total_iterations++;
ConstantCoefficient alpha_cf(alpha);
LinearForm b0,b1;
b0.Update(&H1fes,rhs.GetBlock(0),0);
b1.Update(&L2fes,rhs.GetBlock(1),0);
ExponentialGridFunctionCoefficient exp_psi(psi_gf, zero);
ProductCoefficient neg_exp_psi(-1.0,exp_psi);
GradientGridFunctionCoefficient grad_u_old(&u_old_gf);
ProductCoefficient alpha_f(alpha, f);
GridFunctionCoefficient psi_cf(&psi_gf);
GridFunctionCoefficient psi_old_cf(&psi_old_gf);
SumCoefficient psi_old_minus_psi(psi_old_cf, psi_cf, 1.0, -1.0);
b0.AddDomainIntegrator(new DomainLFIntegrator(alpha_f));
b0.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
b0.Assemble();
b1.AddDomainIntegrator(new DomainLFIntegrator(exp_psi));
b1.AddDomainIntegrator(new DomainLFIntegrator(obstacle));
b1.Assemble();
BilinearForm a00(&H1fes);
a00.SetDiagonalPolicy(mfem::Operator::DIAG_ONE);
a00.AddDomainIntegrator(new DiffusionIntegrator(alpha_cf));
a00.Assemble();
a00.EliminateEssentialBC(ess_bdr,x.GetBlock(0),rhs.GetBlock(0),
mfem::Operator::DIAG_ONE);
a00.Finalize();
SparseMatrix &A00 = a00.SpMat();
MixedBilinearForm a10(&H1fes,&L2fes);
a10.AddDomainIntegrator(new MixedScalarMassIntegrator());
a10.Assemble();
a10.EliminateTrialDofs(ess_bdr, x.GetBlock(0), rhs.GetBlock(1));
a10.Finalize();
SparseMatrix &A10 = a10.SpMat();
SparseMatrix *A01 = Transpose(A10);
BilinearForm a11(&L2fes);
a11.AddDomainIntegrator(new MassIntegrator(neg_exp_psi));
// NOTE: Shift the spectrum of the Hessian matrix for additional
// stability (Quasi-Newton).
ConstantCoefficient eps_cf(-1e-6);
if (order == 1)
{
// NOTE: ∇ₕuₕ = 0 for constant functions.
// Therefore, we use the mass matrix to shift the spectrum
a11.AddDomainIntegrator(new MassIntegrator(eps_cf));
}
else
{
a11.AddDomainIntegrator(new DiffusionIntegrator(eps_cf));
}
a11.Assemble();
a11.Finalize();
SparseMatrix &A11 = a11.SpMat();
BlockOperator A(offsets);
A.SetBlock(0,0,&A00);
A.SetBlock(1,0,&A10);
A.SetBlock(0,1,A01);
A.SetBlock(1,1,&A11);
BlockDiagonalPreconditioner prec(offsets);
prec.SetDiagonalBlock(0,new GSSmoother(A00));
prec.SetDiagonalBlock(1,new GSSmoother(A11));
prec.owns_blocks = 1;
GMRES(A,prec,rhs,x,0,10000,500,1e-12,0.0);
u_gf.MakeRef(&H1fes, x.GetBlock(0), 0);
delta_psi_gf.MakeRef(&L2fes, x.GetBlock(1), 0);
u_tmp -= u_gf;
double Newton_update_size = u_tmp.ComputeL2Error(zero);
u_tmp = u_gf;
double gamma = 1.0;
delta_psi_gf *= gamma;
psi_gf += delta_psi_gf;
if (visualization)
{
sol_sock << "solution\n" << mesh << u_gf << "window_title 'Discrete solution'"
<< flush;
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
}
delete A01;
if (Newton_update_size < increment_u)
{
break;
}
}
u_tmp = u_gf;
u_tmp -= u_old_gf;
increment_u = u_tmp.ComputeL2Error(zero);
mfem::out << "Number of Newton iterations = " << j+1 << endl;
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
u_old_gf = u_gf;
psi_old_gf = psi_gf;
if (increment_u < tol || k == max_it-1)
{
break;
}
double H1_error = u_gf.ComputeH1Error(&exact_coef,&exact_grad_coef);
mfem::out << "H1-error (|| u - uₕᵏ||) = " << H1_error << endl;
}
mfem::out << "\n Outer iterations: " << k+1
<< "\n Total iterations: " << total_iterations
<< "\n Total dofs: " << H1fes.GetTrueVSize() + L2fes.GetTrueVSize()
<< endl;
// 11. Exact solution.
if (visualization)
{
socketstream err_sock(vishost, visport);
err_sock.precision(8);
GridFunction error_gf(&H1fes);
error_gf.ProjectCoefficient(exact_coef);
error_gf -= u_gf;
err_sock << "solution\n" << mesh << error_gf << "window_title 'Error'" <<
flush;
}
{
double L2_error = u_gf.ComputeL2Error(exact_coef);
double H1_error = u_gf.ComputeH1Error(&exact_coef,&exact_grad_coef);
ExponentialGridFunctionCoefficient u_alt_cf(psi_gf,obstacle);
GridFunction u_alt_gf(&L2fes);
u_alt_gf.ProjectCoefficient(u_alt_cf);
double L2_error_alt = u_alt_gf.ComputeL2Error(exact_coef);
mfem::out << "\n Final L2-error (|| u - uₕ||) = " << L2_error <<
endl;
mfem::out << " Final H1-error (|| u - uₕ||) = " << H1_error << endl;
mfem::out << " Final L2-error (|| u - ϕ - exp(ψₕ)||) = " << L2_error_alt <<
endl;
}
return 0;
}
double LogarithmGridFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(u != NULL, "grid function is not set");
double val = u->GetValue(T, ip) - obstacle->Eval(T, ip);
return max(min_val, log(val));
}
double ExponentialGridFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(u != NULL, "grid function is not set");
double val = u->GetValue(T, ip);
return min(max_val, max(min_val, exp(val) + obstacle->Eval(T, ip)));
}
double spherical_obstacle(const Vector &pt)
{
double x = pt(0), y = pt(1);
double r = sqrt(x*x + y*y);
double r0 = 0.5;
double beta = 0.9;
double b = r0*beta;
double tmp = sqrt(r0*r0 - b*b);
double B = tmp + b*b/tmp;
double C = -b/tmp;
if (r > b)
{
return B + r * C;
}
else
{
return sqrt(r0*r0 - r*r);
}
}
double exact_solution_obstacle(const Vector &pt)
{
double x = pt(0), y = pt(1);
double r = sqrt(x*x + y*y);
double r0 = 0.5;
double a = 0.348982574111686;
double A = -0.340129705945858;
if (r > a)
{
return A * log(r);
}
else
{
return sqrt(r0*r0-r*r);
}
}
void exact_solution_gradient_obstacle(const Vector &pt, Vector &grad)
{
double x = pt(0), y = pt(1);
double r = sqrt(x*x + y*y);
double r0 = 0.5;
double a = 0.348982574111686;
double A = -0.340129705945858;
if (r > a)
{
grad(0) = A * x / (r*r);
grad(1) = A * y / (r*r);
}
else
{
grad(0) = - x / sqrt( r0*r0 - r*r );
grad(1) = - y / sqrt( r0*r0 - r*r );
}
}
+523
View File
@@ -0,0 +1,523 @@
// MFEM Example 36 - Parallel Version
//
// Compile with: make ex36p
//
// Sample runs: mpirun -np 4 ex36p -o 2
// mpirun -np 4 ex36p -o 2 -r 4
//
// Description: This example code demonstrates the use of MFEM to solve the
// bound-constrained energy minimization problem
//
// minimize ||∇u||² subject to u ≥ ϕ in H¹₀.
//
// This is known as the obstacle problem, and it is a simple
// mathematical model for contact mechanics.
//
// In this example, the obstacle ϕ is a half-sphere centered
// at the origin of a circular domain Ω. After solving to a
// specified tolerance, the numerical solution is compared to
// a closed-form exact solution to assess accuracy.
//
// The problem is discretized and solved using the proximal
// Galerkin finite element method, introduced by Keith and
// Surowiec [1].
//
// This example highlights the ability of MFEM to deliver high-
// order solutions to variation inequality problems and
// showcases how to set up and solve nonlinear mixed methods.
//
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
double spherical_obstacle(const Vector &pt);
double exact_solution_obstacle(const Vector &pt);
void exact_solution_gradient_obstacle(const Vector &pt, Vector &grad);
class LogarithmGridFunctionCoefficient : public Coefficient
{
protected:
GridFunction *u; // grid function
Coefficient *obstacle;
double min_val;
public:
LogarithmGridFunctionCoefficient(GridFunction &u_, Coefficient &obst_,
double min_val_=-36)
: u(&u_), obstacle(&obst_), min_val(min_val_) { }
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
};
class ExponentialGridFunctionCoefficient : public Coefficient
{
protected:
GridFunction *u;
Coefficient *obstacle;
double min_val;
double max_val;
public:
ExponentialGridFunctionCoefficient(GridFunction &u_, Coefficient &obst_,
double min_val_=0.0, double max_val_=1e6)
: u(&u_), obstacle(&obst_), min_val(min_val_), max_val(max_val_) { }
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
};
int main(int argc, char *argv[])
{
// 0. Initialize MPI and HYPRE.
Mpi::Init();
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
// 1. Parse command-line options.
int order = 1;
int max_it = 10;
int ref_levels = 3;
double alpha = 1.0;
double tol = 1e-5;
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&ref_levels, "-r", "--refs",
"Number of h-refinements.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of iterations");
args.AddOption(&tol, "-tol", "--tol",
"Stopping criteria based on the difference between"
"successive solution updates");
args.AddOption(&alpha, "-step", "--step",
"Step size alpha");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 2. Read the mesh from the mesh file.
const char *mesh_file = "../data/disc-nurbs.mesh";
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
// 3. Postprocess the mesh.
// 3A. Refine the mesh to increase the resolution.
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
// 3B. Interpolate the geometry after refinement to control geometry error.
// NOTE: Minimum second-order interpolation is used to improve the accuracy.
int curvature_order = max(order,2);
mesh.SetCurvature(curvature_order);
// 3C. Rescale the domain to a unit circle (radius = 1).
GridFunction *nodes = mesh.GetNodes();
double scale = 2*sqrt(2);
*nodes /= scale;
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
// 4. Define the necessary finite element spaces on the mesh.
H1_FECollection H1fec(order+1, dim);
ParFiniteElementSpace H1fes(&pmesh, &H1fec);
L2_FECollection L2fec(order-1, dim);
ParFiniteElementSpace L2fes(&pmesh, &L2fec);
int num_dofs_H1 = H1fes.GetTrueVSize();
MPI_Allreduce(MPI_IN_PLACE, &num_dofs_H1, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
int num_dofs_L2 = L2fes.GetTrueVSize();
MPI_Allreduce(MPI_IN_PLACE, &num_dofs_L2, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
if (myid == 0)
{
cout << "Number of H1 finite element unknowns: "
<< num_dofs_H1 << endl;
cout << "Number of L2 finite element unknowns: "
<< num_dofs_L2 << endl;
}
Array<int> offsets(3);
offsets[0] = 0;
offsets[1] = H1fes.GetVSize();
offsets[2] = L2fes.GetVSize();
offsets.PartialSum();
Array<int> toffsets(3);
toffsets[0] = 0;
toffsets[1] = H1fes.GetTrueVSize();
toffsets[2] = L2fes.GetTrueVSize();
toffsets.PartialSum();
BlockVector x(offsets), rhs(offsets);
x = 0.0; rhs = 0.0;
BlockVector tx(toffsets), trhs(toffsets);
tx = 0.0; trhs = 0.0;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
Array<int> empty;
Array<int> ess_tdof_list;
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
H1fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 6. Define an initial guess for the solution.
auto IC_func = [](const Vector &x)
{
double r0 = 1.0;
double rr = 0.0;
for (int i=0; i<x.Size(); i++)
{
rr += x(i)*x(i);
}
return r0*r0 - rr;
};
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
// 7. Define the solution vectors as a finite element grid functions
// corresponding to the fespaces.
ParGridFunction u_gf, delta_psi_gf;
u_gf.MakeRef(&H1fes,x,offsets[0]);
delta_psi_gf.MakeRef(&L2fes,x,offsets[1]);
delta_psi_gf = 0.0;
ParGridFunction u_old_gf(&H1fes);
ParGridFunction psi_old_gf(&L2fes);
ParGridFunction psi_gf(&L2fes);
u_old_gf = 0.0;
psi_old_gf = 0.0;
// 8. Define the function coefficients for the solution and use them to
// initialize the initial guess
FunctionCoefficient exact_coef(exact_solution_obstacle);
VectorFunctionCoefficient exact_grad_coef(dim,exact_solution_gradient_obstacle);
FunctionCoefficient IC_coef(IC_func);
ConstantCoefficient f(0.0);
FunctionCoefficient obstacle(spherical_obstacle);
u_gf.ProjectCoefficient(IC_coef);
u_old_gf = u_gf;
// 9. Initialize the slack variable ψₕ = ln(uₕ)
LogarithmGridFunctionCoefficient ln_u(u_gf, obstacle);
psi_gf.ProjectCoefficient(ln_u);
psi_old_gf = psi_gf;
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock;
if (visualization)
{
sol_sock.open(vishost,visport);
sol_sock.precision(8);
}
// 10. Iterate
int k;
int total_iterations = 0;
double increment_u = 0.1;
for (k = 0; k < max_it; k++)
{
ParGridFunction u_tmp(&H1fes);
u_tmp = u_old_gf;
if (myid == 0)
{
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
}
int j;
for ( j = 0; j < 10; j++)
{
total_iterations++;
ConstantCoefficient alpha_cf(alpha);
ParLinearForm b0,b1;
b0.Update(&H1fes,rhs.GetBlock(0),0);
b1.Update(&L2fes,rhs.GetBlock(1),0);
ExponentialGridFunctionCoefficient exp_psi(psi_gf, zero);
ProductCoefficient neg_exp_psi(-1.0,exp_psi);
GradientGridFunctionCoefficient grad_u_old(&u_old_gf);
ProductCoefficient alpha_f(alpha, f);
GridFunctionCoefficient psi_cf(&psi_gf);
GridFunctionCoefficient psi_old_cf(&psi_old_gf);
SumCoefficient psi_old_minus_psi(psi_old_cf, psi_cf, 1.0, -1.0);
b0.AddDomainIntegrator(new DomainLFIntegrator(alpha_f));
b0.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
b0.Assemble();
b1.AddDomainIntegrator(new DomainLFIntegrator(exp_psi));
b1.AddDomainIntegrator(new DomainLFIntegrator(obstacle));
b1.Assemble();
ParBilinearForm a00(&H1fes);
a00.SetDiagonalPolicy(mfem::Operator::DIAG_ONE);
a00.AddDomainIntegrator(new DiffusionIntegrator(alpha_cf));
a00.Assemble();
HypreParMatrix A00;
a00.FormLinearSystem(ess_tdof_list, x.GetBlock(0), rhs.GetBlock(0),
A00, tx.GetBlock(0), trhs.GetBlock(0));
ParMixedBilinearForm a10(&H1fes,&L2fes);
a10.AddDomainIntegrator(new MixedScalarMassIntegrator());
a10.Assemble();
HypreParMatrix A10;
a10.FormRectangularLinearSystem(ess_tdof_list, empty, x.GetBlock(0),
rhs.GetBlock(1),
A10, tx.GetBlock(0), trhs.GetBlock(1));
HypreParMatrix *A01 = A10.Transpose();
ParBilinearForm a11(&L2fes);
a11.AddDomainIntegrator(new MassIntegrator(neg_exp_psi));
// NOTE: Shift the spectrum of the Hessian matrix for additional
// stability (Quasi-Newton).
ConstantCoefficient eps_cf(-1e-6);
if (order == 1)
{
// NOTE: ∇ₕuₕ = 0 for constant functions.
// Therefore, we use the mass matrix to shift the spectrum
a11.AddDomainIntegrator(new MassIntegrator(eps_cf));
}
else
{
a11.AddDomainIntegrator(new DiffusionIntegrator(eps_cf));
}
a11.Assemble();
a11.Finalize();
HypreParMatrix A11;
a11.FormSystemMatrix(empty, A11);
BlockOperator A(toffsets);
A.SetBlock(0,0,&A00);
A.SetBlock(1,0,&A10);
A.SetBlock(0,1,A01);
A.SetBlock(1,1,&A11);
BlockDiagonalPreconditioner prec(toffsets);
HypreBoomerAMG P00(A00);
P00.SetPrintLevel(0);
HypreSmoother P11(A11);
prec.SetDiagonalBlock(0,&P00);
prec.SetDiagonalBlock(1,&P11);
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetPrintLevel(-1);
gmres.SetRelTol(1e-8);
gmres.SetMaxIter(20000);
gmres.SetKDim(500);
gmres.SetOperator(A);
gmres.SetPreconditioner(prec);
gmres.Mult(trhs,tx);
u_gf.SetFromTrueDofs(tx.GetBlock(0));
delta_psi_gf.SetFromTrueDofs(tx.GetBlock(1));
u_tmp -= u_gf;
double Newton_update_size = u_tmp.ComputeL2Error(zero);
u_tmp = u_gf;
double gamma = 1.0;
delta_psi_gf *= gamma;
psi_gf += delta_psi_gf;
if (visualization)
{
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock << "solution\n" << pmesh << u_gf << "window_title 'Discrete solution'"
<< flush;
}
if (myid == 0)
{
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
}
delete A01;
if (Newton_update_size < increment_u)
{
break;
}
}
u_tmp = u_gf;
u_tmp -= u_old_gf;
increment_u = u_tmp.ComputeL2Error(zero);
if (myid == 0)
{
mfem::out << "Number of Newton iterations = " << j+1 << endl;
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
}
u_old_gf = u_gf;
psi_old_gf = psi_gf;
if (increment_u < tol || k == max_it-1)
{
break;
}
double H1_error = u_gf.ComputeH1Error(&exact_coef,&exact_grad_coef);
if (myid == 0)
{
mfem::out << "H1-error (|| u - uₕᵏ||) = " << H1_error << endl;
}
}
if (myid == 0)
{
mfem::out << "\n Outer iterations: " << k+1
<< "\n Total iterations: " << total_iterations
<< "\n Total dofs: " << num_dofs_H1 + num_dofs_L2
<< endl;
}
// 11. Exact solution.
if (visualization)
{
socketstream err_sock(vishost, visport);
err_sock.precision(8);
ParGridFunction error_gf(&H1fes);
error_gf.ProjectCoefficient(exact_coef);
error_gf -= u_gf;
err_sock << "parallel " << num_procs << " " << myid << "\n";
err_sock << "solution\n" << pmesh << error_gf << "window_title 'Error'" <<
flush;
}
{
double L2_error = u_gf.ComputeL2Error(exact_coef);
double H1_error = u_gf.ComputeH1Error(&exact_coef,&exact_grad_coef);
ExponentialGridFunctionCoefficient u_alt_cf(psi_gf,obstacle);
ParGridFunction u_alt_gf(&L2fes);
u_alt_gf.ProjectCoefficient(u_alt_cf);
double L2_error_alt = u_alt_gf.ComputeL2Error(exact_coef);
if (myid == 0)
{
mfem::out << "\n Final L2-error (|| u - uₕ||) = " << L2_error <<
endl;
mfem::out << " Final H1-error (|| u - uₕ||) = " << H1_error << endl;
mfem::out << " Final L2-error (|| u - ϕ - exp(ψₕ)||) = " << L2_error_alt <<
endl;
}
}
return 0;
}
double LogarithmGridFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(u != NULL, "grid function is not set");
double val = u->GetValue(T, ip) - obstacle->Eval(T, ip);
return max(min_val, log(val));
}
double ExponentialGridFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(u != NULL, "grid function is not set");
double val = u->GetValue(T, ip);
return min(max_val, max(min_val, exp(val) + obstacle->Eval(T, ip)));
}
double spherical_obstacle(const Vector &pt)
{
double x = pt(0), y = pt(1);
double r = sqrt(x*x + y*y);
double r0 = 0.5;
double beta = 0.9;
double b = r0*beta;
double tmp = sqrt(r0*r0 - b*b);
double B = tmp + b*b/tmp;
double C = -b/tmp;
if (r > b)
{
return B + r * C;
}
else
{
return sqrt(r0*r0 - r*r);
}
}
double exact_solution_obstacle(const Vector &pt)
{
double x = pt(0), y = pt(1);
double r = sqrt(x*x + y*y);
double r0 = 0.5;
double a = 0.348982574111686;
double A = -0.340129705945858;
if (r > a)
{
return A * log(r);
}
else
{
return sqrt(r0*r0-r*r);
}
}
void exact_solution_gradient_obstacle(const Vector &pt, Vector &grad)
{
double x = pt(0), y = pt(1);
double r = sqrt(x*x + y*y);
double r0 = 0.5;
double a = 0.348982574111686;
double A = -0.340129705945858;
if (r > a)
{
grad(0) = A * x / (r*r);
grad(1) = A * y / (r*r);
}
else
{
grad(0) = - x / sqrt( r0*r0 - r*r );
grad(1) = - y / sqrt( r0*r0 - r*r );
}
}
+466
View File
@@ -0,0 +1,466 @@
// MFEM Example 37
//
// Compile with: make ex37
//
// Sample runs:
// ex37 -alpha 10
// ex37 -alpha 10 -pv
// ex37 -lambda 0.1 -mu 0.1
// ex37 -o 2 -alpha 5.0 -mi 50 -vf 0.4 -ntol 1e-5
// ex37 -r 6 -o 1 -alpha 25.0 -epsilon 0.02 -mi 50 -ntol 1e-5
//
// Description: This example code demonstrates the use of MFEM to solve a
// density-filtered [3] topology optimization problem. The
// objective is to minimize the compliance
//
// minimize ∫_Ω f⋅u dx over u ∈ [H¹(Ω)]² and ρ ∈ L¹(Ω)
//
// subject to
//
// -Div(r(ρ̃)Cε(u)) = f in Ω + BCs
// -ϵ²Δρ̃ + ρ̃ = ρ in Ω + Neumann BCs
// 0 ≤ ρ ≤ 1 in Ω
// ∫_Ω ρ dx = θ vol(Ω)
//
// Here, r(ρ̃) = ρ₀ + ρ̃³ (1-ρ₀) is the solid isotropic material
// penalization (SIMP) law, C is the elasticity tensor for an
// isotropic linearly elastic material, ϵ > 0 is the design
// length scale, and 0 < θ < 1 is the volume fraction.
//
// The problem is discretized and gradients are computing using
// finite elements [1]. The design is optimized using an entropic
// mirror descent algorithm introduced by Keith and Surowiec [2]
// that is tailored to the bound constraint 0 ≤ ρ ≤ 1.
//
// This example highlights the ability of MFEM to deliver high-
// order solutions to inverse design problems and showcases how
// to set up and solve PDE-constrained optimization problems
// using the so-called reduced space approach.
//
// [1] Andreassen, E., Clausen, A., Schevenels, M., Lazarov, B. S., & Sigmund, O.
// (2011). Efficient topology optimization in MATLAB using 88 lines of
// code. Structural and Multidisciplinary Optimization, 43(1), 1-16.
// [2] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
// [3] Lazarov, B. S., & Sigmund, O. (2011). Filters in topology optimization
// based on Helmholtztype differential equations. International Journal
// for Numerical Methods in Engineering, 86(6), 765-781.
#include "mfem.hpp"
#include <iostream>
#include <fstream>
#include "ex37.hpp"
using namespace std;
using namespace mfem;
/**
* @brief Bregman projection of ρ = sigmoid(ψ) onto the subspace
* ∫_Ω ρ dx = θ vol(Ω) as follows:
*
* 1. Compute the root of the R → R function
* f(c) = ∫_Ω sigmoid(ψ + c) dx - θ vol(Ω)
* 2. Set ψ ← ψ + c.
*
* @param psi a GridFunction to be updated
* @param target_volume θ vol(Ω)
* @param tol Newton iteration tolerance
* @param max_its Newton maximum iteration number
* @return double Final volume, ∫_Ω sigmoid(ψ)
*/
double proj(GridFunction &psi, double target_volume, double tol=1e-12,
int max_its=10)
{
MappedGridFunctionCoefficient sigmoid_psi(&psi, sigmoid);
MappedGridFunctionCoefficient der_sigmoid_psi(&psi, der_sigmoid);
LinearForm int_sigmoid_psi(psi.FESpace());
int_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(sigmoid_psi));
LinearForm int_der_sigmoid_psi(psi.FESpace());
int_der_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(
der_sigmoid_psi));
bool done = false;
for (int k=0; k<max_its; k++) // Newton iteration
{
int_sigmoid_psi.Assemble(); // Recompute f(c) with updated ψ
const double f = int_sigmoid_psi.Sum() - target_volume;
int_der_sigmoid_psi.Assemble(); // Recompute df(c) with updated ψ
const double df = int_der_sigmoid_psi.Sum();
const double dc = -f/df;
psi += dc;
if (abs(dc) < tol) { done = true; break; }
}
if (!done)
{
mfem_warning("Projection reached maximum iteration without converging. "
"Result may not be accurate.");
}
int_sigmoid_psi.Assemble();
return int_sigmoid_psi.Sum();
}
/**
* ---------------------------------------------------------------
* ALGORITHM PREAMBLE
* ---------------------------------------------------------------
*
* The Lagrangian for this problem is
*
* L(u,ρ,ρ̃,w,w̃) = (f,u) - (r(ρ̃) C ε(u),ε(w)) + (f,w)
* - (ϵ² ∇ρ̃,∇w̃) - (ρ̃,w̃) + (ρ,w̃)
*
* where
*
* r(ρ̃) = ρ₀ + ρ̃³ (1 - ρ₀) (SIMP rule)
*
* ε(u) = (∇u + ∇uᵀ)/2 (symmetric gradient)
*
* C e = λtr(e)I + 2μe (isotropic material)
*
* NOTE: The Lame parameters can be computed from Young's modulus E
* and Poisson's ratio ν as follows:
*
* λ = E ν/((1+ν)(1-2ν)), μ = E/(2(1+ν))
*
* ---------------------------------------------------------------
*
* Discretization choices:
*
* u ∈ V ⊂ (H¹)ᵈ (order p)
* ψ ∈ L² (order p - 1), ρ = sigmoid(ψ)
* ρ̃ ∈ H¹ (order p)
* w ∈ V (order p)
* w̃ ∈ H¹ (order p)
*
* ---------------------------------------------------------------
* ALGORITHM
* ---------------------------------------------------------------
*
* Update ρ with projected mirror descent via the following algorithm.
*
* 1. Initialize ψ = inv_sigmoid(vol_fraction) so that ∫ sigmoid(ψ) = θ vol(Ω)
*
* While not converged:
*
* 2. Solve filter equation ∂_w̃ L = 0; i.e.,
*
* (ϵ² ∇ ρ̃, ∇ v ) + (ρ̃,v) = (ρ,v) ∀ v ∈ H¹.
*
* 3. Solve primal problem ∂_w L = 0; i.e.,
*
* (λ r(ρ̃) ∇⋅u, ∇⋅v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v) ∀ v ∈ V.
*
* NB. The dual problem ∂_u L = 0 is the negative of the primal problem due to symmetry.
*
* 4. Solve for filtered gradient ∂_ρ̃ L = 0; i.e.,
*
* (ϵ² ∇ w̃ , ∇ v ) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v) ∀ v ∈ H¹.
*
* 5. Project the gradient onto the discrete latent space; i.e., solve
*
* (G,v) = (w̃,v) ∀ v ∈ L².
*
* 6. Bregman proximal gradient update; i.e.,
*
* ψ ← ψ - αG + c,
*
* where α > 0 is a step size parameter and c ∈ R is a constant ensuring
*
* ∫_Ω sigmoid(ψ - αG + c) dx = θ vol(Ω).
*
* end
*/
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
int ref_levels = 5;
int order = 2;
double alpha = 1.0;
double epsilon = 0.01;
double vol_fraction = 0.5;
int max_it = 1e3;
double itol = 1e-1;
double ntol = 1e-4;
double rho_min = 1e-6;
double lambda = 1.0;
double mu = 1.0;
bool glvis_visualization = true;
bool paraview_output = false;
OptionsParser args(argc, argv);
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&alpha, "-alpha", "--alpha-step-length",
"Step length for gradient descent.");
args.AddOption(&epsilon, "-epsilon", "--epsilon-thickness",
"Length scale for ρ.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of gradient descent iterations.");
args.AddOption(&ntol, "-ntol", "--rel-tol",
"Normalized exit tolerance.");
args.AddOption(&itol, "-itol", "--abs-tol",
"Increment exit tolerance.");
args.AddOption(&vol_fraction, "-vf", "--volume-fraction",
"Volume fraction for the material density.");
args.AddOption(&lambda, "-lambda", "--lambda",
"Lamé constant λ.");
args.AddOption(&mu, "-mu", "--mu",
"Lamé constant μ.");
args.AddOption(&rho_min, "-rmin", "--psi-min",
"Minimum of density coefficient.");
args.AddOption(&glvis_visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&paraview_output, "-pv", "--paraview", "-no-pv",
"--no-paraview",
"Enable or disable ParaView output.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(mfem::out);
return 1;
}
args.PrintOptions(mfem::out);
Mesh mesh = Mesh::MakeCartesian2D(3, 1, mfem::Element::Type::QUADRILATERAL,
true, 3.0, 1.0);
int dim = mesh.Dimension();
// 2. Set BCs.
for (int i = 0; i<mesh.GetNBE(); i++)
{
Element * be = mesh.GetBdrElement(i);
Array<int> vertices;
be->GetVertices(vertices);
double * coords1 = mesh.GetVertex(vertices[0]);
double * coords2 = mesh.GetVertex(vertices[1]);
Vector center(2);
center(0) = 0.5*(coords1[0] + coords2[0]);
center(1) = 0.5*(coords1[1] + coords2[1]);
if (abs(center(0) - 0.0) < 1e-10)
{
// the left edge
be->SetAttribute(1);
}
else
{
// all other boundaries
be->SetAttribute(2);
}
}
mesh.SetAttributes();
// 3. Refine the mesh.
for (int lev = 0; lev < ref_levels; lev++)
{
mesh.UniformRefinement();
}
// 4. Define the necessary finite element spaces on the mesh.
H1_FECollection state_fec(order, dim); // space for u
H1_FECollection filter_fec(order, dim); // space for ρ̃
L2_FECollection control_fec(order-1, dim,
BasisType::GaussLobatto); // space for ψ
FiniteElementSpace state_fes(&mesh, &state_fec,dim);
FiniteElementSpace filter_fes(&mesh, &filter_fec);
FiniteElementSpace control_fes(&mesh, &control_fec);
int state_size = state_fes.GetTrueVSize();
int control_size = control_fes.GetTrueVSize();
int filter_size = filter_fes.GetTrueVSize();
mfem::out << "Number of state unknowns: " << state_size << std::endl;
mfem::out << "Number of filter unknowns: " << filter_size << std::endl;
mfem::out << "Number of control unknowns: " << control_size << std::endl;
// 5. Set the initial guess for ρ.
GridFunction u(&state_fes);
GridFunction psi(&control_fes);
GridFunction psi_old(&control_fes);
GridFunction rho_filter(&filter_fes);
u = 0.0;
rho_filter = vol_fraction;
psi = inv_sigmoid(vol_fraction);
psi_old = inv_sigmoid(vol_fraction);
// ρ = sigmoid(ψ)
MappedGridFunctionCoefficient rho(&psi, sigmoid);
// Interpolation of ρ = sigmoid(ψ) in control fes (for ParaView output)
GridFunction rho_gf(&control_fes);
// ρ - ρ_old = sigmoid(ψ) - sigmoid(ψ_old)
DiffMappedGridFunctionCoefficient succ_diff_rho(&psi, &psi_old, sigmoid);
// 6. Set-up the physics solver.
int maxat = mesh.bdr_attributes.Max();
Array<int> ess_bdr(maxat);
ess_bdr = 0;
ess_bdr[0] = 1;
ConstantCoefficient one(1.0);
ConstantCoefficient lambda_cf(lambda);
ConstantCoefficient mu_cf(mu);
LinearElasticitySolver * ElasticitySolver = new LinearElasticitySolver();
ElasticitySolver->SetMesh(&mesh);
ElasticitySolver->SetOrder(state_fec.GetOrder());
ElasticitySolver->SetupFEM();
Vector center(2); center(0) = 2.9; center(1) = 0.5;
Vector force(2); force(0) = 0.0; force(1) = -1.0;
double r = 0.05;
VolumeForceCoefficient vforce_cf(r,center,force);
ElasticitySolver->SetRHSCoefficient(&vforce_cf);
ElasticitySolver->SetEssentialBoundary(ess_bdr);
// 7. Set-up the filter solver.
ConstantCoefficient eps2_cf(epsilon*epsilon);
DiffusionSolver * FilterSolver = new DiffusionSolver();
FilterSolver->SetMesh(&mesh);
FilterSolver->SetOrder(filter_fec.GetOrder());
FilterSolver->SetDiffusionCoefficient(&eps2_cf);
FilterSolver->SetMassCoefficient(&one);
Array<int> ess_bdr_filter;
if (mesh.bdr_attributes.Size())
{
ess_bdr_filter.SetSize(mesh.bdr_attributes.Max());
ess_bdr_filter = 0;
}
FilterSolver->SetEssentialBoundary(ess_bdr_filter);
FilterSolver->SetupFEM();
BilinearForm mass(&control_fes);
mass.AddDomainIntegrator(new InverseIntegrator(new MassIntegrator(one)));
mass.Assemble();
SparseMatrix M;
Array<int> empty;
mass.FormSystemMatrix(empty,M);
// 8. Define the Lagrange multiplier and gradient functions.
GridFunction grad(&control_fes);
GridFunction w_filter(&filter_fes);
// 9. Define some tools for later.
ConstantCoefficient zero(0.0);
GridFunction onegf(&control_fes);
onegf = 1.0;
GridFunction zerogf(&control_fes);
zerogf = 0.0;
LinearForm vol_form(&control_fes);
vol_form.AddDomainIntegrator(new DomainLFIntegrator(one));
vol_form.Assemble();
double domain_volume = vol_form(onegf);
const double target_volume = domain_volume * vol_fraction;
// 10. Connect to GLVis. Prepare for VisIt output.
char vishost[] = "localhost";
int visport = 19916;
socketstream sout_r;
if (glvis_visualization)
{
sout_r.open(vishost, visport);
sout_r.precision(8);
}
mfem::ParaViewDataCollection paraview_dc("ex37", &mesh);
if (paraview_output)
{
rho_gf.ProjectCoefficient(rho);
paraview_dc.SetPrefixPath("ParaView");
paraview_dc.SetLevelsOfDetail(order);
paraview_dc.SetDataFormat(VTKFormat::BINARY);
paraview_dc.SetHighOrderOutput(true);
paraview_dc.SetCycle(0);
paraview_dc.SetTime(0.0);
paraview_dc.RegisterField("displacement",&u);
paraview_dc.RegisterField("density",&rho_gf);
paraview_dc.RegisterField("filtered_density",&rho_filter);
paraview_dc.Save();
}
// 11. Iterate:
for (int k = 1; k <= max_it; k++)
{
if (k > 1) { alpha *= ((double) k) / ((double) k-1); }
mfem::out << "\nStep = " << k << std::endl;
// Step 1 - Filter solve
// Solve (ϵ^2 ∇ ρ̃, ∇ v ) + (ρ̃,v) = (ρ,v)
FilterSolver->SetRHSCoefficient(&rho);
FilterSolver->Solve();
rho_filter = *FilterSolver->GetFEMSolution();
// Step 2 - State solve
// Solve (λ r(ρ̃) ∇⋅u, ∇⋅v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v)
SIMPInterpolationCoefficient SIMP_cf(&rho_filter,rho_min, 1.0);
ProductCoefficient lambda_SIMP_cf(lambda_cf,SIMP_cf);
ProductCoefficient mu_SIMP_cf(mu_cf,SIMP_cf);
ElasticitySolver->SetLameCoefficients(&lambda_SIMP_cf,&mu_SIMP_cf);
ElasticitySolver->Solve();
u = *ElasticitySolver->GetFEMSolution();
// Step 3 - Adjoint filter solve
// Solve (ϵ² ∇ w̃, ∇ v) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v)
StrainEnergyDensityCoefficient rhs_cf(&lambda_cf,&mu_cf,&u, &rho_filter,
rho_min);
FilterSolver->SetRHSCoefficient(&rhs_cf);
FilterSolver->Solve();
w_filter = *FilterSolver->GetFEMSolution();
// Step 4 - Compute gradient
// Solve G = M⁻¹w̃
GridFunctionCoefficient w_cf(&w_filter);
LinearForm w_rhs(&control_fes);
w_rhs.AddDomainIntegrator(new DomainLFIntegrator(w_cf));
w_rhs.Assemble();
M.Mult(w_rhs,grad);
// Step 5 - Update design variable ψ ← proj(ψ - αG)
psi.Add(-alpha, grad);
const double material_volume = proj(psi, target_volume);
// Compute ||ρ - ρ_old|| in control fes.
double norm_increment = zerogf.ComputeL1Error(succ_diff_rho);
double norm_reduced_gradient = norm_increment/alpha;
psi_old = psi;
double compliance = (*(ElasticitySolver->GetLinearForm()))(u);
mfem::out << "norm of the reduced gradient = " << norm_reduced_gradient <<
std::endl;
mfem::out << "norm of the increment = " << norm_increment << endl;
mfem::out << "compliance = " << compliance << std::endl;
mfem::out << "volume fraction = " << material_volume / domain_volume <<
std::endl;
if (glvis_visualization)
{
GridFunction r_gf(&filter_fes);
r_gf.ProjectCoefficient(SIMP_cf);
sout_r << "solution\n" << mesh << r_gf
<< "window_title 'Design density r(ρ̃)'" << flush;
}
if (paraview_output)
{
rho_gf.ProjectCoefficient(rho);
paraview_dc.SetCycle(k);
paraview_dc.SetTime((double)k);
paraview_dc.Save();
}
if (norm_reduced_gradient < ntol && norm_increment < itol)
{
break;
}
}
delete ElasticitySolver;
delete FilterSolver;
return 0;
}
+748
View File
@@ -0,0 +1,748 @@
// MFEM Example 37 - Serial/Parallel Shared Code
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <functional>
namespace mfem
{
/// @brief Inverse sigmoid function
double inv_sigmoid(double x)
{
double tol = 1e-12;
x = std::min(std::max(tol,x),1.0-tol);
return std::log(x/(1.0-x));
}
/// @brief Sigmoid function
double sigmoid(double x)
{
if (x >= 0)
{
return 1.0/(1.0+std::exp(-x));
}
else
{
return std::exp(x)/(1.0+std::exp(x));
}
}
/// @brief Derivative of sigmoid function
double der_sigmoid(double x)
{
double tmp = sigmoid(-x);
return tmp - std::pow(tmp,2);
}
/// @brief Returns f(u(x)) where u is a scalar GridFunction and f:R → R
class MappedGridFunctionCoefficient : public GridFunctionCoefficient
{
protected:
std::function<double(const double)> fun; // f:R → R
public:
MappedGridFunctionCoefficient()
:GridFunctionCoefficient(),
fun([](double x) {return x;}) {}
MappedGridFunctionCoefficient(const GridFunction *gf,
std::function<double(const double)> fun_,
int comp=1)
:GridFunctionCoefficient(gf, comp),
fun(fun_) {}
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
return fun(GridFunctionCoefficient::Eval(T, ip));
}
void SetFunction(std::function<double(const double)> fun_) { fun = fun_; }
};
/// @brief Returns f(u(x)) - f(v(x)) where u, v are scalar GridFunctions and f:R → R
class DiffMappedGridFunctionCoefficient : public GridFunctionCoefficient
{
protected:
const GridFunction *OtherGridF;
GridFunctionCoefficient OtherGridF_cf;
std::function<double(const double)> fun; // f:R → R
public:
DiffMappedGridFunctionCoefficient()
:GridFunctionCoefficient(),
OtherGridF(nullptr),
OtherGridF_cf(),
fun([](double x) {return x;}) {}
DiffMappedGridFunctionCoefficient(const GridFunction *gf,
const GridFunction *other_gf,
std::function<double(const double)> fun_,
int comp=1)
:GridFunctionCoefficient(gf, comp),
OtherGridF(other_gf),
OtherGridF_cf(OtherGridF),
fun(fun_) {}
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
const double value1 = fun(GridFunctionCoefficient::Eval(T, ip));
const double value2 = fun(OtherGridF_cf.Eval(T, ip));
return value1 - value2;
}
void SetFunction(std::function<double(const double)> fun_) { fun = fun_; }
};
/// @brief Solid isotropic material penalization (SIMP) coefficient
class SIMPInterpolationCoefficient : public Coefficient
{
protected:
GridFunction *rho_filter;
double min_val;
double max_val;
double exponent;
public:
SIMPInterpolationCoefficient(GridFunction *rho_filter_, double min_val_= 1e-6,
double max_val_ = 1.0, double exponent_ = 3)
: rho_filter(rho_filter_), min_val(min_val_), max_val(max_val_),
exponent(exponent_) { }
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip)
{
double val = rho_filter->GetValue(T, ip);
double coeff = min_val + pow(val,exponent)*(max_val-min_val);
return coeff;
}
};
/// @brief Strain energy density coefficient
class StrainEnergyDensityCoefficient : public Coefficient
{
protected:
Coefficient * lambda=nullptr;
Coefficient * mu=nullptr;
GridFunction *u = nullptr; // displacement
GridFunction *rho_filter = nullptr; // filter density
DenseMatrix grad; // auxiliary matrix, used in Eval
double exponent;
double rho_min;
public:
StrainEnergyDensityCoefficient(Coefficient *lambda_, Coefficient *mu_,
GridFunction * u_, GridFunction * rho_filter_, double rho_min_=1e-6,
double exponent_ = 3.0)
: lambda(lambda_), mu(mu_), u(u_), rho_filter(rho_filter_),
exponent(exponent_), rho_min(rho_min_)
{
MFEM_ASSERT(rho_min_ >= 0.0, "rho_min must be >= 0");
MFEM_ASSERT(rho_min_ < 1.0, "rho_min must be > 1");
MFEM_ASSERT(u, "displacement field is not set");
MFEM_ASSERT(rho_filter, "density field is not set");
}
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip)
{
double L = lambda->Eval(T, ip);
double M = mu->Eval(T, ip);
u->GetVectorGradient(T, grad);
double div_u = grad.Trace();
double density = L*div_u*div_u;
int dim = T.GetSpaceDim();
for (int i=0; i<dim; i++)
{
for (int j=0; j<dim; j++)
{
density += M*grad(i,j)*(grad(i,j)+grad(j,i));
}
}
double val = rho_filter->GetValue(T,ip);
return -exponent * pow(val, exponent-1.0) * (1-rho_min) * density;
}
};
/// @brief Volumetric force for linear elasticity
class VolumeForceCoefficient : public VectorCoefficient
{
private:
double r;
Vector center;
Vector force;
public:
VolumeForceCoefficient(double r_,Vector & center_, Vector & force_) :
VectorCoefficient(center_.Size()), r(r_), center(center_), force(force_) { }
using VectorCoefficient::Eval;
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
Vector xx; xx.SetSize(T.GetDimension());
T.Transform(ip,xx);
for (int i=0; i<xx.Size(); i++)
{
xx[i]=xx[i]-center[i];
}
double cr=xx.Norml2();
V.SetSize(T.GetDimension());
if (cr <= r)
{
V = force;
}
else
{
V = 0.0;
}
}
void Set(double r_,Vector & center_, Vector & force_)
{
r=r_;
center = center_;
force = force_;
}
};
/**
* @brief Class for solving Poisson's equation:
*
* - ∇ ⋅(κ ∇ u) = f in Ω
*
*/
class DiffusionSolver
{
private:
Mesh * mesh = nullptr;
int order = 1;
// diffusion coefficient
Coefficient * diffcf = nullptr;
// mass coefficient
Coefficient * masscf = nullptr;
Coefficient * rhscf = nullptr;
Coefficient * essbdr_cf = nullptr;
Coefficient * neumann_cf = nullptr;
VectorCoefficient * gradient_cf = nullptr;
// FEM solver
int dim;
FiniteElementCollection * fec = nullptr;
FiniteElementSpace * fes = nullptr;
Array<int> ess_bdr;
Array<int> neumann_bdr;
GridFunction * u = nullptr;
LinearForm * b = nullptr;
bool parallel;
#ifdef MFEM_USE_MPI
ParMesh * pmesh = nullptr;
ParFiniteElementSpace * pfes = nullptr;
#endif
public:
DiffusionSolver() { }
DiffusionSolver(Mesh * mesh_, int order_, Coefficient * diffcf_,
Coefficient * cf_);
void SetMesh(Mesh * mesh_)
{
mesh = mesh_;
parallel = false;
#ifdef MFEM_USE_MPI
pmesh = dynamic_cast<ParMesh *>(mesh);
if (pmesh) { parallel = true; }
#endif
}
void SetOrder(int order_) { order = order_ ; }
void SetDiffusionCoefficient(Coefficient * diffcf_) { diffcf = diffcf_; }
void SetMassCoefficient(Coefficient * masscf_) { masscf = masscf_; }
void SetRHSCoefficient(Coefficient * rhscf_) { rhscf = rhscf_; }
void SetEssentialBoundary(const Array<int> & ess_bdr_) { ess_bdr = ess_bdr_;};
void SetNeumannBoundary(const Array<int> & neumann_bdr_) { neumann_bdr = neumann_bdr_;};
void SetNeumannData(Coefficient * neumann_cf_) {neumann_cf = neumann_cf_;}
void SetEssBdrData(Coefficient * essbdr_cf_) {essbdr_cf = essbdr_cf_;}
void SetGradientData(VectorCoefficient * gradient_cf_) {gradient_cf = gradient_cf_;}
void ResetFEM();
void SetupFEM();
void Solve();
GridFunction * GetFEMSolution();
LinearForm * GetLinearForm() {return b;}
#ifdef MFEM_USE_MPI
ParGridFunction * GetParFEMSolution();
ParLinearForm * GetParLinearForm()
{
if (parallel)
{
return dynamic_cast<ParLinearForm *>(b);
}
else
{
MFEM_ABORT("Wrong code path. Call GetLinearForm");
return nullptr;
}
}
#endif
~DiffusionSolver();
};
/**
* @brief Class for solving linear elasticity:
*
* -∇ ⋅ σ(u) = f in Ω + BCs
*
* where
*
* σ(u) = λ ∇⋅u I + μ (∇ u + ∇uᵀ)
*
*/
class LinearElasticitySolver
{
private:
Mesh * mesh = nullptr;
int order = 1;
Coefficient * lambda_cf = nullptr;
Coefficient * mu_cf = nullptr;
VectorCoefficient * essbdr_cf = nullptr;
VectorCoefficient * rhs_cf = nullptr;
// FEM solver
int dim;
FiniteElementCollection * fec = nullptr;
FiniteElementSpace * fes = nullptr;
Array<int> ess_bdr;
Array<int> neumann_bdr;
GridFunction * u = nullptr;
LinearForm * b = nullptr;
bool parallel;
#ifdef MFEM_USE_MPI
ParMesh * pmesh = nullptr;
ParFiniteElementSpace * pfes = nullptr;
#endif
public:
LinearElasticitySolver() { }
LinearElasticitySolver(Mesh * mesh_, int order_,
Coefficient * lambda_cf_, Coefficient * mu_cf_);
void SetMesh(Mesh * mesh_)
{
mesh = mesh_;
parallel = false;
#ifdef MFEM_USE_MPI
pmesh = dynamic_cast<ParMesh *>(mesh);
if (pmesh) { parallel = true; }
#endif
}
void SetOrder(int order_) { order = order_ ; }
void SetLameCoefficients(Coefficient * lambda_cf_, Coefficient * mu_cf_) { lambda_cf = lambda_cf_; mu_cf = mu_cf_; }
void SetRHSCoefficient(VectorCoefficient * rhs_cf_) { rhs_cf = rhs_cf_; }
void SetEssentialBoundary(const Array<int> & ess_bdr_) { ess_bdr = ess_bdr_;};
void SetNeumannBoundary(const Array<int> & neumann_bdr_) { neumann_bdr = neumann_bdr_;};
void SetEssBdrData(VectorCoefficient * essbdr_cf_) {essbdr_cf = essbdr_cf_;}
void ResetFEM();
void SetupFEM();
void Solve();
GridFunction * GetFEMSolution();
LinearForm * GetLinearForm() {return b;}
#ifdef MFEM_USE_MPI
ParGridFunction * GetParFEMSolution();
ParLinearForm * GetParLinearForm()
{
if (parallel)
{
return dynamic_cast<ParLinearForm *>(b);
}
else
{
MFEM_ABORT("Wrong code path. Call GetLinearForm");
return nullptr;
}
}
#endif
~LinearElasticitySolver();
};
// Poisson solver
DiffusionSolver::DiffusionSolver(Mesh * mesh_, int order_,
Coefficient * diffcf_, Coefficient * rhscf_)
: mesh(mesh_), order(order_), diffcf(diffcf_), rhscf(rhscf_)
{
#ifdef MFEM_USE_MPI
pmesh = dynamic_cast<ParMesh *>(mesh);
if (pmesh) { parallel = true; }
#endif
SetupFEM();
}
void DiffusionSolver::SetupFEM()
{
dim = mesh->Dimension();
fec = new H1_FECollection(order, dim);
#ifdef MFEM_USE_MPI
if (parallel)
{
pfes = new ParFiniteElementSpace(pmesh, fec);
u = new ParGridFunction(pfes);
b = new ParLinearForm(pfes);
}
else
{
fes = new FiniteElementSpace(mesh, fec);
u = new GridFunction(fes);
b = new LinearForm(fes);
}
#else
fes = new FiniteElementSpace(mesh, fec);
u = new GridFunction(fes);
b = new LinearForm(fes);
#endif
*u=0.0;
if (!ess_bdr.Size())
{
if (mesh->bdr_attributes.Size())
{
ess_bdr.SetSize(mesh->bdr_attributes.Max());
ess_bdr = 1;
}
}
}
void DiffusionSolver::Solve()
{
OperatorPtr A;
Vector B, X;
Array<int> ess_tdof_list;
#ifdef MFEM_USE_MPI
if (parallel)
{
pfes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
}
else
{
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
}
#else
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
#endif
*u=0.0;
if (b)
{
delete b;
#ifdef MFEM_USE_MPI
if (parallel)
{
b = new ParLinearForm(pfes);
}
else
{
b = new LinearForm(fes);
}
#else
b = new LinearForm(fes);
#endif
}
if (rhscf)
{
b->AddDomainIntegrator(new DomainLFIntegrator(*rhscf));
}
if (neumann_cf)
{
MFEM_VERIFY(neumann_bdr.Size(), "neumann_bdr attributes not provided");
b->AddBoundaryIntegrator(new BoundaryLFIntegrator(*neumann_cf),neumann_bdr);
}
else if (gradient_cf)
{
MFEM_VERIFY(neumann_bdr.Size(), "neumann_bdr attributes not provided");
b->AddBoundaryIntegrator(new BoundaryNormalLFIntegrator(*gradient_cf),
neumann_bdr);
}
b->Assemble();
BilinearForm * a = nullptr;
#ifdef MFEM_USE_MPI
if (parallel)
{
a = new ParBilinearForm(pfes);
}
else
{
a = new BilinearForm(fes);
}
#else
a = new BilinearForm(fes);
#endif
a->AddDomainIntegrator(new DiffusionIntegrator(*diffcf));
if (masscf)
{
a->AddDomainIntegrator(new MassIntegrator(*masscf));
}
a->Assemble();
if (essbdr_cf)
{
u->ProjectBdrCoefficient(*essbdr_cf,ess_bdr);
}
a->FormLinearSystem(ess_tdof_list, *u, *b, A, X, B);
CGSolver * cg = nullptr;
Solver * M = nullptr;
#ifdef MFEM_USE_MPI
if (parallel)
{
M = new HypreBoomerAMG;
dynamic_cast<HypreBoomerAMG*>(M)->SetPrintLevel(0);
cg = new CGSolver(pmesh->GetComm());
}
else
{
M = new GSSmoother((SparseMatrix&)(*A));
cg = new CGSolver;
}
#else
M = new GSSmoother((SparseMatrix&)(*A));
cg = new CGSolver;
#endif
cg->SetRelTol(1e-12);
cg->SetMaxIter(10000);
cg->SetPrintLevel(0);
cg->SetPreconditioner(*M);
cg->SetOperator(*A);
cg->Mult(B, X);
delete M;
delete cg;
a->RecoverFEMSolution(X, *b, *u);
delete a;
}
GridFunction * DiffusionSolver::GetFEMSolution()
{
return u;
}
#ifdef MFEM_USE_MPI
ParGridFunction * DiffusionSolver::GetParFEMSolution()
{
if (parallel)
{
return dynamic_cast<ParGridFunction*>(u);
}
else
{
MFEM_ABORT("Wrong code path. Call GetFEMSolution");
return nullptr;
}
}
#endif
DiffusionSolver::~DiffusionSolver()
{
delete u; u = nullptr;
delete fes; fes = nullptr;
#ifdef MFEM_USE_MPI
delete pfes; pfes=nullptr;
#endif
delete fec; fec = nullptr;
delete b;
}
// Elasticity solver
LinearElasticitySolver::LinearElasticitySolver(Mesh * mesh_, int order_,
Coefficient * lambda_cf_, Coefficient * mu_cf_)
: mesh(mesh_), order(order_), lambda_cf(lambda_cf_), mu_cf(mu_cf_)
{
#ifdef MFEM_USE_MPI
pmesh = dynamic_cast<ParMesh *>(mesh);
if (pmesh) { parallel = true; }
#endif
SetupFEM();
}
void LinearElasticitySolver::SetupFEM()
{
dim = mesh->Dimension();
fec = new H1_FECollection(order, dim,BasisType::Positive);
#ifdef MFEM_USE_MPI
if (parallel)
{
pfes = new ParFiniteElementSpace(pmesh, fec, dim);
u = new ParGridFunction(pfes);
b = new ParLinearForm(pfes);
}
else
{
fes = new FiniteElementSpace(mesh, fec,dim);
u = new GridFunction(fes);
b = new LinearForm(fes);
}
#else
fes = new FiniteElementSpace(mesh, fec, dim);
u = new GridFunction(fes);
b = new LinearForm(fes);
#endif
*u=0.0;
if (!ess_bdr.Size())
{
if (mesh->bdr_attributes.Size())
{
ess_bdr.SetSize(mesh->bdr_attributes.Max());
ess_bdr = 1;
}
}
}
void LinearElasticitySolver::Solve()
{
GridFunction * x = nullptr;
OperatorPtr A;
Vector B, X;
Array<int> ess_tdof_list;
#ifdef MFEM_USE_MPI
if (parallel)
{
x = new ParGridFunction(pfes);
pfes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
}
else
{
x = new GridFunction(fes);
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
}
#else
x = new GridFunction(fes);
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list);
#endif
*u=0.0;
if (b)
{
delete b;
#ifdef MFEM_USE_MPI
if (parallel)
{
b = new ParLinearForm(pfes);
}
else
{
b = new LinearForm(fes);
}
#else
b = new LinearForm(fes);
#endif
}
if (rhs_cf)
{
b->AddDomainIntegrator(new VectorDomainLFIntegrator(*rhs_cf));
}
b->Assemble();
*x = 0.0;
BilinearForm * a = nullptr;
#ifdef MFEM_USE_MPI
if (parallel)
{
a = new ParBilinearForm(pfes);
}
else
{
a = new BilinearForm(fes);
}
#else
a = new BilinearForm(fes);
#endif
a->AddDomainIntegrator(new ElasticityIntegrator(*lambda_cf, *mu_cf));
a->Assemble();
if (essbdr_cf)
{
u->ProjectBdrCoefficient(*essbdr_cf,ess_bdr);
}
a->FormLinearSystem(ess_tdof_list, *x, *b, A, X, B);
CGSolver * cg = nullptr;
Solver * M = nullptr;
#ifdef MFEM_USE_MPI
if (parallel)
{
M = new HypreBoomerAMG;
dynamic_cast<HypreBoomerAMG*>(M)->SetPrintLevel(0);
cg = new CGSolver(pmesh->GetComm());
}
else
{
M = new GSSmoother((SparseMatrix&)(*A));
cg = new CGSolver;
}
#else
M = new GSSmoother((SparseMatrix&)(*A));
cg = new CGSolver;
#endif
cg->SetRelTol(1e-10);
cg->SetMaxIter(10000);
cg->SetPrintLevel(0);
cg->SetPreconditioner(*M);
cg->SetOperator(*A);
cg->Mult(B, X);
delete M;
delete cg;
a->RecoverFEMSolution(X, *b, *x);
*u+=*x;
delete a;
delete x;
}
GridFunction * LinearElasticitySolver::GetFEMSolution()
{
return u;
}
#ifdef MFEM_USE_MPI
ParGridFunction * LinearElasticitySolver::GetParFEMSolution()
{
if (parallel)
{
return dynamic_cast<ParGridFunction*>(u);
}
else
{
MFEM_ABORT("Wrong code path. Call GetFEMSolution");
return nullptr;
}
}
#endif
LinearElasticitySolver::~LinearElasticitySolver()
{
delete u; u = nullptr;
delete fes; fes = nullptr;
#ifdef MFEM_USE_MPI
delete pfes; pfes=nullptr;
#endif
delete fec; fec = nullptr;
delete b;
}
} // namespace mfem
+497
View File
@@ -0,0 +1,497 @@
// MFEM Example 37 - Parallel Version
//
// Compile with: make ex37p
//
// Sample runs:
// mpirun -np 4 ex37p -alpha 10 -pv
// mpirun -np 4 ex37p -lambda 0.1 -mu 0.1
// mpirun -np 4 ex37p -o 2 -alpha 5.0 -mi 50 -vf 0.4 -ntol 1e-5
// mpirun -np 4 ex37p -r 6 -o 2 -alpha 10.0 -epsilon 0.02 -mi 50 -ntol 1e-5
//
// Description: This example code demonstrates the use of MFEM to solve a
// density-filtered [3] topology optimization problem. The
// objective is to minimize the compliance
//
// minimize ∫_Ω f⋅u dx over u ∈ [H¹(Ω)]² and ρ ∈ L¹(Ω)
//
// subject to
//
// -Div(r(ρ̃)Cε(u)) = f in Ω + BCs
// -ϵ²Δρ̃ + ρ̃ = ρ in Ω + Neumann BCs
// 0 ≤ ρ ≤ 1 in Ω
// ∫_Ω ρ dx = θ vol(Ω)
//
// Here, r(ρ̃) = ρ₀ + ρ̃³ (1-ρ₀) is the solid isotropic material
// penalization (SIMP) law, C is the elasticity tensor for an
// isotropic linearly elastic material, ϵ > 0 is the design
// length scale, and 0 < θ < 1 is the volume fraction.
//
// The problem is discretized and gradients are computing using
// finite elements [1]. The design is optimized using an entropic
// mirror descent algorithm introduced by Keith and Surowiec [2]
// that is tailored to the bound constraint 0 ≤ ρ ≤ 1.
//
// This example highlights the ability of MFEM to deliver high-
// order solutions to inverse design problems and showcases how
// to set up and solve PDE-constrained optimization problems
// using the so-called reduced space approach.
//
// [1] Andreassen, E., Clausen, A., Schevenels, M., Lazarov, B. S., & Sigmund, O.
// (2011). Efficient topology optimization in MATLAB using 88 lines of
// code. Structural and Multidisciplinary Optimization, 43(1), 1-16.
// [2] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
// [3] Lazarov, B. S., & Sigmund, O. (2011). Filters in topology optimization
// based on Helmholtztype differential equations. International Journal
// for Numerical Methods in Engineering, 86(6), 765-781.
#include "mfem.hpp"
#include <iostream>
#include <fstream>
#include "ex37.hpp"
using namespace std;
using namespace mfem;
/**
* @brief Bregman projection of ρ = sigmoid(ψ) onto the subspace
* ∫_Ω ρ dx = θ vol(Ω) as follows:
*
* 1. Compute the root of the R → R function
* f(c) = ∫_Ω sigmoid(ψ + c) dx - θ vol(Ω)
* 2. Set ψ ← ψ + c.
*
* @param psi a GridFunction to be updated
* @param target_volume θ vol(Ω)
* @param tol Newton iteration tolerance
* @param max_its Newton maximum iteration number
* @return double Final volume, ∫_Ω sigmoid(ψ)
*/
double proj(ParGridFunction &psi, double target_volume, double tol=1e-12,
int max_its=10)
{
MappedGridFunctionCoefficient sigmoid_psi(&psi, sigmoid);
MappedGridFunctionCoefficient der_sigmoid_psi(&psi, der_sigmoid);
ParLinearForm int_sigmoid_psi(psi.ParFESpace());
int_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(sigmoid_psi));
ParLinearForm int_der_sigmoid_psi(psi.ParFESpace());
int_der_sigmoid_psi.AddDomainIntegrator(new DomainLFIntegrator(
der_sigmoid_psi));
bool done = false;
for (int k=0; k<max_its; k++) // Newton iteration
{
int_sigmoid_psi.Assemble(); // Recompute f(c) with updated ψ
double f = int_sigmoid_psi.Sum();
MPI_Allreduce(MPI_IN_PLACE, &f, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
f -= target_volume;
int_der_sigmoid_psi.Assemble(); // Recompute df(c) with updated ψ
double df = int_der_sigmoid_psi.Sum();
MPI_Allreduce(MPI_IN_PLACE, &df, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
const double dc = -f/df;
psi += dc;
if (abs(dc) < tol) { done = true; break; }
}
if (!done)
{
mfem_warning("Projection reached maximum iteration without converging. "
"Result may not be accurate.");
}
int_sigmoid_psi.Assemble();
double material_volume = int_sigmoid_psi.Sum();
MPI_Allreduce(MPI_IN_PLACE, &material_volume, 1, MPI_DOUBLE, MPI_SUM,
MPI_COMM_WORLD);
return material_volume;
}
/**
* ---------------------------------------------------------------
* ALGORITHM PREAMBLE
* ---------------------------------------------------------------
*
* The Lagrangian for this problem is
*
* L(u,ρ,ρ̃,w,w̃) = (f,u) - (r(ρ̃) C ε(u),ε(w)) + (f,w)
* - (ϵ² ∇ρ̃,∇w̃) - (ρ̃,w̃) + (ρ,w̃)
*
* where
*
* r(ρ̃) = ρ₀ + ρ̃³ (1 - ρ₀) (SIMP rule)
*
* ε(u) = (∇u + ∇uᵀ)/2 (symmetric gradient)
*
* C e = λtr(e)I + 2μe (isotropic material)
*
* NOTE: The Lame parameters can be computed from Young's modulus E
* and Poisson's ratio ν as follows:
*
* λ = E ν/((1+ν)(1-2ν)), μ = E/(2(1+ν))
*
* ---------------------------------------------------------------
*
* Discretization choices:
*
* u ∈ V ⊂ (H¹)ᵈ (order p)
* ψ ∈ L² (order p - 1), ρ = sigmoid(ψ)
* ρ̃ ∈ H¹ (order p)
* w ∈ V (order p)
* w̃ ∈ H¹ (order p)
*
* ---------------------------------------------------------------
* ALGORITHM
* ---------------------------------------------------------------
*
* Update ρ with projected mirror descent via the following algorithm.
*
* 1. Initialize ψ = inv_sigmoid(vol_fraction) so that ∫ sigmoid(ψ) = θ vol(Ω)
*
* While not converged:
*
* 2. Solve filter equation ∂_w̃ L = 0; i.e.,
*
* (ϵ² ∇ ρ̃, ∇ v ) + (ρ̃,v) = (ρ,v) ∀ v ∈ H¹.
*
* 3. Solve primal problem ∂_w L = 0; i.e.,
*
* (λ r(ρ̃) ∇⋅u, ∇⋅v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v) ∀ v ∈ V.
*
* NB. The dual problem ∂_u L = 0 is the negative of the primal problem due to symmetry.
*
* 4. Solve for filtered gradient ∂_ρ̃ L = 0; i.e.,
*
* (ϵ² ∇ w̃ , ∇ v ) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v) ∀ v ∈ H¹.
*
* 5. Project the gradient onto the discrete latent space; i.e., solve
*
* (G,v) = (w̃,v) ∀ v ∈ L².
*
* 6. Bregman proximal gradient update; i.e.,
*
* ψ ← ψ - αG + c,
*
* where α > 0 is a step size parameter and c ∈ R is a constant ensuring
*
* ∫_Ω sigmoid(ψ - αG + c) dx = θ vol(Ω).
*
* end
*/
int main(int argc, char *argv[])
{
// 0. Initialize MPI and HYPRE.
Mpi::Init();
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
// 1. Parse command-line options.
int ref_levels = 5;
int order = 2;
double alpha = 1.0;
double epsilon = 0.01;
double vol_fraction = 0.5;
int max_it = 1e3;
double itol = 1e-1;
double ntol = 1e-4;
double rho_min = 1e-6;
double lambda = 1.0;
double mu = 1.0;
bool glvis_visualization = true;
bool paraview_output = false;
OptionsParser args(argc, argv);
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&alpha, "-alpha", "--alpha-step-length",
"Step length for gradient descent.");
args.AddOption(&epsilon, "-epsilon", "--epsilon-thickness",
"Length scale for ρ.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of gradient descent iterations.");
args.AddOption(&ntol, "-ntol", "--rel-tol",
"Normalized exit tolerance.");
args.AddOption(&itol, "-itol", "--abs-tol",
"Increment exit tolerance.");
args.AddOption(&vol_fraction, "-vf", "--volume-fraction",
"Volume fraction for the material density.");
args.AddOption(&lambda, "-lambda", "--lambda",
"Lamé constant λ.");
args.AddOption(&mu, "-mu", "--mu",
"Lamé constant μ.");
args.AddOption(&rho_min, "-rmin", "--psi-min",
"Minimum of density coefficient.");
args.AddOption(&glvis_visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&paraview_output, "-pv", "--paraview", "-no-pv",
"--no-paraview",
"Enable or disable ParaView output.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
mfem::out << num_procs << " number of process created.\n";
args.PrintOptions(cout);
}
Mesh mesh = Mesh::MakeCartesian2D(3, 1, mfem::Element::Type::QUADRILATERAL,
true, 3.0, 1.0);
int dim = mesh.Dimension();
// 2. Set BCs.
for (int i = 0; i<mesh.GetNBE(); i++)
{
Element * be = mesh.GetBdrElement(i);
Array<int> vertices;
be->GetVertices(vertices);
double * coords1 = mesh.GetVertex(vertices[0]);
double * coords2 = mesh.GetVertex(vertices[1]);
Vector center(2);
center(0) = 0.5*(coords1[0] + coords2[0]);
center(1) = 0.5*(coords1[1] + coords2[1]);
if (abs(center(0) - 0.0) < 1e-10)
{
// the left edge
be->SetAttribute(1);
}
else
{
// all other boundaries
be->SetAttribute(2);
}
}
mesh.SetAttributes();
// 3. Refine the mesh.
for (int lev = 0; lev < ref_levels; lev++)
{
mesh.UniformRefinement();
}
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
// 4. Define the necessary finite element spaces on the mesh.
H1_FECollection state_fec(order, dim); // space for u
H1_FECollection filter_fec(order, dim); // space for ρ̃
L2_FECollection control_fec(order-1, dim,
BasisType::GaussLobatto); // space for ψ
ParFiniteElementSpace state_fes(&pmesh, &state_fec,dim);
ParFiniteElementSpace filter_fes(&pmesh, &filter_fec);
ParFiniteElementSpace control_fes(&pmesh, &control_fec);
HYPRE_BigInt state_size = state_fes.GlobalTrueVSize();
HYPRE_BigInt control_size = control_fes.GlobalTrueVSize();
HYPRE_BigInt filter_size = filter_fes.GlobalTrueVSize();
if (myid==0)
{
cout << "Number of state unknowns: " << state_size << endl;
cout << "Number of filter unknowns: " << filter_size << endl;
cout << "Number of control unknowns: " << control_size << endl;
}
// 5. Set the initial guess for ρ.
ParGridFunction u(&state_fes);
ParGridFunction psi(&control_fes);
ParGridFunction psi_old(&control_fes);
ParGridFunction rho_filter(&filter_fes);
u = 0.0;
rho_filter = vol_fraction;
psi = inv_sigmoid(vol_fraction);
psi_old = inv_sigmoid(vol_fraction);
// ρ = sigmoid(ψ)
MappedGridFunctionCoefficient rho(&psi, sigmoid);
// Interpolation of ρ = sigmoid(ψ) in control fes (for ParaView output)
ParGridFunction rho_gf(&control_fes);
// ρ - ρ_old = sigmoid(ψ) - sigmoid(ψ_old)
DiffMappedGridFunctionCoefficient succ_diff_rho(&psi, &psi_old, sigmoid);
// 6. Set-up the physics solver.
int maxat = pmesh.bdr_attributes.Max();
Array<int> ess_bdr(maxat);
ess_bdr = 0;
ess_bdr[0] = 1;
ConstantCoefficient one(1.0);
ConstantCoefficient lambda_cf(lambda);
ConstantCoefficient mu_cf(mu);
LinearElasticitySolver * ElasticitySolver = new LinearElasticitySolver();
ElasticitySolver->SetMesh(&pmesh);
ElasticitySolver->SetOrder(state_fec.GetOrder());
ElasticitySolver->SetupFEM();
Vector center(2); center(0) = 2.9; center(1) = 0.5;
Vector force(2); force(0) = 0.0; force(1) = -1.0;
double r = 0.05;
VolumeForceCoefficient vforce_cf(r,center,force);
ElasticitySolver->SetRHSCoefficient(&vforce_cf);
ElasticitySolver->SetEssentialBoundary(ess_bdr);
// 7. Set-up the filter solver.
ConstantCoefficient eps2_cf(epsilon*epsilon);
DiffusionSolver * FilterSolver = new DiffusionSolver();
FilterSolver->SetMesh(&pmesh);
FilterSolver->SetOrder(filter_fec.GetOrder());
FilterSolver->SetDiffusionCoefficient(&eps2_cf);
FilterSolver->SetMassCoefficient(&one);
Array<int> ess_bdr_filter;
if (pmesh.bdr_attributes.Size())
{
ess_bdr_filter.SetSize(pmesh.bdr_attributes.Max());
ess_bdr_filter = 0;
}
FilterSolver->SetEssentialBoundary(ess_bdr_filter);
FilterSolver->SetupFEM();
ParBilinearForm mass(&control_fes);
mass.AddDomainIntegrator(new InverseIntegrator(new MassIntegrator(one)));
mass.Assemble();
HypreParMatrix M;
Array<int> empty;
mass.FormSystemMatrix(empty,M);
// 8. Define the Lagrange multiplier and gradient functions.
ParGridFunction grad(&control_fes);
ParGridFunction w_filter(&filter_fes);
// 9. Define some tools for later.
ConstantCoefficient zero(0.0);
ParGridFunction onegf(&control_fes);
onegf = 1.0;
ParGridFunction zerogf(&control_fes);
zerogf = 0.0;
ParLinearForm vol_form(&control_fes);
vol_form.AddDomainIntegrator(new DomainLFIntegrator(one));
vol_form.Assemble();
double domain_volume = vol_form(onegf);
const double target_volume = domain_volume * vol_fraction;
// 10. Connect to GLVis. Prepare for VisIt output.
char vishost[] = "localhost";
int visport = 19916;
socketstream sout_r;
if (glvis_visualization)
{
sout_r.open(vishost, visport);
sout_r.precision(8);
}
mfem::ParaViewDataCollection paraview_dc("ex37p", &pmesh);
if (paraview_output)
{
rho_gf.ProjectCoefficient(rho);
paraview_dc.SetPrefixPath("ParaView");
paraview_dc.SetLevelsOfDetail(order);
paraview_dc.SetDataFormat(VTKFormat::BINARY);
paraview_dc.SetHighOrderOutput(true);
paraview_dc.SetCycle(0);
paraview_dc.SetTime(0.0);
paraview_dc.RegisterField("displacement",&u);
paraview_dc.RegisterField("density",&rho_gf);
paraview_dc.RegisterField("filtered_density",&rho_filter);
paraview_dc.Save();
}
// 11. Iterate:
for (int k = 1; k <= max_it; k++)
{
if (k > 1) { alpha *= ((double) k) / ((double) k-1); }
if (myid == 0)
{
cout << "\nStep = " << k << endl;
}
// Step 1 - Filter solve
// Solve (ϵ^2 ∇ ρ̃, ∇ v ) + (ρ̃,v) = (ρ,v)
FilterSolver->SetRHSCoefficient(&rho);
FilterSolver->Solve();
rho_filter = *FilterSolver->GetFEMSolution();
// Step 2 - State solve
// Solve (λ r(ρ̃) ∇⋅u, ∇⋅v) + (2 μ r(ρ̃) ε(u), ε(v)) = (f,v)
SIMPInterpolationCoefficient SIMP_cf(&rho_filter,rho_min, 1.0);
ProductCoefficient lambda_SIMP_cf(lambda_cf,SIMP_cf);
ProductCoefficient mu_SIMP_cf(mu_cf,SIMP_cf);
ElasticitySolver->SetLameCoefficients(&lambda_SIMP_cf,&mu_SIMP_cf);
ElasticitySolver->Solve();
u = *ElasticitySolver->GetFEMSolution();
// Step 3 - Adjoint filter solve
// Solve (ϵ² ∇ w̃, ∇ v) + (w̃ ,v) = (-r'(ρ̃) ( λ |∇⋅u|² + 2 μ |ε(u)|²),v)
StrainEnergyDensityCoefficient rhs_cf(&lambda_cf,&mu_cf,&u, &rho_filter,
rho_min);
FilterSolver->SetRHSCoefficient(&rhs_cf);
FilterSolver->Solve();
w_filter = *FilterSolver->GetFEMSolution();
// Step 4 - Compute gradient
// Solve G = M⁻¹w̃
GridFunctionCoefficient w_cf(&w_filter);
ParLinearForm w_rhs(&control_fes);
w_rhs.AddDomainIntegrator(new DomainLFIntegrator(w_cf));
w_rhs.Assemble();
M.Mult(w_rhs,grad);
// Step 5 - Update design variable ψ ← proj(ψ - αG)
psi.Add(-alpha, grad);
const double material_volume = proj(psi, target_volume);
// Compute ||ρ - ρ_old|| in control fes.
double norm_increment = zerogf.ComputeL1Error(succ_diff_rho);
double norm_reduced_gradient = norm_increment/alpha;
psi_old = psi;
double compliance = (*(ElasticitySolver->GetLinearForm()))(u);
MPI_Allreduce(MPI_IN_PLACE,&compliance,1,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
if (myid == 0)
{
mfem::out << "norm of the reduced gradient = " << norm_reduced_gradient << endl;
mfem::out << "norm of the increment = " << norm_increment << endl;
mfem::out << "compliance = " << compliance << endl;
mfem::out << "volume fraction = " << material_volume / domain_volume << endl;
}
if (glvis_visualization)
{
ParGridFunction r_gf(&filter_fes);
r_gf.ProjectCoefficient(SIMP_cf);
sout_r << "parallel " << num_procs << " " << myid << "\n";
sout_r << "solution\n" << pmesh << r_gf
<< "window_title 'Design density r(ρ̃)'" << flush;
}
if (paraview_output)
{
rho_gf.ProjectCoefficient(rho);
paraview_dc.SetCycle(k);
paraview_dc.SetTime((double)k);
paraview_dc.Save();
}
if (norm_reduced_gradient < ntol && norm_increment < itol)
{
break;
}
}
delete ElasticitySolver;
delete FilterSolver;
return 0;
}
+12 -4
View File
@@ -23,13 +23,14 @@ MFEM_LIB_FILE = mfem_is_not_built
SEQ_EXAMPLES = ex0 ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 \
ex17 ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex28 ex29 ex30 \
ex31 ex33
ex31 ex33 ex34 ex36 ex37
PAR_EXAMPLES = ex0p ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p \
ex12p ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p \
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p ex34p ex35p ex36p \
ex37p
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p \
ex24p ex25p ex26p
ex24p ex25p ex26p ex34p ex35p
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
@@ -92,10 +93,12 @@ $(SUBDIRS_TPRINT):
# Additional dependencies
ex18: $(SRC)ex18.hpp
ex33: $(SRC)ex33.hpp
ex37: $(SRC)ex37.hpp
ifeq ($(MFEM_USE_MPI),YES)
ex18p: $(SRC)ex18.hpp
ex33p: $(SRC)ex33.hpp
ex37p: $(SRC)ex37.hpp
endif
MFEM_TESTS = EXAMPLES
@@ -139,6 +142,10 @@ ex27-test-seq: ex27
@$(call mfem-test,$<,, Serial example,-dg)
ex27p-test-par: ex27p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-dg)
ex37-test-seq: ex37
@$(call mfem-test,$<,, Serial example,-mi 3)
ex37p-test-par: ex37p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-mi 3)
# Testing: optional tests
ifeq ($(MFEM_USE_STRUMPACK),YES)
ex11p-test-strumpack: ex11p
@@ -183,3 +190,4 @@ clean-exec:
@rm -f ex23.mesh ex23-*.gf
@rm -f ex25.mesh ex25-*.gf ex25p-*.*
@rm -rf ex28_* ex28p_*
@rm -rf cond.* cond_mesh.* cond_j.* dsol.* port_mesh.* port_mode.*
+40 -10
View File
@@ -24,13 +24,13 @@ if (MFEM_USE_MPI)
ex10p.cpp
)
list(APPEND PETSC_RC_FILES
rc_ex1p
rc_ex2p
rc_ex1p rc_ex1p_device rc_ex1p_deviceamg
rc_ex2p rc_ex2p_bddc rc_ex2p_asm
rc_ex3p rc_ex3p_bddc
rc_ex4p rc_ex4p_bddc
rc_ex5p_bddc rc_ex5p_fieldsplit
rc_ex9p_expl rc_ex9p_impl
rc_ex10p
rc_ex9p_expl rc_ex9p_expl_device rc_ex9p_impl
rc_ex10p rc_ex10p_mf rc_ex10p_mfop rc_ex10p_jfnk
)
endif()
@@ -39,7 +39,7 @@ if (MFEM_USE_SLEPC)
ex11p.cpp
)
list(APPEND PETSC_RC_FILES
rc_ex11p_lobpcg rc_ex11p_gd
rc_ex11p_lobpcg rc_ex11p_lobpcg_device rc_ex11p_gd
)
endif()
@@ -74,7 +74,13 @@ add_mfem_examples(PETSC_EXAMPLES_SRCS ${PFX} copy_petsc_rc_files test_petsc)
# Command line options for the tests.
set(EX1_ARGS_W -m ../../data/amr-quad.mesh --usepetsc)
set(EX1_ARGS_P -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p)
set(EX1_ARGS_CUDA -m ../../data/star.mesh --usepetsc --partial-assembly --device cuda --petscopts rc_ex1p_device)
set(EX1_ARGS_CUDAAMG -m ../../data/star.mesh --usepetsc --device cuda --petscopts rc_ex1p_deviceamg)
set(EX1_ARGS_HIP -m ../../data/star.mesh --usepetsc --partial-assembly --device hip --petscopts rc_ex1p_device)
set(EX1_ARGS_HIPAMG -m ../../data/star.mesh --usepetsc --device hip --petscopts rc_ex1p_deviceamg)
set(EX2_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p)
set(EX2_ARGS_BDDC -m ../../data/beam-tri.mesh --usepetsc --nonoverlapping --petscopts rc_ex2p_bddc)
set(EX2_ARGS_ASM -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p_asm)
set(EX3_ARGS -m ../../data/klein-bottle.mesh -o 2 -f 0.1 --usepetsc --petscopts rc_ex3p_bddc --nonoverlapping)
set(EX4_ARGS -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping)
set(EX4_HYB_ARGS -m ../../data/klein-bottle.mesh -o 2 --usepetsc --petscopts rc_ex4p_bddc --nonoverlapping --hybridization)
@@ -85,22 +91,46 @@ set(EX6_ARGS -m ../../data/amr-quad.mesh --usepetsc)
set(EX6_NONOVL_ARGS -m ../../data/amr-quad.mesh --usepetsc --nonoverlapping)
set(EX9_E_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl -dt 0.1)
set(EX9_ES_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step)
set(EX9_ES_ARGS_CUDA -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl_device --no-step --partial-assembly --device cuda)
set(EX9_ES_ARGS_HIP -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl_device --no-step --partial-assembly --device hip)
set(EX9_IS_ARGS -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5)
set(EX10_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3)
set(EX10_MF_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mf -tf 6 -s 3 -rs 0 -dt 3)
set(EX10_MFOP_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mfop -tf 6 -s 3 -rs 0 -dt 3)
set(EX10_JFNK_ARGS -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_jfnk --jfnk -tf 6 -s 3 -rs 0 -dt 3)
if (MFEM_USE_SLEPC)
set(EX11_ARGS_SINV -m ../../data/star.mesh --useslepc)
set(EX11_ARGS_LOBPCG -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg)
set(EX11_ARGS_LOBPCG_CUDA -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg_device --device cuda)
set(EX11_ARGS_LOBPCG_HIP -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg_device --device hip)
set(EX11_ARGS_GD -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_gd)
endif()
# Add the tests: one test per command-line-variable.
if (MFEM_ENABLE_TESTING)
set(TEST_OPTIONS_VARS
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX2_ARGS_BDDC EX2_ARGS_ASM EX3_ARGS
EX4_ARGS EX4_HYB_ARGS EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS
EX6_ARGS EX6_NONOVL_ARGS EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS
EX10_MF_ARGS EX10_MFOP_ARGS EX10_JFNK_ARGS)
if (MFEM_USE_SLEPC)
list(APPEND TEST_OPTIONS_VARS EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
list(APPEND TEST_OPTIONS_VARS
EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
endif()
# CUDA/HIP tests
if (MFEM_USE_CUDA)
list(APPEND TEST_OPTIONS_VARS
EX1_ARGS_CUDA EX1_ARGS_CUDAAMG EX9_ES_ARGS_CUDA)
if (MFEM_USE_SLEPC)
list(APPEND TEST_OPTIONS_VARS EX11_ARGS_LOBPCG_CUDA)
endif()
elseif (MFEM_USE_HIP)
list(APPEND TEST_OPTIONS_VARS
EX1_ARGS_HIP EX1_ARGS_HIPAMG EX9_ES_ARGS_HIP)
if (MFEM_USE_SLEPC)
# SLEPc does not support BVSVEC with HIP
# list(APPEND TEST_OPTIONS_VARS EX11_ARGS_LOBPCG_HIP)
endif()
endif()
foreach(TEST_OPTIONS_VAR ${TEST_OPTIONS_VARS})
@@ -115,7 +145,7 @@ if (MFEM_ENABLE_TESTING)
# All PETSC tests are parallel.
if (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME_FULL}_np=4
add_test(NAME ${TEST_NAME_FULL}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${TEST_OPTIONS}
+1 -1
View File
@@ -7,7 +7,7 @@
// mpirun -np 4 ex1p -m ../../data/amr-quad.mesh --petscopts rc_ex1p
//
// Device sample runs:
// mpirun -np 4 ex1p -pa -d cuda --petscopts rc_ex1p_cuda
// mpirun -np 4 ex1p -pa -d cuda --petscopts rc_ex1p_device
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
+29 -9
View File
@@ -66,7 +66,9 @@ include $(MFEM_TEST_MK)
# Testing: Parallel runs
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
TESTNAME = Parallel PETSc example
TESTNAME = Parallel PETSc example
TESTNAME_CUDA = Parallel CUDA PETSc example
TESTNAME_HIP = Parallel HIP PETSc example
%-test-par: %
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME))
@@ -74,8 +76,10 @@ TESTNAME = Parallel PETSc example
# Testing PETSc execution options.
EX1_ARGS_W := -m ../../data/amr-quad.mesh --usepetsc
EX1_ARGS_P := -m ../../data/amr-quad.mesh --usepetsc --petscopts rc_ex1p
EX1_ARGS_CUDA := -m ../../data/star.mesh --usepetsc --partial-assembly --device cuda --petscopts rc_ex1p_cuda
EX1_ARGS_CUDAAMG := -m ../../data/star.mesh --usepetsc --device cuda --petscopts rc_ex1p_cudaamg
EX1_ARGS_CUDA := -m ../../data/star.mesh --usepetsc --partial-assembly --device cuda --petscopts rc_ex1p_device
EX1_ARGS_CUDAAMG := -m ../../data/star.mesh --usepetsc --device cuda --petscopts rc_ex1p_deviceamg
EX1_ARGS_HIP := -m ../../data/star.mesh --usepetsc --partial-assembly --device hip --petscopts rc_ex1p_device
EX1_ARGS_HIPAMG := -m ../../data/star.mesh --usepetsc --device hip --petscopts rc_ex1p_deviceamg
EX2_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p
EX2_ARGS_BDDC := -m ../../data/beam-tri.mesh --usepetsc --nonoverlapping --petscopts rc_ex2p_bddc
EX2_ARGS_ASM := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex2p_asm
@@ -89,7 +93,8 @@ EX6_ARGS := -m ../../data/amr-quad.mesh --usepetsc
EX6_NONOVL_ARGS := -m ../../data/amr-quad.mesh --usepetsc --nonoverlapping
EX9_E_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl -dt 0.1
EX9_ES_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl --no-step
EX9_ES_ARGS_CUDA := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl_cuda --no-step --partial-assembly --device cuda
EX9_ES_ARGS_CUDA := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl_device --no-step --partial-assembly --device cuda
EX9_ES_ARGS_HIP := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_expl_device --no-step --partial-assembly --device hip
EX9_IS_ARGS := -m ../../data/periodic-hexagon.mesh --usepetsc --petscopts rc_ex9p_impl --implicit -tf 0.5
EX10_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p -tf 30 -s 3 -rs 2 -dt 3
EX10_MF_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_mf -tf 6 -s 3 -rs 0 -dt 3
@@ -97,15 +102,20 @@ EX10_MFOP_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_
EX10_JFNK_ARGS := -m ../../data/beam-quad.mesh --usepetsc --petscopts rc_ex10p_jfnk --jfnk -tf 6 -s 3 -rs 0 -dt 3
EX11_ARGS_SINV := -m ../../data/star.mesh --useslepc
EX11_ARGS_LOBPCG := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg
EX11_ARGS_LOBPCG_CUDA := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg_cuda --device cuda
EX11_ARGS_LOBPCG_CUDA := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg_device --device cuda
EX11_ARGS_LOBPCG_HIP := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_lobpcg_device --device hip
EX11_ARGS_GD := -m ../../data/star.mesh --useslepc --slepcopts rc_ex11p_gd
ex1p-test-par: ex1p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_W))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_P))
ifeq ($(MFEM_USE_CUDA),YES)
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_CUDA))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX1_ARGS_CUDAAMG))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_CUDA),$(EX1_ARGS_CUDA))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_CUDA),$(EX1_ARGS_CUDAAMG))
endif
ifeq ($(MFEM_USE_HIP),YES)
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_HIP),$(EX1_ARGS_HIP))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_HIP),$(EX1_ARGS_HIPAMG))
endif
ex2p-test-par: ex2p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX2_ARGS))
@@ -128,7 +138,10 @@ ex9p-test-par: ex9p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX9_ES_ARGS))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX9_IS_ARGS))
ifeq ($(MFEM_USE_CUDA),YES)
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX9_ES_ARGS_CUDA))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_CUDA),$(EX9_ES_ARGS_CUDA))
endif
ifeq ($(MFEM_USE_HIP),YES)
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_HIP),$(EX9_ES_ARGS_HIP))
endif
ex10p-test-par: ex10p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX10_ARGS))
@@ -140,8 +153,12 @@ ex11p-test-par: ex11p
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_SINV))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_LOBPCG))
ifeq ($(MFEM_USE_CUDA),YES)
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_LOBPCG_CUDA))
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_CUDA),$(EX11_ARGS_LOBPCG_CUDA))
endif
# SLEPc does not support BVSVEC with HIP
#ifeq ($(MFEM_USE_HIP),YES)
# @$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME_HIP),$(EX11_ARGS_LOBPCG_HIP))
#endif
@$(call mfem-test,$<, $(RUN_MPI), $(TESTNAME),$(EX11_ARGS_GD))
endif
@@ -156,6 +173,9 @@ clean: clean-build clean-exec
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
rm -rf *.dSYM *.TVD.*breakpoints
ifneq ($(SRC),)
rm -f $(RC_FILES)
endif
clean-exec:
@rm -rf mesh.* sol.* sol_p.* sol_u.* Example5*
+3
View File
@@ -23,6 +23,7 @@ set(SRCS
integ/bilininteg_diffusion_mf.cpp
integ/bilininteg_diffusion_pa.cpp
integ/bilininteg_diffusion_ea.cpp
integ/bilininteg_diffusion_patch.cpp
integ/bilininteg_divdiv_pa.cpp
integ/bilininteg_gradient_pa.cpp
integ/bilininteg_interp_pa.cpp
@@ -87,6 +88,7 @@ set(SRCS
ceed/solvers/algebraic.cpp
ceed/solvers/full-assembly.cpp
ceed/solvers/solvers-atpmg.cpp
kdtree.cpp
linearform.cpp
linearform_ext.cpp
lininteg.cpp
@@ -198,6 +200,7 @@ set(HDRS
ceed/solvers/algebraic.hpp
ceed/solvers/full-assembly.hpp
ceed/solvers/solvers-atpmg.hpp
kdtree.hpp
linearform.hpp
linearform_ext.hpp
lininteg.hpp
+48 -2
View File
@@ -13,6 +13,7 @@
#include "fem.hpp"
#include "../general/device.hpp"
#include "../mesh/nurbs.hpp"
#include <cmath>
namespace mfem
@@ -421,11 +422,17 @@ void BilinearForm::Assemble(int skip_zeros)
"invalid element marker for domain integrator #"
<< k << ", counting from zero");
}
if (domain_integs[k]->Patchwise())
{
MFEM_VERIFY(fes->GetNURBSext(), "Patchwise integration requires a "
<< "NURBS FE space");
}
}
// Element-wise integration
for (int i = 0; i < fes -> GetNE(); i++)
{
int elem_attr = fes->GetMesh()->GetAttribute(i);
doftrans = fes->GetElementVDofs(i, vdofs);
if (element_matrices)
{
@@ -433,11 +440,13 @@ void BilinearForm::Assemble(int skip_zeros)
}
else
{
const int elem_attr = fes->GetMesh()->GetAttribute(i);
elmat.SetSize(0);
for (int k = 0; k < domain_integs.Size(); k++)
{
if ( domain_integs_marker[k] == NULL ||
if ((domain_integs_marker[k] == NULL ||
(*(domain_integs_marker[k]))[elem_attr-1] == 1)
&& !domain_integs[k]->Patchwise())
{
const FiniteElement &fe = *fes->GetFE(i);
eltrans = fes->GetElementTransformation(i);
@@ -479,6 +488,43 @@ void BilinearForm::Assemble(int skip_zeros)
}
}
}
// Patch-wise integration
if (fes->GetNURBSext())
{
for (int p=0; p<mesh->NURBSext->GetNP(); ++p)
{
bool vdofsSet = false;
for (int k = 0; k < domain_integs.Size(); k++)
{
if (domain_integs[k]->Patchwise())
{
if (!vdofsSet)
{
fes->GetPatchVDofs(p, vdofs);
vdofsSet = true;
}
SparseMatrix* spmat = nullptr;
domain_integs[k]->AssemblePatchMatrix(p, *fes, spmat);
Array<int> cols;
Vector srow;
for (int r=0; r<spmat->Height(); ++r)
{
spmat->GetRow(r, cols, srow);
for (int i=0; i<cols.Size(); ++i)
{
cols[i] = vdofs[cols[i]];
}
mat->AddRow(vdofs[r], cols, srow);
}
delete spmat;
}
}
}
}
}
if (boundary_integs.Size())
+7 -1
View File
@@ -254,6 +254,12 @@ public:
/// Access all the integrators added with AddDomainIntegrator().
Array<BilinearFormIntegrator*> *GetDBFI() { return &domain_integs; }
/// @brief Access all boundary markers added with AddDomainIntegrator().
///
/// If no marker was specified when the integrator was added, the
/// corresponding pointer (to Array<int>) will be NULL. */
Array<Array<int>*> *GetDBFI_Marker() { return &domain_integs_marker; }
/// Access all the integrators added with AddBoundaryIntegrator().
Array<BilinearFormIntegrator*> *GetBBFI() { return &boundary_integs; }
/** @brief Access all boundary markers added with AddBoundaryIntegrator().
@@ -452,7 +458,7 @@ public:
practice it is convenient to have it in transposed form for
construction of RAP operators in matrix-free methods. */
virtual const Operator *GetOutputRestrictionTranspose() const
{ return GetOutputProlongation(); }
{ return fes->GetRestrictionTransposeOperator(); }
/// Get the output finite element space restriction matrix
virtual const Operator *GetOutputRestriction() const
{ return GetRestriction(); }
+166 -13
View File
@@ -264,6 +264,14 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
localX.SetSize(elem_restrict->Height(), Device::GetDeviceMemoryType());
localY.SetSize(elem_restrict->Height(), Device::GetDeviceMemoryType());
localY.UseDevice(true); // ensure 'localY = 0.0' is done on device
// Gather the attributes on the host from all the elements
const Mesh &mesh = *trial_fes->GetMesh();
elem_attributes.SetSize(mesh.GetNE());
for (int i = 0; i < mesh.GetNE(); ++i)
{
elem_attributes[i] = mesh.GetAttribute(i);
}
}
// Construct face restriction operators only if the bilinear form has
@@ -289,6 +297,46 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
bdr_face_X.SetSize(bdr_face_restrict_lex->Height(), Device::GetMemoryType());
bdr_face_Y.SetSize(bdr_face_restrict_lex->Height(), Device::GetMemoryType());
bdr_face_Y.UseDevice(true); // ensure 'faceBoundY = 0.0' is done on device
const Mesh &mesh = *trial_fes->GetMesh();
// See LinearFormExtension::Update for explanation of f_to_be logic.
std::unordered_map<int,int> f_to_be;
for (int i = 0; i < mesh.GetNBE(); ++i)
{
const int f = mesh.GetBdrElementEdgeIndex(i);
f_to_be[f] = i;
}
const int nf_bdr = trial_fes->GetNFbyType(FaceType::Boundary);
bdr_attributes.SetSize(nf_bdr);
int f_ind = 0;
int missing_bdr_elems = 0;
for (int f = 0; f < mesh.GetNumFaces(); ++f)
{
if (!mesh.GetFaceInformation(f).IsOfFaceType(FaceType::Boundary))
{
continue;
}
int attribute = 1; // default value
if (f_to_be.find(f) != f_to_be.end())
{
const int be = f_to_be[f];
attribute = mesh.GetBdrAttribute(be);
}
else
{
// If a boundary face does not correspond to the a boundary element,
// we assign it the default attribute of 1. We also generate a
// warning at runtime with the number of such missing elements.
++missing_bdr_elems;
}
bdr_attributes[f_ind] = attribute;
++f_ind;
}
if (missing_bdr_elems)
{
MFEM_WARNING("Missing " << missing_bdr_elems << " boundary elements "
"for boundary faces.");
}
}
}
@@ -299,7 +347,16 @@ void PABilinearFormExtension::Assemble()
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
for (BilinearFormIntegrator *integ : integrators)
{
integ->AssemblePA(*a->FESpace());
if (integ->Patchwise())
{
MFEM_VERIFY(a->FESpace()->GetNURBSext(),
"Patchwise integration requires a NURBS FE space");
integ->AssembleNURBSPA(*a->FESpace());
}
else
{
integ->AssemblePA(*a->FESpace());
}
}
Array<BilinearFormIntegrator*> &bdr_integrators = *a->GetBBFI();
@@ -410,24 +467,52 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int iSz = integrators.Size();
if (DeviceCanUseCeed() || !elem_restrict)
bool allPatchwise = true;
bool somePatchwise = false;
for (int i = 0; i < iSz; ++i)
{
if (integrators[i]->Patchwise())
{
somePatchwise = true;
}
else
{
allPatchwise = false;
}
}
MFEM_VERIFY(!(somePatchwise && !allPatchwise),
"All or none of the integrators should be patchwise");
if (DeviceCanUseCeed() || !elem_restrict || allPatchwise)
{
y.UseDevice(true); // typically this is a large vector, so store on device
y = 0.0;
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AddMultPA(x, y);
if (integrators[i]->Patchwise())
{
integrators[i]->AddMultNURBSPA(x, y);
}
else
{
integrators[i]->AddMultPA(x, y);
}
}
}
else
{
if (iSz)
{
Array<Array<int>*> &elem_markers = *a->GetDBFI_Marker();
elem_restrict->Mult(x, localX);
localY = 0.0;
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AddMultPA(localX, localY);
AddMultWithMarkers(*integrators[i], localX, elem_markers[i], elem_attributes,
false, localY);
}
elem_restrict->MultTranspose(localY, y);
}
@@ -460,17 +545,21 @@ void PABilinearFormExtension::Mult(const Vector &x, Vector &y) const
const bool has_bdr_integs = (n_bdr_face_integs > 0 || n_bdr_integs > 0);
if (bdr_face_restrict_lex && has_bdr_integs)
{
Array<Array<int>*> &bdr_markers = *a->GetBBFI_Marker();
Array<Array<int>*> &bdr_face_markers = *a->GetBFBFI_Marker();
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 < n_bdr_integs; ++i)
{
bdr_integs[i]->AddMultPA(bdr_face_X, bdr_face_Y);
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i], bdr_attributes,
false, bdr_face_Y);
}
for (int i = 0; i < n_bdr_face_integs; ++i)
{
bdr_face_integs[i]->AddMultPA(bdr_face_X, bdr_face_Y);
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X, bdr_face_markers[i],
bdr_attributes, false, bdr_face_Y);
}
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
}
@@ -483,11 +572,13 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
const int iSz = integrators.Size();
if (elem_restrict)
{
Array<Array<int>*> &elem_markers = *a->GetDBFI_Marker();
elem_restrict->Mult(x, localX);
localY = 0.0;
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AddMultTransposePA(localX, localY);
AddMultWithMarkers(*integrators[i], localX, elem_markers[i], elem_attributes,
true, localY);
}
elem_restrict->MultTranspose(localY, y);
}
@@ -517,23 +608,85 @@ void PABilinearFormExtension::MultTranspose(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)
{
Array<Array<int>*> &bdr_markers = *a->GetBBFI_Marker();
Array<Array<int>*> &bdr_face_markers = *a->GetBFBFI_Marker();
bdr_face_restrict_lex->Mult(x, bdr_face_X);
if (bdr_face_X.Size()>0)
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]->AddMultTransposePA(bdr_face_X, bdr_face_Y);
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i], bdr_attributes,
true, bdr_face_Y);
}
for (int i = 0; i < n_bdr_face_integs; ++i)
{
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X, bdr_face_markers[i],
bdr_attributes, true, bdr_face_Y);
}
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
}
}
}
// Compute kernels for PABilinearFormExtension::AddMultWithMarkers.
// Cannot be in member function with non-public visibility.
static void AddWithMarkers_(
const int ne,
const int nd,
const Vector &x,
const Array<int> &markers,
const Array<int> &attributes,
Vector &y)
{
const auto d_x = Reshape(x.Read(), nd, ne);
const auto d_m = Reshape(markers.Read(), markers.Size());
const auto d_attr = Reshape(attributes.Read(), ne);
auto d_y = Reshape(y.ReadWrite(), nd, ne);
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
{
const int attr = d_attr[e];
if (d_m[attr - 1] == 0) { return; }
for (int i = 0; i < nd; ++i)
{
d_y(i, e) += d_x(i, e);
}
});
}
void PABilinearFormExtension::AddMultWithMarkers(
const BilinearFormIntegrator &integ,
const Vector &x,
const Array<int> *markers,
const Array<int> &attributes,
const bool transpose,
Vector &y) const
{
if (markers)
{
tmp_evec.SetSize(y.Size());
tmp_evec = 0.0;
if (transpose) { integ.AddMultTransposePA(x, tmp_evec); }
else { integ.AddMultPA(x, tmp_evec); }
const int ne = attributes.Size();
const int nd = x.Size() / ne;
AddWithMarkers_(ne, nd, tmp_evec, *markers, attributes, y);
}
else
{
if (transpose) { integ.AddMultTransposePA(x, y); }
else { integ.AddMultPA(x, y); }
}
}
// Data and methods for element-assembled bilinear forms
EABilinearFormExtension::EABilinearFormExtension(BilinearForm *form)
: PABilinearFormExtension(form),
+22
View File
@@ -68,6 +68,9 @@ class PABilinearFormExtension : public BilinearFormExtension
{
protected:
const FiniteElementSpace *trial_fes, *test_fes; // Not owned
/// Attributes of all mesh elements.
Array<int> elem_attributes, bdr_attributes;
mutable Vector tmp_evec; // Work array
mutable Vector localX, localY;
mutable Vector int_face_X, int_face_Y;
mutable Vector bdr_face_X, bdr_face_Y;
@@ -91,6 +94,25 @@ public:
protected:
void SetupRestrictionOperators(const L2FaceValues m);
/// @brief Accumulate the action (or transpose) of the integrator on @a x
/// into @a y, taking into account the (possibly null) @a markers array.
///
/// If @a markers is non-null, then only those elements or boundary elements
/// whose attribute is marked in the markers array will be added to @a y.
///
/// @param integ The integrator (domain, boundary, or boundary face).
/// @param x Input E-vector.
/// @param markers Marked attributes (possibly null, meaning all attributes).
/// @param attributes Array of element or boundary element attributes.
/// @param transpose Compute the action or transpose of the integrator .
/// @param y Output E-vector
void AddMultWithMarkers(const BilinearFormIntegrator &integ,
const Vector &x,
const Array<int> *markers,
const Array<int> &attributes,
const bool transpose,
Vector &y) const;
};
/// Data and methods for element-assembled bilinear forms
+47 -10
View File
@@ -26,6 +26,12 @@ void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&)
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleNURBSPA(const FiniteElementSpace&)
{
mfem_error ("BilinearFormIntegrator::AssembleNURBSPA(fes)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&,
const FiniteElementSpace&)
{
@@ -92,7 +98,13 @@ void BilinearFormIntegrator::AssembleDiagonalPA_ADAt(const Vector &, Vector &)
void BilinearFormIntegrator::AddMultPA(const Vector &, Vector &) const
{
MFEM_ABORT("BilinearFormIntegrator::MultAssembled(...)\n"
MFEM_ABORT("BilinearFormIntegrator:AddMultPA:(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AddMultNURBSPA(const Vector &, Vector &) const
{
MFEM_ABORT("BilinearFormIntegrator::AddMultNURBSPA(...)\n"
" is not implemented for this class.");
}
@@ -126,23 +138,30 @@ void BilinearFormIntegrator::AssembleDiagonalMF(Vector &)
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleElementMatrix (
void BilinearFormIntegrator::AssembleElementMatrix(
const FiniteElement &el, ElementTransformation &Trans,
DenseMatrix &elmat )
DenseMatrix &elmat)
{
MFEM_ABORT("BilinearFormIntegrator::AssembleElementMatrix(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleElementMatrix2 (
void BilinearFormIntegrator::AssembleElementMatrix2(
const FiniteElement &el1, const FiniteElement &el2,
ElementTransformation &Trans, DenseMatrix &elmat )
ElementTransformation &Trans, DenseMatrix &elmat)
{
MFEM_ABORT("BilinearFormIntegrator::AssembleElementMatrix2(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleFaceMatrix (
void BilinearFormIntegrator::AssemblePatchMatrix(
const int patch, const FiniteElementSpace &fes, SparseMatrix*& smat)
{
mfem_error ("BilinearFormIntegrator::AssemblePatchMatrix(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleFaceMatrix(
const FiniteElement &el1, const FiniteElement &el2,
FaceElementTransformations &Trans, DenseMatrix &elmat)
{
@@ -848,6 +867,19 @@ void DiffusionIntegrator::AssembleElementMatrix
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
const NURBSFiniteElement *NURBSFE =
dynamic_cast<const NURBSFiniteElement *>(&el);
bool deleteRule = false;
if (NURBSFE && patchRules)
{
const int patch = NURBSFE->GetPatch();
const int* ijk = NURBSFE->GetIJK();
Array<const KnotVector*>& kv = NURBSFE->KnotVectors();
ir = &patchRules->GetElementRule(NURBSFE->GetElement(), patch, ijk, kv,
deleteRule);
}
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
@@ -882,6 +914,11 @@ void DiffusionIntegrator::AssembleElementMatrix
AddMult_a_AAt(w, dshapedxt, elmat);
}
}
if (deleteRule)
{
delete ir;
}
}
void DiffusionIntegrator::AssembleElementMatrix2(
@@ -2419,7 +2456,7 @@ void VectorFEMassIntegrator::AssembleElementMatrix(
{
int dof = el.GetDof();
int spaceDim = Trans.GetSpaceDim();
int vdim = std::max(spaceDim, el.GetVDim());
int vdim = std::max(spaceDim, el.GetRangeDim());
double w;
@@ -2487,7 +2524,7 @@ void VectorFEMassIntegrator::AssembleElementMatrix2(
{
// assume test_fe is scalar FE and trial_fe is vector FE
int spaceDim = Trans.GetSpaceDim();
int vdim = std::max(spaceDim, trial_fe.GetVDim());
int vdim = std::max(spaceDim, trial_fe.GetRangeDim());
int trial_dof = trial_fe.GetDof();
int test_dof = test_fe.GetDof();
double w;
@@ -2585,8 +2622,8 @@ void VectorFEMassIntegrator::AssembleElementMatrix2(
{
// assume both test_fe and trial_fe are vector FE
int spaceDim = Trans.GetSpaceDim();
int trial_vdim = std::max(spaceDim, trial_fe.GetVDim());
int test_vdim = std::max(spaceDim, test_fe.GetVDim());
int trial_vdim = std::max(spaceDim, trial_fe.GetRangeDim());
int test_vdim = std::max(spaceDim, test_fe.GetRangeDim());
int trial_dof = trial_fe.GetDof();
int test_dof = test_fe.GetDof();
double w;
+92 -23
View File
@@ -20,17 +20,6 @@
namespace mfem
{
// Local maximum size of dofs and quads in 1D
constexpr int HCURL_MAX_D1D = 5;
#ifdef MFEM_USE_HIP
constexpr int HCURL_MAX_Q1D = 5;
#else
constexpr int HCURL_MAX_Q1D = 6;
#endif
constexpr int HDIV_MAX_D1D = 5;
constexpr int HDIV_MAX_Q1D = 6;
/// Abstract base class BilinearFormIntegrator
class BilinearFormIntegrator : public NonlinearFormIntegrator
{
@@ -61,6 +50,11 @@ public:
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes);
/// Method defining partial assembly on NURBS patches.
/** The result of the partial assembly is stored internally so that it can be
used later in the method AddMultNURBSPA(). */
virtual void AssembleNURBSPA(const FiniteElementSpace &fes);
virtual void AssemblePABoundary(const FiniteElementSpace &fes);
virtual void AssemblePAInteriorFaces(const FiniteElementSpace &fes);
@@ -82,6 +76,9 @@ public:
called. */
virtual void AddMultPA(const Vector &x, Vector &y) const;
/// Method for partially assembled action on NURBS patches.
virtual void AddMultNURBSPA(const Vector&x, Vector&y) const;
/// Method for partially assembled transposed action.
/** Perform the transpose action of integrator on the input @a x and add the
result to the output @a y. Both @a x and @a y are E-vectors, i.e. they
@@ -148,6 +145,13 @@ public:
ElementTransformation &Trans,
DenseMatrix &elmat);
/** Given a particular NURBS patch, computes the patch matrix as a
SparseMatrix @a smat.
*/
virtual void AssemblePatchMatrix(const int patch,
const FiniteElementSpace &fes,
SparseMatrix*& smat);
virtual void AssembleFaceMatrix(const FiniteElement &el1,
const FiniteElement &el2,
FaceElementTransformations &Trans,
@@ -576,7 +580,7 @@ protected:
inline virtual int GetTestVDim(const FiniteElement & test_fe)
{ return std::max(space_dim, test_fe.GetVDim()); }
{ return std::max(space_dim, test_fe.GetRangeDim()); }
inline virtual void CalcTestShape(const FiniteElement & test_fe,
ElementTransformation &Trans,
@@ -584,7 +588,7 @@ protected:
{ test_fe.CalcVShape(Trans, shape); }
inline virtual int GetTrialVDim(const FiniteElement & trial_fe)
{ return std::max(space_dim, trial_fe.GetVDim()); }
{ return std::max(space_dim, trial_fe.GetRangeDim()); }
inline virtual void CalcTrialShape(const FiniteElement & trial_fe,
ElementTransformation &Trans,
@@ -674,7 +678,7 @@ protected:
inline virtual int GetVDim(const FiniteElement & vector_fe)
{ return std::max(space_dim, vector_fe.GetVDim()); }
{ return std::max(space_dim, vector_fe.GetRangeDim()); }
inline virtual void CalcVShape(const FiniteElement & vector_fe,
ElementTransformation &Trans,
@@ -1101,7 +1105,7 @@ public:
const FiniteElement & trial_fe,
const FiniteElement & test_fe) const
{
return (trial_fe.GetVDim() == 3 &&
return (trial_fe.GetRangeDim() == 3 &&
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
test_fe.GetDerivType() == mfem::FiniteElement::GRAD );
@@ -1284,8 +1288,8 @@ public:
const FiniteElement & trial_fe,
const FiniteElement & test_fe) const
{
return (trial_fe.GetCurlDim() == 3 && trial_fe.GetVDim() == 3 &&
test_fe.GetCurlDim() == 3 && test_fe.GetVDim() == 3 &&
return (trial_fe.GetCurlDim() == 3 && trial_fe.GetRangeDim() == 3 &&
test_fe.GetCurlDim() == 3 && test_fe.GetRangeDim() == 3 &&
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
@@ -1415,7 +1419,7 @@ public:
const FiniteElement & trial_fe,
const FiniteElement & test_fe) const
{
return (trial_fe.GetVDim() == 3 && test_fe.GetCurlDim() == 3 &&
return (trial_fe.GetRangeDim() == 3 && test_fe.GetCurlDim() == 3 &&
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
test_fe.GetDerivType() == mfem::FiniteElement::CURL );
@@ -1485,7 +1489,7 @@ public:
const FiniteElement & trial_fe,
const FiniteElement & test_fe) const
{
return (test_fe.GetVDim() == 3 &&
return (test_fe.GetRangeDim() == 3 &&
trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
@@ -1525,7 +1529,7 @@ public:
const FiniteElement & trial_fe,
const FiniteElement & test_fe) const
{
return (trial_fe.GetCurlDim() == 3 && test_fe.GetVDim() == 3 &&
return (trial_fe.GetCurlDim() == 3 && test_fe.GetRangeDim() == 3 &&
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
@@ -1896,7 +1900,7 @@ protected:
const FiniteElement & trial_fe,
const FiniteElement & test_fe) const
{
return (trial_fe.GetCurlDim() == 3 && test_fe.GetVDim() == 3 &&
return (trial_fe.GetCurlDim() == 3 && test_fe.GetRangeDim() == 3 &&
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
}
@@ -1955,7 +1959,7 @@ protected:
const FiniteElement & trial_fe,
const FiniteElement & test_fe) const
{
return (trial_fe.GetVDim() == 3 && test_fe.GetCurlDim() == 3 &&
return (trial_fe.GetRangeDim() == 3 && test_fe.GetCurlDim() == 3 &&
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
test_fe.GetDerivType() == mfem::FiniteElement::CURL );
}
@@ -2111,6 +2115,59 @@ private:
Vector pa_data;
bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient
// Data for NURBS patch PA
// Type for a variable-row-length 2D array, used for data related to 1D
// quadrature rules in each dimension.
typedef std::vector<std::vector<int>> IntArrayVar2D;
int numPatches = 0;
static constexpr int numTypes = 2; // Number of rule types
// In the case integrationMode == Mode::PATCHWISE_REDUCED, an approximate
// integration rule with sparse nonzero weights is computed by NNLSSolver,
// for each 1D basis function on each patch, in each spatial dimension. For a
// fixed 1D basis function b_i with DOF index i, in the tensor product basis
// of patch p, the prescribed exact 1D rule is of the form
// \sum_k a_{i,j,k} w_k for some integration points indexed by k, with
// weights w_k and coefficients a_{i,j,k} depending on Q(x), an element
// transformation, b_i, and b_j, for all 1D basis functions b_j whose support
// overlaps that of b_i. Define the constraint matrix G = [g_{j,k}] with
// g_{j,k} = a_{i,j,k} and the vector of exact weights w = [w_k]. A reduced
// rule should have different weights w_r, many of them zero, and should
// approximately satisfy Gw_r = Gw. A sparse approximate solution to this
// underdetermined system is computed by NNLSSolver, and its data is stored
// in the following members.
// For each patch p, spatial dimension d (total dim), and rule type t (total
// numTypes), an std::vector<Vector> of reduced quadrature weights for all
// basis functions is stored in reducedWeights[t + numTypes * (d + dim * p)],
// reshaped as rw(t,d,p). Note that nd may vary with respect to the patch and
// spatial dimension. Array reducedIDs is treated similarly.
std::vector<std::vector<Vector>> reducedWeights;
std::vector<IntArrayVar2D> reducedIDs;
std::vector<Array<int>> pQ1D, pD1D;
std::vector<std::vector<Array2D<double>>> pB, pG;
std::vector<IntArrayVar2D> pminD, pmaxD, pminQ, pmaxQ, pminDD, pmaxDD;
std::vector<Array<const IntegrationRule*>> pir1d;
void SetupPatchPA(const int patch, Mesh *mesh, bool unitWeights=false);
void SetupPatchBasisData(Mesh *mesh, unsigned int patch);
/** Called by AssemblePatchMatrix for sparse matrix assembly on a NURBS patch
with full 1D quadrature rules. */
void AssemblePatchMatrix_fullQuadrature(const int patch,
const FiniteElementSpace &fes,
SparseMatrix*& smat);
/** Called by AssemblePatchMatrix for sparse matrix assembly on a NURBS patch
with reduced 1D quadrature rules. */
void AssemblePatchMatrix_reducedQuadrature(const int patch,
const FiniteElementSpace &fes,
SparseMatrix*& smat);
public:
/// Construct a diffusion integrator with coefficient Q = 1
DiffusionIntegrator(const IntegrationRule *ir = nullptr)
@@ -2146,6 +2203,14 @@ public:
ElementTransformation &Trans,
DenseMatrix &elmat);
virtual void AssemblePatchMatrix(const int patch,
const FiniteElementSpace &fes,
SparseMatrix*& smat);
virtual void AssembleNURBSPA(const FiniteElementSpace &fes);
void AssemblePatchPA(const int patch, const FiniteElementSpace &fes);
/// Perform the local action of the BilinearFormIntegrator
virtual void AssembleElementVector(const FiniteElement &el,
ElementTransformation &Tr,
@@ -2180,6 +2245,10 @@ public:
virtual void AddMultTransposePA(const Vector&, Vector&) const;
virtual void AddMultNURBSPA(const Vector&, Vector&) const;
void AddMultPatchPA(const int patch, const Vector &x, Vector &y) const;
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe);
@@ -3371,7 +3440,7 @@ private:
void cross_product(const Vector & x, const DenseMatrix & Y, DenseMatrix & Z)
{
int dim = x.Size();
MFEM_VERIFY(Y.Width() == dim, "Size missmatch");
MFEM_VERIFY(Y.Width() == dim, "Size mismatch");
int dimc = dim == 3 ? dim : 1;
int h = Y.Height();
Z.SetSize(h,dimc);
+27 -12
View File
@@ -13,13 +13,13 @@
#define MFEM_LIBCEED_UTIL
#include "../../../config/config.hpp"
#include <functional>
#include <string>
#include <tuple>
#include <unordered_map>
#include <string>
#include "ceed.hpp"
#ifdef MFEM_USE_CEED
#include <ceed/hash.h>
#include <ceed/backend.h> // for CeedOperatorField
#endif
@@ -105,6 +105,21 @@ const IntegrationRule & GetRule(
/// Return the path to the libCEED q-function headers.
const std::string &GetCeedPath();
/// Wrapper for std::hash.
template <typename T>
inline std::size_t CeedHash(const T key)
{
return std::hash<T> {}(key);
}
/// Effective way to combine hashes (from libCEED).
inline std::size_t CeedHashCombine(std::size_t seed, std::size_t hash)
{
// See https://doi.org/10.1002/asi.10170, or
// https://dl.acm.org/citation.cfm?id=759509.
return seed ^ (hash + (seed << 6) + (seed >> 2));
}
// Hash table for CeedBasis
using BasisKey = std::tuple<const mfem::FiniteElementSpace*,
const mfem::IntegrationRule*,
@@ -115,12 +130,12 @@ struct BasisHash
{
return CeedHashCombine(
CeedHashCombine(
CeedHashInt(reinterpret_cast<CeedHash64_t>(std::get<0>(k))),
CeedHashInt(reinterpret_cast<CeedHash64_t>(std::get<1>(k)))),
CeedHash(std::get<0>(k)),
CeedHash(std::get<1>(k))),
CeedHashCombine(
CeedHashCombine(CeedHashInt(std::get<2>(k)),
CeedHashInt(std::get<3>(k))),
CeedHashInt(std::get<4>(k))));
CeedHashCombine(CeedHash(std::get<2>(k)),
CeedHash(std::get<3>(k))),
CeedHash(std::get<4>(k))));
}
};
using BasisMap = std::unordered_map<const BasisKey, CeedBasis, BasisHash>;
@@ -137,11 +152,11 @@ struct RestrHash
return CeedHashCombine(
CeedHashCombine(
CeedHashCombine(
CeedHashInt(reinterpret_cast<CeedHash64_t>(std::get<0>(k))),
CeedHashInt(std::get<1>(k))),
CeedHashCombine(CeedHashInt(std::get<2>(k)),
CeedHashInt(std::get<3>(k)))),
CeedHashInt(std::get<4>(k)));
CeedHash(std::get<0>(k)),
CeedHash(std::get<1>(k))),
CeedHashCombine(CeedHash(std::get<2>(k)),
CeedHash(std::get<3>(k)))),
CeedHash(std::get<4>(k)));
}
};
using RestrMap =
+15 -3
View File
@@ -1591,14 +1591,21 @@ void VectorQuadratureFunctionCoefficient::Eval(Vector &V,
{
QuadF.HostRead();
const int el_idx = QuadF.GetSpace()->GetEntityIndex(T);
// Handle the case of "interior boundary elements" and FaceQuadratureSpace
// with FaceType::Boundary.
if (el_idx < 0) { V = 0.0; return; }
const int ip_idx = QuadF.GetSpace()->GetPermutedIndex(el_idx, ip.index);
if (index == 0 && vdim == QuadF.GetVDim())
{
QuadF.GetValues(T.ElementNo, ip.index, V);
QuadF.GetValues(el_idx, ip_idx, V);
}
else
{
Vector temp;
QuadF.GetValues(T.ElementNo, ip.index, temp);
QuadF.GetValues(el_idx, ip_idx, temp);
V.SetSize(vdim);
for (int i = 0; i < vdim; i++)
{
@@ -1625,7 +1632,12 @@ double QuadratureFunctionCoefficient::Eval(ElementTransformation &T,
{
QuadF.HostRead();
Vector temp(1);
QuadF.GetValues(T.ElementNo, ip.index, temp);
const int el_idx = QuadF.GetSpace()->GetEntityIndex(T);
// Handle the case of "interior boundary elements" and FaceQuadratureSpace
// with FaceType::Boundary.
if (el_idx < 0) { return 0.0; }
const int ip_idx = QuadF.GetSpace()->GetPermutedIndex(el_idx, ip.index);
QuadF.GetValues(el_idx, ip_idx, temp);
return temp[0];
}
+19 -16
View File
@@ -1243,25 +1243,28 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
HypreParMatrix * Ah;
A_i.Get(Ah);
hypre_ParCSRMatrix *Aih = *Ah;
#if !defined(HYPRE_USING_GPU)
ess_tdof_list.HostRead();
for (int k = 0; k < n; k++)
if (!HypreUsingGPU())
{
const int j = ess_tdof_list[k];
Aih->diag->data[Aih->diag->i[j]] = 0.0;
ess_tdof_list.HostRead();
for (int k = 0; k < n; k++)
{
const int j = ess_tdof_list[k];
Aih->diag->data[Aih->diag->i[j]] = 0.0;
}
}
#else
Ah->HypreReadWrite();
const int *d_ess_tdof_list =
ess_tdof_list.GetMemory().Read(MemoryClass::DEVICE, n);
const int *d_diag_i = Aih->diag->i;
double *d_diag_data = Aih->diag->data;
MFEM_GPU_FORALL(k, n,
else
{
const int j = d_ess_tdof_list[k];
d_diag_data[d_diag_i[j]] = 0.0;
});
#endif
Ah->HypreReadWrite();
const int *d_ess_tdof_list =
ess_tdof_list.GetMemory().Read(MemoryClass::DEVICE, n);
const int *d_diag_i = Aih->diag->i;
double *d_diag_data = Aih->diag->data;
MFEM_GPU_FORALL(k, n,
{
const int j = d_ess_tdof_list[k];
d_diag_data[d_diag_i[j]] = 0.0;
});
}
}
else
{
+1 -1
View File
@@ -922,7 +922,7 @@ void ParaViewDataCollection::Save()
{
const std::string &field_name = qfield.first;
std::ofstream os(vtu_prefix + GenerateVTUFileName(field_name, myid));
qfield.second->SaveVTU(os, pv_data_format, GetCompressionLevel());
qfield.second->SaveVTU(os, pv_data_format, GetCompressionLevel(), field_name);
}
// MPI rank 0 also creates a "PVTU" file that points to all of the separately
+4 -6
View File
@@ -166,21 +166,19 @@ void DGMassInverse::DGMassCGIteration(const Vector &b_, Vector &u_) const
b = b_.Read();
}
constexpr int NB = Q1D ? Q1D : 1; // block size
static constexpr int NB = Q1D ? Q1D : 1; // block size
mfem::forall_2D(NE, NB, NB, [=] MFEM_HOST_DEVICE (int e)
{
constexpr int NB = Q1D ? Q1D : 1; // redefine here for some compilers
// Perform change of basis if needed
if (CHANGE_BASIS)
{
// Transform RHS
DGMassBasis<DIM,D1D,MAX_D1D>(e, NE, q2d_Bt, b_orig, b2, d1d);
DGMassBasis<DIM,D1D>(e, NE, q2d_Bt, b_orig, b2, d1d);
if (IT_MODE)
{
// Transform initial guess
DGMassBasis<DIM,D1D,MAX_D1D>(e, NE, d2q_B, u, u, d1d);
DGMassBasis<DIM,D1D>(e, NE, d2q_B, u, u, d1d);
}
}
@@ -257,7 +255,7 @@ void DGMassInverse::DGMassCGIteration(const Vector &b_, Vector &u_) const
if (CHANGE_BASIS)
{
DGMassBasis<DIM,D1D,MAX_D1D>(e, NE, q2d_B, u, u, d1d);
DGMassBasis<DIM,D1D>(e, NE, q2d_B, u, u, d1d);
}
});
}
+7 -7
View File
@@ -172,7 +172,7 @@ double DGMassDot(const int e,
return s_dot[0];
}
template<int T_D1D = 0, int MAX_D1D = 0>
template<int T_D1D = 0>
MFEM_HOST_DEVICE inline
void DGMassBasis2D(const int e,
const int NE,
@@ -181,7 +181,7 @@ void DGMassBasis2D(const int e,
double *y_,
const int d1d = 0)
{
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
const int D1D = T_D1D ? T_D1D : d1d;
const auto b = Reshape(b_, D1D, D1D);
@@ -213,7 +213,7 @@ void DGMassBasis2D(const int e,
MFEM_SYNC_THREAD;
}
template<int T_D1D = 0, int MAX_D1D = 0>
template<int T_D1D = 0>
MFEM_HOST_DEVICE inline
void DGMassBasis3D(const int e,
const int NE,
@@ -228,7 +228,7 @@ void DGMassBasis3D(const int e,
const auto x = Reshape(x_, D1D, D1D, D1D, NE);
auto y = Reshape(y_, D1D, D1D, D1D, NE);
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED double sB[MD1*MD1];
MFEM_SHARED double sm0[MD1*MD1*MD1];
@@ -260,7 +260,7 @@ void DGMassBasis3D(const int e,
MFEM_SYNC_THREAD;
}
template<int DIM, int T_D1D = 0, int MAX_D1D = 0>
template<int DIM, int T_D1D = 0>
MFEM_HOST_DEVICE inline
void DGMassBasis(const int e,
const int NE,
@@ -271,11 +271,11 @@ void DGMassBasis(const int e,
{
if (DIM == 2)
{
DGMassBasis2D<T_D1D, MAX_D1D>(e, NE, b_, x_, y_, d1d);
DGMassBasis2D<T_D1D>(e, NE, b_, x_, y_, d1d);
}
else if (DIM == 3)
{
DGMassBasis3D<T_D1D, MAX_D1D>(e, NE, b_, x_, y_, d1d);
DGMassBasis3D<T_D1D>(e, NE, b_, x_, y_, d1d);
}
else
{
+66 -300
View File
@@ -14,54 +14,6 @@
namespace mfem
{
void DofTransformation::TransformPrimal(Vector &v) const
{
TransformPrimal(v.GetData());
}
void DofTransformation::TransformPrimalCols(DenseMatrix &V) const
{
for (int c=0; c<V.Width(); c++)
{
TransformPrimal(V.GetColumn(c));
}
}
void DofTransformation::TransformDual(Vector &v) const
{
TransformDual(v.GetData());
}
void DofTransformation::TransformDual(DenseMatrix &V) const
{
TransformDualCols(V);
TransformDualRows(V);
}
void DofTransformation::TransformDualRows(DenseMatrix &V) const
{
Vector row;
for (int r=0; r<V.Height(); r++)
{
V.GetRow(r, row);
TransformDual(row);
V.SetRow(r, row);
}
}
void DofTransformation::TransformDualCols(DenseMatrix &V) const
{
for (int c=0; c<V.Width(); c++)
{
TransformDual(V.GetColumn(c));
}
}
void DofTransformation::InvTransformPrimal(Vector &v) const
{
InvTransformPrimal(v.GetData());
}
void TransformPrimal(const DofTransformation *ran_dof_trans,
const DofTransformation *dom_dof_trans,
DenseMatrix &elmat)
@@ -85,11 +37,6 @@ void TransformPrimal(const DofTransformation *ran_dof_trans,
}
}
void DofTransformation::InvTransformDual(Vector &v) const
{
InvTransformDual(v.GetData());
}
void TransformDual(const DofTransformation *ran_dof_trans,
const DofTransformation *dom_dof_trans,
DenseMatrix &elmat)
@@ -113,15 +60,16 @@ void TransformDual(const DofTransformation *ran_dof_trans,
}
}
void VDofTransformation::TransformPrimal(double *v) const
void StatelessVDofTransformation::TransformPrimal(const Array<int> & face_ori,
double *v) const
{
int size = doftrans_->Size();
int size = sdoftrans_->Size();
if ((Ordering::Type)ordering_ == Ordering::byNODES || vdim_ == 1)
{
for (int i=0; i<vdim_; i++)
{
doftrans_->TransformPrimal(&v[i*size]);
sdoftrans_->TransformPrimal(face_ori, &v[i*size]);
}
}
else
@@ -133,7 +81,7 @@ void VDofTransformation::TransformPrimal(double *v) const
{
vec(j) = v[j*vdim_+i];
}
doftrans_->TransformPrimal(vec);
sdoftrans_->TransformPrimal(face_ori, vec);
for (int j=0; j<size; j++)
{
v[j*vdim_+i] = vec(j);
@@ -142,15 +90,17 @@ void VDofTransformation::TransformPrimal(double *v) const
}
}
void VDofTransformation::InvTransformPrimal(double *v) const
void StatelessVDofTransformation::InvTransformPrimal(
const Array<int> & face_ori,
double *v) const
{
int size = doftrans_->Height();
int size = sdoftrans_->Height();
if ((Ordering::Type)ordering_ == Ordering::byNODES)
{
for (int i=0; i<vdim_; i++)
{
doftrans_->InvTransformPrimal(&v[i*size]);
sdoftrans_->InvTransformPrimal(face_ori, &v[i*size]);
}
}
else
@@ -162,7 +112,7 @@ void VDofTransformation::InvTransformPrimal(double *v) const
{
vec(j) = v[j*vdim_+i];
}
doftrans_->InvTransformPrimal(vec);
sdoftrans_->InvTransformPrimal(face_ori, vec);
for (int j=0; j<size; j++)
{
v[j*vdim_+i] = vec(j);
@@ -171,15 +121,16 @@ void VDofTransformation::InvTransformPrimal(double *v) const
}
}
void VDofTransformation::TransformDual(double *v) const
void StatelessVDofTransformation::TransformDual(const Array<int> & face_ori,
double *v) const
{
int size = doftrans_->Size();
int size = sdoftrans_->Size();
if ((Ordering::Type)ordering_ == Ordering::byNODES)
{
for (int i=0; i<vdim_; i++)
{
doftrans_->TransformDual(&v[i*size]);
sdoftrans_->TransformDual(face_ori, &v[i*size]);
}
}
else
@@ -191,7 +142,7 @@ void VDofTransformation::TransformDual(double *v) const
{
vec(j) = v[j*vdim_+i];
}
doftrans_->TransformDual(vec);
sdoftrans_->TransformDual(face_ori, vec);
for (int j=0; j<size; j++)
{
v[j*vdim_+i] = vec(j);
@@ -200,15 +151,16 @@ void VDofTransformation::TransformDual(double *v) const
}
}
void VDofTransformation::InvTransformDual(double *v) const
void StatelessVDofTransformation::InvTransformDual(const Array<int> & face_ori,
double *v) const
{
int size = doftrans_->Size();
int size = sdoftrans_->Size();
if ((Ordering::Type)ordering_ == Ordering::byNODES)
{
for (int i=0; i<vdim_; i++)
{
doftrans_->InvTransformDual(&v[i*size]);
sdoftrans_->InvTransformDual(face_ori, &v[i*size]);
}
}
else
@@ -220,7 +172,7 @@ void VDofTransformation::InvTransformDual(double *v) const
{
vec(j) = v[j*vdim_+i];
}
doftrans_->InvTransformDual(vec);
sdoftrans_->InvTransformDual(face_ori, vec);
for (int j=0; j<size; j++)
{
v[j*vdim_+i] = vec(j);
@@ -229,7 +181,8 @@ void VDofTransformation::InvTransformDual(double *v) const
}
}
const double ND_DofTransformation::T_data[24] =
// ordering (i0j0, i1j0, i0j1, i1j1), each row is a column major matrix
const double ND_StatelessDofTransformation::T_data[24] =
{
1.0, 0.0, 0.0, 1.0,
-1.0, -1.0, 0.0, 1.0,
@@ -239,10 +192,11 @@ const double ND_DofTransformation::T_data[24] =
0.0, 1.0, 1.0, 0.0
};
const DenseTensor ND_DofTransformation
::T(const_cast<double*>(ND_DofTransformation::T_data), 2, 2, 6);
const DenseTensor ND_StatelessDofTransformation
::T(const_cast<double*>(ND_StatelessDofTransformation::T_data), 2, 2, 6);
const double ND_DofTransformation::TInv_data[24] =
// ordering (i0j0, i1j0, i0j1, i1j1), each row is a column major matrix
const double ND_StatelessDofTransformation::TInv_data[24] =
{
1.0, 0.0, 0.0, 1.0,
-1.0, -1.0, 0.0, 1.0,
@@ -252,301 +206,113 @@ const double ND_DofTransformation::TInv_data[24] =
0.0, 1.0, 1.0, 0.0
};
const DenseTensor ND_DofTransformation
const DenseTensor ND_StatelessDofTransformation
::TInv(const_cast<double*>(TInv_data), 2, 2, 6);
ND_DofTransformation::ND_DofTransformation(int size, int p)
: DofTransformation(size)
ND_StatelessDofTransformation::ND_StatelessDofTransformation(int size, int p,
int num_edges,
int num_tri_faces)
: StatelessDofTransformation(size)
, order(p)
, nedofs(p)
, nfdofs(p*(p-1))
, nedges(num_edges)
, nfaces(num_tri_faces)
{
}
ND_TriDofTransformation::ND_TriDofTransformation(int p)
: ND_DofTransformation(p*(p + 2), p)
{
}
void ND_TriDofTransformation::TransformPrimal(double *v) const
void ND_StatelessDofTransformation::TransformPrimal(const Array<int> & Fo,
double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 1,
"Face orientations are unset in ND_TriDofTransformation");
MFEM_VERIFY(Fo.Size() >= nfaces,
"Face orientation array is shorter than the number of faces in "
"ND_StatelessDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<1; f++)
for (int f=0; f<nfaces; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[3*nedofs + f*nfdofs + 2*i];
T(Fo[f]).Mult(v2, &v[3*nedofs + f*nfdofs + 2*i]);
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
T(Fo[f]).Mult(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_TriDofTransformation::InvTransformPrimal(double *v) const
void ND_StatelessDofTransformation::InvTransformPrimal(const Array<int> & Fo,
double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 1,
"Face orientations are unset in ND_TriDofTransformation");
MFEM_VERIFY(Fo.Size() >= nfaces,
"Face orientation array is shorter than the number of faces in "
"ND_StatelessDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<1; f++)
for (int f=0; f<nfaces; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[3*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).Mult(v2, &v[3*nedofs + f*nfdofs + 2*i]);
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).Mult(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_TriDofTransformation::TransformDual(double *v) const
void ND_StatelessDofTransformation::TransformDual(const Array<int> & Fo,
double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 1,
"Face orientations are unset in ND_TriDofTransformation");
MFEM_VERIFY(Fo.Size() >= nfaces,
"Face orientation array is shorter than the number of faces in "
"ND_StatelessDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<1; f++)
for (int f=0; f<nfaces; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[3*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).MultTranspose(v2, &v[3*nedofs + f*nfdofs + 2*i]);
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).MultTranspose(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_TriDofTransformation::InvTransformDual(double *v) const
void ND_StatelessDofTransformation::InvTransformDual(const Array<int> & Fo,
double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 1,
"Face orientations are unset in ND_TriDofTransformation");
MFEM_VERIFY(Fo.Size() >= nfaces,
"Face orientation array is shorter than the number of faces in "
"ND_StatelessDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<1; f++)
for (int f=0; f<nfaces; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[3*nedofs + f*nfdofs + 2*i];
T(Fo[f]).MultTranspose(v2, &v[3*nedofs + f*nfdofs + 2*i]);
}
}
}
ND_TetDofTransformation::ND_TetDofTransformation(int p)
: ND_DofTransformation(p*(p + 2)*(p + 3)/2, p)
{
}
void ND_TetDofTransformation::TransformPrimal(double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 4,
"Face orientations are unset in ND_TetDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<4; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[6*nedofs + f*nfdofs + 2*i];
T(Fo[f]).Mult(v2, &v[6*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_TetDofTransformation::InvTransformPrimal(double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 4,
"Face orientations are unset in ND_TetDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<4; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[6*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).Mult(v2, &v[6*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_TetDofTransformation::TransformDual(double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 4,
"Face orientations are unset in ND_TetDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<4; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[6*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).MultTranspose(v2, &v[6*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_TetDofTransformation::InvTransformDual(double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 4,
"Face orientations are unset in ND_TetDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<4; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[6*nedofs + f*nfdofs + 2*i];
T(Fo[f]).MultTranspose(v2, &v[6*nedofs + f*nfdofs + 2*i]);
}
}
}
ND_WedgeDofTransformation::ND_WedgeDofTransformation(int p)
: ND_DofTransformation(3 * p * ((p + 1) * (p + 2))/2, p)
{
}
void ND_WedgeDofTransformation::TransformPrimal(double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 2,
"Face orientations are unset in ND_WedgeDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform triangular face DoFs
for (int f=0; f<2; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[9*nedofs + f*nfdofs + 2*i];
T(Fo[f]).Mult(v2, &v[9*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_WedgeDofTransformation::InvTransformPrimal(double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 2,
"Face orientations are unset in ND_WedgeDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform triangular face DoFs
for (int f=0; f<2; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[9*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).Mult(v2, &v[9*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_WedgeDofTransformation::TransformDual(double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 2,
"Face orientations are unset in ND_WedgeDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform triangular face DoFs
for (int f=0; f<2; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[9*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).MultTranspose(v2, &v[9*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_WedgeDofTransformation::InvTransformDual(double *v) const
{
// Return immediately when no face DoFs are present
if (nfdofs < 2) { return; }
MFEM_VERIFY(Fo.Size() >= 2,
"Face orientations are unset in ND_WedgeDofTransformation");
double data[2];
Vector v2(data, 2);
// Transform triangular face DoFs
for (int f=0; f<2; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[9*nedofs + f*nfdofs + 2*i];
T(Fo[f]).MultTranspose(v2, &v[9*nedofs + f*nfdofs + 2*i]);
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
T(Fo[f]).MultTranspose(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
}
}
}
+331 -87
View File
@@ -15,19 +15,31 @@
#include "../config/config.hpp"
#include "../linalg/linalg.hpp"
#include "intrules.hpp"
#include "fe.hpp"
namespace mfem
{
/** The DofTransformation class is an abstract base class for a family of
transformations that map local degrees of freedom (DoFs), contained within
individual elements, to global degrees of freedom, stored within
GridFunction objects. These transformations are necessary to ensure that
basis functions in neighboring elements align correctly. Closely related but
/** The StatelessDofTransformation class is an abstract base class for a family
of transformations that map local degrees of freedom (DoFs), contained
within individual elements, to global degrees of freedom, stored within
GridFunction objects.
In this context "stateless" means that the concrete classes derived from
StatelessDofTransformation do not store information about the relative
orientations of the faces with respect to their neighboring elements. In
other words there is no information specific to a particular element (aside
from the element type e.g. tetrahedron, wedge, or pyramid). The
StatelessDofTransformation provides access to the transformation operators
for specific relative face orientations. These are useful, for example, when
relating DoFs associated with distinct overlapping meshes such as parent and
sub-meshes.
These transformations are necessary to ensure that basis functions in
neighboring (or overlapping) elements align correctly. Closely related but
complementary transformations are required for the entries stored in
LinearForm and BilinearForm objects. The DofTransformation class is designed
to apply the action of both of these types of DoF transformations.
LinearForm and BilinearForm objects. The StatelessDofTransformation class
is designed to apply the action of both of these types of DoF
transformations.
Let the "primal transformation" be given by the operator T. This means that
given a local element vector v the data that must be placed into a
@@ -53,24 +65,84 @@ namespace mfem
D_t = T * D * T^{-1}. This can be accomplished by using a primal
transformation on the columns of D and a dual transformation on its rows.
*/
class DofTransformation
class StatelessDofTransformation
{
protected:
int size_;
Array<int> Fo;
DofTransformation(int size)
StatelessDofTransformation(int size)
: size_(size) {}
public:
inline int Size() const { return size_; }
inline int Height() const { return size_; }
inline int NumRows() const { return size_; }
inline int Width() const { return size_; }
inline int NumCols() const { return size_; }
/** Transform local DoFs to align with the global DoFs. For example, this
transformation can be used to map the local vector computed by
FiniteElement::Project() to the transformed vector stored within a
GridFunction object. */
virtual void TransformPrimal(const Array<int> & face_orientation,
double *v) const = 0;
inline void TransformPrimal(const Array<int> & face_orientation,
Vector &v) const
{ TransformPrimal(face_orientation, v.GetData()); }
/** Inverse transform local DoFs. Used to transform DoFs from a global vector
back to their element-local form. For example, this must be used to
transform the vector obtained using GridFunction::GetSubVector before it
can be used to compute a local interpolation.
*/
virtual void InvTransformPrimal(const Array<int> & face_orientation,
double *v) const = 0;
inline void InvTransformPrimal(const Array<int> & face_orientation,
Vector &v) const
{ InvTransformPrimal(face_orientation, v.GetData()); }
/** Transform dual DoFs as computed by a LinearFormIntegrator before summing
into a LinearForm object. */
virtual void TransformDual(const Array<int> & face_orientation,
double *v) const = 0;
inline void TransformDual(const Array<int> & face_orientation,
Vector &v) const
{ TransformDual(face_orientation, v.GetData()); }
/** Inverse Transform dual DoFs */
virtual void InvTransformDual(const Array<int> & face_orientation,
double *v) const = 0;
inline void InvTransformDual(const Array<int> & face_orientation,
Vector &v) const
{ InvTransformDual(face_orientation, v.GetData()); }
};
/** The DofTransformation class is an extension of the
StatelessDofTransformation which stores the face orientations used to
select the necessary transformations which allows it to offer a collection
of convenience methods.
DofTransformation objects are provided by the FiniteElementSpace which has
access to the mesh and can therefore provide the face orientations. This is
convenient when working with GridFunction, LinearForm, or BilinearForm
objects or their parallel counterparts.
StatelessDofTransformation objects are provided by FiniteElement or
FiniteElementCollection objects which do not have access to face
orientation information. This can be useful in non-standard contexts such as
transferring finite element degrees of freedom between different meshes.
For examples of its use see the TransferMap used by the SubMesh class.
*/
class DofTransformation : virtual public StatelessDofTransformation
{
protected:
Array<int> Fo;
DofTransformation(int size)
: StatelessDofTransformation(size) {}
public:
/** @brief Configure the transformation using face orientations for the
current element. */
/// The face_orientation array can be obtained from Mesh::GetElementFaces.
@@ -79,42 +151,82 @@ public:
inline const Array<int> & GetFaceOrientations() const { return Fo; }
using StatelessDofTransformation::TransformPrimal;
using StatelessDofTransformation::InvTransformPrimal;
using StatelessDofTransformation::TransformDual;
using StatelessDofTransformation::InvTransformDual;
/** Transform local DoFs to align with the global DoFs. For example, this
transformation can be used to map the local vector computed by
FiniteElement::Project() to the transformed vector stored within a
GridFunction object. */
virtual void TransformPrimal(double *v) const = 0;
virtual void TransformPrimal(Vector &v) const;
inline void TransformPrimal(double *v) const
{ TransformPrimal(Fo, v); }
inline void TransformPrimal(Vector &v) const
{ TransformPrimal(v.GetData()); }
/// Transform groups of DoFs stored as dense matrices
virtual void TransformPrimalCols(DenseMatrix &V) const;
inline void TransformPrimalCols(DenseMatrix &V) const
{
for (int c=0; c<V.Width(); c++)
{
TransformPrimal(V.GetColumn(c));
}
}
/** Inverse transform local DoFs. Used to transform DoFs from a global vector
back to their element-local form. For example, this must be used to
transform the vector obtained using GridFunction::GetSubVector before it
can be used to compute a local interpolation.
*/
virtual void InvTransformPrimal(double *v) const = 0;
virtual void InvTransformPrimal(Vector &v) const;
inline void InvTransformPrimal(double *v) const
{ InvTransformPrimal(Fo, v); }
inline void InvTransformPrimal(Vector &v) const
{ InvTransformPrimal(v.GetData()); }
/** Transform dual DoFs as computed by a LinearFormIntegrator before summing
into a LinearForm object. */
virtual void TransformDual(double *v) const = 0;
virtual void TransformDual(Vector &v) const;
inline void TransformDual(double *v) const
{ TransformDual(Fo, v); }
inline void TransformDual(Vector &v) const
{ TransformDual(v.GetData()); }
/** Inverse Transform dual DoFs */
virtual void InvTransformDual(double *v) const = 0;
virtual void InvTransformDual(Vector &v) const;
inline void InvTransformDual(double *v) const
{ InvTransformDual(Fo, v); }
inline void InvTransformDual(Vector &v) const
{ InvTransformDual(v.GetData()); }
/** Transform a matrix of dual DoFs entries as computed by a
BilinearFormIntegrator before summing into a BilinearForm object. */
virtual void TransformDual(DenseMatrix &V) const;
inline void TransformDual(DenseMatrix &V) const
{
TransformDualCols(V);
TransformDualRows(V);
}
/// Transform groups of dual DoFs stored as dense matrices
virtual void TransformDualRows(DenseMatrix &V) const;
virtual void TransformDualCols(DenseMatrix &V) const;
/// Transform rows of a dense matrix containing dual DoFs
inline void TransformDualRows(DenseMatrix &V) const
{
Vector row;
for (int r=0; r<V.Height(); r++)
{
V.GetRow(r, row);
TransformDual(row);
V.SetRow(r, row);
}
}
virtual ~DofTransformation() {}
/// Transform columns of a dense matrix containing dual DoFs
inline void TransformDualCols(DenseMatrix &V) const
{
for (int c=0; c<V.Width(); c++)
{
TransformDual(V.GetColumn(c));
}
}
virtual ~DofTransformation() = default;
};
/** Transform a matrix of DoFs entries from different finite element spaces as
@@ -133,66 +245,143 @@ void TransformDual(const DofTransformation *ran_dof_trans,
const DofTransformation *dom_dof_trans,
DenseMatrix &elmat);
/** The VDofTransformation class implements a nested transformation where an
arbitrary DofTransformation is replicated with a vdim >= 1.
/** The StatelessVDofTransformation class implements a nested transformation
where an arbitrary StatelessDofTransformation is replicated with a
vdim >= 1.
*/
class VDofTransformation : public DofTransformation
class StatelessVDofTransformation : virtual public StatelessDofTransformation
{
private:
protected:
int vdim_;
int ordering_;
DofTransformation * doftrans_;
StatelessDofTransformation * sdoftrans_;
public:
/** @brief Default constructor which requires that SetDofTransformation be
called before use. */
VDofTransformation(int vdim = 1, int ordering = 0)
: DofTransformation(0),
vdim_(vdim), ordering_(ordering),
doftrans_(NULL) {}
StatelessVDofTransformation(int vdim = 1, int ordering = 0)
: StatelessDofTransformation(0)
, vdim_(vdim)
, ordering_(ordering)
, sdoftrans_(NULL)
{}
/// Constructor with a known DofTransformation
VDofTransformation(DofTransformation & doftrans, int vdim = 1,
int ordering = 0)
: DofTransformation(vdim * doftrans.Size()),
vdim_(vdim), ordering_(ordering),
doftrans_(&doftrans) {}
/// Constructor with a known StatelessDofTransformation
StatelessVDofTransformation(StatelessDofTransformation & doftrans,
int vdim = 1,
int ordering = 0)
: StatelessDofTransformation(vdim * doftrans.Size())
, vdim_(vdim)
, ordering_(ordering)
, sdoftrans_(&doftrans)
{}
/// Set or change the vdim parameter
inline void SetVDim(int vdim)
{
vdim_ = vdim;
if (doftrans_)
if (sdoftrans_)
{
size_ = vdim_ * doftrans_->Size();
size_ = vdim_ * sdoftrans_->Size();
}
}
/// Return the current vdim value
inline int GetVDim() const { return vdim_; }
/// Set or change the nested DofTransformation object
inline void SetDofTransformation(DofTransformation & doftrans)
/// Set or change the nested StatelessDofTransformation object
inline void SetDofTransformation(StatelessDofTransformation & doftrans)
{
size_ = vdim_ * doftrans.Size();
sdoftrans_ = &doftrans;
}
/// Return the nested StatelessDofTransformation object
inline StatelessDofTransformation * GetDofTransformation() const
{ return sdoftrans_; }
using StatelessDofTransformation::TransformPrimal;
using StatelessDofTransformation::InvTransformPrimal;
using StatelessDofTransformation::TransformDual;
using StatelessDofTransformation::InvTransformDual;
/** Specializations of these base class methods which account for the vdim
and ordering of the full set of DoFs.
*/
void TransformPrimal(const Array<int> & face_ori, double *v) const;
void InvTransformPrimal(const Array<int> & face_ori, double *v) const;
void TransformDual(const Array<int> & face_ori, double *v) const;
void InvTransformDual(const Array<int> & face_ori, double *v) const;
};
/** The VDofTransformation class implements a nested transformation where an
arbitrary DofTransformation is replicated with a vdim >= 1.
*/
class VDofTransformation : public StatelessVDofTransformation,
public DofTransformation
{
protected:
DofTransformation * doftrans_;
public:
/** @brief Default constructor which requires that SetDofTransformation be
called before use. */
VDofTransformation(int vdim = 1, int ordering = 0)
: StatelessDofTransformation(0)
, StatelessVDofTransformation(vdim, ordering)
, DofTransformation(0)
, doftrans_(NULL)
{}
/// Constructor with a known DofTransformation
/// @note The face orientations in @a doftrans will be copied into the
/// new VDofTransformation object.
VDofTransformation(DofTransformation & doftrans, int vdim = 1,
int ordering = 0)
: StatelessDofTransformation(vdim * doftrans.Size())
, StatelessVDofTransformation(doftrans, vdim, ordering)
, DofTransformation(vdim * doftrans.Size())
, doftrans_(&doftrans)
{
DofTransformation::SetFaceOrientations(doftrans.GetFaceOrientations());
}
using StatelessVDofTransformation::SetDofTransformation;
/// Set or change the nested DofTransformation object
/// @note The face orientations in @a doftrans will be copied into the
/// VDofTransformation object.
void SetDofTransformation(DofTransformation & doftrans)
{
doftrans_ = &doftrans;
StatelessVDofTransformation::SetDofTransformation(doftrans);
DofTransformation::SetFaceOrientations(doftrans.GetFaceOrientations());
}
/// Return the nested DofTransformation object
inline DofTransformation * GetDofTransformation() const { return doftrans_; }
inline void SetFaceOrientation(const Array<int> & face_orientation)
{ Fo = face_orientation; doftrans_->SetFaceOrientations(face_orientation); }
/// Set new face orientations in both the VDofTransformation and the
/// DofTransformation contained within (if there is one).
inline void SetFaceOrientations(const Array<int> & face_orientation)
{
DofTransformation::SetFaceOrientations(face_orientation);
if (doftrans_) { doftrans_->SetFaceOrientations(face_orientation); }
}
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
inline void TransformPrimal(double *v) const
{ TransformPrimal(Fo, v); }
inline void InvTransformPrimal(double *v) const
{ InvTransformPrimal(Fo, v); }
inline void TransformDual(double *v) const
{ TransformDual(Fo, v); }
inline void InvTransformDual(double *v) const
{ InvTransformDual(Fo, v); }
};
/** Abstract base class for high-order Nedelec spaces on elements with
@@ -207,17 +396,22 @@ public:
be accessed as DenseMatrices using the GetFaceTransform() and
GetFaceInverseTransform() methods.
*/
class ND_DofTransformation : public DofTransformation
class ND_StatelessDofTransformation : virtual public StatelessDofTransformation
{
protected:
private:
static const double T_data[24];
static const double TInv_data[24];
static const DenseTensor T, TInv;
int order;
int nedofs; // number of DoFs per edge
int nfdofs; // number of DoFs per face
ND_DofTransformation(int size, int order);
protected:
const int order; // basis function order
const int nedofs; // number of DoFs per edge
const int nfdofs; // number of DoFs per face
const int nedges; // number of edges per element
const int nfaces; // number of triangular faces per element
ND_StatelessDofTransformation(int size, int order,
int num_edges, int num_tri_faces);
public:
// Return the 2x2 transformation operator for the given face orientation
@@ -226,67 +420,117 @@ public:
// Return the 2x2 inverse transformation operator
static const DenseMatrix & GetFaceInverseTransform(int ori)
{ return TInv(ori); }
void TransformPrimal(const Array<int> & face_orientation,
double *v) const;
void InvTransformPrimal(const Array<int> & face_orientation,
double *v) const;
void TransformDual(const Array<int> & face_orientation,
double *v) const;
void InvTransformDual(const Array<int> & face_orientation,
double *v) const;
};
/// Stateless DoF transformation implementation for the Nedelec basis on
/// triangles
class ND_TriStatelessDofTransformation : public ND_StatelessDofTransformation
{
public:
ND_TriStatelessDofTransformation(int order)
: StatelessDofTransformation(order*(order + 2))
, ND_StatelessDofTransformation(order*(order + 2), order, 3, 1)
{}
};
/// DoF transformation implementation for the Nedelec basis on triangles
class ND_TriDofTransformation : public ND_DofTransformation
class ND_TriDofTransformation : public DofTransformation,
public ND_TriStatelessDofTransformation
{
public:
ND_TriDofTransformation(int order);
ND_TriDofTransformation(int order)
: StatelessDofTransformation(order*(order + 2))
, DofTransformation(order*(order + 2))
, ND_TriStatelessDofTransformation(order)
{}
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
using DofTransformation::InvTransformDual;
using ND_TriStatelessDofTransformation::TransformPrimal;
using ND_TriStatelessDofTransformation::InvTransformPrimal;
using ND_TriStatelessDofTransformation::TransformDual;
using ND_TriStatelessDofTransformation::InvTransformDual;
};
/// DoF transformation implementation for the Nedelec basis on tetrahedra
class ND_TetDofTransformation : public ND_DofTransformation
class ND_TetStatelessDofTransformation : public ND_StatelessDofTransformation
{
public:
ND_TetDofTransformation(int order);
ND_TetStatelessDofTransformation(int order)
: StatelessDofTransformation(order*(order + 2)*(order + 3)/2)
, ND_StatelessDofTransformation(order*(order + 2)*(order + 3)/2, order,
6, 4)
{}
};
/// DoF transformation implementation for the Nedelec basis on tetrahedra
class ND_TetDofTransformation : public DofTransformation,
public ND_TetStatelessDofTransformation
{
public:
ND_TetDofTransformation(int order)
: StatelessDofTransformation(order*(order + 2)*(order + 3)/2)
, DofTransformation(order*(order + 2)*(order + 3)/2)
, ND_TetStatelessDofTransformation(order)
{}
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
using ND_TetStatelessDofTransformation::TransformPrimal;
using ND_TetStatelessDofTransformation::InvTransformPrimal;
using ND_TetStatelessDofTransformation::TransformDual;
using ND_TetStatelessDofTransformation::InvTransformDual;
};
/// DoF transformation implementation for the Nedelec basis on wedge elements
class ND_WedgeDofTransformation : public ND_DofTransformation
class ND_WedgeStatelessDofTransformation : public ND_StatelessDofTransformation
{
public:
ND_WedgeDofTransformation(int order);
ND_WedgeStatelessDofTransformation(int order)
: StatelessDofTransformation(3 * order * ((order + 1) * (order + 2))/2)
, ND_StatelessDofTransformation(3 * order * ((order + 1) * (order + 2))/2,
order, 9, 2)
{}
};
/// DoF transformation implementation for the Nedelec basis on wedge elements
class ND_WedgeDofTransformation : public DofTransformation,
public ND_WedgeStatelessDofTransformation
{
public:
ND_WedgeDofTransformation(int order)
: StatelessDofTransformation(3 * order * ((order + 1) * (order + 2))/2)
, DofTransformation(3 * order * ((order + 1) * (order + 2))/2)
, ND_WedgeStatelessDofTransformation(order)
{}
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
using ND_WedgeStatelessDofTransformation::TransformPrimal;
using ND_WedgeStatelessDofTransformation::InvTransformPrimal;
using ND_WedgeStatelessDofTransformation::TransformDual;
using ND_WedgeStatelessDofTransformation::InvTransformDual;
};
} // namespace mfem
+1 -1
View File
@@ -807,7 +807,7 @@ void NodalFiniteElement::Project(
else
{
DenseMatrix vshape(fe.GetDof(), std::max(Trans.GetSpaceDim(),
fe.GetVDim()));
fe.GetRangeDim()));
I.SetSize(vshape.Width()*dof, fe.GetDof());
for (int k = 0; k < dof; k++)
+15 -6
View File
@@ -14,6 +14,7 @@
#include "../intrules.hpp"
#include "../geom.hpp"
#include "../doftrans.hpp"
#include <map>
@@ -306,19 +307,20 @@ public:
FiniteElement(int D, Geometry::Type G, int Do, int O,
int F = FunctionSpace::Pk);
/// Returns the reference space dimension for the finite element
/// Returns the reference space dimension for the finite element.
int GetDim() const { return dim; }
/// Returns the vector dimension for vector-valued finite elements
int GetVDim() const { return vdim; }
/** @brief Returns the vector dimension for vector-valued finite elements,
which is also the dimension of the interpolation operatrion. */
int GetRangeDim() const { return vdim; }
/// Returns the dimension of the curl for vector-valued finite elements
/// Returns the dimension of the curl for vector-valued finite elements.
int GetCurlDim() const { return cdim; }
/// Returns the Geometry::Type of the reference element
/// Returns the Geometry::Type of the reference element.
Geometry::Type GetGeomType() const { return geom_type; }
/// Returns the number of degrees of freedom in the finite element
/// Returns the number of degrees of freedom in the finite element.
int GetDof() const { return dof; }
/** @brief Returns the order of the finite element. In the case of
@@ -576,6 +578,7 @@ public:
virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode) const;
/** @brief Return the mapping from lexicographic face DOFs to lexicographic
element DOFs for the given local face @a face_id. */
/** Given the @a ith DOF (lexicographically ordered) on the face referenced
@@ -590,6 +593,12 @@ public:
when simplex elements are supported in the future. */
virtual void GetFaceMap(const int face_id, Array<int> &face_map) const;
/** @brief Return a DoF transformation object for this particular type of
basis.
*/
virtual StatelessDofTransformation * GetDofTransformation() const
{ return NULL; }
/// Deconstruct the FiniteElement
virtual ~FiniteElement();
+5 -4
View File
@@ -845,7 +845,7 @@ const double ND_TetrahedronElement::c = 1./4.;
ND_TetrahedronElement::ND_TetrahedronElement(const int p)
: VectorFiniteElement(3, Geometry::TETRAHEDRON, p*(p + 2)*(p + 3)/2, p,
H_CURL, FunctionSpace::Pk), dof2tk(dof)
H_CURL, FunctionSpace::Pk), dof2tk(dof), doftrans(p)
{
const double *eop = poly1d.OpenPoints(p - 1);
const double *fop = (p > 1) ? poly1d.OpenPoints(p - 2) : NULL;
@@ -1108,7 +1108,7 @@ const double ND_TriangleElement::c = 1./3.;
ND_TriangleElement::ND_TriangleElement(const int p)
: VectorFiniteElement(2, Geometry::TRIANGLE, p*(p + 2), p,
H_CURL, FunctionSpace::Pk),
dof2tk(dof)
dof2tk(dof), doftrans(p)
{
const double *eop = poly1d.OpenPoints(p - 1);
const double *iop = (p > 1) ? poly1d.OpenPoints(p - 2) : NULL;
@@ -1302,6 +1302,7 @@ ND_WedgeElement::ND_WedgeElement(const int p,
dof2tk(dof),
t_dof(dof),
s_dof(dof),
doftrans(p),
H1TriangleFE(p, cb_type),
NDTriangleFE(p),
H1SegmentFE(p, cb_type),
@@ -1851,7 +1852,7 @@ void ND_R1D_SegmentElement::Project(const FiniteElement &fe,
else
{
double vk[Geometry::MaxDim];
DenseMatrix vshape(fe.GetDof(), fe.GetVDim());
DenseMatrix vshape(fe.GetDof(), fe.GetRangeDim());
double * tk_ptr = const_cast<double*>(tk);
@@ -2292,7 +2293,7 @@ void ND_R2D_FiniteElement::Project(const FiniteElement &fe,
else
{
double vk[Geometry::MaxDim];
DenseMatrix vshape(fe.GetDof(), fe.GetVDim());
DenseMatrix vshape(fe.GetDof(), fe.GetRangeDim());
double * tk_ptr = const_cast<double*>(tk);
+13
View File
@@ -179,6 +179,8 @@ class ND_TetrahedronElement : public VectorFiniteElement
Array<int> dof2tk;
DenseMatrixInverse Ti;
mutable ND_TetStatelessDofTransformation doftrans;
public:
/// Construct the ND_TetrahedronElement of order @a p
ND_TetrahedronElement(const int p);
@@ -199,6 +201,8 @@ public:
ElementTransformation &Trans,
DenseMatrix &I) const
{ LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
virtual StatelessDofTransformation * GetDofTransformation() const
{ return &doftrans; }
using FiniteElement::Project;
virtual void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const
@@ -238,6 +242,8 @@ class ND_TriangleElement : public VectorFiniteElement
Array<int> dof2tk;
DenseMatrixInverse Ti;
mutable ND_TriStatelessDofTransformation doftrans;
public:
/// Construct the ND_TriangleElement of order @a p
ND_TriangleElement(const int p);
@@ -258,6 +264,8 @@ public:
ElementTransformation &Trans,
DenseMatrix &I) const
{ LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
virtual StatelessDofTransformation * GetDofTransformation() const
{ return &doftrans; }
using FiniteElement::Project;
virtual void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const
@@ -338,6 +346,8 @@ private:
#endif
Array<int> dof2tk, t_dof, s_dof;
mutable ND_WedgeStatelessDofTransformation doftrans;
H1_TriangleElement H1TriangleFE;
ND_TriangleElement NDTriangleFE;
H1_SegmentElement H1SegmentFE;
@@ -369,6 +379,9 @@ public:
DenseMatrix &I) const
{ LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
virtual StatelessDofTransformation * GetDofTransformation() const
{ return &doftrans; }
using FiniteElement::Project;
virtual void Project(VectorCoefficient &vc,
+4
View File
@@ -56,6 +56,10 @@ public:
Vector &Weights () const { return weights; }
/// Update the NURBSFiniteElement according to the currently set knot vectors
virtual void SetOrder () const { }
/// Returns the indices (i,j) in 2D or (i,j,k) in 3D of this element in the
/// tensor product ordering of the patch.
const int* GetIJK() const { return ijk; }
};
+4 -4
View File
@@ -1486,7 +1486,7 @@ void RT_R1D_SegmentElement::Project(const FiniteElement &fe,
else
{
double vk[Geometry::MaxDim];
DenseMatrix vshape(fe.GetDof(), fe.GetVDim());
DenseMatrix vshape(fe.GetDof(), fe.GetRangeDim());
double * nk_ptr = const_cast<double*>(nk);
@@ -1523,7 +1523,7 @@ void RT_R1D_SegmentElement::ProjectCurl(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &curl) const
{
DenseMatrix curl_shape(fe.GetDof(), fe.GetVDim());
DenseMatrix curl_shape(fe.GetDof(), fe.GetRangeDim());
Vector curl_k(fe.GetDof());
double * nk_ptr = const_cast<double*>(nk);
@@ -1849,7 +1849,7 @@ void RT_R2D_FiniteElement::Project(const FiniteElement &fe,
else
{
double vk[Geometry::MaxDim];
DenseMatrix vshape(fe.GetDof(), fe.GetVDim());
DenseMatrix vshape(fe.GetDof(), fe.GetRangeDim());
double * nk_ptr = const_cast<double*>(nk);
@@ -1888,7 +1888,7 @@ void RT_R2D_FiniteElement::ProjectCurl(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &curl) const
{
DenseMatrix curl_shape(fe.GetDof(), fe.GetVDim());
DenseMatrix curl_shape(fe.GetDof(), fe.GetRangeDim());
Vector curl_k(fe.GetDof());
double * nk_ptr = const_cast<double*>(nk);
+40 -17
View File
@@ -87,6 +87,16 @@ int FiniteElementCollection::GetDerivMapType(int dim) const
return FiniteElement::UNKNOWN_MAP_TYPE;
}
int FiniteElementCollection::GetRangeDim(int dim) const
{
const FiniteElement *fe = FiniteElementForDim(dim);
if (fe)
{
return fe->GetRangeDim();
}
return 0;
}
int FiniteElementCollection::HasFaceDofs(Geometry::Type geom, int p) const
{
switch (geom)
@@ -1713,7 +1723,7 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
H1_Elements[Geometry::SEGMENT] = new H1_SegmentElement(p, btype);
}
SegDofOrd[0] = new int[2*pm1];
SegDofOrd[0] = (pm1 > 0) ? new int[2*pm1] : nullptr;
SegDofOrd[1] = SegDofOrd[0] + pm1;
for (int i = 0; i < pm1; i++)
{
@@ -1751,7 +1761,7 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
const int &TriDof = H1_dof[Geometry::TRIANGLE];
const int &QuadDof = H1_dof[Geometry::SQUARE];
TriDofOrd[0] = new int[6*TriDof];
TriDofOrd[0] = (TriDof > 0) ? new int[6*TriDof] : nullptr;
for (int i = 1; i < 6; i++)
{
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
@@ -1772,7 +1782,7 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
}
}
QuadDofOrd[0] = new int[8*QuadDof];
QuadDofOrd[0] = (QuadDof > 0) ? new int[8*QuadDof] : nullptr;
for (int i = 1; i < 8; i++)
{
QuadDofOrd[i] = QuadDofOrd[i-1] + QuadDof;
@@ -1855,7 +1865,7 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
H1_Elements[Geometry::PYRAMID] = new LinearPyramidFiniteElement;
const int &TetDof = H1_dof[Geometry::TETRAHEDRON];
TetDofOrd[0] = new int[24*TetDof];
TetDofOrd[0] = (TetDof > 0) ? new int[24*TetDof] : nullptr;
for (int i = 1; i < 24; i++)
{
TetDofOrd[i] = TetDofOrd[i-1] + TetDof;
@@ -2127,7 +2137,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
// No need to set the map_type for Tr_Elements.
const int pp1 = p + 1;
SegDofOrd[0] = new int[2*pp1];
SegDofOrd[0] = (pp1 > 0) ? new int[2*pp1] : nullptr;
SegDofOrd[1] = SegDofOrd[0] + pp1;
for (int i = 0; i <= p; i++)
{
@@ -2160,7 +2170,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
}
const int TriDof = L2_Elements[Geometry::TRIANGLE]->GetDof();
TriDofOrd[0] = new int[6*TriDof];
TriDofOrd[0] = (TriDof > 0) ? new int[6*TriDof] : nullptr;
for (int i = 1; i < 6; i++)
{
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
@@ -2181,7 +2191,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
}
}
const int QuadDof = L2_Elements[Geometry::SQUARE]->GetDof();
OtherDofOrd = new int[QuadDof];
OtherDofOrd = (QuadDof > 0) ? new int[QuadDof] : nullptr;
for (int j = 0; j < QuadDof; j++)
{
OtherDofOrd[j] = j; // for Or == 0
@@ -2225,7 +2235,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
const int PriDof = L2_Elements[Geometry::PRISM]->GetDof();
const int MaxDof = std::max(TetDof, std::max(PriDof, HexDof));
TetDofOrd[0] = new int[24*TetDof];
TetDofOrd[0] = (TetDof > 0) ? new int[24*TetDof] : nullptr;
for (int i = 1; i < 24; i++)
{
TetDofOrd[i] = TetDofOrd[i-1] + TetDof;
@@ -2314,7 +2324,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
}
}
}
OtherDofOrd = new int[MaxDof];
OtherDofOrd = (MaxDof > 0) ? new int[MaxDof] : nullptr;
for (int j = 0; j < MaxDof; j++)
{
OtherDofOrd[j] = j; // for Or == 0
@@ -2502,7 +2512,7 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
RT_Elements[Geometry::SEGMENT] = l2_seg;
RT_dof[Geometry::SEGMENT] = pp1;
SegDofOrd[0] = new int[2*pp1];
SegDofOrd[0] = (pp1 > 0) ? new int[2*pp1] : nullptr;
SegDofOrd[1] = SegDofOrd[0] + pp1;
for (int i = 0; i <= p; i++)
{
@@ -2523,7 +2533,7 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
RT_dof[Geometry::SQUARE] = pp1*pp1;
int TriDof = RT_dof[Geometry::TRIANGLE];
TriDofOrd[0] = new int[6*TriDof];
TriDofOrd[0] = (TriDof > 0) ? new int[6*TriDof] : nullptr;
for (int i = 1; i < 6; i++)
{
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
@@ -2553,7 +2563,7 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
}
int QuadDof = RT_dof[Geometry::SQUARE];
QuadDofOrd[0] = new int[8*QuadDof];
QuadDofOrd[0] = (QuadDof > 0) ? new int[8*QuadDof] : nullptr;
for (int i = 1; i < 8; i++)
{
QuadDofOrd[i] = QuadDofOrd[i-1] + QuadDof;
@@ -2749,7 +2759,7 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
ND_Elements[Geometry::SEGMENT] = new ND_SegmentElement(p, ob_type);
ND_dof[Geometry::SEGMENT] = p;
SegDofOrd[0] = new int[2*p];
SegDofOrd[0] = (p > 0) ? new int[2*p] : nullptr;
SegDofOrd[1] = SegDofOrd[0] + p;
for (int i = 0; i < p; i++)
{
@@ -2769,7 +2779,7 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
ND_dof[Geometry::TRIANGLE] = p*pm1;
int QuadDof = ND_dof[Geometry::SQUARE];
QuadDofOrd[0] = new int[8*QuadDof];
QuadDofOrd[0] = (QuadDof > 0) ? new int[8*QuadDof] : nullptr;
for (int i = 1; i < 8; i++)
{
QuadDofOrd[i] = QuadDofOrd[i-1] + QuadDof;
@@ -2813,7 +2823,7 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
}
int TriDof = ND_dof[Geometry::TRIANGLE];
TriDofOrd[0] = new int[6*TriDof];
TriDofOrd[0] = (TriDof > 0) ? new int[6*TriDof] : nullptr;
for (int i = 1; i < 6; i++)
{
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
@@ -2886,6 +2896,19 @@ ND_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
}
}
StatelessDofTransformation *
ND_FECollection::DofTransformationForGeometry(Geometry::Type GeomType) const
{
if (!Geometry::IsTensorProduct(GeomType) && this->GetOrder() > 1)
{
return FiniteElementForGeometry(GeomType)->GetDofTransformation();
}
else
{
return NULL;
}
}
const int *ND_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
int Or) const
{
@@ -3150,7 +3173,7 @@ ND_R2D_FECollection::ND_R2D_FECollection(const int p, const int dim,
ob_type);
ND_dof[Geometry::SEGMENT] = 2 * p - 1;
SegDofOrd[0] = new int[4 * p - 2];
SegDofOrd[0] = (4*p > 2) ? new int[4 * p - 2] : nullptr;
SegDofOrd[1] = SegDofOrd[0] + 2 * p - 1;
for (int i = 0; i < p; i++)
{
@@ -3334,7 +3357,7 @@ void RT_R2D_FECollection::InitFaces(const int p, const int dim,
RT_Elements[Geometry::SEGMENT] = l2_seg;
RT_dof[Geometry::SEGMENT] = pp1;
SegDofOrd[0] = new int[2*pp1];
SegDofOrd[0] = (pp1 > 0) ? new int[2*pp1] : nullptr;
SegDofOrd[1] = SegDofOrd[0] + pp1;
for (int i = 0; i <= p; i++)
{
+356 -291
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -26,6 +26,7 @@
#include "bilininteg.hpp"
#include "fespace.hpp"
#include "gridfunc.hpp"
#include "kdtree.hpp"
#include "linearform.hpp"
#include "nonlinearform.hpp"
#include "bilinearform.hpp"
+70 -25
View File
@@ -64,7 +64,7 @@ FiniteElementSpace::FiniteElementSpace()
face_dof(NULL),
NURBSext(NULL), own_ext(false),
DoFTrans(0), VDoFTrans(vdim, ordering),
cP(NULL), cR(NULL), cR_hp(NULL), cP_is_set(false),
cP_is_set(false),
Th(Operator::ANY_TYPE),
sequence(0), mesh_sequence(0), orders_changed(false), relaxed_hp(false)
{ }
@@ -123,24 +123,24 @@ void FiniteElementSpace::CopyProlongationAndRestriction(
if (fes.GetConformingProlongation() != NULL)
{
if (perm) { cP = Mult(*perm_mat, *fes.GetConformingProlongation()); }
else { cP = new SparseMatrix(*fes.GetConformingProlongation()); }
if (perm) { cP.reset(Mult(*perm_mat, *fes.GetConformingProlongation())); }
else { cP.reset(new SparseMatrix(*fes.GetConformingProlongation())); }
cP_is_set = true;
}
else if (perm != NULL)
{
cP = perm_mat;
cP.reset(perm_mat);
cP_is_set = true;
perm_mat = NULL;
}
if (fes.GetConformingRestriction() != NULL)
{
if (perm) { cR = Mult(*fes.GetConformingRestriction(), *perm_mat_tr); }
else { cR = new SparseMatrix(*fes.GetConformingRestriction()); }
if (perm) { cR.reset(Mult(*fes.GetConformingRestriction(), *perm_mat_tr)); }
else { cR.reset(new SparseMatrix(*fes.GetConformingRestriction())); }
}
else if (perm != NULL)
{
cR = perm_mat_tr;
cR.reset(perm_mat_tr);
perm_mat_tr = NULL;
}
@@ -309,6 +309,12 @@ FiniteElementSpace::GetBdrElementVDofs(int i, Array<int> &vdofs) const
}
}
void FiniteElementSpace::GetPatchVDofs(int i, Array<int> &vdofs) const
{
GetPatchDofs(i, vdofs);
DofsToVDofs(vdofs);
}
void FiniteElementSpace::GetFaceVDofs(int i, Array<int> &vdofs) const
{
GetFaceDofs(i, vdofs);
@@ -954,7 +960,10 @@ void FiniteElementSpace::BuildConformingInterpolation() const
if (FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS)
{
cP = cR = cR_hp = NULL; // will be treated as identities
cP.reset();
cR.reset();
cR_hp.reset();
R_transpose.reset();
return;
}
@@ -1108,12 +1117,15 @@ void FiniteElementSpace::BuildConformingInterpolation() const
// if all dofs are true dofs leave cP and cR NULL
if (n_true_dofs == ndofs)
{
cP = cR = cR_hp = NULL; // will be treated as identities
cP.reset();
cR.reset();
cR_hp.reset();
R_transpose.reset();
return;
}
// create the conforming prolongation matrix cP
cP = new SparseMatrix(ndofs, n_true_dofs);
cP.reset(new SparseMatrix(ndofs, n_true_dofs));
// create the conforming restriction matrix cR
int *cR_J;
@@ -1127,12 +1139,19 @@ void FiniteElementSpace::BuildConformingInterpolation() const
cR_A[i] = 1.0;
}
cR_I[n_true_dofs] = n_true_dofs;
cR = new SparseMatrix(cR_I, cR_J, cR_A, n_true_dofs, ndofs);
cR.reset(new SparseMatrix(cR_I, cR_J, cR_A, n_true_dofs, ndofs));
}
// In var. order spaces, create the restriction matrix cR_hp which is similar
// to cR, but has interpolation in the extra master edge/face DOFs.
cR_hp = IsVariableOrder() ? new SparseMatrix(n_true_dofs, ndofs) : NULL;
if (IsVariableOrder())
{
cR_hp.reset(new SparseMatrix(n_true_dofs, ndofs));
}
else
{
cR_hp.reset();
}
Array<bool> finalized(ndofs);
finalized = false;
@@ -1250,21 +1269,28 @@ const SparseMatrix* FiniteElementSpace::GetConformingProlongation() const
{
if (Conforming()) { return NULL; }
if (!cP_is_set) { BuildConformingInterpolation(); }
return cP;
return cP.get();
}
const SparseMatrix* FiniteElementSpace::GetConformingRestriction() const
{
if (Conforming()) { return NULL; }
if (!cP_is_set) { BuildConformingInterpolation(); }
return cR;
if (cR && !R_transpose) { R_transpose.reset(new TransposeOperator(*cR)); }
return cR.get();
}
const SparseMatrix* FiniteElementSpace::GetHpConformingRestriction() const
{
if (Conforming()) { return NULL; }
if (!cP_is_set) { BuildConformingInterpolation(); }
return IsVariableOrder() ? cR_hp : cR;
return IsVariableOrder() ? cR_hp.get() : cR.get();
}
const Operator *FiniteElementSpace::GetRestrictionTransposeOperator() const
{
GetRestrictionOperator(); // Ensure that R_transpose is built
return R_transpose.get();
}
int FiniteElementSpace::GetNConformingDofs() const
@@ -2195,7 +2221,10 @@ void FiniteElementSpace::Constructor(Mesh *mesh_, NURBSExtension *NURBSext_,
own_ext = 1;
}
UpdateNURBS();
cP = cR = cR_hp = NULL;
cP.reset();
cR.reset();
cR_hp.reset();
R_transpose.reset();
cP_is_set = false;
ConstructDoFTrans();
@@ -2357,6 +2386,7 @@ void FiniteElementSpace::Construct()
cR = NULL;
cR_hp = NULL;
cP_is_set = false;
R_transpose = NULL;
// 'Th' is initialized/destroyed before this method is called.
int dim = mesh->Dimension();
@@ -2801,11 +2831,24 @@ FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs) const
return DoFTrans[mesh->GetElementBaseGeometry(elem)];
}
void FiniteElementSpace::GetPatchDofs(int patch, Array<int> &dofs) const
{
MFEM_ASSERT(NURBSext,
"FiniteElementSpace::GetPatchDofs needs a NURBSExtension");
NURBSext->GetPatchDofs(patch, dofs);
}
const FiniteElement *FiniteElementSpace::GetFE(int i) const
{
if (i < 0 || !mesh->GetNE()) { return NULL; }
MFEM_VERIFY(i < mesh->GetNE(),
"Invalid element id " << i << ", maximum allowed " << mesh->GetNE()-1);
if (i < 0 || i >= mesh->GetNE())
{
if (mesh->GetNE() == 0)
{
MFEM_ABORT("Empty MPI partitions are not permitted!");
}
MFEM_ABORT("Invalid element id:" << i << "; minimum allowed:" << 0 <<
", maximum allowed:" << mesh->GetNE()-1);
}
const FiniteElement *FE =
fec->GetFE(mesh->GetElementGeometry(i), GetElementOrderImpl(i));
@@ -3205,9 +3248,10 @@ FiniteElementSpace::~FiniteElementSpace()
void FiniteElementSpace::Destroy()
{
delete cR;
delete cR_hp;
delete cP;
R_transpose.reset();
cR.reset();
cR_hp.reset();
cP.reset();
Th.Clear();
L2E_nat.Clear();
L2E_lex.Clear();
@@ -3220,6 +3264,7 @@ void FiniteElementSpace::Destroy()
{
delete x.second;
}
L2F.clear();
for (int i = 0; i < E2IFQ_array.Size(); i++)
{
delete E2IFQ_array[i];
@@ -3319,14 +3364,14 @@ void FiniteElementSpace::GetTrueTransferOperator(
switch (RP_case)
{
case 1:
T.Reset(new ProductOperator(cR, T.Ptr(), false, owner));
T.Reset(new ProductOperator(cR.get(), T.Ptr(), false, owner));
break;
case 2:
T.Reset(new ProductOperator(T.Ptr(), coarse_P, owner, false));
break;
case 3:
T.Reset(new TripleProductOperator(
cR, T.Ptr(), coarse_P, false, owner, false));
cR.get(), T.Ptr(), coarse_P, false, owner, false));
break;
}
}
@@ -3444,7 +3489,7 @@ void FiniteElementSpace::Update(bool want_transform)
if (cP && cR)
{
Th.SetOperatorOwner(false);
Th.Reset(new TripleProductOperator(cP, cR, Th.Ptr(),
Th.Reset(new TripleProductOperator(cP.get(), cR.get(), Th.Ptr(),
false, false, true));
}
break;
+42 -22
View File
@@ -214,7 +214,7 @@ class FaceQuadratureInterpolator;
@par
Clearly the notion of a @b vdof is relevant in each of the three contexts
mentioned above so extra care must be taken whenever @b vdim != 1 to ensure
that the @b edof, @b ldof, or @b tdof is being interpretted correctly.
that the @b edof, @b ldof, or @b tdof is being interpreted correctly.
*/
class FiniteElementSpace
{
@@ -277,12 +277,14 @@ protected:
/** Matrix representing the prolongation from the global conforming dofs to
a set of intermediate partially conforming dofs, e.g. the dofs associated
with a "cut" space on a non-conforming mesh. */
mutable SparseMatrix *cP; // owned
mutable std::unique_ptr<SparseMatrix> cP;
/// Conforming restriction matrix such that cR.cP=I.
mutable SparseMatrix *cR; // owned
mutable std::unique_ptr<SparseMatrix> cR;
/// A version of the conforming restriction matrix for variable-order spaces.
mutable SparseMatrix *cR_hp; // owned
mutable std::unique_ptr<SparseMatrix> cR_hp;
mutable bool cP_is_set;
/// Operator computing the action of the transpose of the restriction.
mutable std::unique_ptr<Operator> R_transpose;
/// Transformation to apply to GridFunctions after space Update().
OperatorHandle Th;
@@ -377,17 +379,6 @@ protected:
/// Return number of possible DOF variants for edge/face (var. order spaces).
int GetNVariants(int entity, int index) const;
/// Helper to encode a sign flip into a DOF index (for Hcurl/Hdiv shapes).
static inline int EncodeDof(int entity_base, int idx)
{ return (idx >= 0) ? (entity_base + idx) : (-1-(entity_base + (-1-idx))); }
/// Helpers to remove encoded sign from a DOF
static inline int DecodeDof(int dof)
{ return (dof >= 0) ? dof : (-1 - dof); }
static inline int DecodeDof(int dof, double& sign)
{ return (dof >= 0) ? (sign = 1, dof) : (sign = -1, (-1 - dof)); }
/// Helper to get vertex, edge or face DOFs (entity=0,1,2 resp.).
int GetEntityDofs(int entity, int index, Array<int> &dofs,
Geometry::Type master_geom = Geometry::INVALID,
@@ -603,10 +594,17 @@ public:
{ return GetConformingProlongation(); }
/// Return an operator that performs the transpose of GetRestrictionOperator
/** The returned operator is owned by the FiniteElementSpace. In serial this
is the same as GetProlongationMatrix() */
virtual const Operator *GetRestrictionTransposeOperator() const
{ return GetConformingProlongation(); }
/** The returned operator is owned by the FiniteElementSpace.
For a serial conforming space, this returns NULL, indicating the identity
operator.
For a parallel conforming space, this will return a matrix-free
(Device)ConformingProlongationOperator.
For a non-conforming mesh this will return a TransposeOperator wrapping
the restriction matrix. */
const Operator *GetRestrictionTransposeOperator() const;
/// An abstract operator that performs the same action as GetRestrictionMatrix
/** In some cases this is an optimized matrix-free implementation. The
@@ -822,6 +820,11 @@ public:
virtual DofTransformation *GetBdrElementDofs(int bel,
Array<int> &dofs) const;
/** @brief Returns indices of degrees of freedom for NURBS patch index
@a patch. Cartesian ordering is used, for the tensor-product degrees of
freedom. */
void GetPatchDofs(int patch, Array<int> &dofs) const;
/// @brief Returns the indices of the degrees of freedom for the specified
/// face, including the DOFs for the edges and the vertices of the face.
///
@@ -904,7 +907,7 @@ public:
/// changed in the forward mappings by passing a value for @a ndofs which
/// differs from that returned by GetNDofs().
///
/// @note Thse methods, with the exception of VDofToDof(), are designed to
/// @note These methods, with the exception of VDofToDof(), are designed to
/// produce the correctly encoded values when dof entries are negative,
/// see @ref ldof for more on negative dof indices.
///
@@ -985,6 +988,18 @@ public:
/// well on sets of @ref ldof "Local Dofs".
static void AdjustVDofs(Array<int> &vdofs);
/// Helper to encode a sign flip into a DOF index (for Hcurl/Hdiv shapes).
static inline int EncodeDof(int entity_base, int idx)
{ return (idx >= 0) ? (entity_base + idx) : (-1-(entity_base + (-1-idx))); }
/// Helper to return the DOF associated with a sign encoded DOF
static inline int DecodeDof(int dof)
{ return (dof >= 0) ? dof : (-1 - dof); }
/// Helper to determine the DOF and sign of a sign encoded DOF
static inline int DecodeDof(int dof, double& sign)
{ return (dof >= 0) ? (sign = 1, dof) : (sign = -1, (-1 - dof)); }
/// @anchor getvdof @name Local Vector DoF Access Members
/// These member functions produce arrays of local vector degree of freedom
/// indices, see @ref ldof and @ref vdof. These indices can be used to
@@ -994,7 +1009,7 @@ 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. The returned indexes are always ordered
/// not necessarily equal to 1. The returned indices are always ordered
/// byNODES, irrespective of whether the space is byNODES or byVDIM.
/// See also GetElementDofs().
///
@@ -1023,6 +1038,9 @@ public:
/// @note The returned object should NOT be deleted by the caller.
DofTransformation *GetBdrElementVDofs(int i, Array<int> &vdofs) const;
/// Returns indices of degrees of freedom in @a vdofs for NURBS patch @a i.
void GetPatchVDofs(int i, Array<int> &vdofs) const;
/// @brief Returns the indices of the degrees of freedom for the specified
/// face, including the DOFs for the edges and the vertices of the face.
///
@@ -1106,7 +1124,9 @@ public:
int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; }
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th element in the mesh object. */
associated with i'th element in the mesh object.
Note: The method has been updated to abort instead of returning NULL for
an empty partition. */
virtual const FiniteElement *GetFE(int i) const;
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
+3 -4
View File
@@ -27,7 +27,6 @@
#include <iostream>
#include <algorithm>
namespace mfem
{
@@ -341,7 +340,7 @@ int GridFunction::VectorDim() const
return fes->GetVDim();
}
return fes->GetVDim()*std::max(fes->GetMesh()->SpaceDimension(),
fe->GetVDim());
fe->GetRangeDim());
}
int GridFunction::CurlDim() const
@@ -1042,7 +1041,7 @@ void GridFunction::GetVectorValue(ElementTransformation &T,
else
{
int spaceDim = fes->GetMesh()->SpaceDimension();
int vdim = std::max(spaceDim, fe->GetVDim());
int vdim = std::max(spaceDim, fe->GetRangeDim());
DenseMatrix vshape(dof, vdim);
fe->CalcVShape(T, vshape);
val.SetSize(vdim);
@@ -1094,7 +1093,7 @@ void GridFunction::GetVectorValues(ElementTransformation &T,
else
{
int spaceDim = fes->GetMesh()->SpaceDimension();
int vdim = std::max(spaceDim, FElem->GetVDim());
int vdim = std::max(spaceDim, FElem->GetRangeDim());
DenseMatrix vshape(dof, vdim);
vals.SetSize(vdim, nip);
+3 -3
View File
@@ -1236,7 +1236,7 @@ void OversetFindPointsGSLIB::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++)
{
@@ -1256,7 +1256,7 @@ void OversetFindPointsGSLIB::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);
findptsms_2(gsl_code.GetData(), sizeof(unsigned int),
gsl_proc.GetData(), sizeof(unsigned int),
gsl_elem.GetData(), sizeof(unsigned int),
@@ -1270,7 +1270,7 @@ void OversetFindPointsGSLIB::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);
findptsms_3(gsl_code.GetData(), sizeof(unsigned int),
gsl_proc.GetData(), sizeof(unsigned int),
gsl_elem.GetData(), sizeof(unsigned int),
+11 -11
View File
@@ -28,8 +28,8 @@ static void EAConvectionAssemble1D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
@@ -38,7 +38,7 @@ static void EAConvectionAssemble1D(const int NE,
{
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 MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double r_Gi[MQ1];
double r_Bj[MQ1];
for (int q = 0; q < Q1D; q++)
@@ -80,8 +80,8 @@ static void EAConvectionAssemble2D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, NE);
@@ -90,8 +90,8 @@ static void EAConvectionAssemble2D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
@@ -157,8 +157,8 @@ static void EAConvectionAssemble3D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 3, NE);
@@ -167,8 +167,8 @@ static void EAConvectionAssemble3D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
+32 -32
View File
@@ -203,8 +203,8 @@ void PAConvectionApply2D(const int ne,
const int NE = ne;
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
@@ -216,8 +216,8 @@ void PAConvectionApply2D(const int ne,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double u[max_D1D][max_D1D];
for (int dy = 0; dy < D1D; ++dy)
@@ -323,8 +323,8 @@ void SmemPAConvectionApply2D(const int ne,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
@@ -338,8 +338,8 @@ void SmemPAConvectionApply2D(const int ne,
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
// constexpr int MDQ = (max_Q1D > max_D1D) ? max_Q1D : max_D1D;
MFEM_SHARED double u[NBZ][max_D1D][max_D1D];
MFEM_FOREACH_THREAD(dy,y,D1D)
@@ -450,8 +450,8 @@ void PAConvectionApply3D(const int ne,
const int NE = ne;
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
@@ -463,8 +463,8 @@ void PAConvectionApply3D(const int ne,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double u[max_D1D][max_D1D][max_D1D];
for (int dz = 0; dz < D1D; ++dz)
@@ -631,8 +631,8 @@ void SmemPAConvectionApply3D(const int ne,
const int NE = ne;
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
@@ -644,8 +644,8 @@ void SmemPAConvectionApply3D(const int ne,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int max_DQ = (max_Q1D > max_D1D) ? max_Q1D : max_D1D;
MFEM_SHARED double sm0[max_DQ*max_DQ*max_DQ];
MFEM_SHARED double sm1[max_DQ*max_DQ*max_DQ];
@@ -835,8 +835,8 @@ void PAConvectionApplyT2D(const int ne,
const int NE = ne;
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto Gt = Reshape(gt.Read(), D1D, Q1D);
@@ -848,8 +848,8 @@ void PAConvectionApplyT2D(const int ne,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double u[max_D1D][max_D1D];
for (int dy = 0; dy < D1D; ++dy)
@@ -951,8 +951,8 @@ void SmemPAConvectionApplyT2D(const int ne,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto Gt = Reshape(gt.Read(), D1D, Q1D);
@@ -966,8 +966,8 @@ void SmemPAConvectionApplyT2D(const int ne,
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED double u[NBZ][max_D1D][max_D1D];
MFEM_FOREACH_THREAD(dy,y,D1D)
{
@@ -1073,8 +1073,8 @@ void PAConvectionApplyT3D(const int ne,
const int NE = ne;
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto Gt = Reshape(gt.Read(), D1D, Q1D);
@@ -1086,8 +1086,8 @@ void PAConvectionApplyT3D(const int ne,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double u[max_D1D][max_D1D][max_D1D];
for (int dz = 0; dz < D1D; ++dz)
@@ -1249,8 +1249,8 @@ void SmemPAConvectionApplyT3D(const int ne,
const int NE = ne;
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto Gt = Reshape(gt.Read(), D1D, Q1D);
@@ -1262,8 +1262,8 @@ void SmemPAConvectionApplyT3D(const int ne,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int max_DQ = (max_Q1D > max_D1D) ? max_Q1D : max_D1D;
MFEM_SHARED double sm0[3*max_DQ*max_DQ*max_DQ];
MFEM_SHARED double sm1[3*max_DQ*max_DQ*max_DQ];
+12 -12
View File
@@ -83,8 +83,8 @@ static void EADGTraceAssemble2DInt(const int NF,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, 2, NF);
@@ -138,8 +138,8 @@ static void EADGTraceAssemble2DBdr(const int NF,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
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);
@@ -181,8 +181,8 @@ static void EADGTraceAssemble3DInt(const int NF,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, D1D, D1D, 2, NF);
@@ -191,8 +191,8 @@ static void EADGTraceAssemble3DInt(const int NF,
{
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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
@@ -278,8 +278,8 @@ static void EADGTraceAssemble3DBdr(const int NF,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
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);
@@ -287,8 +287,8 @@ static void EADGTraceAssemble3DBdr(const int NF,
{
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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
+24 -24
View File
@@ -258,8 +258,8 @@ void PADGTraceApply2D(const int NF,
const int VDIM = 1;
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, 2, 2, NF);
@@ -272,8 +272,8 @@ void PADGTraceApply2D(const int NF,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double u0[max_D1D][VDIM];
double u1[max_D1D][VDIM];
for (int d = 0; d < D1D; d++)
@@ -349,8 +349,8 @@ void PADGTraceApply3D(const int NF,
const int VDIM = 1;
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
@@ -363,8 +363,8 @@ void PADGTraceApply3D(const int NF,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double u0[max_D1D][max_D1D][VDIM];
double u1[max_D1D][max_D1D][VDIM];
for (int d1 = 0; d1 < D1D; d1++)
@@ -494,8 +494,8 @@ void SmemPADGTraceApply3D(const int NF,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
@@ -509,8 +509,8 @@ void SmemPADGTraceApply3D(const int NF,
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED double u0[NBZ][max_D1D][max_D1D];
MFEM_SHARED double u1[NBZ][max_D1D][max_D1D];
MFEM_FOREACH_THREAD(d1,x,D1D)
@@ -659,8 +659,8 @@ void PADGTraceApplyTranspose2D(const int NF,
const int VDIM = 1;
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, 2, 2, NF);
@@ -673,8 +673,8 @@ void PADGTraceApplyTranspose2D(const int NF,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double u0[max_D1D][VDIM];
double u1[max_D1D][VDIM];
for (int d = 0; d < D1D; d++)
@@ -755,8 +755,8 @@ void PADGTraceApplyTranspose3D(const int NF,
const int VDIM = 1;
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
@@ -769,8 +769,8 @@ void PADGTraceApplyTranspose3D(const int NF,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double u0[max_D1D][max_D1D][VDIM];
double u1[max_D1D][max_D1D][VDIM];
for (int d1 = 0; d1 < D1D; d1++)
@@ -911,8 +911,8 @@ void SmemPADGTraceApplyTranspose3D(const int NF,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
@@ -926,8 +926,8 @@ void SmemPADGTraceApplyTranspose3D(const int NF,
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED double u0[NBZ][max_D1D][max_D1D];
MFEM_SHARED double u1[NBZ][max_D1D][max_D1D];
MFEM_FOREACH_THREAD(d1,x,D1D)
+11 -11
View File
@@ -28,8 +28,8 @@ static void EADiffusionAssemble1D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto A = Reshape(eadata.ReadWrite(), D1D, D1D, NE);
@@ -37,7 +37,7 @@ static void EADiffusionAssemble1D(const int NE,
{
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 MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double r_Gi[MQ1];
double r_Gj[MQ1];
for (int q = 0; q < Q1D; q++)
@@ -79,8 +79,8 @@ static void EADiffusionAssemble2D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 3, NE);
@@ -89,8 +89,8 @@ static void EADiffusionAssemble2D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
@@ -156,8 +156,8 @@ static void EADiffusionAssemble3D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 6, NE);
@@ -166,8 +166,8 @@ static void EADiffusionAssemble3D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
+42 -42
View File
@@ -98,8 +98,8 @@ inline void PADiffusionDiagonal2D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
// note the different shape for D, if this is a symmetric matrix we only
@@ -110,8 +110,8 @@ inline void PADiffusionDiagonal2D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
// gradphi \cdot Q \gradphi has four terms
double QD0[MQ1][MD1];
double QD1[MQ1][MD1];
@@ -165,10 +165,10 @@ inline void SmemPADiffusionDiagonal2D(const int NE,
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 int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
MFEM_VERIFY(D1D <= max_d1d, "");
MFEM_VERIFY(Q1D <= max_q1d, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto g = Reshape(g_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
@@ -179,8 +179,8 @@ inline void SmemPADiffusionDiagonal2D(const int NE,
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;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED double BG[2][MQ1*MD1];
double (*B)[MD1] = (double (*)[MD1]) (BG+0);
double (*G)[MD1] = (double (*)[MD1]) (BG+1);
@@ -260,10 +260,10 @@ inline void PADiffusionDiagonal3D(const int NE,
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, "");
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
MFEM_VERIFY(D1D <= max_d1d, "");
MFEM_VERIFY(Q1D <= max_q1d, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Q = Reshape(d.Read(), Q1D*Q1D*Q1D, symmetric ? 6 : 9, NE);
@@ -272,8 +272,8 @@ inline void PADiffusionDiagonal3D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double QQD[MQ1][MQ1][MD1];
double QDD[MQ1][MD1][MD1];
for (int i = 0; i < DIM; ++i)
@@ -361,10 +361,10 @@ inline void SmemPADiffusionDiagonal3D(const int NE,
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, "");
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
MFEM_VERIFY(D1D <= max_d1d, "");
MFEM_VERIFY(Q1D <= max_q1d, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto g = Reshape(g_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D*Q1D*Q1D, symmetric ? 6 : 9, NE);
@@ -374,8 +374,8 @@ inline void SmemPADiffusionDiagonal3D(const int NE,
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 : MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED double BG[2][MQ1*MD1];
double (*B)[MD1] = (double (*)[MD1]) (BG+0);
double (*G)[MD1] = (double (*)[MD1]) (BG+1);
@@ -521,8 +521,8 @@ inline void PADiffusionApply2D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b_.Read(), Q1D, D1D);
auto G = Reshape(g_.Read(), Q1D, D1D);
auto Bt = Reshape(bt_.Read(), D1D, Q1D);
@@ -535,8 +535,8 @@ inline void PADiffusionApply2D(const int NE,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double grad[max_Q1D][max_Q1D][2];
for (int qy = 0; qy < Q1D; ++qy)
@@ -642,10 +642,10 @@ inline void SmemPADiffusionApply2D(const int NE,
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 int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
MFEM_VERIFY(D1D <= max_d1d, "");
MFEM_VERIFY(Q1D <= max_q1d, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto g = Reshape(g_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
@@ -657,8 +657,8 @@ inline void SmemPADiffusionApply2D(const int NE,
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;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED double sBG[2][MQ1*MD1];
double (*B)[MD1] = (double (*)[MD1]) (sBG+0);
double (*G)[MD1] = (double (*)[MD1]) (sBG+1);
@@ -800,8 +800,8 @@ inline void PADiffusionApply3D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
@@ -813,8 +813,8 @@ inline void PADiffusionApply3D(const int NE,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double grad[max_Q1D][max_Q1D][max_Q1D][3];
for (int qz = 0; qz < Q1D; ++qz)
{
@@ -992,10 +992,10 @@ inline void SmemPADiffusionApply3D(const int NE,
{
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, "");
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
MFEM_VERIFY(D1D <= max_d1d, "");
MFEM_VERIFY(Q1D <= max_q1d, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto g = Reshape(g_.Read(), Q1D, D1D);
auto d = Reshape(d_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
@@ -1005,8 +1005,8 @@ inline void SmemPADiffusionApply3D(const int NE,
{
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;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
MFEM_SHARED double sBG[2][MQ1*MD1];
double (*B)[MD1] = (double (*)[MD1]) (sBG+0);
+241
View File
@@ -12,6 +12,7 @@
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "../../mesh/nurbs.hpp"
#include "../ceed/integrators/diffusion/diffusion.hpp"
#include "bilininteg_diffusion_kernels.hpp"
@@ -74,6 +75,29 @@ void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
ir->GetWeights(), geom->J, coeff, pa_data);
}
void DiffusionIntegrator::AssembleNURBSPA(const FiniteElementSpace &fes)
{
fespace = &fes;
Mesh *mesh = fes.GetMesh();
dim = mesh->Dimension();
MFEM_VERIFY(3 == dim, "Only 3D so far");
numPatches = mesh->NURBSext->GetNP();
for (int p=0; p<numPatches; ++p)
{
AssemblePatchPA(p, fes);
}
}
void DiffusionIntegrator::AssemblePatchPA(const int patch,
const FiniteElementSpace &fes)
{
Mesh *mesh = fes.GetMesh();
SetupPatchBasisData(mesh, patch);
SetupPatchPA(patch, mesh); // For full quadrature, unitWeights = false
}
void DiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
{
if (DeviceCanUseCeed())
@@ -115,4 +139,221 @@ void DiffusionIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const
}
}
// This version uses full 1D quadrature rules, taking into account the
// minimum interaction between basis functions and integration points.
void DiffusionIntegrator::AddMultPatchPA(const int patch, const Vector &x,
Vector &y) const
{
MFEM_VERIFY(3 == dim, "Only 3D so far");
const Array<int>& Q1D = pQ1D[patch];
const Array<int>& D1D = pD1D[patch];
const std::vector<Array2D<double>>& B = pB[patch];
const std::vector<Array2D<double>>& G = pG[patch];
const IntArrayVar2D& minD = pminD[patch];
const IntArrayVar2D& maxD = pmaxD[patch];
const IntArrayVar2D& minQ = pminQ[patch];
const IntArrayVar2D& maxQ = pmaxQ[patch];
auto X = Reshape(x.Read(), D1D[0], D1D[1], D1D[2]);
auto Y = Reshape(y.ReadWrite(), D1D[0], D1D[1], D1D[2]);
const auto qd = Reshape(pa_data.Read(), Q1D[0]*Q1D[1]*Q1D[2],
(symmetric ? 6 : 9));
// NOTE: the following is adapted from AssemblePatchMatrix_fullQuadrature
std::vector<Array3D<double>> grad(dim);
// TODO: Can an optimal order of dimensions be determined, for each patch?
Array3D<double> gradXY(3, std::max(Q1D[0], D1D[0]), std::max(Q1D[1], D1D[1]));
Array2D<double> gradX(3, std::max(Q1D[0], D1D[0]));
for (int d=0; d<dim; ++d)
{
grad[d].SetSize(Q1D[0], Q1D[1], Q1D[2]);
for (int qz = 0; qz < Q1D[2]; ++qz)
{
for (int qy = 0; qy < Q1D[1]; ++qy)
{
for (int qx = 0; qx < Q1D[0]; ++qx)
{
grad[d](qx,qy,qz) = 0.0;
}
}
}
}
for (int dz = 0; dz < D1D[2]; ++dz)
{
for (int qy = 0; qy < Q1D[1]; ++qy)
{
for (int qx = 0; qx < Q1D[0]; ++qx)
{
for (int d=0; d<dim; ++d)
{
gradXY(d,qx,qy) = 0.0;
}
}
}
for (int dy = 0; dy < D1D[1]; ++dy)
{
for (int qx = 0; qx < Q1D[0]; ++qx)
{
gradX(0,qx) = 0.0;
gradX(1,qx) = 0.0;
}
for (int dx = 0; dx < D1D[0]; ++dx)
{
const double s = X(dx,dy,dz);
for (int qx = minD[0][dx]; qx <= maxD[0][dx]; ++qx)
{
gradX(0,qx) += s * B[0](qx,dx);
gradX(1,qx) += s * G[0](qx,dx);
}
}
for (int qy = minD[1][dy]; qy <= maxD[1][dy]; ++qy)
{
const double wy = B[1](qy,dy);
const double wDy = G[1](qy,dy);
// This full range of qx values is generally necessary.
for (int qx = 0; qx < Q1D[0]; ++qx)
{
const double wx = gradX(0,qx);
const double wDx = gradX(1,qx);
gradXY(0,qx,qy) += wDx * wy;
gradXY(1,qx,qy) += wx * wDy;
gradXY(2,qx,qy) += wx * wy;
}
}
}
for (int qz = minD[2][dz]; qz <= maxD[2][dz]; ++qz)
{
const double wz = B[2](qz,dz);
const double wDz = G[2](qz,dz);
for (int qy = 0; qy < Q1D[1]; ++qy)
{
for (int qx = 0; qx < Q1D[0]; ++qx)
{
grad[0](qx,qy,qz) += gradXY(0,qx,qy) * wz;
grad[1](qx,qy,qz) += gradXY(1,qx,qy) * wz;
grad[2](qx,qy,qz) += gradXY(2,qx,qy) * wDz;
}
}
}
}
for (int qz = 0; qz < Q1D[2]; ++qz)
{
for (int qy = 0; qy < Q1D[1]; ++qy)
{
for (int qx = 0; qx < Q1D[0]; ++qx)
{
const int q = qx + ((qy + (qz * Q1D[1])) * Q1D[0]);
const double O00 = qd(q,0);
const double O01 = qd(q,1);
const double O02 = qd(q,2);
const double O10 = symmetric ? O01 : qd(q,3);
const double O11 = symmetric ? qd(q,3) : qd(q,4);
const double O12 = symmetric ? qd(q,4) : qd(q,5);
const double O20 = symmetric ? O02 : qd(q,6);
const double O21 = symmetric ? O12 : qd(q,7);
const double O22 = symmetric ? qd(q,5) : qd(q,8);
const double grad0 = grad[0](qx,qy,qz);
const double grad1 = grad[1](qx,qy,qz);
const double grad2 = grad[2](qx,qy,qz);
grad[0](qx,qy,qz) = (O00*grad0)+(O01*grad1)+(O02*grad2);
grad[1](qx,qy,qz) = (O10*grad0)+(O11*grad1)+(O12*grad2);
grad[2](qx,qy,qz) = (O20*grad0)+(O21*grad1)+(O22*grad2);
} // qx
} // qy
} // qz
for (int qz = 0; qz < Q1D[2]; ++qz)
{
for (int dy = 0; dy < D1D[1]; ++dy)
{
for (int dx = 0; dx < D1D[0]; ++dx)
{
for (int d=0; d<3; ++d)
{
gradXY(d,dx,dy) = 0.0;
}
}
}
for (int qy = 0; qy < Q1D[1]; ++qy)
{
for (int dx = 0; dx < D1D[0]; ++dx)
{
for (int d=0; d<3; ++d)
{
gradX(d,dx) = 0.0;
}
}
for (int qx = 0; qx < Q1D[0]; ++qx)
{
const double gX = grad[0](qx,qy,qz);
const double gY = grad[1](qx,qy,qz);
const double gZ = grad[2](qx,qy,qz);
for (int dx = minQ[0][qx]; dx <= maxQ[0][qx]; ++dx)
{
const double wx = B[0](qx,dx);
const double wDx = G[0](qx,dx);
gradX(0,dx) += gX * wDx;
gradX(1,dx) += gY * wx;
gradX(2,dx) += gZ * wx;
}
}
for (int dy = minQ[1][qy]; dy <= maxQ[1][qy]; ++dy)
{
const double wy = B[1](qy,dy);
const double wDy = G[1](qy,dy);
for (int dx = 0; dx < D1D[0]; ++dx)
{
gradXY(0,dx,dy) += gradX(0,dx) * wy;
gradXY(1,dx,dy) += gradX(1,dx) * wDy;
gradXY(2,dx,dy) += gradX(2,dx) * wy;
}
}
}
for (int dz = minQ[2][qz]; dz <= maxQ[2][qz]; ++dz)
{
const double wz = B[2](qz,dz);
const double wDz = G[2](qz,dz);
for (int dy = 0; dy < D1D[1]; ++dy)
{
for (int dx = 0; dx < D1D[0]; ++dx)
{
Y(dx,dy,dz) +=
((gradXY(0,dx,dy) * wz) +
(gradXY(1,dx,dy) * wz) +
(gradXY(2,dx,dy) * wDz));
}
}
} // dz
} // qz
}
void DiffusionIntegrator::AddMultNURBSPA(const Vector &x, Vector &y) const
{
Vector xp, yp;
for (int p=0; p<numPatches; ++p)
{
Array<int> vdofs;
fespace->GetPatchVDofs(p, vdofs);
x.GetSubVector(vdofs, xp);
yp.SetSize(vdofs.Size());
yp = 0.0;
AddMultPatchPA(p, xp, yp);
y.AddElementVector(vdofs, yp);
}
}
} // namespace mfem
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -229,9 +229,9 @@ static void PAGradientApply2D(const int NE,
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, TR_D1D);
auto G = Reshape(g.Read(), Q1D, TR_D1D);
auto Bt = Reshape(bt.Read(), TE_D1D, Q1D);
@@ -245,8 +245,8 @@ static void PAGradientApply2D(const int NE,
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = 2;
// the following variables are evaluated at compile time
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double grad[max_Q1D][max_Q1D][VDIM];
for (int qy = 0; qy < Q1D; ++qy)
@@ -359,9 +359,9 @@ static void PAGradientApply3D(const int NE,
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, TR_D1D);
auto G = Reshape(g.Read(), Q1D, TR_D1D);
auto Bt = Reshape(bt.Read(), TE_D1D, Q1D);
@@ -375,8 +375,8 @@ static void PAGradientApply3D(const int NE,
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = 3;
// the following variables are evaluated at compile time
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double grad[max_Q1D][max_Q1D][max_Q1D][VDIM];
for (int qz = 0; qz < Q1D; ++qz)
@@ -555,11 +555,11 @@ static void SmemPAGradientApply3D(const int NE,
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TR_D1D <= Q1D, "");
MFEM_VERIFY(TE_D1D <= Q1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto b = Reshape(b_.Read(), Q1D, TR_D1D);
auto g = Reshape(g_.Read(), Q1D, TR_D1D);
@@ -575,9 +575,9 @@ static void SmemPAGradientApply3D(const int NE,
const int D1DR = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int D1DE = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1R = T_TR_D1D ? T_TR_D1D : MAX_D1D;
constexpr int MD1E = T_TE_D1D ? T_TE_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int MD1R = T_TR_D1D ? T_TR_D1D : DofQuadLimits::MAX_D1D;
constexpr int MD1E = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
constexpr int MD1 = MD1E > MD1R ? MD1E : MD1R;
constexpr int MDQ = MQ1 > MD1 ? MQ1 : MD1;
MFEM_SHARED double sBG[2][MQ1*MD1];
+35 -29
View File
@@ -26,9 +26,6 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
const Vector &pa_data,
Vector &diag)
{
constexpr static int VDIM = 2;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(bc.Read(), Q1D, D1D);
auto op = Reshape(pa_data.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
@@ -36,6 +33,9 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y components
@@ -83,11 +83,10 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
const Vector &pa_data,
Vector &diag)
{
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");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
@@ -97,6 +96,8 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
@@ -158,10 +159,6 @@ void PAHcurlMassApply2D(const int D1D,
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 Bo = Reshape(bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(bc.Read(), Q1D, D1D);
auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
@@ -172,6 +169,10 @@ void PAHcurlMassApply2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
double mass[MAX_Q1D][MAX_Q1D][VDIM];
for (int qy = 0; qy < Q1D; ++qy)
@@ -288,11 +289,10 @@ void PAHcurlMassApply3D(const int D1D,
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");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
@@ -305,6 +305,9 @@ void PAHcurlMassApply3D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
for (int qz = 0; qz < Q1D; ++qz)
@@ -604,9 +607,6 @@ void PACurlCurlAssembleDiagonal2D(const int D1D,
const Vector &pa_data,
Vector &diag)
{
constexpr static int VDIM = 2;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
auto Gc = Reshape(gc.Read(), Q1D, D1D);
auto op = Reshape(pa_data.Read(), Q1D, Q1D, NE);
@@ -614,6 +614,9 @@ void PACurlCurlAssembleDiagonal2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y components
@@ -661,9 +664,6 @@ void PACurlCurlApply2D(const int D1D,
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 Bo = Reshape(bo.Read(), Q1D, D1D-1);
auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
@@ -675,6 +675,10 @@ void PACurlCurlApply2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
double curl[MAX_Q1D][MAX_Q1D];
// curl[qy][qx] will be computed as du_y/dx - du_x/dy
@@ -824,9 +828,6 @@ void PAHcurlL2Apply2D(const int D1D,
const Vector &x, // trial = H(curl)
Vector &y) // test = L2 or H1
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
const int H1 = (D1Dtest == D1D);
MFEM_VERIFY(y.Size() == NE*D1Dtest*D1Dtest, "Test vector of wrong dimension");
@@ -841,6 +842,10 @@ void PAHcurlL2Apply2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
double curl[MAX_Q1D][MAX_Q1D];
// curl[qy][qx] will be computed as du_y/dx - du_x/dy
@@ -939,9 +944,6 @@ void PAHcurlL2ApplyTranspose2D(const int D1D,
const Vector &x, // trial = H(curl)
Vector &y) // test = L2 or H1
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
const int H1 = (D1Dtest == D1D);
MFEM_VERIFY(x.Size() == NE*D1Dtest*D1Dtest, "Test vector of wrong dimension");
@@ -956,6 +958,10 @@ void PAHcurlL2ApplyTranspose2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
double mass[MAX_Q1D][MAX_Q1D];
// Zero-order term in L2 or H1 test space
+60 -40
View File
@@ -59,8 +59,10 @@ inline void SmemPAHcurlMassAssembleDiagonal3D(const int d1d,
const Vector &pa_data,
Vector &diag)
{
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -72,8 +74,8 @@ inline void SmemPAHcurlMassAssembleDiagonal3D(const int d1d,
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
constexpr int VDIM = 3;
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -218,8 +220,10 @@ inline void SmemPAHcurlMassApply3D(const int d1d,
const Vector &x,
Vector &y)
{
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -234,8 +238,8 @@ inline void SmemPAHcurlMassApply3D(const int d1d,
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
constexpr int VDIM = 3;
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -441,8 +445,10 @@ inline void PACurlCurlAssembleDiagonal3D(const int d1d,
const Vector &pa_data,
Vector &diag)
{
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -476,8 +482,8 @@ inline void PACurlCurlAssembleDiagonal3D(const int d1d,
// which may be non-symmetric depending on a possibly non-symmetric matrix coefficient.
constexpr int VDIM = 3;
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -635,8 +641,10 @@ inline void SmemPACurlCurlAssembleDiagonal3D(const int d1d,
const Vector &pa_data,
Vector &diag)
{
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -667,8 +675,8 @@ inline void SmemPACurlCurlAssembleDiagonal3D(const int d1d,
// 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;
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -848,8 +856,10 @@ inline void PACurlCurlApply3D(const int d1d,
const Vector &x,
Vector &y)
{
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -874,8 +884,8 @@ inline void PACurlCurlApply3D(const int d1d,
// 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;
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -1369,8 +1379,10 @@ inline void SmemPACurlCurlApply3D(const int d1d,
const Vector &x,
Vector &y)
{
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -1392,8 +1404,8 @@ inline void SmemPACurlCurlApply3D(const int d1d,
auto device_kernel = [=] MFEM_DEVICE (int e)
{
constexpr int VDIM = 3;
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -1738,8 +1750,10 @@ inline void PAHcurlL2Apply3D(const int d1d,
const Vector &x,
Vector &y)
{
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -1764,8 +1778,8 @@ inline void PAHcurlL2Apply3D(const int d1d,
// 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;
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -2107,8 +2121,10 @@ inline void SmemPAHcurlL2Apply3D(const int d1d,
const Vector &x,
Vector &y)
{
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -2123,8 +2139,8 @@ inline void SmemPAHcurlL2Apply3D(const int d1d,
{
constexpr int VDIM = 3;
constexpr int maxCoeffDim = 9;
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -2425,8 +2441,10 @@ inline void PAHcurlL2ApplyTranspose3D(const int d1d,
Vector &y)
{
// See PAHcurlL2Apply3D for comments.
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -2442,8 +2460,8 @@ inline void PAHcurlL2ApplyTranspose3D(const int d1d,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr int VDIM = 3;
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -2791,8 +2809,10 @@ inline void SmemPAHcurlL2ApplyTranspose3D(const int d1d,
const Vector &x,
Vector &y)
{
MFEM_VERIFY(T_D1D || d1d <= HCURL_MAX_D1D, "Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= HCURL_MAX_Q1D, "Error: q1d > HCURL_MAX_Q1D");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -2807,8 +2827,8 @@ inline void SmemPAHcurlL2ApplyTranspose3D(const int d1d,
{
constexpr int VDIM = 3;
constexpr int maxCoeffDim = 9;
constexpr int MD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
+15 -13
View File
@@ -224,11 +224,10 @@ void PAHcurlHdivMassApply2D(const int D1D,
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");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 2;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
@@ -244,6 +243,8 @@ void PAHcurlHdivMassApply2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
double mass[MAX_Q1D][MAX_Q1D][VDIM];
for (int qy = 0; qy < Q1D; ++qy)
@@ -323,7 +324,7 @@ void PAHcurlHdivMassApply2D(const int D1D,
for (int qy = 0; qy < Q1D; ++qy)
{
double massX[HDIV_MAX_D1D];
double massX[DofQuadLimits::HDIV_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0.0;
@@ -370,11 +371,10 @@ void PAHcurlHdivMassApply3D(const int D1D,
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");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
@@ -395,6 +395,8 @@ void PAHcurlHdivMassApply3D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
for (int qz = 0; qz < Q1D; ++qz)
@@ -507,7 +509,7 @@ void PAHcurlHdivMassApply3D(const int D1D,
for (int qz = 0; qz < Q1D; ++qz)
{
double massXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
double massXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z test components
@@ -528,7 +530,7 @@ void PAHcurlHdivMassApply3D(const int D1D,
}
for (int qy = 0; qy < Q1D; ++qy)
{
double massX[HDIV_MAX_D1D];
double massX[DofQuadLimits::HDIV_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0.0;
+16 -12
View File
@@ -92,10 +92,12 @@ inline void PAHcurlHdivApply3D(const int d1d,
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");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_D1D_TEST || d1dtest <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1dtest > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int D1Dtest = T_D1D_TEST ? T_D1D_TEST : d1dtest;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -120,8 +122,8 @@ inline void PAHcurlHdivApply3D(const int d1d,
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;
DofQuadLimits::HCURL_MAX_D1D; // Assuming HDIV_MAX_D1D <= HCURL_MAX_D1D
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::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;
@@ -459,10 +461,12 @@ inline void PAHcurlHdivApplyTranspose3D(const int d1d,
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");
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_D1D_TEST || d1dtest <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1dtest > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int D1Dtest = T_D1D_TEST ? T_D1D_TEST : d1dtest;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -487,8 +491,8 @@ inline void PAHcurlHdivApplyTranspose3D(const int d1d,
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;
DofQuadLimits::HCURL_MAX_D1D; // Assuming HDIV_MAX_D1D <= HCURL_MAX_D1D
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::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;
+80 -65
View File
@@ -176,9 +176,6 @@ void PAHdivMassAssembleDiagonal2D(const int D1D,
const Vector &op_,
Vector &diag_)
{
constexpr static int VDIM = 2;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
@@ -186,6 +183,9 @@ void PAHdivMassAssembleDiagonal2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y components
@@ -232,8 +232,10 @@ void PAHdivMassAssembleDiagonal3D(const int D1D,
const Vector &op_,
Vector &diag_)
{
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
"Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
"Error: Q1D > HDIV_MAX_Q1D");
constexpr static int VDIM = 3;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
@@ -254,7 +256,7 @@ void PAHdivMassAssembleDiagonal3D(const int D1D,
const int opc = (c == 0) ? 0 : ((c == 1) ? (symmetric ? 3 : 4) :
(symmetric ? 5 : 8));
double mass[HDIV_MAX_Q1D];
double mass[DofQuadLimits::HDIV_MAX_Q1D];
for (int dz = 0; dz < D1Dz; ++dz)
{
@@ -347,10 +349,6 @@ void PAHdivMassApply2D(const int D1D,
const Vector &x_,
Vector &y_)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HDIV_MAX_D1D;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
@@ -361,6 +359,10 @@ void PAHdivMassApply2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
double mass[MAX_Q1D][MAX_Q1D][VDIM];
for (int qy = 0; qy < Q1D; ++qy)
@@ -478,8 +480,10 @@ void PAHdivMassApply3D(const int D1D,
const Vector &x_,
Vector &y_)
{
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
"Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
"Error: Q1D > HDIV_MAX_Q1D");
constexpr static int VDIM = 3;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
@@ -492,7 +496,7 @@ void PAHdivMassApply3D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
double mass[HDIV_MAX_Q1D][HDIV_MAX_Q1D][HDIV_MAX_Q1D][VDIM];
double mass[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][VDIM];
for (int qz = 0; qz < Q1D; ++qz)
{
@@ -518,7 +522,7 @@ void PAHdivMassApply3D(const int D1D,
for (int dz = 0; dz < D1Dz; ++dz)
{
double massXY[HDIV_MAX_Q1D][HDIV_MAX_Q1D];
double massXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
@@ -529,7 +533,7 @@ void PAHdivMassApply3D(const int D1D,
for (int dy = 0; dy < D1Dy; ++dy)
{
double massX[HDIV_MAX_Q1D];
double massX[DofQuadLimits::HDIV_MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] = 0.0;
@@ -600,7 +604,7 @@ void PAHdivMassApply3D(const int D1D,
for (int qz = 0; qz < Q1D; ++qz)
{
double massXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
double massXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
osc = 0;
@@ -619,7 +623,7 @@ void PAHdivMassApply3D(const int D1D,
}
for (int qy = 0; qy < Q1D; ++qy)
{
double massX[HDIV_MAX_D1D];
double massX[DofQuadLimits::HDIV_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0;
@@ -730,9 +734,6 @@ void PADivDivAssembleDiagonal2D(const int D1D,
const Vector &op_,
Vector &diag_)
{
constexpr static int VDIM = 2;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
@@ -740,6 +741,9 @@ void PADivDivAssembleDiagonal2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y components
@@ -786,8 +790,10 @@ void PADivDivAssembleDiagonal3D(const int D1D,
const Vector &op_,
Vector &diag_)
{
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
"Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
"Error: Q1D > HDIV_MAX_Q1D");
constexpr static int VDIM = 3;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
@@ -809,7 +815,7 @@ void PADivDivAssembleDiagonal3D(const int D1D,
{
for (int dy = 0; dy < D1Dy; ++dy)
{
double a[HDIV_MAX_Q1D];
double a[DofQuadLimits::HDIV_MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
@@ -855,10 +861,6 @@ void PADivDivApply2D(const int D1D,
const Vector &x_,
Vector &y_)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HDIV_MAX_D1D;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
@@ -869,6 +871,10 @@ void PADivDivApply2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
double div[MAX_Q1D][MAX_Q1D];
// div[qy][qx] will be computed as du_x/dx + du_y/dy
@@ -974,8 +980,10 @@ void PADivDivApply3D(const int D1D,
const Vector &x_,
Vector &y_)
{
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
"Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
"Error: Q1D > HDIV_MAX_Q1D");
constexpr static int VDIM = 3;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
@@ -988,7 +996,7 @@ void PADivDivApply3D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
double div[HDIV_MAX_Q1D][HDIV_MAX_Q1D][HDIV_MAX_Q1D];
double div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
for (int qz = 0; qz < Q1D; ++qz)
{
@@ -1011,7 +1019,7 @@ void PADivDivApply3D(const int D1D,
for (int dz = 0; dz < D1Dz; ++dz)
{
double aXY[HDIV_MAX_Q1D][HDIV_MAX_Q1D];
double aXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
@@ -1022,7 +1030,7 @@ void PADivDivApply3D(const int D1D,
for (int dy = 0; dy < D1Dy; ++dy)
{
double aX[HDIV_MAX_Q1D];
double aX[DofQuadLimits::HDIV_MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
aX[qx] = 0.0;
@@ -1078,7 +1086,7 @@ void PADivDivApply3D(const int D1D,
for (int qz = 0; qz < Q1D; ++qz)
{
double aXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
double aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
osc = 0;
@@ -1097,7 +1105,7 @@ void PADivDivApply3D(const int D1D,
}
for (int qy = 0; qy < Q1D; ++qy)
{
double aX[HDIV_MAX_D1D];
double aX[DofQuadLimits::HDIV_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
aX[dx] = 0;
@@ -1207,8 +1215,8 @@ void PAHdivL2AssembleDiagonal_ADAt_2D(const int D1D,
// Compute row (rx,ry), assuming all contributions are from
// a single element.
double row[2*HDIV_MAX_D1D*(HDIV_MAX_D1D-1)];
double div[HDIV_MAX_Q1D][HDIV_MAX_Q1D];
double row[2*DofQuadLimits::HDIV_MAX_D1D*(DofQuadLimits::HDIV_MAX_D1D-1)];
double div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
for (int i=0; i<2*D1D*(D1D - 1); ++i)
{
@@ -1231,7 +1239,7 @@ void PAHdivL2AssembleDiagonal_ADAt_2D(const int D1D,
const int D1Dy = (c == 1) ? D1D : D1D - 1;
const int D1Dx = (c == 0) ? D1D : D1D - 1;
double aX[HDIV_MAX_D1D];
double aX[DofQuadLimits::HDIV_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
aX[dx] = 0;
@@ -1281,8 +1289,10 @@ void PAHdivL2AssembleDiagonal_ADAt_3D(const int D1D,
const Vector &D_,
Vector &diag_)
{
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
"Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
"Error: Q1D > HDIV_MAX_Q1D");
constexpr static int VDIM = 3;
auto L2Bo = Reshape(L2Bo_.Read(), Q1D, L2D1D);
@@ -1303,8 +1313,9 @@ void PAHdivL2AssembleDiagonal_ADAt_3D(const int D1D,
// Compute row (rx,ry,rz), assuming all contributions are from
// a single element.
double row[3*HDIV_MAX_D1D*(HDIV_MAX_D1D-1)*(HDIV_MAX_D1D-1)];
double div[HDIV_MAX_Q1D][HDIV_MAX_Q1D][HDIV_MAX_Q1D];
double row[3*DofQuadLimits::HDIV_MAX_D1D*(DofQuadLimits::HDIV_MAX_D1D-1)*
(DofQuadLimits::HDIV_MAX_D1D-1)];
double div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
for (int i=0; i<3*D1D*(D1D - 1)*(D1D - 1); ++i)
{
@@ -1325,7 +1336,7 @@ void PAHdivL2AssembleDiagonal_ADAt_3D(const int D1D,
for (int qz = 0; qz < Q1D; ++qz)
{
double aXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
double aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
@@ -1343,7 +1354,7 @@ void PAHdivL2AssembleDiagonal_ADAt_3D(const int D1D,
}
for (int qy = 0; qy < Q1D; ++qy)
{
double aX[HDIV_MAX_D1D];
double aX[DofQuadLimits::HDIV_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
aX[dx] = 0;
@@ -1408,10 +1419,6 @@ void PAHdivL2Apply2D(const int D1D,
const Vector &x_,
Vector &y_)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HDIV_MAX_D1D;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
auto Gc = Reshape(Gc_.Read(), Q1D, D1D);
auto L2Bot = Reshape(L2Bot_.Read(), L2D1D, Q1D);
@@ -1421,6 +1428,10 @@ void PAHdivL2Apply2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
double div[MAX_Q1D][MAX_Q1D];
for (int qy = 0; qy < Q1D; ++qy)
@@ -1514,10 +1525,6 @@ void PAHdivL2ApplyTranspose2D(const int D1D,
const Vector &x_,
Vector &y_)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = HDIV_MAX_D1D;
constexpr static int MAX_Q1D = HDIV_MAX_Q1D;
auto L2Bo = Reshape(L2Bo_.Read(), Q1D, L2D1D);
auto Gct = Reshape(Gct_.Read(), D1D, Q1D);
auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
@@ -1527,6 +1534,10 @@ void PAHdivL2ApplyTranspose2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = DofQuadLimits::HDIV_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HDIV_MAX_Q1D;
double div[MAX_Q1D][MAX_Q1D];
for (int qy = 0; qy < Q1D; ++qy)
@@ -1622,8 +1633,10 @@ void PAHdivL2Apply3D(const int D1D,
const Vector &x_,
Vector &y_)
{
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
"Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
"Error: Q1D > HDIV_MAX_Q1D");
constexpr static int VDIM = 3;
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
@@ -1635,7 +1648,7 @@ void PAHdivL2Apply3D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
double div[HDIV_MAX_Q1D][HDIV_MAX_Q1D][HDIV_MAX_Q1D];
double div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
for (int qz = 0; qz < Q1D; ++qz)
{
@@ -1658,7 +1671,7 @@ void PAHdivL2Apply3D(const int D1D,
for (int dz = 0; dz < D1Dz; ++dz)
{
double aXY[HDIV_MAX_Q1D][HDIV_MAX_Q1D];
double aXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
@@ -1669,7 +1682,7 @@ void PAHdivL2Apply3D(const int D1D,
for (int dy = 0; dy < D1Dy; ++dy)
{
double aX[HDIV_MAX_Q1D];
double aX[DofQuadLimits::HDIV_MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
aX[qx] = 0.0;
@@ -1724,7 +1737,7 @@ void PAHdivL2Apply3D(const int D1D,
for (int qz = 0; qz < Q1D; ++qz)
{
double aXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
double aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
for (int dy = 0; dy < L2D1D; ++dy)
{
@@ -1735,7 +1748,7 @@ void PAHdivL2Apply3D(const int D1D,
}
for (int qy = 0; qy < Q1D; ++qy)
{
double aX[HDIV_MAX_D1D];
double aX[DofQuadLimits::HDIV_MAX_D1D];
for (int dx = 0; dx < L2D1D; ++dx)
{
aX[dx] = 0;
@@ -1783,8 +1796,10 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
const Vector &x_,
Vector &y_)
{
MFEM_VERIFY(D1D <= HDIV_MAX_D1D, "Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= HDIV_MAX_Q1D, "Error: Q1D > HDIV_MAX_Q1D");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
"Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
"Error: Q1D > HDIV_MAX_Q1D");
constexpr static int VDIM = 3;
auto L2Bo = Reshape(L2Bo_.Read(), Q1D, L2D1D);
@@ -1796,7 +1811,7 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
double div[HDIV_MAX_Q1D][HDIV_MAX_Q1D][HDIV_MAX_Q1D];
double div[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
for (int qz = 0; qz < Q1D; ++qz)
{
@@ -1811,7 +1826,7 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
for (int dz = 0; dz < L2D1D; ++dz)
{
double aXY[HDIV_MAX_Q1D][HDIV_MAX_Q1D];
double aXY[DofQuadLimits::HDIV_MAX_Q1D][DofQuadLimits::HDIV_MAX_Q1D];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
@@ -1822,7 +1837,7 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
for (int dy = 0; dy < L2D1D; ++dy)
{
double aX[HDIV_MAX_Q1D];
double aX[DofQuadLimits::HDIV_MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
aX[qx] = 0.0;
@@ -1874,7 +1889,7 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
for (int qz = 0; qz < Q1D; ++qz)
{
double aXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
double aXY[DofQuadLimits::HDIV_MAX_D1D][DofQuadLimits::HDIV_MAX_D1D];
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
@@ -1892,7 +1907,7 @@ void PAHdivL2ApplyTranspose3D(const int D1D,
}
for (int qy = 0; qy < Q1D; ++qy)
{
double aX[HDIV_MAX_D1D];
double aX[DofQuadLimits::HDIV_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
aX[dx] = 0;
+4 -4
View File
@@ -140,8 +140,8 @@ inline void SmemPAHdivMassApply2D(const int NE,
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 MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
MFEM_SHARED double smo[MQ1*(MD1-1)];
@@ -310,8 +310,8 @@ inline void SmemPAHdivMassApply3D(const int NE,
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 MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
MFEM_SHARED double smo[MQ1*(MD1-1)];
+42 -29
View File
@@ -34,11 +34,12 @@ static void PAHcurlApplyGradient2D(const int c_dofs1D,
auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, NE);
auto y = Reshape(y_.ReadWrite(), 2 * c_dofs1D * o_dofs1D, NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w[MAX_D1D][MAX_D1D];
// horizontal part
@@ -110,11 +111,12 @@ static void PAHcurlApplyGradient2DBId(const int c_dofs1D,
auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, NE);
auto y = Reshape(y_.ReadWrite(), 2 * c_dofs1D * o_dofs1D, NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w[MAX_D1D][MAX_D1D];
// horizontal part
@@ -178,11 +180,12 @@ static void PAHcurlApplyGradientTranspose2D(
auto x = Reshape(x_.Read(), 2 * c_dofs1D * o_dofs1D, NE);
auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w[MAX_D1D][MAX_D1D];
// horizontal part (open x, closed y)
@@ -253,11 +256,12 @@ static void PAHcurlApplyGradientTranspose2DBId(
auto x = Reshape(x_.Read(), 2 * c_dofs1D * o_dofs1D, NE);
auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w[MAX_D1D][MAX_D1D];
// horizontal part (open x, closed y)
@@ -324,11 +328,12 @@ static void PAHcurlApplyGradient3D(const int c_dofs1D,
auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
auto y = Reshape(y_.ReadWrite(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w1[MAX_D1D][MAX_D1D][MAX_D1D];
double w2[MAX_D1D][MAX_D1D][MAX_D1D];
@@ -511,11 +516,13 @@ static void PAHcurlApplyGradient3DBId(const int c_dofs1D,
auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
auto y = Reshape(y_.ReadWrite(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w1[MAX_D1D][MAX_D1D][MAX_D1D];
double w2[MAX_D1D][MAX_D1D][MAX_D1D];
@@ -678,11 +685,12 @@ static void PAHcurlApplyGradientTranspose3D(
auto x = Reshape(x_.Read(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w1[MAX_D1D][MAX_D1D][MAX_D1D];
double w2[MAX_D1D][MAX_D1D][MAX_D1D];
// ---
@@ -863,11 +871,13 @@ static void PAHcurlApplyGradientTranspose3DBId(
auto x = Reshape(x_.Read(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w1[MAX_D1D][MAX_D1D][MAX_D1D];
double w2[MAX_D1D][MAX_D1D][MAX_D1D];
// ---
@@ -1152,12 +1162,13 @@ static void PAHcurlVecH1IdentityApply2D(const int c_dofs1D,
auto vk = Reshape(pa_data.Read(), 2, (2 * c_dofs1D * o_dofs1D), NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w[2][MAX_D1D][MAX_D1D];
// dofs that point parallel to x-axis (open in x, closed in y)
@@ -1251,13 +1262,13 @@ static void PAHcurlVecH1IdentityApplyTranspose2D(const int c_dofs1D,
auto vk = Reshape(pa_data.Read(), 2, (2 * c_dofs1D * o_dofs1D), NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
//constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w[2][MAX_D1D][MAX_D1D];
// dofs that point parallel to x-axis (open in x, closed in y)
@@ -1360,12 +1371,13 @@ static void PAHcurlVecH1IdentityApply3D(const int c_dofs1D,
auto vk = Reshape(pa_data.Read(), 3, (3 * c_dofs1D * c_dofs1D * o_dofs1D),
NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w1[3][MAX_D1D][MAX_D1D][MAX_D1D];
double w2[3][MAX_D1D][MAX_D1D][MAX_D1D];
@@ -1574,12 +1586,13 @@ static void PAHcurlVecH1IdentityApplyTranspose3D(const int c_dofs1D,
auto vk = Reshape(pa_data.Read(), 3, (3 * c_dofs1D * c_dofs1D * o_dofs1D),
NE);
constexpr static int MAX_D1D = HCURL_MAX_D1D;
MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
MFEM_VERIFY(c_dofs1D <= DeviceDofQuadLimits::Get().MAX_D1D &&
o_dofs1D <= c_dofs1D, "");
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
double w1[3][MAX_D1D][MAX_D1D][MAX_D1D];
double w2[3][MAX_D1D][MAX_D1D][MAX_D1D];
+11 -11
View File
@@ -27,8 +27,8 @@ static void EAMassAssemble1D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto M = Reshape(eadata.ReadWrite(), D1D, D1D, NE);
@@ -36,7 +36,7 @@ static void EAMassAssemble1D(const int NE,
{
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 MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double r_Bi[MQ1];
double r_Bj[MQ1];
for (int q = 0; q < Q1D; q++)
@@ -77,8 +77,8 @@ static void EAMassAssemble2D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
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);
@@ -86,8 +86,8 @@ static void EAMassAssemble2D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
@@ -149,8 +149,8 @@ static void EAMassAssemble3D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
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);
@@ -158,8 +158,8 @@ static void EAMassAssemble3D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int DQ = T_D1D * T_Q1D;
// For quadratic and lower it's better to use registers but for higher-order you start to
+3 -7
View File
@@ -25,8 +25,6 @@ static void PAMassAssembleDiagonal1D(const int NE,
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);
@@ -34,7 +32,6 @@ static void PAMassAssembleDiagonal1D(const int NE,
{
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);
@@ -198,8 +195,7 @@ void PAMassApply1D_Element(const int e,
auto X = ConstDeviceMatrix(x_, D1D, NE);
auto Y = DeviceMatrix(y_, D1D, NE);
constexpr int max_Q1D = MAX_Q1D;
double XQ[max_Q1D];
double XQ[DofQuadLimits::MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
XQ[qx] = 0.0;
@@ -232,8 +228,8 @@ static void PAMassApply1D(const int NE,
const int d1d = 0,
const int q1d = 0)
{
MFEM_VERIFY(d1d <= MAX_D1D, "");
MFEM_VERIFY(q1d <= MAX_Q1D, "");
MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
const auto B = b_.Read();
const auto Bt = bt_.Read();
+40 -40
View File
@@ -42,8 +42,8 @@ inline void PAMassAssembleDiagonal2D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().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);
@@ -51,8 +51,8 @@ inline void PAMassAssembleDiagonal2D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double QD[MQ1][MD1];
for (int qx = 0; qx < Q1D; ++qx)
{
@@ -90,10 +90,10 @@ inline void SmemPAMassAssembleDiagonal2D(const int NE,
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 int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
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);
@@ -103,8 +103,8 @@ inline void SmemPAMassAssembleDiagonal2D(const int NE,
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;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED double B[MQ1][MD1];
MFEM_SHARED double QDZ[NBZ][MQ1][MD1];
double (*QD)[MD1] = (double (*)[MD1])(QDZ + tidz);
@@ -156,8 +156,8 @@ inline void PAMassAssembleDiagonal3D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().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);
@@ -165,8 +165,8 @@ inline void PAMassAssembleDiagonal3D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double QQD[MQ1][MQ1][MD1];
double QDD[MQ1][MD1][MD1];
for (int qx = 0; qx < Q1D; ++qx)
@@ -226,10 +226,10 @@ inline void SmemPAMassAssembleDiagonal3D(const int NE,
{
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, "");
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
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);
@@ -238,8 +238,8 @@ inline void SmemPAMassAssembleDiagonal3D(const int NE,
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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED double B[MQ1][MD1];
MFEM_SHARED double QQD[MQ1][MQ1][MD1];
MFEM_SHARED double QDD[MQ1][MD1][MD1];
@@ -365,8 +365,8 @@ void PAMassApply2D_Element(const int e,
}
}
constexpr int max_D1D = MAX_D1D;
constexpr int max_Q1D = MAX_Q1D;
constexpr int max_D1D = DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = DofQuadLimits::MAX_Q1D;
double sol_xy[max_Q1D][max_Q1D];
for (int qy = 0; qy < Q1D; ++qy)
{
@@ -447,8 +447,8 @@ void SmemPAMassApply2D_Element(const int e,
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;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
auto b = ConstDeviceMatrix(b_, Q1D, D1D);
@@ -592,8 +592,8 @@ void PAMassApply3D_Element(const int e,
}
}
constexpr int max_D1D = MAX_D1D;
constexpr int max_Q1D = MAX_Q1D;
constexpr int max_D1D = DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = DofQuadLimits::MAX_Q1D;
double sol_xyz[max_Q1D][max_Q1D][max_Q1D];
for (int qz = 0; qz < Q1D; ++qz)
{
@@ -722,8 +722,8 @@ void SmemPAMassApply3D_Element(const int e,
{
constexpr int D1D = T_D1D ? T_D1D : d1d;
constexpr 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;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
auto b = ConstDeviceMatrix(b_, Q1D, D1D);
@@ -948,8 +948,8 @@ inline void PAMassApply2D(const int NE,
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, "");
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
const auto B = b_.Read();
const auto Bt = bt_.Read();
@@ -978,10 +978,10 @@ inline void SmemPAMassApply2D(const int NE,
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 int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
MFEM_VERIFY(D1D <= max_d1d, "");
MFEM_VERIFY(Q1D <= max_q1d, "");
const auto b = b_.Read();
const auto D = d_.Read();
const auto x = x_.Read();
@@ -1004,8 +1004,8 @@ inline void PAMassApply3D(const int NE,
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, "");
MFEM_VERIFY(T_D1D ? T_D1D : d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
const auto B = b_.Read();
const auto Bt = bt_.Read();
@@ -1033,10 +1033,10 @@ inline void SmemPAMassApply3D(const int NE,
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, "");
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
MFEM_VERIFY(D1D <= max_d1d, "");
MFEM_VERIFY(Q1D <= max_q1d, "");
auto b = b_.Read();
auto d = d_.Read();
auto x = x_.Read();
+1 -1
View File
@@ -128,7 +128,7 @@ void MassIntegrator::AssemblePABoundary(const FiniteElementSpace &fes)
int map_type = el.GetMapType();
dim = el.GetDim(); // Dimension of the boundary element, *not* the mesh
ne = fes.GetMesh()->GetNBE();
ne = fes.GetMesh()->GetNFbyType(FaceType::Boundary);
nq = ir->GetNPoints();
face_geom = mesh->GetFaceGeometricFactors(*ir, GeometricFactors::DETERMINANTS,
FaceType::Boundary, mt);
+22 -18
View File
@@ -31,10 +31,6 @@ static void PAHcurlH1Apply2D(const int D1D,
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);
@@ -45,6 +41,10 @@ static void PAHcurlH1Apply2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
double mass[MAX_Q1D][MAX_Q1D][VDIM];
for (int qy = 0; qy < Q1D; ++qy)
@@ -155,10 +155,6 @@ static void PAHcurlH1ApplyTranspose2D(const int D1D,
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);
@@ -169,6 +165,10 @@ static void PAHcurlH1ApplyTranspose2D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int VDIM = 2;
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
double mass[MAX_Q1D][MAX_Q1D][VDIM];
for (int qy = 0; qy < Q1D; ++qy)
@@ -280,11 +280,10 @@ static void PAHcurlH1Apply3D(const int D1D,
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");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
@@ -298,6 +297,9 @@ static void PAHcurlH1Apply3D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
for (int qz = 0; qz < Q1D; ++qz)
@@ -470,11 +472,10 @@ static void PAHcurlH1ApplyTranspose3D(const int D1D,
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");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
@@ -488,6 +489,9 @@ static void PAHcurlH1ApplyTranspose3D(const int D1D,
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
constexpr static int MAX_D1D = DofQuadLimits::HCURL_MAX_D1D;
constexpr static int MAX_Q1D = DofQuadLimits::HCURL_MAX_Q1D;
double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
for (int qz = 0; qz < Q1D; ++qz)
+18 -18
View File
@@ -233,8 +233,8 @@ static void PAVectorDiffusionDiagonal2D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
// note the different shape for D, this is a (symmetric) matrix so we only
@@ -245,8 +245,8 @@ static void PAVectorDiffusionDiagonal2D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
// gradphi \cdot Q \gradphi has four terms
double QD0[MQ1][MD1];
double QD1[MQ1][MD1];
@@ -301,10 +301,10 @@ static void PAVectorDiffusionDiagonal3D(const int NE,
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, "");
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
MFEM_VERIFY(D1D <= max_d1d, "");
MFEM_VERIFY(Q1D <= max_q1d, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Q = Reshape(d.Read(), Q1D*Q1D*Q1D, 6, NE);
@@ -313,8 +313,8 @@ static void PAVectorDiffusionDiagonal3D(const int 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;
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double QQD[MQ1][MQ1][MD1];
double QDD[MQ1][MD1][MD1];
for (int i = 0; i < DIM; ++i)
@@ -442,8 +442,8 @@ void PAVectorDiffusionApply2D(const int NE,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
@@ -456,8 +456,8 @@ void PAVectorDiffusionApply2D(const int NE,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double grad[max_Q1D][max_Q1D][2];
for (int c = 0; c < VDIM; c++)
@@ -563,8 +563,8 @@ void PAVectorDiffusionApply3D(const int NE,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int VDIM = 3;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
@@ -576,8 +576,8 @@ void PAVectorDiffusionApply3D(const int NE,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
for (int c = 0; c < VDIM; ++ c)
{
double grad[max_Q1D][max_Q1D][max_Q1D][3];
+26 -26
View File
@@ -170,9 +170,9 @@ static void PADivergenceApply2D(const int NE,
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, TR_D1D);
auto G = Reshape(g.Read(), Q1D, TR_D1D);
auto Bt = Reshape(bt.Read(), TE_D1D, Q1D);
@@ -186,8 +186,8 @@ static void PADivergenceApply2D(const int NE,
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = 2;
// the following variables are evaluated at compile time
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double grad[max_Q1D][max_Q1D][VDIM];
double div[max_Q1D][max_Q1D];
@@ -308,9 +308,9 @@ static void PADivergenceApplyTranspose2D(const int NE,
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto Bt = Reshape(bt.Read(), TR_D1D, Q1D);
auto Gt = Reshape(gt.Read(), TR_D1D, Q1D);
auto B = Reshape(b.Read(), Q1D, TE_D1D);
@@ -324,8 +324,8 @@ static void PADivergenceApplyTranspose2D(const int NE,
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = 2;
// the following variables are evaluated at compile time
constexpr int max_TR_D1D = T_TR_D1D ? T_TR_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_TR_D1D = T_TR_D1D ? T_TR_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double quadTest[max_Q1D][max_Q1D];
double grad[max_Q1D][max_Q1D][VDIM];
@@ -424,9 +424,9 @@ static void PADivergenceApply3D(const int NE,
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, TR_D1D);
auto G = Reshape(g.Read(), Q1D, TR_D1D);
auto Bt = Reshape(bt.Read(), TE_D1D, Q1D);
@@ -440,8 +440,8 @@ static void PADivergenceApply3D(const int NE,
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = 3;
// the following variables are evaluated at compile time
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_TE_D1D = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double grad[max_Q1D][max_Q1D][max_Q1D][VDIM];
double div[max_Q1D][max_Q1D][max_Q1D];
@@ -607,9 +607,9 @@ static void PADivergenceApplyTranspose3D(const int NE,
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto Bt = Reshape(bt.Read(), TR_D1D, Q1D);
auto Gt = Reshape(gt.Read(), TR_D1D, Q1D);
auto B = Reshape(b.Read(), Q1D, TE_D1D);
@@ -623,8 +623,8 @@ static void PADivergenceApplyTranspose3D(const int NE,
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = 3;
// the following variables are evaluated at compile time
constexpr int max_TR_D1D = T_TR_D1D ? T_TR_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_TR_D1D = T_TR_D1D ? T_TR_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double quadTest[max_Q1D][max_Q1D][max_Q1D];
double grad[max_Q1D][max_Q1D][max_Q1D][VDIM];
@@ -786,9 +786,9 @@ static void SmemPADivergenceApply3D(const int NE,
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto b = Reshape(b_.Read(), Q1D, TR_D1D);
auto g = Reshape(g_.Read(), Q1D, TR_D1D);
@@ -804,9 +804,9 @@ static void SmemPADivergenceApply3D(const int NE,
const int D1DR = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int D1DE = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int MD1R = T_TR_D1D ? T_TR_D1D : MAX_D1D;
constexpr int MD1E = T_TE_D1D ? T_TE_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int MD1R = T_TR_D1D ? T_TR_D1D : DofQuadLimits::MAX_D1D;
constexpr int MD1E = T_TE_D1D ? T_TE_D1D : DofQuadLimits::MAX_D1D;
constexpr int MD1 = MD1E > MD1R ? MD1E : MD1R;
constexpr int MDQ = MQ1 > MD1 ? MQ1 : MD1;
MFEM_SHARED double sBG[2][MQ1*MD1];
+16 -16
View File
@@ -118,8 +118,8 @@ static void PAVectorMassAssembleDiagonal2D(const int NE,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int VDIM = 2;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(B_.Read(), Q1D, D1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
auto y = Reshape(diag_.ReadWrite(), D1D, D1D, VDIM, NE);
@@ -127,8 +127,8 @@ static void PAVectorMassAssembleDiagonal2D(const int NE,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double temp[max_Q1D][max_D1D];
for (int qx = 0; qx < Q1D; ++qx)
@@ -170,8 +170,8 @@ static void PAVectorMassAssembleDiagonal3D(const int NE,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int VDIM = 3;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(B_.Read(), Q1D, D1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, NE);
auto y = Reshape(diag_.ReadWrite(), D1D, D1D, D1D, VDIM, NE);
@@ -180,8 +180,8 @@ static void PAVectorMassAssembleDiagonal3D(const int NE,
const int D1D = T_D1D ? T_D1D : d1d; // nvcc workaround
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double temp[max_Q1D][max_Q1D][max_D1D];
for (int qx = 0; qx < Q1D; ++qx)
@@ -281,8 +281,8 @@ static void PAVectorMassApply2D(const int NE,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int VDIM = 2;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(B_.Read(), Q1D, D1D);
auto Bt = Reshape(Bt_.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, NE);
@@ -293,8 +293,8 @@ static void PAVectorMassApply2D(const int NE,
const int D1D = T_D1D ? T_D1D : d1d; // nvcc workaround
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double sol_xy[max_Q1D][max_Q1D];
for (int c = 0; c < VDIM; ++c)
{
@@ -377,8 +377,8 @@ static void PAVectorMassApply3D(const int NE,
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int VDIM = 3;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(B_.Read(), Q1D, D1D);
auto Bt = Reshape(Bt_.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, NE);
@@ -388,8 +388,8 @@ static void PAVectorMassApply3D(const int NE,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double sol_xyz[max_Q1D][max_Q1D][max_Q1D];
for (int c = 0; c < VDIM; ++ c)
{
+3 -3
View File
@@ -38,7 +38,7 @@ static void BLFEvalAssemble2D(const int vdim, const int nbe, const int d,
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double QQ[Q];
for (int c = 0; c < vdim; ++c)
@@ -92,8 +92,8 @@ static void BLFEvalAssemble3D(const int vdim, const int nbe, const int d,
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED double sBt[Q*D];
MFEM_SHARED double sQQ[Q*Q];
+3 -3
View File
@@ -33,7 +33,7 @@ void BFLFEvalAssemble2D(const int nbe, const int d, const int q,
{
if (M(e) == 0) { return; } // ignore (in a lambda return acts as continue)
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double QQ[Q];
for (int qx = 0; qx < q; ++qx)
@@ -67,8 +67,8 @@ void BFLFEvalAssemble3D(const int nbe, const int d, const int q,
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED double sBt[Q*D];
MFEM_SHARED double sQQ[Q*Q];
+4 -4
View File
@@ -36,8 +36,8 @@ static void DLFEvalAssemble2D(const int vdim, const int ne, const int d,
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED double sBt[Q*D];
MFEM_SHARED double sQQ[Q*Q];
@@ -107,8 +107,8 @@ static void DLFEvalAssemble3D(const int vdim, const int ne, const int d,
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQD = (Q >= D) ? Q : D;
double u[D];
+4 -4
View File
@@ -36,8 +36,8 @@ void DLFGradAssemble2D(const int vdim, const int ne, const int d, const int q,
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED double sBGt[2][Q*D];
MFEM_SHARED double sQQ[2][Q*Q];
@@ -130,8 +130,8 @@ void DLFGradAssemble3D(const int vdim, const int ne, const int d, const int q,
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : MAX_D1D;
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQD = (Q >= D) ? Q : D;
MFEM_SHARED double sBGt[2][Q*D];
+12 -8
View File
@@ -22,8 +22,10 @@ static void HdivDLFAssemble2D(
const double *bc, const double *j, const double *weights,
const Vector &coeff, double *y)
{
MFEM_VERIFY(T_D1D || d <= HDIV_MAX_D1D, "Problem size too large.");
MFEM_VERIFY(T_Q1D || q <= HDIV_MAX_Q1D, "Problem size too large.");
MFEM_VERIFY(T_D1D || d <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
"Problem size too large.");
MFEM_VERIFY(T_Q1D || q <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
"Problem size too large.");
static constexpr int vdim = 2;
const auto F = coeff.Read();
@@ -40,8 +42,8 @@ static void HdivDLFAssemble2D(
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : HDIV_MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : HDIV_MAX_D1D;
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
MFEM_SHARED double sBot[Q*D];
MFEM_SHARED double sBct[Q*D];
@@ -121,8 +123,10 @@ static void HdivDLFAssemble3D(
const double *bc, const double *j, const double *weights,
const Vector &coeff, double *y)
{
MFEM_VERIFY(T_D1D || d <= HDIV_MAX_D1D, "Problem size too large.");
MFEM_VERIFY(T_Q1D || q <= HDIV_MAX_Q1D, "Problem size too large.");
MFEM_VERIFY(T_D1D || d <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
"Problem size too large.");
MFEM_VERIFY(T_Q1D || q <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
"Problem size too large.");
static constexpr int vdim = 3;
const auto F = coeff.Read();
@@ -139,8 +143,8 @@ static void HdivDLFAssemble3D(
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : HDIV_MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : HDIV_MAX_D1D;
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
MFEM_SHARED double sBot[Q*D];
MFEM_SHARED double sBct[Q*D];
+8 -8
View File
@@ -136,8 +136,8 @@ static void PAConvectionNLApply2D(const int NE,
{
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
@@ -148,8 +148,8 @@ static void PAConvectionNLApply2D(const int NE,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double data[max_Q1D][max_Q1D][2];
double grad0[max_Q1D][max_Q1D][2];
@@ -273,8 +273,8 @@ static void PAConvectionNLApply3D(const int NE,
constexpr int VDIM = 3;
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, "");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
@@ -288,8 +288,8 @@ static void PAConvectionNLApply3D(const int NE,
constexpr int VDIM = 3;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int max_D1D = T_D1D ? T_D1D : MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : MAX_Q1D;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
double data[max_Q1D][max_Q1D][max_Q1D][VDIM];
double grad0[max_Q1D][max_Q1D][max_Q1D][VDIM];
+330 -2
View File
@@ -16,6 +16,7 @@
// Formulas at http://nines.cs.kuleuven.be/research/ecf/ecf.html
#include "fem.hpp"
#include "../mesh/nurbs.hpp"
#include <cmath>
#ifdef MFEM_USE_MPFR
@@ -35,6 +36,7 @@ IntegrationRule::IntegrationRule(IntegrationRule &irx, IntegrationRule &iry)
ny = iry.GetNPoints();
SetSize(nx * ny);
SetPointIndices();
Order = std::min(irx.GetOrder(), iry.GetOrder());
for (j = 0; j < ny; j++)
{
@@ -59,6 +61,7 @@ IntegrationRule::IntegrationRule(IntegrationRule &irx, IntegrationRule &iry,
const int nz = irz.GetNPoints();
SetSize(nx*ny*nz);
SetPointIndices();
Order = std::min({irx.GetOrder(), iry.GetOrder(), irz.GetOrder()});
for (int iz = 0; iz < nz; ++iz)
{
@@ -124,6 +127,7 @@ void IntegrationRule::GrundmannMollerSimplexRule(int s, int n)
np /= f;
SetSize(np);
SetPointIndices();
Order = 2*s + 1;
int pt = 0;
for (int i = 0; i <= s; i++)
@@ -173,6 +177,52 @@ void IntegrationRule::GrundmannMollerSimplexRule(int s, int n)
}
}
IntegrationRule*
IntegrationRule::ApplyToKnotIntervals(KnotVector const& kv) const
{
const int np = this->GetNPoints();
const int ne = kv.GetNE();
IntegrationRule *kvir = new IntegrationRule(ne * np);
kvir->SetOrder(GetOrder());
double x0 = kv[0];
double x1 = x0;
int id = 0;
for (int e=0; e<ne; ++e)
{
x0 = x1;
if (e == ne-1)
{
x1 = kv[kv.Size() - 1];
}
else
{
// Find the next unique knot
while (id < kv.Size() - 1)
{
id++;
if (kv[id] != x0)
{
x1 = kv[id];
break;
}
}
}
const double s = x1 - x0;
for (int j=0; j<this->GetNPoints(); ++j)
{
const double x = x0 + (s * (*this)[j].x);
(*kvir)[(e * np) + j].Set1w(x, (*this)[j].weight);
}
}
return kvir;
}
#ifdef MFEM_USE_MPFR
@@ -375,6 +425,7 @@ void QuadratureFunctions1D::GaussLegendre(const int np, IntegrationRule* ir)
{
ir->SetSize(np);
ir->SetPointIndices();
ir->SetOrder(2*np - 1);
switch (np)
{
@@ -481,9 +532,11 @@ void QuadratureFunctions1D::GaussLobatto(const int np, IntegrationRule* ir)
if ( np == 1 )
{
ir->IntPoint(0).Set1w(0.5, 1.0);
ir->SetOrder(1);
}
else
{
ir->SetOrder(2*np - 3);
#ifndef MFEM_USE_MPFR
@@ -578,6 +631,7 @@ void QuadratureFunctions1D::OpenUniform(const int np, IntegrationRule* ir)
{
ir->SetSize(np);
ir->SetPointIndices();
ir->SetOrder(np - 1 + np%2);
// The Newton-Cotes quadrature is based on weights that integrate exactly the
// interpolatory polynomial through the equally spaced quadrature points.
@@ -594,6 +648,7 @@ void QuadratureFunctions1D::ClosedUniform(const int np,
{
ir->SetSize(np);
ir->SetPointIndices();
ir->SetOrder(np - 1 + np%2);
if ( np == 1 ) // allow this case as "closed"
{
ir->IntPoint(0).Set1w(0.5, 1.0);
@@ -612,6 +667,7 @@ void QuadratureFunctions1D::OpenHalfUniform(const int np, IntegrationRule* ir)
{
ir->SetSize(np);
ir->SetPointIndices();
ir->SetOrder(np - 1 + np%2);
// Open half points: the centers of np uniform intervals
for (int i = 0; i < np ; ++i)
@@ -628,6 +684,7 @@ void QuadratureFunctions1D::ClosedGL(const int np, IntegrationRule* ir)
ir->SetPointIndices();
ir->IntPoint(0).x = 0.0;
ir->IntPoint(np-1).x = 1.0;
ir->SetOrder(np - 1 + np%2); // Is this the correct order?
if ( np > 2 )
{
@@ -953,13 +1010,17 @@ const IntegrationRule &IntegrationRules::Get(int GeomType, int Order)
if (!HaveIntRule(*ir_array, Order))
{
IntegrationRule *ir = GenerateIntegrationRule(GeomType, Order);
#ifdef MFEM_DEBUG
int RealOrder = Order;
while (RealOrder+1 < ir_array->Size() &&
(*ir_array)[RealOrder+1] == ir)
{
RealOrder++;
}
ir->SetOrder(RealOrder);
MFEM_VERIFY(RealOrder == ir->GetOrder(), "internal error");
#else
MFEM_CONTRACT_VAR(ir);
#endif
}
}
}
@@ -1068,6 +1129,7 @@ IntegrationRule *IntegrationRules::PointIntegrationRule(int Order)
IntegrationRule *ir = new IntegrationRule(1);
ir->IntPoint(0).x = .0;
ir->IntPoint(0).weight = 1.;
ir->SetOrder(1);
PointIntRules[1] = PointIntRules[0] = ir;
@@ -1132,6 +1194,7 @@ IntegrationRule *IntegrationRules::SegmentIntegrationRule(int Order)
{
// Effectively passing memory management to SegmentIntegrationRules
IntegrationRule *refined_ir = new IntegrationRule(2*n);
refined_ir->SetOrder(ir->GetOrder());
for (int j = 0; j < n; j++)
{
refined_ir->IntPoint(j).x = ir->IntPoint(j).x/2.0;
@@ -1156,16 +1219,18 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
// assuming that orders <= 25 are pre-allocated
switch (Order)
{
case 0: // 1 point - 0 degree
case 0: // 1 point - degree 1
case 1:
ir = new IntegrationRule(1);
ir->AddTriMidPoint(0, 0.5);
ir->SetOrder(1);
TriangleIntRules[0] = TriangleIntRules[1] = ir;
return ir;
case 2: // 3 point - 2 degree
ir = new IntegrationRule(3);
ir->AddTriPoints3(0, 1./6., 1./6.);
ir->SetOrder(2);
TriangleIntRules[2] = ir;
// interior points
return ir;
@@ -1174,6 +1239,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
ir = new IntegrationRule(4);
ir->AddTriMidPoint(0, -0.28125); // -9./32.
ir->AddTriPoints3(1, 0.2, 25./96.);
ir->SetOrder(3);
TriangleIntRules[3] = ir;
return ir;
@@ -1181,6 +1247,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
ir = new IntegrationRule(6);
ir->AddTriPoints3(0, 0.091576213509770743460, 0.054975871827660933819);
ir->AddTriPoints3(3, 0.44594849091596488632, 0.11169079483900573285);
ir->SetOrder(4);
TriangleIntRules[4] = ir;
return ir;
@@ -1189,6 +1256,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
ir->AddTriMidPoint(0, 0.1125);
ir->AddTriPoints3(1, 0.10128650732345633880, 0.062969590272413576298);
ir->AddTriPoints3(4, 0.47014206410511508977, 0.066197076394253090369);
ir->SetOrder(5);
TriangleIntRules[5] = ir;
return ir;
@@ -1198,6 +1266,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
ir->AddTriPoints3(3, 0.24928674517091042129, 0.058393137863189683013);
ir->AddTriPoints6(6, 0.053145049844816947353, 0.31035245103378440542,
0.041425537809186787597);
ir->SetOrder(6);
TriangleIntRules[6] = ir;
return ir;
@@ -1212,6 +1281,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
0.30472650086816719592, 0.028775042784981585738);
ir->AddTriPoints3R(9, 0.51584233435359177926, 0.27771616697639178257,
0.20644149867001643817, 0.067493187009802774463);
ir->SetOrder(7);
TriangleIntRules[7] = ir;
return ir;
@@ -1227,6 +1297,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
ir->AddTriPoints6(10, 0.008394777409957605337213834539296,
0.263112829634638113421785786284643,
0.0136151570872174971324223450369544);
ir->SetOrder(8);
TriangleIntRules[8] = ir;
return ir;
@@ -1244,6 +1315,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
ir->AddTriPoints6(13, 0.0368384120547362836348175987833851,
0.2219629891607656956751025276931919,
0.0216417696886446886446886446886446);
ir->SetOrder(9);
TriangleIntRules[9] = ir;
return ir;
@@ -1263,6 +1335,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
ir->AddTriPoints6(19, 0.0095408154002994575801528096228873,
0.0668032510122002657735402127620247,
4.71083348186641172996373548344341E-03);
ir->SetOrder(10);
TriangleIntRules[10] = ir;
return ir;
@@ -1285,6 +1358,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
ir->AddTriPoints6(22, 0.0448416775891304433090523914688007,
0.2772206675282791551488214673424523,
0.0205281577146442833208261574536469);
ir->SetOrder(11);
TriangleIntRules[11] = ir;
return ir;
@@ -1301,6 +1375,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
1.11783866011515E-02);
ir->AddTriPoints6(27, 2.57340505483300E-02, 1.16251915907597E-01,
8.65811555432950E-03);
ir->SetOrder(12);
TriangleIntRules[12] = ir;
return ir;
@@ -1328,6 +1403,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
ir->AddTriPoints6(31, 0.0897330604516053590796290561145196,
0.2723110556841851025078181617634414,
0.0182757511120486476280967518782978);
ir->SetOrder(13);
TriangleIntRules[13] = ir;
return ir;
@@ -1347,6 +1423,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
7.21815405676700E-03);
ir->AddTriPoints6(36, 1.26833093287200E-03, 1.18974497696957E-01,
2.50511441925050E-03);
ir->SetOrder(14);
TriangleIntRules[14] = ir;
return ir;
@@ -1370,6 +1447,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
0.012803670460631195);
ir->AddTriPoints6(48, 0.1684044181246992, 0.281835668099084562,
0.016544097765822835);
ir->SetOrder(15);
TriangleIntRules[15] = ir;
return ir;
@@ -1397,6 +1475,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
9.14639838501250E-03);
ir->AddTriPoints6 (55, 1.46631822248280E-02, 8.07113136795640E-02,
3.33281600208250E-03);
ir->SetOrder(17);
TriangleIntRules[16] = TriangleIntRules[17] = ir;
return ir;
@@ -1428,6 +1507,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
0.0051292818680995);
ir->AddTriPoints6 (67, 0.065494628082938, 0.010161119296278,
0.001899964427651);
ir->SetOrder(19);
TriangleIntRules[18] = TriangleIntRules[19] = ir;
return ir;
@@ -1462,6 +1542,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
0.009336472951467735);
ir->AddTriPoints6(79, 0.140710844943938733, 0.323170566536257485,
0.01140911202919763);
ir->SetOrder(20);
TriangleIntRules[20] = ir;
return ir;
@@ -1513,6 +1594,7 @@ IntegrationRule *IntegrationRules::TriangleIntegrationRule(int Order)
0.00707722325261307);
ir->AddTriPoints6(120, 0.191771865867325067, 0.325618122595983752,
0.007440689780584005);
ir->SetOrder(25);
TriangleIntRules[21] =
TriangleIntRules[22] =
TriangleIntRules[23] =
@@ -1563,6 +1645,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
case 1:
ir = new IntegrationRule(1);
ir->AddTetMidPoint(0, 1./6.);
ir->SetOrder(1);
TetrahedronIntRules[0] = TetrahedronIntRules[1] = ir;
return ir;
@@ -1570,6 +1653,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
ir = new IntegrationRule(4);
// ir->AddTetPoints4(0, 0.13819660112501051518, 1./24.);
ir->AddTetPoints4b(0, 0.58541019662496845446, 1./24.);
ir->SetOrder(2);
TetrahedronIntRules[2] = ir;
return ir;
@@ -1577,6 +1661,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
ir = new IntegrationRule(5);
ir->AddTetMidPoint(0, -2./15.);
ir->AddTetPoints4b(1, 0.5, 0.075);
ir->SetOrder(3);
TetrahedronIntRules[3] = ir;
return ir;
@@ -1585,6 +1670,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
ir->AddTetPoints4(0, 1./14., 343./45000.);
ir->AddTetMidPoint(4, -74./5625.);
ir->AddTetPoints6(5, 0.10059642383320079500, 28./1125.);
ir->SetOrder(4);
TetrahedronIntRules[4] = ir;
return ir;
@@ -1595,6 +1681,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
ir->AddTetPoints4(6, 0.092735250310891226402, 0.012248840519393658257);
ir->AddTetPoints4b(10, 0.067342242210098170608,
0.018781320953002641800);
ir->SetOrder(5);
TetrahedronIntRules[5] = ir;
return ir;
@@ -1608,6 +1695,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
9.2261969239424536825E-03);
ir->AddTetPoints12(12, 0.063661001875017525299, 0.26967233145831580803,
8.0357142857142857143E-03);
ir->SetOrder(6);
TetrahedronIntRules[6] = ir;
return ir;
@@ -1621,6 +1709,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
ir->AddTetPoints4b(15, 2.3825066607381275412E-03,
4.8914252630734993858E-03);
ir->AddTetPoints12(19, 0.1, 0.2, 0.027557319223985890653);
ir->SetOrder(7);
TetrahedronIntRules[7] = ir;
return ir;
@@ -1638,6 +1727,7 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
5.7044858086819185068E-03);
ir->AddTetPoints4(38, 0.20682993161067320408, 0.014250305822866901248);
ir->AddTetMidPoint(42, -0.020500188658639915841);
ir->SetOrder(8);
TetrahedronIntRules[8] = ir;
return ir;
@@ -1668,6 +1758,7 @@ IntegrationRule *IntegrationRules::PyramidIntegrationRule(int Order)
int npts = irc.GetNPoints();
AllocIntRule(PyramidIntRules, Order);
PyramidIntRules[Order] = new IntegrationRule(npts);
PyramidIntRules[Order]->SetOrder(Order); // FIXME: see comment above
for (int k=0; k<npts; k++)
{
@@ -1690,6 +1781,12 @@ IntegrationRule *IntegrationRules::PrismIntegrationRule(int Order)
int ns = irs.GetNPoints();
AllocIntRule(PrismIntRules, Order);
PrismIntRules[Order] = new IntegrationRule(nt * ns);
PrismIntRules[Order]->SetOrder(std::min(irt.GetOrder(), irs.GetOrder()));
while (Order < std::min(irt.GetOrder(), irs.GetOrder()))
{
AllocIntRule(PrismIntRules, ++Order);
PrismIntRules[Order] = PrismIntRules[Order-1];
}
for (int ks=0; ks<ns; ks++)
{
@@ -1725,4 +1822,235 @@ IntegrationRule *IntegrationRules::CubeIntegrationRule(int Order)
return CubeIntRules[Order];
}
IntegrationRule& NURBSMeshRules::GetElementRule(const int elem,
const int patch, const int *ijk,
Array<const KnotVector*> const& kv,
bool & deleteRule) const
{
deleteRule = false;
// First check whether a rule has been assigned to element index elem.
auto search = elementToRule.find(elem);
if (search != elementToRule.end())
{
return *elementRule[search->second];
}
MFEM_VERIFY(patchRules1D.NumRows(),
"Undefined rule in NURBSMeshRules::GetElementRule");
// Use a tensor product of rules on the patch.
MFEM_VERIFY(kv.Size() == dim, "");
int np = 1;
std::vector<std::vector<double>> el(dim);
std::vector<int> npd;
npd.assign(3, 0);
for (int d=0; d<dim; ++d)
{
const int order = kv[d]->GetOrder();
const double kv0 = (*kv[d])[order + ijk[d]];
const double kv1 = (*kv[d])[order + ijk[d] + 1];
const bool rightEnd = (order + ijk[d] + 1) == (kv[d]->Size() - 1);
for (int i=0; i<patchRules1D(patch,d)->Size(); ++i)
{
const IntegrationPoint& ip = (*patchRules1D(patch,d))[i];
if (kv0 <= ip.x && (ip.x < kv1 || rightEnd))
{
const double x = (ip.x - kv0) / (kv1 - kv0);
el[d].push_back(x);
el[d].push_back(ip.weight);
}
}
npd[d] = el[d].size() / 2;
np *= npd[d];
}
IntegrationRule *irp = new IntegrationRule(np);
deleteRule = true;
// Set (*irp)[i + j*npd[0] + k*npd[0]*npd[1]] =
// (el[0][2*i], el[1][2*j], el[2][2*k])
MFEM_VERIFY(npd[0] > 0 && npd[1] > 0, "Assuming 2D or 3D");
for (int i = 0; i < npd[0]; ++i)
{
for (int j = 0; j < npd[1]; ++j)
{
for (int k = 0; k < std::max(npd[2], 1); ++k)
{
const int id = i + j*npd[0] + k*npd[0]*npd[1];
(*irp)[id].x = el[0][2*i];
(*irp)[id].y = el[1][2*j];
(*irp)[id].weight = el[0][(2*i)+1];
(*irp)[id].weight *= el[1][(2*j)+1];
if (npd[2] > 0)
{
(*irp)[id].z = el[2][2*k];
(*irp)[id].weight *= el[2][(2*k)+1];
}
}
}
}
return *irp;
}
void NURBSMeshRules::GetIntegrationPointFrom1D(const int patch, int i, int j,
int k, IntegrationPoint & ip)
{
MFEM_VERIFY(patchRules1D.NumRows() > 0,
"Assuming patchRules1D is set.");
ip.weight = (*patchRules1D(patch,0))[i].weight;
ip.x = (*patchRules1D(patch,0))[i].x;
if (dim > 1)
{
ip.weight *= (*patchRules1D(patch,1))[j].weight;
ip.y = (*patchRules1D(patch,1))[j].x; // 1D rule only has x
}
if (dim > 2)
{
ip.weight *= (*patchRules1D(patch,2))[k].weight;
ip.z = (*patchRules1D(patch,2))[k].x; // 1D rule only has x
}
}
void NURBSMeshRules::Finalize(Mesh const& mesh)
{
if ((int) pointToElem.size() == npatches) { return; } // Already set
MFEM_VERIFY(elementToRule.empty() && patchRules1D.NumRows() > 0
&& npatches > 0, "Assuming patchRules1D is set.");
MFEM_VERIFY(mesh.NURBSext, "");
MFEM_VERIFY(mesh.Dimension() == dim, "");
pointToElem.resize(npatches);
patchRules1D_KnotSpan.resize(npatches);
// First, find all the elements in each patch.
std::vector<std::vector<int>> patchElements(npatches);
for (int e=0; e<mesh.GetNE(); ++e)
{
patchElements[mesh.NURBSext->GetElementPatch(e)].push_back(e);
}
Array<int> ijk(3);
Array<int> maxijk(3);
Array<int> np(3); // Number of points in each dimension
ijk = 0;
Array<const KnotVector*> pkv;
for (int p=0; p<npatches; ++p)
{
patchRules1D_KnotSpan[p].resize(dim);
// For each patch, get the range of ijk.
mesh.NURBSext->GetPatchKnotVectors(p, pkv);
MFEM_VERIFY((int) pkv.Size() == dim, "");
maxijk = 1;
np = 1;
for (int d=0; d<dim; ++d)
{
maxijk[d] = pkv[d]->GetNKS();
np[d] = patchRules1D(p,d)->Size();
}
// For each patch, set a map from ijk to element index.
Array3D<int> ijk2elem(maxijk[0], maxijk[1], maxijk[2]);
ijk2elem = -1;
for (auto elem : patchElements[p])
{
mesh.NURBSext->GetElementIJK(elem, ijk);
MFEM_VERIFY(ijk2elem(ijk[0], ijk[1], ijk[2]) == -1, "");
ijk2elem(ijk[0], ijk[1], ijk[2]) = elem;
}
// For each point, find its ijk and from that its element index.
// It is assumed here that the NURBSFiniteElement kv the same as the
// patch kv.
for (int d=0; d<dim; ++d)
{
patchRules1D_KnotSpan[p][d].SetSize(patchRules1D(p,d)->Size());
for (int r=0; r<patchRules1D(p,d)->Size(); ++r)
{
const IntegrationPoint& ip = (*patchRules1D(p,d))[r];
const int order = pkv[d]->GetOrder();
// Find ijk_d such that ip.x is in the corresponding knot-span.
int ijk_d = 0;
bool found = false;
while (!found)
{
const double kv0 = (*pkv[d])[order + ijk_d];
const double kv1 = (*pkv[d])[order + ijk_d + 1];
const bool rightEnd = (order + ijk_d + 1) == (pkv[d]->Size() - 1);
if (kv0 <= ip.x && (ip.x < kv1 || rightEnd))
{
found = true;
}
else
{
ijk_d++;
}
}
patchRules1D_KnotSpan[p][d][r] = ijk_d;
}
}
pointToElem[p].SetSize(np[0], np[1], np[2]);
for (int i=0; i<np[0]; ++i)
for (int j=0; j<np[1]; ++j)
for (int k=0; k<np[2]; ++k)
{
const int elem = ijk2elem(patchRules1D_KnotSpan[p][0][i],
patchRules1D_KnotSpan[p][1][j],
patchRules1D_KnotSpan[p][2][k]);
MFEM_VERIFY(elem >= 0, "");
pointToElem[p](i,j,k) = elem;
}
} // Loop (p) over patches
}
void NURBSMeshRules::SetPatchRules1D(const int patch,
std::vector<const IntegrationRule*> & ir1D)
{
MFEM_VERIFY((int) ir1D.size() == dim, "Wrong dimension");
for (int i=0; i<dim; ++i)
{
patchRules1D(patch,i) = ir1D[i];
}
}
NURBSMeshRules::~NURBSMeshRules()
{
for (int i=0; i<patchRules1D.NumRows(); ++i)
for (int j=0; j<patchRules1D.NumCols(); ++j)
{
delete patchRules1D(i, j);
}
}
}

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