Compare commits

...
Author SHA1 Message Date
Veselin Dobrev e61f04062f Improve #include logic. 2020-10-29 05:20:58 -07:00
Veselin Dobrev 040a2e1a90 Update the 'raja-cuda' and 'occa-cuda' backends to use the
default stream 0.

Optimize OperatorJacobiSmoother::Mult by fusing kernels as much
as possible.
2020-10-29 04:28:15 -07:00
Tzanio Kolev de4a24b0ff Merge pull request #1837 from mfem/adios2-element-attribute
ADIOS2 output switch material to MFEM attribute in CellData
2020-10-24 19:07:23 -07:00
William F Godoy 4ba894af37 ADIOS2 output switch material to MFEM attribute in CellData
To sync up with ParaViewDataCollection
2020-10-24 11:27:42 -04:00
Tzanio Kolev 1bc87a5778 Merge pull request #1825 from mfem/paraview-bdr
ParaView output of boundary elements and attributes
2020-10-23 07:19:11 -07:00
Will Pazner a83ac75a8f Document and fix path handling in ParMesh::PrintVTU 2020-10-22 13:51:26 -07:00
Tzanio Kolev 2d62a136d0 Merge pull request #1719 from mfem/yohann/test-ceed
Add tests for the libCEED integration in MFEM
2020-10-22 12:28:02 -07:00
Veselin Dobrev 9c82ef12d1 Merge pull request #1749 from mfem/nc-point-mat-index-dev
Unique point matrices in `NCMesh::NCList` [nc-point-mat-index-dev]
2020-10-21 18:27:26 -07:00
Will Pazner 5143a46538 Update CHANGELOG 2020-10-21 13:47:43 -07:00
Tzanio Kolev ec10e26b15 Merge pull request #1819 from mfem/examples/artv3/amgx-ex1p
Minor fixes to amgx:ex1p, adjust amgx defaults
2020-10-21 10:55:15 -07:00
Tzanio Kolev 9161bdca79 Merge pull request #1826 from mfem/tbnlf
Absolute value function 'abs' when argument is of floating point type [tbnlf]
2020-10-21 10:53:50 -07:00
Will Pazner d98cd5ff7c Parallel VTU output for meshes and boundaries 2020-10-20 15:36:22 -07:00
camierjs 83ad60cfbe Absolute value function 'abs' when argument is of floating point type 2020-10-20 09:53:41 -07:00
Will Pazner 7b827ad096 Allow for VTU output of boundary elements and attributes 2020-10-19 17:08:02 -07:00
Yohann Dudouit 47f5468540 Remove extra semicolons 2020-10-19 11:27:34 -07:00
Yohann Dudouit 3f8ff31d52 Reorganize CMakeLists 2020-10-19 10:41:07 -07:00
Yohann Dudouit ba467dbf04 Update hypre test 2020-10-19 10:36:15 -07:00
Yohann Dudouit a88c07b4ac Merge branch 'master' into yohann/test-ceed 2020-10-19 09:49:16 -07:00
Tzanio 18e1a91d61 minor 2020-10-18 18:47:19 -07:00
Arturo Vargas dc768abcab fixed verify message 2020-10-18 14:56:01 -07:00
Arturo Vargas a38b8081b2 add verify for basic example 2020-10-18 14:53:45 -07:00
Arturo Vargas 89d257c335 minor edits 2020-10-18 14:34:05 -07:00
Arturo Vargas 0e36573436 minor documenation fixes, adjust solver preconditioner 2020-10-18 14:13:54 -07:00
Tzanio Kolev f97eef13fc Merge pull request #1756 from mfem/superlu-update-dev
Update SuperLU to 6.3.1
2020-10-18 12:45:51 -07:00
Tzanio 0d95f455f9 Final updates for the SuperLU PR #1756 2020-10-18 12:43:52 -07:00
Tzanio a3563bd454 Merge branch 'master' into superlu-update-dev
Conflicts:
	examples/makefile
2020-10-18 11:21:20 -07:00
Tzanio Kolev e17b0c5aee Merge pull request #1386 from mfem/feature/artv3/amgx
Add support for AmgX
2020-10-18 11:20:00 -07:00
Tzanio 1dafb75576 Final updates for the AmgX PR #1386 2020-10-18 11:16:37 -07:00
Tzanio Kolev 740178cfcf Merge pull request #1714 from mfem/libceed-hip
Enable HIP backend in libCEED
2020-10-18 11:02:53 -07:00
Tzanio 3b01fd0741 Updated CHANGELOG and Example 1 sample runs 2020-10-18 11:00:25 -07:00
Tzanio Kolev ef0c14eb6e Merge pull request #1673 from wcdawn/master
Address leaks in SlepcEigenSolver
2020-10-17 21:43:05 -07:00
Tzanio Kolev e124e91469 Merge pull request #1787 from mfem/barker29/hypre-initial-spelling
hypre.hpp: transition to a correct spelling for SetInitialIterate()
2020-10-17 21:41:49 -07:00
Aaron Fisher 9c269df22d Merge branch 'superlu-update-dev' of github.com:mfem/mfem into superlu-update-dev 2020-10-15 11:53:15 -07:00
Aaron Fisher d668a28b29 Fixed make test in the superlu example. 2020-10-15 11:52:38 -07:00
Veselin Dobrev 7e45098ad1 Merge pull request #1802 from mfem/hypre-smoother-fix
Fix for reusing HypreSmoother
2020-10-14 18:04:36 -07:00
YohannandWill Pazner ca3aa0e446 Delete coeff.
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2020-10-14 11:20:27 -07:00
YohannandWill Pazner fcf5eeef3e Create FunctionCoefficient only when needed.
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2020-10-14 11:20:03 -07:00
Yohann Dudouit a9a372ca5d Replace fes by mesh_fes. 2020-10-13 16:52:50 -07:00
Yohann Dudouit 104f94e645 Update comment. 2020-10-13 15:38:39 -07:00
Yohann Dudouit f4b31f910a Fix the interface for strided restrictions. 2020-10-13 15:14:01 -07:00
Yohann Dudouit f9ede5f5c4 Remove memory leak. 2020-10-13 15:07:55 -07:00
Aaron Fisher 592abbbd41 Merge branch 'superlu-update-dev' of https://github.com/mfem/mfem into superlu-update-dev 2020-10-13 11:55:20 -07:00
Aaron Fisher e99eab4197 Removed a static condensation sample run that I missed. 2020-10-13 11:43:11 -07:00
Tzanio Kolev f931e46e5d Merge branch 'master' into superlu-update-dev 2020-10-13 11:37:02 -07:00
Yohann Dudouit b1d2e2827b Remove compilation warnings in test_ceed.cpp. 2020-10-13 10:56:53 -07:00
Jakub Červený c18fabe72f Fixed crash due to incorrect slave.geom of edge-face constraints. 2020-10-13 14:57:28 +02:00
Arturo Vargas af7bc8f988 minor fixes to examples 2020-10-12 18:32:21 -07:00
Aaron Fisher 44bfdec7fc Fixed some verbiage, removed some defunct sample runs and added some SuperLU command line options to the example. 2020-10-12 17:00:59 -07:00
Tzanio Kolev 265ed8caa8 Merge pull request #1785 from mfem/jfnk
Add KINSOL JFNK interface
2020-10-12 15:26:50 -07:00
Tzanio 983c83d4b5 Minor editing 2020-10-12 15:11:40 -07:00
Julian Andrej aa06473d31 Merge branch 'master' into jfnk 2020-10-12 14:54:28 -07:00
Julian Andrej f44c9f217f changelog entry 2020-10-12 14:49:18 -07:00
Tzanio a4ef4063f3 minor 2020-10-12 14:37:46 -07:00
Arturo Vargas 07b02018b2 Merge branch 'feature/artv3/amgx' of github.com:mfem/mfem into feature/artv3/amgx 2020-10-12 13:21:17 -07:00
Arturo Vargas 7a30f9d690 merge with master + conflicts 2020-10-12 13:21:02 -07:00
Tzanio Kolev 9e8396f5ca Merge pull request #1784 from mfem/mkl-pardiso
Interface to MKL Parallel Direct Sparse Solver for Clusters
2020-10-12 12:39:01 -07:00
Arturo Vargas 48df14a60b make style 2020-10-12 12:34:53 -07:00
Arturo Vargas c8c72d285b PR example fixes 2020-10-12 12:32:50 -07:00
Tzanio 7a917bec44 minor 2020-10-12 11:26:40 -07:00
Julian Andrej c11a9f232b change naming in asserts 2020-10-12 10:10:44 -07:00
Julian Andrej 0f0ad13b17 clarify some comments on the input parameters 2020-10-12 10:09:27 -07:00
Julian Andrej 042fe5c210 unsymmetric -> nonsymmetric 2020-10-12 10:04:02 -07:00
Julian Andrej c7a32cd6e7 style in ex11p 2020-10-12 10:02:34 -07:00
Julian Andrej 4f477a22d7 clarify naming in CHANGELOG 2020-10-12 10:01:43 -07:00
Julian Andrej b34523d8ec clarify naming in INSTALL 2020-10-12 10:00:42 -07:00
Arturo Vargas be9180d7b8 revert ex1,1p, change log, keep amgx examples under amgx folder 2020-10-12 09:22:38 -07:00
Arturo Vargas b7d40db11e configure master rank to only print 2020-10-12 08:28:45 -07:00
Tzanio Kolev a50f58f1de Merge pull request #1687 from mfem/hypre-ilu-dev
Wrapper for Hypre Flexible GMRES and Parallel ILU [hypre-ilu-dev]
2020-10-11 10:47:12 -07:00
Tzanio 6d4c5cb9e8 minor 2020-10-11 10:45:15 -07:00
Jason Hicken 2ff6105824 added description to CHANGELOG 2020-10-11 11:47:59 -04:00
Tzanio Kolev 3553d77f71 Merge pull request #1792 from mfem/jeremy/libceed-07
libceed - update to v0.7
2020-10-10 19:06:03 -07:00
Tzanio 96c7ad1fe8 Styling 2020-10-10 18:30:30 -07:00
Yohann Dudouit b43167f841 Lower the order of the tests. 2020-10-09 16:08:02 -07:00
Yohann Dudouit d27560980e Add ceed tests to cmake. 2020-10-09 16:02:02 -07:00
Arturo Vargas 18b629e39d update notice and github link to amgxwrapper 2020-10-09 14:31:13 -07:00
Will Pazner 2cc635a159 Split CEED unit tests and main file for faster compilation 2020-10-09 12:35:33 -07:00
Yohann Dudouit 5089710785 Add ceed_tests to .gitignore 2020-10-09 12:25:14 -07:00
Arturo Vargas d0cae7b65e improve documentation based on feedback 2020-10-09 10:36:16 -07:00
Veselin Dobrev 58066cb40a Various updates to the build systems mostly related to AmgX. 2020-10-08 22:29:47 -07:00
Yohann Dudouit c409addf73 Remove the test on tet for cuda-gen... 2020-10-08 15:57:19 -07:00
Yohann Dudouit 124be8083d Add tests on periodic and tet mesh. 2020-10-08 15:44:03 -07:00
Yohann Dudouit 1d362dabf4 Rewrite InitCeedBasis/Restriction to work with L2. 2020-10-08 15:43:43 -07:00
Tzanio Kolev bfbde13aef Merge pull request #1807 from mfem/probot-stale-dev
Configuration for the Probot Stale GitHub app
2020-10-08 15:20:16 -07:00
Veselin Dobrev 6feaeca0af Merge pull request #1661 from mfem/stdfunction-dev
[Discuss] Change function coefficients to use a std::function [stdfunction-dev]
2020-10-08 14:11:17 -07:00
Tzanio Kolev b0f3506cd1 Adjusted message 2020-10-08 12:13:38 -07:00
Tzanio Kolev 1324813877 Merge pull request #1683 from mfem/yohann/fix-doc-FULL
Use LEGACYFULL instead of FULL in the documentation.
2020-10-08 12:02:51 -07:00
Tzanio Kolev ffc2ddd19f Merge pull request #1724 from pghysels/fix-strumpack-hypre2160
Fix for STRUMPACK with Hypre >= 21600
2020-10-08 12:02:16 -07:00
Tzanio Kolev 99c541aaf0 Merge pull request #1702 from mfem/bug_parblocknlform
Bug - double ParBlockNonlinearForm::GetEnergy(const Vector &x)
2020-10-08 12:01:05 -07:00
nbeams aa278f92a3 update comments for ceed backends 2020-10-08 13:04:11 -04:00
Yohann Dudouit 3b55af5e7d Add an error message when used on periodic meshes. 2020-10-08 09:55:29 -07:00
Yohann Dudouit 94dfb80751 Remove SetupPA from DiffusionIntegrator. 2020-10-08 09:38:02 -07:00
Yohann 459a463105 Merge branch 'master' into yohann/test-ceed 2020-10-08 09:26:31 -07:00
Yohann Dudouit 7a9267a126 Remove IntegrationRule from InitCeedTensorRestriction. 2020-10-08 09:22:23 -07:00
Tzanio Kolev 36aa62fe1d Proper emoji? 2020-10-08 08:20:27 -07:00
Tzanio 0d9ad5bc2e Updated probot-stale configuration 2020-10-08 08:17:39 -07:00
Tzanio 9dc14f5a3a Configuration for the Probot Stale GitHub app 2020-10-07 19:58:44 -07:00
Tzanio Kolev b0a2d04644 Merge pull request #1803 from mfem/fix/lassen-debug-ci
Build cuda debug on lassen with O2 to speed up [fix/lassen-debug-ci]
2020-10-07 15:51:52 -07:00
Tzanio c55da48818 Fix for #1795 2020-10-06 15:57:15 -07:00
Adrien M. Bernede 76d45096d5 Build cuda debug on lassen with O2 to speed up 2020-10-06 15:15:14 -07:00
Yohann Dudouit 1ee3a4c7ae Improve documentation for AssembleMF. 2020-10-06 11:45:29 -07:00
Veselin Dobrev eec0efad09 Add a CHANGELOG entry for the changes in the function coefficient
classes.

Improve the formatting of some doxygen comments.
2020-10-05 18:03:58 -07:00
Julian Andrej 8ed2b92887 remove code duplication for printlevel 2020-10-05 16:33:34 -07:00
Julian Andrej 5161740a87 adapt to new sundials 2020-10-05 16:22:30 -07:00
Julian Andrej 717f28496f fix sundials cmake 2020-10-05 16:22:04 -07:00
Julian Andrej a2dd91f7a8 Merge branch 'master' into jfnk 2020-10-05 15:24:43 -07:00
Aaron Fisher 9bbbe58c4a Made the version numbers for the latest SuperLU library consistant. 2020-10-05 13:40:54 -07:00
Aaron Fisher f8a3266845 Setup the SuperLU integration to work with SuperLU_DIST 5 or 6. 2020-10-05 13:33:45 -07:00
Aaron Fisher 6f4bf0af67 make style 2020-10-05 10:59:50 -07:00
Tucker Babcock 90b933c56a fix merge conflict 2020-10-04 19:18:22 -04:00
Tucker Babcock 858cfdd2db remove support for overloaded functions in function coefficients that required metaprogramming. 2020-10-04 19:12:53 -04:00
Tzanio Kolev 84e68df837 Merge pull request #1744 from mfem/hotfix/pbnlf-essbdr
Support non-conforming meshes with BlockNonlinearForm and ParBlockNonlinearForm
2020-10-04 12:12:53 -07:00
Tzanio a74337433f Mention in CHANGELOG 2020-10-04 12:11:09 -07:00
Tzanio Kolev e70cf4c5d6 Merge pull request #1726 from balos1/sundials-gpu-dev
Add support for SUNDIALS GPU features [sundials-gpu-dev]
2020-10-04 11:58:40 -07:00
Tzanio Kolev 5ff4841dbc Merge pull request #1665 from mfem/matdiffpa
Matrix coefficients for diffusion PA
2020-10-04 11:54:23 -07:00
Tzanio Kolev 24cef871af Merge pull request #1765 from mfem/blfi-default-assemble-vector-dev
Default implementation of AssembleElementVector and AssembleFaceVector for bilinear integrators [blfi-default-assemble-vector-dev]
2020-10-04 11:49:20 -07:00
Tzanio 8b05534d60 Some comments 2020-10-04 11:48:29 -07:00
Julian Andrej d9a2fde388 remove MKL test code in cmake build system 2020-10-04 10:48:33 -07:00
Veselin Dobrev bdc302e5c2 In ex19p, remove an MPI_Finalize call which is now wrong. 2020-10-02 16:08:21 -07:00
Veselin Dobrev 4fbde641db In ex19p, MPI_Finalize() needs to be called after the destructor of
RubberOperator; this is now achieved using the MPI_Session class.
2020-10-01 17:12:55 -07:00
Jason Hicken ae547f984d fixed minor typo in call to Hypre SetPrecond for FGMRES 2020-10-01 15:11:49 -04:00
Julian Andrej 7a167341ba GMRES -> GMRESFlex 2020-10-01 11:00:50 -07:00
Julian Andrej 9a2904ba55 hypre version guard in test 2020-10-01 10:59:53 -07:00
Julian Andrej 04365ce503 correct typo in test labels 2020-10-01 10:57:36 -07:00
Julian Andrej db1e290721 test target typo 2020-10-01 10:36:19 -07:00
Julian Andrej 4e2383278f newlines 2020-10-01 10:36:03 -07:00
Jakub Červený ac94a3a64e Merge branch 'master' into nc-point-mat-index-dev 2020-10-01 11:09:55 +02:00
Jakub Červený dbad596d65 Documentation: added link to OrientedPointMatrix where edge_flags are commented. 2020-10-01 11:08:07 +02:00
Veselin Dobrev 70f4fcdf23 Due to failures in some cases, increase by a factor of 2 the
tolerance in the "ParallelFormLinearSystem" unit test.
2020-09-30 18:18:24 -07:00
Balos, Cody Joe f95a148f69 fix sundials find_package logic 2020-09-30 09:26:44 -07:00
jeremylt 43b9e2c66e libceed - update to v0.7 2020-09-30 07:52:04 -06:00
Jason Hicken c32232802c added unit test for HypreILU and HypreFGMRES 2020-09-29 21:53:21 -04:00
Balos, Cody Joe 31efd0d227 cmake fixes for SUNDIALS with CUDA 2020-09-29 17:50:36 -07:00
Jason Hicken 94fecaf5ad fixed accidental overwrite of ex7.cpp 2020-09-29 17:01:56 -04:00
Jason Hicken d1d30209f8 fixed the define guard statement, and removed some HypreILU default options 2020-09-29 16:13:10 -04:00
Jason Hicken f173273523 addressing PR issues 2020-09-29 14:46:37 -04:00
Jason Hicken e1539e50d0 Merge branch 'master' into hypre-ilu-dev 2020-09-29 08:55:17 -04:00
Andrew T. Barker aea150bee2 hypre.hpp: transition to a correct spelling for SetInitialIterate() 2020-09-28 08:04:49 -07:00
William Dawn eee6a45458 fixing spacing 2020-09-28 09:41:48 -04:00
William Dawn 4a155f28dd do not double-delete fec 2020-09-28 09:38:51 -04:00
Julian Andrej ffc65ee2f0 move config header out of guarding 2020-09-25 18:56:04 -07:00
Julian Andrej 197854c4c0 guard source and header 2020-09-25 18:50:51 -07:00
Julian Andrej baeed18fc6 remove user.mk 2020-09-25 18:44:40 -07:00
Julian Andrej c18b00f9a3 add to makefile build system 2020-09-25 18:38:20 -07:00
Julian Andrej 765918926f spellcheck 2020-09-25 15:24:52 -07:00
Julian Andrej 0829c40ef1 simplify JFNK codepath 2020-09-25 14:29:12 -07:00
Julian Andrej 78d01a2753 correct comment 2020-09-25 14:28:53 -07:00
Julian Andrej 1fcf44617b typo 2020-09-25 14:27:39 -07:00
Julian Andrej ccdd4151f5 adjust cmake build system to new naming and test output 2020-09-25 14:00:48 -07:00
Julian Andrej 5e2cc2d63b readability and refactoring 2020-09-25 13:57:11 -07:00
Julian Andrej 5aec9ffe25 change matrix data ownership 2020-09-25 13:32:50 -07:00
nbeams b267750431 consolidate CEED_HIP and CEED_CUDA checks 2020-09-25 15:55:29 -04:00
Julian Andrej 145877e2e3 correct interface comment 2020-09-25 11:03:28 -07:00
Julian Andrej cf336ec28f correct delete calls 2020-09-25 11:03:15 -07:00
Julian Andrej 14771eeb79 cmake build system tweak for LC 2020-09-25 10:31:43 -07:00
Julian Andrej 32d0df49d6 added changelog entry 2020-09-25 09:11:58 -07:00
Julian Andrej e5c5d1e419 make style 2020-09-25 08:56:53 -07:00
Julian Andrej 18dc8f7a56 documentation and refactor on teh pardiso interface 2020-09-25 08:07:29 -07:00
Julian Andrej 5720512ef2 add pardiso option to ex11p 2020-09-25 08:07:12 -07:00
bslazarov 08516cfa01 clean unused variables 2020-09-24 19:32:21 -07:00
bslazarov 022e96da56 clean up 2020-09-24 19:10:27 -07:00
Julian Andrej 8f602ab9d3 add support for MKL Cluster Pardiso 2020-09-24 15:15:13 -07:00
bslazarov a673e7e754 more cosmetics 2020-09-24 14:29:46 -07:00
Julian Andrej ce0b3e3b20 add support for KINSOL JFNK 2020-09-24 12:48:42 -07:00
bslazarov d1c9023a3a Merge branch 'master' into bug_parblocknlform 2020-09-24 11:25:22 -07:00
bslazarov 7b297e6661 cosmetics 2020-09-24 10:47:55 -07:00
bslazarov 7eaf68f030 style 2020-09-24 10:40:56 -07:00
bslazarov 0f2676f229 New 3D test for BlockNonlinearForm::GetEnergy() 2020-09-23 20:41:08 -07:00
Yohann Dudouit 11a025b26a Update makefile with new device option. 2020-09-23 12:20:53 -07:00
YohannandWill Pazner 41d0aeeea7 Update tests/unit/ceed/test_ceed.cpp
Handle more cleanly command line option for test_ceed.

Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2020-09-23 12:13:16 -07:00
Yohann Dudouit 56a985b586 Fix ceed_tests. 2020-09-23 12:03:03 -07:00
Yohann Dudouit 395ce0f1f6 Readd inadvertently deleted ceed_tests makefile target. 2020-09-23 11:42:07 -07:00
Balos, Cody Joe bf6012b2db Merge branch 'sundials-gpu-dev' of github.com:balos1/mfem into sundials-gpu-dev 2020-09-22 17:04:22 -07:00
Balos, Cody Joe 027d27fdf9 various minor fixes to address reviewer comments:
- use wildcard to detect sundials library directory
- add some error strings
- remove dead code
2020-09-22 17:04:10 -07:00
Balos, Cody Joe c879180508 call HostRead after ::Step to ensure data is up to date on host 2020-09-22 17:01:11 -07:00
camierjs 8d5aa9ffd9 Add using for nvcc warnings 2020-09-22 16:35:37 -07:00
Tucker Babcock 29294b603d setting size of elvect 2020-09-22 16:55:27 -04:00
Dylan Copeland 5bb18f7fae Removing the verification in Eval that the coefficient is not symmetric. 2020-09-21 17:42:43 -07:00
Yohann b71345dab6 Merge branch 'master' into yohann/test-ceed 2020-09-21 10:04:08 -07:00
Balos, Cody Joe c36d6ca2b1 sundials-gpu-dev: a couple minor fixes 2020-09-21 08:57:45 -07:00
Dylan Copeland 72e8c7771a Merge branch 'master' of github.com:mfem/mfem into matdiffpa 2020-09-18 10:17:08 -07:00
Tucker Babcock 58275bca9a make style 2020-09-17 15:01:14 -04:00
Tucker Babcock e8d1890399 Adding default implementation of AssembleElementVector and AssembleFaceVector for BilinearFormIntegrators that just multiply the state vector by the element stiffness matrix 2020-09-17 14:11:53 -04:00
Jakub Cerveny 2b9505aa0b Added more documentation for PointMatrixHash. 2020-09-17 10:25:44 +02:00
Yohann Dudouit b7584314d1 make style. 2020-09-16 18:30:55 -07:00
Yohann Dudouit 2a3858071a Fix typos. 2020-09-16 18:14:33 -07:00
Yohann Dudouit d62441a60f Rewrite RemoveCeedBasisAndRestriction to fix a bug on Linux. 2020-09-16 18:12:36 -07:00
Yohann Dudouit 846d019ece Erase entries when destroying the CeedBasis and CeedRestr. 2020-09-16 17:16:29 -07:00
Jakub Cerveny 0ad7d157c0 Added documentation for MatrixMap. 2020-09-16 10:35:51 +02:00
Yohann Dudouit 7fd34fa3c3 Merge branch 'yohann/vec-mass-diff' into yohann/test-ceed 2020-09-15 10:54:21 -07:00
Yohann Dudouit 530cd42e58 Use reference instead of value inside RemoveCeedBasisAndRestriction. 2020-09-15 10:31:12 -07:00
nbeams f2d5e1a1d3 update abort kernel functions for HIP 2020-09-14 19:45:51 -04:00
nbeams 28d366b77c allow use of short name for HIP backends in libCEED 2020-09-14 19:45:21 -04:00
nbeams 184fc62fc1 Merge branch 'master' into libceed-hip 2020-09-14 18:24:19 -04:00
Dylan Copeland 8592379542 Allowing symmetric matrix function coefficients to call Eval with copying of values to the full dense matrix. 2020-09-14 12:31:58 -07:00
Yohann Dudouit 42e2120d34 Merge branch 'yohann/vec-mass-diff' into yohann/test-ceed 2020-09-14 10:41:14 -07:00
William Dawn 281bc5a94c fixing leaks in ex11p 2020-09-14 10:27:12 -04:00
William Dawn 1903cabffd no need to set pointer to null in destructor 2020-09-14 09:52:36 -04:00
Veselin Dobrev 0f45ec77b6 Add some ches for assumptions in ceed q-functions. 2020-09-11 19:33:46 -07:00
Yohann Dudouit 8adbd3235c Factorize code into a InitCeedVector function. 2020-09-11 19:13:27 -07:00
Yohann Dudouit e3e9f961a9 Update CMakeLists. 2020-09-11 17:56:19 -07:00
Yohann Dudouit 97bdaeedcd Update CMakeLists. 2020-09-11 17:54:55 -07:00
Yohann Dudouit 2a65380426 include ceed.hpp 2020-09-11 17:09:47 -07:00
Yohann Dudouit c3802dff13 include ceed.hpp 2020-09-11 17:09:15 -07:00
Yohann Dudouit a05113cf08 Add a RemoveCeedBasisAndRestriction function. 2020-09-11 15:44:22 -07:00
Yohann Dudouit da1c9d8077 Add a RemoveCeedBasisAndRestriction function. 2020-09-11 15:43:55 -07:00
Yohann Dudouit 1cd5c44365 make style 2020-09-11 15:13:41 -07:00
Yohann Dudouit fdb3151fe4 make style 2020-09-11 15:13:12 -07:00
Yohann Dudouit d2843d8270 Remove basis and restr when destructing a FiniteElementSpace. 2020-09-11 15:03:08 -07:00
Yohann Dudouit dc6c10d5fb Remove basis and restr when destructing a FiniteElementSpace. 2020-09-11 15:02:07 -07:00
Yohann Dudouit 3f6912f9b0 Move things around. 2020-09-11 14:35:06 -07:00
Yohann Dudouit 99912229dc Let MFEM handle memory for nodes in CeedMFAssemble. 2020-09-11 14:29:30 -07:00
Yohann dd05e8b5d5 Merge branch 'master' into yohann/test-ceed 2020-09-11 11:10:46 -07:00
Yohann Dudouit 7d24b35af1 update CHANGELOG. 2020-09-11 10:59:11 -07:00
Yohann Dudouit f471b8e528 Use DiffusionIntegrator's IntegrationRule in VectorDiffusionIntegrator::AssembleElementVector. 2020-09-11 10:59:03 -07:00
Yohann Dudouit 4799747f2b Merge branch 'yohann/vec-mass-diff' into yohann/test-ceed 2020-09-11 10:24:59 -07:00
Yohann Dudouit 5d73899d88 move things around 2020-09-11 10:24:39 -07:00
Yohann Dudouit fb5ad410c6 Merge branch 'yohann/vec-mass-diff' into yohann/test-ceed 2020-09-11 10:23:25 -07:00
Yohann Dudouit a49325731e Let MFEM handle the memory for the mesh nodes. 2020-09-11 10:20:39 -07:00
Yohann Dudouit e73611a403 Use DEVICE_MASK instead of CUDA 2020-09-11 10:05:57 -07:00
Balos, Cody Joe a5bb313e52 Update to SUNDIALS 5.4.0 RC
This has no changes to the CPU only code (all changes were in
MFEM_USE_CUDA ifdef). The primary change is that mfem controls the
lifetime of the SUNMemoryHelper, thus the SundialsMemHelper class and
mfem::sunmemHelper were added.
2020-09-11 01:09:55 -07:00
Veselin Dobrev b9cd30304a Some formatting edits. 2020-09-11 00:20:08 -07:00
Aaron Fisher 89610836d3 Added the cmake system for the new example and updated the version numbers for SuperLU 2020-09-10 16:10:54 -07:00
Aaron Fisher b0f2390fa7 Minor changes to set us up to use SuperLU 6.3.1, and added a simple SuperLU Example. 2020-09-10 15:51:34 -07:00
Balos, Cody Joe d9e87e1e13 gnu make: look for sundials libraries in lib instead of lib64 2020-09-10 12:06:28 -07:00
Balos, Cody Joe 94e07ba735 remove unused function from FE_Evolution class in ex9 2020-09-10 12:03:50 -07:00
Yohann Dudouit 347e6f2447 Add the missing files..... 2020-09-09 15:40:13 -07:00
Yohann Dudouit 604dab7693 Update test_ceed.cpp to run the tests with AssemblyLevel::NONE. 2020-09-09 15:00:38 -07:00
Yohann Dudouit d2f3e33e72 Add fully matrix-free (MF) VectorMass and VectorDiffusion using libCEED. 2020-09-09 15:00:09 -07:00
Yohann Dudouit f01e45dfde Merge branch 'yohann/ceed-mf' into yohann/test-ceed 2020-09-09 14:39:31 -07:00
William Dawn 73a87ed46a simplify deleting vectors in destructor 2020-09-09 10:17:37 -04:00
Jakub Červený f31c63dad6 Checked hashing function and bucket size distribution. 2020-09-09 10:54:22 +02:00
Jakub Červený 1f8f0a010b make style 2020-09-09 10:34:32 +02:00
Julian Andrej d211b3c305 Simplify Array2D assignment operator 2020-09-08 16:33:59 -07:00
Jakub Červený a7f6573ebd Minor improvements. 2020-09-08 20:34:48 +02:00
Julian Andrej a5a6748731 Set sizes new on Array2D assignment operator 2020-09-08 11:22:38 -07:00
Tucker Babcock a789c63098 updating doc 2020-09-08 13:54:04 -04:00
Tucker Babcock 14c93a200c make style 2020-09-08 13:51:56 -04:00
Tucker Babcock 4145343273 merging master 2020-09-08 13:48:38 -04:00
Tucker Babcock 0eedb90c75 updated function coefficient implementation to use cleaner style suggested by @v-dobrev 2020-09-08 13:30:09 -04:00
Jakub Červený 41babcea77 Switchted to Array instead of std::vector in NCMesh::NCList. 2020-09-08 13:25:13 +02:00
Jakub Červený dbfd3747e4 ParNCMesh works with NCList::point_matrices (still uses aux_pm_store though) 2020-09-08 13:05:33 +02:00
Julian Andrej 109e68d7bb Guard parallel calls in serial build 2020-09-07 11:56:48 -07:00
Jakub Červený 5a06fa5798 New NCList point matrices work in serial. 2020-09-06 20:54:46 +02:00
Jakub Červený a087f7f4f1 Exporting point matrices works. 2020-09-04 17:08:22 +02:00
Julian Andrej 7933fd9b88 Make blocknonlinearform and parblocknonlinearform work with non conforming meshes 2020-09-04 08:05:11 -07:00
Julian Andrej 9a4f7ed262 Modify ex19/ex19p to support non conforming meshes 2020-09-04 07:59:38 -07:00
Jakub Červený 618a8fb85f Creating slave matrix indices with MatrixMap, changed everywhere. 2020-09-04 16:11:02 +02:00
Jakub Červený 07962a73cd WIP hashing point matrices into indices for NCMesh::Slave. 2020-09-04 13:56:09 +02:00
Yohann Dudouit 254724d96f Update incorrect documentation. 2020-09-03 11:56:36 -07:00
Balos, Cody Joe a35d0c984d revert accidental change 2020-09-03 11:55:35 -07:00
Balos, Cody Joe b3659147a5 remove unused code 2020-09-03 11:50:37 -07:00
Balos, Cody Joe 3a1829ba3e update comments for functions marked as deprecated 2020-09-03 11:50:22 -07:00
Balos, Cody Joe 4b292c09a9 fix alignment 2020-09-03 11:45:11 -07:00
Balos, Cody Joe 311eb40ac3 remove TODO comments about ToNVector function 2020-09-03 11:43:01 -07:00
Julian Andrej f7f5b9a82b Moved ess dof elimination from vdofs to tdofs in parallel 2020-09-02 16:13:16 -07:00
Yohann Dudouit fd396ac682 Move code in CEED guard to avoid dead code. 2020-09-02 15:29:28 -07:00
Yohann Dudouit 90e02bbd2d Improve doc. 2020-09-02 14:35:44 -07:00
Yohann Dudouit dc6517f77e move #endif. 2020-09-01 22:07:13 -07:00
Yohann Dudouit 67b317f3df Remove dead code. 2020-09-01 22:02:02 -07:00
Yohann Dudouit 33e29a4bd1 Change IntegrationRule in VectorDiffusion. 2020-09-01 21:11:48 -07:00
Yohann Dudouit d96f7c2c71 Fix a bug. 2020-09-01 21:11:05 -07:00
Yohann Dudouit bc4199f4a5 Replace star and fichera by their q3 versions. 2020-09-01 20:57:56 -07:00
Yohann Dudouit 4cbdfd34ea Change IntegrationRule in VectorDiffusion. 2020-09-01 20:57:10 -07:00
Yohann Dudouit efb937ed06 Fix a bug. 2020-09-01 20:56:40 -07:00
Yohann Dudouit cb8c9e543a Modiify test_ceed for Vector Mass and Diffusion. 2020-09-01 19:45:53 -07:00
Yohann Dudouit deaaea5f12 Add VectorMass and VectorDiffusion to libCEED tests. 2020-09-01 17:13:37 -07:00
Yohann Dudouit 8433c504f5 typo. 2020-09-01 17:12:56 -07:00
Yohann Dudouit 9a52687795 Rename grid to quad. 2020-09-01 17:12:20 -07:00
Yohann Dudouit 2ece2a07f7 Merge branch 'yohann/vec-mass-diff' into yohann/test-ceed 2020-09-01 16:21:53 -07:00
Yohann Dudouit 18c0f1b8ba Reorder initialization in constructor. 2020-09-01 16:19:19 -07:00
Yohann Dudouit 9cd90ff055 Merge branch 'yohann/vec-mass-diff' into yohann/test-ceed 2020-09-01 16:16:41 -07:00
Yohann Dudouit 5e2f4816fd Merge branch 'yohann/ceed-coeff' into yohann/test-ceed 2020-09-01 15:56:19 -07:00
Yohann Dudouit d3b7601f88 Destroy CeedQFunctionContext. 2020-09-01 15:48:22 -07:00
Yohann Dudouit 00444a21db Add a constructor that initializes fields to NULL. 2020-09-01 15:14:56 -07:00
Yohann Dudouit 6823ecee8a Merge branch 'master' into yohann/ceed-coeff 2020-09-01 15:07:34 -07:00
Yohann Dudouit 131e8ba848 Remove useless default case 2020-09-01 15:03:20 -07:00
Yohann Dudouit af51fabcc8 Fix a potential bug. 2020-09-01 14:54:51 -07:00
Yohann Dudouit 401c13fef7 Improve error messages when using MF without libCEED. 2020-09-01 14:51:50 -07:00
Yohann Dudouit 9a141f8629 make style. 2020-09-01 14:37:05 -07:00
Yohann Dudouit dc5a600503 Rewrite constructors. 2020-09-01 11:31:32 -07:00
Yohann Dudouit 1fd8fff49f Move the #ifdef MFEM_USE_CEED logic inside ceed files. 2020-09-01 11:16:51 -07:00
Balos, Cody Joe 3f62a99c64 update N_NewCustom name 2020-08-31 15:54:44 -07:00
Yohann Dudouit f89f626c43 Fix inaccurate comments. 2020-08-31 15:10:18 -07:00
Yohann Dudouit 3eec9ace81 Simplify AssembleMF 2020-08-31 15:06:48 -07:00
Yohann Dudouit a4c3a02c70 Use new context interface for libCEED. 2020-08-31 15:06:26 -07:00
Yohann Dudouit 65e9fcbc2d Merge remote-tracking branch 'origin/master' into yohann/ceed-mf 2020-08-31 15:00:38 -07:00
Yohann Dudouit 2c4cc326de Merge remote-tracking branch 'origin/master' into yohann/vec-mass-diff 2020-08-31 09:57:10 -07:00
Yohann Dudouit 7b5f176765 Refactor Ceed Setup in mass_pa and diffusion_pa 2020-08-31 09:51:44 -07:00
YohannandWill Pazner c5e505b000 Update fem/bilininteg_vecmass.cpp
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2020-08-31 09:45:17 -07:00
YohannandWill Pazner 033592a234 Update fem/bilininteg_vecdiffusion.cpp
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2020-08-31 09:44:51 -07:00
Balos, Cody Joe a5a7608de0 update INSTALL 2020-08-26 13:49:06 -07:00
Balos, Cody Joe 8b02cfc752 fix comment 2020-08-26 13:45:36 -07:00
Balos, Cody Joe 06e4c5039e update CHANGELOG 2020-08-26 13:40:12 -07:00
Balos, Cody Joe 206df44ad2 Always do base.Read() before making an alias in MakeRef.
See https://github.com/mfem/mfem/issues/1578#issuecomment-649962962 for an explanation of why this is necessary.
2020-08-26 13:20:36 -07:00
Balos, Cody Joe c5e75c6472 cleanup 2020-08-26 13:20:36 -07:00
Balos, Cody Joe 8551ca83e9 revert mem_manager.hpp whitespace changes 2020-08-26 13:20:36 -07:00
Balos, Cody Joe c7ead47f1d remove unused includes 2020-08-26 13:20:36 -07:00
Balos, Cody Joe 72e9164c66 revert sample runs section of comment in sundials modification of ex9 2020-08-26 13:20:36 -07:00
Balos, Cody Joe 6f78235cfe keep sundials backwards compatibility when not using cuda 2020-08-26 13:20:36 -07:00
Balos, Cody Joe 937db1a293 Add support for SUNDIALS GPU features
Add support for SUNDIALS CUDA features. These changes will be easily
extendable to support future GPU features in SUNDIALS, e.g. HIP
features. To keep things clean, this creates a SundialsNVector
class to interface with the SUNDIALS N_Vector. This class inherits
from the mfem::Vector class, and follows the pattern used in MFEM
interfaces to other libraries such as PETSc and hypre.
2020-08-26 13:20:36 -07:00
Yohann Dudouit ae549f035a Update comments. 2020-08-26 12:20:16 -07:00
Yohann Dudouit e23c886030 Add destructor to VectorMass and VectorDiffusion. 2020-08-25 15:28:22 -07:00
Dylan Copeland cf0222e0ce Removing height<4 condition. 2020-08-25 14:08:08 -07:00
Yohann Dudouit 7e490f5f05 Merge branch 'yohann/ceed-coeff' into yohann/test-ceed 2020-08-25 13:40:38 -07:00
Yohann Dudouit d41c880974 Update destructor. 2020-08-25 13:39:12 -07:00
Yohann Dudouit 530c37ad8e Merge remote-tracking branch 'origin/jeremy/libceed-refactor-dev' into yohann/test-ceed 2020-08-25 13:18:20 -07:00
Yohann Dudouit 5dbeef3916 Merge branch 'jeremy/libceed-refactor-dev' into yohann/test-ceed 2020-08-25 12:54:36 -07:00
Yohann Dudouit 5afe254020 Merge remote-tracking branch 'origin/jeremy/libceed-refactor-dev' into yohann/test-ceed 2020-08-25 12:54:05 -07:00
Yohann Dudouit 1b34ddd6d2 Use INFO instead of SECTION. 2020-08-25 12:25:26 -07:00
Yohann Dudouit e155c66b4a Merge branch 'yohann/ceed-coeff' into yohann/test-ceed 2020-08-25 12:21:50 -07:00
Yohann Dudouit 8d17dbb03a Refactor test_ceed.cpp. 2020-08-25 12:00:45 -07:00
Yohann Dudouit 839cbc71ce Merge remote-tracking branch 'origin/jeremy/libceed-refactor-dev' into yohann/test-ceed 2020-08-25 10:52:43 -07:00
Pieter Ghysels ef0858c7a1 Fix for STRUMPACK with hypre >= 21600 2020-08-25 10:48:41 -07:00
Yohann Dudouit f6fe94e131 Merge remote-tracking branch 'origin/master' into yohann/test-ceed 2020-08-25 10:32:16 -07:00
Yohann Dudouit f757b76f92 Use device pointer for GridFunctionCoefficient. 2020-08-24 21:22:33 -07:00
Yohann Dudouit 6e6eddd169 Test only order 3 to fasten tests. 2020-08-24 21:21:19 -07:00
Yohann Dudouit 6a6460b809 Change orders in test_ceed. 2020-08-24 17:06:31 -07:00
Yohann Dudouit d216b13f96 Remove unused variable. 2020-08-24 15:45:38 -07:00
Yohann Dudouit 493460f941 Add GPU tests for libCEED. 2020-08-24 14:14:13 -07:00
Dylan Copeland 2b82976ba9 Merge branch 'master' of github.com:mfem/mfem into matdiffpa 2020-08-24 13:05:27 -07:00
Yohann Dudouit c51f2a407d Minor 2020-08-24 09:58:48 -07:00
Dylan CopelandandStefan Henneking 7d756f6016 Remove newline.
Co-authored-by: Stefan Henneking <stefan.henneking@gmail.com>
2020-08-23 13:15:44 -07:00
Yohann Dudouit a696640253 Regorganize test_ceed and add to makefile. 2020-08-21 17:08:35 -07:00
Yohann Dudouit cb973e773d Move test_ceed in a ceed folder. 2020-08-21 15:32:15 -07:00
Yohann Dudouit 34231caee4 Add a skeleton to test the libCEED integration in MFEM. 2020-08-21 15:17:22 -07:00
Yohann Dudouit 2db9129cd7 Remove test_ceed 2020-08-21 15:15:41 -07:00
Yohann Dudouit 56228ded89 typos. 2020-08-21 15:14:24 -07:00
Yohann Dudouit def6aa3ae3 Move test_ceed in miniapps. 2020-08-21 14:49:47 -07:00
Yohann Dudouit 6ba206fcf2 Include ceed.hpp in the ceed test. 2020-08-21 14:17:08 -07:00
Yohann Dudouit 7555df1d11 Remove white space 2020-08-21 13:41:05 -07:00
Yohann Dudouit 9627d2b0ef make style 2020-08-21 13:30:49 -07:00
Yohann Dudouit b24169c858 make style 2020-08-21 13:19:15 -07:00
Yohann Dudouit a61dae6313 Add a test for the libCEED integration. 2020-08-21 13:17:45 -07:00
Yohann Dudouit 39bab7204b make style 2020-08-21 12:28:59 -07:00
Yohann Dudouit b7cabc6aa2 Remove some magic numbers. 2020-08-21 11:40:21 -07:00
Yohann Dudouit a176fb2d52 Add support for all scalar coefficient types. 2020-08-21 11:30:22 -07:00
Yohann DudouitandJeremy L Thompson d28659a50c Fix a bug when vdim > 1.
Co-authored-by: Jeremy L Thompson <25011573+jeremylt@users.noreply.github.com>
2020-08-20 15:58:07 -07:00
nbeams b8992fa122 make style 2020-08-20 18:49:54 -04:00
Yohann Dudouit 485600bbd3 Add vdim to the BuildContext. 2020-08-20 15:35:17 -07:00
Yohann Dudouit 1aea0a752b Minor 2020-08-20 14:52:23 -07:00
Yohann Dudouit 512f3283e8 Modify Qfunctions for mass and diffusion to work in vector case. 2020-08-20 14:39:08 -07:00
nbeams deeef2572d TEMPORARY: hack to get around hipcc error 2020-08-20 17:23:22 -04:00
nbeams 0264406aa9 add XLINKER flag for HIP 2020-08-20 17:20:45 -04:00
nbeams 372dd6b3b2 enable HIP backend for libCEED 2020-08-20 17:20:10 -04:00
Yohann Dudouit 377de82d76 make style 2020-08-20 13:16:32 -07:00
nbeams 0246d693fb Merge branch 'jeremy/libceed-ctx-dev' into libceed-hip 2020-08-20 15:31:47 -04:00
Yohann Dudouit cc7634d475 Add support for Vector Mass and Diffusion using libCEED. 2020-08-20 12:01:56 -07:00
YohannandTzanio Kolev 91f9984a70 Update fem/complex_fem.hpp
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2020-08-17 12:13:40 -07:00
YohannandTzanio Kolev fd67897628 Update fem/complex_fem.hpp
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2020-08-17 12:13:34 -07:00
YohannandTzanio Kolev 77defb3b4a Update fem/bilinearform.hpp
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2020-08-17 12:13:23 -07:00
Dylan Copeland 74fbc63ad7 Merge branch 'master' of github.com:mfem/mfem into matdiffpa 2020-08-14 14:27:56 -07:00
lazarov e6d7736c51 mod 2020-08-13 07:22:24 -07:00
lazarov 79760fc4ab Bug fix for double ParBlockNonlinearForm::GetEnergy(const Vector &x) 2020-08-12 22:30:56 -07:00
Dylan Copeland d245aaa52c Multi-threading some quadrature loops. 2020-08-06 12:43:04 -07:00
Jason Hicken 0e7ebbc839 added safe-guard for NSH option, and included more documentation on ilu_type 2020-08-05 12:03:30 -04:00
Jason Hicken 5949d421f1 added wrappers for Hypre FGMRES and ILU 2020-08-04 17:47:47 -04:00
Yohann Dudouit d386fc532d Remove innaccurate documentation (I think). 2020-08-04 12:01:08 -07:00
Yohann Dudouit 55233ea4d1 Use LEGACYFULL instead of FULL in the documentation. 2020-08-04 11:46:12 -07:00
Dylan Copeland d5d267eefd Fixing merge. 2020-08-03 15:08:47 -07:00
Dylan Copeland c14581a1e8 Merge branch 'master' of https://github.com/mfem/mfem into matdiffpa 2020-08-03 13:03:52 -07:00
William Dawn 051a1bef0f Merge branch 'master' of github.com:wcdawn/mfem into master 2020-08-03 11:43:08 -06:00
William Dawn 76c05e2404 address leaks in SlepcEigenSolver 2020-08-03 11:42:04 -06:00
William Dawn dd05b45c62 address leaks in SlepcEigenSolver 2020-07-31 16:09:01 -06:00
Tucker Babcock f08de96178 updating documentation 2020-07-31 14:24:43 -07:00
Yohann Dudouit c3fa8cdf02 make style 2020-07-31 09:06:04 -07:00
Yohann Dudouit b76a9fbb68 Add mass and diffusion MF to CMakeLists. 2020-07-30 17:05:38 -07:00
Yohann Dudouit 72b1dec3e7 Remove unnecessary qdatasize for MF. 2020-07-30 16:31:23 -07:00
Yohann Dudouit 7f1bde17a2 Add AssembleDiagonalMF. 2020-07-30 16:20:21 -07:00
Yohann Dudouit a59c17e6ae Add fully matrix-free support in MFEM using libCEED. 2020-07-30 16:11:12 -07:00
Tucker Babcock f19fcd01e6 switching to initializers instead of assignments in function coefficient constructors 2020-07-30 14:57:16 -07:00
Tucker Babcock e315af4d4c adding documentation to new members in detail namespace 2020-07-30 14:30:53 -07:00
Tucker Babcock fef6f5bbaf make style 2020-07-30 14:16:17 -07:00
Tucker Babcock 936f49bbad fix lambda function time-independent vector function coefficient constructor 2020-07-30 14:12:06 -07:00
Tucker Babcock febc9a8a6e using template meta-programming SFINAE to remove ambiguity of constructor for stateless lambda 2020-07-30 12:43:59 -07:00
Dylan Copeland 85d7da47a1 Removing SetSymmetric function. Verifying symmetry flag in MatrixFunctionCoefficient::Eval. 2020-07-30 11:40:18 -07:00
Dylan Copeland 66ab25dc09 Eliminating some unnecessary memory. 2020-07-29 21:27:57 -07:00
Dylan Copeland 39f72c9c6b Extending diffusion diagonal assembly for all coefficient types, with unit tests. 2020-07-29 16:14:20 -07:00
Dylan Copeland e4f8acb473 Adding vector coefficients to DiffusionIntegrator, with unit tests. Unifying the setup functions for diffusion and H(curl) mass. 2020-07-29 13:01:48 -07:00
Dylan Copeland 5b8c4ebc0f Adding matrix coefficient support for diffusion PA, with unit tests. 2020-07-28 22:26:09 -07:00
Tucker Babcock deccdec496 using delegating constructors to allow construction with function pointers. This is needed because if one tried to construct a FunctionCoefficient with a function that was overloaded, it could not be implicitly converted to a std::function 2020-07-28 15:38:46 -07:00
Tucker Babcock 3e0e2a7498 fixes for CI 2020-07-28 10:39:44 -07:00
Tucker Babcock 7206fdb854 changing function coefficients to use std::functions instead of function pointers 2020-07-27 21:07:49 -07:00
128 changed files with 7468 additions and 2552 deletions
+61
View File
@@ -0,0 +1,61 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 30
# Number of days of inactivity before an Issue or Pull Request with the stale
# label is closed. Set to false to disable. If disabled, issues still need to
# be closed manually, but will remain marked as stale.
daysUntilClose: 7
# Only issues or pull requests with all of these labels are check if stale.
# Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set
# to `[]` to disable
exemptLabels:
- bug
- WIP
- ready-for-review
- in-review
- in-next
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
:warning: This issue or PR has been automatically marked as stale because it has not
had any activity in the last month. *If no activity occurs in the next week, it will
be automatically closed.* Thank you for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
# only: issues
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:
# daysUntilStale: 30
# markComment: >
# This pull request has been automatically marked as stale because it has not had
# recent activity. It will be closed if no further activity occurs. Thank you
# for your contributions.
# issues:
# exemptLabels:
# - confirmed
+67 -53
View File
@@ -102,28 +102,29 @@ examples/ex25.mesh
examples/ex25-*.gf
examples/ex25p-*.*
examples/sundials/ex9
examples/sundials/ex1[06]
examples/sundials/ex9p
examples/sundials/ex1[06]p
examples/amgx/ex1
examples/amgx/ex1p
examples/amgx/.logamgx
examples/amgx/refined.mesh
examples/amgx/sol.gf
examples/amgx/mesh.*
examples/amgx/sol.*
examples/sundials/ex9.mesh
examples/sundials/ex9-mesh.*
examples/sundials/ex9-init.*
examples/sundials/ex9-final.*
examples/sundials/Example9*
examples/sundials/deformed.*
examples/sundials/velocity.*
examples/sundials/elastic_energy.*
examples/sundials/ex16.mesh
examples/sundials/ex16-mesh.*
examples/sundials/ex16-init.*
examples/sundials/ex16-final.*
examples/sundials/Example16*
examples/gingko/ex1
examples/gingko/refined.mesh
examples/gingko/sol.gf
examples/gingko/mesh.*
examples/gingko/sol.*
examples/hiop/ex9
examples/hiop/ex9p
examples/hiop/ex9.mesh
examples/hiop/ex9-mesh.*
examples/hiop/ex9-init.*
examples/hiop/ex9-final.*
examples/petsc/ex[1-69]p
examples/petsc/ex1[0-1]p
examples/petsc/mesh.*
examples/petsc/sol.*
examples/petsc/sol_p.*
@@ -141,28 +142,51 @@ examples/petsc/mode_*
examples/pumi/ex1
examples/pumi/ex[126]p
examples/hiop/ex9.mesh
examples/hiop/ex9-mesh.*
examples/hiop/ex9-init.*
examples/hiop/ex9-final.*
examples/pumi/refined.mesh
examples/pumi/sol.gf
examples/pumi/mesh.*
examples/pumi/sol.*
examples/pumi/displaced.mesh
examples/sundials/ex9
examples/sundials/ex1[06]
examples/sundials/ex9p
examples/sundials/ex1[06]p
examples/sundials/ex9.mesh
examples/sundials/ex9-mesh.*
examples/sundials/ex9-init.*
examples/sundials/ex9-final.*
examples/sundials/Example9*
examples/sundials/deformed.*
examples/sundials/velocity.*
examples/sundials/elastic_energy.*
examples/sundials/ex16.mesh
examples/sundials/ex16-mesh.*
examples/sundials/ex16-init.*
examples/sundials/ex16-final.*
examples/sundials/Example16*
examples/superlu/ex1p
examples/superlu/mesh.*
examples/superlu/sol.*
miniapps/adjoint/cvsRoberts_ASAi_dns
miniapps/adjoint/adjoint_advection_diffusion
miniapps/electromagnetics/volta
miniapps/electromagnetics/tesla
miniapps/electromagnetics/maxwell
miniapps/electromagnetics/joule
miniapps/electromagnetics/Volta-AMR*
miniapps/electromagnetics/Tesla-AMR*
miniapps/electromagnetics/Maxwell-Parallel*
miniapps/electromagnetics/Joule_*
miniapps/gslib/field-diff
miniapps/gslib/field-interp
miniapps/gslib/findpts
miniapps/gslib/pfindpts
miniapps/meshing/mobius-strip
miniapps/meshing/klein-bottle
miniapps/meshing/toroid
@@ -176,7 +200,6 @@ miniapps/meshing/pmesh-optimizer
miniapps/meshing/minimal-surface
miniapps/meshing/pminimal-surface
miniapps/meshing/polar-nc
miniapps/meshing/mobius-strip.mesh
miniapps/meshing/klein-bottle.mesh
miniapps/meshing/toroid-*.mesh
@@ -190,9 +213,25 @@ miniapps/meshing/optimized*
miniapps/meshing/perturbed*
miniapps/meshing/polar-nc.mesh
miniapps/navier/navier_mms
miniapps/navier/navier_kovasznay
miniapps/navier/navier_tgv
miniapps/navier/navier_shear
miniapps/navier/navier_3dfoc
miniapps/navier/tgv_out*.txt
miniapps/navier/*_output
miniapps/nurbs/nurbs_ex1
miniapps/nurbs/nurbs_ex1p
miniapps/nurbs/nurbs_ex11p
miniapps/nurbs/refined.mesh
miniapps/nurbs/mesh.*
miniapps/nurbs/sol.*
miniapps/nurbs/mode_*
miniapps/nurbs/Example1*
miniapps/performance/ex1
miniapps/performance/ex1p
miniapps/performance/refined.mesh
miniapps/performance/mesh.*
miniapps/performance/sol.*
@@ -210,7 +249,6 @@ miniapps/toys/rubik
miniapps/toys/snake
miniapps/toys/lissajous
miniapps/toys/mondrian
miniapps/toys/snake-init.mesh
miniapps/toys/snake-user.mesh
miniapps/toys/snake-joined.mesh
@@ -225,37 +263,13 @@ miniapps/toys/lissajous.mesh
miniapps/toys/lissajous.gf
miniapps/toys/mondrian.mesh
miniapps/nurbs/nurbs_ex1
miniapps/nurbs/nurbs_ex1p
miniapps/nurbs/nurbs_ex11p
miniapps/nurbs/refined.mesh
miniapps/nurbs/mesh.*
miniapps/nurbs/sol.*
miniapps/nurbs/mode_*
miniapps/nurbs/Example1*
miniapps/gslib/field-diff
miniapps/gslib/field-interp
miniapps/gslib/findpts
miniapps/gslib/pfindpts
miniapps/navier/navier_mms
miniapps/navier/navier_kovasznay
miniapps/navier/navier_tgv
miniapps/navier/navier_shear
miniapps/navier/navier_3dfoc
miniapps/navier/tgv_out*.txt
miniapps/navier/*_output
miniapps/adjoint/cvsRoberts_ASAi_dns
miniapps/adjoint/adjoint_advection_diffusion
# Unit test binary and outputs
tests/unit/output_meshes
tests/unit/unit_tests
tests/unit/punit_tests
tests/unit/sedov_tests_*
tests/unit/psedov_tests_*
tests/unit/ceed_tests
# Test script output
tests/scripts/*.err
+1 -1
View File
@@ -37,7 +37,7 @@ build_mfem_debug_ser_lassen:
- mkdir -p ${BUILD_PATH}
- cp -r ${CI_PROJECT_DIR} ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser_debug
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser_debug
- lalloc 1 -W 5 -q pdebug make -j cuda MFEM_DEBUG="YES" CUDA_ARCH=sm_70
- lalloc 1 -W 5 -q pdebug make -j cuda MFEM_DEBUG="YES" CPPFLAGS=-O2 CUDA_ARCH=sm_70
# Sanity check
sanitycheck_mfem_ser_lassen:
+62 -2
View File
@@ -11,6 +11,16 @@
Version 4.1.1 (development)
===========================
libCEED integration improvements
--------------------------------
- Add support for all types of (scalar) Coefficient.
- Add support for VectorMassIntegrator and VectorDiffusionIntegrator.
- Add support for AssemblyLevel::NONE for MassIntegrator, DiffusionIntegrator,
VectorMassIntegrator, and VectorDiffusionIntegrator. This level of assembly
fully applies on the fly the finite element operator.
Meshing improvements
--------------------
- The graph linear ordering library Gecko, previously an external dependency, is
@@ -56,10 +66,30 @@ Performance improvements
Improved GPU capabilities
-------------------------
- Added a new solver class for simple integration with NVIDIA's multigrid
library, AmgX. The AmgX class is designed to work as a standalone solver or
preconditioner for existing MFEM solvers. It uses MFEM's sparse matrix format
for serial runs and the HypreParMatrix format for parallel runs.
The new solver may be configured to run with one GPU per MPI rank or with more
MPI ranks than GPUs. In the latter case, matrices and vectors are consolidated
to ranks communicating with the GPUs and the solution is then broadcasted.
Although CUDA is required to build, the AmgX support is compatible with the
MFEM CPU device configuration. The examples/amgx folder illustrates how to
integrate AmgX in existing MFEM applications.
The AmgX solver class is partially based on: "AmgXWrapper: An interface
between PETSc and the NVIDIA AmgX library", by Pi-Yueh Chuang and Lorena
A. Barba, doi:10.21105/joss.00280.
- Added support for Chebyshev accelerated polynomial smoother on GPU.
- Optimized AMD/HIP kernel support.
- Enabled HIP support in the libCEED integration, which is now available via the
"ceed-hip" device backend.
- Added a Full Assembly mode compatible with Device kernel execution. This
assembly level builds on top of the current Element Assembly kernels to
compute a global sparse matrix. All integrators supported by element assembly
@@ -67,14 +97,15 @@ Improved GPU capabilities
- Added CUDA support for sparse matrix-vector multiplication with cuSPARSE.
- Added AmgX solver class for simple integration with NVIDIA's multigrid library.
- Added support for BlockOperator on GPU. See the updated Example 5.
- Added partial assembly and GPU support for complex operators, including the
classes ComplexOperator, [Par]ComplexGridFunction, [Par]ComplexLinearForm, and
[Par]SesquilinearForm. See the updated Example 22.
- Added CUDA support for SUNDIALS ODE integrators. See the updated SUNDIALS
modification of Example 9/9p.
Discretization improvements
---------------------------
- Added support for matrix-free interpolation and restriction operators between
@@ -101,6 +132,9 @@ Discretization improvements
Additionally, new LinearForm integrators were also added which make use of
these new QuadratureFunction coefficient classes.
- Non-conforming meshes are now supported with block nonlinear forms. See the
updated Example 19/19p.
- Added support face integrals on the boundaries of NURBS meshes.
- Added support for interpolation of functions in L2, H(div) and H(curl)
@@ -111,6 +145,12 @@ Discretization improvements
member methods in GridFunction and ParGridFunction. See the rates.cpp file in
the tests/convergence directory for sample usage.
- The C-function based coefficient classes (FunctionCoefficient,
VectorFunctionCoefficient, and MatrixFunctionCoefficient) now use the more
general std::function class template. This allows the classes to be backward
compatible (i.e. they can still work with C-functions) and, in addition,
support any "callable", e.g. lambda functions.
Linear and nonlinear solvers
----------------------------
- Added power method to iteratively estimate the largest eigenvalue and the
@@ -119,6 +159,9 @@ Linear and nonlinear solvers
- Added initial support for h- and p-multigrid solvers and preconditioners for
matrix-based and matrix-free discretizations with basic GPU capability.
- Added wrappers for Hypre's flexible GMRES solver and the new parallel ILU
preconditioner. The latter requires hypre version 2.19.0 or later.
- Added a new IterativeSolverMonitor class that allows to monitor the residual
and solution during the solving process of an IterativeSolver after every
iteration.
@@ -139,6 +182,15 @@ Linear and nonlinear solvers
- Added partially assembled convergent diagonal preconditioner for adaptively
refined meshes (i.e. non-conforming finite element spaces), see Example 6/6p.
- Upgraded SuperLU interface to use SuperLU_DIST 6.3.1. Added a simple SuperLU
example in the new directory examples/superlu.
- Extended the KINSOL (SUNDIALS) nonlinear solver interface to support the
Jacobian-free Newton-Krylov method. A usage example is shown in Example 10p.
- Added an interface to the MKL CPardiso solver -- an MPI-parallel sparse direct
solver developed by Intel. See Example 11p for an illustration of its usage.
New and updated examples and miniapps
-------------------------------------
- Added a new example, Example 25/25p, to demonstrate the use of a Perfectly
@@ -213,6 +265,8 @@ Improved testing
triggered only by LLNL developers, see .gitlab-ci.yml, the .gitlab directory
and the updated CONTRIBUTING.md file.
- Add tests for the libCEED integration in MFEM.
- Added testing of the parallel mesh format in tests/par-mesh-format.
Miscellaneous
@@ -225,6 +279,9 @@ Miscellaneous
ParaView v5.8.1. In addition, ADIOS2 allows for setting a user-defined number
of data substreams/subfiles at scale. See examples 5, 9, 12, 16.
- Added VTU output of boundary elements and attributes and parallel VTU (PVTU)
output of parallel meshes for visualization using ParaView.
- The integration order used in the ComputeLpError and ComputeElementLpError
methods of class GridFunction has been increased.
@@ -233,6 +290,9 @@ Miscellaneous
- Renamed "Backend::DEBUG" to "Backend::DEBUG_DEVICE" to avoid conflicts,
as DEBUG is sometimes used as a macro.
- Change the IntegrationRule inside VectorDiffusionIntegrator to use the same
quadrature as DiffusionIntegrator.
Version 4.1, released on March 10, 2020
=======================================
+15 -8
View File
@@ -240,12 +240,14 @@ endif()
# SUNDIALS
if (MFEM_USE_SUNDIALS)
if (NOT MFEM_USE_MPI)
find_package(SUNDIALS REQUIRED NVector_Serial CVODES ARKODE KINSOL)
else()
find_package(SUNDIALS REQUIRED
NVector_Serial NVector_Parallel NVector_ParHyp CVODES ARKODE KINSOL)
set(SUNDIALS_COMPONENTS CVODES ARKODE KINSOL NVector_Serial)
if (MFEM_USE_MPI)
list(APPEND SUNDIALS_COMPONENTS NVector_Parallel NVector_MPIPlusX)
endif()
if (MFEM_USE_CUDA)
list(APPEND SUNDIALS_COMPONENTS NVector_Cuda)
endif()
find_package(SUNDIALS REQUIRED ${SUNDIALS_COMPONENTS})
endif()
# Mesquite
@@ -296,8 +298,7 @@ if (MFEM_USE_CEED)
endif()
if (MFEM_USE_AMGX)
include_directories(${AMGX_DIR}/include)
link_directories(${AMGX_DIR}/lib64 -L${AMGX_DIR}/lib -Xlinker=-rpath=${CUDA_HOME}/lib64)
find_package(AMGX REQUIRED)
endif()
if (MFEM_USE_CONDUIT)
@@ -351,6 +352,12 @@ if (MFEM_USE_ADIOS2)
find_package(ADIOS2 REQUIRED)
endif()
if (MFEM_USE_MKL_CPARDISO)
if (MFEM_USE_MPI)
find_package(MKL_CPARDISO REQUIRED MKL_SEQUENTIAL MKL_LP64 MKL_MPI_WRAPPER)
endif()
endif()
# MFEM_TIMER_TYPE
if (NOT DEFINED MFEM_TIMER_TYPE)
if (APPLE)
@@ -377,7 +384,7 @@ endif()
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
SLEPC MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2
CUSPARSE AMGX)
CUSPARSE MKL_CPARDISO AMGX)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
set(TPL_INCLUDE_DIRS "")
+6
View File
@@ -98,15 +98,18 @@ The MFEM source code has the following structure:
│ └── web
│ └── examples
├── examples
│ ├── amgx
│ ├── ginkgo
│ ├── hiop
│ ├── petsc
│ ├── pumi
│ └── sundials
| └── superlu
├── fem
│ └── libceed
├── general
├── linalg
│ └── simd
├── mesh
├── miniapps
│ ├── adjoint
@@ -114,11 +117,14 @@ The MFEM source code has the following structure:
│ ├── electromagnetics
│ ├── gslib
│ ├── meshing
│ ├── navier
│ ├── nurbs
│ ├── performance
│ ├── tools
│ └── toys
└── tests
├── convergence
├── par-mesh-format
├── scripts
├── unit
│ ├── ...
+35 -16
View File
@@ -344,24 +344,27 @@ MFEM_USE_SUPERLU = YES/NO
SuperLURowLocMatrix a distributed CSR matrix class needed by SuperLU. When
enabled, this option uses the SUPERLU_* library options, see below.
MFEM_USE_SUPERLU5 = YES/NO
If SuperLU functionality is enabled, use the older 5.1.0 version rather than
the more recent 6+ versions.
MFEM_USE_STRUMPACK = YES/NO
Enable MFEM functionality based on the STRUMPACK sparse direct solver and
preconditioner through the STRUMPACKSolver and STRUMPACKRowLocMatrix
classes. When enabled, this option uses the STRUMPACK_* library options, see
below.
MFEM_USE_AMGX = YES/NO
Enable MFEM functionality based on the AMGX multigrid library from
NVIDIA. When enabled, this options enables the user to use SparseMatrices
and HypreParMatrices to solve linear systems using routines from the AMGX
library.
MFEM_USE_GINKGO = YES/NO
Enable MFEM functionality based on the Ginkgo library, which provides
iterative linear solvers and preconditioners with OpenMP, CUDA backends, see
https://github.com/ginkgo-project/ginkgo. When enabled, the user can use
Ginkgo's solvers and preconditioners as shown in examples/ginkgo/.
MFEM_USE_AMGX = YES/NO
Enable MFEM functionality based on the AmgX multigrid library from NVIDIA.
Allows the user to use SparseMatrices and HypreParMatrices to solve linear
systems with the routines from the AmgX library.
MFEM_USE_GNUTLS = YES/NO
Enable secure socket support in class socketstream, using the auxiliary
GnuTLS_* classes, based on the GnuTLS library. This option may be useful in
@@ -492,6 +495,13 @@ MFEM_USE_CEED = YES/NO
library for performant high-order operator evaluation developed by the Center
for Efficient Exascale Discretizations in the Exascale Computing Project.
MFEM_USE_MKL_CPARDISO = YES/NO
Enables the interface to MKL CPardiso: the Intel MKL Parallel Direct Sparse
Solver for Clusters. Make sure to set the correct values for MKL_MPI_WRAPPER
and MKL_LIBRARY_SUBDIR as shown in defaults.mk. If you configure MFEM with
MFEM_USE_LAPACK=YES, verify that the MKL LAPACK libraries are used. The
OpenMP capabilities are disabled at link time.
MFEM_BUILD_TAG = (any value)
An optional tag to characterize the build. Exported to config/config.mk.
Can be used to identify the MFEM build from other makefiles.
@@ -541,11 +551,14 @@ The specific libraries and their options are:
Beginning with MFEM v3.3, SUNDIALS v2.7.0 is supported.
Beginning with MFEM v3.3.2, SUNDIALS v3.0.0 is also supported.
Beginning with MFEM v4.1, only SUNDIALS v5.0.0+ is supported.
When MFEM_USE_CUDA is enabled, only SUNDIALS v5.4.0+ is supported.
If MFEM_USE_MPI is enabled, we expect that SUNDIALS is built with support for
both MPI and hypre.
If MFEM_USE_CUDA is enabled, we expect that SUNDIALS is built with support
for CUDA.
URL: http://computation.llnl.gov/projects/sundials/sundials-software
Options: SUNDIALS_OPT, SUNDIALS_LIB.
Versions: SUNDIALS >= 5.0.0.
Versions: SUNDIALS >= 5.0.0, SUNDIALS >= 5.4.0 for CUDA suppport.
- Mesquite (optional), used when MFEM_USE_MESQUITE = YES.
URL: http://trilinos.org/oldsite/packages/mesquite
@@ -580,6 +593,11 @@ The specific libraries and their options are:
URL: https://ginkgo-project.github.io
Options: GINKGO_OPT (Not used), GINKGO_LIB.
- AmgX (optional), used when MFEM_USE_AMGX = YES.
URL: https://github.com/NVIDIA/AMGX
Options: AMGX_OPT, AMGX_LIB.
Versions: AmgX >= 2.1, older versions may work too.
- GnuTLS (optional), used when MFEM_USE_GNUTLS = YES. On most Linux systems,
GnuTLS is available as a development package, e.g. gnutls-devel. On Mac OS X,
one can get the library through the Homebrew package manager (http://brew.sh).
@@ -651,16 +669,16 @@ The specific libraries and their options are:
Options: GSLIB_OPT, GSLIB_LIB.
Versions: GSLIB >= 1.0.5.
- MKL CPardiso (optional), used when MFEM_USE_MKL_CPARDISO = YES.
URL: https://software.intel.com/content/www/us/en/develop/tools/math-kernel-library.html
Options: MKL_CPARDISO_OPT, MKL_CPARDISO_LIB.
Versions: Intel MKL >= 2020.
- CUDA (optional), used when MFEM_USE_CUDA = YES.
URL: https://developer.nvidia.com/cuda-toolkit
Options: CUDA_CXX, CUDA_ARCH, CUDA_OPT, CUDA_LIB.
Versions: CUDA >= 9.1, older versions may work too.
- AMGX (optional), used when MFEM_USE_AMGX = YES.
URL: https://github.com/NVIDIA/AMGX
Options: AMGX_OPT, AMGX_LIB.
Versions: AMGX >= 2.1, older versions may work too.
- HIP (optional), used when MFEM_USE_HIP = YES.
URL: https://rocm.github.io/ROCmInstall.html
Options: HIP_CXX, HIP_ARCH, HIP_OPT, HIP_LIB.
@@ -668,13 +686,13 @@ The specific libraries and their options are:
- OCCA (optional), used when MFEM_USE_OCCA = YES.
URL: https://libocca.org
Options: OCCA_DIR, OCCA_OPT, OCCA_LIB.
Versions: OCCA >= 1.0.9.
Versions: OCCA >= 1.1.0.
- libCEED (optional), used when MFEM_USE_CEED = YES.
URL: https://github.com/CEED/libCEED
https://ceed.exascaleproject.org/libceed
Options: CEED_DIR, CEED_OPT, CEED_LIB.
Versions: libCEED > 0.6, git-hash bdfed75.
Versions: libCEED >= 0.7.
- RAJA (optional), used when MFEM_USE_RAJA = YES.
Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported.
@@ -817,8 +835,8 @@ MFEM_USE_MESQUITE
MFEM_USE_SUITESPARSE
MFEM_USE_SUPERLU
MFEM_USE_STRUMPACK
MFEM_USE_AMGX
MFEM_USE_GINKGO
MFEM_USE_AMGX
MFEM_USE_GNUTLS
MFEM_USE_NETCDF
MFEM_USE_MPFR
@@ -867,11 +885,12 @@ The CMake build system adds auto-detection for the following packages/libraries:
- HYPRE
- METIS - The option MFEM_USE_METIS_5 is auto-detected.
- ParMETIS
- MESQUITE
- SuiteSparse
- SuperLUDist, STRUMPACK
- ParMETIS
- Ginkgo
- AMGX
- GNUTLS - Extends the built-in CMake support, to search GNUTLS_DIR as well.
- NETCDF
- MPFR
+2 -1
View File
@@ -25,7 +25,8 @@ This project distributes the sources of several external software products with
their own respective licenses which can be found in their code and attached
license files. These software products and their licenses are as follows:
* AmgXWrapper (linalg/amgxsolver.{hpp,cpp}) -- MIT license
* Catch++ (tests/unit/catch.hpp) -- Boost 1.0 license
* Gecko (general/gecko.{cpp,hpp}) -- BSD 3-clause license
* Picojson (fem/picojson.h) -- Custom 2-clause license
* Catch++ (tests/unit/catch.hpp) -- Boost 1.0 license
* Zstr (general/zstr.hpp) -- MIT license
+1
View File
@@ -34,6 +34,7 @@ set(MFEM_USE_SUITESPARSE @MFEM_USE_SUITESPARSE@)
set(MFEM_USE_SUPERLU @MFEM_USE_SUPERLU@)
set(MFEM_USE_STRUMPACK @MFEM_USE_STRUMPACK@)
set(MFEM_USE_GINKGO @MFEM_USE_GINKGO@)
set(MFEM_USE_AMGX @MFEM_USE_AMGX@)
set(MFEM_USE_GNUTLS @MFEM_USE_GNUTLS@)
set(MFEM_USE_GSLIB @MFEM_USE_GSLIB@)
set(MFEM_USE_NETCDF @MFEM_USE_NETCDF@)
+9 -6
View File
@@ -74,6 +74,9 @@
// [Deprecated] Enable experimental OpenMP support. Requires MFEM_THREAD_SAFE.
#cmakedefine MFEM_USE_LEGACY_OPENMP
// Internal MFEM option: enable group/batch allocation for some small objects.
#cmakedefine MFEM_USE_MEMALLOC
// Enable MFEM functionality based on the Mesquite library.
#cmakedefine MFEM_USE_MESQUITE
@@ -86,12 +89,12 @@
// Enable MFEM functionality based on the STRUMPACK library.
#cmakedefine MFEM_USE_STRUMPACK
// Internal MFEM option: enable group/batch allocation for some small objects.
#cmakedefine MFEM_USE_MEMALLOC
// Enable functionality based on the Ginkgo library
#cmakedefine MFEM_USE_GINKGO
// Enable MFEM functionality based on the AmgX library
#cmakedefine MFEM_USE_AMGX
// Enable MFEM functionality based on the GnuTLS library
#cmakedefine MFEM_USE_GNUTLS
@@ -126,9 +129,6 @@
// Requires a CUDA compiler (nvcc).
#cmakedefine MFEM_USE_CUDA
// Enable MFEM functionality based on the AMGX library
#cmakedefine MFEM_USE_AMGX
// Enable MFEM functionality based on the RAJA library
#cmakedefine MFEM_USE_RAJA
@@ -159,4 +159,7 @@
// library.
#cmakedefine MFEM_USE_SIMMETRIX
// Enable interface to the MKL CPardiso library.
#cmakedefine MFEM_USE_MKL_CPARDISO
#endif // MFEM_CONFIG_HEADER
+20
View File
@@ -0,0 +1,20 @@
# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Defines the following variables:
# - AMGX_FOUND
# - AMGX_LIBRARIES
# - AMGX_INCLUDE_DIRS
include(MfemCmakeUtilities)
set(AMGX_REQUIRED_LIBRARIES cusparse cusolver cublas nvToolsExt)
mfem_find_package(AMGX AMGX AMGX_DIR "include" "amgx_c.h" "lib" "amgx"
"Paths to headers required by AMGX." "Libraries required by AMGX.")
@@ -0,0 +1,32 @@
# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Defines the following variables:
# - MKL_CPARDISO_FOUND
# - MKL_CPARDISO_LIBRARIES
# - MKL_CPARDISO_INCLUDE_DIRS
if(NOT MKL_MPI_WRAPPER_LIB)
message(FATAL_ERROR "MKL CPardiso enabled but no MKL MPI Wrapper lib specified")
endif()
if(NOT MKL_LIBRARY_DIR)
message(WARNING "Using default MKL library path. Double check the variable MKL_LIBRARY_DIR")
set(MKL_LIBRARY_DIR "lib")
endif()
include(MfemCmakeUtilities)
mfem_find_package(MKL_CPARDISO MKL_CPARDISO
MKL_CPARDISO_DIR "include" mkl_cluster_sparse_solver.h ${MKL_LIBRARY_DIR} mkl_core
"Paths to headers required by MKL CPardiso." "Libraries required by MKL CPARDISO."
ADD_COMPONENT MKL_LP64 "include" "" ${MKL_LIBRARY_DIR} mkl_intel_lp64
ADD_COMPONENT MKL_SEQUENTIAL "include" "" ${MKL_LIBRARY_DIR} mkl_sequential
ADD_COMPONENT MKL_MPI_WRAPPER "include" "" ${MKL_LIBRARY_DIR} ${MKL_MPI_WRAPPER_LIB})
+6 -2
View File
@@ -20,10 +20,14 @@ mfem_find_package(SUNDIALS SUNDIALS SUNDIALS_DIR
"Paths to headers required by SUNDIALS." "Libraries required by SUNDIALS."
ADD_COMPONENT NVector_Serial
"include" nvector/nvector_serial.h "lib" sundials_nvecserial
ADD_COMPONENT NVector_Parallel
"include" nvector/nvector_parallel.h "lib" sundials_nvecparallel
ADD_COMPONENT NVector_Cuda
"include" nvector/nvector_cuda.h "lib" sundials_nveccuda
ADD_COMPONENT NVector_ParHyp
"include" nvector/nvector_parhyp.h "lib" sundials_nvecparhyp
ADD_COMPONENT NVector_Parallel
"include" nvector/nvector_parallel.h "lib" sundials_nvecparallel
ADD_COMPONENT NVector_MPIPlusX
"include" nvector/nvector_mpiplusx.h "lib" sundials_nvecmpiplusx
ADD_COMPONENT CVODE "include" cvode/cvode.h "lib" sundials_cvode
ADD_COMPONENT CVODES "include" cvodes/cvodes.h "lib" sundials_cvodes
ADD_COMPONENT ARKODE "include" arkode/arkode.h "lib" sundials_arkode
@@ -738,10 +738,11 @@ function(mfem_export_mk_files)
MFEM_DEBUG MFEM_USE_EXCEPTIONS MFEM_USE_ZLIB MFEM_USE_LIBUNWIND
MFEM_USE_LAPACK MFEM_THREAD_SAFE MFEM_USE_OPENMP MFEM_USE_LEGACY_OPENMP
MFEM_USE_MEMALLOC MFEM_USE_SUNDIALS MFEM_USE_MESQUITE MFEM_USE_SUITESPARSE
MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS
MFEM_USE_GSLIB MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_CUDA MFEM_USE_OCCA MFEM_USE_RAJA
MFEM_USE_UMPIRE MFEM_USE_SIMD MFEM_USE_ADIOS2)
MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GINKGO MFEM_USE_AMGX
MFEM_USE_GNUTLS MFEM_USE_GSLIB MFEM_USE_NETCDF MFEM_USE_PETSC
MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_CONDUIT MFEM_USE_PUMI
MFEM_USE_CUDA MFEM_USE_OCCA MFEM_USE_RAJA MFEM_USE_UMPIRE MFEM_USE_SIMD
MFEM_USE_ADIOS2)
foreach(var ${CONFIG_MK_BOOL_VARS})
if (${var})
set(${var} YES)
+3
View File
@@ -45,6 +45,9 @@
#ifdef MFEM_USE_STRUMPACK
#error Building with STRUMPACK (MFEM_USE_STRUMPACK=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
#ifdef MFEM_USE_MKL_CPARDISO
#error Building with MKL CPARDISO (MFEM_USE_MKL_CPARDISO=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
#ifdef MFEM_USE_PETSC
#error Building with PETSc (MFEM_USE_PETSC=YES) requires MPI (MFEM_USE_MPI=YES)
#endif
+7 -3
View File
@@ -93,6 +93,7 @@
// Enable MFEM functionality based on the SuperLU library.
// #define MFEM_USE_SUPERLU
// #define MFEM_USE_SUPERLU5
// Enable MFEM functionality based on the STRUMPACK library.
// #define MFEM_USE_STRUMPACK
@@ -100,6 +101,9 @@
// Enable MFEM features based on the Ginkgo library
// #define MFEM_USE_GINKGO
// Enable MFEM functionality based on the AmgX library.
// #define MFEM_USE_AMGX
// Enable secure socket streams based on the GNUTLS library
// #define MFEM_USE_GNUTLS
@@ -137,9 +141,6 @@
// Requires a CUDA compiler (nvcc).
// #define MFEM_USE_CUDA
// Enable MFEM functionality based on the AMGX library.
// #define MFEM_USE_AMGX
// Build the AMD GPU/HIP-enabled version of the MFEM library.
// Requires a HIP compiler (hipcc).
// #define MFEM_USE_HIP
@@ -166,4 +167,7 @@
// library.
// #define MFEM_USE_SIMMETRIX
// Enable interface to the MKL CPardiso library.
// #define MFEM_USE_MKL_CPARDISO
#endif // MFEM_CONFIG_HEADER
+3 -1
View File
@@ -32,8 +32,10 @@ MFEM_USE_SUNDIALS = @MFEM_USE_SUNDIALS@
MFEM_USE_MESQUITE = @MFEM_USE_MESQUITE@
MFEM_USE_SUITESPARSE = @MFEM_USE_SUITESPARSE@
MFEM_USE_SUPERLU = @MFEM_USE_SUPERLU@
MFEM_USE_SUPERLU5 = @MFEM_USE_SUPERLU5@
MFEM_USE_STRUMPACK = @MFEM_USE_STRUMPACK@
MFEM_USE_GINKGO = @MFEM_USE_GINKGO@
MFEM_USE_AMGX = @MFEM_USE_AMGX@
MFEM_USE_GNUTLS = @MFEM_USE_GNUTLS@
MFEM_USE_NETCDF = @MFEM_USE_NETCDF@
MFEM_USE_PETSC = @MFEM_USE_PETSC@
@@ -45,7 +47,6 @@ MFEM_USE_PUMI = @MFEM_USE_PUMI@
MFEM_USE_HIOP = @MFEM_USE_HIOP@
MFEM_USE_GSLIB = @MFEM_USE_GSLIB@
MFEM_USE_CUDA = @MFEM_USE_CUDA@
MFEM_USE_AMGX = @MFEM_USE_AMGX@
MFEM_USE_HIP = @MFEM_USE_HIP@
MFEM_USE_RAJA = @MFEM_USE_RAJA@
MFEM_USE_OCCA = @MFEM_USE_OCCA@
@@ -53,6 +54,7 @@ MFEM_USE_CEED = @MFEM_USE_CEED@
MFEM_USE_UMPIRE = @MFEM_USE_UMPIRE@
MFEM_USE_SIMD = @MFEM_USE_SIMD@
MFEM_USE_ADIOS2 = @MFEM_USE_ADIOS2@
MFEM_USE_MKL_CPARDISO = @MFEM_USE_MKL_CPARDISO@
# Compiler, compile options, and link options
MFEM_CXX = @MFEM_CXX@
+11 -3
View File
@@ -33,8 +33,10 @@ option(MFEM_USE_SUNDIALS "Enable SUNDIALS usage" OFF)
option(MFEM_USE_MESQUITE "Enable MESQUITE usage" OFF)
option(MFEM_USE_SUITESPARSE "Enable SuiteSparse usage" OFF)
option(MFEM_USE_SUPERLU "Enable SuperLU_DIST usage" OFF)
option(MFEM_USE_SUPERLU5 "Use the old SuperLU_DIST 5.1 version" OFF)
option(MFEM_USE_STRUMPACK "Enable STRUMPACK usage" OFF)
option(MFEM_USE_GINKGO "Enable Ginkgo usage" OFF)
option(MFEM_USE_AMGX "Enable AmgX usage" OFF)
option(MFEM_USE_GNUTLS "Enable GNUTLS usage" OFF)
option(MFEM_USE_GSLIB "Enable GSLIB usage" OFF)
option(MFEM_USE_NETCDF "Enable NETCDF usage" OFF)
@@ -52,6 +54,7 @@ option(MFEM_USE_CEED "Enable CEED" OFF)
option(MFEM_USE_UMPIRE "Enable Umpire" OFF)
option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" OFF)
option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
option(MFEM_USE_MKL_CPARDISO "Enable MKL CPardiso" OFF)
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
@@ -88,7 +91,7 @@ set(METIS_DIR "${MFEM_DIR}/../metis-4.0" CACHE PATH "Path to the METIS library."
set(LIBUNWIND_DIR "" CACHE PATH "Path to Libunwind.")
# For sundials_nvecparhyp and nvecparallel remember to build with MPI_ENABLED=ON
# For sundials_nvecmpiplusx and nvecparallel remember to build with MPI_ENABLE=ON
# and modify cmake variables for hypre for sundials
set(SUNDIALS_DIR "${MFEM_DIR}/../sundials-5.0.0/instdir" CACHE PATH
"Path to the SUNDIALS library.")
@@ -109,7 +112,7 @@ set(ParMETIS_DIR "${MFEM_DIR}/../parmetis-4.0.3" CACHE PATH
set(ParMETIS_REQUIRED_PACKAGES "METIS" CACHE STRING
"Additional packages required by ParMETIS.")
set(SuperLUDist_DIR "${MFEM_DIR}/../SuperLU_DIST_5.1.0" CACHE PATH
set(SuperLUDist_DIR "${MFEM_DIR}/../SuperLU_DIST_6.3.1" CACHE PATH
"Path to the SuperLU_DIST library.")
# SuperLU_DIST may also depend on "OpenMP", depending on how it was compiled.
set(SuperLUDist_REQUIRED_PACKAGES "MPI" "BLAS" "ParMETIS" CACHE STRING
@@ -145,6 +148,8 @@ set(ScaLAPACK_TARGET_NAMES scalapack)
set(Ginkgo_DIR "${MFEM_DIR}/../ginkgo" CACHE PATH "Path to the Ginkgo library.")
set(AMGX_DIR "${MFEM_DIR}/../amgx" CACHE PATH "Path to AmgX")
set(GNUTLS_DIR "" CACHE PATH "Path to the GnuTLS library.")
set(GSLIB_DIR "" CACHE PATH "Path to the GSLIB library.")
@@ -180,9 +185,12 @@ set(HIOP_DIR "${MFEM_DIR}/../hiop/install" CACHE STRING
set(HIOP_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
"Packages that HiOp depends on.")
set(MKL_CPARDISO_DIR "" CACHE STRING "MKL installation path.")
set(MKL_MPI_WRAPPER_LIB "mkl_blacs_mpich_lp64" CACHE STRING "MKL MPI wrapper library")
set(MKL_LIBRARY_DIR "" CACHE STRING "Custom library subdirectory")
set(OCCA_DIR "${MFEM_DIR}/../occa" CACHE PATH "Path to OCCA")
set(RAJA_DIR "${MFEM_DIR}/../raja" CACHE PATH "Path to RAJA")
set(AMGX_DIR "${MFEM_DIR}/../amgx" CACHE PATH "Path to AMGX")
set(CEED_DIR "${MFEM_DIR}/../libCEED" CACHE PATH "Path to libCEED")
set(UMPIRE_DIR "${MFEM_DIR}/../umpire" CACHE PATH "Path to Umpire")
+36 -14
View File
@@ -120,8 +120,10 @@ MFEM_USE_SUNDIALS = NO
MFEM_USE_MESQUITE = NO
MFEM_USE_SUITESPARSE = NO
MFEM_USE_SUPERLU = NO
MFEM_USE_SUPERLU5 = NO
MFEM_USE_STRUMPACK = NO
MFEM_USE_GINKGO = NO
MFEM_USE_AMGX = NO
MFEM_USE_GNUTLS = NO
MFEM_USE_NETCDF = NO
MFEM_USE_PETSC = NO
@@ -133,7 +135,6 @@ MFEM_USE_PUMI = NO
MFEM_USE_HIOP = NO
MFEM_USE_GSLIB = NO
MFEM_USE_CUDA = NO
MFEM_USE_AMGX = NO
MFEM_USE_HIP = NO
MFEM_USE_RAJA = NO
MFEM_USE_OCCA = NO
@@ -141,6 +142,7 @@ MFEM_USE_CEED = NO
MFEM_USE_UMPIRE = NO
MFEM_USE_SIMD = NO
MFEM_USE_ADIOS2 = NO
MFEM_USE_MKL_CPARDISO = NO
# Compile and link options for zlib.
ZLIB_DIR =
@@ -190,15 +192,19 @@ OPENMP_LIB =
POSIX_CLOCKS_LIB = -lrt
# SUNDIALS library configuration
# For sundials_nvecparhyp and nvecparallel remember to build with MPI_ENABLED=ON
# For sundials_nvecmpiplusx and nvecparallel remember to build with MPI_ENABLE=ON
# and modify cmake variables for hypre for sundials
SUNDIALS_DIR = @MFEM_DIR@/../sundials-5.0.0/instdir
SUNDIALS_OPT = -I$(SUNDIALS_DIR)/include
SUNDIALS_LIB = -Wl,-rpath,$(SUNDIALS_DIR)/lib64 -L$(SUNDIALS_DIR)/lib64\
SUNDIALS_DIR = @MFEM_DIR@/../sundials-5.0.0/instdir
SUNDIALS_OPT = -I$(SUNDIALS_DIR)/include
SUNDIALS_LIBDIR = $(wildcard $(SUNDIALS_DIR)/lib*)
SUNDIALS_LIB = $(XLINKER)-rpath,$(SUNDIALS_LIBDIR) -L$(SUNDIALS_LIBDIR)\
-lsundials_arkode -lsundials_cvodes -lsundials_nvecserial -lsundials_kinsol
ifeq ($(MFEM_USE_MPI),YES)
SUNDIALS_LIB += -lsundials_nvecparhyp -lsundials_nvecparallel
SUNDIALS_LIB += -lsundials_nvecparallel -lsundials_nvecmpiplusx
endif
ifeq ($(MFEM_USE_CUDA),YES)
SUNDIALS_LIB += -lsundials_nveccuda
endif
# If SUNDIALS was built with KLU:
# MFEM_USE_SUITESPARSE = YES
@@ -217,9 +223,15 @@ SUITESPARSE_LIB = -Wl,-rpath,$(SUITESPARSE_DIR)/lib -L$(SUITESPARSE_DIR)/lib\
-lsuitesparseconfig $(LIB_RT) $(METIS_LIB) $(LAPACK_LIB)
# SuperLU library configuration
SUPERLU_DIR = @MFEM_DIR@/../SuperLU_DIST_5.1.0
SUPERLU_OPT = -I$(SUPERLU_DIR)/SRC
SUPERLU_LIB = -Wl,-rpath,$(SUPERLU_DIR)/lib -L$(SUPERLU_DIR)/lib -lsuperlu_dist_5.1.0
ifeq ($(MFEM_USE_SUPERLU5),YES)
SUPERLU_DIR = @MFEM_DIR@/../SuperLU_DIST_5.1.0
SUPERLU_OPT = -I$(SUPERLU_DIR)/include
SUPERLU_LIB = -Wl,-rpath,$(SUPERLU_DIR)/lib -L$(SUPERLU_DIR)/lib -lsuperlu_dist_5.1.0
else
SUPERLU_DIR = @MFEM_DIR@/../SuperLU_DIST_6.3.1
SUPERLU_OPT = -I$(SUPERLU_DIR)/include
SUPERLU_LIB = -Wl,-rpath,$(SUPERLU_DIR)/lib64 -L$(SUPERLU_DIR)/lib64 -lsuperlu_dist -lblas
endif
# SCOTCH library configuration (required by STRUMPACK <= v2.1.0, optional in
# STRUMPACK >= v2.2.0)
@@ -252,7 +264,13 @@ STRUMPACK_LIB = -L$(STRUMPACK_DIR)/lib -lstrumpack $(MPI_FORTRAN_LIB)\
# Ginkgo library configuration (currently not needed)
GINKGO_DIR = @MFEM_DIR@/../ginkgo/install
GINKGO_OPT = -isystem $(GINKGO_DIR)/include
GINKGO_LIB = $(XLINKER)-rpath,$(GINKGO_DIR)/lib -L$(GINKGO_DIR)/lib -lginkgo -lginkgo_omp -lginkgo_cuda -lginkgo_reference
GINKGO_LIB = $(XLINKER)-rpath,$(GINKGO_DIR)/lib -L$(GINKGO_DIR)/lib -lginkgo\
-lginkgo_omp -lginkgo_cuda -lginkgo_reference
# AmgX library configuration
AMGX_DIR = @MFEM_DIR@/../amgx
AMGX_OPT = -I$(AMGX_DIR)/include
AMGX_LIB = -lcusparse -lcusolver -lcublas -lnvToolsExt -L$(AMGX_DIR)/lib -lamgx
# GnuTLS library configuration
GNUTLS_OPT =
@@ -373,10 +391,14 @@ UMPIRE_DIR = @MFEM_DIR@/../umpire
UMPIRE_OPT = -I$(UMPIRE_DIR)/include
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -lumpire
# AMGX library configuration
AMGX_DIR = @MFEM_DIR@/../amgx
AMGX_OPT = -I$(AMGX_DIR)/include
AMGX_LIB = -L$(CUDA_HOME)/lib64 -lcusparse -lcusolver -lcublas -lnvToolsExt -L$(AMGX_DIR)/lib -lamgx -Xlinker=-rpath=$(CUDA_HOME)/lib64
# MKL CPardiso library configuration
MKL_CPARDISO_DIR ?=
MKL_MPI_WRAPPER ?= mkl_blacs_mpich_lp64
MKL_LIBRARY_SUBDIR ?= lib
MKL_CPARDISO_OPT = -I$(MKL_CPARDISO_DIR)/include
MKL_CPARDISO_LIB = -Wl,-rpath,$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR)\
-L$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR) -l$(MKL_MPI_WRAPPER)\
-lmkl_intel_lp64 -lmkl_sequential -lmkl_core
# If YES, enable some informational messages
VERBOSE = NO
+5 -1
View File
@@ -127,6 +127,11 @@ if (MFEM_USE_GINKGO)
add_subdirectory(ginkgo)
endif()
# Include the examples/amgx directory if AmgX is enabled
if (MFEM_USE_AMGX)
add_subdirectory(amgx)
endif()
# Include the examples/petsc directory if PETSc is enabled.
if (MFEM_USE_PETSC)
add_subdirectory(petsc)
@@ -140,4 +145,3 @@ endif()
if (MFEM_USE_HIOP)
add_subdirectory(hiop)
endif()
+79
View File
@@ -0,0 +1,79 @@
# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
set(AMGX_EXAMPLES_SRCS)
list(APPEND AMGX_EXAMPLES_SRCS
ex1.cpp
)
if (MFEM_USE_MPI)
list(APPEND AMGX_EXAMPLES_SRCS
ex1p.cpp
)
endif()
set(AMGX_JSON_FILES amg_pcg.json multi_gs.json precon.json)
# Include the source directory where mfem.hpp and mfem-performance.hpp are.
include_directories(BEFORE ${PROJECT_BINARY_DIR})
# Add targets to copy *.json files from the source directory
foreach(JSON_FILE ${AMGX_JSON_FILES})
add_custom_command(OUTPUT ${JSON_FILE}
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/${JSON_FILE} ${JSON_FILE}
COMMENT "copy ${JSON_FILE}")
endforeach()
add_custom_target(copy_amgx_json_files DEPENDS ${AMGX_JSON_FILES}
COMMENT "Copying AMGX example json files ...")
# Add "test_amgx" target, see below.
add_custom_target(test_amgx
${CMAKE_CTEST_COMMAND} -R amgx USES_TERMINAL)
# Add one executable per cpp file, adding "amgx_" as prefix. Sets
# "copy_amgx_json_files" as a prerequisite for the given examples. Also, sets
# "test_amgx" as a target that depends on the given examples.
set(PFX amgx_)
add_mfem_examples(AMGX_EXAMPLES_SRCS ${PFX} copy_amgx_json_files test_amgx)
# Testing.
# The AMGX tests can be run separately using the target "test_amgx"
# which builds the examples and runs:
# ctest -R amgx
# Command line options for the tests.
# Example 1/1p:
set(EX1_TEST_OPTS)
set(EX1P_TEST_OPTS)
# Add the tests: one test per source file.
foreach(SRC_FILE ${AMGX_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
+18
View File
@@ -0,0 +1,18 @@
Finite Element Discretization Library
__
_ __ ___ / _| ___ _ __ ___
| '_ ` _ \ | |_ / _ \| '_ ` _ \
| | | | | || _|| __/| | | | | |
|_| |_| |_||_| \___||_| |_| |_|
https://mfem.org
This directory contains modifications of the example codes that illustrate the
use of MFEM features based on NVIDIA's multigrid library AmgX.
To build these examples, make sure that MFEM is configured with the option
"MFEM_USE_AMGX = YES", see the top-level INSTALL file for details (version
2.1 of AmgX is recommended, though older versions may work too.
We recommend comparing the original example codes with the corresponding files
in the current directory.
+1 -1
View File
@@ -17,7 +17,7 @@
"interpolator": "D2",
"max_row_sum" : 0.9,
"strength_threshold" : 0.25,
"max_iters": 1,
"max_iters": 2,
"monitor_residual": 0,
"store_res_history": 0,
"scope": "amg",
+45 -61
View File
@@ -1,50 +1,15 @@
// MFEM Example 1
// AmgX Modification
//
// Compile with: make ex1
//
// Sample runs: ex1 -m ../../data/square-disc.mesh
// ex1 -m ../../data/star.mesh
// ex1 -m ../../data/star-mixed.mesh
// ex1 -m ../../data/escher.mesh
// ex1 -m ../../data/fichera.mesh
// ex1 -m ../../data/fichera-mixed.mesh
// ex1 -m ../../data/toroid-wedge.mesh
// ex1 -m ../../data/periodic-annulus-sector.msh
// ex1 -m ../../data/periodic-torus-sector.msh
// ex1 -m ../../data/square-disc-p2.vtk -o 2
// ex1 -m ../../data/square-disc-p3.mesh -o 3
// ex1 -m ../../data/square-disc-nurbs.mesh -o -1
// ex1 -m ../../data/star-mixed-p2.mesh -o 2
// ex1 -m ../../data/disc-nurbs.mesh -o -1
// ex1 -m ../../data/pipe-nurbs.mesh -o -1
// ex1 -m ../../data/fichera-mixed-p2.mesh -o 2
// ex1 -m ../../data/star-surf.mesh
// ex1 -m ../../data/square-disc-surf.mesh
// ex1 -m ../../data/inline-segment.mesh
// ex1 -m ../../data/amr-quad.mesh
// ex1 -m ../../data/amr-hex.mesh
// ex1 -m ../../data/fichera-amr.mesh
// ex1 -m ../../data/mobius-strip.mesh
// ex1 -m ../../data/mobius-strip.mesh -o -1 -sc
//
// Device sample runs:
// ex1 -pa -d cuda
// ex1 -pa -d raja-cuda
// ex1 -pa -d occa-cuda
// ex1 -pa -d raja-omp
// ex1 -pa -d occa-omp
// ex1 -pa -d ceed-cpu
// * ex1 -pa -d ceed-cuda
// ex1 -pa -d ceed-cuda:/gpu/cuda/shared
// ex1 -m ../../data/beam-hex.mesh -pa -d cuda
// ex1 -m ../../data/beam-tet.mesh -pa -d ceed-cpu
// ex1 -m ../../data/beam-tet.mesh -pa -d ceed-cuda:/gpu/cuda/ref
//
// AmgX sample runs:
// ./ex1 --amgx-file multi_gs.json --amgx-solver
// ./ex1 --amgx-file precon.json --amgx-preconditioner
// ./ex1 --amgx-file multi_gs.json --amgx-solver -d cuda
// ./ex1 --amgx-file precon.json --amgx-preconditioner -d cuda
// ex1
// ex1 -d cuda
// ex1 --amgx-file multi_gs.json --amgx-solver
// ex1 --amgx-file precon.json --amgx-preconditioner
// ex1 --amgx-file multi_gs.json --amgx-solver -d cuda
// ex1 --amgx-file precon.json --amgx-preconditioner -d cuda
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
@@ -77,8 +42,9 @@ int main(int argc, char *argv[])
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
bool amgx_lib = true;
bool amgx_solver = true;
const char* amgx_json_file = ""; // jason file for amgx
const char* amgx_json_file = ""; // JSON file for AmgX
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -90,11 +56,12 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&amgx_lib, "-amgx", "--amgx-lib", "-no-amgx",
"--no-amgx-lib", "Use AmgX in example.");
args.AddOption(&amgx_json_file, "--amgx-file", "--amgx-file",
"AMGX solver config file (overrides --amgx-solver, --amgx-verbose)");
args.AddOption(&amgx_solver, "--amgx-solver", "--amgx-solver",
"--amgx-preconditioner",
"--amgx-preconditioner",
"--amgx-preconditioner", "--amgx-preconditioner",
"Configure AMGX as solver or preconditioner.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
@@ -109,9 +76,6 @@ int main(int argc, char *argv[])
}
args.PrintOptions(cout);
MFEM_VERIFY(!pa && strcmp(amgx_json_file,"") != 0,
"An AmgX json file is needed for this example \n");
// 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);
@@ -208,10 +172,29 @@ int main(int argc, char *argv[])
cout << "Size of linear system: " << A->Height() << endl;
// 11. Solve the linear system A X = B.
if (!pa)
if (pa)
{
// Jacobi preconditioning in partial assembly mode
if (UsesTensorBasis(fespace))
{
OperatorJacobiSmoother M(a, ess_tdof_list);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
else
{
CG(*A, B, X, 1, 400, 1e-12, 0.0);
}
}
else if (amgx_lib && strcmp(amgx_json_file,"") == 0)
{
bool amgx_verbose = false;
AmgXSolver amgx(AmgXSolver::PRECONDITIONER, amgx_verbose);
amgx.SetOperator(*A.As<SparseMatrix>());
PCG(*A, amgx, B, X, 1, 200, 1e-12, 0.0);
}
else if (amgx_lib && strcmp(amgx_json_file,"") != 0)
{
AmgXSolver amgx;
amgx.ReadParameters(amgx_json_file, AmgXSolver::EXTERNAL);
amgx.InitSerial();
amgx.SetOperator(*A.As<SparseMatrix>());
@@ -224,19 +207,20 @@ int main(int argc, char *argv[])
{
PCG(*A.As<SparseMatrix>(), amgx, B, X, 3, 40, 1e-12, 0.0);
}
}
else // Jacobi preconditioning in partial assembly mode
else
{
if (UsesTensorBasis(fespace))
{
OperatorJacobiSmoother M(a, ess_tdof_list);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
else
{
CG(*A, B, X, 1, 400, 1e-12, 0.0);
}
#ifndef MFEM_USE_SUITESPARSE
// 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
// 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
}
// 12. Recover the solution as a finite element grid function.
+68 -69
View File
@@ -1,45 +1,13 @@
// MFEM Example 1 - Parallel Version
// AmgX Modification
//
// Compile with: make ex1p
//
// Sample runs: mpirun -np 4 ex1p -m ../../data/square-disc.mesh
// mpirun -np 4 ex1p -m ../../data/star.mesh
// mpirun -np 4 ex1p -m ../../data/star-mixed.mesh
// mpirun -np 4 ex1p -m ../../data/escher.mesh
// mpirun -np 4 ex1p -m ../../data/fichera.mesh
// mpirun -np 4 ex1p -m ../../data/fichera-mixed.mesh
// mpirun -np 4 ex1p -m ../../data/toroid-wedge.mesh
// mpirun -np 4 ex1p -m ../../data/periodic-annulus-sector.msh
// mpirun -np 4 ex1p -m ../../data/periodic-torus-sector.msh
// mpirun -np 4 ex1p -m ../../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex1p -m ../../data/square-disc-p3.mesh -o 3
// mpirun -np 4 ex1p -m ../../data/square-disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../../data/star-mixed-p2.mesh -o 2
// mpirun -np 4 ex1p -m ../../data/disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../../data/pipe-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../../data/ball-nurbs.mesh -o 2
// mpirun -np 4 ex1p -m ../../data/fichera-mixed-p2.mesh -o 2
// mpirun -np 4 ex1p -m ../../data/star-surf.mesh
// mpirun -np 4 ex1p -m ../../data/square-disc-surf.mesh
// mpirun -np 4 ex1p -m ../../data/inline-segment.mesh
// mpirun -np 4 ex1p -m ../../data/amr-quad.mesh
// mpirun -np 4 ex1p -m ../../data/amr-hex.mesh
// mpirun -np 4 ex1p -m ../../data/mobius-strip.mesh
// mpirun -np 4 ex1p -m ../../data/mobius-strip.mesh -o -1 -sc
//
// Device sample runs:
// mpirun -np 4 ex1p -pa -d cuda
// mpirun -np 4 ex1p -pa -d occa-cuda
// mpirun -np 4 ex1p -pa -d raja-omp
// mpirun -np 4 ex1p -pa -d ceed-cpu
// * mpirun -np 4 ex1p -pa -d ceed-cuda
// mpirun -np 4 ex1p -pa -d ceed-cuda:/gpu/cuda/shared
// mpirun -np 4 ex1p -m ../../data/beam-tet.mesh -pa -d ceed-cpu
//
// AmgX sample runs:
//
// mpirun -n 40 ./ex1p --amgx-file amg_pcg.json
// lrun -n 4 ./ex1p --amgx-file amg_pcg.json --amgx-mpi-gpu-exclusive
// mpirun -np 4 ex1p
// mpirun -np 4 ex1p -d cuda
// mpirun -np 10 ex1p --amgx-file amg_pcg.json --amgx-mpi-teams
// mpirun -np 4 ex1p --amgx-file amg_pcg.json
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
@@ -78,8 +46,9 @@ int main(int argc, char *argv[])
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
bool amgx_mpi_teams = true;
const char* amgx_json_file = ""; // jason file for amgx
bool amgx_lib = true;
bool amgx_mpi_teams = false;
const char* amgx_json_file = ""; // JSON file for AmgX
int ndevices = 1;
OptionsParser args(argc, argv);
@@ -92,17 +61,20 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&amgx_lib, "-amgx", "--amgx-lib", "-no-amgx",
"--no-amgx-lib", "Use AmgX in example.");
args.AddOption(&amgx_json_file, "--amgx-file", "--amgx-file",
"AMGX solver config file (overrides --amgx-solver, --amgx-verbose)");
args.AddOption(&amgx_mpi_teams, "--amgx-mpi-teams", "--amgx-mpi-teams",
"--amgx-mpi-gpu-exclusive", "--amgx-mpi-gpu-exclusive",
"Create MPI teams when using AMGX.");
"Create MPI teams when using AmgX to load balance between ranks and GPUs.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&ndevices, "-nd","--nd","Number of GPU devices.");
args.AddOption(&ndevices, "-nd","--gpus-per-node-in-teams-mode",
"Number of GPU devices per node (Only used if amgx_mpi_teams is true).");
args.Parse();
if (!args.Good())
@@ -117,9 +89,6 @@ int main(int argc, char *argv[])
if (myid == 0)
{
args.PrintOptions(cout);
MFEM_VERIFY(!pa == true && strcmp(amgx_json_file,"") != 0,
"An AmgX json file is needed for this example \n");
}
// 3. Enable hardware devices such as GPUs, and programming models such as
@@ -236,34 +205,11 @@ int main(int argc, char *argv[])
// 13. Solve the linear system A X = B.
// * With full assembly, use the BoomerAMG preconditioner from hypre.
// * If AmgX is available solve using amg preconditioner.
// * With partial assembly, use Jacobi smoothing, for now.
Solver *prec = NULL;
if (!pa)
if (pa)
{
AmgXSolver amgx;
amgx.ReadParameters(amgx_json_file, AmgXSolver::EXTERNAL);
if (amgx_mpi_teams)
{
//Forms MPI teams to load balance between mpi ranks and gpus
amgx.InitMPITeams(MPI_COMM_WORLD, ndevices);
}
else
{
//Assumes MPI == number of devices
amgx.InitExclusiveGPU(MPI_COMM_WORLD);
}
amgx.SetOperator(*A.As<HypreParMatrix>());
amgx.Mult(B, X);
}
else
{
if (UsesTensorBasis(fespace))
{
prec = new OperatorJacobiSmoother(a, ess_tdof_list);
@@ -277,7 +223,60 @@ int main(int argc, char *argv[])
cg.SetOperator(*A);
cg.Mult(B, X);
delete prec;
}
else if (amgx_lib && strcmp(amgx_json_file,"") == 0)
{
MFEM_VERIFY(!amgx_mpi_teams,
"Please add JSON file to try AmgX with MPI teams mode");
bool amgx_verbose = false;
prec = new AmgXSolver(MPI_COMM_WORLD, AmgXSolver::PRECONDITIONER,
amgx_verbose);
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
if (prec) { cg.SetPreconditioner(*prec); }
cg.SetOperator(*A);
cg.Mult(B, X);
delete prec;
}
else if (amgx_lib && strcmp(amgx_json_file,"") != 0)
{
AmgXSolver amgx;
amgx.ReadParameters(amgx_json_file, AmgXSolver::EXTERNAL);
if (amgx_mpi_teams)
{
// Forms MPI teams to load balance between MPI ranks and GPUs
amgx.InitMPITeams(MPI_COMM_WORLD, ndevices);
}
else
{
// Assumes each MPI rank is paired with a GPU
amgx.InitExclusiveGPU(MPI_COMM_WORLD);
}
amgx.SetOperator(*A.As<HypreParMatrix>());
amgx.Mult(B, X);
// Release MPI communicators and resources created by AmgX
amgx.Finalize();
}
else
{
prec = new HypreBoomerAMG;
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
if (prec) { cg.SetPreconditioner(*prec); }
cg.SetOperator(*A);
cg.Mult(B, X);
delete prec;
}
// 14. Recover the parallel grid function corresponding to X. This is the
+3
View File
@@ -70,3 +70,6 @@ clean: clean-build
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -f .logamgx refined.mesh sol.gf mesh.* sol.*
+14 -28
View File
@@ -35,6 +35,7 @@
// ex1 -pa -d occa-omp
// ex1 -pa -d ceed-cpu
// * ex1 -pa -d ceed-cuda
// * ex1 -pa -d ceed-hip
// ex1 -pa -d ceed-cuda:/gpu/cuda/shared
// ex1 -m ../data/beam-hex.mesh -pa -d cuda
// ex1 -m ../data/beam-tet.mesh -pa -d ceed-cpu
@@ -71,7 +72,6 @@ int main(int argc, char *argv[])
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
bool amgx = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -83,8 +83,6 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&amgx, "-amgx", "--amgx-precon", "-no-amgx",
"--no-amgx-precon", "Use AmgX V-cycle as preconditioner for CG.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
@@ -194,31 +192,7 @@ int main(int argc, char *argv[])
cout << "Size of linear system: " << A->Height() << endl;
// 11. Solve the linear system A X = B.
if (pa)
{
// Jacobi preconditioning in partial assembly mode
if (UsesTensorBasis(fespace))
{
OperatorJacobiSmoother M(a, ess_tdof_list);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
else
{
CG(*A, B, X, 1, 400, 1e-12, 0.0);
}
}
else if (amgx)
{
#if defined(MFEM_USE_AMGX)
bool amgx_verbose = false;
AmgXSolver amgx(AmgXSolver::PRECONDITIONER, amgx_verbose);
amgx.SetOperator(*A.As<SparseMatrix>());
PCG(*A, amgx, B, X, 1, 200, 1e-12, 0.0);
#else
mfem_error("MFEM not configured with AMGX \n");
#endif
}
else
if (!pa)
{
#ifndef MFEM_USE_SUITESPARSE
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
@@ -232,6 +206,18 @@ int main(int argc, char *argv[])
umf_solver.Mult(B, X);
#endif
}
else // Jacobi preconditioning in partial assembly mode
{
if (UsesTensorBasis(fespace))
{
OperatorJacobiSmoother M(a, ess_tdof_list);
PCG(*A, M, B, X, 1, 400, 1e-12, 0.0);
}
else
{
CG(*A, B, X, 1, 400, 1e-12, 0.0);
}
}
// 12. Recover the solution as a finite element grid function.
a.RecoverFEMSolution(X, b, x);
+16 -2
View File
@@ -72,6 +72,7 @@ int main(int argc, char *argv[])
int seed = 75;
bool slu_solver = false;
bool sp_solver = false;
bool cpardiso_solver = false;
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -95,6 +96,10 @@ int main(int argc, char *argv[])
#ifdef MFEM_USE_STRUMPACK
args.AddOption(&sp_solver, "-sp", "--strumpack", "-no-sp",
"--no-strumpack", "Use the STRUMPACK Solver.");
#endif
#ifdef MFEM_USE_MKL_CPARDISO
args.AddOption(&cpardiso_solver, "-cpardiso", "--cpardiso", "-no-cpardiso",
"--no-cpardiso", "Use the MKL CPardiso Solver.");
#endif
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
@@ -236,7 +241,7 @@ int main(int argc, char *argv[])
// preconditioner for A to be used within the solver. Set the matrices
// which define the generalized eigenproblem A x = lambda M x.
Solver * precond = NULL;
if (!slu_solver && !sp_solver)
if (!slu_solver && !sp_solver && !cpardiso_solver)
{
HypreBoomerAMG * amg = new HypreBoomerAMG(*A);
amg->SetPrintLevel(0);
@@ -268,10 +273,19 @@ int main(int argc, char *argv[])
strumpack->SetFromCommandLine();
precond = strumpack;
}
#endif
#ifdef MFEM_USE_MKL_CPARDISO
if (cpardiso_solver)
{
auto cpardiso = new CPardisoSolver(A->GetComm());
cpardiso->SetMatrixType(CPardisoSolver::MatType::REAL_STRUCTURE_SYMMETRIC);
cpardiso->SetPrintLevel(1);
cpardiso->SetOperator(*A);
precond = cpardiso;
}
#endif
}
HypreLOBPCG * lobpcg = new HypreLOBPCG(MPI_COMM_WORLD);
lobpcg->SetNumModes(nev);
lobpcg->SetRandomSeed(seed);
+37 -27
View File
@@ -8,6 +8,7 @@
// ex19 -m ../data/beam-hex.mesh
// ex19 -m ../data/beam-tet.mesh
// ex19 -m ../data/beam-wedge.mesh
// ex19 -m ../data/beam-quad-amr.mesh
//
// Description: This examples solves a quasi-static incompressible nonlinear
// elasticity problem of the form 0 = H(x), where H is an
@@ -96,7 +97,7 @@ protected:
Array<FiniteElementSpace *> spaces;
// Offsets for extracting block vector segments
Array<int> &block_offsets;
Array<int> &block_trueOffsets;
// Jacobian for block access
BlockOperator *jacobian;
@@ -152,7 +153,7 @@ protected:
Coefficient &mu;
// Block offsets for variable access
Array<int> &block_offsets;
Array<int> &block_trueOffsets;
public:
RubberOperator(Array<FiniteElementSpace *> &fes, Array<Array<int> *>&ess_bdr,
@@ -246,8 +247,8 @@ int main(int argc, char *argv[])
spaces[0] = &R_space;
spaces[1] = &W_space;
int R_size = R_space.GetVSize();
int W_size = W_space.GetVSize();
int R_size = R_space.GetTrueVSize();
int W_size = W_space.GetTrueVSize();
// 6. Define the Dirichlet conditions (set to boundary attribute 1 and 2)
Array<Array<int> *> ess_bdr(2);
@@ -271,13 +272,13 @@ int main(int argc, char *argv[])
std::cout << "***********************************************************\n";
// 8. Define the block structure of the solution vector (u then p)
Array<int> block_offsets(3);
block_offsets[0] = 0;
block_offsets[1] = R_space.GetVSize();
block_offsets[2] = W_space.GetVSize();
block_offsets.PartialSum();
Array<int> block_trueOffsets(3);
block_trueOffsets[0] = 0;
block_trueOffsets[1] = R_space.GetTrueVSize();
block_trueOffsets[2] = W_space.GetTrueVSize();
block_trueOffsets.PartialSum();
BlockVector xp(block_offsets);
BlockVector xp(block_trueOffsets);
// 9. Define grid functions for the current configuration, reference
// configuration, final deformation, and pressure
@@ -286,8 +287,8 @@ int main(int argc, char *argv[])
GridFunction x_def(&R_space);
GridFunction p_gf(&W_space);
x_gf.MakeRef(&R_space, xp.GetBlock(0), 0);
p_gf.MakeRef(&W_space, xp.GetBlock(1), 0);
x_gf.MakeTRef(&R_space, xp.GetBlock(0), 0);
p_gf.MakeTRef(&W_space, xp.GetBlock(1), 0);
VectorFunctionCoefficient deform(dim, InitialDeformation);
VectorFunctionCoefficient refconfig(dim, ReferenceConfiguration);
@@ -296,14 +297,19 @@ int main(int argc, char *argv[])
x_ref.ProjectCoefficient(refconfig);
p_gf = 0.0;
x_gf.SetTrueVector();
p_gf.SetTrueVector();
// 10. Initialize the incompressible neo-Hookean operator
RubberOperator oper(spaces, ess_bdr, block_offsets,
RubberOperator oper(spaces, ess_bdr, block_trueOffsets,
newton_rel_tol, newton_abs_tol, newton_iter, c_mu);
// 11. Solve the Newton system
oper.Solve(xp);
// 12. Compute the final deformation
x_gf.SetFromTrueVector();
p_gf.SetFromTrueVector();
subtract(x_gf, x_ref, x_def);
// 13. Visualize the results if requested
@@ -349,7 +355,7 @@ int main(int argc, char *argv[])
JacobianPreconditioner::JacobianPreconditioner(Array<FiniteElementSpace *> &fes,
SparseMatrix &mass,
Array<int> &offsets)
: Solver(offsets[2]), block_offsets(offsets), pressure_mass(&mass)
: Solver(offsets[2]), block_trueOffsets(offsets), pressure_mass(&mass)
{
fes.Copy(spaces);
@@ -381,18 +387,18 @@ JacobianPreconditioner::JacobianPreconditioner(Array<FiniteElementSpace *> &fes,
void JacobianPreconditioner::Mult(const Vector &k, Vector &y) const
{
// Extract the blocks from the input and output vectors
Vector disp_in(k.GetData() + block_offsets[0],
block_offsets[1]-block_offsets[0]);
Vector pres_in(k.GetData() + block_offsets[1],
block_offsets[2]-block_offsets[1]);
Vector disp_in(k.GetData() + block_trueOffsets[0],
block_trueOffsets[1]-block_trueOffsets[0]);
Vector pres_in(k.GetData() + block_trueOffsets[1],
block_trueOffsets[2]-block_trueOffsets[1]);
Vector disp_out(y.GetData() + block_offsets[0],
block_offsets[1]-block_offsets[0]);
Vector pres_out(y.GetData() + block_offsets[1],
block_offsets[2]-block_offsets[1]);
Vector disp_out(y.GetData() + block_trueOffsets[0],
block_trueOffsets[1]-block_trueOffsets[0]);
Vector pres_out(y.GetData() + block_trueOffsets[1],
block_trueOffsets[2]-block_trueOffsets[1]);
Vector temp(block_offsets[1]-block_offsets[0]);
Vector temp2(block_offsets[1]-block_offsets[0]);
Vector temp(block_trueOffsets[1]-block_trueOffsets[0]);
Vector temp2(block_trueOffsets[1]-block_trueOffsets[0]);
// Perform the block elimination for the preconditioner
mass_pcg->Mult(pres_in, pres_out);
@@ -447,9 +453,9 @@ RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
double abs_tol,
int iter,
Coefficient &c_mu)
: Operator(fes[0]->GetVSize() + fes[1]->GetVSize()),
: Operator(fes[0]->GetTrueVSize() + fes[1]->GetTrueVSize()),
newton_solver(), newton_monitor("Newton", 1),
j_monitor(" GMRES", 3), mu(c_mu), block_offsets(offsets)
j_monitor(" GMRES", 3), mu(c_mu), block_trueOffsets(offsets)
{
Array<Vector *> rhs(2);
rhs = NULL; // Set all entries in the array
@@ -471,12 +477,16 @@ RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
a->AddDomainIntegrator(new MassIntegrator(one));
a->Assemble();
a->Finalize();
OperatorPtr op;
Array<int> p_ess_tdofs;
a->FormSystemMatrix(p_ess_tdofs, op);
pressure_mass = a->LoseMat();
delete a;
// Initialize the Jacobian preconditioner
JacobianPreconditioner *jac_prec =
new JacobianPreconditioner(fes, *pressure_mass, block_offsets);
new JacobianPreconditioner(fes, *pressure_mass, block_trueOffsets);
j_prec = jac_prec;
// Set up the Jacobian solver
+8 -8
View File
@@ -8,6 +8,7 @@
// mpirun -np 2 ex19p -m ../data/beam-hex.mesh
// mpirun -np 2 ex19p -m ../data/beam-tet.mesh
// mpirun -np 2 ex19p -m ../data/beam-wedge.mesh
// mpirun -np 2 ex19p -m ../data/beam-quad-amr.mesh
//
// Description: This examples solves a quasi-static incompressible nonlinear
// elasticity problem of the form 0 = H(x), where H is an
@@ -196,10 +197,8 @@ void InitialDeformation(const Vector &x, Vector &y);
int main(int argc, char *argv[])
{
// 1. Initialize MPI
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
MPI_Session mpi;
const int myid = mpi.WorldRank();
// 2. Parse command-line options
const char *mesh_file = "../data/beam-tet.mesh";
@@ -239,7 +238,6 @@ int main(int argc, char *argv[])
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
@@ -399,8 +397,6 @@ int main(int argc, char *argv[])
// 19. Free the used memory
delete pmesh;
MPI_Finalize();
return 0;
}
@@ -474,7 +470,11 @@ void JacobianPreconditioner::SetOperator(const Operator &op)
{
HypreBoomerAMG *stiff_prec_amg = new HypreBoomerAMG();
stiff_prec_amg->SetPrintLevel(0);
stiff_prec_amg->SetElasticityOptions(spaces[0]);
if (!spaces[0]->GetParMesh()->Nonconforming())
{
stiff_prec_amg->SetElasticityOptions(spaces[0]);
}
stiff_prec = stiff_prec_amg;
+1 -14
View File
@@ -33,6 +33,7 @@
// mpirun -np 4 ex1p -pa -d raja-omp
// mpirun -np 4 ex1p -pa -d ceed-cpu
// * mpirun -np 4 ex1p -pa -d ceed-cuda
// * mpirun -np 4 ex1p -pa -d ceed-hip
// mpirun -np 4 ex1p -pa -d ceed-cuda:/gpu/cuda/shared
// mpirun -np 4 ex1p -m ../data/beam-tet.mesh -pa -d ceed-cpu
//
@@ -73,7 +74,6 @@ int main(int argc, char *argv[])
bool pa = false;
const char *device_config = "cpu";
bool visualization = true;
bool amgx = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -85,8 +85,6 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&amgx, "-amgx", "--amgx-precon", "-no-amgx",
"--no-amgx-precon", "Use AmgX V-cycle as preconditioner for CG.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
@@ -221,7 +219,6 @@ int main(int argc, char *argv[])
// 13. Solve the linear system A X = B.
// * With full assembly, use the BoomerAMG preconditioner from hypre.
// * If AmgX is available solve using amg preconditioner.
// * With partial assembly, use Jacobi smoothing, for now.
Solver *prec = NULL;
if (pa)
@@ -231,16 +228,6 @@ int main(int argc, char *argv[])
prec = new OperatorJacobiSmoother(a, ess_tdof_list);
}
}
else if (amgx)
{
#if defined(MFEM_USE_AMGX)
bool amgx_verbose = false;
prec = new AmgXSolver(MPI_COMM_WORLD, AmgXSolver::PRECONDITIONER,
amgx_verbose);
#else
mfem_error("MFEM not configured with AMGX \n");
#endif
}
else
{
prec = new HypreBoomerAMG;
+1 -1
View File
@@ -5,7 +5,7 @@
| | | | | || _|| __/| | | | | |
|_| |_| |_||_| \___||_| |_| |_|
http://mfem.org
https://mfem.org
This directory contains modifications of the example codes that illustrate the
use of MFEM features based on the Ginkgo high-performance linear algebra library
+1 -1
View File
@@ -5,7 +5,7 @@
| | | | | || _|| __/| | | | | |
|_| |_| |_||_| \___||_| |_| |_|
http://mfem.org
https://mfem.org
This directory contains modifications of the example codes that illustrate the
use of MFEM for solving nonlinear constrained optimization problems, including
+11
View File
@@ -48,6 +48,12 @@ endif
ifeq ($(MFEM_USE_GINKGO),YES)
SUBDIRS += ginkgo
endif
ifeq ($(MFEM_USE_AMGX),YES)
SUBDIRS += amgx
endif
ifeq ($(MFEM_USE_SUPERLU),YES)
SUBDIRS += superlu
endif
SUBDIRS_ALL = $(addsuffix /all,$(SUBDIRS))
SUBDIRS_TEST = $(addsuffix /test,$(SUBDIRS))
@@ -119,6 +125,11 @@ ex11p-test-superlu: ex11p
@$(call mfem-test,$<, $(RUN_MPI), SuperLU_DIST example,--superlu)
test-par-YES: ex11p-test-superlu
endif
ifeq ($(MFEM_USE_MKL_CPARDISO),YES)
ex11p-test-cpardiso: ex11p
@$(call mfem-test,$<, $(RUN_MPI), MKL_CPARDISO example,--cpardiso)
test-par-YES: ex11p-test-cpardiso
endif
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
+1 -1
View File
@@ -5,7 +5,7 @@
| | | | | || _|| __/| | | | | |
|_| |_| |_||_| \___||_| |_| |_|
http://mfem.org
https://mfem.org
This directory contains modifications of the example codes that illustrate the
use of MFEM features based on the PETSc suite.
+4 -9
View File
@@ -410,21 +410,16 @@ int main(int argc, char *argv[])
}
// 12. Free the used memory.
if (!use_slepc)
{
delete lobpcg;
}
else
{
delete slepc;
}
delete lobpcg;
delete slepc;
delete precond;
delete M;
delete A;
delete pA;
delete pM;
#if defined(MFEM_USE_SUPERLU) || defined(MFEM_USE_STRUMPACK)
delete Arow;
#endif
delete fespace;
if (order > 0)
{
+1 -1
View File
@@ -5,7 +5,7 @@
| | | | | || _|| __/| | | | | |
|_| |_| |_||_| \___||_| |_| |_|
http://mfem.org
https://mfem.org
This directory contains modifications of the example codes that illustrate the
use of MFEM features based on the Parallel Unstructured Mesh Infrastructure,
+1 -1
View File
@@ -5,7 +5,7 @@
| | | | | || _|| __/| | | | | |
|_| |_| |_||_| \___||_| |_| |_|
http://mfem.org
https://mfem.org
This directory contains modifications of the example codes that illustrate the
use of MFEM features based on the SUNDIALS suite of time integration and
+4 -2
View File
@@ -721,12 +721,14 @@ HyperelasticOperator::HyperelasticOperator(ParFiniteElementSpace &f,
if (nls_type == KINSOL)
{
KINSolver *kinsolver = new KINSolver(f.GetComm(), KIN_NONE, true);
KINSolver *kinsolver = new KINSolver(f.GetComm(), KIN_LINESEARCH, true);
kinsolver->SetJFNK(true);
kinsolver->SetLSMaxIter(100);
newton_solver = kinsolver;
newton_solver->SetOperator(*reduced_oper);
newton_solver->SetMaxIter(200);
newton_solver->SetRelTol(rel_tol);
newton_solver->SetPrintLevel(0);
newton_solver->SetPrintLevel(1);
kinsolver->SetMaxSetupCalls(4);
}
else
+171 -23
View File
@@ -13,17 +13,27 @@
// ex9 -m ../../data/disc-nurbs.mesh -p 1 -r 3 -s 7 -dt 0.005 -tf 9
// ex9 -m ../../data/periodic-cube.mesh -p 0 -r 2 -s 8 -dt 0.02 -tf 8 -o 2
//
// Device sample runs:
// ex9 -pa
// ex9 -ea
// ex9 -fa
// ex9 -pa -m ../../data/periodic-cube.mesh
// ex9 -pa -m ../../data/periodic-cube.mesh -d cuda
// ex9 -ea -m ../../data/periodic-cube.mesh -d cuda
// ex9 -fa -m ../../data/periodic-cube.mesh -d cuda
//
// Description: This example code solves the time-dependent advection equation
// du/dt + v.grad(u) = 0, where v is a given fluid velocity, and
// u0(x)=u(0,x) is a given initial condition.
//
// The example demonstrates the use of Discontinuous Galerkin (DG)
// bilinear forms in MFEM (face integrators), the use of explicit
// ODE time integrators, the definition of periodic boundary
// conditions through periodic meshes, as well as the use of GLVis
// for persistent visualization of a time-evolving solution. The
// saving of time-dependent data files for external visualization
// with VisIt (visit.llnl.gov) is also illustrated.
// bilinear forms in MFEM (face integrators), the use of implicit
// and explicit ODE time integrators, the definition of periodic
// boundary conditions through periodic meshes, as well as the use
// of GLVis for persistent visualization of a time-evolving
// solution. The saving of time-dependent data files for external
// visualization with VisIt (visit.llnl.gov) and ParaView
// (paraview.org) is also illustrated.
#include "mfem.hpp"
#include <fstream>
@@ -53,6 +63,54 @@ double inflow_function(const Vector &x);
// Mesh bounding box
Vector bb_min, bb_max;
class DG_Solver : public Solver
{
private:
SparseMatrix &M, &K, A;
GMRESSolver linear_solver;
BlockILU prec;
double dt;
public:
DG_Solver(SparseMatrix &M_, SparseMatrix &K_, const FiniteElementSpace &fes)
: M(M_),
K(K_),
prec(fes.GetFE(0)->GetDof(),
BlockILU::Reordering::MINIMUM_DISCARDED_FILL),
dt(-1.0)
{
linear_solver.iterative_mode = false;
linear_solver.SetRelTol(1e-9);
linear_solver.SetAbsTol(0.0);
linear_solver.SetMaxIter(100);
linear_solver.SetPrintLevel(0);
linear_solver.SetPreconditioner(prec);
}
void SetTimeStep(double dt_)
{
if (dt_ != dt)
{
dt = dt_;
// Form operator A = M - dt*K
A = K;
A *= -dt;
A += M;
// this will also call SetOperator on the preconditioner
linear_solver.SetOperator(A);
}
}
void SetOperator(const Operator &op)
{
linear_solver.SetOperator(op);
}
virtual void Mult(const Vector &x, Vector &y) const
{
linear_solver.Mult(x, y);
}
};
/** A time-dependent operator for the right-hand side of the ODE. The DG weak
form of du/dt = -v.grad(u) is M du/dt = K u + b, where M and K are the mass
@@ -62,19 +120,21 @@ Vector bb_min, bb_max;
class FE_Evolution : public TimeDependentOperator
{
private:
SparseMatrix &M, &K;
BilinearForm &M, &K;
const Vector &b;
DSmoother M_prec;
Solver *M_prec;
CGSolver M_solver;
DG_Solver *dg_solver;
mutable Vector z;
public:
FE_Evolution(SparseMatrix &_M, SparseMatrix &_K, const Vector &_b);
FE_Evolution(BilinearForm &_M, BilinearForm &_K, const Vector &_b);
virtual void Mult(const Vector &x, Vector &y) const;
virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k);
virtual ~FE_Evolution() { }
virtual ~FE_Evolution();
};
@@ -85,11 +145,16 @@ int main(int argc, char *argv[])
const char *mesh_file = "../../data/periodic-hexagon.mesh";
int ref_levels = 2;
int order = 3;
int ode_solver_type = 4;
bool pa = false;
bool ea = false;
bool fa = false;
const char *device_config = "cpu";
int ode_solver_type = 7;
double t_final = 10.0;
double dt = 0.01;
bool visualization = true;
bool visualization = false;
bool visit = false;
bool paraview = false;
bool binary = false;
int vis_steps = 5;
@@ -108,6 +173,14 @@ int main(int argc, char *argv[])
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&fa, "-fa", "--full-assembly", "-no-fa",
"--no-full-assembly", "Enable Full Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver:\n\t"
"1 - Forward Euler,\n\t"
@@ -128,6 +201,9 @@ int main(int argc, char *argv[])
args.AddOption(&visit, "-visit", "--visit-datafiles", "-no-visit",
"--no-visit-datafiles",
"Save data files for VisIt (visit.llnl.gov) visualization.");
args.AddOption(&paraview, "-paraview", "--paraview-datafiles", "-no-paraview",
"--no-paraview-datafiles",
"Save data files for ParaView (paraview.org) visualization.");
args.AddOption(&binary, "-binary", "--binary-datafiles", "-ascii",
"--ascii-datafiles",
"Use binary (Sidre) or ascii format for VisIt data files.");
@@ -147,6 +223,9 @@ int main(int argc, char *argv[])
}
args.PrintOptions(cout);
Device device(device_config);
device.Print();
// 2. Read the mesh from the given mesh file. We can handle geometrically
// periodic meshes in this code.
Mesh mesh(mesh_file, 1, 1);
@@ -168,7 +247,7 @@ int main(int argc, char *argv[])
// 4. Define the discontinuous DG finite element space of the given
// polynomial order on the refined mesh.
DG_FECollection fec(order, dim);
DG_FECollection fec(order, dim, BasisType::GaussLobatto);
FiniteElementSpace fes(&mesh, &fec);
cout << "Number of unknowns: " << fes.GetVSize() << endl;
@@ -181,8 +260,23 @@ int main(int argc, char *argv[])
FunctionCoefficient u0(u0_function);
BilinearForm m(&fes);
m.AddDomainIntegrator(new MassIntegrator);
BilinearForm k(&fes);
if (pa)
{
m.SetAssemblyLevel(AssemblyLevel::PARTIAL);
k.SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
else if (ea)
{
m.SetAssemblyLevel(AssemblyLevel::ELEMENT);
k.SetAssemblyLevel(AssemblyLevel::ELEMENT);
}
else if (fa)
{
m.SetAssemblyLevel(AssemblyLevel::FULL);
k.SetAssemblyLevel(AssemblyLevel::FULL);
}
m.AddDomainIntegrator(new MassIntegrator);
k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
k.AddInteriorFaceIntegrator(
new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
@@ -194,11 +288,11 @@ int main(int argc, char *argv[])
new BoundaryFlowIntegrator(inflow, velocity, -1.0, -0.5));
m.Assemble();
m.Finalize();
int skip_zeros = 0;
k.Assemble(skip_zeros);
k.Finalize(skip_zeros);
b.Assemble();
m.Finalize();
k.Finalize(skip_zeros);
// 6. Define the initial conditions, save the corresponding grid function to
// a file and (optionally) save data in the VisIt format and initialize
@@ -239,6 +333,20 @@ int main(int argc, char *argv[])
dc->Save();
}
ParaViewDataCollection *pd = NULL;
if (paraview)
{
pd = new ParaViewDataCollection("Example9", &mesh);
pd->SetPrefixPath("ParaView");
pd->RegisterField("solution", &u);
pd->SetLevelsOfDetail(order);
pd->SetDataFormat(VTKFormat::BINARY);
pd->SetHighOrderOutput(true);
pd->SetCycle(0);
pd->SetTime(0.0);
pd->Save();
}
socketstream sout;
if (visualization)
{
@@ -265,7 +373,7 @@ int main(int argc, char *argv[])
// 7. Define the time-dependent evolution operator describing the ODE
// right-hand side, and define the ODE solver used for time integration.
FE_Evolution adv(m.SpMat(), k.SpMat(), b);
FE_Evolution adv(m, k, b);
double t = 0.0;
adv.SetTime(t);
@@ -289,12 +397,18 @@ int main(int argc, char *argv[])
cvode->UseSundialsLinearSolver();
ode_solver = cvode; break;
case 8:
arkode = new ARKStepSolver(ARKStepSolver::EXPLICIT);
arkode->Init(adv);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
arkode->SetOrder(4);
ode_solver = arkode; break;
case 9:
arkode = new ARKStepSolver(ARKStepSolver::EXPLICIT);
arkode->Init(adv);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
if (ode_solver_type == 9) { arkode->SetERKTableNum(FEHLBERG_13_7_8); }
arkode->SetERKTableNum(FEHLBERG_13_7_8);
ode_solver = arkode; break;
}
@@ -329,6 +443,13 @@ int main(int argc, char *argv[])
dc->SetTime(t);
dc->Save();
}
if (paraview)
{
pd->SetCycle(ti);
pd->SetTime(t);
pd->Save();
}
}
}
@@ -342,6 +463,7 @@ int main(int argc, char *argv[])
// 10. Free the used memory.
delete ode_solver;
delete pd;
delete dc;
return 0;
@@ -349,12 +471,23 @@ int main(int argc, char *argv[])
// Implementation of class FE_Evolution
FE_Evolution::FE_Evolution(SparseMatrix &_M, SparseMatrix &_K, const Vector &_b)
: TimeDependentOperator(_M.Size()), M(_M), K(_K), b(_b), z(_M.Size())
FE_Evolution::FE_Evolution(BilinearForm &_M, BilinearForm &_K, const Vector &_b)
: TimeDependentOperator(_M.Height()), M(_M), K(_K), b(_b), z(_M.Height())
{
M_solver.SetPreconditioner(M_prec);
M_solver.SetOperator(M);
Array<int> ess_tdof_list;
if (M.GetAssemblyLevel() == AssemblyLevel::LEGACYFULL)
{
M_prec = new DSmoother(M.SpMat());
M_solver.SetOperator(M.SpMat());
dg_solver = new DG_Solver(M.SpMat(), K.SpMat(), *M.FESpace());
}
else
{
M_prec = new OperatorJacobiSmoother(M, ess_tdof_list);
M_solver.SetOperator(M);
dg_solver = NULL;
}
M_solver.SetPreconditioner(*M_prec);
M_solver.iterative_mode = false;
M_solver.SetRelTol(1e-9);
M_solver.SetAbsTol(0.0);
@@ -370,6 +503,21 @@ void FE_Evolution::Mult(const Vector &x, Vector &y) const
M_solver.Mult(z, y);
}
void FE_Evolution::ImplicitSolve(const double dt, const Vector &x, Vector &k)
{
MFEM_VERIFY(dg_solver != NULL,
"Implicit time integration is not supported with partial assembly");
K.Mult(x, z);
z += b;
dg_solver->SetTimeStep(dt);
dg_solver->Mult(z, k);
}
FE_Evolution::~FE_Evolution()
{
delete M_prec;
delete dg_solver;
}
// Velocity coefficient
void velocity_function(const Vector &x, Vector &v)
+240 -28
View File
@@ -13,17 +13,28 @@
// mpirun -np 4 ex9p -m ../../data/disc-nurbs.mesh -p 1 -rp 2 -s 7 -dt 0.0025 -tf 9
// mpirun -np 4 ex9p -m ../../data/periodic-cube.mesh -p 0 -rp 1 -s 8 -dt 0.01 -tf 8 -o 2
//
// Device sample runs:
// mpirun -np 4 ex9p -pa
// mpirun -np 4 ex9p -ea
// mpirun -np 4 ex9p -fa
// mpirun -np 4 ex9p -pa -m ../../data/periodic-cube.mesh
// mpirun -np 4 ex9p -pa -m ../../data/periodic-cube.mesh -d cuda
// mpirun -np 4 ex9p -ea -m ../../data/periodic-cube.mesh -d cuda
// mpirun -np 4 ex9p -fa -m ../../data/periodic-cube.mesh -d cuda
//
// Description: This example code solves the time-dependent advection equation
// du/dt + v.grad(u) = 0, where v is a given fluid velocity, and
// u0(x)=u(0,x) is a given initial condition.
//
// The example demonstrates the use of Discontinuous Galerkin (DG)
// bilinear forms in MFEM (face integrators), the use of explicit
// ODE time integrators, the definition of periodic boundary
// conditions through periodic meshes, as well as the use of GLVis
// for persistent visualization of a time-evolving solution. The
// saving of time-dependent data files for external visualization
// with VisIt (visit.llnl.gov) is also illustrated.
// bilinear forms in MFEM (face integrators), the use of implicit
// and explicit ODE time integrators, the definition of periodic
// boundary conditions through periodic meshes, as well as the use
// of GLVis for persistent visualization of a time-evolving
// solution. Saving of time-dependent data files for visualization
// with VisIt (visit.llnl.gov) and ParaView (paraview.org), as
// well as the optional saving with ADIOS2 (adios2.readthedocs.io)
// are also illustrated.
#include "mfem.hpp"
#include <fstream>
@@ -52,6 +63,66 @@ double inflow_function(const Vector &x);
// Mesh bounding box
Vector bb_min, bb_max;
class DG_Solver : public Solver
{
private:
HypreParMatrix &M, &K;
SparseMatrix M_diag;
HypreParMatrix *A;
GMRESSolver linear_solver;
BlockILU prec;
double dt;
public:
DG_Solver(HypreParMatrix &M_, HypreParMatrix &K_, const FiniteElementSpace &fes)
: M(M_),
K(K_),
A(NULL),
linear_solver(M.GetComm()),
prec(fes.GetFE(0)->GetDof(),
BlockILU::Reordering::MINIMUM_DISCARDED_FILL),
dt(-1.0)
{
linear_solver.iterative_mode = false;
linear_solver.SetRelTol(1e-9);
linear_solver.SetAbsTol(0.0);
linear_solver.SetMaxIter(100);
linear_solver.SetPrintLevel(0);
linear_solver.SetPreconditioner(prec);
M.GetDiag(M_diag);
}
void SetTimeStep(double dt_)
{
if (dt_ != dt)
{
dt = dt_;
// Form operator A = M - dt*K
delete A;
A = Add(-dt, K, 0.0, K);
SparseMatrix A_diag;
A->GetDiag(A_diag);
A_diag.Add(1.0, M_diag);
// this will also call SetOperator on the preconditioner
linear_solver.SetOperator(*A);
}
}
void SetOperator(const Operator &op)
{
linear_solver.SetOperator(op);
}
virtual void Mult(const Vector &x, Vector &y) const
{
linear_solver.Mult(x, y);
}
~DG_Solver()
{
delete A;
}
};
/** A time-dependent operator for the right-hand side of the ODE. The DG weak
form of du/dt = -v.grad(u) is M du/dt = K u + b, where M and K are the mass
@@ -61,19 +132,21 @@ Vector bb_min, bb_max;
class FE_Evolution : public TimeDependentOperator
{
private:
HypreParMatrix &M, &K;
OperatorHandle M, K;
const Vector &b;
HypreSmoother M_prec;
Solver *M_prec;
CGSolver M_solver;
DG_Solver *dg_solver;
mutable Vector z;
public:
FE_Evolution(HypreParMatrix &_M, HypreParMatrix &_K, const Vector &_b);
FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K, const Vector &_b);
virtual void Mult(const Vector &x, Vector &y) const;
virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k);
virtual ~FE_Evolution() { }
virtual ~FE_Evolution();
};
@@ -91,11 +164,17 @@ int main(int argc, char *argv[])
int ser_ref_levels = 2;
int par_ref_levels = 0;
int order = 3;
int ode_solver_type = 4;
bool pa = false;
bool ea = false;
bool fa = false;
const char *device_config = "cpu";
int ode_solver_type = 7;
double t_final = 10.0;
double dt = 0.01;
bool visualization = true;
bool visualization = false;
bool visit = false;
bool paraview = false;
bool adios2 = false;
bool binary = false;
int vis_steps = 5;
@@ -116,6 +195,14 @@ int main(int argc, char *argv[])
"Number of times to refine the mesh uniformly in parallel.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&fa, "-fa", "--full-assembly", "-no-fa",
"--no-full-assembly", "Enable Full Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver:\n\t"
"1 - Forward Euler,\n\t"
@@ -136,6 +223,12 @@ int main(int argc, char *argv[])
args.AddOption(&visit, "-visit", "--visit-datafiles", "-no-visit",
"--no-visit-datafiles",
"Save data files for VisIt (visit.llnl.gov) visualization.");
args.AddOption(&paraview, "-paraview", "--paraview-datafiles", "-no-paraview",
"--no-paraview-datafiles",
"Save data files for ParaView (paraview.org) visualization.");
args.AddOption(&adios2, "-adios2", "--adios2-streams", "-no-adios2",
"--no-adios2-streams",
"Save data using adios2 streams.");
args.AddOption(&binary, "-binary", "--binary-datafiles", "-ascii",
"--ascii-datafiles",
"Use binary (Sidre) or ascii format for VisIt data files.");
@@ -155,6 +248,7 @@ int main(int argc, char *argv[])
{
args.PrintOptions(cout);
}
// check for vaild ODE solver option
if (ode_solver_type < 1 || ode_solver_type > 9)
{
@@ -166,6 +260,9 @@ int main(int argc, char *argv[])
return 3;
}
Device device(device_config);
if (myid == 0) { device.Print(); }
// 3. Read the serial mesh from the given mesh file on all processors. We can
// handle geometrically periodic meshes in this code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
@@ -197,7 +294,7 @@ int main(int argc, char *argv[])
// 6. Define the parallel discontinuous DG finite element space on the
// parallel refined mesh of the given polynomial order.
DG_FECollection fec(order, dim);
DG_FECollection fec(order, dim, BasisType::GaussLobatto);
ParFiniteElementSpace *fes = new ParFiniteElementSpace(pmesh, &fec);
HYPRE_Int global_vSize = fes->GlobalTrueVSize();
@@ -214,8 +311,24 @@ int main(int argc, char *argv[])
FunctionCoefficient u0(u0_function);
ParBilinearForm *m = new ParBilinearForm(fes);
m->AddDomainIntegrator(new MassIntegrator);
ParBilinearForm *k = new ParBilinearForm(fes);
if (pa)
{
m->SetAssemblyLevel(AssemblyLevel::PARTIAL);
k->SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
else if (ea)
{
m->SetAssemblyLevel(AssemblyLevel::ELEMENT);
k->SetAssemblyLevel(AssemblyLevel::ELEMENT);
}
else if (fa)
{
m->SetAssemblyLevel(AssemblyLevel::FULL);
k->SetAssemblyLevel(AssemblyLevel::FULL);
}
m->AddDomainIntegrator(new MassIntegrator);
k->AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
k->AddInteriorFaceIntegrator(
new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
@@ -226,15 +339,13 @@ int main(int argc, char *argv[])
b->AddBdrFaceIntegrator(
new BoundaryFlowIntegrator(inflow, velocity, -1.0, -0.5));
m->Assemble();
m->Finalize();
int skip_zeros = 0;
m->Assemble();
k->Assemble(skip_zeros);
k->Finalize(skip_zeros);
b->Assemble();
m->Finalize();
k->Finalize(skip_zeros);
HypreParMatrix *M = m->ParallelAssemble();
HypreParMatrix *K = k->ParallelAssemble();
HypreParVector *B = b->ParallelAssemble();
// 8. Define the initial conditions, save the corresponding grid function to
@@ -273,6 +384,8 @@ int main(int argc, char *argv[])
{
dc = new VisItDataCollection("Example9-Parallel", pmesh);
dc->SetPrecision(precision);
// To save the mesh using MFEM's parallel mesh format:
// dc->SetFormat(DataCollection::PARALLEL_FORMAT);
}
dc->RegisterField("solution", u);
dc->SetCycle(0);
@@ -280,6 +393,41 @@ int main(int argc, char *argv[])
dc->Save();
}
ParaViewDataCollection *pd = NULL;
if (paraview)
{
pd = new ParaViewDataCollection("Example9P", pmesh);
pd->SetPrefixPath("ParaView");
pd->RegisterField("solution", u);
pd->SetLevelsOfDetail(order);
pd->SetDataFormat(VTKFormat::BINARY);
pd->SetHighOrderOutput(true);
pd->SetCycle(0);
pd->SetTime(0.0);
pd->Save();
}
// Optionally output a BP (binary pack) file using ADIOS2. This can be
// visualized with the ParaView VTX reader.
#ifdef MFEM_USE_ADIOS2
ADIOS2DataCollection *adios2_dc = NULL;
if (adios2)
{
std::string postfix(mesh_file);
postfix.erase(0, std::string("../data/").size() );
postfix += "_o" + std::to_string(order);
const std::string collection_name = "ex9-p-" + postfix + ".bp";
adios2_dc = new ADIOS2DataCollection(MPI_COMM_WORLD, collection_name, pmesh);
// output data substreams are half the number of mpi processes
adios2_dc->SetParameter("SubStreams", std::to_string(num_procs/2) );
adios2_dc->RegisterField("solution", u);
adios2_dc->SetCycle(0);
adios2_dc->SetTime(0.0);
adios2_dc->Save();
}
#endif
socketstream sout;
if (visualization)
{
@@ -312,7 +460,7 @@ int main(int argc, char *argv[])
// 9. Define the time-dependent evolution operator describing the ODE
// right-hand side, and define the ODE solver used for time integration.
FE_Evolution adv(*M, *K, *B);
FE_Evolution adv(*m, *k, *B);
double t = 0.0;
adv.SetTime(t);
@@ -384,6 +532,23 @@ int main(int argc, char *argv[])
dc->SetTime(t);
dc->Save();
}
if (paraview)
{
pd->SetCycle(ti);
pd->SetTime(t);
pd->Save();
}
#ifdef MFEM_USE_ADIOS2
// transient solutions can be visualized with ParaView
if (adios2)
{
adios2_dc->SetCycle(ti);
adios2_dc->SetTime(t);
adios2_dc->Save();
}
#endif
}
}
@@ -403,13 +568,18 @@ int main(int argc, char *argv[])
delete u;
delete B;
delete b;
delete K;
delete k;
delete M;
delete m;
delete fes;
delete pmesh;
delete ode_solver;
delete pd;
#ifdef MFEM_USE_ADIOS2
if (adios2)
{
delete adios2_dc;
}
#endif
delete dc;
MPI_Finalize();
@@ -418,15 +588,43 @@ int main(int argc, char *argv[])
// Implementation of class FE_Evolution
FE_Evolution::FE_Evolution(HypreParMatrix &_M, HypreParMatrix &_K,
FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K,
const Vector &_b)
: TimeDependentOperator(_M.Height()),
M(_M), K(_K), b(_b), M_solver(M.GetComm()), z(_M.Height())
b(_b),
M_solver(_M.ParFESpace()->GetComm()),
z(_M.Height())
{
M_prec.SetType(HypreSmoother::Jacobi);
M_solver.SetPreconditioner(M_prec);
M_solver.SetOperator(M);
if (_M.GetAssemblyLevel()==AssemblyLevel::LEGACYFULL)
{
M.Reset(_M.ParallelAssemble(), true);
K.Reset(_K.ParallelAssemble(), true);
}
else
{
M.Reset(&_M, false);
K.Reset(&_K, false);
}
M_solver.SetOperator(*M);
Array<int> ess_tdof_list;
if (_M.GetAssemblyLevel()==AssemblyLevel::LEGACYFULL)
{
HypreParMatrix &M_mat = *M.As<HypreParMatrix>();
HypreParMatrix &K_mat = *K.As<HypreParMatrix>();
HypreSmoother *hypre_prec = new HypreSmoother(M_mat, HypreSmoother::Jacobi);
M_prec = hypre_prec;
dg_solver = new DG_Solver(M_mat, K_mat, *_M.FESpace());
}
else
{
M_prec = new OperatorJacobiSmoother(_M, ess_tdof_list);
dg_solver = NULL;
}
M_solver.SetPreconditioner(*M_prec);
M_solver.iterative_mode = false;
M_solver.SetRelTol(1e-9);
M_solver.SetAbsTol(0.0);
@@ -434,14 +632,28 @@ FE_Evolution::FE_Evolution(HypreParMatrix &_M, HypreParMatrix &_K,
M_solver.SetPrintLevel(0);
}
void FE_Evolution::ImplicitSolve(const double dt, const Vector &x, Vector &k)
{
K->Mult(x, z);
z += b;
dg_solver->SetTimeStep(dt);
dg_solver->Mult(z, k);
}
void FE_Evolution::Mult(const Vector &x, Vector &y) const
{
// y = M^{-1} (K x + b)
K.Mult(x, z);
K->Mult(x, z);
z += b;
M_solver.Mult(z, y);
}
FE_Evolution::~FE_Evolution()
{
delete M_prec;
delete dg_solver;
}
// Velocity coefficient
void velocity_function(const Vector &x, Vector &v)
+62
View File
@@ -0,0 +1,62 @@
# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
set(SUPERLU_EXAMPLES_SRCS)
if (MFEM_USE_MPI)
list(APPEND SUPERLU_EXAMPLES_SRCS
ex1p.cpp
)
endif()
# Include the source directory where mfem.hpp and mfem-performance.hpp are.
include_directories(BEFORE ${PROJECT_BINARY_DIR})
# Add "test_superlu" target, see below.
add_custom_target(test_superlu
${CMAKE_CTEST_COMMAND} -R superlu USES_TERMINAL)
# Add one executable per cpp file, adding "superlu_" as prefix. Sets
# "test_superlu" as a target that depends on the given examples.
set(PFX superlu_)
add_mfem_examples(SUPERLU_EXAMPLES_SRCS ${PFX} "" test_superlu)
# Testing.
# The SuperLU tests can be run separately using the target "test_superlu"
# which builds the examples and runs:
# ctest -R superlu
# Command line options for the tests.
# Example 1: Test SuperLU on the simple Poisson problem
set(EX1_COMMON_OPTS -m ../../data/star.mesh -p 2)
set(EX1P_TEST_OPTS ${EX1_COMMON_OPTS})
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUPERLU_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
+321
View File
@@ -0,0 +1,321 @@
// MFEM Example 1 - Parallel Version
// SuperLU Modification
//
// Compile with: make ex1p
//
// Sample runs: mpirun -np 4 ex1p -m ../../data/square-disc.mesh
// mpirun -np 4 ex1p -m ../../data/star.mesh
// mpirun -np 4 ex1p -m ../../data/star-mixed.mesh
// mpirun -np 4 ex1p -m ../../data/escher.mesh
// mpirun -np 4 ex1p -m ../../data/fichera.mesh
// mpirun -np 4 ex1p -m ../../data/fichera-mixed.mesh
// mpirun -np 4 ex1p -m ../../data/toroid-wedge.mesh
// mpirun -np 4 ex1p -m ../../data/periodic-annulus-sector.msh
// mpirun -np 4 ex1p -m ../../data/periodic-torus-sector.msh
// mpirun -np 4 ex1p -m ../../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex1p -m ../../data/square-disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../../data/star-mixed-p2.mesh -o 2
// mpirun -np 4 ex1p -m ../../data/disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../../data/pipe-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../../data/ball-nurbs.mesh -o 2
// mpirun -np 4 ex1p -m ../../data/star-surf.mesh
// mpirun -np 4 ex1p -m ../../data/square-disc-surf.mesh
// mpirun -np 4 ex1p -m ../../data/inline-segment.mesh
// mpirun -np 4 ex1p -m ../../data/amr-quad.mesh
// mpirun -np 4 ex1p -m ../../data/amr-hex.mesh
// mpirun -np 4 ex1p -m ../../data/mobius-strip.mesh
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../../data/star.mesh";
int order = 1;
const char *device_config = "cpu";
bool visualization = true;
int slu_colperm = 4;
int slu_rowperm = 1;
int slu_iterref = 2;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&slu_colperm, "-cp", "--colperm",
"SuperLU Column Permutation Method: 0-NATURAL, 1-MMD-ATA "
"2-MMD_AT_PLUS_A, 3-COLAMD, 4-METIS_AT_PLUS_A, 5-PARMETIS "
"6-ZOLTAN");
args.AddOption(&slu_rowperm, "-rp", "--rowperm",
"SuperLU Row Permutation Method: 0-NOROWPERM, 1-LargeDiag");
args.AddOption(&slu_iterref, "-rp", "--rowperm",
"SuperLU Iterative Refinement: 0-NOREFINE, 1-Single, "
"2-Double, 3-Extra");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 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(mesh_file, 1, 1);
int dim = mesh.Dimension();
// 5. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
{
int ref_levels =
(int)floor(log(1000./mesh.GetNE())/log(2.)/dim);
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);
mesh.Clear();
{
int par_ref_levels = 2;
for (int l = 0; l < par_ref_levels; l++)
{
pmesh.UniformRefinement();
}
}
// 7. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
bool delete_fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
delete_fec = true;
}
else if (pmesh.GetNodes())
{
fec = pmesh.GetNodes()->OwnFEC();
delete_fec = false;
if (myid == 0)
{
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
}
else
{
fec = new H1_FECollection(order = 1, dim);
delete_fec = true;
}
ParFiniteElementSpace fespace(&pmesh, fec);
HYPRE_Int size = fespace.GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 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 from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
fespace.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
// (1,phi_i) where phi_i are the basis functions in fespace.
ParLinearForm b(&fespace);
ConstantCoefficient one(1.0);
b.AddDomainIntegrator(new DomainLFIntegrator(one));
b.Assemble();
// 10. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(&fespace);
x = 0.0;
// 11. Set up the parallel bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
ParBilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator(one));
// 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.
a.Assemble();
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
// 13. Solve the linear system A X = B utilizing SuperLU.
SuperLUSolver *superlu = new SuperLUSolver(MPI_COMM_WORLD);
Operator *SLU_A = new SuperLURowLocMatrix(*A.As<HypreParMatrix>());
superlu->SetPrintStatistics(true);
superlu->SetSymmetricPattern(false);
if (slu_colperm == 0)
{
superlu->SetColumnPermutation(superlu::NATURAL);
}
else if (slu_colperm == 1)
{
superlu->SetColumnPermutation(superlu::MMD_ATA);
}
else if (slu_colperm == 2)
{
superlu->SetColumnPermutation(superlu::MMD_AT_PLUS_A);
}
else if (slu_colperm == 3)
{
superlu->SetColumnPermutation(superlu::COLAMD);
}
else if (slu_colperm == 4)
{
superlu->SetColumnPermutation(superlu::METIS_AT_PLUS_A);
}
else if (slu_colperm == 5)
{
superlu->SetColumnPermutation(superlu::PARMETIS);
}
else if (slu_colperm == 6)
{
superlu->SetColumnPermutation(superlu::ZOLTAN);
}
if (slu_rowperm == 0)
{
superlu->SetRowPermutation(superlu::NOROWPERM);
}
else if (slu_rowperm == 1)
{
#ifdef MFEM_USE_SUPERLU5
superlu->SetRowPermutation(superlu::LargeDiag);
#else
superlu->SetRowPermutation(superlu::LargeDiag_MC64);
#endif
}
if (slu_iterref == 0)
{
superlu->SetIterativeRefine(superlu::NOREFINE);
}
else if (slu_iterref == 1)
{
superlu->SetIterativeRefine(superlu::SLU_SINGLE);
}
else if (slu_iterref == 2)
{
superlu->SetIterativeRefine(superlu::SLU_DOUBLE);
}
else if (slu_iterref == 3)
{
superlu->SetIterativeRefine(superlu::SLU_EXTRA);
}
superlu->SetOperator(*SLU_A);
superlu->SetPrintStatistics(true);
superlu->Mult(B, X);
// 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 << "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);
}
// 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 << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << x << flush;
}
// 17. Free the used memory.
if (delete_fec)
{
delete fec;
}
MPI_Finalize();
return 0;
}
+79
View File
@@ -0,0 +1,79 @@
# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/superlu/,)
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_EXAMPLES =
PAR_EXAMPLES = ex1p
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
else
EXAMPLES = $(PAR_EXAMPLES) $(SEQ_EXAMPLES)
endif
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all clean clean-build clean-exec
# Remove built-in rule
%: %.cpp
# Replace the default implicit rule for *.cpp files
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
all: $(EXAMPLES)
ifeq ($(MFEM_USE_SUPERLU),NO)
$(EXAMPLES):
$(error MFEM is not configured with SuperLU)
endif
MFEM_TESTS = EXAMPLES
include $(MFEM_TEST_MK)
# Testing: Parallel runs
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
PARALLEL_NAME := Parallel SuperLU example
%-test-par: %
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME))
# Testing: Specific execution options:
# Example 1: Test SuperLU on the simple poisson problem
EX1_COMMON_ARGS := -m ../../data/star.mesh
EX1P_ARGS := $(EX1_COMMON_ARGS)
ex1p-test-par: ex1p
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME),$(EX1P_ARGS))
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
# Generate an error message if the MFEM library is not built and exit
$(MFEM_LIB_FILE):
$(error The MFEM library is not built)
clean: clean-build clean-exec
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -f mesh.* sol.*
+10 -11
View File
@@ -17,6 +17,7 @@ set(SRCS
bilininteg_convection_ea.cpp
bilininteg_dgtrace_pa.cpp
bilininteg_dgtrace_ea.cpp
bilininteg_diffusion_mf.cpp
bilininteg_diffusion_pa.cpp
bilininteg_diffusion_ea.cpp
bilininteg_divergence.cpp
@@ -24,11 +25,14 @@ set(SRCS
bilininteg_hdiv.cpp
bilininteg_vectorfe.cpp
bilininteg_gradient.cpp
bilininteg_mass_mf.cpp
bilininteg_mass_pa.cpp
bilininteg_mass_ea.cpp
bilininteg_transpose_ea.cpp
bilininteg_vecdiffusion.cpp
bilininteg_vecdiffusion_mf.cpp
bilininteg_vecmass.cpp
bilininteg_vecmass_mf.cpp
coefficient.cpp
complex_fem.cpp
convergence.cpp
@@ -42,6 +46,9 @@ set(SRCS
gridfunc.cpp
hybridization.cpp
intrules.cpp
libceed/ceed.cpp
libceed/diffusion.cpp
libceed/mass.cpp
linearform.cpp
lininteg.cpp
multigrid.cpp
@@ -78,6 +85,9 @@ set(HDRS
gridfunc.hpp
hybridization.hpp
intrules.hpp
libceed/ceed.hpp
libceed/diffusion.hpp
libceed/mass.hpp
linearform.hpp
lininteg.hpp
multigrid.hpp
@@ -137,17 +147,6 @@ if (MFEM_USE_MPI)
prestriction.hpp)
endif()
if (MFEM_USE_CEED)
list(APPEND SRCS
libceed/ceed.cpp
libceed/diffusion.cpp
libceed/mass.cpp)
list(APPEND HDRS
libceed/ceed.hpp
libceed/diffusion.hpp
libceed/mass.hpp)
endif()
convert_filenames_to_full_paths(SRCS)
convert_filenames_to_full_paths(HDRS)
+1 -2
View File
@@ -133,8 +133,7 @@ void BilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
ext = new PABilinearFormExtension(this);
break;
case AssemblyLevel::NONE:
mfem_error("Matrix-free action not supported yet... stay tuned!");
// ext = new MFBilinearFormExtension(this);
ext = new MFBilinearFormExtension(this);
break;
default:
mfem_error("Unknown assembly level");
+7 -14
View File
@@ -157,7 +157,8 @@ public:
/// Set the desired assembly level.
/** Valid choices are:
- AssemblyLevel::FULL (default)
- AssemblyLevel::LEGACYFULL (default)
- AssemblyLevel::FULL
- AssemblyLevel::PARTIAL
- AssemblyLevel::ELEMENT
- AssemblyLevel::NONE
@@ -415,9 +416,7 @@ public:
returned in the variable @a A, of type OpType, holding a *reference* to
the system matrix (created with the method OpType::MakeRef()). The
reference will be invalidated when SetOperatorType(), Update(), or the
destructor is called.
Currently, this method can be used only with AssemblyLevel::FULL. */
destructor is called. */
template <typename OpType>
void FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x, Vector &b,
OpType &A, Vector &X, Vector &B,
@@ -439,9 +438,7 @@ public:
returned in the variable @a A, of type OpType, holding a *reference* to
the system matrix (created with the method OpType::MakeRef()). The
reference will be invalidated when SetOperatorType(), Update(), or the
destructor is called.
Currently, this method can be used only with AssemblyLevel::FULL. */
destructor is called. */
template <typename OpType>
void FormSystemMatrix(const Array<int> &ess_tdof_list, OpType &A)
{
@@ -759,7 +756,7 @@ public:
/// Sets all sparse values of \f$ M \f$ to @a a.
void operator=(const double a) { *mat = a; }
/// Set the desired assembly level. The default is AssemblyLevel::FULL.
/// Set the desired assembly level. The default is AssemblyLevel::LEGACYFULL.
/** This method must be called before assembly. */
void SetAssemblyLevel(AssemblyLevel assembly_level);
@@ -861,9 +858,7 @@ public:
returned in the variable @a A, of type OpType, holding a *reference* to
the system matrix (created with the method OpType::MakeRef()). The
reference will be invalidated when SetOperatorType(), Update(), or the
destructor is called.
Currently, this method can be used only with AssemblyLevel::FULL. */
destructor is called. */
template <typename OpType>
void FormRectangularSystemMatrix(const Array<int> &trial_tdof_list,
const Array<int> &test_tdof_list, OpType &A)
@@ -893,9 +888,7 @@ public:
returned in the variable @a A, of type OpType, holding a *reference* to
the system matrix (created with the method OpType::MakeRef()). The
reference will be invalidated when SetOperatorType(), Update(), or the
destructor is called.
Currently, this method can be used only with AssemblyLevel::FULL. */
destructor is called. */
template <typename OpType>
void FormRectangularLinearSystem(const Array<int> &trial_tdof_list,
const Array<int> &test_tdof_list,
+200
View File
@@ -36,6 +36,206 @@ const Operator *BilinearFormExtension::GetRestriction() const
return a->GetRestriction();
}
// Data and methods for partially-assembled bilinear forms
MFBilinearFormExtension::MFBilinearFormExtension(BilinearForm *form)
: BilinearFormExtension(form),
trialFes(a->FESpace()),
testFes(a->FESpace())
{
elem_restrict = NULL;
int_face_restrict_lex = NULL;
bdr_face_restrict_lex = NULL;
}
void MFBilinearFormExtension::Assemble()
{
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int integratorCount = integrators.Size();
for (int i = 0; i < integratorCount; ++i)
{
integrators[i]->AssembleMF(*a->FESpace());
}
}
void MFBilinearFormExtension::AssembleDiagonal(Vector &y) const
{
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int iSz = integrators.Size();
if (elem_restrict && !DeviceCanUseCeed())
{
localY = 0.0;
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AssembleDiagonalMF(localY);
}
const ElementRestriction* H1elem_restrict =
dynamic_cast<const ElementRestriction*>(elem_restrict);
if (H1elem_restrict)
{
H1elem_restrict->MultTransposeUnsigned(localY, y);
}
else
{
elem_restrict->MultTranspose(localY, y);
}
}
else
{
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]->AssembleDiagonalMF(y);
}
}
}
void MFBilinearFormExtension::Update()
{
FiniteElementSpace *fes = a->FESpace();
height = width = fes->GetVSize();
trialFes = fes;
testFes = fes;
elem_restrict = nullptr;
int_face_restrict_lex = nullptr;
bdr_face_restrict_lex = nullptr;
}
void MFBilinearFormExtension::FormSystemMatrix(const Array<int> &ess_tdof_list,
OperatorHandle &A)
{
Operator *oper;
Operator::FormSystemOperator(ess_tdof_list, oper);
A.Reset(oper); // A will own oper
}
void MFBilinearFormExtension::FormLinearSystem(const Array<int> &ess_tdof_list,
Vector &x, Vector &b,
OperatorHandle &A,
Vector &X, Vector &B,
int copy_interior)
{
Operator *oper;
Operator::FormLinearSystem(ess_tdof_list, x, b, oper, X, B, copy_interior);
A.Reset(oper); // A will own oper
}
void MFBilinearFormExtension::Mult(const Vector &x, Vector &y) const
{
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int iSz = integrators.Size();
if (DeviceCanUseCeed() || !elem_restrict)
{
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]->AddMultMF(x, y);
}
}
else
{
elem_restrict->Mult(x, localX);
localY = 0.0;
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AddMultMF(localX, localY);
}
elem_restrict->MultTranspose(localY, y);
}
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int iFISz = intFaceIntegrators.Size();
if (int_face_restrict_lex && iFISz>0)
{
int_face_restrict_lex->Mult(x, faceIntX);
if (faceIntX.Size()>0)
{
faceIntY = 0.0;
for (int i = 0; i < iFISz; ++i)
{
intFaceIntegrators[i]->AddMultMF(faceIntX, faceIntY);
}
int_face_restrict_lex->MultTranspose(faceIntY, y);
}
}
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (bdr_face_restrict_lex && bFISz>0)
{
bdr_face_restrict_lex->Mult(x, faceBdrX);
if (faceBdrX.Size()>0)
{
faceBdrY = 0.0;
for (int i = 0; i < bFISz; ++i)
{
bdrFaceIntegrators[i]->AddMultMF(faceBdrX, faceBdrY);
}
bdr_face_restrict_lex->MultTranspose(faceBdrY, y);
}
}
}
void MFBilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
{
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int iSz = integrators.Size();
if (elem_restrict)
{
elem_restrict->Mult(x, localX);
localY = 0.0;
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AddMultTransposeMF(localX, localY);
}
elem_restrict->MultTranspose(localY, y);
}
else
{
y.UseDevice(true);
y = 0.0;
for (int i = 0; i < iSz; ++i)
{
integrators[i]->AddMultTransposeMF(x, y);
}
}
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int iFISz = intFaceIntegrators.Size();
if (int_face_restrict_lex && iFISz>0)
{
int_face_restrict_lex->Mult(x, faceIntX);
if (faceIntX.Size()>0)
{
faceIntY = 0.0;
for (int i = 0; i < iFISz; ++i)
{
intFaceIntegrators[i]->AddMultTransposeMF(faceIntX, faceIntY);
}
int_face_restrict_lex->MultTranspose(faceIntY, y);
}
}
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (bdr_face_restrict_lex && bFISz>0)
{
bdr_face_restrict_lex->Mult(x, faceBdrX);
if (faceBdrX.Size()>0)
{
faceBdrY = 0.0;
for (int i = 0; i < bFISz; ++i)
{
bdrFaceIntegrators[i]->AddMultTransposeMF(faceBdrX, faceBdrY);
}
bdr_face_restrict_lex->MultTranspose(faceBdrY, y);
}
}
}
// Data and methods for partially-assembled bilinear forms
PABilinearFormExtension::PABilinearFormExtension(BilinearForm *form)
+19 -12
View File
@@ -130,24 +130,31 @@ public:
void MultTranspose(const Vector &x, Vector &y) const;
};
/// Data and methods for matrix-free bilinear forms NOT YET IMPLEMENTED.
/// Data and methods for matrix-free bilinear forms
class MFBilinearFormExtension : public BilinearFormExtension
{
public:
MFBilinearFormExtension(BilinearForm *form)
: BilinearFormExtension(form) { }
protected:
const FiniteElementSpace *trialFes, *testFes; // Not owned
mutable Vector localX, localY;
mutable Vector faceIntX, faceIntY;
mutable Vector faceBdrX, faceBdrY;
const Operator *elem_restrict; // Not owned
const Operator *int_face_restrict_lex; // Not owned
const Operator *bdr_face_restrict_lex; // Not owned
/// TODO
void Assemble() {}
void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A) {}
public:
MFBilinearFormExtension(BilinearForm *form);
void Assemble();
void AssembleDiagonal(Vector &diag) const;
void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A);
void FormLinearSystem(const Array<int> &ess_tdof_list,
Vector &x, Vector &b,
OperatorHandle &A, Vector &X, Vector &B,
int copy_interior = 0) {}
void Mult(const Vector &x, Vector &y) const {}
void MultTranspose(const Vector &x, Vector &y) const {}
void Update() {}
~MFBilinearFormExtension() {}
int copy_interior = 0);
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const;
void Update();
};
/// Class extending the MixedBilinearForm class to support different AssemblyLevels.
+95 -37
View File
@@ -96,6 +96,30 @@ void BilinearFormIntegrator::AddMultTransposePA(const Vector &, Vector &) const
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleMF(const FiniteElementSpace &fes)
{
mfem_error ("BilinearFormIntegrator::AssembleMF(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AddMultMF(const Vector &, Vector &) const
{
mfem_error ("BilinearFormIntegrator::AddMultMF(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AddMultTransposeMF(const Vector &, Vector &) const
{
mfem_error ("BilinearFormIntegrator::AddMultTransposeMF(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleDiagonalMF(Vector &)
{
mfem_error ("BilinearFormIntegrator::AssembleDiagonalMF(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleElementMatrix (
const FiniteElement &el, ElementTransformation &Trans,
DenseMatrix &elmat )
@@ -133,8 +157,22 @@ void BilinearFormIntegrator::AssembleElementVector(
const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun,
Vector &elvect)
{
mfem_error("BilinearFormIntegrator::AssembleElementVector\n"
" is not implemented for this class.");
// Note: This default implementation is general but not efficient
DenseMatrix elmat;
AssembleElementMatrix(el, Tr, elmat);
elvect.SetSize(elmat.Height());
elmat.Mult(elfun, elvect);
}
void BilinearFormIntegrator::AssembleFaceVector(
const FiniteElement &el1, const FiniteElement &el2,
FaceElementTransformations &Tr, const Vector &elfun, Vector &elvect)
{
// Note: This default implementation is general but not efficient
DenseMatrix elmat;
AssembleFaceMatrix(el1, el2, Tr, elmat);
elvect.SetSize(elmat.Height());
elmat.Mult(elfun, elvect);
}
@@ -516,10 +554,12 @@ void DiffusionIntegrator::AssembleElementMatrix
#ifdef MFEM_THREAD_SAFE
DenseMatrix dshape(nd,dim), dshapedxt(nd,spaceDim), invdfdx(dim,spaceDim);
Vector D(VQ ? VQ->GetVDim() : 0);
#else
dshape.SetSize(nd,dim);
dshapedxt.SetSize(nd,spaceDim);
invdfdx.SetSize(dim,spaceDim);
D.SetSize(VQ ? VQ->GetVDim() : 0);
#endif
elmat.SetSize(nd);
@@ -537,7 +577,20 @@ void DiffusionIntegrator::AssembleElementMatrix
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
Mult(dshape, Trans.AdjugateJacobian(), dshapedxt);
if (!MQ)
if (MQ)
{
MQ->Eval(invdfdx, Trans, ip);
invdfdx *= w;
Mult(dshapedxt, invdfdx, dshape);
AddMultABt(dshape, dshapedxt, elmat);
}
else if (VQ)
{
VQ->Eval(D, Trans, ip);
D *= w;
AddMultADAt(dshapedxt, D, elmat);
}
else
{
if (Q)
{
@@ -545,13 +598,6 @@ void DiffusionIntegrator::AssembleElementMatrix
}
AddMult_a_AAt(w, dshapedxt, elmat);
}
else
{
MQ->Eval(invdfdx, Trans, ip);
invdfdx *= w;
Mult(dshapedxt, invdfdx, dshape);
AddMultABt(dshape, dshapedxt, elmat);
}
}
}
@@ -570,12 +616,14 @@ void DiffusionIntegrator::AssembleElementMatrix2(
DenseMatrix dshape(tr_nd, dim), dshapedxt(tr_nd, spaceDim);
DenseMatrix te_dshape(te_nd, dim), te_dshapedxt(te_nd, spaceDim);
DenseMatrix invdfdx(dim, spaceDim);
Vector D(VQ ? VQ->GetVDim() : 0);
#else
dshape.SetSize(tr_nd, dim);
dshapedxt.SetSize(tr_nd, spaceDim);
te_dshape.SetSize(te_nd, dim);
te_dshapedxt.SetSize(te_nd, spaceDim);
invdfdx.SetSize(dim, spaceDim);
D.SetSize(VQ ? VQ->GetVDim() : 0);
#endif
elmat.SetSize(te_nd, tr_nd);
@@ -595,7 +643,20 @@ void DiffusionIntegrator::AssembleElementMatrix2(
Mult(dshape, invdfdx, dshapedxt);
Mult(te_dshape, invdfdx, te_dshapedxt);
// invdfdx, dshape, and te_dshape no longer needed
if (!MQ)
if (MQ)
{
MQ->Eval(invdfdx, Trans, ip);
invdfdx *= w;
Mult(te_dshapedxt, invdfdx, te_dshape);
AddMultABt(te_dshape, dshapedxt, elmat);
}
else if (VQ)
{
VQ->Eval(D, Trans, ip);
D *= w;
AddMultADAt(dshapedxt, D, elmat);
}
else
{
if (Q)
{
@@ -604,13 +665,6 @@ void DiffusionIntegrator::AssembleElementMatrix2(
dshapedxt *= w;
AddMultABt(te_dshapedxt, dshapedxt, elmat);
}
else
{
MQ->Eval(invdfdx, Trans, ip);
invdfdx *= w;
Mult(te_dshapedxt, invdfdx, te_dshape);
AddMultABt(te_dshape, dshapedxt, elmat);
}
}
}
@@ -622,12 +676,19 @@ void DiffusionIntegrator::AssembleElementVector(
int dim = el.GetDim();
double w;
if (VQ)
{
MFEM_VERIFY(VQ->GetVDim() == dim, "Unexpected dimension for VectorCoefficient");
}
#ifdef MFEM_THREAD_SAFE
DenseMatrix dshape(nd,dim), invdfdx(dim), mq(dim);
Vector D(VQ ? VQ->GetVDim() : 0);
#else
dshape.SetSize(nd,dim);
invdfdx.SetSize(dim);
mq.SetSize(dim);
D.SetSize(VQ ? VQ->GetVDim() : 0);
#endif
vec.SetSize(dim);
pointflux.SetSize(dim);
@@ -646,7 +707,7 @@ void DiffusionIntegrator::AssembleElementVector(
CalcAdjugate(Tr.Jacobian(), invdfdx); // invdfdx = adj(J)
w = ip.weight / Tr.Weight();
if (!MQ)
if (!MQ && !VQ)
{
dshape.MultTranspose(elfun, vec);
invdfdx.MultTranspose(vec, pointflux);
@@ -657,11 +718,21 @@ void DiffusionIntegrator::AssembleElementVector(
}
else
{
dshape.MultTranspose(elfun, pointflux);
invdfdx.MultTranspose(pointflux, vec);
MQ->Eval(mq, Tr, ip);
mq.Mult(vec, pointflux);
if (MQ)
{
MQ->Eval(mq, Tr, ip);
mq.Mult(vec, pointflux);
}
else
{
VQ->Eval(D, Tr, ip);
for (int j=0; j<dim; ++j)
{
pointflux[j] *= D[j];
}
}
}
pointflux *= w;
invdfdx.Mult(pointflux, vec);
@@ -2194,16 +2265,7 @@ void VectorDiffusionIntegrator::AssembleElementMatrix(
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
// integrand is rational function if det(J) is not constant
int order = 2 * Trans.OrderGrad(&el); // order of the numerator
if (el.Space() == FunctionSpace::rQk)
{
ir = &RefinedIntRules.Get(el.GetGeomType(), order);
}
else
{
ir = &IntRules.Get(el.GetGeomType(), order);
}
ir = &DiffusionIntegrator::GetRule(el,el);
}
elmat = 0.0;
@@ -2254,11 +2316,7 @@ void VectorDiffusionIntegrator::AssembleElementVector(
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
// integrand is rational function if det(J) is not constant
int order = 2 * Tr.OrderGrad(&el); // order of the numerator
ir = (el.Space() == FunctionSpace::rQk) ?
&RefinedIntRules.Get(el.GetGeomType(), order) :
&IntRules.Get(el.GetGeomType(), order);
ir = &DiffusionIntegrator::GetRule(el,el);
}
elvect = 0.0;
+108 -65
View File
@@ -95,6 +95,30 @@ public:
// const FiniteElementSpace &test_fes,
// Vector &emat);
/// Method defining matrix-free assembly.
/** The result of fully matrix-free assembly is stored internally so that it
can be used later in the methods AddMultMF() and AddMultTransposeMF(). */
virtual void AssembleMF(const FiniteElementSpace &fes);
/** Perform the 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 represent
the element-wise discontinuous version of the FE space.
This method can be called only after the method AssembleMF() has been
called. */
virtual void AddMultMF(const Vector &x, Vector &y) const;
/** 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
represent the element-wise discontinuous version of the FE space.
This method can be called only after the method AssemblePA() has been
called. */
virtual void AddMultTransposeMF(const Vector &x, Vector &y) const;
/// Assemble diagonal and add it to Vector @a diag.
virtual void AssembleDiagonalMF(Vector &diag);
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext,
@@ -131,11 +155,22 @@ public:
FaceElementTransformations &Trans,
DenseMatrix &elmat);
/// Perform the local action of the BilinearFormIntegrator
/// @brief Perform the local action of the BilinearFormIntegrator.
/// Note that the default implementation in the base class is general but not
/// efficient.
virtual void AssembleElementVector(const FiniteElement &el,
ElementTransformation &Tr,
const Vector &elfun, Vector &elvect);
/// @brief Perform the local action of the BilinearFormIntegrator resulting
/// from a face integral term.
/// Note that the default implementation in the base class is general but not
/// efficient.
virtual void AssembleFaceVector(const FiniteElement &el1,
const FiniteElement &el2,
FaceElementTransformations &Tr,
const Vector &elfun, Vector &elvect);
virtual void AssembleElementGrad(const FiniteElement &el,
ElementTransformation &Tr,
const Vector &elfun, DenseMatrix &elmat)
@@ -1863,6 +1898,7 @@ class DiffusionIntegrator: public BilinearFormIntegrator
{
protected:
Coefficient *Q;
VectorCoefficient *VQ;
MatrixCoefficient *MQ;
private:
@@ -1870,6 +1906,7 @@ private:
#ifndef MFEM_THREAD_SAFE
DenseMatrix dshape, dshapedxt, invdfdx, mq;
DenseMatrix te_dshape, te_dshapedxt;
Vector D;
#endif
// PA extension
@@ -1878,54 +1915,30 @@ private:
const GeometricFactors *geom; ///< Not owned
int dim, ne, dofs1D, quad1D;
Vector pa_data;
#ifdef MFEM_USE_CEED
bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient
// CEED extension
CeedData* ceedDataPtr;
#endif
public:
/// Construct a diffusion integrator with coefficient Q = 1
DiffusionIntegrator()
{
Q = NULL;
MQ = NULL;
maps = NULL;
geom = NULL;
#ifdef MFEM_USE_CEED
ceedDataPtr = NULL;
#endif
}
: Q(NULL), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL), ceedDataPtr(NULL) { }
/// Construct a diffusion integrator with a scalar coefficient q
DiffusionIntegrator(Coefficient &q)
: Q(&q)
{
MQ = NULL;
maps = NULL;
geom = NULL;
#ifdef MFEM_USE_CEED
ceedDataPtr = NULL;
#endif
}
: Q(&q), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL), ceedDataPtr(NULL) { }
/// Construct a diffusion integrator with a vector coefficient q
DiffusionIntegrator(VectorCoefficient &q)
: Q(NULL), VQ(&q), MQ(NULL), maps(NULL), geom(NULL), ceedDataPtr(NULL) { }
/// Construct a diffusion integrator with a matrix coefficient q
DiffusionIntegrator(MatrixCoefficient &q)
: MQ(&q)
{
Q = NULL;
maps = NULL;
geom = NULL;
#ifdef MFEM_USE_CEED
ceedDataPtr = NULL;
#endif
}
: Q(NULL), VQ(NULL), MQ(&q), maps(NULL), geom(NULL), ceedDataPtr(NULL) { }
virtual ~DiffusionIntegrator()
{
#ifdef MFEM_USE_CEED
delete ceedDataPtr;
#endif
}
/** Given a particular Finite Element computes the element stiffness matrix
@@ -1956,6 +1969,8 @@ public:
using BilinearFormIntegrator::AssemblePA;
virtual void AssembleMF(const FiniteElementSpace &fes);
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
@@ -1963,12 +1978,14 @@ public:
virtual void AssembleDiagonalPA(Vector &diag);
virtual void AssembleDiagonalMF(Vector &diag);
virtual void AddMultMF(const Vector&, Vector&) const;
virtual void AddMultPA(const Vector&, Vector&) const;
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe);
void SetupPA(const FiniteElementSpace &fes);
};
/** Class for local mass matrix assembling a(u,v) := (Q u, v) */
@@ -1986,39 +2003,22 @@ protected:
const GeometricFactors *geom; ///< Not owned
int dim, ne, nq, dofs1D, quad1D;
#ifdef MFEM_USE_CEED
// CEED extension
CeedData* ceedDataPtr;
#endif
public:
MassIntegrator(const IntegrationRule *ir = NULL)
: BilinearFormIntegrator(ir)
{
Q = NULL;
maps = NULL;
geom = NULL;
#ifdef MFEM_USE_CEED
ceedDataPtr = NULL;
#endif
}
: BilinearFormIntegrator(ir), Q(NULL), maps(NULL), geom(NULL),
ceedDataPtr(NULL) { }
/// Construct a mass integrator with coefficient q
MassIntegrator(Coefficient &q, const IntegrationRule *ir = NULL)
: BilinearFormIntegrator(ir), Q(&q)
{
maps = NULL;
geom = NULL;
#ifdef MFEM_USE_CEED
ceedDataPtr = NULL;
#endif
}
: BilinearFormIntegrator(ir), Q(&q), maps(NULL), geom(NULL),
ceedDataPtr(NULL) { }
virtual ~MassIntegrator()
{
#ifdef MFEM_USE_CEED
delete ceedDataPtr;
#endif
}
/** Given a particular Finite Element computes the element mass matrix
elmat. */
@@ -2032,6 +2032,8 @@ public:
using BilinearFormIntegrator::AssemblePA;
virtual void AssembleMF(const FiniteElementSpace &fes);
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
@@ -2039,6 +2041,10 @@ public:
virtual void AssembleDiagonalPA(Vector &diag);
virtual void AssembleDiagonalMF(Vector &diag);
virtual void AddMultMF(const Vector&, Vector&) const;
virtual void AddMultPA(const Vector&, Vector&) const;
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
@@ -2145,24 +2151,34 @@ protected:
const GeometricFactors *geom; ///< Not owned
int dim, ne, nq, dofs1D, quad1D;
// CEED extension
CeedData* ceedDataPtr;
public:
/// Construct an integrator with coefficient 1.0
VectorMassIntegrator()
: vdim(-1), Q_order(0), Q(NULL), VQ(NULL), MQ(NULL) { }
: vdim(-1), Q_order(0), Q(NULL), VQ(NULL), MQ(NULL), ceedDataPtr(NULL) { }
/** Construct an integrator with scalar coefficient q. If possible, save
memory by using a scalar integrator since the resulting matrix is block
diagonal with the same diagonal block repeated. */
VectorMassIntegrator(Coefficient &q, int qo = 0)
: vdim(-1), Q(&q) { VQ = NULL; MQ = NULL; Q_order = qo; }
: vdim(-1), Q_order(qo), Q(&q), VQ(NULL), MQ(NULL), ceedDataPtr(NULL) { }
VectorMassIntegrator(Coefficient &q, const IntegrationRule *ir)
: BilinearFormIntegrator(ir), vdim(-1), Q(&q)
{ VQ = NULL; MQ = NULL; Q_order = 0; }
: BilinearFormIntegrator(ir), vdim(-1), Q_order(0), Q(&q), VQ(NULL),
MQ(NULL), ceedDataPtr(NULL) { }
/// Construct an integrator with diagonal coefficient q
VectorMassIntegrator(VectorCoefficient &q, int qo = 0)
: vdim(q.GetVDim()), VQ(&q) { Q = NULL; MQ = NULL; Q_order = qo; }
: vdim(q.GetVDim()), Q_order(qo), Q(NULL), VQ(&q), MQ(NULL),
ceedDataPtr(NULL) { }
/// Construct an integrator with matrix coefficient q
VectorMassIntegrator(MatrixCoefficient &q, int qo = 0)
: vdim(q.GetVDim()), MQ(&q) { Q = NULL; VQ = NULL; Q_order = qo; }
: vdim(q.GetVDim()), Q_order(qo), Q(NULL), VQ(NULL), MQ(&q),
ceedDataPtr(NULL) { }
virtual ~VectorMassIntegrator()
{
delete ceedDataPtr;
}
int GetVDim() const { return vdim; }
void SetVDim(int vdim) { this->vdim = vdim; }
@@ -2176,8 +2192,11 @@ public:
DenseMatrix &elmat);
using BilinearFormIntegrator::AssemblePA;
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleMF(const FiniteElementSpace &fes);
virtual void AssembleDiagonalPA(Vector &diag);
virtual void AssembleDiagonalMF(Vector &diag);
virtual void AddMultPA(const Vector &x, Vector &y) const;
virtual void AddMultMF(const Vector &x, Vector &y) const;
};
@@ -2541,13 +2560,23 @@ protected:
int dim, sdim, ne, dofs1D, quad1D;
Vector pa_data;
// CEED extension
CeedData* ceedDataPtr;
private:
DenseMatrix dshape, dshapedxt, pelmat;
DenseMatrix Jinv, gshape;
public:
VectorDiffusionIntegrator() { Q = NULL; }
VectorDiffusionIntegrator(Coefficient &q) { Q = &q; }
VectorDiffusionIntegrator()
: Q(NULL), ceedDataPtr(NULL) { }
VectorDiffusionIntegrator(Coefficient &q)
: Q(&q), ceedDataPtr(NULL) { }
virtual ~VectorDiffusionIntegrator()
{
delete ceedDataPtr;
}
virtual void AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
@@ -2557,8 +2586,11 @@ public:
const Vector &elfun, Vector &elvect);
using BilinearFormIntegrator::AssemblePA;
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleMF(const FiniteElementSpace &fes);
virtual void AssembleDiagonalPA(Vector &diag);
virtual void AssembleDiagonalMF(Vector &diag);
virtual void AddMultPA(const Vector &x, Vector &y) const;
virtual void AddMultMF(const Vector &x, Vector &y) const;
};
/** Integrator for the linear elasticity form:
@@ -3029,6 +3061,17 @@ protected:
VectorCoefficient *VQ;
};
}
// PA Diffusion Assemble 2D kernel
template<const int T_SDIM>
void PADiffusionSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d);
}
#endif
+70
View File
@@ -0,0 +1,70 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "libceed/diffusion.hpp"
using namespace std;
namespace mfem
{
void DiffusionIntegrator::AssembleMF(const FiniteElementSpace &fes)
{
#ifdef MFEM_USE_CEED
// Assuming the same element type
fespace = &fes;
Mesh *mesh = fes.GetMesh();
if (mesh->GetNE() == 0) { return; }
const FiniteElement &el = *fes.GetFE(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
if (DeviceCanUseCeed())
{
delete ceedDataPtr;
ceedDataPtr = new CeedData;
InitCeedCoeff(Q, *mesh, *ir, ceedDataPtr);
return CeedMFDiffusionAssemble(fes, *ir, *ceedDataPtr);
}
#endif
mfem_error("Error: DiffusionIntegrator::AssembleMF only implemented with libCEED");
}
void DiffusionIntegrator::AssembleDiagonalMF(Vector &diag)
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAssembleDiagonal(ceedDataPtr, diag);
}
else
#endif
{
mfem_error("Error: DiffusionIntegrator::AssembleDiagonalMF only implemented with libCEED");
}
}
void DiffusionIntegrator::AddMultMF(const Vector &x, Vector &y) const
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAddMult(ceedDataPtr, x, y);
}
else
#endif
{
mfem_error("Error: DiffusionIntegrator::AddMultMF only implemented with libCEED");
}
}
}
+312 -145
View File
@@ -80,28 +80,24 @@ static void OccaPADiffusionSetup3D(const int D1D,
}
#endif // MFEM_USE_OCCA
// PA Diffusion Assemble 2D kernel
template<const int T_SDIM>
static void PADiffusionSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d);
template<>
void PADiffusionSetup2D<2>(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
{
const bool symmetric = (coeffDim != 4);
const bool const_c = c.Size() == 1;
MFEM_VERIFY(coeffDim < 3 ||
!const_c, "Constant matrix coefficient not supported");
const auto W = Reshape(w.Read(), Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,2,2,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
Reshape(c.Read(), Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1) :
Reshape(c.Read(), coeffDim,Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D, symmetric ? 3 : 4, NE);
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
@@ -112,11 +108,39 @@ void PADiffusionSetup2D<2>(const int Q1D,
const double J21 = J(qx,qy,1,0,e);
const double J12 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
const double c_detJ = W(qx,qy) * coeff / ((J11*J22)-(J21*J12));
D(qx,qy,0,e) = c_detJ * (J12*J12 + J22*J22); // 1,1
D(qx,qy,1,e) = -c_detJ * (J12*J11 + J22*J21); // 1,2
D(qx,qy,2,e) = c_detJ * (J11*J11 + J21*J21); // 2,2
const double w_detJ = W(qx,qy) / ((J11*J22)-(J21*J12));
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient
{
// First compute entries of R = MJ^{-T}, without det J factor.
const double M11 = C(0,qx,qy,e);
const double M12 = C(1,qx,qy,e);
const double M21 = symmetric ? M12 : C(2,qx,qy,e);
const double M22 = symmetric ? C(2,qx,qy,e) : C(3,qx,qy,e);
const double R11 = M11*J22 - M12*J12;
const double R21 = M21*J22 - M22*J12;
const double R12 = -M11*J21 + M12*J11;
const double R22 = -M21*J21 + M22*J11;
// Now set y to J^{-1}R.
D(qx,qy,0,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
D(qx,qy,1,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
D(qx,qy,2,e) = w_detJ * (symmetric ? (-J21*R12 + J11*R22) :
(J22*R12 - J12*R22)); // 2,2 or 1,2
if (!symmetric)
{
D(qx,qy,3,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
}
}
else // Vector or scalar coefficient
{
const double C1 = const_c ? C(0,0,0,0) : C(0,qx,qy,e);
const double C2 = const_c ? C(0,0,0,0) :
(coeffDim == 2 ? C(1,qx,qy,e) : C(0,qx,qy,e));
D(qx,qy,0,e) = w_detJ * (C2*J12*J12 + C1*J22*J22); // 1,1
D(qx,qy,1,e) = -w_detJ * (C2*J12*J11 + C1*J22*J21); // 1,2
D(qx,qy,2,e) = w_detJ * (C2*J11*J11 + C1*J21*J21); // 2,2
}
}
}
});
@@ -125,12 +149,14 @@ void PADiffusionSetup2D<2>(const int Q1D,
// PA Diffusion Assemble 2D kernel with 3D node coords
template<>
void PADiffusionSetup2D<3>(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
{
MFEM_VERIFY(coeffDim == 1, "Matrix and vector coefficients not supported");
constexpr int DIM = 2;
constexpr int SDIM = 3;
const bool const_c = c.Size() == 1;
@@ -167,19 +193,23 @@ void PADiffusionSetup2D<3>(const int Q1D,
}
// PA Diffusion Assemble 3D kernel
static void PADiffusionSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
void PADiffusionSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &c,
Vector &d)
{
const bool symmetric = (coeffDim != 9);
const bool const_c = c.Size() == 1;
MFEM_VERIFY(coeffDim < 6 ||
!const_c, "Constant matrix coefficient not supported");
const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1) :
Reshape(c.Read(), Q1D,Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D,Q1D, 6, NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1,1) :
Reshape(c.Read(), coeffDim,Q1D,Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D,Q1D, symmetric ? 6 : 9, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
@@ -200,8 +230,7 @@ static void PADiffusionSetup3D(const int Q1D,
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double coeff = const_c ? C(0,0,0,0) : C(qx,qy,qz,e);
const double c_detJ = W(qx,qy,qz) * coeff / detJ;
const double w_detJ = W(qx,qy,qz) / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
@@ -212,13 +241,69 @@ static void PADiffusionSetup3D(const int Q1D,
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
D(qx,qy,qz,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
D(qx,qy,qz,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
D(qx,qy,qz,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
D(qx,qy,qz,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
D(qx,qy,qz,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
D(qx,qy,qz,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
{
// Compute entries of R = MJ^{-T} = M adj(J)^T, without det J.
const double M11 = C(0, qx,qy,qz, e);
const double M12 = C(1, qx,qy,qz, e);
const double M13 = C(2, qx,qy,qz, e);
const double M21 = (!symmetric) ? C(3, qx,qy,qz, e) : M12;
const double M22 = (!symmetric) ? C(4, qx,qy,qz, e) : C(3, qx,qy,qz, e);
const double M23 = (!symmetric) ? C(5, qx,qy,qz, e) : C(4, qx,qy,qz, e);
const double M31 = (!symmetric) ? C(6, qx,qy,qz, e) : M13;
const double M32 = (!symmetric) ? C(7, qx,qy,qz, e) : M23;
const double M33 = (!symmetric) ? C(8, qx,qy,qz, e) : C(5, qx,qy,qz, e);
const double R11 = M11*A11 + M12*A12 + M13*A13;
const double R12 = M11*A21 + M12*A22 + M13*A23;
const double R13 = M11*A31 + M12*A32 + M13*A33;
const double R21 = M21*A11 + M22*A12 + M23*A13;
const double R22 = M21*A21 + M22*A22 + M23*A23;
const double R23 = M21*A31 + M22*A32 + M23*A33;
const double R31 = M31*A11 + M32*A12 + M33*A13;
const double R32 = M31*A21 + M32*A22 + M33*A23;
const double R33 = M31*A31 + M32*A32 + M33*A33;
// Now set D to J^{-1} R = adj(J) R
D(qx,qy,qz,0,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
const double D12 = w_detJ * (A11*R12 + A12*R22 + A13*R32);
D(qx,qy,qz,1,e) = D12; // 1,2
D(qx,qy,qz,2,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
const double D21 = w_detJ * (A21*R11 + A22*R21 + A23*R31);
const double D22 = w_detJ * (A21*R12 + A22*R22 + A23*R32);
const double D23 = w_detJ * (A21*R13 + A22*R23 + A23*R33);
const double D33 = w_detJ * (A31*R13 + A32*R23 + A33*R33);
D(qx,qy,qz,3,e) = symmetric ? D22 : D21; // 2,2 or 2,1
D(qx,qy,qz,4,e) = symmetric ? D23 : D22; // 2,3 or 2,2
D(qx,qy,qz,5,e) = symmetric ? D33 : D23; // 3,3 or 2,3
if (!symmetric)
{
D(qx,qy,qz,6,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
D(qx,qy,qz,7,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
D(qx,qy,qz,8,e) = D33; // 3,3
}
}
else // Vector or scalar coefficient version
{
const double C1 = const_c ? C(0,0,0,0,0) : C(0,qx,qy,qz,e);
const double C2 = const_c ? C(0,0,0,0,0) :
(coeffDim == 3 ? C(1,qx,qy,qz,e) : C(0,qx,qy,qz,e));
const double C3 = const_c ? C(0,0,0,0,0) :
(coeffDim == 3 ? C(2,qx,qy,qz,e) : C(0,qx,qy,qz,e));
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
D(qx,qy,qz,0,e) = w_detJ * (C1*A11*A11 + C2*A12*A12 + C3*A13*A13); // 1,1
D(qx,qy,qz,1,e) = w_detJ * (C1*A11*A21 + C2*A12*A22 + C3*A13*A23); // 2,1
D(qx,qy,qz,2,e) = w_detJ * (C1*A11*A31 + C2*A12*A32 + C3*A13*A33); // 3,1
D(qx,qy,qz,3,e) = w_detJ * (C1*A21*A21 + C2*A22*A22 + C3*A23*A23); // 2,2
D(qx,qy,qz,4,e) = w_detJ * (C1*A21*A31 + C2*A22*A32 + C3*A23*A33); // 3,2
D(qx,qy,qz,5,e) = w_detJ * (C1*A31*A31 + C2*A32*A32 + C3*A33*A33); // 3,3
}
}
}
}
@@ -229,6 +314,7 @@ static void PADiffusionSetup(const int dim,
const int sdim,
const int D1D,
const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &W,
const Vector &J,
@@ -247,8 +333,8 @@ static void PADiffusionSetup(const int dim,
#else
MFEM_CONTRACT_VAR(D1D);
#endif // MFEM_USE_OCCA
if (sdim == 2) { PADiffusionSetup2D<2>(Q1D, NE, W, J, C, D); }
if (sdim == 3) { PADiffusionSetup2D<3>(Q1D, NE, W, J, C, D); }
if (sdim == 2) { PADiffusionSetup2D<2>(Q1D, coeffDim, NE, W, J, C, D); }
if (sdim == 3) { PADiffusionSetup2D<3>(Q1D, coeffDim, NE, W, J, C, D); }
}
if (dim == 3)
{
@@ -259,11 +345,11 @@ static void PADiffusionSetup(const int dim,
return;
}
#endif // MFEM_USE_OCCA
PADiffusionSetup3D(Q1D, NE, W, J, C, D);
PADiffusionSetup3D(Q1D, coeffDim, NE, W, J, C, D);
}
}
void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes)
void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assuming the same element type
fespace = &fes;
@@ -271,16 +357,13 @@ void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes)
if (mesh->GetNE() == 0) { return; }
const FiniteElement &el = *fes.GetFE(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
if (ceedDataPtr) { delete ceedDataPtr; }
CeedData* ptr = new CeedData();
ceedDataPtr = ptr;
InitCeedCoeff(Q, ptr);
return CeedPADiffusionAssemble(fes, *ir, *ptr);
delete ceedDataPtr;
ceedDataPtr = new CeedData;
InitCeedCoeff(Q, *mesh, *ir, ceedDataPtr);
return CeedPADiffusionAssemble(fes, *ir, *ceedDataPtr);
}
#endif
const int dims = el.GetDim();
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
@@ -291,9 +374,80 @@ void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes)
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(symmDims * nq * ne, Device::GetDeviceMemoryType());
int coeffDim = 1;
Vector coeff;
if (Q == nullptr)
const int MQfullDim = MQ ? MQ->GetHeight() * MQ->GetWidth() : 0;
if (MQ)
{
MFEM_VERIFY(MQ->GetHeight() == dim && MQ->GetWidth() == dim, "");
const int MQsymmDim = MQ->GetWidth() * (MQ->GetWidth() + 1) / 2;
const int MQdim = MQ->IsSymmetric() ? MQsymmDim : MQfullDim;
coeffDim = MQdim;
coeff.SetSize(MQdim * nq * ne);
symmetric = MQ ? MQ->IsSymmetric() : true;
DenseMatrix M;
Vector Msymm;
if (symmetric)
{
Msymm.SetSize(MQsymmDim);
}
else
{
M.SetSize(dim);
}
auto C = Reshape(coeff.HostWrite(), MQdim, nq, ne);
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
if (MQ->IsSymmetric())
{
MQ->EvalSymmetric(Msymm, *tr, ir->IntPoint(p));
for (int i=0; i<MQsymmDim; ++i)
{
C(i, p, e) = Msymm[i];
}
}
else
{
MQ->Eval(M, *tr, ir->IntPoint(p));
for (int i=0; i<dim; ++i)
for (int j=0; j<dim; ++j)
{
C(j+(i*dim), p, e) = M(i,j);
}
}
}
}
}
else if (VQ)
{
MFEM_VERIFY(VQ->GetVDim() == dim, "");
coeffDim = VQ->GetVDim();
coeff.SetSize(coeffDim * nq * ne);
auto C = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
Vector D(coeffDim);
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
VQ->Eval(D, *tr, ir->IntPoint(p));
for (int i=0; i<coeffDim; ++i)
{
C(i, p, e) = D[i];
}
}
}
}
else if (Q == nullptr)
{
coeff.SetSize(1);
coeff(0) = 1.0;
@@ -329,18 +483,15 @@ void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes)
}
}
}
PADiffusionSetup(dim, sdim, dofs1D, quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
pa_data.SetSize((symmetric ? symmDims : MQfullDim) * nq * ne,
Device::GetDeviceMemoryType());
PADiffusionSetup(dim, sdim, dofs1D, quad1D, coeffDim, ne, ir->GetWeights(),
geom->J, coeff, pa_data);
}
void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
SetupPA(fes);
}
template<int T_D1D = 0, int T_Q1D = 0>
static void PADiffusionDiagonal2D(const int NE,
const bool symmetric,
const Array<double> &b,
const Array<double> &g,
const Vector &d,
@@ -354,9 +505,9 @@ static void PADiffusionDiagonal2D(const int NE,
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
// note the different shape for D, this is a (symmetric) matrix so we only
// note the different shape for D, if this is a symmetric matrix we only
// store necessary entries
auto D = Reshape(d.Read(), Q1D*Q1D, 3, NE);
auto D = Reshape(d.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL(e, NE,
{
@@ -378,12 +529,13 @@ static void PADiffusionDiagonal2D(const int NE,
for (int qy = 0; qy < Q1D; ++qy)
{
const int q = qx + qy * Q1D;
const double D0 = D(q,0,e);
const double D1 = D(q,1,e);
const double D2 = D(q,2,e);
QD0[qx][dy] += B(qy, dy) * B(qy, dy) * D0;
QD1[qx][dy] += B(qy, dy) * G(qy, dy) * D1;
QD2[qx][dy] += G(qy, dy) * G(qy, dy) * D2;
const double D00 = D(q,0,e);
const double D10 = D(q,1,e);
const double D01 = symmetric ? D10 : D(q,2,e);
const double D11 = symmetric ? D(q,2,e) : D(q,3,e);
QD0[qx][dy] += B(qy, dy) * B(qy, dy) * D00;
QD1[qx][dy] += B(qy, dy) * G(qy, dy) * (D01 + D10);
QD2[qx][dy] += G(qy, dy) * G(qy, dy) * D11;
}
}
}
@@ -395,7 +547,6 @@ static void PADiffusionDiagonal2D(const int NE,
{
Y(dx,dy,e) += G(qx, dx) * G(qx, dx) * QD0[qx][dy];
Y(dx,dy,e) += G(qx, dx) * B(qx, dx) * QD1[qx][dy];
Y(dx,dy,e) += B(qx, dx) * G(qx, dx) * QD1[qx][dy];
Y(dx,dy,e) += B(qx, dx) * B(qx, dx) * QD2[qx][dy];
}
}
@@ -406,6 +557,7 @@ static void PADiffusionDiagonal2D(const int NE,
// Shared memory PA Diffusion Diagonal 2D kernel
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
static void SmemPADiffusionDiagonal2D(const int NE,
const bool symmetric,
const Array<double> &b_,
const Array<double> &g_,
const Vector &d_,
@@ -422,7 +574,7 @@ static void SmemPADiffusionDiagonal2D(const int NE,
MFEM_VERIFY(Q1D <= MQ1, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto g = Reshape(g_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D*Q1D, 3, NE);
auto D = Reshape(d_.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
{
@@ -435,10 +587,10 @@ static void SmemPADiffusionDiagonal2D(const int NE,
MFEM_SHARED double BG[2][MQ1*MD1];
double (*B)[MD1] = (double (*)[MD1]) (BG+0);
double (*G)[MD1] = (double (*)[MD1]) (BG+1);
MFEM_SHARED double QD[4][NBZ][MD1][MQ1];
MFEM_SHARED double QD[3][NBZ][MD1][MQ1];
double (*QD0)[MD1] = (double (*)[MD1])(QD[0] + tidz);
double (*QD1)[MD1] = (double (*)[MD1])(QD[1] + tidz);
double (*QD2)[MD1] = (double (*)[MD1])(QD[3] + tidz);
double (*QD2)[MD1] = (double (*)[MD1])(QD[2] + tidz);
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
@@ -461,17 +613,18 @@ static void SmemPADiffusionDiagonal2D(const int NE,
for (int qy = 0; qy < Q1D; ++qy)
{
const int q = qx + qy * Q1D;
const double D0 = D(q,0,e);
const double D1 = D(q,1,e);
const double D2 = D(q,2,e);
const double D00 = D(q,0,e);
const double D10 = D(q,1,e);
const double D01 = symmetric ? D10 : D(q,2,e);
const double D11 = symmetric ? D(q,2,e) : D(q,3,e);
const double By = B[qy][dy];
const double Gy = G[qy][dy];
const double BB = By * By;
const double BG = By * Gy;
const double GG = Gy * Gy;
QD0[qx][dy] += BB * D0;
QD1[qx][dy] += BG * D1;
QD2[qx][dy] += GG * D2;
QD0[qx][dy] += BB * D00;
QD1[qx][dy] += BG * (D01 + D10);
QD2[qx][dy] += GG * D11;
}
}
}
@@ -489,7 +642,6 @@ static void SmemPADiffusionDiagonal2D(const int NE,
const double GG = Gx * Gx;
Y(dx,dy,e) += GG * QD0[qx][dy];
Y(dx,dy,e) += BG * QD1[qx][dy];
Y(dx,dy,e) += BG * QD1[qx][dy];
Y(dx,dy,e) += BB * QD2[qx][dy];
}
}
@@ -499,6 +651,7 @@ static void SmemPADiffusionDiagonal2D(const int NE,
template<int T_D1D = 0, int T_Q1D = 0>
static void PADiffusionDiagonal3D(const int NE,
const bool symmetric,
const Array<double> &b,
const Array<double> &g,
const Vector &d,
@@ -515,7 +668,7 @@ static void PADiffusionDiagonal3D(const int NE,
MFEM_VERIFY(Q1D <= MQ1, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Q = Reshape(d.Read(), Q1D*Q1D*Q1D, 6, NE);
auto Q = Reshape(d.Read(), Q1D*Q1D*Q1D, symmetric ? 6 : 9, NE);
auto Y = Reshape(y.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL(e, NE,
{
@@ -540,9 +693,10 @@ static void PADiffusionDiagonal3D(const int NE,
for (int qz = 0; qz < Q1D; ++qz)
{
const int q = qx + (qy + qz * Q1D) * Q1D;
const int k = j >= i ?
const int ksym = j >= i ?
3 - (3-i)*(2-i)/2 + j:
3 - (3-j)*(2-j)/2 + i;
const int k = symmetric ? ksym : (i*DIM) + j;
const double O = Q(q,k,e);
const double Bz = B(qz,dz);
const double Gz = G(qz,dz);
@@ -598,6 +752,7 @@ static void PADiffusionDiagonal3D(const int NE,
// Shared memory PA Diffusion Diagonal 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void SmemPADiffusionDiagonal3D(const int NE,
const bool symmetric,
const Array<double> &b_,
const Array<double> &g_,
const Vector &d_,
@@ -614,7 +769,7 @@ static void SmemPADiffusionDiagonal3D(const int NE,
MFEM_VERIFY(Q1D <= MQ1, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto g = Reshape(g_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D*Q1D*Q1D, 6, NE);
auto D = Reshape(d_.Read(), Q1D*Q1D*Q1D, symmetric ? 6 : 9, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
{
@@ -655,9 +810,10 @@ static void SmemPADiffusionDiagonal3D(const int NE,
for (int qz = 0; qz < Q1D; ++qz)
{
const int q = qx + (qy + qz * Q1D) * Q1D;
const int k = j >= i ?
3 - (3-i)*(2-i)/2 + j:
3 - (3-j)*(2-j)/2 + i;
const int ksym = j >= i ?
3 - (3-i)*(2-i)/2 + j:
3 - (3-j)*(2-j)/2 + i;
const int k = symmetric ? ksym : (i*DIM) + j;
const double O = D(q,k,e);
const double Bz = B[qz][dz];
const double Gz = G[qz][dz];
@@ -716,6 +872,7 @@ static void PADiffusionAssembleDiagonal(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symm,
const Array<double> &B,
const Array<double> &G,
const Vector &D,
@@ -725,30 +882,30 @@ static void PADiffusionAssembleDiagonal(const int dim,
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPADiffusionDiagonal2D<2,2,8>(NE,B,G,D,Y);
case 0x33: return SmemPADiffusionDiagonal2D<3,3,8>(NE,B,G,D,Y);
case 0x44: return SmemPADiffusionDiagonal2D<4,4,4>(NE,B,G,D,Y);
case 0x55: return SmemPADiffusionDiagonal2D<5,5,4>(NE,B,G,D,Y);
case 0x66: return SmemPADiffusionDiagonal2D<6,6,2>(NE,B,G,D,Y);
case 0x77: return SmemPADiffusionDiagonal2D<7,7,2>(NE,B,G,D,Y);
case 0x88: return SmemPADiffusionDiagonal2D<8,8,1>(NE,B,G,D,Y);
case 0x99: return SmemPADiffusionDiagonal2D<9,9,1>(NE,B,G,D,Y);
default: return PADiffusionDiagonal2D(NE,B,G,D,Y,D1D,Q1D);
case 0x22: return SmemPADiffusionDiagonal2D<2,2,8>(NE,symm,B,G,D,Y);
case 0x33: return SmemPADiffusionDiagonal2D<3,3,8>(NE,symm,B,G,D,Y);
case 0x44: return SmemPADiffusionDiagonal2D<4,4,4>(NE,symm,B,G,D,Y);
case 0x55: return SmemPADiffusionDiagonal2D<5,5,4>(NE,symm,B,G,D,Y);
case 0x66: return SmemPADiffusionDiagonal2D<6,6,2>(NE,symm,B,G,D,Y);
case 0x77: return SmemPADiffusionDiagonal2D<7,7,2>(NE,symm,B,G,D,Y);
case 0x88: return SmemPADiffusionDiagonal2D<8,8,1>(NE,symm,B,G,D,Y);
case 0x99: return SmemPADiffusionDiagonal2D<9,9,1>(NE,symm,B,G,D,Y);
default: return PADiffusionDiagonal2D(NE,symm,B,G,D,Y,D1D,Q1D);
}
}
else if (dim == 3)
{
switch ((D1D << 4 ) | Q1D)
{
case 0x23: return SmemPADiffusionDiagonal3D<2,3>(NE,B,G,D,Y);
case 0x34: return SmemPADiffusionDiagonal3D<3,4>(NE,B,G,D,Y);
case 0x45: return SmemPADiffusionDiagonal3D<4,5>(NE,B,G,D,Y);
case 0x56: return SmemPADiffusionDiagonal3D<5,6>(NE,B,G,D,Y);
case 0x67: return SmemPADiffusionDiagonal3D<6,7>(NE,B,G,D,Y);
case 0x78: return SmemPADiffusionDiagonal3D<7,8>(NE,B,G,D,Y);
case 0x89: return SmemPADiffusionDiagonal3D<8,9>(NE,B,G,D,Y);
case 0x9A: return SmemPADiffusionDiagonal3D<9,10>(NE,B,G,D,Y);
default: return PADiffusionDiagonal3D(NE,B,G,D,Y,D1D,Q1D);
case 0x23: return SmemPADiffusionDiagonal3D<2,3>(NE,symm,B,G,D,Y);
case 0x34: return SmemPADiffusionDiagonal3D<3,4>(NE,symm,B,G,D,Y);
case 0x45: return SmemPADiffusionDiagonal3D<4,5>(NE,symm,B,G,D,Y);
case 0x56: return SmemPADiffusionDiagonal3D<5,6>(NE,symm,B,G,D,Y);
case 0x67: return SmemPADiffusionDiagonal3D<6,7>(NE,symm,B,G,D,Y);
case 0x78: return SmemPADiffusionDiagonal3D<7,8>(NE,symm,B,G,D,Y);
case 0x89: return SmemPADiffusionDiagonal3D<8,9>(NE,symm,B,G,D,Y);
case 0x9A: return SmemPADiffusionDiagonal3D<9,10>(NE,symm,B,G,D,Y);
default: return PADiffusionDiagonal3D(NE,symm,B,G,D,Y,D1D,Q1D);
}
}
MFEM_ABORT("Unknown kernel.");
@@ -756,15 +913,14 @@ static void PADiffusionAssembleDiagonal(const int dim,
void DiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAssembleDiagonalPA(ceedDataPtr, diag);
CeedAssembleDiagonal(ceedDataPtr, diag);
}
else
#endif
{
PADiffusionAssembleDiagonal(dim, dofs1D, quad1D, ne,
if (pa_data.Size()==0) { AssemblePA(*fespace); }
PADiffusionAssembleDiagonal(dim, dofs1D, quad1D, ne, symmetric,
maps->B, maps->G, pa_data, diag);
}
}
@@ -873,6 +1029,7 @@ static void OccaPADiffusionApply3D(const int D1D,
// PA Diffusion Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void PADiffusionApply2D(const int NE,
const bool symmetric,
const Array<double> &b_,
const Array<double> &g_,
const Array<double> &bt_,
@@ -891,7 +1048,7 @@ static void PADiffusionApply2D(const int NE,
auto G = Reshape(g_.Read(), Q1D, D1D);
auto Bt = Reshape(bt_.Read(), D1D, Q1D);
auto Gt = Reshape(gt_.Read(), D1D, Q1D);
auto D = Reshape(d_.Read(), Q1D*Q1D, 3, NE);
auto D = Reshape(d_.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
auto X = Reshape(x_.Read(), D1D, D1D, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL(e, NE,
@@ -947,14 +1104,15 @@ static void PADiffusionApply2D(const int NE,
const int q = qx + qy * Q1D;
const double O11 = D(q,0,e);
const double O12 = D(q,1,e);
const double O22 = D(q,2,e);
const double O21 = D(q,1,e);
const double O12 = symmetric ? O21 : D(q,2,e);
const double O22 = symmetric ? D(q,2,e) : D(q,3,e);
const double gradX = grad[qy][qx][0];
const double gradY = grad[qy][qx][1];
grad[qy][qx][0] = (O11 * gradX) + (O12 * gradY);
grad[qy][qx][1] = (O12 * gradX) + (O22 * gradY);
grad[qy][qx][1] = (O21 * gradX) + (O22 * gradY);
}
}
for (int qy = 0; qy < Q1D; ++qy)
@@ -993,6 +1151,7 @@ static void PADiffusionApply2D(const int NE,
// Shared memory PA Diffusion Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
static void SmemPADiffusionApply2D(const int NE,
const bool symmetric,
const Array<double> &b_,
const Array<double> &g_,
const Vector &d_,
@@ -1010,7 +1169,7 @@ static void SmemPADiffusionApply2D(const int NE,
MFEM_VERIFY(Q1D <= MQ1, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto g = Reshape(g_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D*Q1D, 3, NE);
auto D = Reshape(d_.Read(), Q1D*Q1D, symmetric ? 3 : 4, NE);
auto x = Reshape(x_.Read(), D1D, D1D, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
@@ -1092,12 +1251,13 @@ static void SmemPADiffusionApply2D(const int NE,
{
const int q = (qx + ((qy) * Q1D));
const double O11 = D(q,0,e);
const double O12 = D(q,1,e);
const double O22 = D(q,2,e);
const double O21 = D(q,1,e);
const double O12 = symmetric ? O21 : D(q,2,e);
const double O22 = symmetric ? D(q,2,e) : D(q,3,e);
const double gX = QQ0[qy][qx];
const double gY = QQ1[qy][qx];
QQ0[qy][qx] = (O11 * gX) + (O12 * gY);
QQ1[qy][qx] = (O12 * gX) + (O22 * gY);
QQ1[qy][qx] = (O21 * gX) + (O22 * gY);
}
}
MFEM_SYNC_THREAD;
@@ -1149,6 +1309,7 @@ static void SmemPADiffusionApply2D(const int NE,
// PA Diffusion Apply 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void PADiffusionApply3D(const int NE,
const bool symmetric,
const Array<double> &b,
const Array<double> &g,
const Array<double> &bt,
@@ -1166,7 +1327,7 @@ static void PADiffusionApply3D(const int NE,
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto Gt = Reshape(gt.Read(), D1D, Q1D);
auto D = Reshape(d_.Read(), Q1D*Q1D*Q1D, 6, NE);
auto D = Reshape(d_.Read(), Q1D*Q1D*Q1D, symmetric ? 6 : 9, NE);
auto X = Reshape(x_.Read(), D1D, D1D, D1D, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL(e, NE,
@@ -1257,15 +1418,18 @@ static void PADiffusionApply3D(const int NE,
const double O11 = D(q,0,e);
const double O12 = D(q,1,e);
const double O13 = D(q,2,e);
const double O22 = D(q,3,e);
const double O23 = D(q,4,e);
const double O33 = D(q,5,e);
const double O21 = symmetric ? O12 : D(q,3,e);
const double O22 = symmetric ? D(q,3,e) : D(q,4,e);
const double O23 = symmetric ? D(q,4,e) : D(q,5,e);
const double O31 = symmetric ? O13 : D(q,6,e);
const double O32 = symmetric ? O23 : D(q,7,e);
const double O33 = symmetric ? D(q,5,e) : D(q,8,e);
const double gradX = grad[qz][qy][qx][0];
const double gradY = grad[qz][qy][qx][1];
const double gradZ = grad[qz][qy][qx][2];
grad[qz][qy][qx][0] = (O11*gradX)+(O12*gradY)+(O13*gradZ);
grad[qz][qy][qx][1] = (O12*gradX)+(O22*gradY)+(O23*gradZ);
grad[qz][qy][qx][2] = (O13*gradX)+(O23*gradY)+(O33*gradZ);
grad[qz][qy][qx][1] = (O21*gradX)+(O22*gradY)+(O23*gradZ);
grad[qz][qy][qx][2] = (O31*gradX)+(O32*gradY)+(O33*gradZ);
}
}
}
@@ -1364,6 +1528,7 @@ static MFEM_HOST_DEVICE inline double sign(const int q, const int d)
template<int T_D1D = 0, int T_Q1D = 0>
static void SmemPADiffusionApply3D(const int NE,
const bool symmetric,
const Array<double> &b_,
const Array<double> &g_,
const Vector &d_,
@@ -1380,7 +1545,7 @@ static void SmemPADiffusionApply3D(const int NE,
MFEM_VERIFY(Q1D <= M1Q, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto g = Reshape(g_.Read(), Q1D, D1D);
auto d = Reshape(d_.Read(), Q1D, Q1D, Q1D, 6, NE);
auto d = Reshape(d_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, 1,
@@ -1527,15 +1692,18 @@ static void SmemPADiffusionApply3D(const int NE,
const double O11 = d(qx,qy,qz,0,e);
const double O12 = d(qx,qy,qz,1,e);
const double O13 = d(qx,qy,qz,2,e);
const double O22 = d(qx,qy,qz,3,e);
const double O23 = d(qx,qy,qz,4,e);
const double O33 = d(qx,qy,qz,5,e);
const double O21 = symmetric ? O12 : d(qx,qy,qz,3,e);
const double O22 = symmetric ? d(qx,qy,qz,3,e) : d(qx,qy,qz,4,e);
const double O23 = symmetric ? d(qx,qy,qz,4,e) : d(qx,qy,qz,5,e);
const double O31 = symmetric ? O13 : d(qx,qy,qz,6,e);
const double O32 = symmetric ? O23 : d(qx,qy,qz,7,e);
const double O33 = symmetric ? d(qx,qy,qz,5,e) : d(qx,qy,qz,8,e);
const double gX = u[qz];
const double gY = v[qz];
const double gZ = w[qz];
QQQ0[qz][qy][qx] = (O11*gX) + (O12*gY) + (O13*gZ);
QQQ1[qz][qy][qx] = (O12*gX) + (O22*gY) + (O23*gZ);
QQQ2[qz][qy][qx] = (O13*gX) + (O23*gY) + (O33*gZ);
QQQ1[qz][qy][qx] = (O21*gX) + (O22*gY) + (O23*gZ);
QQQ2[qz][qy][qx] = (O31*gX) + (O32*gY) + (O33*gZ);
}
}
}
@@ -1656,6 +1824,7 @@ static void PADiffusionApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symm,
const Array<double> &B,
const Array<double> &G,
const Array<double> &Bt,
@@ -1686,15 +1855,15 @@ static void PADiffusionApply(const int dim,
{
switch (ID)
{
case 0x22: return SmemPADiffusionApply2D<2,2,16>(NE,B,G,D,X,Y);
case 0x33: return SmemPADiffusionApply2D<3,3,16>(NE,B,G,D,X,Y);
case 0x44: return SmemPADiffusionApply2D<4,4,8>(NE,B,G,D,X,Y);
case 0x55: return SmemPADiffusionApply2D<5,5,8>(NE,B,G,D,X,Y);
case 0x66: return SmemPADiffusionApply2D<6,6,4>(NE,B,G,D,X,Y);
case 0x77: return SmemPADiffusionApply2D<7,7,4>(NE,B,G,D,X,Y);
case 0x88: return SmemPADiffusionApply2D<8,8,2>(NE,B,G,D,X,Y);
case 0x99: return SmemPADiffusionApply2D<9,9,2>(NE,B,G,D,X,Y);
default: return PADiffusionApply2D(NE,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
case 0x22: return SmemPADiffusionApply2D<2,2,16>(NE,symm,B,G,D,X,Y);
case 0x33: return SmemPADiffusionApply2D<3,3,16>(NE,symm,B,G,D,X,Y);
case 0x44: return SmemPADiffusionApply2D<4,4,8>(NE,symm,B,G,D,X,Y);
case 0x55: return SmemPADiffusionApply2D<5,5,8>(NE,symm,B,G,D,X,Y);
case 0x66: return SmemPADiffusionApply2D<6,6,4>(NE,symm,B,G,D,X,Y);
case 0x77: return SmemPADiffusionApply2D<7,7,4>(NE,symm,B,G,D,X,Y);
case 0x88: return SmemPADiffusionApply2D<8,8,2>(NE,symm,B,G,D,X,Y);
case 0x99: return SmemPADiffusionApply2D<9,9,2>(NE,symm,B,G,D,X,Y);
default: return PADiffusionApply2D(NE,symm,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
}
}
@@ -1702,16 +1871,16 @@ static void PADiffusionApply(const int dim,
{
switch (ID)
{
case 0x23: return SmemPADiffusionApply3D<2,3>(NE,B,G,D,X,Y);
case 0x34: return SmemPADiffusionApply3D<3,4>(NE,B,G,D,X,Y);
case 0x45: return SmemPADiffusionApply3D<4,5>(NE,B,G,D,X,Y);
case 0x46: return SmemPADiffusionApply3D<4,6>(NE,B,G,D,X,Y);
case 0x56: return SmemPADiffusionApply3D<5,6>(NE,B,G,D,X,Y);
case 0x58: return SmemPADiffusionApply3D<5,8>(NE,B,G,D,X,Y);
case 0x67: return SmemPADiffusionApply3D<6,7>(NE,B,G,D,X,Y);
case 0x78: return SmemPADiffusionApply3D<7,8>(NE,B,G,D,X,Y);
case 0x89: return SmemPADiffusionApply3D<8,9>(NE,B,G,D,X,Y);
default: return PADiffusionApply3D(NE,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
case 0x23: return SmemPADiffusionApply3D<2,3>(NE,symm,B,G,D,X,Y);
case 0x34: return SmemPADiffusionApply3D<3,4>(NE,symm,B,G,D,X,Y);
case 0x45: return SmemPADiffusionApply3D<4,5>(NE,symm,B,G,D,X,Y);
case 0x46: return SmemPADiffusionApply3D<4,6>(NE,symm,B,G,D,X,Y);
case 0x56: return SmemPADiffusionApply3D<5,6>(NE,symm,B,G,D,X,Y);
case 0x58: return SmemPADiffusionApply3D<5,8>(NE,symm,B,G,D,X,Y);
case 0x67: return SmemPADiffusionApply3D<6,7>(NE,symm,B,G,D,X,Y);
case 0x78: return SmemPADiffusionApply3D<7,8>(NE,symm,B,G,D,X,Y);
case 0x89: return SmemPADiffusionApply3D<8,9>(NE,symm,B,G,D,X,Y);
default: return PADiffusionApply3D(NE,symm,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
}
}
MFEM_ABORT("Unknown kernel.");
@@ -1720,15 +1889,13 @@ static void PADiffusionApply(const int dim,
// PA Diffusion Apply kernel
void DiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAddMultPA(ceedDataPtr, x, y);
CeedAddMult(ceedDataPtr, x, y);
}
else
#endif
{
PADiffusionApply(dim, dofs1D, quad1D, ne,
PADiffusionApply(dim, dofs1D, quad1D, ne, symmetric,
maps->B, maps->G, maps->Bt, maps->Gt,
pa_data, x, y);
}
-168
View File
@@ -19,174 +19,6 @@ using namespace std;
namespace mfem
{
// PA H(curl) Mass Assemble 2D kernel
void PAHcurlSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff,
Vector &op)
{
const int NQ = Q1D*Q1D;
const bool symmetric = (coeffDim != 4);
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
auto C = Reshape(coeff.Read(), coeffDim, NQ, NE);
auto y = Reshape(op.Write(), NQ, symmetric ? 3 : 4, NE);
MFEM_FORALL(e, NE,
{
for (int q = 0; q < NQ; ++q)
{
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient version
{
// First compute entries of R = MJ^{-T}, without det J factor.
const double M11 = C(0, q, e);
const double M12 = C(1, q, e);
const double M21 = symmetric ? M12 : C(2, q, e);
const double M22 = symmetric ? C(2, q, e) : C(3, q, e);
const double R11 = M11*J22 - M12*J12;
const double R21 = M21*J22 - M22*J12;
const double R12 = -M11*J21 + M12*J11;
const double R22 = -M21*J21 + M22*J11;
// Now set y to J^{-1}R.
const double w_detJ = W[q] / ((J11*J22)-(J21*J12));
y(q,0,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
y(q,1,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
y(q,2,e) = w_detJ * (symmetric ? (-J21*R12 + J11*R22) :
(J22*R12 - J12*R22)); // 2,2 or 1,2
if (!symmetric)
{
y(q,3,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
}
}
else // Vector or scalar coefficient version
{
const double c_detJ1 = W[q] * C(0, q, e) / ((J11*J22)-(J21*J12));
const double c_detJ2 = (coeffDim == 2) ? W[q] * C(1, q, e)
/ ((J11*J22)-(J21*J12)) : c_detJ1;
y(q,0,e) = (c_detJ2*J12*J12 + c_detJ1*J22*J22); // 1,1
y(q,1,e) = -(c_detJ2*J12*J11 + c_detJ1*J22*J21); // 1,2
y(q,2,e) = (c_detJ2*J11*J11 + c_detJ1*J21*J21); // 2,2
}
}
});
}
// PA H(curl) Mass Assemble 3D kernel
void PAHcurlSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff,
Vector &op)
{
const int NQ = Q1D*Q1D*Q1D;
const bool symmetric = (coeffDim != 9);
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
auto C = Reshape(coeff.Read(), coeffDim, NQ, NE);
auto y = Reshape(op.Write(), NQ, symmetric ? 6 : 9, NE);
MFEM_FORALL(e, NE,
{
for (int q = 0; q < NQ; ++q)
{
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J31 = J(q,2,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double J32 = J(q,2,1,e);
const double J13 = J(q,0,2,e);
const double J23 = J(q,1,2,e);
const double J33 = J(q,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double w_detJ = W[q] / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
{
// First compute entries of R = MJ^{-T} = M adj(J)^T, without det J factor.
const double M11 = C(0, q, e);
const double M12 = C(1, q, e);
const double M13 = C(2, q, e);
const double M21 = (!symmetric) ? C(3, q, e) : M12;
const double M22 = (!symmetric) ? C(4, q, e) : C(3, q, e);
const double M23 = (!symmetric) ? C(5, q, e) : C(4, q, e);
const double M31 = (!symmetric) ? C(6, q, e) : M13;
const double M32 = (!symmetric) ? C(7, q, e) : M23;
const double M33 = (!symmetric) ? C(8, q, e) : C(5, q, e);
const double R11 = M11*A11 + M12*A12 + M13*A13;
const double R12 = M11*A21 + M12*A22 + M13*A23;
const double R13 = M11*A31 + M12*A32 + M13*A33;
const double R21 = M21*A11 + M22*A12 + M23*A13;
const double R22 = M21*A21 + M22*A22 + M23*A23;
const double R23 = M21*A31 + M22*A32 + M23*A33;
const double R31 = M31*A11 + M32*A12 + M33*A13;
const double R32 = M31*A21 + M32*A22 + M33*A23;
const double R33 = M31*A31 + M32*A32 + M33*A33;
// Now set y to J^{-1} R = adj(J) R
y(q,0,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
const double Y12 = w_detJ * (A11*R12 + A12*R22 + A13*R32);
y(q,1,e) = Y12; // 1,2
y(q,2,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
const double Y21 = w_detJ * (A21*R11 + A22*R21 + A23*R31);
const double Y22 = w_detJ * (A21*R12 + A22*R22 + A23*R32);
const double Y23 = w_detJ * (A21*R13 + A22*R23 + A23*R33);
const double Y33 = w_detJ * (A31*R13 + A32*R23 + A33*R33);
y(q,3,e) = symmetric ? Y22 : Y21; // 2,2 or 2,1
y(q,4,e) = symmetric ? Y23 : Y22; // 2,3 or 2,2
y(q,5,e) = symmetric ? Y33 : Y23; // 3,3 or 2,3
if (!symmetric)
{
y(q,6,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
y(q,7,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
y(q,8,e) = Y33; // 3,3
}
}
else // Vector or scalar coefficient version
{
const double D1 = C(0, q, e);
const double D2 = coeffDim == 3 ? C(1, q, e) : D1;
const double D3 = coeffDim == 3 ? C(2, q, e) : D1;
// detJ J^{-1} D J^{-T} = (1/detJ) adj(J) D adj(J)^T
y(q,0,e) = w_detJ * (D1*A11*A11 + D2*A12*A12 + D3*A13*A13); // 1,1
y(q,1,e) = w_detJ * (D1*A11*A21 + D2*A12*A22 + D3*A13*A23); // 2,1
y(q,2,e) = w_detJ * (D1*A11*A31 + D2*A12*A32 + D3*A13*A33); // 3,1
y(q,3,e) = w_detJ * (D1*A21*A21 + D2*A22*A22 + D3*A23*A23); // 2,2
y(q,4,e) = w_detJ * (D1*A21*A31 + D2*A22*A32 + D3*A23*A33); // 3,2
y(q,5,e) = w_detJ * (D1*A31*A31 + D2*A32*A32 + D3*A33*A33); // 3,3
}
}
});
}
void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
+71
View File
@@ -0,0 +1,71 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "libceed/mass.hpp"
using namespace std;
namespace mfem
{
void MassIntegrator::AssembleMF(const FiniteElementSpace &fes)
{
#ifdef MFEM_USE_CEED
// Assuming the same element type
fespace = &fes;
Mesh *mesh = fes.GetMesh();
if (mesh->GetNE() == 0) { return; }
const FiniteElement &el = *fes.GetFE(0);
ElementTransformation *T = mesh->GetElementTransformation(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, *T);
if (DeviceCanUseCeed())
{
delete ceedDataPtr;
ceedDataPtr = new CeedData;
InitCeedCoeff(Q, *mesh, *ir, ceedDataPtr);
return CeedMFMassAssemble(fes, *ir, *ceedDataPtr);
}
#endif
mfem_error("Error: MassIntegrator::AssembleMF only implemented with libCEED");
}
void MassIntegrator::AddMultMF(const Vector &x, Vector &y) const
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAddMult(ceedDataPtr, x, y);
}
else
#endif
{
mfem_error("Error: MassIntegrator::AddMultMF only implemented with libCEED");
}
}
void MassIntegrator::AssembleDiagonalMF(Vector &diag)
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAssembleDiagonal(ceedDataPtr, diag);
}
else
#endif
{
mfem_error("Error: MassIntegrator::AssembleDiagonalMF only implemented with libCEED");
}
}
} // namespace mfem
+7 -20
View File
@@ -23,7 +23,7 @@ namespace mfem
// PA Mass Assemble kernel
void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assuming the same element type
fespace = &fes;
@@ -32,16 +32,13 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
const FiniteElement &el = *fes.GetFE(0);
ElementTransformation *T = mesh->GetElementTransformation(0);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, *T);
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
if (ceedDataPtr) { delete ceedDataPtr; }
CeedData* ptr = new CeedData();
ceedDataPtr = ptr;
InitCeedCoeff(Q, ptr);
return CeedPAMassAssemble(fes, *ir, *ptr);
delete ceedDataPtr;
ceedDataPtr = new CeedData;
InitCeedCoeff(Q, *mesh, *ir, ceedDataPtr);
return CeedPAMassAssemble(fes, *ir, *ceedDataPtr);
}
#endif
dim = mesh->Dimension();
ne = fes.GetMesh()->GetNE();
nq = ir->GetNPoints();
@@ -155,12 +152,6 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
}
}
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
SetupPA(fes);
}
template<int T_D1D = 0, int T_Q1D = 0>
static void PAMassAssembleDiagonal2D(const int NE,
const Array<double> &b,
@@ -468,13 +459,11 @@ static void PAMassAssembleDiagonal(const int dim, const int D1D,
void MassIntegrator::AssembleDiagonalPA(Vector &diag)
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAssembleDiagonalPA(ceedDataPtr, diag);
CeedAssembleDiagonal(ceedDataPtr, diag);
}
else
#endif
{
PAMassAssembleDiagonal(dim, dofs1D, quad1D, ne, maps->B, pa_data, diag);
}
@@ -1227,13 +1216,11 @@ static void PAMassApply(const int dim,
void MassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAddMultPA(ceedDataPtr, x, y);
CeedAddMult(ceedDataPtr, x, y);
}
else
#endif
{
PAMassApply(dim, dofs1D, quad1D, ne, maps->B, maps->Bt, pa_data, x, y);
}
+53 -31
View File
@@ -12,6 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "libceed/diffusion.hpp"
using namespace std;
@@ -129,6 +130,13 @@ void VectorDiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
const FiniteElement &el = *fes.GetFE(0);
const IntegrationRule *ir
= IntRule ? IntRule : &DiffusionIntegrator::GetRule(el, el);
if (DeviceCanUseCeed())
{
delete ceedDataPtr;
ceedDataPtr = new CeedData;
InitCeedCoeff(Q, *mesh, *ir, ceedDataPtr);
return CeedPADiffusionAssemble(fes, *ir, * ceedDataPtr);
}
const int dims = el.GetDim();
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
@@ -506,33 +514,40 @@ void PAVectorDiffusionApply3D(const int NE,
// PA Diffusion Apply kernel
void VectorDiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
const int D1D = dofs1D;
const int Q1D = quad1D;
const Array<double> &B = maps->B;
const Array<double> &G = maps->G;
const Array<double> &Bt = maps->Bt;
const Array<double> &Gt = maps->Gt;
const Vector &D = pa_data;
if (dim == 2 && sdim == 3)
if (DeviceCanUseCeed())
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return PAVectorDiffusionApply2D<2,2,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x33: return PAVectorDiffusionApply2D<3,3,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x44: return PAVectorDiffusionApply2D<4,4,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x55: return PAVectorDiffusionApply2D<5,5,3>(ne,B,G,Bt,Gt,D,x,y);
default:
return PAVectorDiffusionApply2D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D,sdim);
}
CeedAddMult(ceedDataPtr, x, y);
}
if (dim == 2 && sdim == 2)
{ return PAVectorDiffusionApply2D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D,sdim); }
else
{
const int D1D = dofs1D;
const int Q1D = quad1D;
const Array<double> &B = maps->B;
const Array<double> &G = maps->G;
const Array<double> &Bt = maps->Bt;
const Array<double> &Gt = maps->Gt;
const Vector &D = pa_data;
if (dim == 3 && sdim == 3)
{ return PAVectorDiffusionApply3D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D); }
if (dim == 2 && sdim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return PAVectorDiffusionApply2D<2,2,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x33: return PAVectorDiffusionApply2D<3,3,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x44: return PAVectorDiffusionApply2D<4,4,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x55: return PAVectorDiffusionApply2D<5,5,3>(ne,B,G,Bt,Gt,D,x,y);
default:
return PAVectorDiffusionApply2D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D,sdim);
}
}
if (dim == 2 && sdim == 2)
{ return PAVectorDiffusionApply2D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D,sdim); }
MFEM_ABORT("Unknown kernel.");
if (dim == 3 && sdim == 3)
{ return PAVectorDiffusionApply3D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D); }
MFEM_ABORT("Unknown kernel.");
}
}
template<int T_D1D = 0, int T_Q1D = 0>
@@ -726,14 +741,21 @@ static void PAVectorDiffusionAssembleDiagonal(const int dim,
void VectorDiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
{
PAVectorDiffusionAssembleDiagonal(dim,
dofs1D,
quad1D,
ne,
maps->B,
maps->G,
pa_data,
diag);
if (DeviceCanUseCeed())
{
CeedAssembleDiagonal(ceedDataPtr, diag);
}
else
{
PAVectorDiffusionAssembleDiagonal(dim,
dofs1D,
quad1D,
ne,
maps->B,
maps->G,
pa_data,
diag);
}
}
} // namespace mfem
+69
View File
@@ -0,0 +1,69 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "libceed/diffusion.hpp"
using namespace std;
namespace mfem
{
void VectorDiffusionIntegrator::AssembleMF(const FiniteElementSpace &fes)
{
#ifdef MFEM_USE_CEED
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement &el = *fes.GetFE(0);
const IntegrationRule *ir
= IntRule ? IntRule : &DiffusionIntegrator::GetRule(el, el);
if (DeviceCanUseCeed())
{
delete ceedDataPtr;
ceedDataPtr = new CeedData;
InitCeedCoeff(Q, *mesh, *ir, ceedDataPtr);
return CeedMFDiffusionAssemble(fes, *ir, * ceedDataPtr);
}
#endif
mfem_error("Error: VectorDiffusionIntegrator::AssembleMF only implemented with libCEED");
}
void VectorDiffusionIntegrator::AddMultMF(const Vector &x, Vector &y) const
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAddMult(ceedDataPtr, x, y);
}
else
#endif
{
mfem_error("Error: VectorDiffusionIntegrator::AssembleDiagonalMF only implemented with libCEED");
}
}
void VectorDiffusionIntegrator::AssembleDiagonalMF(Vector &diag)
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAssembleDiagonal(ceedDataPtr, diag);
}
else
#endif
{
mfem_error("Error: VectorDiffusionIntegrator::AddMultMF only implemented with libCEED");
}
}
} // namespace mfem
+31 -9
View File
@@ -12,6 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "libceed/mass.hpp"
using namespace std;
@@ -30,6 +31,13 @@ void VectorMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
ElementTransformation *T = mesh->GetElementTransformation(0);
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(el, el, *T);
if (DeviceCanUseCeed())
{
delete ceedDataPtr;
ceedDataPtr = new CeedData;
InitCeedCoeff(Q, *mesh, *ir, ceedDataPtr);
return CeedPAMassAssemble(fes, *ir, *ceedDataPtr);
}
dim = mesh->Dimension();
ne = fes.GetMesh()->GetNE();
nq = ir->GetNPoints();
@@ -361,7 +369,14 @@ static void PAVectorMassApply(const int dim,
void VectorMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
PAVectorMassApply(dim, dofs1D, quad1D, ne, maps->B, maps->Bt, pa_data, x, y);
if (DeviceCanUseCeed())
{
CeedAddMult(ceedDataPtr, x, y);
}
else
{
PAVectorMassApply(dim, dofs1D, quad1D, ne, maps->B, maps->Bt, pa_data, x, y);
}
}
template<const int T_D1D = 0, const int T_Q1D = 0>
@@ -514,14 +529,21 @@ static void PAVectorMassAssembleDiagonal(const int dim,
void VectorMassIntegrator::AssembleDiagonalPA(Vector &diag)
{
PAVectorMassAssembleDiagonal(dim,
dofs1D,
quad1D,
ne,
maps->B,
maps->Bt,
pa_data,
diag);
if (DeviceCanUseCeed())
{
CeedAssembleDiagonal(ceedDataPtr, diag);
}
else
{
PAVectorMassAssembleDiagonal(dim,
dofs1D,
quad1D,
ne,
maps->B,
maps->Bt,
pa_data,
diag);
}
}
} // namespace mfem
+74
View File
@@ -0,0 +1,74 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "libceed/mass.hpp"
using namespace std;
namespace mfem
{
// MF Mass Integrator
// MF Mass Assemble kernel
void VectorMassIntegrator::AssembleMF(const FiniteElementSpace &fes)
{
#ifdef MFEM_USE_CEED
// Assuming the same element type
Mesh *mesh = fes.GetMesh();
if (mesh->GetNE() == 0) { return; }
const FiniteElement &el = *fes.GetFE(0);
ElementTransformation *T = mesh->GetElementTransformation(0);
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(el, el, *T);
if (DeviceCanUseCeed())
{
delete ceedDataPtr;
ceedDataPtr = new CeedData;
InitCeedCoeff(Q, *mesh, *ir, ceedDataPtr);
return CeedMFMassAssemble(fes, *ir, *ceedDataPtr);
}
#endif
mfem_error("Error: VectorMassIntegrator::AssembleMF only implemented with libCEED");
}
void VectorMassIntegrator::AddMultMF(const Vector &x, Vector &y) const
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAddMult(ceedDataPtr, x, y);
}
else
#endif
{
mfem_error("Error: VectorMassIntegrator::AssembleDiagonalMF only implemented with libCEED");
}
}
void VectorMassIntegrator::AssembleDiagonalMF(Vector &diag)
{
#ifdef MFEM_USE_CEED
if (DeviceCanUseCeed())
{
CeedAssembleDiagonal(ceedDataPtr, diag);
}
else
#endif
{
mfem_error("Error: VectorMassIntegrator::AddMultMF only implemented with libCEED");
}
}
} // namespace mfem
+140 -141
View File
@@ -15,21 +15,13 @@
namespace mfem
{
void PAHcurlSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff,
Vector &op);
void PAHcurlSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff,
Vector &op);
void PADiffusionSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
const Vector &_coeff,
Vector &op);
void PAHcurlMassAssembleDiagonal2D(const int D1D,
const int Q1D,
@@ -189,12 +181,11 @@ void PAHcurlHdivSetup3D(const int Q1D,
Vector &_coeff,
Vector &op)
{
const int NQ = Q1D*Q1D*Q1D;
const bool symmetric = (coeffDim != 9);
auto W = _w.Read();
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
auto y = Reshape(op.Write(), 9, NQ, NE);
auto W = Reshape(_w.Read(), Q1D, Q1D, Q1D);
auto J = Reshape(j.Read(), Q1D, Q1D, Q1D, 3, 3, NE);
auto coeff = Reshape(_coeff.Read(), coeffDim, Q1D, Q1D, Q1D, NE);
auto y = Reshape(op.Write(), 9, Q1D, Q1D, Q1D, NE);
const int i11 = 0;
const int i12 = transpose ? 3 : 1;
@@ -206,83 +197,89 @@ void PAHcurlHdivSetup3D(const int Q1D,
const int i32 = transpose ? 5 : 7;
const int i33 = 8;
MFEM_FORALL(e, NE,
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
{
for (int q = 0; q < NQ; ++q)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J31 = J(q,2,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double J32 = J(q,2,1,e);
const double J13 = J(q,0,2,e);
const double J23 = J(q,1,2,e);
const double J33 = J(q,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double w_detJ = W[q] / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
// First compute entries of R = MJ
const double M11 = (!symmetric) ? coeff(i11, q, e) : coeff(0, q, e);
const double M12 = (!symmetric) ? coeff(i12, q, e) : coeff(1, q, e);
const double M13 = (!symmetric) ? coeff(i13, q, e) : coeff(2, q, e);
const double M21 = (!symmetric) ? coeff(i21, q, e) : M12;
const double M22 = (!symmetric) ? coeff(i22, q, e) : coeff(3, q, e);
const double M23 = (!symmetric) ? coeff(i23, q, e) : coeff(4, q, e);
const double M31 = (!symmetric) ? coeff(i31, q, e) : M13;
const double M32 = (!symmetric) ? coeff(i32, q, e) : M23;
const double M33 = (!symmetric) ? coeff(i33, q, e) : coeff(5, q, e);
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double J11 = J(qx,qy,qz,0,0,e);
const double J21 = J(qx,qy,qz,1,0,e);
const double J31 = J(qx,qy,qz,2,0,e);
const double J12 = J(qx,qy,qz,0,1,e);
const double J22 = J(qx,qy,qz,1,1,e);
const double J32 = J(qx,qy,qz,2,1,e);
const double J13 = J(qx,qy,qz,0,2,e);
const double J23 = J(qx,qy,qz,1,2,e);
const double J33 = J(qx,qy,qz,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double w_detJ = W(qx,qy,qz) / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
const double R11 = M11*J11 + M12*J12 + M13*J13;
const double R12 = M11*J21 + M12*J22 + M13*J23;
const double R13 = M11*J31 + M12*J32 + M13*J33;
const double R21 = M21*J11 + M22*J12 + M23*J13;
const double R22 = M21*J21 + M22*J22 + M23*J23;
const double R23 = M21*J31 + M22*J32 + M23*J33;
const double R31 = M31*J11 + M32*J12 + M33*J13;
const double R32 = M31*J21 + M32*J22 + M33*J23;
const double R33 = M31*J31 + M32*J32 + M33*J33;
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
{
// First compute entries of R = MJ
const double M11 = (!symmetric) ? coeff(i11,qx,qy,qz,e) : coeff(0,qx,qy,qz,e);
const double M12 = (!symmetric) ? coeff(i12,qx,qy,qz,e) : coeff(1,qx,qy,qz,e);
const double M13 = (!symmetric) ? coeff(i13,qx,qy,qz,e) : coeff(2,qx,qy,qz,e);
const double M21 = (!symmetric) ? coeff(i21,qx,qy,qz,e) : M12;
const double M22 = (!symmetric) ? coeff(i22,qx,qy,qz,e) : coeff(3,qx,qy,qz,e);
const double M23 = (!symmetric) ? coeff(i23,qx,qy,qz,e) : coeff(4,qx,qy,qz,e);
const double M31 = (!symmetric) ? coeff(i31,qx,qy,qz,e) : M13;
const double M32 = (!symmetric) ? coeff(i32,qx,qy,qz,e) : M23;
const double M33 = (!symmetric) ? coeff(i33,qx,qy,qz,e) : coeff(5,qx,qy,qz,e);
// Now set y to detJ J^{-1} R = adj(J) R
y(i11,q,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
y(i12,q,e) = w_detJ * (A11*R12 + A12*R22 + A13*R32); // 1,2
y(i13,q,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
y(i21,q,e) = w_detJ * (A21*R11 + A22*R21 + A23*R31); // 2,1
y(i22,q,e) = w_detJ * (A21*R12 + A22*R22 + A23*R32); // 2,2
y(i23,q,e) = w_detJ * (A21*R13 + A22*R23 + A23*R33); // 2,3
y(i31,q,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
y(i32,q,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
y(i33,q,e) = w_detJ * (A31*R13 + A32*R23 + A33*R33); // 3,3
}
else if (coeffDim == 3) // Vector coefficient version
{
const double D1 = coeff(0, q, e);
const double D2 = coeff(1, q, e);
const double D3 = coeff(2, q, e);
// detJ J^{-1} DJ = adj(J) DJ
y(i11,q,e) = w_detJ * (D1*A11*J11 + D2*A12*J21 + D3*A13*J31); // 1,1
y(i12,q,e) = w_detJ * (D1*A11*J12 + D2*A12*J22 + D3*A13*J32); // 1,2
y(i13,q,e) = w_detJ * (D1*A11*J13 + D2*A12*J23 + D3*A13*J33); // 1,3
y(i21,q,e) = w_detJ * (D1*A21*J11 + D2*A22*J21 + D3*A23*J31); // 2,1
y(i22,q,e) = w_detJ * (D1*A21*J12 + D2*A22*J22 + D3*A23*J32); // 2,2
y(i23,q,e) = w_detJ * (D1*A21*J13 + D2*A22*J23 + D3*A23*J33); // 2,3
y(i31,q,e) = w_detJ * (D1*A31*J11 + D2*A32*J21 + D3*A33*J31); // 3,1
y(i32,q,e) = w_detJ * (D1*A31*J12 + D2*A32*J22 + D3*A33*J32); // 3,2
y(i33,q,e) = w_detJ * (D1*A31*J13 + D2*A32*J23 + D3*A33*J33); // 3,3
const double R11 = M11*J11 + M12*J12 + M13*J13;
const double R12 = M11*J21 + M12*J22 + M13*J23;
const double R13 = M11*J31 + M12*J32 + M13*J33;
const double R21 = M21*J11 + M22*J12 + M23*J13;
const double R22 = M21*J21 + M22*J22 + M23*J23;
const double R23 = M21*J31 + M22*J32 + M23*J33;
const double R31 = M31*J11 + M32*J12 + M33*J13;
const double R32 = M31*J21 + M32*J22 + M33*J23;
const double R33 = M31*J31 + M32*J32 + M33*J33;
// Now set y to detJ J^{-1} R = adj(J) R
y(i11,qx,qy,qz,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
y(i12,qx,qy,qz,e) = w_detJ * (A11*R12 + A12*R22 + A13*R32); // 1,2
y(i13,qx,qy,qz,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
y(i21,qx,qy,qz,e) = w_detJ * (A21*R11 + A22*R21 + A23*R31); // 2,1
y(i22,qx,qy,qz,e) = w_detJ * (A21*R12 + A22*R22 + A23*R32); // 2,2
y(i23,qx,qy,qz,e) = w_detJ * (A21*R13 + A22*R23 + A23*R33); // 2,3
y(i31,qx,qy,qz,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
y(i32,qx,qy,qz,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
y(i33,qx,qy,qz,e) = w_detJ * (A31*R13 + A32*R23 + A33*R33); // 3,3
}
else if (coeffDim == 3) // Vector coefficient version
{
const double D1 = coeff(0,qx,qy,qz,e);
const double D2 = coeff(1,qx,qy,qz,e);
const double D3 = coeff(2,qx,qy,qz,e);
// detJ J^{-1} DJ = adj(J) DJ
y(i11,qx,qy,qz,e) = w_detJ * (D1*A11*J11 + D2*A12*J21 + D3*A13*J31); // 1,1
y(i12,qx,qy,qz,e) = w_detJ * (D1*A11*J12 + D2*A12*J22 + D3*A13*J32); // 1,2
y(i13,qx,qy,qz,e) = w_detJ * (D1*A11*J13 + D2*A12*J23 + D3*A13*J33); // 1,3
y(i21,qx,qy,qz,e) = w_detJ * (D1*A21*J11 + D2*A22*J21 + D3*A23*J31); // 2,1
y(i22,qx,qy,qz,e) = w_detJ * (D1*A21*J12 + D2*A22*J22 + D3*A23*J32); // 2,2
y(i23,qx,qy,qz,e) = w_detJ * (D1*A21*J13 + D2*A22*J23 + D3*A23*J33); // 2,3
y(i31,qx,qy,qz,e) = w_detJ * (D1*A31*J11 + D2*A32*J21 + D3*A33*J31); // 3,1
y(i32,qx,qy,qz,e) = w_detJ * (D1*A31*J12 + D2*A32*J22 + D3*A33*J32); // 3,2
y(i33,qx,qy,qz,e) = w_detJ * (D1*A31*J13 + D2*A32*J23 + D3*A33*J33); // 3,3
}
}
}
}
});
@@ -300,59 +297,61 @@ void PAHcurlHdivSetup2D(const int Q1D,
Vector &_coeff,
Vector &op)
{
const int NQ = Q1D*Q1D;
const bool symmetric = (coeffDim != 4);
auto W = _w.Read();
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
auto y = Reshape(op.Write(), 4, NQ, NE);
auto W = Reshape(_w.Read(), Q1D, Q1D);
auto J = Reshape(j.Read(), Q1D, Q1D, 2, 2, NE);
auto coeff = Reshape(_coeff.Read(), coeffDim, Q1D, Q1D, NE);
auto y = Reshape(op.Write(), 4, Q1D, Q1D, NE);
const int i11 = 0;
const int i12 = transpose ? 2 : 1;
const int i21 = transpose ? 1 : 2;
const int i22 = 3;
MFEM_FORALL(e, NE,
MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
{
for (int q = 0; q < NQ; ++q)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double w_detJ = W[q] / (J11*J22) - (J21*J12);
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient version
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
// First compute entries of R = MJ
const double M11 = coeff(i11, q, e);
const double M12 = (!symmetric) ? coeff(i12, q, e) : coeff(1, q, e);
const double M21 = (!symmetric) ? coeff(i21, q, e) : M12;
const double M22 = (!symmetric) ? coeff(i22, q, e) : coeff(2, q, e);
const double J11 = J(qx,qy,0,0,e);
const double J21 = J(qx,qy,1,0,e);
const double J12 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double w_detJ = W(qx,qy) / (J11*J22) - (J21*J12);
const double R11 = M11*J11 + M12*J21;
const double R12 = M11*J12 + M12*J22;
const double R21 = M21*J11 + M22*J21;
const double R22 = M21*J12 + M22*J22;
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient version
{
// First compute entries of R = MJ
const double M11 = coeff(i11,qx,qy,e);
const double M12 = (!symmetric) ? coeff(i12,qx,qy,e) : coeff(1,qx,qy,e);
const double M21 = (!symmetric) ? coeff(i21,qx,qy,e) : M12;
const double M22 = (!symmetric) ? coeff(i22,qx,qy,e) : coeff(2,qx,qy,e);
// Now set y to J^{-1} R
y(i11,q,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
y(i12,q,e) = w_detJ * ( J22*R12 - J12*R22); // 1,2
y(i21,q,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
y(i22,q,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
}
else if (coeffDim == 2) // Vector coefficient version
{
const double D1 = coeff(0, q, e);
const double D2 = coeff(1, q, e);
const double R11 = D1*J11;
const double R12 = D1*J12;
const double R21 = D2*J21;
const double R22 = D2*J22;
y(i11,q,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
y(i12,q,e) = w_detJ * ( J22*R12 - J12*R22); // 1,2
y(i21,q,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
y(i22,q,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
const double R11 = M11*J11 + M12*J21;
const double R12 = M11*J12 + M12*J22;
const double R21 = M21*J11 + M22*J21;
const double R22 = M21*J12 + M22*J22;
// Now set y to J^{-1} R
y(i11,qx,qy,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
y(i12,qx,qy,e) = w_detJ * ( J22*R12 - J12*R22); // 1,2
y(i21,qx,qy,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
y(i22,qx,qy,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
}
else if (coeffDim == 2) // Vector coefficient version
{
const double D1 = coeff(0,qx,qy,e);
const double D2 = coeff(1,qx,qy,e);
const double R11 = D1*J11;
const double R12 = D1*J12;
const double R21 = D2*J21;
const double R22 = D2*J22;
y(i11,qx,qy,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
y(i12,qx,qy,e) = w_detJ * ( J22*R12 - J12*R22); // 1,2
y(i21,qx,qy,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
y(i22,qx,qy,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
}
}
}
});
@@ -856,13 +855,13 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
if (trial_curl && test_curl && dim == 3)
{
PAHcurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
PADiffusionSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (trial_curl && test_curl && dim == 2)
{
PAHcurlSetup2D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
PADiffusionSetup2D<2>(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (trial_div && test_div && dim == 3)
{
@@ -1109,13 +1108,13 @@ void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
// Use the same setup functions as VectorFEMassIntegrator.
if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, 1, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
PADiffusionSetup3D(quad1D, 1, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, 1, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
PADiffusionSetup2D<2>(quad1D, 1, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
+40 -13
View File
@@ -38,11 +38,11 @@ double FunctionCoefficient::Eval(ElementTransformation & T,
if (Function)
{
return ((*Function)(transip));
return Function(transip);
}
else
{
return (*TDFunction)(transip, GetTime());
return TDFunction(transip, GetTime());
}
}
@@ -112,11 +112,11 @@ void VectorFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
V.SetSize(vdim);
if (Function)
{
(*Function)(transip, V);
Function(transip, V);
}
else
{
(*TDFunction)(transip, GetTime(), V);
TDFunction(transip, GetTime(), V);
}
if (Q)
{
@@ -301,18 +301,45 @@ void MatrixFunctionCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
K.SetSize(height, width);
if (Function)
if (symmetric) // Use SymmFunction
{
(*Function)(transip, K);
}
else if (TDFunction)
{
(*TDFunction)(transip, GetTime(), K);
MFEM_VERIFY(height == width && SymmFunction,
"MatrixFunctionCoefficient is not symmetric");
Vector Ksym((width * (width + 1)) / 2); // 1x1: 1, 2x2: 3, 3x3: 6
SymmFunction(transip, Ksym);
// Copy upper triangular values from Ksym to the full matrix K
int os = 0;
for (int i=0; i<height; ++i)
{
for (int j=i; j<width; ++j)
{
const double Kij = Ksym[j - i + os];
K(i,j) = Kij;
if (j != i) { K(j,i) = Kij; }
}
os += width - i;
}
}
else
{
K = mat;
if (Function)
{
Function(transip, K);
}
else if (TDFunction)
{
TDFunction(transip, GetTime(), K);
}
else
{
K = mat;
}
}
if (Q)
{
K *= Q->Eval(T, ip, GetTime());
@@ -323,7 +350,7 @@ void MatrixFunctionCoefficient::EvalSymmetric(Vector &K,
ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_VERIFY(symmetric && height == width && height < 4 && SymmFunction,
MFEM_VERIFY(symmetric && height == width && SymmFunction,
"MatrixFunctionCoefficient is not symmetric");
double x[3];
@@ -335,7 +362,7 @@ void MatrixFunctionCoefficient::EvalSymmetric(Vector &K,
if (SymmFunction)
{
(*SymmFunction)(transip, K);
SymmFunction(transip, K);
}
if (Q)
+81 -87
View File
@@ -12,6 +12,8 @@
#ifndef MFEM_COEFFICIENT
#define MFEM_COEFFICIENT
#include <functional>
#include "../config/config.hpp"
#include "../linalg/linalg.hpp"
#include "intrules.hpp"
@@ -123,28 +125,25 @@ public:
const IntegrationPoint &ip);
};
/// A general C-function coefficient
/// A general function coefficient
class FunctionCoefficient : public Coefficient
{
protected:
double (*Function)(const Vector &);
double (*TDFunction)(const Vector &, double);
std::function<double(const Vector &)> Function;
std::function<double(const Vector &, double)> TDFunction;
public:
/// Define a time-independent coefficient from a pointer to a C-function
FunctionCoefficient(double (*f)(const Vector &))
{
Function = f;
TDFunction = NULL;
}
/// Define a time-independent coefficient from a std function
/** \param F time-independent std::function */
FunctionCoefficient(std::function<double(const Vector &)> F)
: Function(std::move(F))
{ }
/// Define a time-dependent coefficient from a pointer to a C-function
FunctionCoefficient(double (*tdf)(const Vector &, double))
{
Function = NULL;
TDFunction = tdf;
}
/// Define a time-dependent coefficient from a std function
/** \param TDF time-dependent function */
FunctionCoefficient(std::function<double(const Vector &, double)> TDF)
: TDFunction(std::move(TDF))
{ }
/// (DEPRECATED) Define a time-independent coefficient from a C-function
/** @deprecated Use the method where the C-function, @a f, uses a const
@@ -405,33 +404,34 @@ public:
const Vector& GetVec() { return vec; }
};
/// A general C-function vector coefficient
/// A general vector function coefficient
class VectorFunctionCoefficient : public VectorCoefficient
{
private:
void (*Function)(const Vector &, Vector &);
void (*TDFunction)(const Vector &, double, Vector &);
std::function<void(const Vector &, Vector &)> Function;
std::function<void(const Vector &, double, Vector &)> TDFunction;
Coefficient *Q;
public:
/// Construct a time-independent vector coefficient from a C-function
VectorFunctionCoefficient(int dim, void (*F)(const Vector &, Vector &),
Coefficient *q = NULL)
: VectorCoefficient(dim), Q(q)
{
Function = F;
TDFunction = NULL;
}
/// Construct a time-dependent vector coefficient from a C-function
/// Define a time-independent vector coefficient from a std function
/** \param dim - the size of the vector
\param F - time-independent function
\param q - optional scalar Coefficient to scale the vector coefficient */
VectorFunctionCoefficient(int dim,
void (*TDF)(const Vector &, double, Vector &),
Coefficient *q = NULL)
: VectorCoefficient(dim), Q(q)
{
Function = NULL;
TDFunction = TDF;
}
std::function<void(const Vector &, Vector &)> F,
Coefficient *q = nullptr)
: VectorCoefficient(dim), Function(std::move(F)), Q(q)
{ }
/// Define a time-dependent vector coefficient from a std function
/** \param dim - the size of the vector
\param TDF - time-dependent function
\param q - optional scalar Coefficient to scale the vector coefficient */
VectorFunctionCoefficient(int dim,
std::function<void(const Vector &, double, Vector &)> TDF,
Coefficient *q = nullptr)
: VectorCoefficient(dim), TDFunction(std::move(TDF)), Q(q)
{ }
using VectorCoefficient::Eval;
/// Evaluate the vector coefficient at @a ip.
@@ -721,7 +721,6 @@ public:
/// For backward compatibility get the width of the matrix.
int GetVDim() const { return width; }
void SetSymmetric(bool s) { symmetric = s; }
bool IsSymmetric() const { return symmetric; }
/** @brief Evaluate the matrix coefficient in the element described by @a T
@@ -762,61 +761,56 @@ public:
/** @brief A matrix coefficient with an optional scalar coefficient multiplier
\a q. The matrix function can either be represented by a C-function or a
constant matrix provided when constructing this object. */
\a q. The matrix function can either be represented by a std function or
a constant matrix provided when constructing this object. */
class MatrixFunctionCoefficient : public MatrixCoefficient
{
private:
void (*Function)(const Vector &, DenseMatrix &);
void (*SymmFunction)(const Vector &, Vector &);
void (*TDFunction)(const Vector &, double, DenseMatrix &);
std::function<void(const Vector &, DenseMatrix &)> Function;
std::function<void(const Vector &, Vector &)> SymmFunction;
std::function<void(const Vector &, double, DenseMatrix &)> TDFunction;
Coefficient *Q;
DenseMatrix mat;
public:
/// Construct a square matrix coefficient from a C-function without time
/// dependence.
MatrixFunctionCoefficient(int dim, void (*F)(const Vector &, DenseMatrix &),
Coefficient *q = NULL)
: MatrixCoefficient(dim), Q(q)
{
Function = F;
TDFunction = NULL;
mat.SetSize(0);
}
/// Construct a constant matrix coefficient times a scalar Coefficient
MatrixFunctionCoefficient(const DenseMatrix &m, Coefficient &q)
: MatrixCoefficient(m.Height(), m.Width()), Q(&q)
{
Function = NULL;
TDFunction = NULL;
mat = m;
}
/// Construct a square matrix coefficient from a C-function with
/// time-dependence.
/// Define a time-independent square matrix coefficient from a std function
/** \param dim - the size of the matrix
\param F - time-independent function
\param q - optional scalar Coefficient to scale the matrix coefficient */
MatrixFunctionCoefficient(int dim,
void (*TDF)(const Vector &, double, DenseMatrix &),
Coefficient *q = NULL)
: MatrixCoefficient(dim), Q(q)
{
Function = NULL;
TDFunction = TDF;
mat.SetSize(0);
}
std::function<void(const Vector &, DenseMatrix &)> F,
Coefficient *q = nullptr)
: MatrixCoefficient(dim), Function(std::move(F)), Q(q), mat(0)
{ }
/// Construct a symmetric square matrix coefficient from a C-function
/// defining a vector function used by EvalSymmetric
MatrixFunctionCoefficient(int dim, void (*F)(const Vector &, Vector &),
/// Define a constant matrix coefficient times a scalar Coefficient
/** \param m - constant matrix
\param q - optional scalar Coefficient to scale the matrix coefficient */
MatrixFunctionCoefficient(const DenseMatrix &m, Coefficient &q)
: MatrixCoefficient(m.Height(), m.Width()), Q(&q), mat(m)
{ }
/// Define a time-dependent square matrix coefficient from a std function
/** \param dim - the size of the matrix
\param TDF - time-dependent function
\param q - optional scalar Coefficient to scale the matrix coefficient */
MatrixFunctionCoefficient(int dim,
std::function<void(const Vector &, double, DenseMatrix &)> TDF,
Coefficient *q = nullptr)
: MatrixCoefficient(dim), TDFunction(std::move(TDF)), Q(q)
{ }
/** @brief Define a time-independent symmetric square matrix coefficient from
a std function */
/** \param dim - the size of the matrix
\param SymmF - function used in EvalSymmetric
\param q - optional scalar Coefficient to scale the matrix coefficient */
MatrixFunctionCoefficient(int dim,
std::function<void(const Vector &, Vector &)> SymmF,
Coefficient *q = NULL)
: MatrixCoefficient(dim, true), Q(q)
{
SymmFunction = F;
Function = NULL;
TDFunction = NULL;
mat.SetSize(0);
}
: MatrixCoefficient(dim, true), SymmFunction(std::move(SymmF)), Q(q), mat(0)
{ }
/// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
@@ -889,7 +883,7 @@ public:
/// Coefficients based on sums, products, or other functions of coefficients.
///@{
/** Scalar coefficient defined as the linear combination of two scalar
/** @brief Scalar coefficient defined as the linear combination of two scalar
coefficients or a scalar and a scalar coefficient */
class SumCoefficient : public Coefficient
{
@@ -946,8 +940,8 @@ public:
}
};
/** Scalar coefficient defined as the product of two scalar coefficients or
a scalar and a scalar coefficient. */
/** @brief Scalar coefficient defined as the product of two scalar coefficients
or a scalar and a scalar coefficient. */
class ProductCoefficient : public Coefficient
{
private:
@@ -985,8 +979,8 @@ public:
{ return ((a == NULL ) ? aConst : a->Eval(T, ip) ) * b->Eval(T, ip); }
};
/** Scalar coefficient defined as the ratio of two scalars where one or both
scalars are scalar coefficients. */
/** @brief Scalar coefficient defined as the ratio of two scalars where one or
both scalars are scalar coefficients. */
class RatioCoefficient : public Coefficient
{
private:
+4 -2
View File
@@ -238,7 +238,8 @@ public:
/// Set the desired assembly level.
/** Valid choices are:
- AssemblyLevel::FULL (default)
- AssemblyLevel::LEGACYFULL (default)
- AssemblyLevel::FULL
- AssemblyLevel::PARTIAL
- AssemblyLevel::ELEMENT
- AssemblyLevel::NONE
@@ -575,7 +576,8 @@ public:
/// Set the desired assembly level.
/** Valid choices are:
- AssemblyLevel::FULL (default)
- AssemblyLevel::LEGACYFULL (default)
- AssemblyLevel::FULL
- AssemblyLevel::PARTIAL
- AssemblyLevel::ELEMENT
- AssemblyLevel::NONE
+1 -1
View File
@@ -908,7 +908,7 @@ void ParaViewDataCollection::Save()
// CELL DATA
out << "<PCellData>\n";
out << "\t<PDataArray type=\"Int32\" Name=\"" << "material"
out << "\t<PDataArray type=\"Int32\" Name=\"" << "attribute"
<< "\" NumberOfComponents=\"1\""
<< " format=\"" << GetDataFormatString() << "\"/>\n";
out << "</PCellData>\n";
+4
View File
@@ -382,6 +382,10 @@ public:
int Error() const { return error; }
/// Reset the error state
void ResetError(int err = NO_ERROR) { error = err; }
#ifdef MFEM_USE_MPI
friend class ParMesh;
#endif
};
+5 -3
View File
@@ -14,6 +14,7 @@
#include "../general/text.hpp"
#include "../general/forall.hpp"
#include "../mesh/mesh_headers.hpp"
#include "../fem/libceed/ceed.hpp"
#include "fem.hpp"
#include <cmath>
@@ -698,7 +699,7 @@ void FiniteElementSpace::BuildConformingInterpolation() const
for (int entity = 1; entity <= 2; entity++)
{
const NCMesh::NCList &list = mesh->ncmesh->GetNCList(entity);
if (!list.masters.size()) { continue; }
if (!list.masters.Size()) { continue; }
Array<int> master_dofs, slave_dofs;
@@ -706,7 +707,7 @@ void FiniteElementSpace::BuildConformingInterpolation() const
DenseMatrix I;
// loop through all master edges/faces, constrain their slave edges/faces
for (unsigned mi = 0; mi < list.masters.size(); mi++)
for (int mi = 0; mi < list.masters.Size(); mi++)
{
const NCMesh::Master &master = list.masters[mi];
@@ -730,7 +731,7 @@ void FiniteElementSpace::BuildConformingInterpolation() const
GetEntityDofs(entity, slave.index, slave_dofs, master.Geom());
if (!slave_dofs.Size()) { continue; }
slave.OrientedPointMatrix(T.GetPointMat());
list.OrientedPointMatrix(slave, T.GetPointMat());
fe->GetLocalInterpolation(T, I);
// make each slave DOF dependent on all master DOFs
@@ -2160,6 +2161,7 @@ void FiniteElementSpace::Destroy()
delete [] bdofs;
delete [] fdofs;
}
RemoveCeedBasisAndRestriction(this);
}
void FiniteElementSpace::GetTransferOperator(
+1 -1
View File
@@ -68,7 +68,7 @@ void Hybridization::ConstructC()
{
const int dim = pmesh->Dimension();
const NCMesh::NCList &shared = pmesh->pncmesh->GetSharedList(dim-1);
num_shared_slave_faces = (HYPRE_Int)shared.slaves.size();
num_shared_slave_faces = (HYPRE_Int) shared.slaves.Size();
MPI_Allreduce(&num_shared_slave_faces, &glob_num_shared_slave_faces, 1,
HYPRE_MPI_INT, MPI_SUM, pmesh->GetComm());
MFEM_ASSERT(glob_num_shared_slave_faces%2 == 0, "");
+505 -365
View File
File diff suppressed because it is too large Load Diff
+157 -93
View File
@@ -14,68 +14,29 @@
#include "../../config/config.hpp"
#ifdef MFEM_USE_CEED
#include "../../general/device.hpp"
#include "../../linalg/vector.hpp"
#ifdef MFEM_USE_CEED
#include <ceed.h>
#include <ceed-hash.h>
#endif
#include <tuple>
#include <unordered_map>
namespace mfem
{
class Mesh;
class FiniteElementSpace;
class GridFunction;
class IntegrationRule;
class Coefficient;
// Hash table for CeedBasis
using CeedBasisKey =
std::tuple<const FiniteElementSpace*, const IntegrationRule*, int, int, int>;
struct CeedBasisHash
{
std::size_t operator()(const CeedBasisKey& k) const
{
return CeedHashCombine(CeedHashCombine(CeedHashInt(
reinterpret_cast<CeedHash64_t>(std::get<0>(k))),
CeedHashInt(
reinterpret_cast<CeedHash64_t>(std::get<1>(k)))),
CeedHashCombine(CeedHashCombine(CeedHashInt(std::get<2>(k)),
CeedHashInt(std::get<3>(k))),
CeedHashInt(std::get<4>(k))));
}
};
using CeedBasisMap =
std::unordered_map<const CeedBasisKey, CeedBasis, CeedBasisHash>;
// Hash table for CeedElemRestriction
using CeedRestrKey = std::tuple<const FiniteElementSpace*, int, int, int>;
struct CeedRestrHash
{
std::size_t operator()(const CeedRestrKey& k) const
{
return 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))));
}
};
using CeedRestrMap =
std::unordered_map<const CeedRestrKey, CeedElemRestriction, CeedRestrHash>;
namespace internal
{
extern Ceed ceed; // defined in device.cpp
extern CeedBasisMap basis_map;
extern CeedRestrMap restr_map;
}
#ifdef MFEM_USE_CEED
/// A structure used to pass additional data to f_build_diff and f_apply_diff
struct BuildContext { CeedInt dim, space_dim; CeedScalar coeff; };
struct BuildContext { CeedInt dim, space_dim, vdim; CeedScalar coeff; };
enum class CeedCoeff { Const, Grid };
enum class CeedCoeff { Const, Grid, Quad };
struct CeedConstCoeff
{
@@ -90,8 +51,17 @@ struct CeedGridCoeff
CeedVector coeffVector;
};
struct CeedQuadCoeff
{
Vector coeff;
CeedElemRestriction restr;
CeedVector coeffVector;
};
#endif
struct CeedData
{
#ifdef MFEM_USE_CEED
CeedOperator build_oper, oper;
CeedBasis basis, mesh_basis;
CeedElemRestriction restr, mesh_restr, restr_i, mesh_restr_i;
@@ -104,39 +74,51 @@ struct CeedData
CeedVector u, v;
CeedData()
: build_oper(nullptr), oper(nullptr), basis(nullptr), mesh_basis(nullptr),
restr(nullptr), mesh_restr(nullptr), restr_i(nullptr), mesh_restr_i(nullptr),
apply_qfunc(nullptr), build_qfunc(nullptr), node_coords(nullptr),
rho(nullptr), coeff(nullptr), build_ctx(nullptr) { }
~CeedData()
{
CeedOperatorDestroy(&build_oper);
CeedOperatorDestroy(&oper);
CeedElemRestrictionDestroy(&restr_i);
CeedElemRestrictionDestroy(&mesh_restr_i);
CeedQFunctionDestroy(&apply_qfunc);
CeedQFunctionDestroy(&build_qfunc);
CeedQFunctionContextDestroy(&build_ctx);
CeedVectorDestroy(&node_coords);
CeedVectorDestroy(&rho);
if (coeff_type==CeedCoeff::Grid)
if (coeff_type==CeedCoeff::Const)
{
CeedGridCoeff* c = (CeedGridCoeff*)coeff;
delete static_cast<CeedConstCoeff*>(coeff);
}
else if (coeff_type==CeedCoeff::Grid)
{
CeedGridCoeff* c = static_cast<CeedGridCoeff*>(coeff);
CeedVectorDestroy(&c->coeffVector);
delete c;
}
else
else if (coeff_type==CeedCoeff::Quad)
{
delete (CeedConstCoeff*)coeff;
CeedQuadCoeff* c = static_cast<CeedQuadCoeff*>(coeff);
CeedVectorDestroy(&c->coeffVector);
delete c;
}
CeedVectorDestroy(&u);
CeedVectorDestroy(&v);
}
#endif
};
/** This structure contains the data to assemble a PA operator with libCEED.
See libceed/mass.cpp or libceed/diffusion.cpp for examples. */
struct CeedPAOperator
{
#ifdef MFEM_USE_CEED
/** The finite element space for the trial and test functions. */
const FiniteElementSpace &fes;
/** The Integration Rule to use to compote the operator. */
/** The Integration Rule to use to compute the operator. */
const IntegrationRule &ir;
/** The number of quadrature data at each quadrature point. */
int qdatasize;
@@ -147,11 +129,11 @@ struct CeedPAOperator
std::string const_func;
/** The Qfunction to build the quadrature data with constant coefficient. */
CeedQFunctionUser const_qf;
/** The name of the Qfunction to build the quadrature data with grid function
coefficient. */
std::string grid_func;
/** The Qfunction to build the quad. data with grid function coefficient. */
CeedQFunctionUser grid_qf;
/** The name of the Qfunction to build the quadrature data with a coefficient
evaluated at quadrature points. */
std::string quad_func;
/** The Qfunction to build the quad. data with a coefficient. */
CeedQFunctionUser quad_qf;
/** The name of the Qfunction to apply the operator. */
std::string apply_func;
/** The Qfunction to apply the operator. */
@@ -162,11 +144,84 @@ struct CeedPAOperator
/** The evaluation mode to apply to the test function ( CEED_EVAL_INTERP,
CEED_EVAL_GRAD, etc.)*/
CeedEvalMode test_op;
#endif
};
struct CeedMFOperator
{
#ifdef MFEM_USE_CEED
/** The finite element space for the trial and test functions. */
const FiniteElementSpace &fes;
/** The Integration Rule to use to compote the operator. */
const IntegrationRule &ir;
/** The path to the header containing the functions for libCEED. */
std::string header;
/** The name of the Qfunction to apply the quadrature data with a constant
coefficient.*/
std::string const_func;
/** The Qfunction to apply the quadrature data with constant coefficient. */
CeedQFunctionUser const_qf;
/** The name of the Qfunction to apply the quadrature data with a coefficient
evaluated at quadrature point. */
std::string quad_func;
/** The Qfunction to apply the quad. data with a coefficient evaluated at
quadrature point. */
CeedQFunctionUser quad_qf;
/** The evaluation mode to apply to the trial function (CEED_EVAL_INTERP,
CEED_EVAL_GRAD, etc.) */
CeedEvalMode trial_op;
/** The evaluation mode to apply to the test function ( CEED_EVAL_INTERP,
CEED_EVAL_GRAD, etc.)*/
CeedEvalMode test_op;
#endif
};
/** @brief Identifies the type of coefficient of the Integrator to initialize
accordingly the CeedData. */
void InitCeedCoeff(Coefficient* Q, CeedData* ptr);
void InitCeedCoeff(Coefficient* Q, Mesh &mesh, const IntegrationRule &ir,
CeedData* ptr);
/** This function initializes an arbitrary linear operator using the partial
assembly decomposition in libCEED. The operator details are described by the
struct CEEDPAOperator input. */
void CeedPAAssemble(const CeedPAOperator& op,
CeedData& ceedData);
/** This function initializes an arbitrary linear operator using a fully matrix
free decomposition. The operator details are described by the
struct CEEDPAOperator input. */
void CeedMFAssemble(const CeedMFOperator& op,
CeedData& ceedData);
/** @brief Function that applies a libCEED operator. */
void CeedAddMult(const CeedData *ceedDataPtr,
const Vector &x,
Vector &y);
/** @brief Function that assembles a libCEED operator diagonal. */
void CeedAssembleDiagonal(const CeedData *ceedDataPtr,
Vector &diag);
/** @brief Function that determines if a CEED kernel should be used, based on
the current mfem::Device configuration. */
inline bool DeviceCanUseCeed()
{
return Device::Allows(Backend::CEED_MASK);
}
/** @brief Remove from ceed_basis_map and ceed_restr_map the entries associated
with the given @a fes. */
void RemoveCeedBasisAndRestriction(const FiniteElementSpace *fes);
#ifdef MFEM_USE_CEED
/// Initialize a CeedVector from a Vector
void InitCeedVector(const Vector &v, CeedVector &cv);
/// Initialize a strided CeedElemRestriction
void InitCeedStridedRestriction(const FiniteElementSpace &fes,
CeedInt nelem, CeedInt nqpts, CeedInt qdatasize,
const CeedInt *strides,
CeedElemRestriction *restr);
/// Initialize a CeedBasis and a CeedElemRestriction
void InitCeedBasisAndRestriction(const FiniteElementSpace &fes,
@@ -177,43 +232,52 @@ void InitCeedBasisAndRestriction(const FiniteElementSpace &fes,
/// Return the path to the libCEED q-function headers.
const std::string &GetCeedPath();
/** This function initializes an arbitrary linear operator using the partial
assembly decomposition in libCEED. The operator details are described by the
struct CEEDPAOperator input. */
void CeedPAAssemble(const CeedPAOperator& op,
CeedData& ceedData);
/** @brief Function that applies a libCEED PA operator. */
void CeedAddMultPA(const CeedData *ceedDataPtr,
const Vector &x,
Vector &y);
/** @brief Function that assembles a libCEED PA operator diagonal. */
void CeedAssembleDiagonalPA(const CeedData *ceedDataPtr,
Vector &diag);
/** @brief Function that determines if a CEED kernel should be used, based on
the current mfem::Device configuration. */
inline bool DeviceCanUseCeed()
// Hash table for CeedBasis
using CeedBasisKey =
std::tuple<const FiniteElementSpace*, const IntegrationRule*, int, int, int>;
struct CeedBasisHash
{
return Device::Allows(Backend::CEED_CUDA) ||
(Device::Allows(Backend::CEED_CPU) &&
!Device::Allows(Backend::DEVICE_MASK|Backend::OMP_MASK));
std::size_t operator()(const CeedBasisKey& k) const
{
return CeedHashCombine(
CeedHashCombine(
CeedHashInt(reinterpret_cast<CeedHash64_t>(std::get<0>(k))),
CeedHashInt(reinterpret_cast<CeedHash64_t>(std::get<1>(k)))),
CeedHashCombine(
CeedHashCombine(CeedHashInt(std::get<2>(k)),
CeedHashInt(std::get<3>(k))),
CeedHashInt(std::get<4>(k))));
}
};
using CeedBasisMap =
std::unordered_map<const CeedBasisKey, CeedBasis, CeedBasisHash>;
// Hash table for CeedElemRestriction
using CeedRestrKey = std::tuple<const FiniteElementSpace*, int, int, int>;
struct CeedRestrHash
{
std::size_t operator()(const CeedRestrKey& k) const
{
return 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))));
}
};
using CeedRestrMap =
std::unordered_map<const CeedRestrKey, CeedElemRestriction, CeedRestrHash>;
namespace internal
{
extern Ceed ceed; // defined in device.cpp
extern CeedBasisMap basis_map;
extern CeedRestrMap restr_map;
}
} // namespace mfem
#else // MFEM_USE_CEED
namespace mfem
{
inline bool DeviceCanUseCeed()
{
return false;
}
} // namespace mfem
#endif // MFEM_USE_CEED
} // namespace mfem
#endif // MFEM_LIBCEED_HPP
+30 -5
View File
@@ -11,9 +11,10 @@
#include "diffusion.hpp"
#ifdef MFEM_USE_CEED
#include "ceed.hpp"
#ifdef MFEM_USE_CEED
#include "diffusion.h"
#endif
namespace mfem
{
@@ -21,18 +22,42 @@ namespace mfem
void CeedPADiffusionAssemble(const FiniteElementSpace &fes,
const mfem::IntegrationRule &irm, CeedData& ceedData)
{
CeedInt dim = fes.GetMesh()->SpaceDimension();
#ifdef MFEM_USE_CEED
Mesh &mesh = *fes.GetMesh();
// Perform checks for some assumptions made in the Q-functions.
MFEM_VERIFY(mesh.Dimension() == mesh.SpaceDimension(), "case not supported");
MFEM_VERIFY(fes.GetVDim() == 1 || fes.GetVDim() == mesh.Dimension(),
"case not supported");
int dim = mesh.Dimension();
CeedPAOperator diffOp = {fes, irm,
dim * (dim + 1) / 2, "/diffusion.h",
":f_build_diff_const", f_build_diff_const,
":f_build_diff_grid", f_build_diff_grid,
":f_build_diff_quad", f_build_diff_quad,
":f_apply_diff", f_apply_diff,
CEED_EVAL_GRAD,
CEED_EVAL_GRAD
};
CeedPAAssemble(diffOp, ceedData);
#else
mfem_error("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
void CeedMFDiffusionAssemble(const FiniteElementSpace &fes,
const mfem::IntegrationRule &irm, CeedData& ceedData)
{
#ifdef MFEM_USE_CEED
CeedMFOperator diffOp = {fes, irm,
"/diffusion.h",
":f_apply_diff_mf_const", f_apply_diff_mf_const,
":f_apply_diff_mf_quad", f_apply_diff_mf_quad,
CEED_EVAL_GRAD,
CEED_EVAL_GRAD
};
CeedMFAssemble(diffOp, ceedData);
#else
mfem_error("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
} // namespace mfem
#endif // MFEM_USE_CEED
+354 -7
View File
@@ -10,7 +10,7 @@
// CONTRIBUTING.md for details.
/// A structure used to pass additional data to f_build_diff and f_apply_diff
struct BuildContext { CeedInt dim, space_dim; CeedScalar coeff; };
struct BuildContext { CeedInt dim, space_dim, vdim; CeedScalar coeff; };
/// libCEED Q-function for building quadrature data for a diffusion operator
/// with a constant coefficient
@@ -88,8 +88,8 @@ CEED_QFUNCTION(f_build_diff_const)(void *ctx, CeedInt Q,
}
/// libCEED Q-function for building quadrature data for a diffusion operator
/// with a grid function coefficient
CEED_QFUNCTION(f_build_diff_grid)(void *ctx, CeedInt Q,
/// coefficient evaluated at quadrature points.
CEED_QFUNCTION(f_build_diff_quad)(void *ctx, CeedInt Q,
const CeedScalar *const *in,
CeedScalar *const *out)
{
@@ -172,15 +172,15 @@ CEED_QFUNCTION(f_apply_diff)(void *ctx, CeedInt Q,
// in[0], out[0] have shape [dim, nc=1, Q]
const CeedScalar *ug = in[0], *qd = in[1];
CeedScalar *vg = out[0];
switch (bc->dim)
switch (10*bc->dim + bc->vdim)
{
case 1:
case 11:
for (CeedInt i = 0; i < Q; i++)
{
vg[i] = ug[i] * qd[i];
}
break;
case 2:
case 21:
for (CeedInt i = 0; i < Q; i++)
{
const CeedScalar ug0 = ug[i + Q * 0];
@@ -189,7 +189,23 @@ CEED_QFUNCTION(f_apply_diff)(void *ctx, CeedInt Q,
vg[i + Q * 1] = qd[i + Q * 1] * ug0 + qd[i + Q * 2] * ug1;
}
break;
case 3:
case 22:
for (CeedInt i = 0; i < Q; i++)
{
const CeedScalar qd00 = qd[i + Q * 0];
const CeedScalar qd01 = qd[i + Q * 1];
const CeedScalar qd10 = qd01;
const CeedScalar qd11 = qd[i + Q * 2];
for (CeedInt c = 0; c < 2; c++)
{
const CeedScalar ug0 = ug[i + Q * (c+2*0)];
const CeedScalar ug1 = ug[i + Q * (c+2*1)];
vg[i + Q * (c+2*0)] = qd00 * ug0 + qd01 * ug1;
vg[i + Q * (c+2*1)] = qd10 * ug0 + qd11 * ug1;
}
}
break;
case 31:
for (CeedInt i = 0; i < Q; i++)
{
const CeedScalar ug0 = ug[i + Q * 0];
@@ -200,6 +216,337 @@ CEED_QFUNCTION(f_apply_diff)(void *ctx, CeedInt Q,
vg[i + Q * 2] = qd[i + Q * 2] * ug0 + qd[i + Q * 4] * ug1 + qd[i + Q * 5] * ug2;
}
break;
case 33:
for (CeedInt i = 0; i < Q; i++)
{
const CeedScalar qd00 = qd[i + Q * 0];
const CeedScalar qd01 = qd[i + Q * 1];
const CeedScalar qd02 = qd[i + Q * 2];
const CeedScalar qd10 = qd01;
const CeedScalar qd11 = qd[i + Q * 3];
const CeedScalar qd12 = qd[i + Q * 4];
const CeedScalar qd20 = qd02;
const CeedScalar qd21 = qd12;
const CeedScalar qd22 = qd[i + Q * 5];
for (CeedInt c = 0; c < 3; c++)
{
const CeedScalar ug0 = ug[i + Q * (c+3*0)];
const CeedScalar ug1 = ug[i + Q * (c+3*1)];
const CeedScalar ug2 = ug[i + Q * (c+3*2)];
vg[i + Q * (c+3*0)] = qd00 * ug0 + qd01 * ug1 + qd02 * ug2;
vg[i + Q * (c+3*1)] = qd10 * ug0 + qd11 * ug1 + qd12 * ug2;
vg[i + Q * (c+3*2)] = qd20 * ug0 + qd21 * ug1 + qd22 * ug2;
}
}
break;
}
return 0;
}
/// libCEED Q-function for applying a diff operator
CEED_QFUNCTION(f_apply_diff_mf_const)(void *ctx, CeedInt Q,
const CeedScalar *const *in,
CeedScalar *const *out)
{
BuildContext *bc = (BuildContext*)ctx;
// in[0], out[0] have shape [dim, nc=1, Q]
// in[1] is Jacobians with shape [dim, nc=dim, Q]
// in[2] is quadrature weights, size (Q)
//
// At every quadrature point, compute qw/det(J).adj(J).adj(J)^T
const CeedScalar coeff = bc->coeff;
const CeedScalar *ug = in[0], *J = in[1], *qw = in[2];
CeedScalar *vg = out[0];
switch (10 * bc->dim + bc->vdim)
{
case 11:
for (CeedInt i = 0; i < Q; i++)
{
const CeedScalar qd = coeff * qw[i] / J[i];
vg[i] = ug[i] * qd;
}
break;
case 21:
for (CeedInt i = 0; i < Q; i++)
{
// J: 0 2 qd: 0 1 adj(J): J22 -J12
// 1 3 1 2 -J21 J11
const CeedScalar J11 = J[i + Q * 0];
const CeedScalar J21 = J[i + Q * 1];
const CeedScalar J12 = J[i + Q * 2];
const CeedScalar J22 = J[i + Q * 3];
const CeedScalar w = qw[i] / (J11 * J22 - J21 * J12);
CeedScalar qd[3];
qd[0] = coeff * w * (J12 * J12 + J22 * J22);
qd[1] = - coeff * w * (J11 * J12 + J21 * J22);
qd[2] = coeff * w * (J11 * J11 + J21 * J21);
const CeedScalar ug0 = ug[i + Q * 0];
const CeedScalar ug1 = ug[i + Q * 1];
vg[i + Q * 0] = qd[0] * ug0 + qd[1] * ug1;
vg[i + Q * 1] = qd[1] * ug0 + qd[2] * ug1;
}
break;
case 22:
for (CeedInt i = 0; i < Q; i++)
{
// J: 0 2 qd: 0 1 adj(J): J22 -J12
// 1 3 1 2 -J21 J11
const CeedScalar J11 = J[i + Q * 0];
const CeedScalar J21 = J[i + Q * 1];
const CeedScalar J12 = J[i + Q * 2];
const CeedScalar J22 = J[i + Q * 3];
const CeedScalar w = qw[i] / (J11 * J22 - J21 * J12);
CeedScalar qd[3];
qd[0] = coeff * w * (J12 * J12 + J22 * J22);
qd[1] = - coeff * w * (J11 * J12 + J21 * J22);
qd[2] = coeff * w * (J11 * J11 + J21 * J21);
for (CeedInt c = 0; c < 2; c++)
{
const CeedScalar ug0 = ug[i + Q * (c+2*0)];
const CeedScalar ug1 = ug[i + Q * (c+2*1)];
vg[i + Q * (c+2*0)] = qd[0] * ug0 + qd[1] * ug1;
vg[i + Q * (c+2*1)] = qd[1] * ug0 + qd[2] * ug1;
}
}
break;
case 31:
for (CeedInt i = 0; i < Q; i++)
{
// J: 0 3 6 qd: 0 1 2
// 1 4 7 1 3 4
// 2 5 8 2 4 5
const CeedScalar J11 = J[i + Q * 0];
const CeedScalar J21 = J[i + Q * 1];
const CeedScalar J31 = J[i + Q * 2];
const CeedScalar J12 = J[i + Q * 3];
const CeedScalar J22 = J[i + Q * 4];
const CeedScalar J32 = J[i + Q * 5];
const CeedScalar J13 = J[i + Q * 6];
const CeedScalar J23 = J[i + Q * 7];
const CeedScalar J33 = J[i + Q * 8];
const CeedScalar A11 = J22 * J33 - J23 * J32;
const CeedScalar A12 = J13 * J32 - J12 * J33;
const CeedScalar A13 = J12 * J23 - J13 * J22;
const CeedScalar A21 = J23 * J31 - J21 * J33;
const CeedScalar A22 = J11 * J33 - J13 * J31;
const CeedScalar A23 = J13 * J21 - J11 * J23;
const CeedScalar A31 = J21 * J32 - J22 * J31;
const CeedScalar A32 = J12 * J31 - J11 * J32;
const CeedScalar A33 = J11 * J22 - J12 * J21;
const CeedScalar w = qw[i] / (J11 * A11 + J21 * A12 + J31 * A13);
CeedScalar qd[6];
qd[0] = coeff * w * (A11 * A11 + A12 * A12 + A13 * A13);
qd[1] = coeff * w * (A11 * A21 + A12 * A22 + A13 * A23);
qd[2] = coeff * w * (A11 * A31 + A12 * A32 + A13 * A33);
qd[3] = coeff * w * (A21 * A21 + A22 * A22 + A23 * A23);
qd[4] = coeff * w * (A21 * A31 + A22 * A32 + A23 * A33);
qd[5] = coeff * w * (A31 * A31 + A32 * A32 + A33 * A33);
const CeedScalar ug0 = ug[i + Q * 0];
const CeedScalar ug1 = ug[i + Q * 1];
const CeedScalar ug2 = ug[i + Q * 2];
vg[i + Q * 0] = qd[0] * ug0 + qd[1] * ug1 + qd[2] * ug2;
vg[i + Q * 1] = qd[1] * ug0 + qd[3] * ug1 + qd[4] * ug2;
vg[i + Q * 2] = qd[2] * ug0 + qd[4] * ug1 + qd[5] * ug2;
}
break;
case 33:
for (CeedInt i = 0; i < Q; i++)
{
// J: 0 3 6 qd: 0 1 2
// 1 4 7 1 3 4
// 2 5 8 2 4 5
const CeedScalar J11 = J[i + Q * 0];
const CeedScalar J21 = J[i + Q * 1];
const CeedScalar J31 = J[i + Q * 2];
const CeedScalar J12 = J[i + Q * 3];
const CeedScalar J22 = J[i + Q * 4];
const CeedScalar J32 = J[i + Q * 5];
const CeedScalar J13 = J[i + Q * 6];
const CeedScalar J23 = J[i + Q * 7];
const CeedScalar J33 = J[i + Q * 8];
const CeedScalar A11 = J22 * J33 - J23 * J32;
const CeedScalar A12 = J13 * J32 - J12 * J33;
const CeedScalar A13 = J12 * J23 - J13 * J22;
const CeedScalar A21 = J23 * J31 - J21 * J33;
const CeedScalar A22 = J11 * J33 - J13 * J31;
const CeedScalar A23 = J13 * J21 - J11 * J23;
const CeedScalar A31 = J21 * J32 - J22 * J31;
const CeedScalar A32 = J12 * J31 - J11 * J32;
const CeedScalar A33 = J11 * J22 - J12 * J21;
const CeedScalar w = qw[i] / (J11 * A11 + J21 * A12 + J31 * A13);
CeedScalar qd[6];
qd[0] = coeff * w * (A11 * A11 + A12 * A12 + A13 * A13);
qd[1] = coeff * w * (A11 * A21 + A12 * A22 + A13 * A23);
qd[2] = coeff * w * (A11 * A31 + A12 * A32 + A13 * A33);
qd[3] = coeff * w * (A21 * A21 + A22 * A22 + A23 * A23);
qd[4] = coeff * w * (A21 * A31 + A22 * A32 + A23 * A33);
qd[5] = coeff * w * (A31 * A31 + A32 * A32 + A33 * A33);
for (CeedInt c = 0; c < 3; c++)
{
const CeedScalar ug0 = ug[i + Q * (c+3*0)];
const CeedScalar ug1 = ug[i + Q * (c+3*1)];
const CeedScalar ug2 = ug[i + Q * (c+3*2)];
vg[i + Q * (c+3*0)] = qd[0] * ug0 + qd[1] * ug1 + qd[2] * ug2;
vg[i + Q * (c+3*1)] = qd[1] * ug0 + qd[3] * ug1 + qd[4] * ug2;
vg[i + Q * (c+3*2)] = qd[2] * ug0 + qd[4] * ug1 + qd[5] * ug2;
}
}
break;
}
return 0;
}
CEED_QFUNCTION(f_apply_diff_mf_quad)(void *ctx, CeedInt Q,
const CeedScalar *const *in,
CeedScalar *const *out)
{
BuildContext *bc = (BuildContext*)ctx;
// in[0], out[0] have shape [dim, nc=1, Q]
// in[1] is Jacobians with shape [dim, nc=dim, Q]
// in[2] is quadrature weights, size (Q)
//
// At every quadrature point, compute qw/det(J).adj(J).adj(J)^T
const CeedScalar *c = in[0], *ug = in[1], *J = in[2], *qw = in[3];
CeedScalar *vg = out[0];
switch (10 * bc->dim + bc->vdim)
{
case 11:
for (CeedInt i = 0; i < Q; i++)
{
const CeedScalar qd = c[i] * qw[i] / J[i];
vg[i] = ug[i] * qd;
}
break;
case 21:
for (CeedInt i = 0; i < Q; i++)
{
// J: 0 2 qd: 0 1 adj(J): J22 -J12
// 1 3 1 2 -J21 J11
const CeedScalar J11 = J[i + Q * 0];
const CeedScalar J21 = J[i + Q * 1];
const CeedScalar J12 = J[i + Q * 2];
const CeedScalar J22 = J[i + Q * 3];
const CeedScalar w = qw[i] / (J11 * J22 - J21 * J12);
CeedScalar qd[3];
const CeedScalar coeff = c[i];
qd[0] = coeff * w * (J12 * J12 + J22 * J22);
qd[1] = - coeff * w * (J11 * J12 + J21 * J22);
qd[2] = coeff * w * (J11 * J11 + J21 * J21);
const CeedScalar ug0 = ug[i + Q * 0];
const CeedScalar ug1 = ug[i + Q * 1];
vg[i + Q * 0] = qd[0] * ug0 + qd[1] * ug1;
vg[i + Q * 1] = qd[1] * ug0 + qd[2] * ug1;
}
break;
case 22:
for (CeedInt i = 0; i < Q; i++)
{
// J: 0 2 qd: 0 1 adj(J): J22 -J12
// 1 3 1 2 -J21 J11
const CeedScalar J11 = J[i + Q * 0];
const CeedScalar J21 = J[i + Q * 1];
const CeedScalar J12 = J[i + Q * 2];
const CeedScalar J22 = J[i + Q * 3];
const CeedScalar w = qw[i] / (J11 * J22 - J21 * J12);
CeedScalar qd[3];
const CeedScalar coeff = c[i];
qd[0] = coeff * w * (J12 * J12 + J22 * J22);
qd[1] = - coeff * w * (J11 * J12 + J21 * J22);
qd[2] = coeff * w * (J11 * J11 + J21 * J21);
for (CeedInt c = 0; c < 2; c++)
{
const CeedScalar ug0 = ug[i + Q * (c+2*0)];
const CeedScalar ug1 = ug[i + Q * (c+2*1)];
vg[i + Q * (c+2*0)] = qd[0] * ug0 + qd[1] * ug1;
vg[i + Q * (c+2*1)] = qd[1] * ug0 + qd[2] * ug1;
}
}
break;
case 31:
for (CeedInt i = 0; i < Q; i++)
{
// J: 0 3 6 qd: 0 1 2
// 1 4 7 1 3 4
// 2 5 8 2 4 5
const CeedScalar J11 = J[i + Q * 0];
const CeedScalar J21 = J[i + Q * 1];
const CeedScalar J31 = J[i + Q * 2];
const CeedScalar J12 = J[i + Q * 3];
const CeedScalar J22 = J[i + Q * 4];
const CeedScalar J32 = J[i + Q * 5];
const CeedScalar J13 = J[i + Q * 6];
const CeedScalar J23 = J[i + Q * 7];
const CeedScalar J33 = J[i + Q * 8];
const CeedScalar A11 = J22 * J33 - J23 * J32;
const CeedScalar A12 = J13 * J32 - J12 * J33;
const CeedScalar A13 = J12 * J23 - J13 * J22;
const CeedScalar A21 = J23 * J31 - J21 * J33;
const CeedScalar A22 = J11 * J33 - J13 * J31;
const CeedScalar A23 = J13 * J21 - J11 * J23;
const CeedScalar A31 = J21 * J32 - J22 * J31;
const CeedScalar A32 = J12 * J31 - J11 * J32;
const CeedScalar A33 = J11 * J22 - J12 * J21;
const CeedScalar w = qw[i] / (J11 * A11 + J21 * A12 + J31 * A13);
CeedScalar qd[6];
const CeedScalar coeff = c[i];
qd[0] = coeff * w * (A11 * A11 + A12 * A12 + A13 * A13);
qd[1] = coeff * w * (A11 * A21 + A12 * A22 + A13 * A23);
qd[2] = coeff * w * (A11 * A31 + A12 * A32 + A13 * A33);
qd[3] = coeff * w * (A21 * A21 + A22 * A22 + A23 * A23);
qd[4] = coeff * w * (A21 * A31 + A22 * A32 + A23 * A33);
qd[5] = coeff * w * (A31 * A31 + A32 * A32 + A33 * A33);
const CeedScalar ug0 = ug[i + Q * 0];
const CeedScalar ug1 = ug[i + Q * 1];
const CeedScalar ug2 = ug[i + Q * 2];
vg[i + Q * 0] = qd[0] * ug0 + qd[1] * ug1 + qd[2] * ug2;
vg[i + Q * 1] = qd[1] * ug0 + qd[3] * ug1 + qd[4] * ug2;
vg[i + Q * 2] = qd[2] * ug0 + qd[4] * ug1 + qd[5] * ug2;
}
break;
case 33:
for (CeedInt i = 0; i < Q; i++)
{
// J: 0 3 6 qd: 0 1 2
// 1 4 7 1 3 4
// 2 5 8 2 4 5
const CeedScalar J11 = J[i + Q * 0];
const CeedScalar J21 = J[i + Q * 1];
const CeedScalar J31 = J[i + Q * 2];
const CeedScalar J12 = J[i + Q * 3];
const CeedScalar J22 = J[i + Q * 4];
const CeedScalar J32 = J[i + Q * 5];
const CeedScalar J13 = J[i + Q * 6];
const CeedScalar J23 = J[i + Q * 7];
const CeedScalar J33 = J[i + Q * 8];
const CeedScalar A11 = J22 * J33 - J23 * J32;
const CeedScalar A12 = J13 * J32 - J12 * J33;
const CeedScalar A13 = J12 * J23 - J13 * J22;
const CeedScalar A21 = J23 * J31 - J21 * J33;
const CeedScalar A22 = J11 * J33 - J13 * J31;
const CeedScalar A23 = J13 * J21 - J11 * J23;
const CeedScalar A31 = J21 * J32 - J22 * J31;
const CeedScalar A32 = J12 * J31 - J11 * J32;
const CeedScalar A33 = J11 * J22 - J12 * J21;
const CeedScalar w = qw[i] / (J11 * A11 + J21 * A12 + J31 * A13);
CeedScalar qd[6];
const CeedScalar coeff = c[i];
qd[0] = coeff * w * (A11 * A11 + A12 * A12 + A13 * A13);
qd[1] = coeff * w * (A11 * A21 + A12 * A22 + A13 * A23);
qd[2] = coeff * w * (A11 * A31 + A12 * A32 + A13 * A33);
qd[3] = coeff * w * (A21 * A21 + A22 * A22 + A23 * A23);
qd[4] = coeff * w * (A21 * A31 + A22 * A32 + A23 * A33);
qd[5] = coeff * w * (A31 * A31 + A32 * A32 + A33 * A33);
for (CeedInt c = 0; c < 3; c++)
{
const CeedScalar ug0 = ug[i + Q * (c+3*0)];
const CeedScalar ug1 = ug[i + Q * (c+3*1)];
const CeedScalar ug2 = ug[i + Q * (c+3*2)];
vg[i + Q * (c+3*0)] = qd[0] * ug0 + qd[1] * ug1 + qd[2] * ug2;
vg[i + Q * (c+3*1)] = qd[1] * ug0 + qd[3] * ug1 + qd[4] * ug2;
vg[i + Q * (c+3*2)] = qd[2] * ug0 + qd[4] * ug1 + qd[5] * ug2;
}
}
break;
}
return 0;
}
+4 -3
View File
@@ -14,7 +14,6 @@
#include "ceed.hpp"
#ifdef MFEM_USE_CEED
#include "../fespace.hpp"
namespace mfem
@@ -25,8 +24,10 @@ void CeedPADiffusionAssemble(const FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
CeedData& ceedData);
void CeedMFDiffusionAssemble(const FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
CeedData& ceedData);
}
#endif // MFEM_USE_CEED
#endif // MFEM_LIBCEED_DIFF_HPP
+28 -3
View File
@@ -11,9 +11,10 @@
#include "mass.hpp"
#ifdef MFEM_USE_CEED
#include "ceed.hpp"
#ifdef MFEM_USE_CEED
#include "mass.h"
#endif
namespace mfem
{
@@ -21,17 +22,41 @@ namespace mfem
void CeedPAMassAssemble(const FiniteElementSpace &fes,
const mfem::IntegrationRule &irm, CeedData& ceedData)
{
#ifdef MFEM_USE_CEED
Mesh &mesh = *fes.GetMesh();
// Perform checks for some assumptions made in the Q-functions.
MFEM_VERIFY(mesh.Dimension() == mesh.SpaceDimension(), "case not supported");
MFEM_VERIFY(1 <= fes.GetVDim() && fes.GetVDim() <= 3, "case not supported");
CeedPAOperator massOp = {fes, irm,
1, "/mass.h",
":f_build_mass_const", f_build_mass_const,
":f_build_mass_grid", f_build_mass_grid,
":f_build_mass_quad", f_build_mass_quad,
":f_apply_mass", f_apply_mass,
CEED_EVAL_INTERP,
CEED_EVAL_INTERP
};
CeedPAAssemble(massOp, ceedData);
#else
mfem_error("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
void CeedMFMassAssemble(const FiniteElementSpace &fes,
const mfem::IntegrationRule &irm, CeedData& ceedData)
{
#ifdef MFEM_USE_CEED
CeedMFOperator massOp = {fes, irm,
"/mass.h",
":f_apply_mass_mf_const", f_apply_mass_mf_const,
":f_apply_mass_mf_quad", f_apply_mass_mf_quad,
CEED_EVAL_INTERP,
CEED_EVAL_INTERP
};
CeedMFAssemble(massOp, ceedData);
#else
mfem_error("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
} // namespace mfem
#endif // MFEM_USE_CEED
+162 -5
View File
@@ -10,7 +10,7 @@
// CONTRIBUTING.md for details.
/// A structure used to pass additional data to f_build_diff and f_apply_diff
struct BuildContext { CeedInt dim, space_dim; CeedScalar coeff; };
struct BuildContext { CeedInt dim, space_dim, vdim; CeedScalar coeff; };
/// libCEED Q-function for building quadrature data for a mass operator with a
/// constant coefficient
@@ -56,8 +56,8 @@ CEED_QFUNCTION(f_build_mass_const)(void *ctx, CeedInt Q,
}
/// libCEED Q-function for building quadrature data for a mass operator with a
/// grid function coefficient
CEED_QFUNCTION(f_build_mass_grid)(void *ctx, CeedInt Q,
/// coefficient evaluated at quadrature points.
CEED_QFUNCTION(f_build_mass_quad)(void *ctx, CeedInt Q,
const CeedScalar *const *in,
CeedScalar *const *out)
{
@@ -102,11 +102,168 @@ CEED_QFUNCTION(f_apply_mass)(void *ctx, CeedInt Q,
const CeedScalar *const *in,
CeedScalar *const *out)
{
BuildContext *bc = (BuildContext *)ctx;
const CeedScalar *u = in[0], *w = in[1];
CeedScalar *v = out[0];
for (CeedInt i=0; i<Q; i++)
switch (bc->vdim)
{
v[i] = w[i] * u[i];
case 1:
for (CeedInt i=0; i<Q; i++)
{
v[i] = w[i] * u[i];
}
break;
case 2:
for (CeedInt i=0; i<Q; i++)
{
const CeedScalar W = w[i];
for (CeedInt c = 0; c < 2; c++)
{
v[i+c*Q] = W * u[i+c*Q];
}
}
break;
case 3:
for (CeedInt i=0; i<Q; i++)
{
const CeedScalar W = w[i];
for (CeedInt c = 0; c < 3; c++)
{
v[i+c*Q] = W * u[i+c*Q];
}
}
break;
}
return 0;
}
/// libCEED Q-function for applying a diff operator
CEED_QFUNCTION(f_apply_mass_mf_const)(void *ctx, CeedInt Q,
const CeedScalar *const *in, CeedScalar *const *out)
{
BuildContext *bc = (BuildContext*)ctx;
const CeedScalar coeff = bc->coeff;
const CeedScalar *u = in[0], *J = in[1], *qw = in[2];
CeedScalar *v = out[0];
switch (10 * bc->dim + bc->vdim)
{
case 11:
for (CeedInt i = 0; i < Q; i++)
{
const CeedScalar rho = coeff * qw[i] / J[i];
v[i] = rho * u[i];
}
break;
case 21:
for (CeedInt i = 0; i < Q; i++)
{
const CeedScalar rho = coeff * (J[i+Q*0]*J[i+Q*3] - J[i+Q*1]*J[i+Q*2]) * qw[i];
v[i] = rho * u[i];
}
break;
case 22:
for (CeedInt i=0; i<Q; i++)
{
// 0 2
// 1 3
const CeedScalar rho = coeff * (J[i+Q*0]*J[i+Q*3] - J[i+Q*1]*J[i+Q*2]) * qw[i];
for (CeedInt c = 0; c < 2; c++)
{
v[i+c*Q] = rho * u[i+c*Q];
}
}
break;
case 31:
for (CeedInt i = 0; i < Q; i++)
{
const CeedScalar rho = (J[i+Q*0]*(J[i+Q*4]*J[i+Q*8] - J[i+Q*5]*J[i+Q*7]) -
J[i+Q*1]*(J[i+Q*3]*J[i+Q*8] - J[i+Q*5]*J[i+Q*6]) +
J[i+Q*2]*(J[i+Q*3]*J[i+Q*7] - J[i+Q*4]*J[i+Q*6])) * coeff * qw[i];
v[i] = rho * u[i];
}
break;
case 33:
for (CeedInt i=0; i<Q; i++)
{
// 0 3 6
// 1 4 7
// 2 5 8
const CeedScalar rho = (J[i+Q*0]*(J[i+Q*4]*J[i+Q*8] - J[i+Q*5]*J[i+Q*7]) -
J[i+Q*1]*(J[i+Q*3]*J[i+Q*8] - J[i+Q*5]*J[i+Q*6]) +
J[i+Q*2]*(J[i+Q*3]*J[i+Q*7] - J[i+Q*4]*J[i+Q*6])) * coeff * qw[i];
for (CeedInt c = 0; c < 3; c++)
{
v[i+c*Q] = rho * u[i+c*Q];
}
}
break;
}
return 0;
}
CEED_QFUNCTION(f_apply_mass_mf_quad)(void *ctx, CeedInt Q,
const CeedScalar *const *in, CeedScalar *const *out)
{
BuildContext *bc = (BuildContext*)ctx;
const CeedScalar *c = in[0], *u = in[1], *J = in[2], *qw = in[3];
CeedScalar *v = out[0];
switch (10 * bc->dim + bc->vdim)
{
case 11:
for (CeedInt i=0; i<Q; i++)
{
const CeedScalar rho = c[i] * J[i] * qw[i];
v[i] = rho * u[i];
}
break;
case 21:
for (CeedInt i=0; i<Q; i++)
{
// 0 2
// 1 3
const CeedScalar rho = c[i] * (J[i+Q*0]*J[i+Q*3] - J[i+Q*1]*J[i+Q*2]) * qw[i];
v[i] = rho * u[i];
}
break;
case 22:
for (CeedInt i=0; i<Q; i++)
{
// 0 2
// 1 3
const CeedScalar rho = c[i] * (J[i+Q*0]*J[i+Q*3] - J[i+Q*1]*J[i+Q*2]) * qw[i];
for (CeedInt c = 0; c < 2; c++)
{
v[i+c*Q] = rho * u[i+c*Q];
}
}
break;
case 31:
for (CeedInt i=0; i<Q; i++)
{
// 0 3 6
// 1 4 7
// 2 5 8
const CeedScalar rho = (J[i+Q*0]*(J[i+Q*4]*J[i+Q*8] - J[i+Q*5]*J[i+Q*7]) -
J[i+Q*1]*(J[i+Q*3]*J[i+Q*8] - J[i+Q*5]*J[i+Q*6]) +
J[i+Q*2]*(J[i+Q*3]*J[i+Q*7] - J[i+Q*4]*J[i+Q*6])) * c[i] * qw[i];
v[i] = rho * u[i];
}
break;
case 33:
for (CeedInt i=0; i<Q; i++)
{
// 0 3 6
// 1 4 7
// 2 5 8
const CeedScalar rho = (J[i+Q*0]*(J[i+Q*4]*J[i+Q*8] - J[i+Q*5]*J[i+Q*7]) -
J[i+Q*1]*(J[i+Q*3]*J[i+Q*8] - J[i+Q*5]*J[i+Q*6]) +
J[i+Q*2]*(J[i+Q*3]*J[i+Q*7] - J[i+Q*4]*J[i+Q*6])) * c[i] * qw[i];
for (CeedInt c = 0; c < 3; c++)
{
v[i+c*Q] = rho * u[i+c*Q];
}
}
break;
}
return 0;
}
+4 -3
View File
@@ -14,7 +14,6 @@
#include "ceed.hpp"
#ifdef MFEM_USE_CEED
#include "../fespace.hpp"
namespace mfem
@@ -25,8 +24,10 @@ void CeedPAMassAssemble(const FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
CeedData& ceedData);
void CeedMFMassAssemble(const FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
CeedData& ceedData);
}
#endif // MFEM_USE_CEED
#endif // MFEM_LIBCEED_MASS_HPP
+126 -75
View File
@@ -131,8 +131,8 @@ void NonlinearForm::Mult(const Vector &x, Vector &y) const
const Vector &px = Prolongate(x);
if (P) { aux2.SetSize(P->Height()); }
// If we are in parallel, ParNonLinearForm::Mult uses the aux2 vector.
// In serial, place the result directly in y.
// If we are in parallel, ParNonLinearForm::Mult uses the aux2 vector. In
// serial, place the result directly in y.
Vector &py = P ? aux2 : y;
if (ext)
@@ -456,11 +456,12 @@ void BlockNonlinearForm::SetSpaces(Array<FiniteElementSpace *> &f)
for (int j=0; j<Grads.NumCols(); ++j)
{
delete Grads(i,j);
delete cGrads(i,j);
}
}
for (int i = 0; i < ess_vdofs.Size(); ++i)
for (int i = 0; i < ess_tdofs.Size(); ++i)
{
delete ess_vdofs[i];
delete ess_tdofs[i];
}
height = 0;
@@ -486,10 +487,33 @@ void BlockNonlinearForm::SetSpaces(Array<FiniteElementSpace *> &f)
Grads.SetSize(fes.Size(), fes.Size());
Grads = NULL;
ess_vdofs.SetSize(fes.Size());
cGrads.SetSize(fes.Size(), fes.Size());
cGrads = NULL;
P.SetSize(fes.Size());
cP.SetSize(fes.Size());
ess_tdofs.SetSize(fes.Size());
for (int s = 0; s < fes.Size(); ++s)
{
ess_vdofs[s] = new Array<int>;
// Retrieve prolongation matrix for each FE space
P[s] = fes[s]->GetProlongationMatrix();
cP[s] = dynamic_cast<const SparseMatrix *>(P[s]);
// If the P Operator exists and its type is not SparseMatrix, this
// indicates the Operator is part of parallel run.
if (P[s] && !cP[s])
{
is_serial = false;
}
// If the P Operator exists and its type is SparseMatrix, this indicates
// the Operator is serial but needs prolongation on assembly.
if (cP[s])
{
needs_prolongation = true;
}
ess_tdofs[s] = new Array<int>;
}
}
@@ -506,45 +530,18 @@ void BlockNonlinearForm::AddBdrFaceIntegrator(BlockNonlinearFormIntegrator *nfi,
bfnfi_marker.Append(&bdr_attr_marker);
}
void BlockNonlinearForm::SetEssentialBC(const
Array<Array<int> *>&bdr_attr_is_ess,
Array<Vector *> &rhs)
void BlockNonlinearForm::SetEssentialBC(
const Array<Array<int> *> &bdr_attr_is_ess, Array<Vector *> &rhs)
{
int i, j, vsize, nv;
for (int s=0; s<fes.Size(); ++s)
for (int s = 0; s < fes.Size(); ++s)
{
// First, set u variables
vsize = fes[s]->GetVSize();
Array<int> vdof_marker(vsize);
ess_tdofs[s]->SetSize(ess_tdofs.Size());
// virtual call, works in parallel too
fes[s]->GetEssentialVDofs(*(bdr_attr_is_ess[s]), vdof_marker);
nv = 0;
for (i = 0; i < vsize; ++i)
{
if (vdof_marker[i])
{
nv++;
}
}
ess_vdofs[s]->SetSize(nv);
for (i = j = 0; i < vsize; ++i)
{
if (vdof_marker[i])
{
(*ess_vdofs[s])[j++] = i;
}
}
fes[s]->GetEssentialTrueDofs(*bdr_attr_is_ess[s], *ess_tdofs[s]);
if (rhs[s])
{
for (i = 0; i < nv; ++i)
{
(*rhs[s])[(*ess_vdofs[s])[i]] = 0.0;
}
rhs[s]->SetSubVector(*ess_tdofs[s], 0.0);
}
}
}
@@ -757,18 +754,52 @@ void BlockNonlinearForm::MultBlocked(const BlockVector &bx,
delete vdofs[s];
delete el_y[s];
delete el_x[s];
by.GetBlock(s).SetSubVector(*ess_vdofs[s], 0.0);
}
}
const BlockVector &BlockNonlinearForm::Prolongate(const BlockVector &bx) const
{
MFEM_VERIFY(bx.Size() == Width(), "invalid input BlockVector size");
if (needs_prolongation)
{
aux1.Update(block_offsets);
for (int s = 0; s < fes.Size(); s++)
{
P[s]->Mult(bx.GetBlock(s), aux1.GetBlock(s));
}
return aux1;
}
return bx;
}
void BlockNonlinearForm::Mult(const Vector &x, Vector &y) const
{
xs.Update(x.GetData(), block_offsets);
ys.Update(y.GetData(), block_offsets);
BlockVector bx(x.GetData(), block_trueOffsets);
BlockVector by(y.GetData(), block_trueOffsets);
const BlockVector &pbx = Prolongate(bx);
if (needs_prolongation)
{
aux2.Update(block_offsets);
}
BlockVector &pby = needs_prolongation ? aux2 : by;
xs.Update(pbx.GetData(), block_offsets);
ys.Update(pby.GetData(), block_offsets);
MultBlocked(xs, ys);
for (int s = 0; s < fes.Size(); s++)
{
if (cP[s])
{
cP[s]->MultTranspose(pby.GetBlock(s), by.GetBlock(s));
}
by.GetBlock(s).SetSubVector(*ess_tdofs[s], 0.0);
}
}
Operator &BlockNonlinearForm::GetGradientBlocked(const BlockVector &bx) const
void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx) const
{
const int skip_zeros = 0;
Array<Array<int> *> vdofs(fes.Size());
@@ -780,13 +811,6 @@ Operator &BlockNonlinearForm::GetGradientBlocked(const BlockVector &bx) const
Array<const FiniteElement *>fe2(fes.Size());
ElementTransformation * T;
if (BlockGrad != NULL)
{
delete BlockGrad;
}
BlockGrad = new BlockOperator(block_offsets);
for (int i=0; i<fes.Size(); ++i)
{
el_x_const[i] = el_x[i] = new Vector();
@@ -951,44 +975,70 @@ Operator &BlockNonlinearForm::GetGradientBlocked(const BlockVector &bx) const
}
}
for (int s=0; s<fes.Size(); ++s)
{
for (int i = 0; i < ess_vdofs[s]->Size(); ++i)
{
for (int j=0; j<fes.Size(); ++j)
{
if (s==j)
{
Grads(s,s)->EliminateRowCol((*ess_vdofs[s])[i], Matrix::DIAG_ONE);
}
else
{
Grads(s,j)->EliminateRow((*ess_vdofs[s])[i]);
Grads(j,s)->EliminateCol((*ess_vdofs[s])[i]);
}
}
}
}
for (int i=0; i<fes.Size(); ++i)
{
for (int j=0; j<fes.Size(); ++j)
{
BlockGrad->SetBlock(i,j,Grads(i,j));
delete elmats(i,j);
}
delete vdofs2[i];
delete vdofs[i];
delete el_x[i];
}
return *BlockGrad;
}
Operator &BlockNonlinearForm::GetGradient(const Vector &x) const
{
xs.Update(x.GetData(), block_offsets);
return GetGradientBlocked(xs);
BlockVector bx(x.GetData(), block_trueOffsets);
const BlockVector &pbx = Prolongate(bx);
ComputeGradientBlocked(pbx);
Array2D<SparseMatrix *> mGrads(fes.Size(), fes.Size());
mGrads = Grads;
if (needs_prolongation)
{
for (int s1 = 0; s1 < fes.Size(); ++s1)
{
for (int s2 = 0; s2 < fes.Size(); ++s2)
{
delete cGrads(s1, s2);
cGrads(s1, s2) = RAP(*cP[s1], *Grads(s1, s2), *cP[s2]);
mGrads(s1, s2) = cGrads(s1, s2);
}
}
}
for (int s = 0; s < fes.Size(); ++s)
{
for (int i = 0; i < ess_tdofs[s]->Size(); ++i)
{
for (int j = 0; j < fes.Size(); ++j)
{
if (s == j)
{
mGrads(s, s)->EliminateRowCol((*ess_tdofs[s])[i],
Matrix::DIAG_ONE);
}
else
{
mGrads(s, j)->EliminateRow((*ess_tdofs[s])[i]);
mGrads(j, s)->EliminateCol((*ess_tdofs[s])[i]);
}
}
}
}
delete BlockGrad;
BlockGrad = new BlockOperator(block_trueOffsets);
for (int i = 0; i < fes.Size(); ++i)
{
for (int j = 0; j < fes.Size(); ++j)
{
BlockGrad->SetBlock(i, j, mGrads(i, j));
}
}
return *BlockGrad;
}
BlockNonlinearForm::~BlockNonlinearForm()
@@ -999,8 +1049,9 @@ BlockNonlinearForm::~BlockNonlinearForm()
for (int j=0; j<fes.Size(); ++j)
{
delete Grads(i,j);
delete cGrads(i,j);
}
delete ess_vdofs[i];
delete ess_tdofs[i];
}
for (int i = 0; i < dnfi.Size(); ++i)
+25 -4
View File
@@ -199,24 +199,41 @@ protected:
GridFunction-like block-vector data (e.g. in parallel). */
mutable BlockVector xs, ys;
mutable Array2D<SparseMatrix*> Grads;
mutable Array2D<SparseMatrix*> Grads, cGrads;
mutable BlockOperator *BlockGrad;
// A list of the offsets
Array<int> block_offsets;
Array<int> block_trueOffsets;
// Essential vdofs: one list of vdofs for each space in 'fes'
Array<Array<int> *> ess_vdofs;
// Array of Arrays of tdofs for each space in 'fes'
Array<Array<int> *> ess_tdofs;
/// Array of pointers to the prolongation matrix of fes, may be NULL
Array<const Operator *> P;
/// Array of results of dynamic-casting P to SparseMatrix pointer
Array<const SparseMatrix *> cP;
/// Indicator if the Operator is part of a parallel run
bool is_serial = true;
/// Indicator if the Operator needs prolongation on assembly
bool needs_prolongation = false;
mutable BlockVector aux1, aux2;
const BlockVector &Prolongate(const BlockVector &bx) const;
/// Specialized version of GetEnergy() for BlockVectors
double GetEnergyBlocked(const BlockVector &bx) const;
/// Specialized version of Mult() for BlockVector%s
/// Block L-Vector to Block L-Vector
void MultBlocked(const BlockVector &bx, BlockVector &by) const;
/// Specialized version of GetGradient() for BlockVector
Operator &GetGradientBlocked(const BlockVector &bx) const;
void ComputeGradientBlocked(const BlockVector &bx) const;
public:
/// Construct an empty BlockNonlinearForm. Initialize with SetSpaces().
@@ -261,8 +278,12 @@ public:
virtual double GetEnergy(const Vector &x) const;
/// Method is only called in serial, the parallel version calls MultBlocked
/// directly.
virtual void Mult(const Vector &x, Vector &y) const;
/// Method is only called in serial, the parallel version calls
/// GetGradientBlocked directly.
virtual Operator &GetGradient(const Vector &x) const;
/// Destructor.
+1 -1
View File
@@ -76,7 +76,7 @@ public:
void KeepNbrBlock(bool knb = true) { keep_nbr_block = knb; }
/** @brief Set the operator type id for the parallel matrix/operator when
using AssemblyLevel::FULL. */
using AssemblyLevel::LEGACYFULL. */
/** If using static condensation or hybridization, call this method *after*
enabling it. */
void SetOperatorType(Operator::Type tid)
+6 -6
View File
@@ -1999,13 +1999,13 @@ int ParFiniteElementSpace
for (int entity = 0; entity <= 2; entity++)
{
const NCMesh::NCList &list = pncmesh->GetNCList(entity);
if (!list.masters.size()) { continue; }
if (!list.masters.Size()) { continue; }
IsoparametricTransformation T;
DenseMatrix I;
// process masters that we own or that affect our edges/faces
for (unsigned mi = 0; mi < list.masters.size(); mi++)
for (int mi = 0; mi < list.masters.Size(); mi++)
{
const NCMesh::Master &mf = list.masters[mi];
@@ -2036,7 +2036,7 @@ int ParFiniteElementSpace
GetEntityDofs(entity, sf.index, slave_dofs, mf.Geom());
if (!slave_dofs.Size()) { continue; }
sf.OrientedPointMatrix(T.GetPointMat());
list.OrientedPointMatrix(sf, T.GetPointMat());
fe->GetLocalInterpolation(T, I);
// make each slave DOF dependent on all master DOFs
@@ -2064,12 +2064,12 @@ int ParFiniteElementSpace
{
const NCMesh::NCList &list = pncmesh->GetNCList(entity);
std::size_t lsize[3] =
{ list.conforming.size(), list.masters.size(), list.slaves.size() };
int lsize[3] =
{ list.conforming.Size(), list.masters.Size(), list.slaves.Size() };
for (int l = 0; l < 3; l++)
{
for (std::size_t i = 0; i < lsize[l]; i++)
for (int i = 0; i < lsize[l]; i++)
{
const MeshId &id =
(l == 0) ? list.conforming[i] :
+3
View File
@@ -1093,6 +1093,9 @@ double L2ZZErrorEstimator(BilinearFormIntegrator &flux_integrator,
if (xfes->GetNE())
{
MFEM_VERIFY(smooth_flux_fes.GetFE(0) != NULL,
"Could not obtain FE of smooth flux space.");
if (smooth_flux_fes.GetFE(0)->GetRangeType() == FiniteElement::SCALAR)
{
VectorMassIntegrator *vmass = new VectorMassIntegrator;
+40 -11
View File
@@ -200,23 +200,34 @@ void ParBlockNonlinearForm::SetEssentialBC(const
BlockNonlinearForm::SetEssentialBC(bdr_attr_is_ess, nullarray);
for (int s=0; s<fes.Size(); ++s)
for (int s = 0; s < fes.Size(); ++s)
{
if (rhs[s])
{
ParFiniteElementSpace *pfes = ParFESpace(s);
for (int i=0; i < ess_vdofs[s]->Size(); ++i)
{
int tdof = pfes->GetLocalTDofNumber((*(ess_vdofs[s]))[i]);
if (tdof >= 0)
{
(*rhs[s])(tdof) = 0.0;
}
}
rhs[s]->SetSubVector(*ess_tdofs[s], 0.0);
}
}
}
double ParBlockNonlinearForm::GetEnergy(const Vector &x) const
{
xs_true.Update(x.GetData(), block_trueOffsets);
xs.Update(block_offsets);
for (int s = 0; s < fes.Size(); ++s)
{
fes[s]->GetProlongationMatrix()->Mult(xs_true.GetBlock(s), xs.GetBlock(s));
}
double enloc = BlockNonlinearForm::GetEnergyBlocked(xs);
double englo = 0.0;
MPI_Allreduce(&enloc, &englo, 1, MPI_DOUBLE, MPI_SUM,
ParFESpace(0)->GetComm());
return englo;
}
void ParBlockNonlinearForm::Mult(const Vector &x, Vector &y) const
{
xs_true.Update(x.GetData(), block_trueOffsets);
@@ -241,6 +252,8 @@ void ParBlockNonlinearForm::Mult(const Vector &x, Vector &y) const
{
fes[s]->GetProlongationMatrix()->MultTranspose(
ys.GetBlock(s), ys_true.GetBlock(s));
ys_true.GetBlock(s).SetSubVector(*ess_tdofs[s], 0.0);
}
}
@@ -257,8 +270,18 @@ const BlockOperator & ParBlockNonlinearForm::GetLocalGradient(
xs_true.GetBlock(s), xs.GetBlock(s));
}
BlockNonlinearForm::GetGradientBlocked(xs); // (re)assemble Grad with b.c.
BlockNonlinearForm::ComputeGradientBlocked(xs); // (re)assemble Grad with b.c.
delete BlockGrad;
BlockGrad = new BlockOperator(block_offsets);
for (int i = 0; i < fes.Size(); ++i)
{
for (int j = 0; j < fes.Size(); ++j)
{
BlockGrad->SetBlock(i, j, Grads(i, j));
}
}
return *BlockGrad;
}
@@ -314,6 +337,9 @@ BlockOperator & ParBlockNonlinearForm::GetGradient(const Vector &x) const
pfes[s1]->GetDofOffsets(), Grads(s1,s1));
Ph.ConvertFrom(pfes[s1]->Dof_TrueDof_Matrix());
phBlockGrad(s1,s1)->MakePtAP(dA, Ph);
OperatorHandle Ae;
Ae.EliminateRowsCols(*phBlockGrad(s1,s1), *ess_tdofs[s1]);
}
else
{
@@ -327,6 +353,9 @@ BlockOperator & ParBlockNonlinearForm::GetGradient(const Vector &x) const
Ph.ConvertFrom(pfes[s2]->Dof_TrueDof_Matrix());
phBlockGrad(s1,s2)->MakeRAP(Rh, dA, Ph);
phBlockGrad(s1,s2)->EliminateRows(*ess_tdofs[s1]);
phBlockGrad(s1,s2)->EliminateCols(*ess_tdofs[s2]);
}
pBlockGrad->SetBlock(s1, s2, phBlockGrad(s1,s2)->Ptr());
+4
View File
@@ -82,6 +82,9 @@ protected:
mutable BlockOperator *pBlockGrad;
public:
/// Computes the energy of the system
virtual double GetEnergy(const Vector &x) const;
/// Construct an empty ParBlockNonlinearForm. Initialize with SetParSpaces().
ParBlockNonlinearForm() : pBlockGrad(NULL) { }
@@ -103,6 +106,7 @@ public:
virtual void SetEssentialBC(const Array<Array<int> *>&bdr_attr_is_ess,
Array<Vector *> &rhs);
/// Block T-Vector to Block T-Vector
virtual void Mult(const Vector &x, Vector &y) const;
/// Return the local block gradient matrix for the given true-dof vector x
+4 -4
View File
@@ -298,7 +298,7 @@ void adios2stream::Print(const Mesh& mesh, const mode print_mode)
element_nvertices = static_cast<size_t>(mesh.elements[0]->GetNVertices());
}
SafeDefineVariable<uint64_t>(io, "connectivity", {}, {}, {nelements, element_nvertices+1});
SafeDefineVariable<int32_t>(io, "material", {}, {}, {nelements});
SafeDefineVariable<int32_t>(io, "attribute", {}, {}, {nelements});
// vertices
SafeDefineVariable<uint32_t>(io,"NumOfVertices", {adios2::LocalValueDim});
@@ -351,7 +351,7 @@ void adios2stream::Print(const Mesh& mesh, const mode print_mode)
(var_connectivity);
adios2::Variable<int32_t> var_element_attribute =
io.InquireVariable<int32_t>("material");
io.InquireVariable<int32_t>("attribute");
adios2::Variable<int32_t>::Span span_element_attribute = engine.Put<int32_t>
(var_element_attribute);
@@ -435,7 +435,7 @@ void adios2stream::Print(const Mesh& mesh, const mode print_mode)
engine.Put<uint64_t>(varConnectivity);
adios2::Variable<int32_t> varElementAttribute =
io.InquireVariable<int32_t>("material");
io.InquireVariable<int32_t>("attribute");
// zero-copy access to adios2 buffer to put non-contiguous to contiguous memory
adios2::Variable<int32_t>::Span spanElementAttribute =
engine.Put<int32_t>(varElementAttribute);
@@ -720,7 +720,7 @@ std::string adios2stream::VTKSchema() const noexcept
vtkSchema += R"(
</Points>
<CellData>
<DataArray Name="material" />
<DataArray Name="attribute" />
</CellData>
<Cells>
<DataArray Name="connectivity" />
+2
View File
@@ -411,6 +411,8 @@ public:
inline void operator=(const T &a)
{ array1d = a; }
inline Array2D& operator=(const Array2D &a) = default;
/// Make this Array a reference to 'master'
inline void MakeRef(const Array2D &master)
{ M = master.M; N = master.N; array1d.MakeRef(master.array1d); }
+1
View File
@@ -31,6 +31,7 @@
#endif
#ifdef MFEM_USE_RAJA
#define CAMP_USE_PLATFORM_DEFAULT_STREAM 1
#include "RAJA/RAJA.hpp"
#if defined(RAJA_ENABLE_CUDA) && !defined(MFEM_USE_CUDA)
#error When RAJA is built with CUDA, MFEM_USE_CUDA=YES is required
+28 -3
View File
@@ -11,6 +11,9 @@
#include "forall.hpp"
#include "occa.hpp"
#if defined(MFEM_USE_OCCA) && OCCA_CUDA_ENABLED
#include <occa/modes/cuda/stream.hpp>
#endif
#ifdef MFEM_USE_CEED
#include "../fem/libceed/ceed.hpp"
#endif
@@ -43,7 +46,7 @@ CeedRestrMap ceed_restr_map;
static const Backend::Id backend_list[Backend::NUM_BACKENDS] =
{
Backend::CEED_CUDA, Backend::OCCA_CUDA, Backend::RAJA_CUDA, Backend::CUDA,
Backend::HIP, Backend::DEBUG_DEVICE,
Backend::CEED_HIP, Backend::HIP, Backend::DEBUG_DEVICE,
Backend::OCCA_OMP, Backend::RAJA_OMP, Backend::OMP,
Backend::CEED_CPU, Backend::OCCA_CPU, Backend::RAJA_CPU, Backend::CPU
};
@@ -52,7 +55,7 @@ static const Backend::Id backend_list[Backend::NUM_BACKENDS] =
static const char *backend_name[Backend::NUM_BACKENDS] =
{
"ceed-cuda", "occa-cuda", "raja-cuda", "cuda",
"hip", "debug",
"ceed-hip", "hip", "debug",
"occa-omp", "raja-omp", "omp",
"ceed-cpu", "occa-cpu", "raja-cpu", "cpu"
};
@@ -163,10 +166,12 @@ Device::~Device()
{
CeedBasisDestroy(&entry.second);
}
internal::ceed_basis_map.clear();
for (auto entry : internal::ceed_restr_map)
{
CeedElemRestrictionDestroy(&entry.second);
}
internal::ceed_restr_map.clear();
// Destroy Ceed context
CeedDestroy(&internal::ceed);
#endif
@@ -233,6 +238,10 @@ void Device::Configure(const std::string &device, const int dev)
{
Get().MarkBackend(Backend::CUDA);
}
if (Allows(Backend::CEED_HIP))
{
Get().MarkBackend(Backend::HIP);
}
// Perform setup.
Get().Setup(dev);
@@ -404,6 +413,10 @@ static void OccaDeviceSetup(const int dev)
#if OCCA_CUDA_ENABLED
std::string mode("mode: 'CUDA', device_id : ");
internal::occaDevice.setup(mode.append(1,'0'+dev));
auto def_stream = new occa::cuda::stream(
internal::occaDevice.getModeDevice(),
occa::properties(), (CUstream)0);
internal::occaDevice.setStream(def_stream);
#else
MFEM_ABORT("the OCCA CUDA backend requires OCCA built with CUDA!");
#endif
@@ -449,7 +462,8 @@ static void CeedDeviceSetup(const char* ceed_spec)
CeedInit(ceed_spec, &internal::ceed);
const char *ceed_backend;
CeedGetResource(internal::ceed, &ceed_backend);
if (strcmp(ceed_spec, ceed_backend) && strcmp(ceed_spec, "/cpu/self"))
if (strcmp(ceed_spec, ceed_backend) && strcmp(ceed_spec, "/cpu/self") &&
strcmp(ceed_spec, "/gpu/hip"))
{
mfem::out << std::endl << "WARNING!!!\n"
"libCEED is not using the requested backend!!!\n"
@@ -518,6 +532,17 @@ void Device::Setup(const int device)
CeedDeviceSetup(device_option);
}
}
if (Allows(Backend::CEED_HIP))
{
if (!device_option)
{
CeedDeviceSetup("/gpu/hip");
}
else
{
CeedDeviceSetup(device_option);
}
}
if (Allows(Backend::DEBUG_DEVICE)) { ngpu = 1; }
}
+8 -5
View File
@@ -59,14 +59,17 @@ struct Backend
CEED_CPU = 1 << 10,
/** @brief [device] CEED CUDA backend working together with the CUDA
backend. Enabled when MFEM_USE_CEED = YES and MFEM_USE_CUDA = YES.
NOTE: The current default libCEED GPU backend is non-deterministic! */
NOTE: The current default libCEED CUDA backend is non-deterministic! */
CEED_CUDA = 1 << 11,
/** @brief [device] CEED HIP backend working together with the HIP
backend. Enabled when MFEM_USE_CEED = YES and MFEM_USE_HIP = YES. */
CEED_HIP = 1 << 12,
/** @brief [device] Debug backend: host memory is READ/WRITE protected
while a device is in use. It allows to test the "device" code-path
(using separate host/device memory pools and host <-> device
transfers) without any GPU hardware. As 'DEBUG' is sometimes used
as a macro, `_DEVICE` has been added to avoid conflicts. */
DEBUG_DEVICE = 1 << 12
DEBUG_DEVICE = 1 << 13
};
/** @brief Additional useful constants. For example, the *_MASK constants can
@@ -74,18 +77,18 @@ struct Backend
enum
{
/// Number of backends: from (1 << 0) to (1 << (NUM_BACKENDS-1)).
NUM_BACKENDS = 13,
NUM_BACKENDS = 14,
/// Biwise-OR of all CPU backends
CPU_MASK = CPU | RAJA_CPU | OCCA_CPU | CEED_CPU,
/// Biwise-OR of all CUDA backends
CUDA_MASK = CUDA | RAJA_CUDA | OCCA_CUDA | CEED_CUDA,
/// Biwise-OR of all HIP backends
HIP_MASK = HIP,
HIP_MASK = HIP | CEED_HIP,
/// Biwise-OR of all OpenMP backends
OMP_MASK = OMP | RAJA_OMP | OCCA_OMP,
/// Bitwise-OR of all CEED backends
CEED_MASK = CEED_CPU | CEED_CUDA,
CEED_MASK = CEED_CPU | CEED_CUDA | CEED_HIP,
/// Biwise-OR of all device backends
DEVICE_MASK = CUDA_MASK | HIP_MASK | DEBUG_DEVICE,
+24
View File
@@ -15,6 +15,9 @@
#include "../config/config.hpp"
#include <iomanip>
#include <sstream>
#ifdef MFEM_USE_HIP
#include <hip/hip_runtime.h>
#endif
namespace mfem
{
@@ -144,6 +147,22 @@ void mfem_warning(const char *msg = NULL);
"invalid index " #i << " = " << (i) << \
", valid range is [" << (imin) << ',' << (imax) << ')')
// Additional abort functions for HIP
#if defined(MFEM_USE_HIP)
template<typename T>
__host__ void abort_msg(T & msg)
{
MFEM_ABORT(msg);
}
template<typename T>
__device__ void abort_msg(T & msg)
{
abort();
}
#endif
// Abort inside a device kernel
#if defined(__CUDA_ARCH__)
#define MFEM_ABORT_KERNEL(msg) \
@@ -151,6 +170,11 @@ void mfem_warning(const char *msg = NULL);
printf(msg); \
asm("trap;"); \
}
#elif defined(MFEM_USE_HIP)
#define MFEM_ABORT_KERNEL(msg) \
{ \
abort_msg(msg); \
}
#else
#define MFEM_ABORT_KERNEL(msg) MFEM_ABORT(msg)
#endif
+9
View File
@@ -115,6 +115,12 @@ const char *GetConfigStr()
#ifdef MFEM_USE_STRUMPACK
"MFEM_USE_STRUMPACK\n"
#endif
#ifdef MFEM_USE_GINKGO
"MFEM_USE_GINKGO\n"
#endif
#ifdef MFEM_USE_AMGX
"MFEM_USE_AMGX\n"
#endif
#ifdef MFEM_USE_GNUTLS
"MFEM_USE_GNUTLS\n"
#endif
@@ -136,6 +142,9 @@ const char *GetConfigStr()
#ifdef MFEM_USE_PUMI
"MFEM_USE_PUMI\n"
#endif
#ifdef MFEM_USE_HIOP
"MFEM_USE_HIOP\n"
#endif
#ifdef MFEM_USE_CUDA
"MFEM_USE_CUDA\n"
#endif
+15 -11
View File
@@ -57,12 +57,6 @@ if (MFEM_USE_MPI)
list(APPEND HDRS
hypre.hpp
hypre_parcsr.hpp)
if (MFEM_USE_AMGX)
list(APPEND SRCS
amgxsolver.cpp)
list(APPEND HDRS
amgxsolver.hpp)
endif()
if (MFEM_USE_PETSC)
list(APPEND SRCS
petsc.cpp)
@@ -77,11 +71,6 @@ if (MFEM_USE_MPI)
endif()
endif()
if (MFEM_USE_GINKGO)
list(APPEND SRCS ginkgo.cpp)
list(APPEND HDRS ginkgo.hpp)
endif()
if (MFEM_USE_SUNDIALS)
list(APPEND SRCS sundials.cpp)
list(APPEND HDRS sundials.hpp)
@@ -99,11 +88,26 @@ if (MFEM_USE_STRUMPACK)
list(APPEND HDRS strumpack.hpp)
endif()
if (MFEM_USE_GINKGO)
list(APPEND SRCS ginkgo.cpp)
list(APPEND HDRS ginkgo.hpp)
endif()
if (MFEM_USE_AMGX)
list(APPEND SRCS amgxsolver.cpp)
list(APPEND HDRS amgxsolver.hpp)
endif()
if (MFEM_USE_HIOP)
list(APPEND SRCS hiop.cpp)
list(APPEND HDRS hiop.hpp)
endif()
if (MFEM_USE_MKL_CPARDISO)
list(APPEND SRCS cpardiso.cpp)
list(APPEND HDRS cpardiso.hpp)
endif()
convert_filenames_to_full_paths(SRCS)
convert_filenames_to_full_paths(HDRS)
+61 -50
View File
@@ -9,10 +9,15 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
//Reference
//Pi-Yueh Chuang, & Lorena A. Barba (2017).
//AmgXWrapper: An interface between PETSc and the NVIDIA AmgX library. J.
//Open Source Software, 2(16):280, doi:10.21105/joss.00280
// Implementation of the MFEM wrapper for Nvidia's multigrid library, AmgX
//
// This work is partially based on:
//
// Pi-Yueh Chuang and Lorena A. Barba (2017).
// AmgXWrapper: An interface between PETSc and the NVIDIA AmgX library.
// J. Open Source Software, 2(16):280, doi:10.21105/joss.00280
//
// See https://github.com/barbagroup/AmgXWrapper.
#include "../config/config.hpp"
#include "amgxsolver.hpp"
@@ -104,19 +109,18 @@ void AmgXSolver::InitExclusiveGPU(const MPI_Comm &comm)
mfem_error("This AmgXSolver instance has been initialized on this process.");
}
//Note that every MPI rank may talk to a GPU
// Note that every MPI rank may talk to a GPU
mpi_gpu_mode = "mpi-gpu-exclusive";
gpuProc = 0;
//Increment number of AmgX instances
// Increment number of AmgX instances
count++;
MPI_Comm_dup(comm, &gpuWorld);
MPI_Comm_size(gpuWorld, &gpuWorldSize);
MPI_Comm_rank(gpuWorld, &myGpuWorldRank);
//Each rank will only see 1 device
//call it device 0
// Each rank will only see 1 device call it device 0
nDevs = 1, devID = 0;
InitAmgX();
@@ -124,8 +128,8 @@ void AmgXSolver::InitExclusiveGPU(const MPI_Comm &comm)
isInitialized = true;
}
// Intialize for MPI ranks > GPUs, all devices are visible
// to all of the MPI ranks
// Initialize for MPI ranks > GPUs, all devices are visible to all of the MPI
// ranks
void AmgXSolver::InitMPITeams(const MPI_Comm &comm,
const int nDevs)
{
@@ -137,7 +141,7 @@ void AmgXSolver::InitMPITeams(const MPI_Comm &comm,
mpi_gpu_mode = "mpi-teams";
//Increment number of AmgX instances
// Increment number of AmgX instances
count++;
// Get the name of this node
@@ -221,7 +225,7 @@ void AmgXSolver::DefaultParameters(const AMGX_MODE amgxMode_,
" \"interpolator\": \"D2\", \n"
" \"max_row_sum\" : 0.9, \n"
" \"strength_threshold\" : 0.25, \n"
" \"max_iters\": 1, \n"
" \"max_iters\": 2, \n"
" \"scope\": \"amg\", \n"
" \"max_levels\": 100, \n"
" \"cycle\": \"V\", \n"
@@ -267,6 +271,12 @@ void AmgXSolver::InitAmgX()
AMGX_SAFE_CALL(AMGX_initialize_plugins());
AMGX_SAFE_CALL(AMGX_install_signal_handler());
AMGX_SAFE_CALL(AMGX_register_print_callback(
[](const char *msg, int length)->void
{
int irank; MPI_Comm_rank(MPI_COMM_WORLD, &irank);
if (irank == 0) { mfem::out<<msg;} }));
}
MFEM_VERIFY(configSrc != CONFIG_SRC::UNDEFINED,
@@ -392,7 +402,7 @@ void AmgXSolver::SetDeviceIDs(const int nDevs)
void AmgXSolver::GatherArray(const Array<double> &inArr, Array<double> &outArr,
const int mpiTeamSz, const MPI_Comm &mpiTeamComm) const
{
//Calculate number of elements to be collected from each process
// Calculate number of elements to be collected from each process
Array<int> Apart(mpiTeamSz);
int locAsz = inArr.Size();
MPI_Gather(&locAsz, 1, MPI_INT,
@@ -400,7 +410,7 @@ void AmgXSolver::GatherArray(const Array<double> &inArr, Array<double> &outArr,
MPI_Barrier(mpiTeamComm);
//Determine stride for process (to be used by root)
// Determine stride for process (to be used by root)
Array<int> Adisp(mpiTeamSz);
int myid; MPI_Comm_rank(mpiTeamComm, &myid);
if (myid == 0)
@@ -420,7 +430,7 @@ void AmgXSolver::GatherArray(const Array<double> &inArr, Array<double> &outArr,
void AmgXSolver::GatherArray(const Vector &inArr, Vector &outArr,
const int mpiTeamSz, const MPI_Comm &mpiTeamComm) const
{
//Calculate number of elements to be collected from each process
// Calculate number of elements to be collected from each process
Array<int> Apart(mpiTeamSz);
int locAsz = inArr.Size();
MPI_Gather(&locAsz, 1, MPI_INT,
@@ -428,7 +438,7 @@ void AmgXSolver::GatherArray(const Vector &inArr, Vector &outArr,
MPI_Barrier(mpiTeamComm);
//Determine stride for process (to be used by root)
// Determine stride for process (to be used by root)
Array<int> Adisp(mpiTeamSz);
int myid; MPI_Comm_rank(mpiTeamComm, &myid);
if (myid == 0)
@@ -448,7 +458,7 @@ void AmgXSolver::GatherArray(const Vector &inArr, Vector &outArr,
void AmgXSolver::GatherArray(const Array<int> &inArr, Array<int> &outArr,
const int mpiTeamSz, const MPI_Comm &mpiTeamComm) const
{
//Calculate number of elements to be collected from each process
// Calculate number of elements to be collected from each process
Array<int> Apart(mpiTeamSz);
int locAsz = inArr.Size();
MPI_Gather(&locAsz, 1, MPI_INT,
@@ -456,7 +466,7 @@ void AmgXSolver::GatherArray(const Array<int> &inArr, Array<int> &outArr,
MPI_Barrier(mpiTeamComm);
//Determine stride for process (to be used by root)
// Determine stride for process (to be used by root)
Array<int> Adisp(mpiTeamSz);
int myid; MPI_Comm_rank(mpiTeamComm, &myid);
if (myid == 0)
@@ -478,7 +488,7 @@ void AmgXSolver::GatherArray(const Array<int64_t> &inArr,
Array<int64_t> &outArr,
const int mpiTeamSz, const MPI_Comm &mpiTeamComm) const
{
//Calculate number of elements to be collected from each process
// Calculate number of elements to be collected from each process
Array<int> Apart(mpiTeamSz);
int locAsz = inArr.Size();
MPI_Gather(&locAsz, 1, MPI_INT,
@@ -486,7 +496,7 @@ void AmgXSolver::GatherArray(const Array<int64_t> &inArr,
MPI_Barrier(mpiTeamComm);
//Determine stride for process
// Determine stride for process
Array<int> Adisp(mpiTeamSz);
int myid; MPI_Comm_rank(mpiTeamComm, &myid);
if (myid == 0)
@@ -509,14 +519,14 @@ void AmgXSolver::GatherArray(const Vector &inArr, Vector &outArr,
const int mpiTeamSz, const MPI_Comm &mpiTeamComm,
Array<int> &Apart, Array<int> &Adisp) const
{
//Calculate number of elements to be collected from each process
// Calculate number of elements to be collected from each process
int locAsz = inArr.Size();
MPI_Allgather(&locAsz, 1, MPI_INT,
Apart.HostWrite(),1, MPI_INT, mpiTeamComm);
MPI_Barrier(mpiTeamComm);
//Determine stride for process
// Determine stride for process
Adisp[0] = 0;
for (int i=1; i<mpiTeamSz; ++i)
{
@@ -565,7 +575,7 @@ void AmgXSolver::SetMatrix(const SparseMatrix &in_A, const bool update_mat)
#ifdef MFEM_USE_MPI
void AmgXSolver::SetMatrix(const HypreParMatrix &A, const bool update_mat)
{
//Require hypre >= 2.16.
// Require hypre >= 2.16.
#if MFEM_HYPRE_VERSION < 21600
mfem_error("Hypre version 2.16+ is required when using AmgX \n");
#endif
@@ -578,14 +588,14 @@ void AmgXSolver::SetMatrix(const HypreParMatrix &A, const bool update_mat)
Array<double> loc_A(A_csr->data, (int)A_csr->num_nonzeros);
const Array<int> loc_I(A_csr->i, (int)A_csr->num_rows+1);
//Column index must be int64_t so we must promote here
// Column index must be int64_t so we must promote here
Array<int64_t> loc_J((int)A_csr->num_nonzeros);
for (int i=0; i<A_csr->num_nonzeros; ++i)
{
loc_J[i] = A_csr->big_j[i];
}
//Asumes one GPU per MPI rank
// Assumes one GPU per MPI rank
if (mpi_gpu_mode=="mpi-gpu-exclusive")
{
return SetMatrixMPIGPUExclusive(A, loc_A, loc_I, loc_J, update_mat);
@@ -606,7 +616,7 @@ void AmgXSolver::SetMatrixMPIGPUExclusive(const HypreParMatrix &A,
const Array<int64_t> &loc_J,
const bool update_mat)
{
//Create a vector of offsets describing matrix row partitions
// Create a vector of offsets describing matrix row partitions
Array<int64_t> rowPart(gpuWorldSize+1); rowPart = 0.0;
int64_t myStart = A.GetRowStarts()[0];
@@ -655,16 +665,16 @@ void AmgXSolver::SetMatrixMPITeams(const HypreParMatrix &A,
const Array<int64_t> &loc_J,
const bool update_mat)
{
// The following arrays hold the consolidated
// diagonal + off diagonal matrix data
// The following arrays hold the consolidated diagonal + off-diagonal matrix
// data
Array<int> all_I;
Array<int64_t> all_J;
Array<double> all_A;
//Determine array sizes
// Determine array sizes
int J_allsz(0), all_NNZ(0), nDevRows(0);
const int loc_row_len = std::abs(A.RowPart()[1] -
A.RowPart()[0]); //end of row partition
A.RowPart()[0]); // end of row partition
const int loc_Jz_sz = loc_J.Size();
const int loc_A_sz = loc_A.Size();
@@ -692,13 +702,13 @@ void AmgXSolver::SetMatrixMPITeams(const HypreParMatrix &A,
if (myDevWorldRank == 0)
{
// A fix up step is needed for the array holding row data
// to remove extra zeros when consolidating team data.
// A fix up step is needed for the array holding row data to remove extra
// zeros when consolidating team data.
Array<int> z_ind(devWorldSize+1);
int iter = 1;
while (iter < devWorldSize-1)
{
//Determine the indices of zeros in global all_I array
// Determine the indices of zeros in global all_I array
int counter = 0;
z_ind[counter] = counter;
counter++;
@@ -711,15 +721,16 @@ void AmgXSolver::SetMatrixMPITeams(const HypreParMatrix &A,
}
}
z_ind[devWorldSize] = all_I.Size()-1;
//End of determining indices of zeros in global all_I Array
// End of determining indices of zeros in global all_I Array
//Bump all_I
// Bump all_I
for (int idx=z_ind[1]+1; idx < z_ind[2]; idx++)
{
all_I[idx] = all_I[idx-1] + (all_I[idx+1] - all_I[idx]);
}
//Shift array after bump to remove uncesssary values in middle of array
// Shift array after bump to remove unnecessary values in middle of
// array
for (int idx=z_ind[2]; idx < all_I.Size()-1; ++idx)
{
all_I[idx] = all_I[idx+1];
@@ -728,7 +739,7 @@ void AmgXSolver::SetMatrixMPITeams(const HypreParMatrix &A,
}
// LAST TIME THROUGH ARRAY
//Determine the indices of zeros in global row_ptr array
// Determine the indices of zeros in global row_ptr array
int counter = 0;
z_ind[counter] = counter;
counter++;
@@ -742,8 +753,8 @@ void AmgXSolver::SetMatrixMPITeams(const HypreParMatrix &A,
}
z_ind[devWorldSize] = all_I.Size()-1;
//End of determining indices of zeros in global all_I Array
//BUMP all_I one last time
// End of determining indices of zeros in global all_I Array BUMP all_I
// one last time
for (int idx=z_ind[1]+1; idx < all_I.Size()-1; idx++)
{
all_I[idx] = all_I[idx-1] + (all_I[idx+1] - all_I[idx]);
@@ -752,8 +763,8 @@ void AmgXSolver::SetMatrixMPITeams(const HypreParMatrix &A,
local_rows = nDevRows;
}
//Create row partition
mat_local_rows = local_rows; //class copy
// Create row partition
mat_local_rows = local_rows; // class copy
Array<int64_t> rowPart;
if (gpuProc == 0)
{
@@ -764,13 +775,13 @@ void AmgXSolver::SetMatrixMPITeams(const HypreParMatrix &A,
gpuWorld);
MPI_Barrier(gpuWorld);
//Fixup step
// Fixup step
for (int i=1; i<rowPart.Size(); ++i)
{
rowPart[i] += rowPart[i-1];
}
//upload A matrix to AmgX
// Upload A matrix to AmgX
MPI_Barrier(gpuWorld);
int nGlobalRows = A.M();
@@ -793,7 +804,7 @@ void AmgXSolver::SetMatrixMPITeams(const HypreParMatrix &A,
AMGX_solver_setup(solver, AmgXA);
//Bind vectors to A
// Bind vectors to A
AMGX_vector_bind(AmgXP, AmgXA);
AMGX_vector_bind(AmgXRHS, AmgXA);
}
@@ -847,11 +858,11 @@ void AmgXSolver::UpdateOperator(const Operator& op)
void AmgXSolver::Mult(const Vector& B, Vector& X) const
{
//Set intial guess to zero
// Set initial guess to zero
X.UseDevice(true);
X = 0.0;
//Mult for serial, and mpi-exclusive modes
// Mult for serial, and mpi-exclusive modes
if (mpi_gpu_mode != "mpi-teams")
{
AMGX_vector_upload(AmgXP, X.Size(), 1, X.ReadWrite());
@@ -935,7 +946,7 @@ int AmgXSolver::GetNumIterations()
void AmgXSolver::Finalize()
{
//Check instance is initialized
// Check instance is initialized
if (! isInitialized || count < 1)
{
mfem_error("Error in AmgXSolver::Finalize(). \n"
@@ -980,8 +991,8 @@ void AmgXSolver::Finalize()
#endif
}
// re-set necessary variables in case users want to reuse
// the variable of this instance for a new instance
// re-set necessary variables in case users want to reuse the variable of
// this instance for a new instance
#ifdef MFEM_USE_MPI
gpuProc = MPI_UNDEFINED;
if (globalCpuWorld != MPI_COMM_NULL)
@@ -998,5 +1009,5 @@ void AmgXSolver::Finalize()
isInitialized = false;
}
}//mfem namespace
} // mfem namespace
#endif
+75 -100
View File
@@ -29,136 +29,115 @@ namespace mfem
{
/**
MFEM wrapper for Nvidia's multigrid library,
AmgX (https://github.com/NVIDIA/AMGX).
MFEM wrapper for Nvidia's multigrid library, AmgX (github.com/NVIDIA/AMGX)
AmgX requires building MFEM with CUDA, and AMGX
enabled. For distributed memory parallism,
MPI and Hypre (version 16.0+) are also required.
Although CUDA is required for building,
the AmgX wrapper is compatible with
a MFEM CPU device configuration.
AmgX requires building MFEM with CUDA, and AMGX enabled. For distributed
memory parallism, MPI and Hypre (version 16.0+) are also required. Although
CUDA is required for building, the AmgX solver is compatible with a MFEM CPU
device configuration.
The AmgXSolver class is designed to work
as a solver or preconditioner for MFEM existing
solvers. The AmgX solver class may be configured
in one of three ways:
The AmgXSolver class is designed to work as a solver or preconditioner for
existing MFEM solvers. The AmgX solver class may be configured in one of
three ways:
Serial - Takes a SparseMatrix solves
on a single GPU and assumes no MPI
Serial - Takes a SparseMatrix solves on a single GPU and assumes no MPI
communication.
Exclusive GPU - Takes a HypreParMatrix
and assumes each MPI rank is paired with
an Nvidia GPU.
Exclusive GPU - Takes a HypreParMatrix and assumes each MPI rank is paired
with an Nvidia GPU.
MPI Teams - Takes a HypreParMatrix and
enables flexibility between number of MPI
ranks, and GPUs. Specifically, MPI ranks
are grouped with GPUs and a matrix consolidation
step is taken so the MPI root of each team
performs the necessary AmgX library calls.
The solution is then broadcasted to appropriate ranks.
This is particularly useful when configuring MFEM's
device as CPU.
MPI Teams - Takes a HypreParMatrix and enables flexibility between number of
MPI ranks, and GPUs. Specifically, MPI ranks are grouped with GPUs and a
matrix consolidation step is taken so the MPI root of each team performs the
necessary AmgX library calls. The solution is then broadcasted to appropriate
ranks. This is particularly useful when configuring MFEM's device as
CPU. This work is based on the AmgXWrapper of Chuang and Barba. Routines were
adopted and modified for setting up MPI communicators.
Examples 1,1p demonstrate basic usage with
default parameters, while examples under the
amgx folder demonstrate configuring the wrapper
as a solver, preconditioner, configuring and
running with exclusive GPU or MPI teams modes.
Examples 1/1p in the examples/amgx directory demonstrate configuring the
wrapper as a solver and preconditioner, as well as configuring and running
with exclusive GPU or MPI teams modes.
Reference:
Pi-Yueh Chuang, & Lorena A. Barba (2017).
AmgXWrapper: An interface between PETSc and the NVIDIA AmgX library.
J. Open Source Software, 2(16):280, doi:10.21105/joss.00280
This work is partially based on:
*/
Pi-Yueh Chuang and Lorena A. Barba (2017).
AmgXWrapper: An interface between PETSc and the NVIDIA AmgX library.
J. Open Source Software, 2(16):280, doi:10.21105/joss.00280
See https://github.com/barbagroup/AmgXWrapper.
*/
class AmgXSolver : public Solver
{
public:
/**
Flags to configure AmgXSolver
as a solver or preconditioner
*/
/// Flags to configure AmgXSolver as a solver or preconditioner
enum AMGX_MODE {SOLVER, PRECONDITIONER};
/**
Flags to determine whether user solver
settings are defined internally
in the source code or will be read through an
external json file.
Flags to determine whether user solver settings are defined internally in
the source code or will be read through an external JSON file.
*/
enum CONFIG_SRC {INTERNAL, EXTERNAL, UNDEFINED};
AmgXSolver() = default;
/**
Configures AmgX with a default configuration based on the
AmgX mode, and verbosity. Assumes no MPI parallism.
*/
Configures AmgX with a default configuration based on the AmgX mode, and
verbosity. Assumes no MPI parallism.
*/
AmgXSolver(const AMGX_MODE amgxMode_, const bool verbose);
/**
Once the solver configuration has been established through
either the ReadParameters method or the constructor,
InitSerial will initalize the library.
If configuring with constructor, the constructor will
make this call.
Once the solver configuration has been established through either the
ReadParameters method or the constructor, InitSerial will initalize the
library. If configuring with constructor, the constructor will make this
call.
*/
void InitSerial();
#ifdef MFEM_USE_MPI
/**
Configures AmgX with a default configuration based on the
AmgX mode, and verbosity. Pairs each MPI rank with one GPU.
Configures AmgX with a default configuration based on the AmgX mode, and
verbosity. Pairs each MPI rank with one GPU.
*/
AmgXSolver(const MPI_Comm &comm, const AMGX_MODE amgxMode_, const bool verbose);
/**
Configures AmgX with a default configuration based on the
AmgX mode, and verbosity. Creates MPI teams around GPUs
to support MPI ranks > GPUs. Consolidates linear solver data
to avoid multiple ranks sharing GPUs. Requires specifying
number of devices in each compute node.
Configures AmgX with a default configuration based on the AmgX mode, and
verbosity. Creates MPI teams around GPUs to support MPI ranks >
GPUs. Consolidates linear solver data to avoid multiple ranks sharing
GPUs. Requires specifying number of devices in each compute node.
*/
AmgXSolver(const MPI_Comm &comm, const int nDevs,
const AMGX_MODE amgx_Mode_, const bool verbose);
/**
Once the solver configuration has been established,
either through the constructor or the
ReadParameters method, InitSerial will initalize the library.
If configuring with constructor, the constructor will
make this call.
Once the solver configuration has been established, either through the
constructor or the ReadParameters method, InitSerial will initalize the
library. If configuring with constructor, the constructor will make this
call.
*/
void InitExclusiveGPU(const MPI_Comm &comm);
/**
Once the solver configuration has been established,
either through the ReadParameters method,
InitMPITeams will intialize the library and create
MPI teams based on the number of devices on each node
(nDevs).
If configuring with constructor, the constructor will
make this call.
Once the solver configuration has been established, either through the
ReadParameters method, InitMPITeams will initialize the library and create
MPI teams based on the number of devices on each node (nDevs). If
configuring with constructor, the constructor will make this call.
*/
void InitMPITeams(const MPI_Comm &comm,
const int nDevs);
#endif
/**
Sets Operator for AmgX library, either
MFEM SparseMatrix or HypreParMatrix
Sets Operator for AmgX library, either MFEM SparseMatrix or HypreParMatrix
*/
virtual void SetOperator(const Operator &op);
/**
Replaces the matrix coefficients in the
AmgX solver.
*/
Replaces the matrix coefficients in the AmgX solver.
*/
void UpdateOperator(const Operator &op);
virtual void Mult(const Vector& b, Vector& x) const;
@@ -174,13 +153,12 @@ public:
@param [in] verbose true, false. Specifies the level
of verbosity.
When configured as a preconditioner, the default configuration
is to apply two iterations of an AMG V cycle with AmgX's default
smoother (block Jacobi).
When configured as a preconditioner, the default configuration is to apply
two iterations of an AMG V cycle with AmgX's default smoother (block
Jacobi).
As a solver the preconditioned conjugate gradient method is used.
The AMG V cycle with a block Jacobi smoother is used as a
preconditioner.
As a solver the preconditioned conjugate gradient method is used. The AMG
V-cycle with a block Jacobi smoother is used as a preconditioner.
*/
void DefaultParameters(const AMGX_MODE amgxMode_, const bool verbose);
@@ -197,22 +175,22 @@ private:
CONFIG_SRC configSrc = UNDEFINED;
#ifdef MFEM_USE_MPI
// Consolidates matrix diagonal and off diagonal data
// and uploads matrix to AmgX.
// Consolidates matrix diagonal and off diagonal data and uploads matrix to
// AmgX.
void SetMatrixMPIGPUExclusive(const HypreParMatrix &A,
const Array<double> &loc_A,
const Array<int> &loc_I, const Array<int64_t> &loc_J,
const bool update_mat = false);
// Consolidates matrix diagonal and off diagonal data
// for all ranks in an MPI team. Root rank of each MPI
// team holds the the consolidated data and sets matrix.
// Consolidates matrix diagonal and off diagonal data for all ranks in an MPI
// team. Root rank of each MPI team holds the the consolidated data and sets
// matrix.
void SetMatrixMPITeams(const HypreParMatrix &A, const Array<double> &loc_A,
const Array<int> &loc_I, const Array<int64_t> &loc_J,
const bool update_mat = false);
// The following methods consolidate array data to the root node in
// a MPI team.
// The following methods consolidate array data to the root node in a MPI
// team.
void GatherArray(const Array<double> &inArr, Array<double> &outArr,
const int mpiTeamSz, const MPI_Comm &mpiTeam) const;
@@ -225,8 +203,8 @@ private:
void GatherArray(const Array<int64_t> &inArr, Array<int64_t> &outArr,
const int mpiTeamSz, const MPI_Comm &mpiTeam) const;
// The following methods consolidate array data to the root node in
// a MPI team as well as store array partitions and displacements.
// The following methods consolidate array data to the root node in a MPI
// team as well as store array partitions and displacements.
void GatherArray(const Vector &inArr, Vector &outArr,
const int mpiTeamSz, const MPI_Comm &mpiTeamComm,
Array<int> &Apart, Array<int> &Adisp) const;
@@ -275,20 +253,17 @@ private:
int myGlobalRank;
// Total number of MPI procs in a node
// + rank id
// Total number of MPI procs in a node + rank id
int localSize;
int myLocalRank;
// Total number of MPI ranks sharing a device
// + rank id
// Total number of MPI ranks sharing a device + rank id
int devWorldSize;
int myDevWorldRank;
// Total number of MPI procs calling AmgX
// + rank id
// Total number of MPI procs calling AmgX + rank id
int gpuWorldSize;
int myGpuWorldRank;
@@ -328,11 +303,11 @@ private:
void InitAmgX();
// Row partion for HypreMatrix
// Row partition for the HypreParMatrix
int64_t mat_local_rows;
std::string mpi_gpu_mode;
};
}
#endif //MFEM_USE_AMGX
#endif //MFEM_AMGX_SOLVER
#endif // MFEM_USE_AMGX
#endif // MFEM_AMGX_SOLVER
+225
View File
@@ -0,0 +1,225 @@
#include "cpardiso.hpp"
#include "hypre.hpp"
#include <algorithm>
#include <vector>
#include <numeric>
#ifdef MFEM_USE_MPI
#ifdef MFEM_USE_MKL_CPARDISO
namespace mfem
{
CPardisoSolver::CPardisoSolver(MPI_Comm comm) : comm_(comm)
{
// Indicate that default parameters are changed
iparm[0] = 1;
// Use METIS for fill-in reordering
iparm[1] = 2;
// Do not write the solution into the x vector data
iparm[5] = 0;
// Maximum number of iterative refinement steps
iparm[7] = 2;
// Perturb the pivot elements with 1E-13
iparm[9] = 13;
// Use nonsymmetric permutation
iparm[10] = 1;
// Perform a check on the input data
iparm[26] = 1;
// 0-based indexing in CSR data structure
iparm[34] = 1;
// All inputs are distributed between MPI processes
iparm[39] = 2;
// Maximum number of numerical factorizations
maxfct = 1;
// Which factorization to use. This parameter is ignored and always assumed
// to be equal to 1. See MKL documentation.
mnum = 1;
// Print statistical information in file
msglvl = 0;
// Initialize error flag
error = 0;
// Real nonsymmetric matrix
mtype = MatType::REAL_NONSYMMETRIC;
// Number of right hand sides
nrhs = 1;
};
void CPardisoSolver::SetOperator(const Operator &op)
{
auto hypreParMat = dynamic_cast<const HypreParMatrix &>(op);
MFEM_ASSERT(hypreParMat, "Must pass HypreParMatrix as Operator");
auto parcsr_op = static_cast<hypre_ParCSRMatrix *>(
const_cast<HypreParMatrix &>(hypreParMat));
hypre_CSRMatrix *csr_op = hypre_MergeDiagAndOffd(parcsr_op);
#if MFEM_HYPRE_VERSION >= 21600
hypre_CSRMatrixBigJtoJ(csr_op);
#endif
m = parcsr_op->global_num_rows;
first_row = parcsr_op->first_row_index;
nnz_loc = csr_op->num_nonzeros;
m_loc = csr_op->num_rows;
height = m_loc;
width = m_loc;
double *csr_nzval = csr_op->data;
int *csr_colind = csr_op->j;
delete[] csr_rowptr;
delete[] reordered_csr_colind;
delete[] reordered_csr_nzval;
csr_rowptr = new int[m_loc + 1];
reordered_csr_colind = new int[nnz_loc];
reordered_csr_nzval = new double[nnz_loc];
for (int i = 0; i <= m_loc; i++)
{
csr_rowptr[i] = (csr_op->i)[i];
}
// CPardiso expects the column indices to be sorted for each row
std::vector<int> permutation_idx(nnz_loc);
std::iota(permutation_idx.begin(), permutation_idx.end(), 0);
for (int i = 0; i < m_loc; i++)
{
std::sort(permutation_idx.begin() + csr_rowptr[i],
permutation_idx.begin() + csr_rowptr[i + 1],
[csr_colind](int i1, int i2)
{
return csr_colind[i1] < csr_colind[i2];
});
}
for (int i = 0; i < nnz_loc; i++)
{
reordered_csr_colind[i] = csr_colind[permutation_idx[i]];
reordered_csr_nzval[i] = csr_nzval[permutation_idx[i]];
}
hypre_CSRMatrixDestroy(csr_op);
// The number of row in global matrix, rhs element and solution vector that
// begins the input domain belonging to this MPI process
iparm[40] = first_row;
// The number of row in global matrix, rhs element and solution vector that
// ends the input domain belonging to this MPI process
iparm[41] = first_row + m_loc - 1;
// Analyze inputs
phase = 11;
cluster_sparse_solver(pt,
&maxfct,
&mnum,
&mtype,
&phase,
&m,
reordered_csr_nzval,
csr_rowptr,
reordered_csr_colind,
&idum,
&nrhs,
iparm,
&msglvl,
&ddum,
&ddum,
&comm_,
&error);
MFEM_ASSERT(error == 0, "CPardiso analyze input error");
// Numerical factorization
phase = 22;
cluster_sparse_solver(pt,
&maxfct,
&mnum,
&mtype,
&phase,
&m,
reordered_csr_nzval,
csr_rowptr,
reordered_csr_colind,
&idum,
&nrhs,
iparm,
&msglvl,
&ddum,
&ddum,
&comm_,
&error);
MFEM_ASSERT(error == 0, "CPardiso factorization input error");
}
void CPardisoSolver::Mult(const Vector &b, Vector &x) const
{
// Solve
phase = 33;
cluster_sparse_solver(pt,
&maxfct,
&mnum,
&mtype,
&phase,
&m,
reordered_csr_nzval,
csr_rowptr,
reordered_csr_colind,
&idum,
&nrhs,
iparm,
&msglvl,
b.GetData(),
x.GetData(),
&comm_,
&error);
MFEM_ASSERT(error == 0, "Pardiso solve error");
}
void CPardisoSolver::SetPrintLevel(int print_level)
{
msglvl = print_level;
}
void CPardisoSolver::SetMatrixType(MatType mat_type)
{
mtype = mat_type;
}
CPardisoSolver::~CPardisoSolver()
{
// Release all internal memory
phase = -1;
cluster_sparse_solver(pt,
&maxfct,
&mnum,
&mtype,
&phase,
&m,
reordered_csr_nzval,
csr_rowptr,
reordered_csr_colind,
&idum,
&nrhs,
iparm,
&msglvl,
&ddum,
&ddum,
&comm_,
&error);
MFEM_ASSERT(error == 0, "CPardiso free error");
delete[] csr_rowptr;
delete[] reordered_csr_colind;
delete[] reordered_csr_nzval;
}
} // namespace mfem
#endif // MFEM_USE_MKL_CPARDISO
#endif // MFEM_USE_MPI
+125
View File
@@ -0,0 +1,125 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_CPARDISO
#define MFEM_CPARDISO
#include "../config/config.hpp"
#ifdef MFEM_USE_MPI
#ifdef MFEM_USE_MKL_CPARDISO
#include "mkl_cluster_sparse_solver.h"
#include "operator.hpp"
namespace mfem
{
/**
* @brief MKL Parallel Direct Sparse Solver for Clusters
*
* Interface to MKL CPardiso: the MPI-enabled Intel MKL version of Pardiso
*/
class CPardisoSolver : public Solver
{
public:
enum MatType
{
REAL_STRUCTURE_SYMMETRIC = 1,
REAL_NONSYMMETRIC = 11
};
/**
* @brief Construct a new CPardisoSolver object
*
* @param comm MPI Communicator
*/
CPardisoSolver(MPI_Comm comm);
/**
* @brief Set the Operator object and perform factorization
*
* @a op needs to be of type HypreParMatrix. The contents are copied and
* reordered in an internal CSR structure.
*
* @param op Operator to use in factorization and solve
*/
void SetOperator(const Operator &op) override;
/**
* @brief Solve
*
* @param b RHS vector
* @param x Solution vector
*/
void Mult(const Vector &b, Vector &x) const override;
/**
* @brief Set the print level for MKL CPardiso
*
* Prints statistics after the factorization and after each solve.
*
* @param print_lvl Print level
*/
void SetPrintLevel(int print_lvl);
/**
* @brief Set the matrix type
*
* The matrix type supported is either real and symmetric or real and
* non-symmetric.
*
* @param mat_type Matrix type
*/
void SetMatrixType(MatType mat_type);
~CPardisoSolver();
private:
MPI_Comm comm_;
// Global number of rows
int m;
// First row index of the global matrix on the local MPI rank
int first_row;
// Local number of nonzero entries
int nnz_loc;
// Local number of rows, obtained from a ParCSR matrix
int m_loc;
// CSR data structure for the copy data of the local CSR matrix
int *csr_rowptr = nullptr;
double *reordered_csr_nzval = nullptr;
int *reordered_csr_colind = nullptr;
// Internal solver memory pointer pt,
// 32-bit: int pt[64]
// 64-bit: long int pt[64] or void *pt[64] should be OK on both architectures
mutable void *pt[64] = {0};
// Solver control parameters, detailed description can be found in the
// constructor.
mutable int iparm[64] = {0};
mutable int maxfct, mnum, msglvl, phase, error;
int mtype;
int nrhs;
// Dummy variables
mutable int idum;
mutable double ddum;
};
} // namespace mfem
#endif
#endif // MFEM_USE_MKL_CPARDISO
#endif // MFEM_USE_MPI
+37
View File
@@ -300,6 +300,43 @@ void OperatorHandle::EliminateRowsCols(OperatorHandle &A,
}
}
void OperatorHandle::EliminateRows(const Array<int> &ess_dof_list)
{
switch (Type())
{
case Operator::Hypre_ParCSR:
{
#ifdef MFEM_USE_MPI
this->As<HypreParMatrix>()->EliminateRows(ess_dof_list);
#else
MFEM_ABORT("type id = Hypre_ParCSR requires MFEM_USE_MPI");
#endif
break;
}
default:
MFEM_ABORT(not_supported_msg << Type());
}
}
void OperatorHandle::EliminateCols(const Array<int> &ess_dof_list)
{
switch (Type())
{
case Operator::Hypre_ParCSR:
{
#ifdef MFEM_USE_MPI
auto Ae = this->As<HypreParMatrix>()->EliminateCols(ess_dof_list);
delete Ae;
#else
MFEM_ABORT("type id = Hypre_ParCSR requires MFEM_USE_MPI");
#endif
break;
}
default:
MFEM_ABORT(not_supported_msg << Type());
}
}
void OperatorHandle::EliminateBC(const OperatorHandle &A_e,
const Array<int> &ess_dof_list,
const Vector &X, Vector &B) const
+6
View File
@@ -186,6 +186,12 @@ public:
elimination of the essential dofs @a ess_dof_list. */
void EliminateRowsCols(OperatorHandle &A, const Array<int> &ess_dof_list);
/// Eliminate the rows corresponding to the essential dofs @a ess_dof_list
void EliminateRows(const Array<int> &ess_dof_list);
/// Eliminate columns corresponding to the essential dofs @a ess_dof_list
void EliminateCols(const Array<int> &ess_dof_list);
/// Eliminate essential dofs from the solution @a X into the r.h.s. @a B.
/** The argument @a A_e is expected to be the result of the method
EliminateRowsCols(). */
+243 -3
View File
@@ -2268,7 +2268,6 @@ void HypreSmoother::SetOperator(const Operator &op)
Vector ones(height), diag(l1_norms, height);
ones = 1.0;
A->Mult(ones, diag);
type = 1;
}
else
{
@@ -2420,13 +2419,17 @@ void HypreSmoother::Mult(const HypreParVector &b, HypreParVector &x) const
}
else
{
int hypre_type = type;
// hypre doesn't have lumped Jacobi, so treat the action as l1-Jacobi
if (type == 5) { hypre_type = 1; }
if (Z == NULL)
hypre_ParCSRRelax(*A, b, type,
hypre_ParCSRRelax(*A, b, hypre_type,
relax_times, l1_norms, relax_weight, omega,
max_eig_est, min_eig_est, poly_order, poly_fraction,
x, *V, NULL);
else
hypre_ParCSRRelax(*A, b, type,
hypre_ParCSRRelax(*A, b, hypre_type,
relax_times, l1_norms, relax_weight, omega,
max_eig_est, min_eig_est, poly_order, poly_fraction,
x, *V, *Z);
@@ -2898,6 +2901,165 @@ HypreGMRES::~HypreGMRES()
}
HypreFGMRES::HypreFGMRES(MPI_Comm comm) : precond(NULL)
{
iterative_mode = true;
HYPRE_ParCSRFlexGMRESCreate(comm, &fgmres_solver);
SetDefaultOptions();
}
HypreFGMRES::HypreFGMRES(HypreParMatrix &_A) : HypreSolver(&_A), precond(NULL)
{
MPI_Comm comm;
iterative_mode = true;
HYPRE_ParCSRMatrixGetComm(*A, &comm);
HYPRE_ParCSRFlexGMRESCreate(comm, &fgmres_solver);
SetDefaultOptions();
}
void HypreFGMRES::SetDefaultOptions()
{
int k_dim = 50;
int max_iter = 100;
double tol = 1e-6;
HYPRE_ParCSRFlexGMRESSetKDim(fgmres_solver, k_dim);
HYPRE_ParCSRFlexGMRESSetMaxIter(fgmres_solver, max_iter);
HYPRE_ParCSRFlexGMRESSetTol(fgmres_solver, tol);
}
void HypreFGMRES::SetOperator(const Operator &op)
{
const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
// update base classes: Operator, Solver, HypreSolver
height = new_A->Height();
width = new_A->Width();
A = const_cast<HypreParMatrix *>(new_A);
if (precond)
{
precond->SetOperator(*A);
this->SetPreconditioner(*precond);
}
setup_called = 0;
delete X;
delete B;
B = X = NULL;
}
void HypreFGMRES::SetTol(double tol)
{
HYPRE_ParCSRFlexGMRESSetTol(fgmres_solver, tol);
}
void HypreFGMRES::SetMaxIter(int max_iter)
{
HYPRE_ParCSRFlexGMRESSetMaxIter(fgmres_solver, max_iter);
}
void HypreFGMRES::SetKDim(int k_dim)
{
HYPRE_ParCSRFlexGMRESSetKDim(fgmres_solver, k_dim);
}
void HypreFGMRES::SetLogging(int logging)
{
HYPRE_ParCSRFlexGMRESSetLogging(fgmres_solver, logging);
}
void HypreFGMRES::SetPrintLevel(int print_lvl)
{
HYPRE_ParCSRFlexGMRESSetPrintLevel(fgmres_solver, print_lvl);
}
void HypreFGMRES::SetPreconditioner(HypreSolver &_precond)
{
precond = &_precond;
HYPRE_ParCSRFlexGMRESSetPrecond(fgmres_solver,
_precond.SolveFcn(),
_precond.SetupFcn(),
_precond);
}
void HypreFGMRES::Mult(const HypreParVector &b, HypreParVector &x) const
{
int myid;
HYPRE_Int time_index = 0;
HYPRE_Int num_iterations;
double final_res_norm;
MPI_Comm comm;
HYPRE_Int print_level;
HYPRE_FlexGMRESGetPrintLevel(fgmres_solver, &print_level);
HYPRE_ParCSRMatrixGetComm(*A, &comm);
if (!setup_called)
{
if (print_level > 0)
{
time_index = hypre_InitializeTiming("FGMRES Setup");
hypre_BeginTiming(time_index);
}
HYPRE_ParCSRFlexGMRESSetup(fgmres_solver, *A, b, x);
setup_called = 1;
if (print_level > 0)
{
hypre_EndTiming(time_index);
hypre_PrintTiming("Setup phase times", comm);
hypre_FinalizeTiming(time_index);
hypre_ClearTiming();
}
}
if (print_level > 0)
{
time_index = hypre_InitializeTiming("FGMRES Solve");
hypre_BeginTiming(time_index);
}
if (!iterative_mode)
{
x = 0.0;
}
HYPRE_ParCSRFlexGMRESSolve(fgmres_solver, *A, b, x);
if (print_level > 0)
{
hypre_EndTiming(time_index);
hypre_PrintTiming("Solve phase times", comm);
hypre_FinalizeTiming(time_index);
hypre_ClearTiming();
HYPRE_ParCSRFlexGMRESGetNumIterations(fgmres_solver, &num_iterations);
HYPRE_ParCSRFlexGMRESGetFinalRelativeResidualNorm(fgmres_solver,
&final_res_norm);
MPI_Comm_rank(comm, &myid);
if (myid == 0)
{
mfem::out << "FGMRES Iterations = " << num_iterations << endl
<< "Final FGMRES Relative Residual Norm = " << final_res_norm
<< endl;
}
}
}
HypreFGMRES::~HypreFGMRES()
{
HYPRE_ParCSRFlexGMRESDestroy(fgmres_solver);
}
void HypreDiagScale::SetOperator(const Operator &op)
{
const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
@@ -3080,6 +3242,84 @@ HypreEuclid::~HypreEuclid()
}
#if MFEM_HYPRE_VERSION >= 21900
HypreILU::HypreILU()
{
HYPRE_ILUCreate(&ilu_precond);
SetDefaultOptions();
}
void HypreILU::SetDefaultOptions()
{
// The type of incomplete LU used locally and globally (see class doc)
HYPRE_Int ilu_type = 0; // ILU(k) locally and block Jacobi globally
HYPRE_ILUSetType(ilu_precond, ilu_type);
// Maximum iterations; 1 iter for preconditioning
HYPRE_Int max_iter = 1;
HYPRE_ILUSetMaxIter(ilu_precond, max_iter);
// The tolerance when used as a smoother; set to 0.0 for preconditioner
HYPRE_Real tol = 0.0;
HYPRE_ILUSetTol(ilu_precond, tol);
// Fill level for ILU(k)
HYPRE_Int lev_fill = 1;
HYPRE_ILUSetLevelOfFill(ilu_precond, lev_fill);
// Local reordering scheme; 0 = no reordering, 1 = reverse Cuthill-McKee
HYPRE_Int reorder_type = 1;
HYPRE_ILUSetLocalReordering(ilu_precond, reorder_type);
// Information print level; 0 = none, 1 = setup, 2 = solve, 3 = setup+solve
HYPRE_Int print_level = 0;
HYPRE_ILUSetPrintLevel(ilu_precond, print_level);
}
void HypreILU::ResetILUPrecond()
{
if (ilu_precond)
{
HYPRE_ILUDestroy(ilu_precond);
}
HYPRE_ILUCreate(&ilu_precond);
SetDefaultOptions();
}
void HypreILU::SetLevelOfFill(HYPRE_Int lev_fill)
{
HYPRE_ILUSetLevelOfFill(ilu_precond, lev_fill);
}
void HypreILU::SetPrintLevel(HYPRE_Int print_level)
{
HYPRE_ILUSetPrintLevel(ilu_precond, print_level);
}
void HypreILU::SetOperator(const Operator &op)
{
const HypreParMatrix *new_A = dynamic_cast<const HypreParMatrix *>(&op);
MFEM_VERIFY(new_A, "new Operator must be a HypreParMatrix!");
if (A) { ResetILUPrecond(); }
// update base classes: Operator, Solver, HypreSolver
height = new_A->Height();
width = new_A->Width();
A = const_cast<HypreParMatrix *>(new_A);
setup_called = 0;
delete X;
delete B;
B = X = NULL;
}
HypreILU::~HypreILU()
{
HYPRE_ILUDestroy(ilu_precond);
}
#endif
HypreBoomerAMG::HypreBoomerAMG()
{
HYPRE_BoomerAMGCreate(&amg_precond);
+118 -5
View File
@@ -160,9 +160,10 @@ public:
~HypreParVector();
#ifdef MFEM_USE_SUNDIALS
/// Return a new wrapper SUNDIALS N_Vector of type SUNDIALS_NVEC_PARALLEL.
/** The returned N_Vector must be destroyed by the caller. */
virtual N_Vector ToNVector();
/// (DEPRECATED) Return a new wrapper SUNDIALS N_Vector of type SUNDIALS_NVEC_PARALLEL.
/** @deprecated The returned N_Vector must be destroyed by the caller. */
MFEM_DEPRECATED virtual N_Vector ToNVector();
using Vector::ToNVector;
#endif
};
@@ -782,8 +783,11 @@ public:
2) enable residual-based stopping criteria. */
void SetResidualConvergenceOptions(int res_frequency=-1, double rtol=0.0);
/// deprecated: use SetZeroInitialIterate()
MFEM_DEPRECATED void SetZeroInintialIterate() { iterative_mode = false; }
/// non-hypre setting
void SetZeroInintialIterate() { iterative_mode = false; }
void SetZeroInitialIterate() { iterative_mode = false; }
void GetNumIterations(int &num_iterations)
{
@@ -836,8 +840,11 @@ public:
/// Set the hypre solver to be used as a preconditioner
void SetPreconditioner(HypreSolver &precond);
/// deprecated: use SetZeroInitialIterate()
MFEM_DEPRECATED void SetZeroInintialIterate() { iterative_mode = false; }
/// non-hypre setting
void SetZeroInintialIterate() { iterative_mode = false; }
void SetZeroInitialIterate() { iterative_mode = false; }
/// The typecast to HYPRE_Solver returns the internal gmres_solver
virtual operator HYPRE_Solver() const { return gmres_solver; }
@@ -856,6 +863,56 @@ public:
virtual ~HypreGMRES();
};
/// Flexible GMRES solver in hypre
class HypreFGMRES : public HypreSolver
{
private:
HYPRE_Solver fgmres_solver;
HypreSolver * precond;
/// Default, generally robust, FGMRES options
void SetDefaultOptions();
public:
HypreFGMRES(MPI_Comm comm);
HypreFGMRES(HypreParMatrix &_A);
virtual void SetOperator(const Operator &op);
void SetTol(double tol);
void SetMaxIter(int max_iter);
void SetKDim(int dim);
void SetLogging(int logging);
void SetPrintLevel(int print_lvl);
/// Set the hypre solver to be used as a preconditioner
void SetPreconditioner(HypreSolver &precond);
/// deprecated: use SetZeroInitialIterate()
MFEM_DEPRECATED void SetZeroInintialIterate() { iterative_mode = false; }
/// non-hypre setting
void SetZeroInitialIterate() { iterative_mode = false; }
/// The typecast to HYPRE_Solver returns the internal fgmres_solver
virtual operator HYPRE_Solver() const { return fgmres_solver; }
/// FGMRES Setup function
virtual HYPRE_PtrToParSolverFcn SetupFcn() const
{ return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRFlexGMRESSetup; }
/// FGMRES Solve function
virtual HYPRE_PtrToParSolverFcn SolveFcn() const
{ return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSRFlexGMRESSolve; }
/// Solve Ax=b with hypre's FGMRES
virtual void Mult (const HypreParVector &b, HypreParVector &x) const;
using HypreSolver::Mult;
virtual ~HypreFGMRES();
};
/// The identity operator as a hypre solver
class HypreIdentity : public HypreSolver
{
@@ -962,6 +1019,62 @@ public:
virtual ~HypreEuclid();
};
#if MFEM_HYPRE_VERSION >= 21900
/**
@brief Wrapper for Hypre's native parallel ILU preconditioner.
The default ILU factorization type is ILU(k). If you need to change this, or
any other option, you can use the HYPRE_Solver method to cast the object for use
with Hypre's native functions. For example, if want to use natural ordering
rather than RCM reordering, you can use the following approach:
@code
mfem::HypreILU ilu();
int reorder_type = 0;
HYPRE_ILUSetLocalReordering(ilu, reorder_type);
@endcode
*/
class HypreILU : public HypreSolver
{
private:
HYPRE_Solver ilu_precond;
/// Set the ILU default options
void SetDefaultOptions();
/** Reset the ILU preconditioner.
@note If ilu_precond is NULL, this method allocates; otherwise it destroys
ilu_precond and allocates a new object. In both cases the default options
are set. */
void ResetILUPrecond();
public:
/// Constructor; sets the default options
HypreILU();
virtual ~HypreILU();
/// Set the fill level for ILU(k); the default is k=1.
void SetLevelOfFill(HYPRE_Int lev_fill);
/// Set the print level: 0 = none, 1 = setup, 2 = solve, 3 = setup+solve
void SetPrintLevel(HYPRE_Int print_level);
/// The typecast to HYPRE_Solver returns the internal ilu_precond
virtual operator HYPRE_Solver() const { return ilu_precond; }
virtual void SetOperator(const Operator &op);
/// ILU Setup function
virtual HYPRE_PtrToParSolverFcn SetupFcn() const
{ return (HYPRE_PtrToParSolverFcn) HYPRE_ILUSetup; }
/// ILU Solve function
virtual HYPRE_PtrToParSolverFcn SolveFcn() const
{ return (HYPRE_PtrToParSolverFcn) HYPRE_ILUSolve; }
};
#endif
/// The BoomerAMG solver in hypre
class HypreBoomerAMG : public HypreSolver
{
+4
View File
@@ -65,6 +65,10 @@
#include "strumpack.hpp"
#endif
#ifdef MFEM_USE_MKL_CPARDISO
#include "cpardiso.hpp"
#endif
#endif // MFEM_USE_MPI
#endif

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