Compare commits

...
Author SHA1 Message Date
blaz d167956031 elplast solver and mesh 2022-12-17 00:24:24 -08:00
blaz e9682c79c0 ASCII test 2022-08-12 16:49:44 -07:00
blaz 7741eef3d5 Merge remote-tracking branch 'origin/paraview-ascii-fix' into bsl/elastoplast 2022-08-12 16:44:10 -07:00
Will Pazner c14899c149 Fix ParaView ASCII output (was going to mfem::out instead of file stream) 2022-08-12 12:04:25 -07:00
blaz 878b4a4aed Merge branch 'master' into bsl/elastoplast 2022-08-12 11:48:57 -07:00
blaz af6dab528b modified ASCII dump 2022-08-12 11:36:22 -07:00
Tzanio Kolev fcf50aae53 Merge pull request #3122 from mfem/minres-device
UseDevice in MINRESSolver
2022-08-08 08:27:11 -07:00
Tzanio Kolev e2636e7492 Merge pull request #3123 from mfem/minor-fixes
Minor PA and solver fixes
2022-08-05 08:16:49 -07:00
blaz 8a353a1357 makefile 2022-08-03 12:41:00 -07:00
Veselin Dobrev d70bf954ae Merge pull request #3035 from mfem/pmesh-to-serial-mesh
Save a ParMesh as a serial mesh
2022-08-02 11:40:22 -07:00
Veselin Dobrev 74ea5db428 Merge pull request #3089 from mfem/pmesh-setnodalspace
Set Nodes correctly for ParMesh with ParFESpace using SetNodalFESpace
2022-08-02 11:39:32 -07:00
Tzanio Kolev 6f780be8b6 Merge pull request #3052 from mfem/artv3/hypre-opt/ParCSRMatrixLocalTranspose
Support hypre_ParCSRMatrixLocalTranspose
2022-08-02 11:27:44 -07:00
Will Pazner af81ad2656 Merge pull request #3061 from mfem/artv3/hypre/add-lcublas
add cublas flag for hypre
2022-08-02 09:58:00 -07:00
Will Pazner 9ef3e3533a Minor CGSolver::Mult output fixes 2022-07-30 12:35:17 -07:00
Will Pazner e4d4a84ac8 Use UsesTensorBasis in check LinearForm::SupportsDevice 2022-07-30 12:35:17 -07:00
Will Pazner dbdb234d1d Fix host access of GeometricFactors 2022-07-30 12:35:17 -07:00
Will Pazner 457d39c643 UseDevice in MINRESSolver 2022-07-30 10:36:04 -07:00
Tzanio Kolev b3a37687a0 Merge pull request #3023 from mfem/yohann/explicit-cast-mandel
Add an explicit cast to avoid implicit cast warning.
2022-07-29 07:56:28 -07:00
Tzanio Kolev be0c57cc73 Merge pull request #2953 from mfem/yohann/mixed-mesh
Add support for mixed meshes using libCEED.
2022-07-28 16:32:08 -07:00
Veselin Dobrev 351a5a00f7 Update some comments 2022-07-27 16:31:22 -07:00
Veselin Dobrev 9592ee5ab6 Fix the HYPRE version where hypre_ParCSRMatrixLocalTranspose() was
introduced.

Add a method HypreParMatrix::EnsureMultTranspose() that calls
hypre_ParCSRMatrixLocalTranspose() when HYPRE is built for GPUs.

Use HypreParMatrix::EnsureMultTranspose() in the implementation of
class ParFiniteElementSpace when constructing the parallel
prolongation operator as a HypreParMatrix.
2022-07-27 16:16:44 -07:00
Tzanio Kolev d2764aa218 Update miniapps/electromagnetics/maxwell.cpp 2022-07-27 09:11:45 -07:00
Yohann Dudouit 5e235154a5 Revert "Temporarily disable 2D parallel mixed mesg runs until #2953 is fixed"
This reverts commit e3775d570f.
2022-07-26 16:33:16 -07:00
Yohann Dudouit 6979e3ae40 Fix UsesTensorBasis to return false on mixed meshes.
- Thanks @mlstowell !
2022-07-26 16:17:49 -07:00
Veselin Dobrev f2f489a36e Updated ParMesh::GetSerialMesh() with some overflow checks and
some small tweaks.

Replace some uses of 'long' with 'long long' to better support
Win64 builds where 'long' is 32-bit and 'long long' is 64-bit.
On Linux and MacOS, both types are typically 64-bit.

Updated various "MemoryUsage" methods to return 'std::size_t'
instead of 'long' since the latter is 32-bit in Win64 builds.

Updated CHANGELOG.
2022-07-26 16:09:12 -07:00
Tzanio Kolev e3775d570f Temporarily disable 2D parallel mixed mesg runs until #2953 is fixed 2022-07-26 12:52:14 -07:00
Tzanio Kolev a4acfbb6bd Fixed a bug 2022-07-26 12:46:38 -07:00
Will Pazner 9c2d3f81d0 Merge remote-tracking branch 'origin/master' into artv3/hypre/add-lcublas
# Conflicts:
#	CMakeLists.txt
2022-07-26 11:52:40 -07:00
Veselin Dobrev 3ef72174c8 Merge branch 'master' into pmesh-to-serial-mesh 2022-07-26 10:12:27 -07:00
Tzanio Kolev 670b7b1ae3 Merge pull request #3000 from mfem/tmop-metrics
Mesh Untangling and worst case quality improvement metrics (TMOP)
2022-07-24 14:32:09 -07:00
Tzanio Kolev 2c061c0366 Merge branch 'master' into artv3/hypre-opt/ParCSRMatrixLocalTranspose 2022-07-15 07:39:42 -07:00
Tzanio Kolev 154073caf3 Merge branch 'master' into tmop-metrics 2022-07-15 07:38:46 -07:00
Tzanio Kolev baa438344f Merge branch 'master' into yohann/mixed-mesh 2022-07-15 07:38:14 -07:00
Tzanio Kolev b77b608d21 Merge pull request #3106 from mfem/vcpkg-patch-metis
Use mfem/tpls for vcpkg Metis
2022-07-14 12:46:11 -07:00
blaz d66df0b954 strain and stress coefficients 2022-07-13 23:29:59 -07:00
Tzanio Kolev 40af7f79ad Update fem/tmop_tools.cpp 2022-07-13 18:29:43 -07:00
Tzanio Kolev 6ec94abe05 Update fem/tmop.hpp 2022-07-13 18:29:36 -07:00
Vladimir Z Tomov 7bfe22ad28 Verified valid input barrier metric. 2022-07-13 17:39:54 -07:00
Vladimir Z Tomov 855d610ba1 Aborted the worst-quality for now, as there are open questions. 2022-07-13 17:26:56 -07:00
Vladimir Z Tomov e29260f2df Removed unnecessary func calls. 2022-07-13 17:07:24 -07:00
Will Pazner 3f0fe1b4eb Use mfem/tpls for vcpkg Metis
Patch the vcpkg portfile for Metis used in GitHub Actions on Windows
to download the metis archive from mfem/tpls rather than the official
Metis server.
2022-07-13 13:47:31 -07:00
Yohann Dudouit dfd3bbe1b4 Remove explicit delete of CeedElemRestriction.
- Double free was creating issues.
2022-07-13 13:32:50 -07:00
Tzanio Kolev e81c4b86c3 Update linalg/hypre_parcsr.cpp 2022-07-13 12:16:58 -07:00
Tzanio Kolev 13543703bd Update linalg/hypre_parcsr.cpp 2022-07-13 12:16:41 -07:00
Tzanio Kolev 9bfaf169ed Update linalg/hypre_parcsr.cpp 2022-07-13 12:16:04 -07:00
Tzanio Kolev 6652c061d5 Merge pull request #3102 from mfem/tmop-da3-race-fix
Fix over-writing fmin race in fem/tmop/tmop_pa_da3.cpp [tmop-da3-race-fix]
2022-07-13 12:14:25 -07:00
Tzanio Kolev 65b0d86736 Merge pull request #3080 from mfem/vector-fe-div-mt-integral
Support map type INTEGRAL in PA VectorFEDivergenceIntegrator
2022-07-13 12:14:04 -07:00
Ketan Mittal bcc694aa41 merge conflict in CHANGELOG 2022-07-12 16:15:51 -07:00
Ketan Mittal 4884063dab reviewer comments 2022-07-12 16:15:02 -07:00
Arturo VargasandTzanio Kolev d4d002aca7 Update linalg/hypre_parcsr.cpp
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2022-07-12 13:51:13 -07:00
Will Pazner 773ea0cc5d Merge pull request #3056 from mfem/yohann/fa-form-system
Full Assembly BC elimination and HypreParMatrix
2022-07-12 10:32:42 -07:00
Tzanio Kolev e9acd4c084 Small fixed + organized CHANGELOG 2022-07-12 08:36:57 -07:00
Tzanio Kolev 9dc2495906 Merge branch 'master' into yohann/mixed-mesh 2022-07-12 08:09:50 -07:00
Ketan Mittal 8692b9ab56 add MPI_Barrier;useful for large meshes 2022-07-11 13:03:40 -07:00
Ketan Mittal 5dcf7e17d8 remove old commented out code 2022-07-11 11:52:28 -07:00
Ketan Mittal e69d5bd59c Merge branch 'master' of https://github.com/mfem/mfem into tmop-metrics 2022-07-11 11:49:44 -07:00
Ketan Mittal b02bfbc799 documentation 2022-07-11 11:49:24 -07:00
Ketan Mittal edbe8ee14b update miniapps 2022-07-11 11:37:50 -07:00
Tzanio Kolev 2a033c3298 Update test_pa_coeff.cpp 2022-07-11 11:30:29 -07:00
Tzanio Kolev 3d7b3b18fb Merge pull request #3012 from researchapps/add/multistage-build
adding multistage-build for slimmer container
2022-07-10 16:44:38 -07:00
Ketan Mittal 47fe9738ec combine untangling and worst case metrics into 1 2022-07-08 16:04:20 -07:00
camierjs 69e9674c06 Fix over-writing fmin race in fem/tmop/tmop_pa_da3.cpp 2022-07-08 09:48:23 -07:00
vsoch 972e13a595 remove PR trigger
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-07-07 12:44:48 -06:00
Tzanio Kolev 2208fc9aa8 Merge pull request #3077 from mfem/dlf-map-type
Support map type INTEGRAL in device DomainLFIntegrator
2022-07-07 10:17:19 -07:00
Tzanio Kolev e6c39635c9 Merge pull request #3068 from mfem/smem-hdiv-mass
Optimized shared memory H(div) mass kernels
2022-07-05 12:41:32 -07:00
Tzanio Kolev 5fa59a2f66 Merge pull request #2814 from mfem/enzyme-nonlinear
Nonlinear elasticity example with PA and AD
2022-07-05 12:41:04 -07:00
Tzanio Kolev 8b41d1dd05 Merge pull request #2760 from mfem/ortho-solver
Move OrthoSolver to solvers.hpp/cpp
2022-07-05 12:40:00 -07:00
Veselin Dobrev e7485db5eb Suppress a warning from the Intel compiler in the Hooke miniapp 2022-07-01 17:20:49 -07:00
blaz 9a30d77546 initial mesh refinement 2022-06-30 12:41:28 -07:00
Veselin Dobrev 4614a69b51 Fix the out-of-source GNU make build in miniapps/hooke 2022-06-29 17:01:37 -07:00
Yohann Dudouit c11576a686 Addressing review feedback from @acfisher. 2022-06-28 15:48:38 -07:00
Veselin Dobrev c93c185315 Building and testing tweaks for miniapps/hooke. 2022-06-28 00:02:52 -07:00
Veselin Dobrev fe55085199 Small additions 2022-06-27 20:16:39 -07:00
Veselin Dobrev 9f13caf64e Small tweaks 2022-06-27 19:57:58 -07:00
Veselin Dobrev fc1a8776ba Merge pull request #3078 from mfem/disable-docker-ci-forks
Disable Build Deploy Container workflow in forks
2022-06-27 16:11:02 -07:00
Veselin Dobrev 01f981d705 Revert no longer needed changes in device.cpp 2022-06-27 16:03:56 -07:00
Yohann Dudouit c225923cce Remove check for GPUHypre + debug. 2022-06-27 15:26:33 -07:00
Yohann Dudouit 8f90dc5c03 Try fixing CI issues. 2022-06-24 12:27:15 -07:00
Tzanio Kolev a46cf91039 Fixed additional instances of implicit type conversion 2022-06-24 09:43:50 -07:00
Arturo Vargas 0aaf837463 add version guards 2022-06-24 08:56:50 -07:00
Arturo Vargas ef53cb55fd Merge branch 'master' into artv3/hypre-opt/ParCSRMatrixLocalTranspose 2022-06-24 08:46:13 -07:00
Veselin Dobrev 9de9bdaa64 Fix a warning in class OrthoSolver in the serial build. 2022-06-23 16:49:50 -07:00
Veselin Dobrev 2bb7d8fe72 Some tweaks and documentation in class OrthoSolver. 2022-06-23 16:33:25 -07:00
Ketan Mittal 0d6809927f minor 2022-06-23 15:27:17 -07:00
Ketan Mittal 023d6e3276 add override 2022-06-23 14:52:43 -07:00
Veselin Dobrev 3dd5cbbe07 Merge pull request #2934 from mfem/artv3/umpire-mem-for-face-geo-facts
Add umpire pools to face geometric factor memory
2022-06-23 12:40:15 -07:00
Ketan Mittal cdc8c9634f add method for setting nodal FESpace in par meshes 2022-06-23 10:03:55 -07:00
Julian Andrej 94578246c6 terrible style application 2022-06-22 13:55:23 -07:00
Julian Andrej 66849d50a8 a little more refined type deduction 2022-06-22 13:53:41 -07:00
Julian Andrej a3dc3fa717 working in comments from reviews 2022-06-22 09:41:17 -07:00
Julian Andrej 33fc6fa644 add a unit test 2022-06-22 09:16:00 -07:00
Yohann Dudouit c0fbb01a73 Remove InitTensorRestriction. 2022-06-21 13:15:59 -07:00
Yohann Dudouit a3429fa4ab Add mixed meshes sample runs with libCEED in ex1 and ex1p. 2022-06-21 12:14:29 -07:00
Will Pazner 1b812b4a36 Support map type INTEGRAL in PA VectorFEDivergenceIntegrator 2022-06-17 19:11:18 -07:00
Will Pazner 96af414790 Disable Build Deploy Container workflow in forks 2022-06-17 11:06:24 -07:00
Tzanio Kolev e327e111ad Merge pull request #3024 from mfem/quiet-unit-tests
Quieter unit tests
2022-06-17 08:15:03 -07:00
Tzanio Kolev 413fb4e44b Merge pull request #3044 from mfem/extend-ex33
Extend `ex33` to arbitrary fractional exponents
2022-06-17 08:14:17 -07:00
Julian Andrej 7e44926d03 more msvc nonsense 2022-06-17 07:56:37 -07:00
Julian Andrej e5f2c551bf Merge branch 'master' of github.com:mfem/mfem into enzyme-nonlinear 2022-06-17 07:55:49 -07:00
Will Pazner c251fa7d78 Support general coefficients in shared memory H(div) mass kernels 2022-06-16 16:43:51 -07:00
Will Pazner 9495bf51dd Merge remote-tracking branch 'origin/hdivpa' into smem-hdiv-mass
# Conflicts:
#	fem/bilininteg_vectorfe.cpp
2022-06-16 16:43:33 -07:00
Tzanio Kolev 29b8f10fdb Merge pull request #3064 from mfem/delete-vector-operators
Explicitly delete some Vector operator overloads
2022-06-16 16:26:54 -07:00
Tzanio Kolev ef98bba35c Merge pull request #3041 from mfem/facequadinterp-smem-eval3d
Shared Memory FaceQuadratureInterpolator::Eval3D
2022-06-16 16:24:52 -07:00
Will Pazner 295d5a0ac9 Support map type INTEGRAL in device DomainLFIntegrator 2022-06-16 12:18:37 -07:00
Yohann Dudouit b81fa9f479 Rename TestSameMatrices to CompareMatricesNonZeros. 2022-06-16 09:49:54 -07:00
Yohann Dudouit c81506c238 Use random values instead of constant values. 2022-06-16 09:24:58 -07:00
Arturo Vargas a2c73fab47 move declaration of m_d_mt before Fnodes 2022-06-16 09:23:56 -07:00
YohannandDylan Copeland 9332beb87a Update linalg/operator.hpp
Co-authored-by: Dylan Copeland <dylancopeland@gmail.com>
2022-06-16 09:13:02 -07:00
Will Pazner 6d5403daab Remove unnecessary declarations 2022-06-16 09:06:10 -07:00
Dylan Copeland 1c7164a5b1 Adding more diagonal assembly tests and making the logic of the tests clearer. 2022-06-15 21:53:05 -05:00
Arturo Vargas 941262e9d3 use my_d_mt instead of d_mt in Fnodes 2022-06-15 18:54:38 -07:00
Will Pazner 5cfeb44ea2 Flatten tensors 2022-06-14 22:03:51 -07:00
Julian Andrej 513b4433b2 plz msvc 2022-06-14 17:25:41 -07:00
Yohann Dudouit 542bd7ecd8 Add note to EliminateRHS. 2022-06-14 17:24:51 -07:00
camierjs 2dd937d526 Reshape input vectors to D1D*(D1D-1)[(D1D-1)] 2022-06-14 16:14:53 -07:00
Julian Andrej c03554d7b0 remove restrict keyword 2022-06-14 15:34:05 -07:00
camierjs ddd5f51c29 Update SmemPAHdivMassApply kernels with tensors 2022-06-14 15:33:29 -07:00
Dylan CopelandandWill Pazner df8b66826b PR suggestion
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2022-06-14 17:05:57 -05:00
Julian Andrej ea45cda9bb include to get CI working 2022-06-14 14:33:23 -07:00
Julian Andrej 2f198f7e2d cmake build 2022-06-14 13:42:53 -07:00
Yohann Dudouit 8a88a7c7a4 Improve ParallelRAP documentation. 2022-06-14 13:01:29 -07:00
Yohann Dudouit 7a9462b41e Add check for device debug and hypre using GPU. 2022-06-14 12:56:04 -07:00
Yohann Dudouit 0ba5fd7e8a Fix A_diag ownership. 2022-06-14 12:46:01 -07:00
Julian Andrej 065b5f9fde add to makefile build system 2022-06-14 12:08:33 -07:00
Julian Andrej f04fdefd1a rework enzyme inclusion 2022-06-14 11:55:27 -07:00
Yohann Dudouit 28c512a2b9 Let A own even if it should not... 2022-06-14 11:52:26 -07:00
Yohann Dudouit 841fe38186 Try something else... 2022-06-13 19:11:29 -07:00
Yohann Dudouit 63b969754f Ownership mon amour... 2022-06-13 18:49:41 -07:00
Yohann Dudouit 2b21ebc361 Fix the fix of the fix. 2022-06-13 18:33:55 -07:00
Yohann Dudouit b9afa1fe99 Fix the fix. 2022-06-13 18:17:51 -07:00
Yohann Dudouit 664dc801d3 Fix bug. 2022-06-13 17:07:34 -07:00
Yohann Dudouit 5275b4926d Move HypreStealOwnership in hypre.hpp/cpp. 2022-06-13 15:47:02 -07:00
Yohann Dudouit 91c73f9481 Update CHANGELOG. 2022-06-13 11:21:34 -07:00
Yohann Dudouit e19ef66f80 Avoid shadowing in SparseMatrix. 2022-06-13 11:15:55 -07:00
Yohann Dudouit 94e763c272 Update documentation about diagonal policy. 2022-06-13 11:10:18 -07:00
Yohann Dudouit b3128b0897 Remove unnecessary header. 2022-06-13 10:59:54 -07:00
Yohann Dudouit fb7fdecb9f Use moved methods. 2022-06-13 10:59:38 -07:00
Yohann Dudouit 6ed5dfd1e6 Move EliminateBC in HypreParMatrix. 2022-06-13 10:58:47 -07:00
Yohann Dudouit 45d5bd70e1 Move ElimnateBC in SparseMatrix. 2022-06-13 10:57:56 -07:00
camierjs 3b1a806bc0 Update test_calcshape to avoid duplicate tests and sync test numbers with master 2022-06-13 10:05:27 -07:00
Julian Andrej 67e0beb41d change name to hooke 2022-06-13 09:22:51 -07:00
camierjs ae2b918ff6 Merge master in quiet-unit-tests 2022-06-13 09:21:45 -07:00
Julian Andrej ed8e6fc20d Merge github.com:mfem/mfem into enzyme-nonlinear 2022-06-13 09:04:52 -07:00
Will Pazner be121033ed Optimize for QuadratureFunctionCoefficient in VectorFEMassIntegrator::AssemblePA 2022-06-12 12:53:04 -07:00
Will Pazner 2d7938ed3e Optimized shared memory H(div) mass kernels 2022-06-12 12:52:15 -07:00
Yohann Dudouit 28bdb1a235 Remove incorrect doc. 2022-06-10 16:19:28 -07:00
Arturo Vargas c78e984d69 add additional guards to avoidusing diagT 2022-06-10 16:03:08 -07:00
Tzanio Kolev 26a18096d3 Merge pull request #3054 from mfem/artv3/convection-trace-orders
Add additional orders to conv + trace
2022-06-10 15:30:50 -07:00
Arturo Vargas ab64e55247 add cublas find to cmake 2022-06-10 14:16:07 -07:00
Arturo Vargas aee9379f34 disable hypre_ParCSRMatrixBooleanMatvecT and make style 2022-06-10 13:31:27 -07:00
Yohann Dudouit 3e40a30e5d Add sample runs with "fa" in ex1 and ex1p. 2022-06-10 11:33:54 -07:00
Yohann Dudouit 24b66d11cc Update CHANGELOG. 2022-06-10 11:28:14 -07:00
Socratis Petrides f40aa8985b parallel example 1D,3D support 2022-06-10 11:27:07 -07:00
Socratis Petrides 0917cebd10 adding support for 1D, 3D and AMR mesh 2022-06-10 11:16:39 -07:00
Ketan Mittal 5ac499ff34 fix bug when saving on rank != 0 2022-06-10 10:50:58 -07:00
Socratis Petrides 38c60734b6 fix typo, increase maxit in CG and remove slow sample run 2022-06-10 10:37:38 -07:00
Ketan Mittal 7d40cb822c functionality to get the serial mesh object on one of the ranks 2022-06-10 10:19:59 -07:00
Yohann Dudouit 3ed49a8ccf Merge remote-tracking branch 'origin/master' into yohann/fa-form-system 2022-06-10 10:18:15 -07:00
Ketan Mittal d7fbcda0fa refactoring 2022-06-10 10:05:37 -07:00
Arturo Vargas 45ee759dd7 Merge branch 'master' into artv3/hypre-opt/ParCSRMatrixLocalTranspose 2022-06-09 16:13:28 -07:00
Tzanio Kolev 6fee4044ef Merge pull request #3047 from mfem/has-sp-mat-elim
Add HasSpMatElim
2022-06-09 10:20:52 -07:00
Tzanio Kolev c6d8097500 Merge pull request #3062 from mfem/newton-summary
Fix no convergence output in Newton solver
2022-06-09 10:20:40 -07:00
Julian Andrej b13e1afad0 update changelog 2022-06-08 17:13:34 -07:00
Julian Andrej 9de38b3f2e Merge branch 'enzyme-nonlinear' of github.com:mfem/mfem into enzyme-nonlinear 2022-06-08 17:12:25 -07:00
Julian Andrej 3f3398f6de add glvis viz 2022-06-08 17:07:27 -07:00
Julian Andrej 6287639acc capitalization 2022-06-08 17:04:41 -07:00
Julian Andrej 91e6559d36 correct gradient type name 2022-06-08 17:04:28 -07:00
Julian Andrej c6d1f20249 Merge github.com:mfem/mfem into enzyme-nonlinear 2022-06-08 17:02:28 -07:00
Julian AndrejandTzanio Kolev a3d2b38f31 Update miniapps/elasticity/kernels/kernel_helpers.hpp
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2022-06-08 17:01:37 -07:00
Julian AndrejandTzanio Kolev 4de70fd432 Update miniapps/elasticity/kernels/kernel_helpers.hpp
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2022-06-08 17:01:31 -07:00
Julian AndrejandTzanio Kolev 71c167805d Update config/defaults.mk
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2022-06-08 17:01:08 -07:00
Julian AndrejandTzanio Kolev 6ef17443a4 Update CHANGELOG
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2022-06-08 17:01:00 -07:00
Julian AndrejandTzanio Kolev 67300f588d Update CHANGELOG
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2022-06-08 17:00:47 -07:00
Tzanio Kolev 26f37ac152 Merge branch 'master' into enzyme-nonlinear 2022-06-08 12:44:47 -07:00
Tzanio Kolev 9fd2fe536d Merge pull request #3060 from mfem/cmake-target-include-dirs
Solves cmake include directory ordering issue
2022-06-08 12:44:13 -07:00
Tzanio Kolev 777e352a76 Merge branch 'master' into enzyme-nonlinear
Conflicts:
	makefile
2022-06-08 11:23:44 -07:00
Will Pazner 4ea8883b23 Delete Vector::operator- and operator+ 2022-06-07 12:14:19 -07:00
Julian Andrej 23a8ffe384 update error message 2022-06-07 12:06:51 -07:00
Julian Andrej 5d110683f6 add missing comments 2022-06-07 12:04:03 -07:00
Will Pazner 7b36ff88a1 Fix no convergence output in Newton solver 2022-06-06 17:33:33 -07:00
Yohann Dudouit 255302eae6 Add forall.hpp in hypre.hpp. 2022-06-06 16:46:55 -07:00
Yohann Dudouit 07f8b8f525 Include "hypre.hpp". 2022-06-06 16:44:15 -07:00
Yohann Dudouit baea0cf188 Fix doc. 2022-06-06 16:32:20 -07:00
Yohann Dudouit aefc9068e0 Minor. 2022-06-06 16:09:15 -07:00
Yohann Dudouit 52137ea095 Add documentation to FABilinearFormExtension::EliminateBC. 2022-06-06 16:07:33 -07:00
Yohann Dudouit e131e0f3a6 Rename SerialEliminateBC and ParallelEliminateBC in EliminateBC. 2022-06-06 16:07:05 -07:00
Will Pazner 33cdfdcd6e Minor Doxygen edits 2022-06-06 15:57:28 -07:00
Yohann Dudouit 21dc848651 Factorize code between bilinearform_ext and lor. 2022-06-06 15:54:18 -07:00
Tom Stitt 1df33bfceb doc fix 2022-06-06 15:45:47 -07:00
Tom Stitt 26cc3465e2 adds SpMat and improves docs 2022-06-06 15:43:25 -07:00
Tom StittandWill Pazner b4787f3fff Update fem/bilinearform.hpp
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2022-06-06 15:24:45 -07:00
Yohann Dudouit 48f4efb5a5 Add a test for variable order using libCEED. 2022-06-06 14:09:26 -07:00
Yohann Dudouit 5218ea2649 Support variable polynomial order. 2022-06-06 14:08:56 -07:00
Arturo Vargas 976d64ff95 add cublas flag 2022-06-06 10:44:45 -07:00
camierjs cc86955b73 Solve cmake include directory ordering issue 2022-06-06 09:02:47 -07:00
Yohann Dudouit f4ce842065 Rename to prevent shadowing. 2022-06-03 13:08:12 -07:00
Yohann Dudouit ae27de9af2 Remove unused variable. 2022-06-03 12:20:56 -07:00
Yohann Dudouit 78cf39781d make style. 2022-06-02 17:09:44 -07:00
Will Pazner fdc0ed7cd7 Use GENERATE_COPY instead of GENERATE 2022-06-02 16:01:40 -07:00
Will Pazner 46a5b8cd81 Use verbose_tests global instead of hard-coded verbose or log flags 2022-06-02 15:34:34 -07:00
Will Pazner b2a7499cbf Add options to enable mfem::out test output and verbose mode
Also move global variable definitions to run_unit_tests.hpp to avoid duplication
in each test main cpp file.
2022-06-02 15:34:00 -07:00
Will Pazner 38d771af7c Use range in GENERATE 2022-06-02 15:33:00 -07:00
Yohann Dudouit 881d0be80a Merge remote-tracking branch 'origin/master' into yohann/mixed-mesh 2022-06-02 14:24:02 -07:00
Will Pazner 15de7d1352 Add unit tests README 2022-06-02 10:40:02 -07:00
Tzanio Kolev d3e94af7f1 Merge pull request #2952 from mfem/yohann/libCEED-refactor
Reorganize libCEED integration.
2022-06-02 09:49:38 -07:00
Will Pazner b8b0645195 Use CAPTURE and INFO for unit test output 2022-06-01 16:34:20 -07:00
Vladimir Z Tomov 47b42e9f7d SetOperator -> SetSolver 2022-06-01 16:22:58 -07:00
Arturo Vargas b7bd26fe50 add additional orders 2022-06-01 14:58:37 -07:00
Will Pazner c3d2bdaf19 Include mfem::out and mfem::err output in unit tests only with -s flag 2022-06-01 14:51:15 -07:00
Ketan Mittal 8f328237ab remove shadow variable 2022-06-01 09:45:39 -07:00
Ketan Mittal 6872f7bee6 CHANGELOG 2022-06-01 08:52:34 -07:00
Ketan Mittal eed10fe35b remove unused variable 2022-05-31 13:56:59 -07:00
Ketan Mittal cdcc3339d6 fix computation of initial energy in miniapps 2022-05-31 13:42:45 -07:00
Ketan Mittal c911247ee3 Merge branch 'master' of https://github.com/mfem/mfem into tmop-metrics 2022-05-31 11:48:15 -07:00
Ketan Mittal bc546dc598 make worst case metric inherit from untangling metric 2022-05-31 11:48:03 -07:00
YohannandTzanio Kolev 3916f7dabf Update miniapps/toys/mandel.cpp
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2022-05-31 11:33:23 -07:00
Will Pazner e3aa89f6fa Merge pull request #3004 from adam-sim-dev/wd4819
Disable C4819 warnings for building on Windows using Visual Studio
2022-05-31 11:16:19 -07:00
Will Pazner 716af52129 Merge pull request #2879 from mfem/talgoim
Support for the Algoim library [talgoim]
2022-05-31 11:15:51 -07:00
Tzanio Kolev a740c51819 Merge pull request #3034 from mfem/linext-tsip
Linear form extension ElementTransformation SetIntPoint fix [linext-tsip]
2022-05-30 21:52:01 -07:00
Tzanio Kolev 8cf4f4bde6 Merge pull request #2948 from mfem/gslib-mixed-meshes
Support for pyramids and mixed meshes for FindPointsGSLIB
2022-05-30 21:51:32 -07:00
Tobias Duswald e91c582d03 Apply changes from review
Co-authored-by:
brendankeith <keith10@llnl.gov>
Co-authored-by: psocratis <petrides1@llnl.gov>
2022-05-27 18:04:57 -07:00
Arturo Vargas d539dc6fb3 optimize At application 2022-05-27 17:38:44 -07:00
Ketan Mittal cb0d8a7af6 wordsmithing 2022-05-27 10:35:47 -07:00
Ketan Mittal e25eb36d29 Merge branch 'master' of https://github.com/mfem/mfem into tmop-metrics 2022-05-27 10:06:05 -07:00
Tzanio Kolev 9ca8a44c4a Merge pull request #3040 from mfem/mpi_session_fix
Replace `MPI_Session` with `Mpi::Init`
2022-05-27 09:20:43 -07:00
Tobias Duswald 863638bb47 Make serial and parallel example identical 2022-05-26 17:36:05 -07:00
Tobias Duswald c9685df178 Update ex33p to new logic 2022-05-26 17:35:40 -07:00
Tom Stitt 0999fddcab Add HasSpMatElim to check if mat_e is null. Useful check before trying to use SpMatElim, which will fail if mat_e is null 2022-05-26 15:55:54 -07:00
Tom Stitt d1b4d38e5d revert non-specialized called
add more specializations
2022-05-26 14:18:53 -07:00
Julian Andrej 178ceeeaa3 rename methods 2022-05-26 10:30:47 -07:00
Julian Andrej d1cf744f06 clarify neohookean model restriction to 3D 2022-05-26 10:25:41 -07:00
Julian Andrej 4c7b9989d9 clarify symbolic comment 2022-05-26 10:24:54 -07:00
Tobias Duswald d59281d801 Astyle Format 2022-05-25 16:28:12 -07:00
Tobias Duswald 043b338fee Add explanation for computation of coefficients 2022-05-25 16:26:32 -07:00
Tobias Duswald 83074c4c0a Generalize ex33 to alpha > 0 2022-05-25 16:19:10 -07:00
Tom Stitt 9d204c8d81 rename based on pr comments 2022-05-25 12:16:06 -07:00
Tom StittandYohann e237f942e8 Apply suggestions from code review
Co-authored-by: Yohann <dudouit1@llnl.gov>
2022-05-25 12:12:39 -07:00
Ketan Mittal 32f4c4f88e documentation and fixed typo 2022-05-25 11:35:54 -07:00
Tzanio Kolev 921298317c Merge pull request #2998 from mfem/gslib-par-bug
GSLIB bug fix in InterpolateGeneral
2022-05-25 08:59:20 -07:00
Will Pazner 59523357ea Merge remote-tracking branch 'origin/master' into wd4819
# Conflicts:
#	CMakeLists.txt
2022-05-24 21:48:09 -07:00
Veselin Dobrev 55e5002c58 In navier_turbchan.cpp, switch to Mpi::Init() instead of
MPI_Session similar to all other examples and miniapps.
2022-05-24 19:21:30 -07:00
Tom Stitt 185f63bdc5 add and use shared memory version of FaceQuadratureInterpolator::Eval3D to avoid large runtime allocations due to scratch memory usage 2022-05-24 19:20:21 -07:00
Tzanio Kolev 00493be395 Typo 2022-05-24 16:57:58 -07:00
Stowell, Mark L a78ca4eea9 Merge branch 'master' into yohann/libCEED-refactor 2022-05-24 14:26:19 -07:00
Ketan Mittal c9ddefd68a fix VLA issue 2022-05-24 11:22:34 -07:00
Ketan Mittal 0b7980091e minor 2022-05-24 10:48:00 -07:00
Yohann Dudouit 6bb1aaba5d Refactor RAP and EliminateBC in FABilinearFormExtension 2022-05-24 10:29:48 -07:00
camierjs 5434bc61e5 Linear form extension ElementTransformation SetIntPoint fix 2022-05-24 09:47:17 -07:00
blaz 9af32f09b5 Merge branch 'talgoim' of https://github.com/mfem/mfem into talgoim 2022-05-23 20:05:03 -07:00
blaz 64da28ff89 cmake - remove MFEM_USE_BLITZ 2022-05-23 20:03:54 -07:00
Dylan Copeland 079f9cce33 Generalized diagonal assembly. 2022-05-23 19:42:09 -07:00
Dylan Copeland 244719c39c Generalized coefficient support for H(div) mass integrator, with unit tests. 2022-05-23 16:43:54 -07:00
Tzanio Kolev 80033b00f9 Merge pull request #3022 from mfem/yohann/remove-mesh-operators-warning
Remove conversion warning from `double` to `int`.
2022-05-20 07:34:51 -07:00
Ketan Mittal 76c7dd9bd8 Merge branch 'master' into gslib-mixed-meshes 2022-05-19 15:26:18 -07:00
Ketan Mittal ac1511d400 sample run for mixed mesh with -hr and -pr option 2022-05-19 15:21:02 -07:00
Will Pazner a1c905b6ee Remove unit test output 2022-05-19 14:54:21 -07:00
Yohann Dudouit fe300a678a Add an explicit cast to avoid warning. 2022-05-19 13:49:33 -07:00
Yohann Dudouit bd11e84eed Remove convertion warning from double to int. 2022-05-19 13:27:22 -07:00
Yohann Dudouit ff1bf46376 Update CMake install for libCEED. 2022-05-19 12:32:35 -07:00
Yohann Dudouit 54c1073f4c Minor simplification. 2022-05-19 12:21:01 -07:00
Ketan Mittal 78458fed0a minor 2022-05-19 11:13:20 -07:00
Ketan Mittal 8497117c61 Merge branch 'master' of https://github.com/mfem/mfem into pmesh-to-serial-mesh 2022-05-19 10:58:55 -07:00
Ketan Mittal d2753a59b0 clean up 2022-05-19 09:18:19 -07:00
Ketan Mittal 6e16d5b7bf minor 2022-05-18 17:31:11 -07:00
Ketan Mittal f273e9b04f make style 2022-05-18 17:28:17 -07:00
Ketan Mittal cb731d4f1a working for surface meshes 2022-05-18 17:28:01 -07:00
Ketan Mittal 7d1b925438 initial commit 2022-05-18 16:10:50 -07:00
Tzanio Kolev 6e82a1953b Merge branch 'master' into enzyme-nonlinear
Conflicts:
	tests/benchmarks/makefile
2022-05-18 14:05:21 -07:00
Tzanio Kolev e5cd867ec7 Merge pull request #2973 from mfem/windows-ci-dev
Windows CI
2022-05-18 13:52:54 -07:00
Tzanio Kolev b4fa1aa4e4 Merge pull request #2947 from mfem/yohann/bench-assembly-levels
A benchmark for the different levels of assembly inspired by the CEED benchmark.
2022-05-17 22:00:49 -07:00
Max Yang ebb903a6b4 Remove completed TODOs, update dependency cache tags 2022-05-17 20:52:44 -07:00
Tzanio Kolev afa0a11256 Updated CHANGELOG and README 2022-05-17 19:32:35 -07:00
Tzanio Kolev f80a366ec9 Switched to mfem/github-actions@v2.2 actions 2022-05-17 19:05:39 -07:00
Yohann Dudouit eb0882ed94 Use device version of BC elimination. 2022-05-17 17:46:05 -07:00
Yohann Dudouit 0a051d9428 Add serial test. 2022-05-17 17:45:32 -07:00
Yohann Dudouit 4104e010d5 Add RAP and EliminateBC methods. 2022-05-17 16:55:29 -07:00
Arturo Vargas d9d01bdf5b enable the use of custom allocators for dg trace integrator 2022-05-17 16:13:36 -07:00
Yohann Dudouit beaaa373ee Merge remote-tracking branch 'origin/fa-hypre-par-matrix' into yohann/fa-form-system 2022-05-17 16:12:02 -07:00
Arturo Vargas 80f8a57a43 actually use my_d_mt in face geometric factors 2022-05-17 15:48:44 -07:00
Arturo Vargas c7df56044c Merge branch 'master' into artv3/umpire-mem-for-face-geo-facts 2022-05-17 15:44:22 -07:00
Arturo Vargas 4ffd22a8ec PR review comments 2022-05-17 15:43:50 -07:00
vsoch 65f3507406 add DEBIAN_FRONTEND=noninteractive
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-05-17 16:38:08 -06:00
Yohann Dudouit cd161542b3 Remove dead code. 2022-05-17 15:35:19 -07:00
Yohann Dudouit 17ef5ae043 FABilinearFormExtension::FormSystemMatrix and FABilinearFormExtension::FormLinearSystem finally working but give wrong results. 2022-05-17 15:33:08 -07:00
vsoch 654a070e12 fix build context to be config/docker
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-05-17 15:50:23 -06:00
vsoch 979954402b ensure pull request tests build
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-05-17 15:32:22 -06:00
Max Yang a85e3a92e7 Remove unused step 2022-05-17 13:45:39 -07:00
Max Yang cea53ca6e9 Trying to fix appveyor: add msmpi paths manually 2022-05-17 13:30:48 -07:00
Max Yang b4fb8a0ee5 Trying to fix appveyor: remove more mpi paths 2022-05-17 13:22:52 -07:00
Max Yang 6dd9ae8710 Bump appveyor windows vm version 2022-05-17 13:13:31 -07:00
Max Yang 533bfa2c10 Trying to fix appveyor: use absolute metis path, remove mpi paths 2022-05-17 13:00:17 -07:00
Max Yang 7ca6127412 Debugging appveyor 2022-05-17 12:41:08 -07:00
Ketan Mittal d1189500e8 Merge branch 'master' into gslib-mixed-meshes 2022-05-17 11:33:10 -07:00
Ketan Mittal 0e79554abb Merge branch 'gslib-mixed-meshes' of https://github.com/mfem/mfem into gslib-mixed-meshes 2022-05-17 11:31:44 -07:00
Ketan Mittal fe2c508e66 typos 2022-05-17 11:31:30 -07:00
YohannandJean-Sylvain CAMIER d3a86a6fc5 Update tests/benchmarks/bench_assembly_levels.cpp
Co-authored-by: Jean-Sylvain CAMIER <camier1@llnl.gov>
2022-05-17 10:41:40 -07:00
Max Yang a9ec4da11c Place metis and hypre outside of mfem source directory 2022-05-17 10:38:58 -07:00
Max Yang 81fe4ce350 Restore appveyor.yml 2022-05-17 10:23:53 -07:00
Max Yang 72be8e1c2e Merge branch 'master' into windows-ci-dev 2022-05-17 10:06:40 -07:00
Max Yang 37510c886b Split hypre job into windows-specific job 2022-05-17 10:05:49 -07:00
blaz e49241697e clean the paraview files 2022-05-16 19:16:41 -07:00
blaz 5d198063fe style 2022-05-16 18:32:09 -07:00
blaz aabc91bac1 more changes 2022-05-16 18:30:11 -07:00
blaz 81c2d1e62d Merge branch 'talgoim' of https://github.com/mfem/mfem into talgoim 2022-05-16 18:25:52 -07:00
blaz 77815d4a17 small changes 2022-05-16 18:25:39 -07:00
Vladimir Z Tomov 07f8a57592 Minor edits. 2022-05-16 18:24:55 -07:00
Veselin Dobrev 116e0edb82 Merge pull request #3001 from mfem/repo-check-dev
Improved repo-check test [repo-check-dev]
2022-05-16 15:10:50 -07:00
vsoch bc5fbe767f adding multistage-build for slimmer container
I am currently running into an issue where when I shell inside my backspace turns
into a forward space, and I am hoping someone can reproduce to determine if there
is a bug we need to track down or if I am just a nut :)

Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-05-16 15:20:26 -06:00
Yohann Dudouit 333e7dc512 Merge branch 'master' into yohann/fa-form-system 2022-05-16 13:53:50 -07:00
Will Pazner aef972353a Merge pull request #3002 from mfem/simplify_ex18
[Simplify] Remove redundant class in ex18
2022-05-16 08:58:29 -07:00
Tzanio Kolev 610db2ded2 Merge pull request #2969 from mfem/project-div-integrated-gll
Add ProjectDiv for L2 IntegratedGLL basis
2022-05-15 19:11:30 -07:00
Yohann Dudouit 43ae57c3b3 Fix make install 2022-05-13 12:23:10 -07:00
YohannandTzanio Kolev d2b9ba3cd9 Update CHANGELOG
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2022-05-13 10:28:17 -07:00
YohannandTzanio Kolev d0d39330c1 Update tests/benchmarks/makefile
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2022-05-13 10:28:01 -07:00
blaz 896faa00ce compilation fix 2022-05-13 10:22:46 -07:00
Tzanio Kolev 646217d3bd Merge pull request #2981 from researchapps/add/docker-build-for-demo
feature: adding demo container and automated builds for mfem
2022-05-13 07:42:05 -07:00
Tzanio Kolev 9ad6dd49ce Merge pull request #2945 from mfem/gslib-test-fix
Fix tests for gslib miniapps
2022-05-13 07:40:48 -07:00
Tzanio Kolev 6c89a3da24 minor 2022-05-12 16:02:31 -07:00
Will Pazner e55bc02e65 Merge pull request #2986 from mfem/ex10_pause
Notification of GLVis visualization pause in Example 10
2022-05-12 14:40:55 -07:00
Yohann Dudouit a3067ead11 Rename file, improve documentation and function names. 2022-05-12 10:34:53 -07:00
adam-sim-dev 27b633240c Disable C4819 warnings for building on Windows using Visual Studio 2022-05-12 09:44:09 +08:00
Ketan Mittal f04b6a467e computation of quantiles for untangler 2022-05-11 08:50:27 -07:00
Tzanio Kolev b30b091ae9 wrap long lines in repo-check if statements, take 2 2022-05-10 17:17:15 -07:00
Tzanio Kolev fc6431519e wrap long lines in repo-check if statements 2022-05-10 17:13:44 -07:00
VanessasaurusandTzanio Kolev 0502fb134f naked workflow_dispatch
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2022-05-10 17:49:05 -06:00
Keith afa9ddac83 remove redundant class in ex18 2022-05-10 16:45:56 -07:00
Veselin Dobrev 9f9b943a7b A few tweaks for GSLIB tests: for CMake and out-of-source builds. 2022-05-10 16:16:07 -07:00
Tzanio Kolev 86504ea370 Added the option to manually trigger all workflows 2022-05-10 16:14:31 -07:00
Yohann Dudouit f2c4dce655 Fix path to qFunctions. 2022-05-10 15:12:49 -07:00
Tzanio Kolev a0a15ba9a1 Run repo-check on both pushes and PR updates, skipping duplicate runs 2022-05-10 14:49:11 -07:00
Ketan Mittal f3fe49a07c computation of min det(T) and max mu(T) clean up 2022-05-10 13:42:41 -07:00
Yohann Dudouit fb219d9e9f Merge branch 'master' into yohann/libCEED-refactor 2022-05-10 10:11:52 -07:00
vsoch f0d4f17a92 final tweaks to text in README!
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-05-10 10:32:58 -06:00
vsoch c498568caa resolving conflict in changelog
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-05-10 10:32:07 -06:00
vsoch 79795eb9e5 tweaks to readmes for docker and main readme
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-05-10 10:30:57 -06:00
Ketan Mittal 7f1e9aca34 minor 2022-05-10 08:00:20 -07:00
Tzanio Kolev c41998d9be Merge branch 'master' into gslib-mixed-meshes 2022-05-10 07:51:44 -07:00
blaz ad6a5bdce4 small fix 2022-05-09 12:23:02 -07:00
blaz b39ca1071e small fix 2022-05-09 12:21:25 -07:00
Ketan Mittal a8337fbf92 update INSTALL 2022-05-09 11:18:52 -07:00
Ketan Mittal 4f29945a1d add blitz dependency 2022-05-09 11:18:45 -07:00
Ketan Mittal 634519cc89 minor fix 2022-05-09 11:03:06 -07:00
Ketan Mittal 7d8877de64 sample runs for serial miniapp and minor fix 2022-05-09 11:00:41 -07:00
Ketan Mittal 7947c5f2de update to use new metrics 2022-05-09 10:57:56 -07:00
Ketan Mittal b58a6b599f calculate parameter for worst-case metric 2022-05-09 10:57:43 -07:00
Ketan Mittal 0b653bc3cd add shifted barrier and worst-case metric 2022-05-09 10:57:21 -07:00
vsoch 38eac8e1f1 remove trailing whitespace
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-05-08 17:16:40 -06:00
vsoch 87a937ab61 updating docker example to run automata with -no-vis
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-05-08 17:16:03 -06:00
blaz 3af8845583 Merge branch 'talgoim' of https://github.com/mfem/mfem into talgoim 2022-05-07 23:33:46 -07:00
blaz d336f7b348 gitingnore 2022-05-07 23:32:59 -07:00
blaz fa4af62911 style 2022-05-07 18:43:24 -07:00
blaz cd721c10dc added sample runs 2022-05-07 18:38:46 -07:00
blaz 6d3e374b92 algoim test renamed to lsf_integral 2022-05-07 18:30:46 -07:00
blaz 43a0fb7de1 added default lines 2022-05-07 18:29:55 -07:00
Ketan Mittal d3e484d67a add another level set example 2022-05-06 17:41:51 -07:00
Ketan Mittal e72dba2320 Merge branch 'gslib-mixed-meshes' of https://github.com/mfem/mfem into gslib-mixed-meshes 2022-05-06 16:36:19 -07:00
Ketan Mittal 4e414ecfa3 add boundary elements to the mesh 2022-05-06 16:36:03 -07:00
Ketan Mittal 761fe546e0 Merge branch 'master' into gslib-mixed-meshes 2022-05-06 16:09:21 -07:00
Ketan Mittal ff3352c138 Merge branch 'gslib-mixed-meshes' of https://github.com/mfem/mfem into gslib-mixed-meshes 2022-05-06 16:08:35 -07:00
Ketan Mittal 6428ea6ff9 add sample run with new mixed mesh 2022-05-06 16:08:21 -07:00
Ketan Mittal 34da2b7067 add mixed mesh with all 4 3D element types 2022-05-06 16:08:06 -07:00
Max Yang cc3d4f9bff Pass build system option to hypre action 2022-05-06 14:43:57 -07:00
Ketan Mittal 680e3b4451 fix gslib bug for InterpolateGeneral when ncomp>1 and some points were not found 2022-05-06 13:05:08 -07:00
blaz ec3ad4a4db bug-fix 2022-05-05 15:01:27 -07:00
blaz 9cd52233d8 bug-fix 2022-05-05 14:24:00 -07:00
blaz 8a16bde0d9 modified to avoid test errors 2022-05-05 14:06:54 -07:00
blaz 241b89b1ca Added specific instructions for Algoim v1 2022-05-05 13:29:23 -07:00
blaz 8fe876fd45 Revert to Algoim 1 2022-05-05 12:27:34 -07:00
blaz c986685157 does not require algoim lib to be defined 2022-05-04 22:02:21 -07:00
blaz 78e500b210 style and small code modifications 2022-05-04 21:52:44 -07:00
blaz 31b6f9a949 cleaned code left from other branches 2022-05-04 21:35:56 -07:00
blaz 701d0c56de comparison with MFEM integration 2022-05-04 21:29:47 -07:00
blaz 0b91ed131a fixes for makefile compilation without the algoim library 2022-05-04 19:07:41 -07:00
blaz 45dcea96a9 Merge branch 'master' into talgoim 2022-05-04 17:11:16 -07:00
Max Yang 1090002199 Change hypre cache entry 2022-04-30 13:10:47 -07:00
Max Yang 60c1c3b263 Revert to custom hypre build for Windows 2022-04-30 13:08:49 -07:00
vsoch 9cb757d7c0 clean up white spaces
I tested installing glvis, and since it requires llvm it is not
only long, but also can freeze your computer (depending on resources).
So my suggestion is that we use a base image where this build has already
happened and keep the base image here simple

Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-04-30 01:12:49 -06:00
Max Yang 2cb44d0858 Try to fix quotations when adding extra config 2022-04-29 23:49:21 -07:00
Max Yang 6fae0af65d Use vcpkg-supplied lapack for parallel Windows jobs 2022-04-29 18:33:16 -07:00
vsoch 8be4ab8d24 updating README to README.md to be able to link to docker
and moving docker config into config/docker so it renders nicely!

Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-04-29 18:50:04 -06:00
vsoch 9a57c46a67 tweaks to change #->$ and other details in README-DOCKER
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-04-29 18:46:38 -06:00
vsoch 493455d2e8 suggested change needed to have double quotes
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-04-29 18:05:53 -06:00
vsoch d5e53b05d8 review comments - tweaks to DOCKER-README and location of Dockerfile
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-04-29 18:04:16 -06:00
VanessasaurusandTzanio Kolev 9879cb6286 Update .github/workflows/build-container.yaml
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2022-04-29 17:05:04 -06:00
Max Yang 676a517ac4 Some fixups 2022-04-29 15:21:42 -07:00
Max Yang d0a9975ed9 Temporarily retag hypre/metis caches 2022-04-29 15:11:43 -07:00
Max Yang 7306d8232b Use vcpkg to install hypre for Windows 2022-04-29 15:08:03 -07:00
Max Yang cc34595c12 Use library only build for debug targets to save space 2022-04-28 16:55:31 -07:00
Max Yang 83521be2ed Disable full tests for ubuntu cmake build 2022-04-28 15:55:30 -07:00
Cheung ef85361108 fixing code-style 2022-04-28 15:13:19 -07:00
Cheung b27f23b2eb Notify user about pause 2022-04-28 15:04:31 -07:00
Max Yang 5e7068c5c2 Add missing shell specifiers 2022-04-28 11:48:32 -07:00
Max Yang 593dfa9576 Enable cmake checks/tests on Windows builds 2022-04-28 11:30:00 -07:00
Max Yang 1211ffa747 Merge branch 'master' into windows-ci-dev 2022-04-28 11:15:46 -07:00
Max Yang 6c15135c01 Use mpi-aware cache key 2022-04-28 10:42:00 -07:00
Max Yang 7005c6d309 Some fixups 2022-04-28 10:37:44 -07:00
Max Yang 4105ca8682 Update tags for cache on analysis workflow 2022-04-28 10:33:46 -07:00
Max Yang 98ba78232b Remove appveyor test for windows 2022-04-28 10:31:32 -07:00
Max Yang 73110ccc9d Try to install metis 5 with vcpkg 2022-04-27 23:44:41 -07:00
Max Yang 40afdd27a2 Add default metis build system parameter 2022-04-27 23:01:07 -07:00
Max Yang 79bd683456 Use cmake when building with metis 5 2022-04-27 22:49:33 -07:00
Max Yang ec70b61e7b Fixup metis 5 environment vars generation 2022-04-27 22:43:28 -07:00
Max Yang b77355da6b Fixup 2022-04-27 22:35:52 -07:00
Max Yang 1e58ee0f8f Use metis 5 for windows builds 2022-04-27 22:34:25 -07:00
Max Yang 2fe67469af Revert "Use relative paths for hypre"
This reverts commit f6d3b55a57.
2022-04-27 17:27:35 -07:00
Max Yang f6d3b55a57 Use relative paths for hypre 2022-04-27 17:07:39 -07:00
Max Yang 4771d56b16 Use mpi4py msmpi installer 2022-04-27 16:48:15 -07:00
Max Yang ca57dba8e9 Update to ubuntu 20.04 runners 2022-04-27 16:17:33 -07:00
Max Yang c52c37928f Fix matrix 2022-04-27 16:14:28 -07:00
Max Yang 1e0d43c3d0 Change cache tag for hypre 2022-04-27 16:06:05 -07:00
Yohann Dudouit ecf3c10c08 Add support for FA in ex1 and ex1p. 2022-04-27 15:20:36 -07:00
Yohann Dudouit e3297d9e91 Attempt to implement FormLinearSystem and FormSystemMatrix. 2022-04-27 15:20:07 -07:00
Max Yang 3df049ff16 Update paths for build-metis, build-hypre actions 2022-04-27 14:55:10 -07:00
Max Yang 5ea48b315e Fix msmpisdk path 2022-04-27 14:51:44 -07:00
Max Yang 7f9ce35de1 Fix powershell download command, only download mpi on parallel jobs 2022-04-27 14:49:16 -07:00
Max Yang efe756cf6e Fix job matrix 2022-04-27 14:45:18 -07:00
Max Yang 0c8b3cfddf Attempting to add MPI-enabled windows actions 2022-04-27 14:35:23 -07:00
vsoch 891a1a8c76 dockerfile: remove un-needed sw4 install from previous container test
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-04-27 12:27:57 -06:00
vsoch cd444e75f3 dockerfile: remove un-needed sw4 install from previous container test
Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-04-27 12:27:06 -06:00
vsoch 4501b42ab6 feature: adding demo container and automated builds for mfem
as discussed, this is a simple container build to provide mfem in spack, and then
show example of running examples and miniapps. This is paired with an automated build
so we always have an updated container base. This container setup can be extended to include
other kinds of builds, or other use cases

Signed-off-by: vsoch <vsoch@users.noreply.github.com>
2022-04-26 19:50:01 -06:00
Yohann Dudouit 7b70e27f1f alphabetical order. 2022-04-26 09:39:28 -07:00
Tzanio Kolev 353f5b7d5d Update CHANGELOG 2022-04-25 08:22:32 -07:00
Will Pazner a25650fb14 Add using statement to fix warning with nvcc 2022-04-25 07:59:12 -07:00
Max Yang b05761093c Select config for ctest on Windows 2022-04-22 11:51:41 -07:00
Max Yang faa5aab288 Use target_include_directories() to propagate includes to subprojects 2022-04-22 11:21:29 -07:00
Max Yang e156c69b1a Make unit tests a subproject to enable all-build on Windows 2022-04-20 16:05:02 -07:00
Max Yang bc035b8a2b Use fork of mfem github actions 2022-04-20 15:59:36 -07:00
Max Yang 7536ebe177 Add windows gh action runners 2022-04-20 15:59:13 -07:00
Yohann Dudouit 30abbd417a Add entry to CHANGELOG. 2022-04-20 11:25:59 -07:00
Will Pazner f8b7be7137 Add some consts 2022-04-19 12:23:17 -07:00
Will Pazner 11375da69a Support map type INTEGRAL for the test space in VectorFEDivergenceIntegrator 2022-04-15 11:54:20 -07:00
Will Pazner af02170c00 Bugfix: set ScaleIntegrated before calling Eval with IntegratedGLL basis
Because the Poly_1D::Basis1D are cached and shared between finite element
spaces/collections, the *same* Basis object can be used in finite elements with
different map types (e.g. VALUE, INTEGRAL, H_CURL, or H_DIV). This means that
setting ScaleIntegrated when the map type is set will not always give correct
results. To fix this, we need to make sure that ScaleIntegrated is set correctly
before every call to EvalIntegrated.
2022-04-15 11:33:31 -07:00
Will Pazner 5967224259 Support projecting coefficients onto L2 elements with IntegratedGLL basis 2022-04-15 11:05:11 -07:00
Will Pazner 0b5d50da32 Remove check for nodal basis in L2_TetrahedronElement constructor
This allows creating 3D L2 finite element collections with IntegratedGLL basis
type.
2022-04-15 09:24:54 -07:00
Will Pazner 17bce1a92d Add ProjectDiv for L2 elements with IntegratedGLL basis 2022-04-15 09:24:10 -07:00
Will Pazner 107b5c236e Compare RHS vectors in assembly level unit test 2022-04-14 16:39:24 -07:00
Ketan Mittal 3fb4e88f2b Merge branch 'gslib-mixed-meshes' of https://github.com/mfem/mfem into gslib-mixed-meshes 2022-04-12 12:58:43 -07:00
Ketan Mittal 1bce66fc91 Merge branch 'master' of https://github.com/mfem/mfem into gslib-mixed-meshes 2022-04-12 12:57:17 -07:00
Ketan Mittal e1b9622d60 update CHANGELOG 2022-04-12 12:57:05 -07:00
Tzanio 236bd3eb55 Merge branch 'master' into gslib-test-fix 2022-04-11 14:06:06 -07:00
Tzanio 609e954e41 Merge branch 'master' into gslib-mixed-meshes 2022-04-11 14:05:16 -07:00
Yohann Dudouit 2cbe41f37d Merge branch 'master' into yohann/libCEED-refactor 2022-04-11 14:05:14 -07:00
Yohann Dudouit 7ebc606f16 Merge branch 'master' into yohann/libCEED-refactor 2022-04-11 11:52:58 -07:00
Yohann Dudouit 6e56564b2c Remove unused namespace. 2022-04-11 11:45:05 -07:00
Yohann Dudouit 460fa618fb Move #ifdef out of namespace. 2022-04-11 11:44:03 -07:00
Ketan Mittal c031260510 Merge branch 'master' of https://github.com/mfem/mfem into gslib-mixed-meshes 2022-04-11 11:41:03 -07:00
Ketan Mittal 4e821b139b fix double curly braces 2022-04-11 11:38:59 -07:00
Yohann Dudouit 819712212a Refactor ceed.hpp. 2022-04-11 11:38:44 -07:00
Yohann Dudouit 6fe7e0f8b8 Remove cast operator. 2022-04-11 11:37:00 -07:00
Ketan Mittal 370b2ef64b minor 2022-04-11 11:36:53 -07:00
Yohann Dudouit 06fd125d85 Revert public default constructor for PAIntegrator. 2022-04-11 11:35:33 -07:00
Yohann Dudouit 5239c10c1c Remove unnecessary forward declaration. 2022-04-11 11:28:47 -07:00
Yohann Dudouit f8ce8fe5c0 Indent makefile 2022-04-11 11:02:46 -07:00
Yohann Dudouit 7f58074e97 Add documentation. 2022-04-06 17:30:36 -07:00
Yohann Dudouit 81178ac5fd Add destructor for MixedIntegrator. 2022-04-06 16:43:35 -07:00
Yohann Dudouit 021e39e537 Remove newline. 2022-04-06 16:32:30 -07:00
Yohann Dudouit 3456950640 Verify integrators are used correctly. 2022-04-06 16:31:23 -07:00
Yohann Dudouit 79e352c460 Remove debugging code. 2022-04-06 16:11:40 -07:00
Yohann Dudouit 3c6210d83a Test NLConvection on mixed meshes. 2022-04-06 16:04:26 -07:00
Yohann Dudouit fbf563955d Split Convection tests and test mixed meshes. 2022-04-06 16:03:36 -07:00
Yohann Dudouit 9a72bced50 Fix bugs in MF NLConvection QFunctions. 2022-04-06 16:02:41 -07:00
Yohann Dudouit b5025ea8b0 Add mixed mesh support to MF NLConvection. 2022-04-06 16:02:09 -07:00
Yohann Dudouit d1a5ffa822 Add mixed mesh support to MF Convection. 2022-04-06 16:01:19 -07:00
Yohann Dudouit 82b32e9a30 Clean a bit MixedIntegrator. 2022-04-06 16:00:09 -07:00
Yohann Dudouit a6cd361884 Add mixed mesh tests to "CEED mass & diffusion". 2022-04-06 11:46:16 -07:00
Yohann Dudouit 15c481f52e Add support for mixed meshes to ceed:MFIntegrator. 2022-04-06 11:45:39 -07:00
Yohann Dudouit 3404d4c938 Wrap "WithIndices" functions to generalize code. 2022-04-06 11:12:28 -07:00
Yohann Dudouit 29d1803362 Avoid applying restriction two times... 2022-04-06 10:11:29 -07:00
Yohann Dudouit e5bcaaffb7 Fix bugs in InitCoefficientWithIndices. 2022-04-05 17:33:03 -07:00
Yohann Dudouit 41e90576de Add support for mixed mesh to VectorMass. 2022-04-05 17:32:36 -07:00
Yohann Dudouit 9c4021e35b Add mixed mesh support to VectorDiffusion. 2022-04-05 17:31:32 -07:00
Yohann Dudouit 2530418b8c Switch between MixedPA and PA. 2022-04-05 17:30:57 -07:00
Yohann Dudouit cd5c8571af Add support for mixed meshes to ConvectionIntegrator. 2022-04-05 16:31:17 -07:00
Julian Andrej 0eb2d04854 make enzyme variables extern 2022-04-05 15:50:09 -07:00
Yohann Dudouit 81c951a8b8 Refactor ceed/restriction.cpp.
- Fix bugs on L2.
2022-04-05 15:41:28 -07:00
Yohann Dudouit 8b8141020d Add InitCoeffRestrictionWithIndices.
- Add `restr_type::Coeff`.
- Fix `QuadCoefficient` on mixed meshes.
2022-04-05 15:40:25 -07:00
Julian Andrej c9f5103796 correct includes 2022-04-05 15:32:37 -07:00
Yohann Dudouit 5b96b41815 Remove unnecessary IntegrationRule in InitRestriction. 2022-04-05 14:11:47 -07:00
Yohann Dudouit 482a7f84ea Add support for QuadratureFunctionCoefficient on mixed meshes. 2022-04-05 12:24:48 -07:00
Yohann Dudouit f188b9eebc Simplify restriction.cpp. 2022-04-04 14:20:17 -07:00
Yohann Dudouit 80ddc79123 Factorize code in basis.cpp. 2022-04-04 13:55:10 -07:00
Yohann Dudouit 31005dda60 More fixes to the path... 2022-04-04 13:10:45 -07:00
Yohann Dudouit bd7b0a2c06 Fix libCEED GPU path. 2022-04-04 13:06:47 -07:00
Yohann Dudouit 4e1e6531f3 Add mixed mesh support for DiffusionIntegrator. 2022-04-04 12:18:09 -07:00
Yohann Dudouit 6223000e9a Add a generic GetRule function. 2022-04-04 12:17:27 -07:00
Yohann Dudouit ec689e5d33 Fix InitBasisWithIndices. 2022-04-04 12:16:13 -07:00
Yohann Dudouit f1c472dc20 Add support for pyramids. 2022-04-01 13:52:41 -07:00
Yohann Dudouit 5fe0d860d7 Avoid building ElementRestriction when using CEED. 2022-04-01 13:42:25 -07:00
Yohann Dudouit accae8301b Fix check for tensor element. 2022-04-01 13:41:47 -07:00
Yohann Dudouit 13e0a2da4a Reorder headers. 2022-03-31 18:36:36 -07:00
Yohann Dudouit 3cf17a01fa more... 2022-03-31 18:35:24 -07:00
Yohann Dudouit 352f2a78c1 Even more mixed. 2022-03-31 18:32:54 -07:00
Yohann Dudouit f141a63f08 Add doc. 2022-03-31 18:32:01 -07:00
Yohann Dudouit 9d64363c0c Remove more mixed stuff. 2022-03-31 18:31:35 -07:00
Yohann Dudouit 4debd25d4e Remove mixed code. 2022-03-31 18:16:17 -07:00
Yohann Dudouit 10a39a23ed Add documentation to interface.hpp. 2022-03-31 18:03:08 -07:00
Yohann Dudouit f4578552dc Merge branch 'yohann/mixed-mesh' of https://github.com/mfem/mfem into yohann/mixed-mesh 2022-03-31 17:59:27 -07:00
Yohann Dudouit 485f9b07d7 Add mixed_integrator to interface. 2022-03-31 17:58:32 -07:00
Yohann Dudouit 7f9eb72e74 Add documentation to interface.hpp. 2022-03-31 17:56:49 -07:00
Yohann Dudouit 02e4cbe75b Use Mixed mesh for mass PA. 2022-03-31 17:45:59 -07:00
Yohann Dudouit d81a2728b4 Add MixedPAIntegrator for mixed meshes. 2022-03-31 17:45:59 -07:00
Yohann Dudouit 9a3451fcb2 Fix CMake. 2022-03-31 17:40:56 -07:00
Yohann Dudouit dfc4100189 Update CMakeLists.txt 2022-03-31 17:38:24 -07:00
Yohann Dudouit 5316e51c4f Use Mixed mesh for mass PA. 2022-03-31 17:29:49 -07:00
Yohann Dudouit b2825c9625 Add MixedPAIntegrator for mixed meshes. 2022-03-31 17:28:41 -07:00
Yohann Dudouit c3de163140 Remove Mixed mesh. 2022-03-31 17:27:11 -07:00
Yohann Dudouit 5adc33c8a5 Reorganize libCEED integration. 2022-03-31 17:18:06 -07:00
Will Pazner 1ca041cabc Add (failing) unit test for AssemblyLevel::FULL HypreParMatrix 2022-03-31 15:16:16 -07:00
Julian Andrej 41123cdb19 reviewer comments 2022-03-30 13:05:32 -07:00
Jean-Sylvain CAMIER 35d9a405a6 add benchmarks
* Add tests/benchmarks/bench_nle

* Sync & re-use

* Before cleaning

* cleanup and reuse miniapp headers

* Meld toward enzyme-nonlinear
2022-03-30 11:57:36 -07:00
Ketan Mittal f10054f059 make style 2022-03-30 10:13:26 -07:00
Ketan Mittal 67240ad1b1 bug in triangle split 2022-03-30 10:13:05 -07:00
Julian Andrej 8c76b75573 documentation 2022-03-30 09:20:25 -07:00
Julian Andrej 9d06122995 Merge branch 'master' into enzyme-nonlinear 2022-03-30 09:19:55 -07:00
Julian Andrej 73f4c3298e cleanup namespace use 2022-03-30 09:19:45 -07:00
Julian Andrej 2af6d555a3 changelog 2022-03-30 08:33:19 -07:00
Ketan Mittal 1a98618b51 use Arrays instead of individual pointers 2022-03-29 17:54:34 -07:00
Ketan Mittal a27096bff7 add sample runs for pyramids 2022-03-29 11:58:01 -07:00
Ketan Mittal 020b22ddd1 update sample runs 2022-03-29 11:47:46 -07:00
Ketan Mittal a9b05a0f6e Merge branch 'master' of https://github.com/mfem/mfem into gslib-mixed-meshes 2022-03-29 11:47:21 -07:00
Ketan Mittal b827a345a0 add support for pyramids 2022-03-29 11:46:27 -07:00
Vladimir Z Tomov d413251dcb Merge branch 'master' into ortho-solver 2022-03-29 11:13:18 -07:00
Ketan Mittal 76f908faf8 minor 2022-03-29 10:24:56 -07:00
Yohann Dudouit 967b57d53f Add assembly informations. 2022-03-29 10:08:34 -07:00
Yohann Dudouit bd33166074 Small doc improvment. 2022-03-29 09:38:17 -07:00
Yohann Dudouit 0f11218117 Refactor max_order. 2022-03-29 09:35:12 -07:00
Yohann Dudouit 15e77043b8 Some cleaning. 2022-03-29 08:57:29 -07:00
Yohann Dudouit d83d149f75 Merge branch 'yohann/bench-assembly-levels' of https://github.com/mfem/mfem into yohann/bench-assembly-levels 2022-03-28 17:16:15 -07:00
Yohann Dudouit fca5939fb5 Better heuristic 2022-03-28 17:16:10 -07:00
Yohann Dudouit a0cc3022e2 Change Order/MaxDofs. 2022-03-28 17:15:25 -07:00
Yohann Dudouit 9acaa5f973 Only build when runnable. 2022-03-28 17:03:00 -07:00
Yohann Dudouit 358544f81a Inverse order and target_dofs. 2022-03-28 16:47:13 -07:00
Ketan Mittal 3e38e89951 restore deleted space 2022-03-28 16:02:25 -07:00
Ketan Mittal 2217598ab6 add tests to CMakeLists.txt 2022-03-28 16:00:12 -07:00
Ketan Mittal 3bf477d6c8 fix schwarz_ex1p to set some default number of ranks for individual meshes 2022-03-28 15:59:11 -07:00
Yohann Dudouit bc0b4d9703 Fix num_elems in is_runnable(). 2022-03-28 15:58:02 -07:00
Yohann Dudouit 74d99721f6 More pesimistic heuristic... 2022-03-28 15:46:32 -07:00
Yohann Dudouit d79a364cbc Modify is_runnable(). 2022-03-28 15:34:59 -07:00
Yohann Dudouit e4db8d5b8b Replace MaxN with MaxDofs. 2022-03-28 15:03:12 -07:00
Yohann Dudouit 0591b7bbbf Increase max mesh size to 64. 2022-03-28 14:43:04 -07:00
Yohann Dudouit 93e77854e6 Add heurisitc to avoid running out of memory. 2022-03-28 14:06:00 -07:00
Yohann Dudouit 6e8314d78a Parametrize on N. 2022-03-25 15:03:11 -07:00
Julian Andrej eba4c64e15 little description of the miniapp 2022-03-25 14:36:47 -07:00
Julian Andrej 5ed43cb1b4 formatting 2022-03-25 14:29:55 -07:00
Yohann Dudouit 3229f37814 Add Dofs prints. 2022-03-25 14:21:38 -07:00
Julian Andrej c9a8df1e0d formatting 2022-03-25 13:54:26 -07:00
Yohann Dudouit 7f4283acfd Comment unsupported benchmarks. 2022-03-25 13:01:44 -07:00
Julian Andrej 6de42881be formatting 2022-03-25 11:13:34 -07:00
Julian Andrej db592e1f2a merge tensor_isotropic and tensor header files 2022-03-25 11:06:35 -07:00
Arturo Vargas 3c7241e735 make style 2022-03-24 16:56:35 -07:00
Arturo Vargas d1dd6c9546 add umpire pools to face geometric factor memory 2022-03-24 16:54:59 -07:00
Yohann Dudouit 0340acecce Add a CEED inspired benchmark for all the assembly levels. 2022-03-24 15:08:01 -07:00
Julian Andrej 7bf7c35218 copyright 2022-03-22 11:46:18 -07:00
Julian Andrej 8da89221b3 copyright notice 2022-03-22 11:37:56 -07:00
Julian Andrej 24824722f2 Merge branch 'master' into enzyme-nonlinear 2022-03-22 11:35:10 -07:00
Ketan Mittal e5618a9f13 Merge branch 'master' of https://github.com/mfem/mfem into gslib-mixed-meshes 2022-03-21 15:28:46 -07:00
Ketan Mittal 8c00a4dc9f fix overset setup 2022-03-21 15:28:11 -07:00
Ketan Mittal 6775e2a538 refactor 2022-03-21 14:26:43 -07:00
Ketan Mittal 2c7ba1c208 working in serial and parallel 2022-03-21 12:59:37 -07:00
Julian Andrej a7a8e61bb3 missing include 2022-03-18 15:28:51 -07:00
Ketan Mittal 5962ae8bb2 WIP: first version for mixed meshes 2022-03-18 15:06:21 -07:00
Julian Andrej a26a3dde23 refactor 2022-03-18 14:31:50 -07:00
Julian Andrej e404adf317 add gradient caching 2022-03-17 10:49:27 -07:00
Julian Andrej c7a94e8f8b return const T& instead of copying 2022-03-16 13:19:14 -07:00
Julian Andrej b3e6b22b71 remove enzyme loose-types option 2022-03-16 11:40:47 -07:00
Jean-Sylvain CAMIER 73cb59919e Enzyme nonlinear device [enzyme-nonlinear-device] (#2874)
* Debug device runs

* CUDA runs with nvcc

* Optimize ApplyGradient3D

* Cleanup & Simplify

* Device order 3, optimize option & cleanup

* Cleanup, remove original code & meld toward source

* Remove fdual.hpp from miniapps/autodiff/CMakeLists

* Revert std pow, but nvcc errors

* Add value_type pow(value_type a, value_type b)

* Remove unused cuda header

* Remove extra ';'

* remove extra ';'

* Simplify KernelHelpers templated calls

* Simplify init part of the helper kernels

* Add linalg/tensor_isotropic.hpp and move B,G near instantiated function calls

* Simplify B & G in elasticity kernels
2022-03-14 10:36:29 -07:00
blaz 37d82e2232 gitignore 2022-03-11 11:45:37 -08:00
blaz 821da7283b makefile 2022-03-10 08:31:58 -08:00
blaz 9b8bdd9351 rm user.cmake 2022-03-09 23:20:28 -08:00
blaz 0133c4334d style 2022-03-09 23:17:17 -08:00
blaz 4369ad9d75 marking for faces 2022-03-09 23:12:53 -08:00
blaz 408a9ae55b miniapp makefile 2022-03-09 23:05:54 -08:00
blaz cff5cee978 modified the input mesh 2022-03-09 23:01:13 -08:00
blaz 2e16020700 Integration rules based on Algoim 2022-03-09 22:47:32 -08:00
blaz c5f8836fc7 Confifuration Algoim and Blitz 2022-03-09 22:44:34 -08:00
Julian Andrej 65d63395c0 adapt example for modified dual type 2022-02-24 10:35:37 -08:00
Julian Andrej 9fd331714d adapt dual type to miniapp and remove fdual implementation 2022-02-24 08:37:24 -08:00
Julian Andrej ad0a5e0474 doxygen 2022-02-14 14:52:44 -08:00
Julian Andrej 3b0618405b outstream 2022-02-14 14:21:27 -08:00
Julian Andrej 05e264c53e sane formatting 2022-02-11 10:54:58 -08:00
Julian Andrej cd03b3fd74 copyright notice 2022-02-11 10:24:42 -08:00
Julian Andrej bc6d4e68b4 make enzyme version a variable 2022-02-11 10:22:00 -08:00
Julian Andrej 4beda68a36 add enzyme to makefile build system 2022-02-11 08:04:36 -08:00
Julian AndrejandSam Mish 6a79901fa7 draft for nonlinear elasticity example using PA and AD
Co-authored-by: Sam Mish <mish2@llnl.gov>
2022-02-10 11:53:09 -08:00
Vladimir Z Tomov 7de0cfe77d Fixed unused variable for the serial build. 2022-01-10 21:09:16 -08:00
Vladimir Z Tomov 441b503593 Added serial support, MFEM_USE_MPI checks. 2022-01-10 20:59:24 -08:00
Vladimir Z Tomov f1614c5185 Moved OrthoSolver to solvers.hpp/cpp. 2022-01-10 20:48:44 -08:00
265 changed files with 27500 additions and 4096 deletions
+15 -3
View File
@@ -1,10 +1,13 @@
version: '{build}'
# https://www.appveyor.com/docs/build-environment/#build-worker-images
image: Visual Studio 2017
image: Visual Studio 2019
install:
# Start from outside clone directory
- cd ..
# Install MS-MPI
- ps: Start-FileDownload 'https://download.microsoft.com/download/B/2/E/B2EB83FE-98C2-4156-834A-E1711E6884FB/MSMpiSetup.exe'
- MSMpiSetup.exe -unattend
@@ -15,6 +18,11 @@ install:
- msmpisdk.msi /passive
- set PATH=C:\Program Files\Microsoft MPI\Bin;%PATH%
# Set MSMPI environment variables needed for CMake detection
- set MSMPI_LIB32=C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86
- set MSMPI_LIB64=C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x64
- set MSMPI_INC=C:\Program Files (x86)\Microsoft SDKs\MPI\Include
# Install METIS, use a mirror because the original source server is not always
# up. Original url:
# http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-5.1.0.tar.gz
@@ -25,20 +33,24 @@ install:
- cmake -H. -Bbuild
# -DCMAKE_BUILD_TYPE=Release
- cmake --build build
- set METIS_PATH=%cd%
- cd ..
# Install hypre
- ps: Start-FileDownload 'https://github.com/hypre-space/hypre/archive/v2.19.0.tar.gz'
- 7z x v2.19.0.tar.gz -so | 7z x -si -ttar > nul
- cd hypre-2.19.0/src
- cmake -H. -Bbuild -DMPI_C_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DMPI_C_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include"
- cmake -H. -Bbuild
- cmake --build build
- cmake --build build --target install
- cd ../..
# Return to clone directory
- cd %APPVEYOR_BUILD_FOLDER%
# MFEM
before_build:
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_parallel -DMFEM_USE_MPI=TRUE -DMFEM_USE_METIS_5=TRUE -DMPI_CXX_LIBRARIES="C:\Program Files (x86)\Microsoft SDKs\MPI\Lib\x86\msmpi.lib" -DMPI_CXX_INCLUDE_PATH="C:\Program Files (x86)\Microsoft SDKs\MPI\Include" -DHYPRE_DIR=%cd%\hypre-2.19.0\src\hypre -DMETIS_LIBRARIES=%cd%\metis-5.1.0\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%cd%\metis-5.1.0\include
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_parallel -DMFEM_USE_MPI=TRUE -DMFEM_USE_METIS_5=TRUE -DHYPRE_DIR=%cd%\..\hypre-2.19.0\src\hypre -DMETIS_LIBRARIES=%METIS_PATH%\build\libmetis\Debug\metis.lib -DMETIS_INCLUDE_DIRS=%METIS_PATH%\include
- cmake -H. -DCMAKE_INSTALL_PREFIX=install -Bbuild_serial -DMFEM_USE_MPI=FALSE
build_script:
+82
View File
@@ -0,0 +1,82 @@
name: Build Deploy Container
on:
# Always have a base image ready to go - this is a nightly build
schedule:
- cron: 0 3 * * *
# Allow manual trigger of a build
workflow_dispatch:
# On push to main we build and deploy images
push:
branches:
- master
# Publish packages on release
release:
types: [published]
jobs:
build:
if: github.repository == 'mfem/mfem' # Don't run in forks
permissions:
packages: write
strategy:
fail-fast: false
matrix:
# Dockerfiles to build, a matrix supports future expanded builds
container: [["config/docker/Dockerfile.base", "ghcr.io/mfem/mfem-ubuntu-base"],
["config/docker/Dockerfile", "ghcr.io/mfem/mfem-ubuntu"]]
runs-on: ubuntu-latest
name: Build
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Make Space For Build
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
# It's easier to reference named variables than indexes of the matrix
- name: Set Environment
env:
dockerfile: ${{ matrix.container[0] }}
uri: ${{ matrix.container[1] }}
run: |
echo "dockerfile=$dockerfile" >> $GITHUB_ENV
echo "uri=$uri" >> $GITHUB_ENV
- name: Pull previous layers for cache
run: docker pull ${uri}:latest || echo "No container to pull"
- name: Build Container
run: |
container=$uri:latest
docker build -f ${dockerfile} -t ${container} .
echo "container=$container" >> $GITHUB_ENV
- name: GHCR Login
if: (github.event_name != 'pull_request')
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy
if: (github.event_name != 'pull_request')
run: |
docker push ${container}
- name: Tag and Push Release
if: (github.event_name == 'release')
run: |
tag=${GITHUB_REF#refs/tags/}
echo "Tagging and releasing ${uri}:${tag}"
docker tag ${uri}:latest ${uri}:${tag}
docker push ${uri}:${tag}
+85 -17
View File
@@ -27,6 +27,7 @@ on:
- master
- next
pull_request:
workflow_dispatch:
env:
HYPRE_ARCHIVE: v2.19.0.tar.gz
@@ -46,11 +47,18 @@ jobs:
builds-and-tests:
strategy:
matrix:
os: [ubuntu-18.04, macos-10.15]
os: [ubuntu-20.04, macos-10.15, windows-2022]
target: [dbg, opt]
mpi: [seq, par]
build-system: [make]
build-system: [make, cmake]
hypre-target: [int32]
exclude:
- os: ubuntu-20.04
build-system: cmake
- os: macos-10.15
build-system: cmake
- os: windows-2022
build-system: make
# 'include' allows us to:
# - Add a variable to all jobs without creating a new matrix dimension.
# Codecov is defined that way.
@@ -64,13 +72,15 @@ jobs:
codecov: NO
- target: opt
codecov: YES
- os: ubuntu-18.04
- os: windows-2022
codecov: NO
- os: ubuntu-20.04
target: opt
codecov: NO
mpi: par
build-system: cmake
hypre-target: int32
- os: ubuntu-18.04
- os: ubuntu-20.04
target: opt
codecov: NO
mpi: par
@@ -102,13 +112,13 @@ jobs:
# TODO: It would be nice to have only one step, e.g. with a dedicated
# action, but I (@adrienbernede) don't see how at the moment.
- name: get MPI (Linux)
if: matrix.mpi == 'par' && matrix.os == 'ubuntu-18.04'
if: matrix.mpi == 'par' && matrix.os == 'ubuntu-20.04'
run: |
sudo apt-get install mpich libmpich-dev
export MAKE_CXX_FLAG="MPICXX=mpic++"
- name: get lcov (Linux)
if: matrix.codecov == 'YES' && matrix.os == 'ubuntu-18.04'
if: matrix.codecov == 'YES' && matrix.os == 'ubuntu-20.04'
run: |
sudo apt-get install lcov
@@ -129,6 +139,10 @@ jobs:
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install lcov
- name: get MPI (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-2022'
uses: mpi4py/setup-mpi@v1.0.3
# Get Hypre through cache, or build it.
# Install will only run on cache miss.
- name: cache hypre
@@ -137,36 +151,71 @@ jobs:
uses: actions/cache@v2
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-v2.0
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-v2.2
- name: get hypre
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-hypre@v2.0
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os != 'windows-2022'
uses: mfem/github-actions/build-hypre@v2.2
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: make
- name: get hypre (Windows)
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os == 'windows-2022'
uses: mfem/github-actions/build-hypre@v2.2
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: cmake
# Get Metis through cache, or build it.
# Install will only run on cache miss.
- name: cache metis
id: metis-cache
if: matrix.mpi == 'par'
if: matrix.mpi == 'par' && matrix.os != 'windows-2022'
uses: actions/cache@v2
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.0
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
- name: install metis
if: matrix.mpi == 'par' && steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.0
if: matrix.mpi == 'par' && matrix.os != 'windows-2022' && steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.2
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
- name: cache vcpkg (Windows)
id: vcpkg-cache
uses: actions/cache@v3
with:
path: vcpkg_cache
key: ${{ runner.os }}-${{ matrix.mpi }}-vcpkg-v1
- name: prepare binary cache location
if: matrix.os == 'windows-2022' && steps.vcpkg-cache.outputs.cache-hit != 'true'
run: |
mkdir -p vcpkg_cache
- name: install metis (Windows)
if: matrix.mpi == 'par' && matrix.os == 'windows-2022'
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
run: |
$PortFile = 'C:\vcpkg\ports\metis\portfile.cmake'
$OriginalURL = 'http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-${METIS_VERSION}.tar.gz'
$NewURL = 'https://github.com/mfem/tpls/raw/gh-pages/metis-5.1.0.tar.gz'
(Get-Content $PortFile).replace($OriginalURL, $NewURL) | Set-Content $PortFile
vcpkg install metis --triplet=x64-windows-static
# MFEM build and test
- name: build
uses: mfem/github-actions/build-mfem@v2.1
uses: mfem/github-actions/build-mfem@v2.2
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
with:
os: ${{ matrix.os }}
target: ${{ matrix.target }}
@@ -176,6 +225,8 @@ jobs:
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
mfem-dir: ${{ env.MFEM_TOP_DIR }}
config-options: ${{ env.MFEM_EXTRA_CONFIG }}
library-only: ${{ matrix.target == 'dbg' }}
# Run checks (and only checks) on debug targets
- name: checks
@@ -193,10 +244,27 @@ jobs:
run: |
cd ${{ env.MFEM_TOP_DIR }} && make test
- name: cmake unit tests
if: matrix.build-system == 'cmake'
- name: cmake checks
if: matrix.build-system == 'cmake' && matrix.target == 'dbg'
run: |
cd ${{ env.MFEM_TOP_DIR }}/build/tests/unit && ctest --output-on-failure
CTEST_CONFIG="Debug"
cd ${{ env.MFEM_TOP_DIR }} && cmake --build build --target check --config ${CTEST_CONFIG}
shell: bash
- name: cmake unit tests (Ubuntu 20.04)
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os == 'ubuntu-20.04'
run: |
CTEST_CONFIG="Release"
[[ ${{ matrix.target }} == 'dbg' ]] && CTEST_CONFIG="Debug"
cd ${{ env.MFEM_TOP_DIR }}/build/tests/unit && ctest --output-on-failure -C ${CTEST_CONFIG}
shell: bash
- name: cmake tests
if: matrix.build-system == 'cmake' && matrix.target == 'opt' && matrix.os != 'ubuntu-20.04'
run: |
CTEST_CONFIG="Release"
cd ${{ env.MFEM_TOP_DIR }}/build && ctest --output-on-failure -C ${CTEST_CONFIG}
shell: bash
# Code coverage (process and upload reports)
- name: codecov
+6 -5
View File
@@ -20,6 +20,7 @@ on:
- master
- next
pull_request:
workflow_dispatch:
env:
HYPRE_ARCHIVE: v2.19.0.tar.gz
@@ -53,11 +54,11 @@ jobs:
uses: actions/cache@v2
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.0
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.2
- name: Get Hypre
if: steps.hypre-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-hypre@v2.0
uses: mfem/github-actions/build-hypre@v2.2
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
@@ -68,18 +69,18 @@ jobs:
uses: actions/cache@v2
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.0
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
- name: Install Metis
if: steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.0
uses: mfem/github-actions/build-metis@v2.2
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
# MFEM build and test
- name: build-mfem
uses: mfem/github-actions/build-mfem@v2.0
uses: mfem/github-actions/build-mfem@v2.2
with:
os: ${{ runner.os }}
target: opt
+28 -6
View File
@@ -16,16 +16,28 @@ permissions:
on:
push:
pull_request:
workflow_dispatch:
# This workflow is run on pushes to any branch in the MFEM repo (with or without
# PRs), as well as on updates to PRs from forks. In particular, we do not
# duplicate work by running on both pushes and updates to local PRs. We do that
# by checking if the workflow trigger is 'push' ("github.event_name == 'push'")
# and if we are in a fork ("github.event.pull_request.head.repo.full_name !=
# github.repository").
jobs:
file-headers-check:
runs-on: ubuntu-18.04
if: |
(github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.0
with:
access_token: ${{ github.token }}
- name: checkout mfem
uses: actions/checkout@v2
@@ -49,7 +61,10 @@ jobs:
continue-on-error: true
- name: wrap-up
if: steps.copyright.outcome != 'success' || steps.license.outcome != 'success' || steps.release.outcome != 'success'
if: |
steps.copyright.outcome != 'success' ||
steps.license.outcome != 'success' ||
steps.release.outcome != 'success'
run: |
if [[ "${{ steps.copyright.outcome }}" != "success" ]]; then
echo "copyright check failed, unroll log for details"
@@ -64,7 +79,9 @@ jobs:
code-style:
runs-on: ubuntu-18.04
if: |
(github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v2
@@ -79,7 +96,9 @@ jobs:
documentation:
runs-on: ubuntu-18.04
if: |
(github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v2
@@ -94,9 +113,12 @@ jobs:
./runtest documentation
branch-history:
if: github.ref != 'refs/heads/next' && github.ref != 'refs/heads/master'
if: |
github.ref != 'refs/heads/next' &&
github.ref != 'refs/heads/master' &&
(github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository)
runs-on: ubuntu-18.04
steps:
- name: checkout mfem
uses: actions/checkout@v2
+4
View File
@@ -261,12 +261,14 @@ miniapps/performance/sol.*
miniapps/shifted/distance
miniapps/shifted/ParaViewDistance
miniapps/shifted/ParaViewLSF
miniapps/shifted/extrapolate
miniapps/shifted/ParaViewExtrapolate
miniapps/shifted/diffusion
miniapps/shifted/diffusion.mesh
miniapps/shifted/diffusion.gf
miniapps/shifted/ParaViewDiffusion
miniapps/shifted/lsf_integral
miniapps/tools/display-basis
miniapps/tools/load-dc
@@ -305,6 +307,8 @@ miniapps/solvers/sol.*
miniapps/parelag/MultilevelHcurlHdivSolver
miniapps/parelag/*.mesh
miniapps/hooke/hooke
# Unit test binary and outputs
tests/unit/output_meshes
tests/unit/unit_tests
+80 -12
View File
@@ -10,17 +10,23 @@
Version 4.4.1 (development)
===========================
- Added WhiteGaussianNoiseDomainLFIntegrator: a LinearFormIntegrator class for
spatial Gaussian white noise.
- Added a new Zienkiewicz-Zhu patch recovery-based a posteriori error estimator.
See fem/estimators.hpp.
Meshing improvements
--------------------
- Added support for mixed meshes and pyramids in GSLIB-FindPoints.
- Added support for ParMoonolith, https://bitbucket.org/zulianp/par_moonolith,
which provides parallel non-conforming, non-matching, variational, volumetric
mesh information transfer. With ParMortarAssember, fields can be exchanged
between arbitrarily distributed and unrelated finite element meshes in a
variationally consistent way.
Discretization improvements
---------------------------
- Added support for assembling low-order-refined matrices using a GPU-enabled
"batched" algorithm. The lor_solvers and plor_solvers now fully support GPU
acceleration.
- Added support for partial assembly and fully matrix-free operators on mixed
meshes (different element types and p-adaptivity) through libCEED, including
device acceleration, e.g. with NVIDIA and AMD GPUs. The p-adaptivity is
currently limited by MFEM capabilities, i.e. 2D serial meshes. All mixed
element topologies are supported in serial and parallel: segment, triangle,
square, tetrahedron, cube, prism, and pyramid.
- Added full assembly and device support for several LinearForm integrators:
* DomainLF: (f, v)
@@ -28,12 +34,59 @@ Version 4.4.1 (development)
* DomainLFGrad: (f, grad(v))
* VectorDomainLFGrad: ((f1x,f1y,f1z,...,fnx,fny,fnz), grad(v1,...,vn))
- Added WhiteGaussianNoiseDomainLFIntegrator: a LinearFormIntegrator class for
spatial Gaussian white noise.
- Added a new Zienkiewicz-Zhu patch recovery-based a posteriori error estimator.
See fem/estimators.hpp.
Linear and nonlinear solvers
----------------------------
New and updated examples and miniapps
-------------------------------------
- Added a new elasticity miniapp, Hooke, that showcases a low-level approach of
using MFEM to solve a nonlinear elasticity problem based on the fundamental
finite element operator decomposition. The miniapp also integrates with
automatic differentiation tools like a native dual number implementation or a
third party library such as Enzyme. See miniapps/elasticity for more details.
- Add a new example code, Example 33/33p, to demonstrate the solution of
spectral fractional PDEs with MFEM.
- Added support for assembling low-order-refined matrices using a GPU-enabled
"batched" algorithm. The lor_solvers and plor_solvers now fully support GPU
acceleration.
Integrations, testing and documentation
---------------------------------------
- Added a Dockerfile for a simple MFEM container, see config/docker/README.md.
- Added support for ParMoonolith, https://bitbucket.org/zulianp/par_moonolith,
which provides parallel non-conforming, non-matching, variational, volumetric
mesh information transfer. With ParMortarAssember, fields can be exchanged
between arbitrarily distributed and unrelated finite element meshes in a
variationally consistent way.
- Added support for the LLVM-based automatic differentiation tool Enzyme, see
https://github.com/EnzymeAD/Enzyme. Build system flags and a convenience
header are provided. The functionality and interaction are demonstrated in a
new miniapp in miniapps/elasticity.
- Added example for body-fitted volumetric and shape integration using the
Algoim library.
- Added Windows 2022 CI testing with GitHub actions.
Miscellaneous
-------------
- Various other simplifications, extensions, and bugfixes in the code.
- Added boundary elimination with device support for `SparseMatrix` and
`HypreParMatrix`.
- When using `AssemblyLevel::FULL`, `FABilinearFormExtension::FormSystemMatrix`
outputs an `OperatorHandle` containing a `SparseMatrix` in serial, and an
`HypreParMatrix` in parallel (instead of a `ConstrainedOperator`).
- Added TMOP metrics for mesh untangling and worst-case quality improvement.
Version 4.4, released on March 21, 2022
=======================================
@@ -66,6 +119,11 @@ Meshing improvements
- Added a simpler interface to access mesh face information, see FaceInformation
and GetFaceInformation in the Mesh class.
- Added the method ParMesh::GetSerialMesh() that reconstructs a partitioned
parallel mesh on a given single rank. Also, added the method
ParMesh::PrintAsSerial() that saves the reconstructed serial mesh to a C++
stream on rank 0.
- Gmsh meshes where all elements have zero physical tag (the default Gmsh output
format if no physical groups are defined) are now successfully loaded, and
elements are reassigned attribute number 1.
@@ -155,6 +213,9 @@ Integrations, testing and documentation
- Switched from Artistic Style (astyle) version 2.05.1 to version 3.1 for code
formatting. See the "make style" target.
- New benchmark for the different assembly levels inspired by the CEED
Bake-Off Problems, see tests/benchmarks/bench_assembly_levels.cpp.
Miscellaneous
-------------
- Added a simple singleton class, Mpi, as a replacement for MPI_Session. New
@@ -165,6 +226,13 @@ Miscellaneous
- Fixed several MinGW build issues on Windows.
- In various places in the library, replace the use of 'long' with 'long long'
to better support Win64 builds where 'long' is 32-bit and 'long long' is
64-bit. On Linux and MacOS, both types are typically 64-bit.
- Update various "MemoryUsage" methods to return 'std::size_t' instead of 'long'
since the latter is 32-bit in Win64 builds.
- Added 'double' atomicAdd implementation for previous versions of CUDA.
- HypreParVector and Vector now support C++ move semantics, and the copy
+31 -13
View File
@@ -136,6 +136,8 @@ if (MFEM_USE_CUDA)
"CUDA flags set for MFEM" FORCE)
set(CUSPARSE_FOUND TRUE)
set(CUSPARSE_LIBRARIES "cusparse")
set(CUBLAS_FOUND TRUE)
set(CUSBLAS_LIBRARIES "cublas")
endif()
if (XSDK_ENABLE_C)
@@ -268,7 +270,7 @@ if (MFEM_USE_OPENMP OR MFEM_USE_LEGACY_OPENMP)
if(APPLE)
# On macOS, the compiler needs additional help to find the <omp.h> header.
# See issue #2642 for more information.
include_directories(${OpenMP_CXX_INCLUDE_DIRS})
set(OPENMP_INCLUDE_DIRS ${OpenMP_CXX_INCLUDE_DIRS})
endif(APPLE)
endif()
@@ -431,6 +433,11 @@ if (MFEM_USE_CALIPER)
find_package(Caliper REQUIRED)
endif()
# Algoim
if (MFEM_USE_ALGOIM)
find_package(Algoim REQUIRED)
endif()
# ADIOS2 for parallel I/O
if (MFEM_USE_ADIOS2)
find_package(ADIOS2 REQUIRED)
@@ -447,6 +454,11 @@ if (MFEM_USE_PARELAG)
find_package(PARELAG REQUIRED)
endif()
# Enzyme
if (MFEM_USE_ENZYME)
find_package(ENZYME REQUIRED)
endif()
# MFEM_TIMER_TYPE
if (NOT DEFINED MFEM_TIMER_TYPE)
if (APPLE)
@@ -473,8 +485,8 @@ endif()
set(MFEM_TPLS OPENMP HYPRE BLAS LAPACK SuperLUDist METIS SuiteSparse SUNDIALS
PETSC SLEPC MESQUITE MUMPS STRUMPACK AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB
NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
ADIOS2 CUSPARSE MKL_CPARDISO AMGX CALIPER CODIPACK BENCHMARK PARELAG
MPI_CXX HIP HIPSPARSE MOONOLITH)
ADIOS2 CUBLAS CUSPARSE MKL_CPARDISO AMGX CALIPER CODIPACK BENCHMARK PARELAG
MPI_CXX HIP HIPSPARSE MOONOLITH BLITZ ALGOIM ENZYME)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
@@ -489,7 +501,6 @@ endforeach(TPL)
list(REMOVE_DUPLICATES TPL_LIBRARIES)
list(REMOVE_DUPLICATES TPL_INCLUDE_DIRS)
# message(STATUS "TPL_INCLUDE_DIRS = ${TPL_INCLUDE_DIRS}")
include_directories(${TPL_INCLUDE_DIRS})
if (OPENMP_FOUND)
message(STATUS "MFEM: using package OpenMP")
@@ -546,6 +557,15 @@ target_link_libraries(mfem PUBLIC ${TPL_LIBRARIES})
if (MINGW)
target_link_libraries(mfem PRIVATE ws2_32)
endif()
if (MSVC)
target_compile_options(mfem PUBLIC "/wd4819")
endif()
message(STATUS "TPL_INCLUDE_DIRS = ${TPL_INCLUDE_DIRS}")
target_include_directories(mfem
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
${TPL_INCLUDE_DIRS})
set_target_properties(mfem PROPERTIES VERSION "${mfem_VERSION}")
set_target_properties(mfem PROPERTIES SOVERSION "${mfem_VERSION}")
@@ -674,6 +694,10 @@ set(INSTALL_LIB_DIR lib
set(INSTALL_CMAKE_DIR lib/cmake/mfem
CACHE PATH "Relative path for installing cmake config files.")
target_include_directories(mfem
PUBLIC
$<INSTALL_INTERFACE:${INSTALL_INCLUDE_DIR}>)
# The 'install' target will not depend on 'all'.
# set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY TRUE)
@@ -707,7 +731,7 @@ endif()
if (MFEM_USE_CEED)
install(DIRECTORY ${MFEM_SOURCE_DIRS}
DESTINATION ${INSTALL_INCLUDE_DIR}/mfem
FILES_MATCHING PATTERN "fem/ceed/*.h")
FILES_MATCHING PATTERN "fem/ceed/integrators/*/*.h")
endif()
# Install ${HEADERS}
@@ -738,14 +762,8 @@ export(TARGETS ${PROJECT_NAME}
# TODO: How do we register the install-tree? Replacing the build-tree?
export(PACKAGE ${PROJECT_NAME})
# Extract the include directories required to use MFEM
get_target_property(MFEM_TPL_INCLUDE_DIRS mfem INCLUDE_DIRECTORIES)
if (NOT MFEM_TPL_INCLUDE_DIRS)
set(MFEM_TPL_INCLUDE_DIRS "")
endif()
# This is the build-tree version
set(INCLUDE_INSTALL_DIRS ${PROJECT_BINARY_DIR} ${MFEM_TPL_INCLUDE_DIRS})
set(INCLUDE_INSTALL_DIRS ${PROJECT_BINARY_DIR} ${TPL_INCLUDE_DIRS})
set(LIB_INSTALL_DIR ${PROJECT_BINARY_DIR})
configure_package_config_file(config/cmake/MFEMConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/MFEMConfig.cmake
@@ -753,7 +771,7 @@ configure_package_config_file(config/cmake/MFEMConfig.cmake.in
PATH_VARS INCLUDE_INSTALL_DIRS LIB_INSTALL_DIR)
# This is the version that will be installed
set(INCLUDE_INSTALL_DIRS ${INSTALL_INCLUDE_DIR} ${MFEM_TPL_INCLUDE_DIRS})
set(INCLUDE_INSTALL_DIRS ${INSTALL_INCLUDE_DIR} ${TPL_INCLUDE_DIRS})
set(LIB_INSTALL_DIR ${INSTALL_LIB_DIR})
configure_package_config_file(config/cmake/MFEMConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/MFEMConfig.cmake
+1
View File
@@ -131,6 +131,7 @@ The MFEM source code has the following structure:
│ ├── common
│ ├── electromagnetics
│ ├── gslib
│ ├── hooke
│ ├── meshing
│ ├── mtop
│ ├── navier
+38
View File
@@ -471,6 +471,14 @@ MFEM_USE_CODIPACK = YES/NO
Enable automatic differentiation using the CoDiPack library.
www.scicomp.uni-kl.de/codi/
MFEM_USE_ALGOIM = YES/NO
Enable the usage of Algoim - a collection of high-order accurate numerical
methods and C++ algorithms for working with implicitly-defined geometry and
level set methods. The Algoim library requires the Blitz++ library. The MFEM
provides interface to Algoim v1. Thus, to check out the specific state use:
git checkout 9c9ca0ef094d8ab0390ed36367a1151b459bbe0a
https://algoim.github.io
MFEM_USE_ADFORWARD = YES/NO
Enable forward mode for AD packages. This option is valid
only if the AD package supports two modes (backward/forward).
@@ -550,6 +558,14 @@ MFEM_USE_PARELAG = YES/NO
use ParELAG. In fact, ParELAG is dependent on MFEM. Therefore, this option
currently only concerns the miniapps.
MFEM_USE_ENZYME = YES/NO
Enables automatic differentiation support through the LLVM plugin Enzyme.
This requires the compiler to be set to clang (>=14.0.0). We also advise to
use the link time optimization (LTO) plugin, to enable functions that you
define over multiple files (compilation units) and want to be differentiated
automatically, to work. This requires to also use LLVM/LLD for linking.
Recommended options are in config/defaults.mk.
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.
@@ -738,6 +754,20 @@ The specific libraries and their options are:
Options: GSLIB_OPT, GSLIB_LIB.
Versions: GSLIB >= 1.0.7.
- ALGOIM (optional), used when MFE_USE_ALGOIM=YES. The library provides only
headers so it just needs to be downloaded at the same level as MFEM. Download
the specific version we use as:
"git clone https://github.com/algoim/algoim.git;
git checkout 9c9ca0ef094d8ab0390ed36367a1151b459bbe0a"
ALGOIM depends on BLITZ and rhe library must be built prior to the MFEM build.
Download v1.0.2, untar it at the same level as MFEM and create a symbolic link:
"ln -s blitz-1.0.2 blitz".
Build Blitz using CMake as:
"cmake . -DCMAKE_INSTALL_PREFIX=.; make lib; make install"
URL: https://github.com/blitzpp/blitz/archive/refs/tags/1.0.2.tar.gz
Options: BLITZ_OPT, BLITZ_LIB
Versions: BLITZ = 1.0.2
- 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.
@@ -814,6 +844,12 @@ The specific libraries and their options are:
URL: https://github.com/LLNL/parelag
Options: PARELAG_DIR, PARELAG_OPT, PARELAG_LIB.
- Enzyme, used when MFEM_USE_ENZYME = YES. Requires LLVM/Clang >= 14.0.0.
URL: https://github.com/EnzymeAD/Enzyme
Options: ENZYME_DIR, ENZYME_OPT, ENZYME_LIB.
Versions: Enzyme >= v0.0.33.
Building with CMake
===================
The MFEM build system consists of two steps: configuration and compilation.
@@ -952,6 +988,7 @@ MFEM_USE_CALIPER
MFEM_USE_FMS
MFEM_USE_BENCHMARK
MFEM_USE_PARELAG
MFEM_USE_ENZYME
The following options are CMake specific:
@@ -1011,6 +1048,7 @@ The CMake build system adds auto-detection for the following packages/libraries:
- FMS
- BENCHMARK
- ParELAG
- Enzyme
The following built-in CMake packages are also used:
+19 -12
View File
@@ -7,21 +7,24 @@
https://mfem.org
MFEM is a modular parallel C++ library for finite element methods. Its goal is
to enable high-performance scalable finite element discretization research and
application development on a wide variety of platforms, ranging from laptops to
supercomputers.
[MFEM](https://mfem.org) is a modular parallel C++ library for finite element
methods. Its goal is to enable high-performance scalable finite element
discretization research and application development on a wide variety of
platforms, ranging from laptops to supercomputers.
We welcome contributions and feedback from the community. Please see the file
CONTRIBUTING.md for additional details about our development process.
[CONTRIBUTING.md](CONTRIBUTING.md) for additional details about our development
process.
* For building instructions, see the file INSTALL, or type "make help".
* For building instructions, see the file [INSTALL](INSTALL), or type "make help".
* Copyright and licensing information can be found in files LICENSE and NOTICE.
* Copyright and licensing information can be found in files [LICENSE](LICENSE) and [NOTICE](NOTICE).
* The best starting point for new users interested in MFEM's features is to
review the examples and miniapps at https://mfem.org/examples.
* Instructions for learning with Docker are in [config/docker](config/docker).
Conceptually, MFEM can be viewed as a finite element toolbox that provides the
building blocks for developing finite element algorithms in a manner similar to
that of MATLAB for linear algebra methods. In particular, MFEM provides support
@@ -58,12 +61,16 @@ solvers from the hypre library. Comprehensive support for other external
packages, e.g. PETSc, SUNDIALS and libCEED is also included, giving access to
additional linear and nonlinear solvers, preconditioners, time integrators, etc.
For examples of using MFEM, see the examples/ and miniapps/ directories, as well
as the OpenGL visualization tool GLVis which is available at https://glvis.org.
For examples of using MFEM, see the [examples/](examples) and [miniapps/](miniapps)
directories, as well as the OpenGL visualization tool GLVis which is available
at https://glvis.org.
## License
MFEM is distributed under the terms of the BSD-3 license. All new contributions
must be made under this license. See LICENSE and NOTICE for details.
must be made under this license. See [LICENSE](LICENSE) and [NOTICE](NOTICE) for
details.
SPDX-License-Identifier: BSD-3-Clause
LLNL Release Number: LLNL-CODE-806117
SPDX-License-Identifier: BSD-3-Clause <br>
LLNL Release Number: LLNL-CODE-806117 <br>
DOI: 10.11578/dc.20171025.1248
+2
View File
@@ -58,8 +58,10 @@ set(MFEM_USE_MOONOLITH @MFEM_USE_MOONOLITH@)
set(MFEM_USE_CODIPACK @MFEM_USE_CODIPACK@)
set(MFEM_USE_ADFORWARD @MFEM_USE_ADFORWARD@)
set(MFEM_USE_CALIPER @MFEM_USE_CALIPER@)
set(MFEM_USE_ALGOIM @MFEM_USE_ALGOIM@)
set(MFEM_USE_BENCHMARK @MFEM_USE_BENCHMARK@)
set(MFEM_USE_PARELAG @MFEM_USE_PARELAG@)
set(MFEM_USE_ENZYME @MFEM_USE_ENZYME@)
set(MFEM_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
set(MFEM_CXX_FLAGS "@CMAKE_CXX_FLAGS@")
+6
View File
@@ -160,6 +160,9 @@
// Enable MFEM functionality based on the Caliper library
#cmakedefine MFEM_USE_CALIPER
// Enable MFEM functionality based on the Algoim library
#cmakedefine MFEM_USE_ALGOIM
// Which library functions to use in class StopWatch for measuring time.
// For a list of the available options, see INSTALL.
// If not defined, an option is selected automatically.
@@ -187,4 +190,7 @@
// Enable MFEM functionality based on the Google Benchmark library.
#cmakedefine MFEM_USE_BENCHMARK
// Enable Enzyme for AD
#cmakedefine MFEM_USE_ENZYME
#endif // MFEM_CONFIG_HEADER
+22
View File
@@ -0,0 +1,22 @@
# Copyright (c) 2010-2022, 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:
# - ALGOIM_FOUND
# - ALGOIM_LIBRARIES
# - ALGOIM_INCLUDE_DIRS
include(MfemCmakeUtilities)
mfem_find_package(Algoim ALGOIM ALGOIM_DIR
"include" "algoim_quad.hpp"
"" ""
"Paths to headers required by Algoim."
"Libraries required by Algoim.")
+22
View File
@@ -0,0 +1,22 @@
# Copyright (c) 2010-2022, 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:
# - BLITZ_FOUND
# - BLITZ_LIBRARIES
# - BLITZ_INCLUDE_DIRS
include(MfemCmakeUtilities)
mfem_find_package(Blitz BLITZ BLITZ_DIR
"include" "blitz/blitz.h"
"lib" "blitz"
"Paths to headers required by Blitz."
"Libraries required by Blitz.")
+27
View File
@@ -0,0 +1,27 @@
# Copyright (c) 2010-2022, 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.
message(STATUS "Looking for ENZYME ...")
message(STATUS " in ENZYME_DIR = ${ENZYME_DIR}")
# Make sure the directory and version combination works. Do nothing otherwise.
if(EXISTS "${ENZYME_DIR}/ClangEnzyme-${ENZYME_VERSION}.so")
message(STATUS "Found ENZYME: ${ENZYME_DIR}/ClangEnzyme-${ENZYME_VERSION}.so")
# Set ENZYME_FOUND
set(ENZYME_FOUND TRUE CACHE BOOL "ENZYME was found." FORCE)
# Set CXX flags to accomodate the Enzyme Clang plugin
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Xclang -load -Xclang ${ENZYME_DIR}/ClangEnzyme-${ENZYME_VERSION}.so -mllvm -enzyme-loose-types=1")
set(MFEM_USE_ENZYME YES)
else()
endif()
+1 -1
View File
@@ -15,5 +15,5 @@
# - GSLIB_INCLUDE_DIRS
include(MfemCmakeUtilities)
mfem_find_package(gslib GSLIB GSLIB_DIR "include" gslib.h "lib" gs
mfem_find_package(GSLIB GSLIB GSLIB_DIR "include" gslib.h "lib" gs
"Paths to headers required by GSLIB." "Libraries required by GSLIB.")
@@ -894,7 +894,7 @@ function(mfem_export_mk_files)
MFEM_USE_HIP MFEM_USE_RAJA MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_CALIPER
MFEM_USE_UMPIRE MFEM_USE_SIMD MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO
MFEM_USE_ADFORWARD MFEM_USE_CODIPACK MFEM_USE_BENCHMARK MFEM_USE_PARELAG
MFEM_USE_MOONOLITH)
MFEM_USE_MOONOLITH MFEM_USE_ALGOIM MFEM_USE_ENZYME)
foreach(var ${CONFIG_MK_BOOL_VARS})
if (${var})
set(${var} YES)
+6
View File
@@ -167,6 +167,9 @@
// Enable functionality based on the Caliper library.
// #define MFEM_USE_CALIPER
// Enable functionality based on the Algoim library.
// #define MFEM_USE_ALGOIM
// Enable functionality based on the Umpire library.
// #define MFEM_USE_UMPIRE
@@ -192,4 +195,7 @@
// Enable functionality based on the Google Benchmark library.
// #define MFEM_USE_BENCHMARK
// Enable the Enzyme LLVM plugin
// #define MFEM_USE_ENZYME
#endif // MFEM_CONFIG_HEADER
+1
View File
@@ -63,6 +63,7 @@ MFEM_USE_ADFORWARD = @MFEM_USE_ADFORWARD@
MFEM_USE_CODIPACK = @MFEM_USE_CODIPACK@
MFEM_USE_BENCHMARK = @MFEM_USE_BENCHMARK@
MFEM_USE_PARELAG = @MFEM_USE_PARELAG@
MFEM_USE_ENZYME = @MFEM_USE_ENZYME@
# Compiler, compile options, and link options
MFEM_CXX = @MFEM_CXX@
+7
View File
@@ -58,11 +58,13 @@ 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_CALIPER "Enable Caliper support" OFF)
option(MFEM_USE_ALGOIM "Enable Algoim support" OFF)
option(MFEM_USE_MKL_CPARDISO "Enable MKL CPardiso" OFF)
option(MFEM_USE_ADFORWARD "Enable forward mode for AD" OFF)
option(MFEM_USE_CODIPACK "Enable automatic differentiation (AD) using CoDiPack" OFF)
option(MFEM_USE_BENCHMARK "Enable Google Benchmark" OFF)
option(MFEM_USE_PARELAG "Enable ParELAG" OFF)
option(MFEM_USE_ENZYME "Enable Enzyme" OFF)
# Optional overrides for autodetected MPIEXEC and MPIEXEC_NUMPROC_FLAG
# set(MFEM_MPIEXEC "mpirun" CACHE STRING "Command for running MPI tests")
@@ -236,6 +238,11 @@ set(RAJA_DIR "${MFEM_DIR}/../raja" CACHE PATH "Path to RAJA")
set(CEED_DIR "${MFEM_DIR}/../libCEED" CACHE PATH "Path to libCEED")
set(UMPIRE_DIR "${MFEM_DIR}/../umpire" CACHE PATH "Path to Umpire")
set(CALIPER_DIR "${MFEM_DIR}/../caliper" CACHE PATH "Path to Caliper")
set(BLITZ_DIR "${MFEM_DIR}/../blitz" CACHE PATH "Path to Blitz")
set(ALGOIM_DIR "${MFEM_DIR}/../algoim" CACHE PATH "Path to Algoim")
set(ALGOIM_REQUIRED_PACKAGES "BLITZ" CACHE STRING
"Packages that ALGOIM depends on.")
set(BENCHMARK_DIR "${MFEM_DIR}/../google-benchmark" CACHE PATH
"Path to Google Benchmark")
+32 -1
View File
@@ -42,6 +42,9 @@ STATIC = YES
SHARED = NO
# CUDA configuration options
#
# If you set MFEM_USE_ENZYME=YES, CUDA_CXX has to be configured to use cuda with
# clang as its host compiler.
CUDA_CXX = nvcc
CUDA_ARCH = sm_60
CUDA_FLAGS = -x=cu --expt-extended-lambda -arch=$(CUDA_ARCH)
@@ -153,6 +156,7 @@ MFEM_USE_RAJA = NO
MFEM_USE_OCCA = NO
MFEM_USE_CEED = NO
MFEM_USE_CALIPER = NO
MFEM_USE_ALGOIM = NO
MFEM_USE_UMPIRE = NO
MFEM_USE_SIMD = NO
MFEM_USE_ADIOS2 = NO
@@ -162,6 +166,7 @@ MFEM_USE_ADFORWARD = NO
MFEM_USE_CODIPACK = NO
MFEM_USE_BENCHMARK = NO
MFEM_USE_PARELAG = NO
MFEM_USE_ENZYME = NO
# MPI library compile and link flags
# These settings are used only when building MFEM with MPI + HIP
@@ -202,7 +207,7 @@ HYPRE_OPT = -I$(HYPRE_DIR)/include
HYPRE_LIB = -L$(HYPRE_DIR)/lib -lHYPRE
ifeq (YES,$(MFEM_USE_CUDA))
# This is only necessary when hypre is built with cuda:
HYPRE_LIB += -lcusparse -lcurand
HYPRE_LIB += -lcusparse -lcurand -lcublas
endif
ifeq (YES,$(MFEM_USE_HIP))
# This is only necessary when hypre is built with hip:
@@ -469,6 +474,16 @@ CALIPER_DIR = @MFEM_DIR@/../caliper
CALIPER_OPT = -I$(CALIPER_DIR)/include
CALIPER_LIB = $(XLINKER)-rpath,$(CALIPER_DIR)/lib64 -L$(CALIPER_DIR)/lib64 -lcaliper
# BLITZ library configuration
BLITZ_DIR = @MFEM_DIR@/../blitz
BLITZ_OPT = -I$(BLITZ_DIR)/include
BLITZ_LIB = $(XLINKER)-rpath,$(BLITZ_DIR)/lib -L$(BLITZ_DIR)/lib -lblitz
# ALGOIM library configuration
ALGOIM_DIR = @MFEM_DIR@/../algoim
ALGOIM_OPT = -I$(ALGOIM_DIR)/src $(BLITZ_OPT)
ALGOIM_LIB = $(BLITZ_LIB)
# BENCHMARK library configuration
BENCHMARK_DIR = @MFEM_DIR@/../google-benchmark
BENCHMARK_OPT = -I$(BENCHMARK_DIR)/include
@@ -509,6 +524,22 @@ PARELAG_DIR = @MFEM_DIR@/../parelag
PARELAG_OPT = -I$(PARELAG_DIR)/src -I$(PARELAG_DIR)/build/src
PARELAG_LIB = -L$(PARELAG_DIR)/build/src -lParELAG
# Enzyme configuration
# If you want to enable automatic differentiation at compile time, use the
# options below, adapted to your configuration. To be more flexible, we
# recommend using the Enzyme plugin during link time optimization. One option is
# to add your options to the global compiler/linker flags like
#
# BASE_FLAGS += -flto
# CXX_XLINKER += -fuse-ld=lld -Wl,--lto-legacy-pass-manager\
# -Wl,-mllvm=-load=$(ENZYME_DIR)/LLDEnzyme-$(ENZYME_VERSION).so -Wl,
#
ENZYME_DIR ?= @MFEM_DIR@/../enzyme
ENZYME_VERSION ?= 14
ENZYME_OPT = -fno-experimental-new-pass-manager -Xclang -load -Xclang $(ENZYME_DIR)/ClangEnzyme-$(ENZYME_VERSION).so
ENZYME_LIB = ""
# If YES, enable some informational messages
VERBOSE = NO
+27
View File
@@ -0,0 +1,27 @@
FROM ghcr.io/mfem/mfem-ubuntu-base:latest as builder
# docker build -t ghcr.io/mfem/mfem-ubuntu .
COPY ./config/docker/spack.yaml /opt/mfem-env/spack.yaml
RUN apt-get install -y python3 && \
cd /opt/mfem-env && \
. /opt/spack/share/spack/setup-env.sh && \
spack env activate . && \
spack env view regenerate
FROM ubuntu:22.04
COPY --from=builder /opt/view /opt/view
COPY --from=builder /opt/mfem-view /opt/mfem-view
RUN apt-get update && \
apt-get install -y unzip gfortran && \
apt-get install -y libcurl4-openssl-dev libssl-dev
ENV PATH=$PATH:/opt/mfem-view/bin
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/mfem-view/lib:/opt/mfem-view/lib64
ENV DEBIAN_FRONTEND=noninteractive
# The user will see the view on shell into the container
WORKDIR /opt/mfem-view
ENTRYPOINT ["/bin/bash"]
+47
View File
@@ -0,0 +1,47 @@
FROM ghcr.io/rse-ops/cuda-ubuntu-20.04:cuda-11.0.3
# docker build -f Dockerfile.base -t ghcr.io/mfem/mfem-ubuntu-base .
RUN apt-get update && \
apt-get install -y unzip gfortran && \
spack compiler find && \
apt-get install -y libcurl4-openssl-dev libssl-dev
# /code is the working directory for code
WORKDIR /code
COPY . /code
# This is for a spack environment/view to install from there
RUN mkdir -p /opt/mfem-env \
&& (echo "spack:" \
&& echo " view:" \
&& echo " mfem:" \
&& echo " root: /opt/mfem-view" \
&& echo " link_type: copy" \
&& echo " packages:" \
&& echo " all:" \
&& echo " target:" \
&& echo " - x86_64_v3" \
&& echo " config:" \
&& echo " concretizer: clingo" \
&& echo " compiler:" \
&& echo " target:" \
&& echo " - x86_64_v3" \
&& echo " install_missing_compilers: true" \
&& echo " concretization: together") > /opt/mfem-env/spack.yaml
RUN cd /opt/mfem-env && \
. /opt/spack/share/spack/setup-env.sh && \
spack env activate . && \
spack develop --path /code mfem@master+examples+miniapps && \
spack add mfem@master+examples+miniapps # && \
# spack install
# ensure mfem always on various paths
#RUN cd /opt/mfem-env && \
# spack env activate --sh -d . >> /etc/profile.d/z10_spack_environment.sh
# Present the software install when we shell in
# The view is at /opt/mfem-env/.spack-env/view
#WORKDIR /opt/software
#ENTRYPOINT ["/bin/bash", "--rcfile", "/etc/profile", "-l", "-c"]
+147
View File
@@ -0,0 +1,147 @@
# mfem Docker
We provide a [Dockerfile.base](Dockerfile.base) to build an ubuntu base image,
and a [Dockerfile](Dockerfile) to build a smaller one with a multi-stage build.
You can use this image for a demo of using mfem! 🎉️
Updated containers are built and deployed on merges to the main branch and releases.
If you want to request a build on demand, you can [manually run the workflow](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow) thanks to the workflow dispatch event.
### Usage
Here is how to build the container. Note that we build so it belongs to the same
namespace as the repository here. "ghcr.io" means "GitHub Container Registry" and
is the [GitHub packages](https://github.com/features/packages) registry that supports
Docker images and other OCI artifacts. From the root of the repository:
```bash
$ docker build -f config/docker/Dockerfile -t ghcr.io/mfem/mfem-ubuntu .
$ docker build -f config/docker/Dockerfile.base -t ghcr.io/mfem/mfem-ubuntu-base .
```
### Shell Ubuntu
To shell into the container:
```bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu
```
This smaller image has a view where everything is installed.
```bash
$ ls
bin etc include lib libexec sbin share var
```
- Examples are in share/mfem/examples
- Examples are in share/mfem/miniapps
You can read more about interaction with these examples and miniapps below.
### Shell Ubuntu Base
To shell into the container:
```bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base bash
```
Off the bat, you can see mfem libraries are in your path so you can jump into development:
```bash
env | grep mfem
```
```bash
PKG_CONFIG_PATH=/opt/mfem-env/.spack-env/view/lib/pkgconfig:/opt/mfem-env/.spack-env/view/share/pkgconfig:/opt/mfem-env/.spack-env/view/lib64/pkgconfig
PWD=/opt/mfem-env
MANPATH=/opt/mfem-env/.spack-env/view/share/man:/opt/mfem-env/.spack-env/view/man:
CMAKE_PREFIX_PATH=/opt/mfem-env/.spack-env/view
SPACK_ENV=/opt/mfem-env
ACLOCAL_PATH=/opt/mfem-env/.spack-env/view/share/aclocal
LD_LIBRARY_PATH=/opt/mfem-env/.spack-env/view/lib:/opt/mfem-env/.spack-env/view/lib64
PATH=/opt/mfem-env/.spack-env/view/bin:/opt/view/bin:/opt/spack/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
```
#### Examples and MiniApps
If you want to develop a tool that _uses_ mfem, you can find the built libraries in:
```
$ ls /opt/mfem-env/.spack-env/view/
bin etc include lib libexec sbin share var
```
And yes, this is the working directory when you shell into the container!
You can find the examples here:
```bash
cd share/mfem/examples
```
```bash
$ ./ex0
Options used:
--mesh ../data/star.mesh
--order 1
Number of unknowns: 101
Iteration : 0 (B r, r) = 0.184259
Iteration : 1 (B r, r) = 0.102754
Iteration : 2 (B r, r) = 0.00558141
Iteration : 3 (B r, r) = 1.5247e-05
Iteration : 4 (B r, r) = 1.13807e-07
Iteration : 5 (B r, r) = 6.27231e-09
Iteration : 6 (B r, r) = 3.76268e-11
Iteration : 7 (B r, r) = 6.07423e-13
Iteration : 8 (B r, r) = 4.10615e-15
Average reduction factor = 0.140201
```
Try running a few, and look at the associated .cpp file for the source code!
You can also explore the "mini apps," also in share/mfem, but under miniapps.
```bash
# This is run from the examples directory
$ cd ../miniapps
```
```bash
$ ls
CMakeLists.txt common meshing nurbs shifted toys
adjoint electromagnetics mtop parelag solvers
autodiff gslib navier performance tools
```
And an example in "toys"
```bash
cd toys
```
```bash
$ ./automata -no-vis
Options used:
--num-steps 16
--rule 90
--no-visualization
Rule:
111 110 101 100 011 010 001 000
0 1 0 1 1 0 1 0
Applying rule...done.
```
Have fun!
#### Your own App
If you want to develop with your own code base
(and mfem as is in the container) you can bind to somewhere else in the container (e.g., src)
```bash
$ docker run -it ghcr.io/mfem/mfem-ubuntu-base -v $PWD:/src bash
```
In the above, we can pretend your project is in the present working directory (PWD) and we are
binding to source. You can then use the mfem in the container for development, and if you
want to distribute your library or app in a container, you can use the mfem container as the base.
+11
View File
@@ -0,0 +1,11 @@
spack:
specs: [mfem@master+examples+miniapps]
view:
mfem:
root: /opt/mfem-view
link_type: copy
concretization: together
develop:
mfem:
path: /code
spec: mfem@master+examples+miniapps
+56
View File
@@ -0,0 +1,56 @@
MFEM mesh v1.0
#
# MFEM Geomety Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
# PYRAMID = 7
dimension
3
elements
4
1 5 0 1 4 3 6 7 10 9
1 6 4 1 5 10 7 11
1 7 11 7 1 5 8
1 4 2 5 1 8
boundary
14
1 3 0 3 4 1
1 3 6 7 10 9
1 3 0 6 9 3
1 3 0 1 7 6
1 3 3 9 10 4
1 2 1 5 2
1 2 1 4 5
1 2 1 8 7
1 2 1 2 8
1 2 2 5 8
1 2 5 11 8
1 2 7 8 11
1 2 7 11 10
1 3 4 10 11 5
vertices
12
3
0 0 0
1 0 0
2 0 0
0 1 0
1 1 0
2 1 0
0 0 1
1 0 1
2 0 1
0 1 1
1 1 1
2 1 1
+9
View File
@@ -30,6 +30,7 @@
//
// Device sample runs:
// ex1 -pa -d cuda
// ex1 -fa -d cuda
// ex1 -pa -d raja-cuda
// * ex1 -pa -d raja-hip
// ex1 -pa -d occa-cuda
@@ -37,9 +38,13 @@
// ex1 -pa -d occa-omp
// ex1 -pa -d ceed-cpu
// ex1 -pa -d ceed-cpu -o 4 -a
// ex1 -pa -d ceed-cpu -m ../data/square-mixed.mesh
// ex1 -pa -d ceed-cpu -m ../data/fichera-mixed.mesh
// * ex1 -pa -d ceed-cuda
// * ex1 -pa -d ceed-hip
// ex1 -pa -d ceed-cuda:/gpu/cuda/shared
// ex1 -pa -d ceed-cuda:/gpu/cuda/shared -m ../data/square-mixed.mesh
// ex1 -pa -d ceed-cuda:/gpu/cuda/shared -m ../data/fichera-mixed.mesh
// 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
@@ -73,6 +78,7 @@ int main(int argc, char *argv[])
int order = 1;
bool static_cond = false;
bool pa = false;
bool fa = false;
const char *device_config = "cpu";
bool visualization = true;
bool algebraic_ceed = false;
@@ -87,6 +93,8 @@ 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(&fa, "-fa", "--full-assembly", "-no-fa",
"--no-full-assembly", "Enable Full Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
#ifdef MFEM_USE_CEED
@@ -184,6 +192,7 @@ int main(int argc, char *argv[])
// domain integrator.
BilinearForm a(&fespace);
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
if (fa) { a.SetAssemblyLevel(AssemblyLevel::FULL); }
a.AddDomainIntegrator(new DiffusionIntegrator(one));
// 10. Assemble the bilinear form and the corresponding linear system,
+2
View File
@@ -305,6 +305,8 @@ int main(int argc, char *argv[])
vis_w.precision(8);
visualize(vis_w, mesh, &x, &w, "Elastic energy density", true);
}
cout << "GLVis visualization paused."
<< " Press space (in the GLVis window) to resume it.\n";
}
double ee0 = oper.ElasticEnergy(x.GetTrueVector());
+5
View File
@@ -351,6 +351,11 @@ int main(int argc, char *argv[])
vis_w.precision(8);
visualize(vis_w, pmesh, &x_gf, &w_gf, "Elastic energy density", true);
}
if (myid == 0)
{
cout << "GLVis visualization paused."
<< " Press space (in the GLVis window) to resume it.\n";
}
}
double ee0 = oper.ElasticEnergy(x_gf);
+2 -2
View File
@@ -43,7 +43,7 @@
#include <sstream>
#include <iostream>
// Classes FE_Evolution, RiemannSolver, DomainIntegrator and FaceIntegrator
// Classes FE_Evolution, RiemannSolver, and FaceIntegrator
// shared between the serial and parallel version of the example.
#include "ex18.hpp"
@@ -189,7 +189,7 @@ int main(int argc, char *argv[])
// 7. Set up the nonlinear form corresponding to the DG discretization of the
// flux divergence, and assemble the corresponding mass matrix.
MixedBilinearForm Aflux(&dfes, &fes);
Aflux.AddDomainIntegrator(new DomainIntegrator(dim));
Aflux.AddDomainIntegrator(new TransposeIntegrator(new GradientIntegrator()));
Aflux.Assemble();
NonlinearForm A(&vfes);
-75
View File
@@ -56,27 +56,6 @@ public:
const Vector &nor, Vector &flux);
};
// Constant (in time) mixed bilinear form multiplying the flux grid function.
// The form is (vec(v), grad(w)) where the trial space = vector L2 space (mesh
// dim) and test space = scalar L2 space.
class DomainIntegrator : public BilinearFormIntegrator
{
private:
Vector shape;
DenseMatrix flux;
DenseMatrix dshapedr;
DenseMatrix dshapedx;
public:
DomainIntegrator(const int dim);
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Tr,
DenseMatrix &elmat);
};
// Interior face term: <F.n(u),[w]>
class FaceIntegrator : public NonlinearFormIntegrator
{
@@ -318,60 +297,6 @@ double RiemannSolver::Eval(const Vector &state1, const Vector &state2,
return maxE;
}
// Implementation of class DomainIntegrator
DomainIntegrator::DomainIntegrator(const int dim) : flux(num_equation, dim) { }
void DomainIntegrator::AssembleElementMatrix2(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Tr,
DenseMatrix &elmat)
{
// Assemble the form (vec(v), grad(w))
// Trial space = vector L2 space (mesh dim)
// Test space = scalar L2 space
const int dof_trial = trial_fe.GetDof();
const int dof_test = test_fe.GetDof();
const int dim = trial_fe.GetDim();
shape.SetSize(dof_trial);
dshapedr.SetSize(dof_test, dim);
dshapedx.SetSize(dof_test, dim);
elmat.SetSize(dof_test, dof_trial * dim);
elmat = 0.0;
const int maxorder = max(trial_fe.GetOrder(), test_fe.GetOrder());
const int intorder = 2 * maxorder;
const IntegrationRule *ir = &IntRules.Get(trial_fe.GetGeomType(), intorder);
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
// Calculate the shape functions
trial_fe.CalcShape(ip, shape);
shape *= ip.weight;
// Compute the physical gradients of the test functions
Tr.SetIntPoint(&ip);
test_fe.CalcDShape(ip, dshapedr);
Mult(dshapedr, Tr.AdjugateJacobian(), dshapedx);
for (int d = 0; d < dim; d++)
{
for (int j = 0; j < dof_test; j++)
{
for (int k = 0; k < dof_trial; k++)
{
elmat(j, k + d * dof_trial) += shape(k) * dshapedx(j, d);
}
}
}
}
}
// Implementation of class FaceIntegrator
FaceIntegrator::FaceIntegrator(RiemannSolver &rsolver_, const int dim) :
rsolver(rsolver_),
+2 -2
View File
@@ -43,7 +43,7 @@
#include <sstream>
#include <iostream>
// Classes FE_Evolution, RiemannSolver, DomainIntegrator and FaceIntegrator
// Classes FE_Evolution, RiemannSolver, and FaceIntegrator
// shared between the serial and parallel version of the example.
#include "ex18.hpp"
@@ -219,7 +219,7 @@ int main(int argc, char *argv[])
// 9. Set up the nonlinear form corresponding to the DG discretization of the
// flux divergence, and assemble the corresponding mass matrix.
MixedBilinearForm Aflux(&dfes, &fes);
Aflux.AddDomainIntegrator(new DomainIntegrator(dim));
Aflux.AddDomainIntegrator(new TransposeIntegrator(new GradientIntegrator()));
Aflux.Assemble();
ParNonlinearForm A(&vfes);
+9
View File
@@ -30,13 +30,18 @@
//
// Device sample runs:
// mpirun -np 4 ex1p -pa -d cuda
// mpirun -np 4 ex1p -fa -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-cpu -o 4 -a
// mpirun -np 4 ex1p -pa -d ceed-cpu -m ../data/square-mixed.mesh
// mpirun -np 4 ex1p -pa -d ceed-cpu -m ../data/fichera-mixed.mesh
// * 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 -pa -d ceed-cuda:/gpu/cuda/shared -m ../data/square-mixed.mesh
// mpirun -np 4 ex1p -pa -d ceed-cuda:/gpu/cuda/shared -m ../data/fichera-mixed.mesh
// mpirun -np 4 ex1p -m ../data/beam-tet.mesh -pa -d ceed-cpu
//
// Description: This example code demonstrates the use of MFEM to define a
@@ -74,6 +79,7 @@ int main(int argc, char *argv[])
int order = 1;
bool static_cond = false;
bool pa = false;
bool fa = false;
const char *device_config = "cpu";
bool visualization = true;
bool algebraic_ceed = false;
@@ -88,6 +94,8 @@ 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(&fa, "-fa", "--full-assembly", "-no-fa",
"--no-full-assembly", "Enable Full Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
#ifdef MFEM_USE_CEED
@@ -211,6 +219,7 @@ int main(int argc, char *argv[])
// Diffusion domain integrator.
ParBilinearForm a(&fespace);
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
if (fa) { a.SetAssemblyLevel(AssemblyLevel::FULL); }
a.AddDomainIntegrator(new DiffusionIntegrator(one));
// 12. Assemble the parallel bilinear form and the corresponding linear
+1 -1
View File
@@ -182,7 +182,7 @@ int main(int argc, char *argv[])
}
for (int level = 0; level < order_refinements; ++level)
{
collections.Append(new H1_FECollection(std::pow(2, level+1), dim));
collections.Append(new H1_FECollection((int)std::pow(2, level+1), dim));
fespaces.AddOrderRefinedLevel(collections.Last());
}
+1 -1
View File
@@ -219,7 +219,7 @@ int main(int argc, char *argv[])
}
for (int level = 0; level < order_refinements; ++level)
{
collections.Append(new H1_FECollection(std::pow(2, level+1), dim));
collections.Append(new H1_FECollection((int)std::pow(2, level+1), dim));
fespaces->AddOrderRefinedLevel(collections.Last());
}
+280 -68
View File
@@ -3,34 +3,63 @@
// Compile with: make ex33
//
// Sample runs: ex33 -m ../data/square-disc.mesh -alpha 0.33 -o 2
// ex33 -m ../data/square-disc.mesh -alpha 4.5 -o 3
// ex33 -m ../data/star.mesh -alpha 1.4 -o 3
// ex33 -m ../data/star.mesh -alpha 0.99 -o 3
// ex33 -m ../data/inline-quad.mesh -alpha 0.5 -o 3
// ex33 -m ../data/amr-quad.mesh -alpha 1.5 -o 3
// ex33 -m ../data/disc-nurbs.mesh -alpha 0.33 -o 3
// ex33 -m ../data/disc-nurbs.mesh -alpha 2.4 -o 3 -r 4
// ex33 -m ../data/l-shape.mesh -alpha 0.33 -o 3 -r 4
// ex33 -m ../data/l-shape.mesh -alpha 1.7 -o 3 -r 5
//
// Verification runs:
// ex33 -m ../data/inline-segment.mesh -ver -alpha 1.7 -o 2 -r 2
// ex33 -m ../data/inline-quad.mesh -ver -alpha 1.2 -o 2 -r 2
// ex33 -m ../data/amr-quad.mesh -ver -alpha 2.6 -o 2 -r 2
// ex33 -m ../data/inline-hex.mesh -ver -alpha 0.3 -o 2 -r 1
//
// Note: the analytic solution to this problem is u = ∏_{i=0}^{dim-1} sin(π x_i)
// for all alpha.
//
// Description:
//
// In this example we solve the following fractional PDE with MFEM:
//
// ( - Δ )^α u = f in Ω, u = 0 on ∂Ω, 0 < α < 1,
// ( - Δ )^α u = f in Ω, u = 0 on ∂Ω, 0 < α,
//
// To solve this FPDE, we rely on a rational approximation [2] of the normal
// linear operator A^{-α}, where A = - Δ (with associated homogeneous
// boundary conditions). Namely, we first approximate the operator
// To solve this FPDE, we apply the operator ( - Δ )^(-N), where the integer
// N is given by floor(α). By doing so, we obtain
//
// A^{-α} ≈ Σ_{i=0}^N c_i (A + d_i I)^{-1}, d_0 = 0, d_i > 0,
// ( - Δ )^(α-N) u = ( - Δ )^(-N) f in Ω, u = 0 on ∂Ω, 0 < α.
//
// We first compute the right hand side by solving the integer order PDE
//
// ( - Δ )^N g = f in Ω, g = ( - Δ )^k g = 0 on ∂Ω, k = 1,..,N-1
//
// The remaining FPDE is then given by
//
// ( - Δ )^(α-N) u = g in Ω, u = 0 on ∂Ω.
//
// We rely on a rational approximation [2] of the normal linear operator
// A^{-α + N}, where A = - Δ (with associated homogeneous boundary conditions)
// and (a-N) in (0,1). We approximate the operator
//
// A^{-α+N} ≈ Σ_{i=0}^M c_i (A + d_i I)^{-1}, d_0 = 0, d_i > 0,
//
// where I is the L2-identity operator and the coefficients c_i and d_i
// are generated offline to a prescribed accuracy in a pre-processing step.
// We use the triple-A algorithm [1] to generate the rational approximation
// that this partial fractional expansion derives from. We then solve N+1
// that this partial fractional expansion derives from. We then solve M+1
// independent integer-order PDEs,
//
// A u_i + d_i u_i = c_i f in Ω, u_i = 0 on ∂Ω, i=0,...,N,
// A u_i + d_i u_i = c_i g in Ω, u_i = 0 on ∂Ω, i=0,...,M,
//
// using MFEM and sum u_i to arrive at an approximate solution of the FPDE
//
// u ≈ Σ_{i=0}^N u_i.
// u ≈ Σ_{i=0}^M u_i.
//
// (If alpha is an integer, we stop after the first PDE was solved.)
//
// References:
//
@@ -47,6 +76,8 @@
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string>
#include "ex33.hpp"
@@ -59,8 +90,9 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/star.mesh";
int order = 1;
int num_refs = 3;
bool visualization = true;
double alpha = 0.5;
bool visualization = true;
bool verification = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -75,6 +107,9 @@ int main(int argc, char *argv[])
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&verification, "-ver", "--verification", "-no-ver",
"--no-verification",
"Use sinusoidal function (f) for analytic comparison.");
args.Parse();
if (!args.Good())
{
@@ -84,9 +119,31 @@ int main(int argc, char *argv[])
args.PrintOptions(cout);
Array<double> coeffs, poles;
int progress_steps = 1;
// 2. Compute the coefficients that define the integer-order PDEs.
ComputePartialFractionApproximation(alpha,coeffs,poles);
// 2. Compute the rational expansion coefficients that define the
// integer-order PDEs.
const int power_of_laplace = floor(alpha);
double exponent_to_approximate = alpha - power_of_laplace;
bool integer_order = false;
// Check if alpha is an integer or not.
if (abs(exponent_to_approximate) > 1e-12)
{
mfem::out << "Approximating the fractional exponent "
<< exponent_to_approximate
<< endl;
ComputePartialFractionApproximation(exponent_to_approximate, coeffs,
poles);
// If the example is build without LAPACK, the exponent_to_approximate
// might be modified by the function call above.
alpha = exponent_to_approximate + power_of_laplace;
}
else
{
integer_order = true;
mfem::out << "Treating integer order PDE." << endl;
}
// 3. Read the mesh from the given mesh file.
Mesh mesh(mesh_file, 1, 1);
@@ -99,8 +156,8 @@ int main(int argc, char *argv[])
}
// 5. Define a finite element space on the mesh.
FiniteElementCollection *fec = new H1_FECollection(order, dim);
FiniteElementSpace fespace(&mesh, fec);
H1_FECollection fec(order, dim);
FiniteElementSpace fespace(&mesh, &fec);
cout << "Number of finite element unknowns: "
<< fespace.GetTrueVSize() << endl;
@@ -114,79 +171,234 @@ int main(int argc, char *argv[])
}
// 7. Define diffusion coefficient, load, and solution GridFunction.
ConstantCoefficient f(1.0);
auto func = [&alpha](const Vector &x)
{
double val = 1.0;
for (int i=0; i<x.Size(); i++)
{
val *= sin(M_PI*x(i));
}
return pow(x.Size()*pow(M_PI,2), alpha) * val;
};
FunctionCoefficient f(func);
ConstantCoefficient one(1.0);
GridFunction u(&fespace);
u = 0.;
GridFunction x(&fespace);
GridFunction g(&fespace);
u = 0.0;
x = 0.0;
g = 0.0;
// 8. Prepare for visualization.
char vishost[] = "localhost";
int visport = 19916;
socketstream xout, uout;
ostringstream oss_x, oss_u;
if (visualization)
// 9. Set up the linear form b(.) for integer-order PDE solves.
LinearForm b(&fespace);
if (verification)
{
xout.open(vishost, visport);
xout.precision(8);
uout.open(vishost, visport);
uout.precision(8);
// This statement is only relevant for the verification of the code. It
// uses a different f such that an analytic solution is known and easy
// to compare with the numerical one. The FPDE becomes:
// (-Δ)^α u = (2\pi ^2)^α sin(\pi x) sin(\pi y) on [0,1]^2
// -> u(x,y) = sin(\pi x) sin(\pi y)
b.AddDomainIntegrator(new DomainLFIntegrator(f));
}
for (int i = 0; i < coeffs.Size(); i++)
else
{
// 9. Set up the linear form b(.) for integer-order PDE solve.
LinearForm b(&fespace);
ProductCoefficient cf(coeffs[i], f);
b.AddDomainIntegrator(new DomainLFIntegrator(cf));
b.Assemble();
b.AddDomainIntegrator(new DomainLFIntegrator(one));
}
b.Assemble();
// 10. Define GridFunction for integer-order PDE solve.
GridFunction x(&fespace);
x = 0.0;
// ------------------------------------------------------------------------
// 10. Solve the PDE (-Δ)^N g = f, i.e. compute g = (-Δ)^{-1}^N f.
// ------------------------------------------------------------------------
// 11. Set up the bilinear form a(.,.) for integer-order PDE solve.
BilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator(one));
ConstantCoefficient c2(-poles[i]);
a.AddDomainIntegrator(new MassIntegrator(c2));
a.Assemble();
if (power_of_laplace > 0)
{
// 10.1 Compute Stiffnes Matrix
BilinearForm k(&fespace);
k.AddDomainIntegrator(new DiffusionIntegrator(one));
k.Assemble();
// 12. Assemble the bilinear form and the corresponding linear system.
OperatorPtr A;
// 10.2 Compute Mass Matrix
BilinearForm m(&fespace);
m.AddDomainIntegrator(new MassIntegrator(one));
m.Assemble();
SparseMatrix mass;
Array<int> empty;
m.FormSystemMatrix(empty, mass);
// 10.3 Form the system of equations
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
OperatorPtr Op;
k.FormLinearSystem(ess_tdof_list, g, b, Op, X, B);
GSSmoother M((SparseMatrix&)(*Op));
// 13. Solve the linear system A X = B.
GSSmoother M((SparseMatrix&)(*A));
mfem::out << "\nSolving PDE -Δ u + " << -poles[i]
<< " u = " << coeffs[i] << " f " << endl;
PCG(*A, M, B, X, 3, 200, 1e-12, 0.0);
// 14. Recover the solution as a finite element grid function.
a.RecoverFEMSolution(X, b, x);
// 15. Accumulate integer-order PDE solutions.
u+=x;
// 16. Send the solutions by socket to a GLVis server.
if (visualization)
mfem::out << "\nComputing (-Δ) ^ -" << power_of_laplace
<< " ( f ) " << endl;
for (int i = 0; i < power_of_laplace; i++)
{
oss_x.str(""); oss_x.clear();
oss_x << "Solution of PDE -Δ u + " << -poles[i]
<< " u = " << coeffs[i] << " f";
xout << "solution\n" << mesh << x
<< "window_title '" << oss_x.str() << "'" << flush;
// 10.4 Solve the linear system Op X = B (N times).
PCG(*Op, M, B, X, 3, 300, 1e-12, 0.0);
oss_u.str(""); oss_u.clear();
oss_u << "Solution of fractional PDE -Δ^" << alpha
<< " u = f";
uout << "solution\n" << mesh << u
<< "window_title '" << oss_u.str() << "'" << flush;
// 10.5 Visualize the solution g of -Δ ^ N g = f in the last step
if (i == power_of_laplace - 1)
{
// Needed for visualization and solution verification.
k.RecoverFEMSolution(X, b, g);
if (integer_order && verification)
{
// For an integer order PDE, g is also our solution u.
u+=g;
}
if (visualization)
{
socketstream fout;
ostringstream oss_f;
fout.open(vishost, visport);
fout.precision(8);
oss_f.str(""); oss_f.clear();
oss_f << "Step " << progress_steps++ << ": Solution of PDE -Δ ^ "
<< power_of_laplace
<< " g = f";
fout << "solution\n" << mesh << g
<< "window_title '" << oss_f.str() << "'" << flush;
}
}
// 10.6 Prepare for next iteration (primal / dual space)
mass.Mult(X, B);
X.SetSubVectorComplement(ess_tdof_list,0.0);
}
// 10.7 Extract solution for the next step. The b now corresponds to the
// function g in the PDE.
const SparseMatrix * R = fespace.GetRestrictionMatrix();
if (R)
{
R->MultTranspose(B,b);
}
else
{
b = B;
}
}
// 17. Free the used memory.
delete fec;
// ------------------------------------------------------------------------
// 11. Solve the fractional PDE by solving M integer order PDEs and adding
// up the solutions.
// ------------------------------------------------------------------------
if (!integer_order)
{
// Setup visualization.
socketstream xout, uout;
ostringstream oss_x, oss_u;
if (visualization)
{
xout.open(vishost, visport);
xout.precision(8);
uout.open(vishost, visport);
uout.precision(8);
}
// Iterate over all expansion coefficient that contribute to the
// solution.
for (int i = 0; i < coeffs.Size(); i++)
{
mfem::out << "\nSolving PDE -Δ u + " << -poles[i]
<< " u = " << coeffs[i] << " g " << endl;
// 11.1 Reset GridFunction for integer-order PDE solve.
x = 0.0;
// 11.2 Set up the bilinear form a(.,.) for integer-order PDE solve.
BilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator(one));
ConstantCoefficient d_i(-poles[i]);
a.AddDomainIntegrator(new MassIntegrator(d_i));
a.Assemble();
// 11.3 Assemble the bilinear form and the corresponding linear system.
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
// 11.4 Solve the linear system A X = B.
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 3, 300, 1e-12, 0.0);
// 11.5 Recover the solution as a finite element grid function.
a.RecoverFEMSolution(X, b, x);
// 11.6 Accumulate integer-order PDE solutions.
x *= coeffs[i];
u += x;
// 11.7 Send fractional PDE solution to a GLVis server.
if (visualization)
{
oss_x.str(""); oss_x.clear();
oss_x << "Step " << progress_steps
<< ": Solution of PDE -Δ u + " << -poles[i]
<< " u = " << coeffs[i] << " g";
xout << "solution\n" << mesh << x
<< "window_title '" << oss_x.str() << "'" << flush;
oss_u.str(""); oss_u.clear();
oss_u << "Step " << progress_steps + 1
<< ": Solution of fractional PDE (-Δ)^" << alpha
<< " u = f";
uout << "solution\n" << mesh << u
<< "window_title '" << oss_u.str() << "'"
<< flush;
}
}
}
// ------------------------------------------------------------------------
// 12. (optional) Verify the solution.
// ------------------------------------------------------------------------
if (verification)
{
auto solution = [] (const Vector &x)
{
double val = 1.0;
for (int i=0; i<x.Size(); i++)
{
val *= sin(M_PI*x(i));
}
return val;
};
FunctionCoefficient sol(solution);
double l2_error = u.ComputeL2Error(sol);
string analytic_solution,expected_mesh;
switch (dim)
{
case 1:
analytic_solution = "sin(π x)";
expected_mesh = "inline_segment.mesh";
break;
case 2:
analytic_solution = "sin(π x) sin(π y)";
expected_mesh = "inline_quad.mesh";
break;
default:
analytic_solution = "sin(π x) sin(π y) sin(π z)";
expected_mesh = "inline_hex.mesh";
break;
}
mfem::out << "\n" << string(80,'=')
<< "\n\nSolution Verification in "<< dim << "D \n\n"
<< "Analytic solution : " << analytic_solution << "\n"
<< "Expected mesh : " << expected_mesh <<"\n"
<< "Your mesh : " << mesh_file << "\n"
<< "L2 error : " << l2_error << "\n\n"
<< string(80,'=') << endl;
}
return 0;
}
+15 -4
View File
@@ -32,6 +32,7 @@
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
using namespace mfem;
@@ -249,6 +250,13 @@ void PartialFractionExpansion(double scale, Array<double> & poles,
coeffs.SetSize(psize);
coeffs = scale;
// Note: C p(z)/q(z) = Σ_i c_i / (z - p_i) results in an system of equations
// where the N unknowns are the coefficients c_i. After multiplying the
// system with q(z), the coefficients c_i can be computed analytically by
// choosing N values for z. Choosing z_j = = p_j diagonalizes the system and
// one can obtain an analytic form for the c_i coefficients. The result is
// implemented in the code block below.
for (int i=0; i<psize; i++)
{
double tmp_numer=1.0;
@@ -305,9 +313,12 @@ void ComputePartialFractionApproximation(double & alpha,
if (print_warning)
{
mfem::out
<< "\nMFEM is compiled without LAPACK.\nUsing precomputed values for PartialFractionApproximation. \n"
<< "Only alpha = 0.33, 0.5, and 0.99 are available.\nThe default is alpha = 0.5."
<< std::endl;
<< "\n" << string(80, '=')
<< "\nMFEM is compiled without LAPACK."
<< "\nUsing precomputed values for PartialFractionApproximation."
<< "\nOnly alpha = 0.33, 0.5, and 0.99 are available."
<< "\nThe default is alpha = 0.5.\n" << string(80, '=') << "\n"
<< endl;
}
const double eps = std::numeric_limits<double>::epsilon();
@@ -351,7 +362,7 @@ void ComputePartialFractionApproximation(double & alpha,
if (print_warning)
{
mfem::out << "Using precomputed values for alpha = "
mfem::out << "=> Using precomputed values for alpha = "
<< alpha << "\n" << std::endl;
}
+294 -143
View File
@@ -3,34 +3,63 @@
// Compile with: make ex33p
//
// Sample runs: mpirun -np 4 ex33p -m ../data/square-disc.mesh -alpha 0.33 -o 2
// mpirun -np 4 ex33p -m ../data/square-disc.mesh -alpha 4.5 -o 3
// mpirun -np 4 ex33p -m ../data/star.mesh -alpha 1.4 -o 3
// mpirun -np 4 ex33p -m ../data/star.mesh -alpha 0.99 -o 3
// mpirun -np 4 ex33p -m ../data/inline-quad.mesh -alpha 0.5 -o 3
// mpirun -np 4 ex33p -m ../data/disc-nurbs.mesh -alpha 0.33 -o 3
// mpirun -np 4 ex33p -m ../data/amr-quad.mesh -alpha 1.5 -o 3
// mpirun -np 4 ex33p -m ../data/disc-nurbs.mesh -alpha 0.33 -o 3 -r 2
// mpirun -np 4 ex33p -m ../data/disc-nurbs.mesh -alpha 2.4 -o 3 -r 4
// mpirun -np 4 ex33p -m ../data/l-shape.mesh -alpha 0.33 -o 3 -r 4
// mpirun -np 4 ex33p -m ../data/l-shape.mesh -alpha 1.7 -o 3 -r 5
//
// Verification runs:
// mpirun -np 4 ex33p -m ../data/inline-segment.mesh -ver -alpha 1.7 -o 2 -r 2
// mpirun -np 4 ex33p -m ../data/inline-quad.mesh -ver -alpha 1.2 -o 2 -r 2
// mpirun -np 4 ex33p -m ../data/amr-quad.mesh -ver -alpha 2.6 -o 2 -r 2
// mpirun -np 4 ex33p -m ../data/inline-hex.mesh -ver -alpha 0.3 -o 2 -r 1
// Note: the analytic solution to this problem is u = ∏_{i=0}^{dim-1} sin(π x_i)
// for all alpha.
//
// Description:
//
// In this example we solve the following fractional PDE with MFEM:
//
// ( - Δ )^α u = f in Ω, u = 0 on ∂Ω, 0 < α < 1,
// ( - Δ )^α u = f in Ω, u = 0 on ∂Ω, 0 < α,
//
// To solve this FPDE, we rely on a rational approximation [2] of the normal
// linear operator A^{-α}, where A = - Δ (with associated homogeneous
// boundary conditions). Namely, we first approximate the operator
// To solve this FPDE, we apply the operator ( - Δ )^(-N), where the integer
// N is given by floor(α). By doing so, we obtain
//
// A^{-α} ≈ Σ_{i=0}^N c_i (A + d_i I)^{-1}, d_0 = 0, d_i > 0,
// ( - Δ )^(α-N) u = ( - Δ )^(-N) f in Ω, u = 0 on ∂Ω, 0 < α.
//
// We first compute the right hand side by solving the integer order PDE
//
// ( - Δ )^N g = f in Ω, g = ( - Δ )^k g = 0 on ∂Ω, k = 1,..,N-1
//
// The remaining FPDE is then given by
//
// ( - Δ )^(α-N) u = g in Ω, u = 0 on ∂Ω.
//
// We rely on a rational approximation [2] of the normal linear operator
// A^{-α + N}, where A = - Δ (with associated homogeneous boundary conditions)
// and (a-N) in (0,1). We approximate the operator
//
// A^{-α+N} ≈ Σ_{i=0}^M c_i (A + d_i I)^{-1}, d_0 = 0, d_i > 0,
//
// where I is the L2-identity operator and the coefficients c_i and d_i
// are generated offline to a prescribed accuracy in a pre-processing step.
// We use the triple-A algorithm [1] to generate the rational approximation
// that this partial fractional expansion derives from. We then solve N+1
// that this partial fractional expansion derives from. We then solve M+1
// independent integer-order PDEs,
//
// A u_i + d_i u_i = c_i f in Ω, u_i = 0 on ∂Ω, i=0,...,N,
// A u_i + d_i u_i = c_i g in Ω, u_i = 0 on ∂Ω, i=0,...,M,
//
// using MFEM and sum u_i to arrive at an approximate solution of the FPDE
//
// u ≈ Σ_{i=0}^N u_i.
// u ≈ Σ_{i=0}^M u_i.
//
// (If alpha is an integer, we stop after the first PDE was solved.)
//
// References:
//
@@ -47,6 +76,8 @@
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string>
#include "ex33.hpp"
@@ -65,9 +96,9 @@ int main(int argc, char *argv[])
const char *mesh_file = "../data/star.mesh";
int order = 1;
int num_refs = 3;
bool visualization = true;
bool visualize_x = false;
double alpha = 0.5;
bool visualization = true;
bool verification = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -79,12 +110,12 @@ int main(int argc, char *argv[])
"Number of uniform refinements");
args.AddOption(&alpha, "-alpha", "--alpha",
"Fractional exponent");
args.AddOption(&visualize_x, "-vis_x", "--visualize_x", "-no-vis_x",
"--no-visualization_x",
"Enable or disable GLVis visualization of each integer-order PDE solution.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization of the fractional PDE solution.");
"Enable or disable GLVis visualization.");
args.AddOption(&verification, "-ver", "--verification", "-no-ver",
"--no-verification",
"Use sinusoidal function (f) for analytic comparison.");
args.Parse();
if (!args.Good())
{
@@ -97,61 +128,51 @@ int main(int argc, char *argv[])
}
Array<double> coeffs, poles;
int progress_steps = 1;
// 2. Compute the coefficients that define the integer-order PDEs.
ComputePartialFractionApproximation(alpha,coeffs,poles);
int num_par_solves;
int max_par_solves = max(1,num_procs/2);
for (num_par_solves=max_par_solves; num_par_solves>0; num_par_solves--)
// 2. Compute the rational expansion coefficients that define the
// integer-order PDEs.
const int power_of_laplace = floor(alpha);
double exponent_to_approximate = alpha - power_of_laplace;
bool integer_order = false;
// Check if alpha is an integer or not.
if (abs(exponent_to_approximate) > 1e-12)
{
if (num_procs%num_par_solves==0 && num_par_solves<coeffs.Size())
if (Mpi::Root())
{
break;
mfem::out << "Approximating the fractional exponent "
<< exponent_to_approximate
<< endl;
}
ComputePartialFractionApproximation(exponent_to_approximate, coeffs,
poles);
// If the example is build without LAPACK, the exponent_to_approximate
// might be modified by the function call above.
alpha = exponent_to_approximate + power_of_laplace;
}
else
{
integer_order = true;
if (Mpi::Root())
{
mfem::out << "Treating integer order PDE." << endl;
}
}
if (num_par_solves == 1) {num_par_solves = num_procs;}
int solver_ranks = num_procs/num_par_solves;
// 3. Split the MPI communicator:
// row_comm is used for parallel partition of the mesh
// col_comm is used for independent integer-order solves
int row_color = myid / solver_ranks; // Determine color based on row
int col_color = myid % solver_ranks; // Determine color based on col
MPI_Comm row_comm, col_comm;
MPI_Comm_split(MPI_COMM_WORLD, row_color, myid, &row_comm);
MPI_Comm_split(MPI_COMM_WORLD, col_color, myid, &col_comm);
int row_rank, row_size, col_rank, col_size;
MPI_Comm_rank(row_comm, &row_rank);
MPI_Comm_size(row_comm, &row_size);
MPI_Comm_rank(col_comm, &col_rank);
MPI_Comm_size(col_comm, &col_size);
if (Mpi::Root())
{
mfem::out << "\nTotal number of MPI ranks = " << num_procs << endl;
mfem::out << "Number of independent parallel solves = " << col_size << endl;
mfem::out << "Number of MPI ranks within each solve = " << row_size
<<"\n" << endl;
}
// 4. Read the mesh from the given mesh file.
// 3. Read the mesh from the given mesh file.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
// 5. Refine the mesh to increase the resolution.
// 4. Refine the mesh to increase the resolution.
for (int i = 0; i < num_refs; i++)
{
mesh.UniformRefinement();
}
ParMesh pmesh(row_comm, mesh);
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
// 6. Define a finite element space on the mesh.
// 5. Define a finite element space on the mesh.
H1_FECollection fec(order, dim);
ParFiniteElementSpace fespace(&pmesh, &fec);
if (Mpi::Root())
@@ -160,7 +181,7 @@ int main(int argc, char *argv[])
<< fespace.GetTrueVSize() << endl;
}
// 7. Determine the list of true (i.e. conforming) essential boundary dofs.
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
Array<int> ess_tdof_list;
if (pmesh.bdr_attributes.Size())
{
@@ -169,120 +190,250 @@ int main(int argc, char *argv[])
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 8. Define diffusion coefficient, load, and solution GridFunction.
ConstantCoefficient f(1.0);
// 7. Define diffusion coefficient, load, and solution GridFunction.
auto func = [&alpha](const Vector &x)
{
double val = 1.0;
for (int i=0; i<x.Size(); i++)
{
val *= sin(M_PI*x(i));
}
return pow(x.Size()*pow(M_PI,2), alpha) * val;
};
FunctionCoefficient f(func);
ConstantCoefficient one(1.0);
ParGridFunction u(&fespace);
ParGridFunction x(&fespace);
ParGridFunction g(&fespace);
u = 0.0;
x = 0.0;
g = 0.0;
// 8. Prepare for visualization.
char vishost[] = "localhost";
int visport = 19916;
// 9. Set up the linear form b(.) for integer-order PDE solves.
ParLinearForm b(&fespace);
b.AddDomainIntegrator(new DomainLFIntegrator(f));
if (verification)
{
// This statement is only relevant for the verification of the code. It
// uses a different f such that an analytic solution is known and easy
// to compare with the numerical one. The FPDE becomes:
// (-Δ)^α u = (2\pi ^2)^α sin(\pi x) sin(\pi y) on [0,1]^2
// -> u(x,y) = sin(\pi x) sin(\pi y)
b.AddDomainIntegrator(new DomainLFIntegrator(f));
}
else
{
b.AddDomainIntegrator(new DomainLFIntegrator(one));
}
b.Assemble();
int my_coeff_size = max(coeffs.Size()/col_size,1);
int ibeg = col_rank*my_coeff_size;
if (ibeg + 2*my_coeff_size > coeffs.Size())
// ------------------------------------------------------------------------
// 10. Solve the PDE (-Δ)^N g = f, i.e. compute g = (-Δ)^{-1}^N f.
// ------------------------------------------------------------------------
if (power_of_laplace > 0)
{
my_coeff_size = coeffs.Size()-col_rank*my_coeff_size;
}
else if (ibeg > coeffs.Size() - 1)
{
my_coeff_size = 0;
}
// 10.1 Compute Stiffnes Matrix
ParBilinearForm k(&fespace);
k.AddDomainIntegrator(new DiffusionIntegrator(one));
k.Assemble();
int iend = ibeg+my_coeff_size;
// 10.2 Compute Mass Matrix
ParBilinearForm m(&fespace);
m.AddDomainIntegrator(new MassIntegrator(one));
m.Assemble();
HypreParMatrix mass;
Array<int> empty;
m.FormSystemMatrix(empty, mass);
for (int i = ibeg; i < iend; i++)
{
// 10. Reset GridFunction for integer-order PDE solve.
x = 0.0;
// 11. Set up the bilinear form a(.,.) for integer-order PDE solve.
ParBilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator(one));
ConstantCoefficient d_i(-poles[i]);
a.AddDomainIntegrator(new MassIntegrator(d_i));
a.Assemble();
// 12. Assemble the bilinear form and the corresponding linear system.
OperatorPtr A;
// 10.3 Form the system of equations
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
// 13. Solve the linear system A X = B.
HypreBoomerAMG * prec = new HypreBoomerAMG;
prec->SetPrintLevel(-1);
int print_level = (col_rank==0) ? 3 : 0;
if (Mpi::Root())
{
mfem::out << "\nMPI rank " << myid
<< ": Solving PDE -Δ u + " << -poles[i]
<< " u = " << coeffs[i] << " f " << endl;
}
CGSolver cg(row_comm);
OperatorPtr Op;
k.FormLinearSystem(ess_tdof_list, g, b, Op, X, B);
HypreBoomerAMG prec;
prec.SetPrintLevel(-1);
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(print_level);
cg.SetPreconditioner(*prec);
cg.SetOperator(*A);
cg.Mult(B, X);
delete prec;
cg.SetPrintLevel(3);
cg.SetPreconditioner(prec);
cg.SetOperator(*Op);
// 14. Recover the solution as a finite element grid function.
a.RecoverFEMSolution(X, b, x);
// 15. Accumulate integer-order PDE solutions.
x *= coeffs[i];
u += x;
// 16. Send integer-order PDE solutions to a GLVis server.
if (visualize_x)
if (Mpi::Root())
{
if (col_rank > 0 && i < iend-1)
mfem::out << "\nComputing (-Δ) ^ -" << power_of_laplace
<< " ( f ) " << endl;
}
for (int i = 0; i < power_of_laplace; i++)
{
// 10.4 Solve the linear system Op X = B (N times).
cg.Mult(B, X);
// 10.5 Visualize the solution g of -Δ ^ N g = f in the last step
if (i == power_of_laplace - 1)
{
MPI_Status status;
MPI_Recv(nullptr,0,MPI_INT, col_rank-1,0,col_comm,&status);
// Needed for visualization and solution verification.
k.RecoverFEMSolution(X, b, g);
if (integer_order && verification)
{
// For an integer order PDE, g is also our solution u.
u+=g;
}
if (visualization)
{
socketstream fout;
ostringstream oss_f;
fout.open(vishost, visport);
fout.precision(8);
oss_f.str(""); oss_f.clear();
oss_f << "Step " << progress_steps++ << ": Solution of PDE -Δ ^ "
<< power_of_laplace
<< " g = f";
fout << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << pmesh << g
<< "window_title '" << oss_f.str() << "'" << flush;
}
}
char vishost[] = "localhost";
int visport = 19916;
socketstream xout(vishost, visport);
// 10.6 Prepare for next iteration (primal / dual space)
mass.Mult(X, B);
X.SetSubVectorComplement(ess_tdof_list,0.0);
}
// 10.7 Extract solution for the next step. The b now corresponds to the
// function g in the PDE.
const SparseMatrix* rm = fespace.GetRestrictionMatrix();
rm->MultTranspose(B, b);
}
// ------------------------------------------------------------------------
// 11. Solve the fractional PDE by solving M integer order PDEs and adding
// up the solutions.
// ------------------------------------------------------------------------
if (!integer_order)
{
// Setup visualization.
socketstream xout, uout;
ostringstream oss_x, oss_u;
if (visualization)
{
xout.open(vishost, visport);
xout.precision(8);
ostringstream oss;
oss << "Solution of PDE -Δ u + " << -poles[i]
<< " u = " << coeffs[i] << " f" ;
xout << "parallel " << row_size << " " << row_rank << "\n";
xout << "solution\n" << pmesh << x
<< "window_title '" << oss.str() << "'" << flush;
if (col_rank < col_size-1)
uout.open(vishost, visport);
uout.precision(8);
}
// Iterate over all expansion coefficient that contribute to the
// solution.
for (int i = 0; i < coeffs.Size(); i++)
{
if (Mpi::Root())
{
MPI_Send(nullptr,0,MPI_INT,col_rank+1,0,col_comm);
mfem::out << "\nSolving PDE -Δ u + " << -poles[i]
<< " u = " << coeffs[i] << " g " << endl;
}
// 11.1 Reset GridFunction for integer-order PDE solve.
x = 0.0;
// 11.2 Set up the bilinear form a(.,.) for integer-order PDE solve.
ParBilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator(one));
ConstantCoefficient d_i(-poles[i]);
a.AddDomainIntegrator(new MassIntegrator(d_i));
a.Assemble();
// 11.3 Assemble the bilinear form and the corresponding linear system.
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
// 11.4 Solve the linear system A X = B.
HypreBoomerAMG prec;
prec.SetPrintLevel(-1);
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(3);
cg.SetPreconditioner(prec);
cg.SetOperator(*A);
cg.Mult(B, X);
// 11.5 Recover the solution as a finite element grid function.
a.RecoverFEMSolution(X, b, x);
// 11.6 Accumulate integer-order PDE solutions.
x *= coeffs[i];
u += x;
// 11.7 Send fractional PDE solution to a GLVis server.
if (visualization)
{
oss_x.str(""); oss_x.clear();
oss_x << "Step " << progress_steps
<< ": Solution of PDE -Δ u + " << -poles[i]
<< " u = " << coeffs[i] << " g";
xout << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << pmesh << x
<< "window_title '" << oss_x.str() << "'" << flush;
oss_u.str(""); oss_u.clear();
oss_u << "Step " << progress_steps + 1
<< ": Solution of fractional PDE (-Δ)^" << alpha
<< " u = f";
uout << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << pmesh << u
<< "window_title '" << oss_u.str() << "'"
<< flush;
}
}
}
// 17. Accumulate for the fractional PDE solution
MPI_Allreduce(MPI_IN_PLACE, u.GetData(), u.Size(),
MPI_DOUBLE, MPI_SUM,col_comm);
// 18. Send fractional PDE solution to a GLVis server.
if (visualization)
// ------------------------------------------------------------------------
// 12. (optional) Verify the solution.
// ------------------------------------------------------------------------
if (verification)
{
if (col_rank == 0)
auto solution = [] (const Vector &x)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream uout(vishost, visport);
uout.precision(8);
ostringstream oss;
oss << "Solution of fractional PDE -Δ^" << alpha
<< " u = f" ;
uout << "parallel " << row_size << " " << row_rank << "\n";
uout << "solution\n" << pmesh << u
<< "window_title '" << oss.str() << "'" << flush;
double val = 1.0;
for (int i=0; i<x.Size(); i++)
{
val *= sin(M_PI*x(i));
}
return val;
};
FunctionCoefficient sol(solution);
double l2_error = u.ComputeL2Error(sol);
if (Mpi::Root())
{
string analytic_solution,expected_mesh;
switch (dim)
{
case 1:
analytic_solution = "sin(π x)";
expected_mesh = "inline_segment.mesh";
break;
case 2:
analytic_solution = "sin(π x) sin(π y)";
expected_mesh = "inline_quad.mesh";
break;
default:
analytic_solution = "sin(π x) sin(π y) sin(π z)";
expected_mesh = "inline_hex.mesh";
break;
}
mfem::out << "\n" << string(80,'=')
<< "\n\nSolution Verification in "<< dim << "D \n\n"
<< "Analytic solution : " << analytic_solution << "\n"
<< "Expected mesh : " << expected_mesh <<"\n"
<< "Your mesh : " << mesh_file << "\n"
<< "L2 error : " << l2_error << "\n\n"
<< string(80,'=') << endl;
}
}
+25 -20
View File
@@ -58,15 +58,17 @@ set(SRCS
gridfunc.cpp
hybridization.cpp
intrules.cpp
ceed/algebraic.cpp
ceed/full-assembly.cpp
ceed/solvers-atpmg.cpp
ceed/convection.cpp
ceed/diffusion.cpp
ceed/nlconvection.cpp
ceed/mass.cpp
ceed/operator.cpp
ceed/util.cpp
ceed/interface/basis.cpp
ceed/interface/restriction.cpp
ceed/interface/operator.cpp
ceed/interface/util.cpp
ceed/integrators/convection/convection.cpp
ceed/integrators/diffusion/diffusion.cpp
ceed/integrators/nlconvection/nlconvection.cpp
ceed/integrators/mass/mass.cpp
ceed/solvers/algebraic.cpp
ceed/solvers/full-assembly.cpp
ceed/solvers/solvers-atpmg.cpp
linearform.cpp
linearform_ext.cpp
lininteg.cpp
@@ -158,17 +160,20 @@ set(HDRS
gridfunc.hpp
hybridization.hpp
intrules.hpp
ceed/algebraic.hpp
ceed/full-assembly.hpp
ceed/solvers-atpmg.hpp
ceed/coefficient.hpp
ceed/convection.hpp
ceed/diffusion.hpp
ceed/integrator.hpp
ceed/mass.hpp
ceed/nlconvection.hpp
ceed/operator.hpp
ceed/util.hpp
ceed/interface/basis.hpp
ceed/interface/integrator.hpp
ceed/interface/interface.hpp
ceed/interface/operator.hpp
ceed/interface/restriction.hpp
ceed/interface/util.hpp
ceed/integrators/convection/convection.hpp
ceed/integrators/diffusion/diffusion.hpp
ceed/integrators/mass/mass.hpp
ceed/integrators/nlconvection/nlconvection.hpp
ceed/interface/coefficient.hpp
ceed/solvers/algebraic.hpp
ceed/solvers/full-assembly.hpp
ceed/solvers/solvers-atpmg.hpp
linearform.hpp
linearform_ext.hpp
lininteg.hpp
+40 -4
View File
@@ -305,38 +305,66 @@ public:
/// Finalizes the matrix initialization.
virtual void Finalize(int skip_zeros = 1);
/// Returns a const reference to the sparse matrix.
/** @brief Returns a const reference to the sparse matrix: \f$ M \f$
This will fail if HasSpMat() is false. */
const SparseMatrix &SpMat() const
{
MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced");
return *mat;
}
/// Returns a reference to the sparse matrix: \f$ M \f$
/** @brief Returns a reference to the sparse matrix: \f$ M \f$
This will fail if HasSpMat() is false. */
SparseMatrix &SpMat()
{
MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced");
return *mat;
}
/** @brief Returns true if the sparse matrix is not null, false otherwise.
@sa SpMat(). */
bool HasSpMat()
{
return mat != nullptr;
}
/** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer
to it. Used for transfering ownership. */
SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; }
/// Returns a const reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$
/** @brief Returns a const reference to the sparse matrix of eliminated b.c.:
\f$ M_e \f$
This will fail if HasSpMatElim() is false. */
const SparseMatrix &SpMatElim() const
{
MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced");
return *mat_e;
}
/// Returns a reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$
/** @brief Returns a reference to the sparse matrix of eliminated b.c.:
\f$ M_e \f$
This will fail if HasSpMatElim() is false. */
SparseMatrix &SpMatElim()
{
MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced");
return *mat_e;
}
/** @brief Returns true if the sparse matrix of eliminated b.c.s is not null,
false otherwise.
@sa SpMatElim(). */
bool HasSpMatElim()
{
return mat_e != nullptr;
}
/// Adds new Domain Integrator. Assumes ownership of @a bfi.
void AddDomainIntegrator(BilinearFormIntegrator *bfi);
/// Adds new Domain Integrator restricted to certain elements specified by
@@ -410,6 +438,14 @@ public:
virtual const Operator *GetOutputRestriction() const
{ return GetRestriction(); }
/// @brief Compute serial RAP operator and store it in @a A as a SparseMatrix.
void SerialRAP(OperatorHandle &A)
{
MFEM_ASSERT(mat, "SerialRAP requires the SparseMatrix to be assembled.");
ConformingAssemble();
A.Reset(mat, false);
}
/** @brief Form the linear system A X = B, corresponding to this bilinear
form and the linear form @a b(.). */
/** This method applies any necessary transformations to the linear system
+53 -1
View File
@@ -16,7 +16,7 @@
#include "bilinearform.hpp"
#include "pbilinearform.hpp"
#include "pgridfunc.hpp"
#include "ceed/util.hpp"
#include "ceed/interface/util.hpp"
namespace mfem
{
@@ -251,6 +251,7 @@ PABilinearFormExtension::PABilinearFormExtension(BilinearForm *form)
void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
{
if ( Device::Allows(Backend::CEED_MASK) ) { return; }
ElementDofOrdering ordering = UsesTensorBasis(*a->FESpace())?
ElementDofOrdering::LEXICOGRAPHIC:
ElementDofOrdering::NATIVE;
@@ -956,6 +957,57 @@ void FABilinearFormExtension::Assemble()
}
}
void FABilinearFormExtension::RAP(OperatorHandle &A)
{
#ifdef MFEM_USE_MPI
if ( auto pa = dynamic_cast<ParBilinearForm*>(a) )
{
pa->ParallelRAP(*pa->mat, A);
}
else
#endif
{
a->SerialRAP(A);
}
}
void FABilinearFormExtension::EliminateBC(const Array<int> &ess_dofs,
OperatorHandle &A)
{
#ifdef MFEM_USE_MPI
if ( dynamic_cast<ParBilinearForm*>(a) )
{
A.As<HypreParMatrix>()->EliminateBC(ess_dofs,
DiagonalPolicy::DIAG_ONE);
}
else
#endif
{
A.As<SparseMatrix>()->EliminateBC(ess_dofs,
DiagonalPolicy::DIAG_ONE);
}
}
void FABilinearFormExtension::FormSystemMatrix(const Array<int> &ess_dofs,
OperatorHandle &A)
{
RAP(A);
EliminateBC(ess_dofs, A);
}
void FABilinearFormExtension::FormLinearSystem(const Array<int> &ess_tdof_list,
Vector &x, Vector &b,
OperatorHandle &A,
Vector &X, Vector &B,
int copy_interior)
{
Operator *A_out;
Operator::FormLinearSystem(ess_tdof_list, x, b, A_out, X, B, copy_interior);
delete A_out;
FormSystemMatrix(ess_tdof_list, A);
}
void FABilinearFormExtension::DGMult(const Vector &x, Vector &y) const
{
#ifdef MFEM_USE_MPI
+9
View File
@@ -125,6 +125,15 @@ public:
FABilinearFormExtension(BilinearForm *form);
void Assemble();
void RAP(OperatorHandle &A);
/** @note Always does `DIAG_ONE` policy to be consistent with
`Operator::FormConstrainedSystemOperator`. */
void EliminateBC(const Array<int> &ess_dofs, OperatorHandle &A);
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;
+2 -1
View File
@@ -1672,7 +1672,8 @@ void VectorFEDivergenceIntegrator::AssembleElementMatrix2(
{
const IntegrationPoint &ip = ir->IntPoint(i);
trial_fe.CalcDivShape(ip, divshape);
test_fe.CalcShape(ip, shape);
Trans.SetIntPoint(&ip);
test_fe.CalcPhysShape(Trans, shape);
double w = ip.weight;
if (Q)
{
+6 -3
View File
@@ -15,6 +15,7 @@
#include "../config/config.hpp"
#include "nonlininteg.hpp"
#include "fespace.hpp"
#include "ceed/interface/util.hpp"
namespace mfem
{
@@ -2397,8 +2398,9 @@ public:
scalar function given by FiniteElement through standard transformation.
Here, u is the trial function and p is the test function.
Note: the element matrix returned by AssembleElementMatrix2 does NOT depend
on the ElementTransformation Trans. */
Note: if the test space does not have map type INTEGRAL, then the element
matrix returned by AssembleElementMatrix2 will not depend on the
ElementTransformation Trans. */
class VectorFEDivergenceIntegrator : public BilinearFormIntegrator
{
protected:
@@ -2735,7 +2737,8 @@ private:
public:
DivDivIntegrator() { Q = NULL; }
DivDivIntegrator(Coefficient &q) : Q(&q) { }
DivDivIntegrator(Coefficient &q, const IntegrationRule *ir = NULL) :
BilinearFormIntegrator(ir), Q(&q) { }
virtual void AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
+11 -2
View File
@@ -12,7 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/convection.hpp"
#include "ceed/integrators/convection/convection.hpp"
using namespace std;
@@ -30,7 +30,16 @@ void ConvectionIntegrator::AssembleMF(const FiniteElementSpace &fes)
if (DeviceCanUseCeed())
{
delete ceedOp;
ceedOp = new ceed::MFConvectionIntegrator(fes, *ir, Q, alpha);
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedMFConvectionIntegrator(*this, fes, Q, alpha);
}
else
{
ceedOp = new ceed::MFConvectionIntegrator(fes, *ir, Q, alpha);
}
return;
}
MFEM_ABORT("Error: ConvectionIntegrator::AssembleMF only implemented with"
+13 -2
View File
@@ -12,7 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/convection.hpp"
#include "ceed/integrators/convection/convection.hpp"
#include "quadinterpolator.hpp"
namespace mfem
@@ -1386,7 +1386,16 @@ void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
if (DeviceCanUseCeed())
{
delete ceedOp;
ceedOp = new ceed::PAConvectionIntegrator(fes, *ir, Q, alpha);
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedPAConvectionIntegrator(*this, fes, Q, alpha);
}
else
{
ceedOp = new ceed::PAConvectionIntegrator(fes, *ir, Q, alpha);
}
return;
}
const int dims = el.GetDim();
@@ -1497,6 +1506,7 @@ static void PAConvectionApply(const int dim,
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPAConvectionApply3D<2,2>(NE,B,G,Bt,Gt,op,x,y);
case 0x23: return SmemPAConvectionApply3D<2,3>(NE,B,G,Bt,Gt,op,x,y);
case 0x24: return SmemPAConvectionApply3D<2,4>(NE,B,G,Bt,Gt,op,x,y);
case 0x26: return SmemPAConvectionApply3D<2,6>(NE,B,G,Bt,Gt,op,x,y);
@@ -1548,6 +1558,7 @@ static void PAConvectionApplyT(const int dim,
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPAConvectionApplyT3D<2,2>(NE,B,G,Bt,Gt,op,x,y);
case 0x23: return SmemPAConvectionApplyT3D<2,3>(NE,B,G,Bt,Gt,op,x,y);
case 0x24: return SmemPAConvectionApplyT3D<2,4>(NE,B,G,Bt,Gt,op,x,y);
case 0x26: return SmemPAConvectionApplyT3D<2,6>(NE,B,G,Bt,Gt,op,x,y);
+6 -1
View File
@@ -136,6 +136,9 @@ static void PADGTraceSetup(const int dim,
void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
{
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
Device::GetDeviceMemoryType() : pa_mt;
nf = fes.GetNFbyType(type);
if (nf==0) { return; }
// Assumes tensor-product elements
@@ -153,7 +156,7 @@ void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
geom = mesh->GetFaceGeometricFactors(
*ir,
FaceGeometricFactors::DETERMINANTS |
FaceGeometricFactors::NORMALS, type);
FaceGeometricFactors::NORMALS, type, mt);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
quad1D = maps->nqpt;
@@ -695,6 +698,7 @@ static void PADGTraceApply(const int dim,
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPADGTraceApply3D<2,2,1>(NF,B,Bt,op,x,y);
case 0x23: return SmemPADGTraceApply3D<2,3,1>(NF,B,Bt,op,x,y);
case 0x34: return SmemPADGTraceApply3D<3,4,2>(NF,B,Bt,op,x,y);
case 0x45: return SmemPADGTraceApply3D<4,5,2>(NF,B,Bt,op,x,y);
@@ -1124,6 +1128,7 @@ static void PADGTraceApplyTranspose(const int dim,
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPADGTraceApplyTranspose3D<2,2>(NF,B,Bt,op,x,y);
case 0x23: return SmemPADGTraceApplyTranspose3D<2,3>(NF,B,Bt,op,x,y);
case 0x34: return SmemPADGTraceApplyTranspose3D<3,4>(NF,B,Bt,op,x,y);
case 0x45: return SmemPADGTraceApplyTranspose3D<4,5>(NF,B,Bt,op,x,y);
+11 -2
View File
@@ -12,7 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/diffusion.hpp"
#include "ceed/integrators/diffusion/diffusion.hpp"
using namespace std;
@@ -33,7 +33,16 @@ void DiffusionIntegrator::AssembleMF(const FiniteElementSpace &fes)
MFEM_VERIFY(!VQ && !MQ,
"Only scalar coefficient supported for DiffusionIntegrator"
" with libCEED");
ceedOp = new ceed::MFDiffusionIntegrator(fes, *ir, Q);
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedMFDiffusionIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::MFDiffusionIntegrator(fes, *ir, Q);
}
return;
}
MFEM_ABORT("Error: DiffusionIntegrator::AssembleMF only implemented with"
+17 -5
View File
@@ -12,7 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/diffusion.hpp"
#include "ceed/integrators/diffusion/diffusion.hpp"
using namespace std;
@@ -271,18 +271,21 @@ void PADiffusionSetup3D(const int Q1D,
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)
if (symmetric)
{
D(qx,qy,qz,3,e) = D22; // 2,2
}
else
{
D(qx,qy,qz,3,e) = w_detJ * (A21*R11 + A22*R21 + A23*R31); // 2,1
D(qx,qy,qz,6,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
D(qx,qy,qz,7,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
D(qx,qy,qz,8,e) = D33; // 3,3
@@ -365,7 +368,16 @@ void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
MFEM_VERIFY(!VQ && !MQ,
"Only scalar coefficient supported for DiffusionIntegrator"
" with libCEED");
ceedOp = new ceed::PADiffusionIntegrator(fes, *ir, Q);
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedPADiffusionIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::PADiffusionIntegrator(fes, *ir, Q);
}
return;
}
const int dims = el.GetDim();
+626 -31
View File
@@ -24,18 +24,20 @@ namespace mfem
// PA H(div) Mass Assemble 2D kernel
void PAHdivSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff_,
Vector &op)
{
const bool symmetric = (coeffDim != 4);
const int NQ = Q1D*Q1D;
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
auto coeff = Reshape(coeff_.Read(), NQ, NE);
auto y = Reshape(op.Write(), NQ, 3, NE);
auto C = Reshape(coeff_.Read(), coeffDim, NQ, NE);
auto y = Reshape(op.Write(), NQ, symmetric ? 3 : 4, NE);
MFEM_FORALL(e, NE,
{
@@ -45,28 +47,60 @@ void PAHdivSetup2D(const int Q1D,
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 c_detJ = W[q] * coeff(q, e) / ((J11*J22)-(J21*J12));
// (c/detJ) J^T J
y(q,0,e) = c_detJ * (J11*J11 + J21*J21); // 1,1
y(q,1,e) = c_detJ * (J11*J12 + J21*J22); // 1,2
y(q,2,e) = c_detJ * (J12*J12 + J22*J22); // 2,2
const double c_detJ = W[q] / ((J11*J22)-(J21*J12));
// (1/detJ) J^T C J
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient
{
const double C11 = C(0,q,e);
const double C12 = C(1,q,e);
const double C21 = symmetric ? C12 : C(2,q,e);
const double C22 = symmetric ? C(2,q,e) : C(3,q,e);
const double R11 = C11*J11 + C12*J21;
const double R21 = C21*J11 + C22*J21;
const double R12 = C11*J12 + C12*J22;
const double R22 = C21*J12 + C22*J22;
y(q,0,e) = c_detJ * (J11*R11 + J21*R21); // 1,1
y(q,1,e) = c_detJ * (J11*R12 + J21*R22); // 1,2
if (symmetric)
{
y(q,2,e) = c_detJ * (J12*R12 + J22*R22); // 2,2
}
else
{
y(q,2,e) = c_detJ * (J12*R11 + J22*R21); // 2,1
y(q,3,e) = c_detJ * (J12*R12 + J22*R22); // 2,2
}
}
else // Vector or scalar coefficient
{
const double C1 = C(0,q,e);
const double C2 = (coeffDim == 2 ? C(1,q,e) : C1);
y(q,0,e) = c_detJ * (J11*C1*J11 + J21*C2*J21); // 1,1
y(q,1,e) = c_detJ * (J11*C1*J12 + J21*C2*J22); // 1,2
y(q,2,e) = c_detJ * (J12*C1*J12 + J22*C2*J22); // 2,2
}
}
});
}
// PA H(div) Mass Assemble 3D kernel
void PAHdivSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &coeff_,
Vector &op)
{
const bool symmetric = (coeffDim != 9);
const int NQ = Q1D*Q1D*Q1D;
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
auto coeff = Reshape(coeff_.Read(), NQ, NE);
auto y = Reshape(op.Write(), NQ, 6, NE);
auto C = Reshape(coeff_.Read(), coeffDim, NQ, NE);
auto y = Reshape(op.Write(), NQ, symmetric ? 6 : 9, NE);
MFEM_FORALL(e, NE,
{
@@ -84,14 +118,58 @@ void PAHdivSetup3D(const int Q1D,
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double c_detJ = W[q] * coeff(q, e) / detJ;
// (c/detJ) J^T J
y(q,0,e) = c_detJ * (J11*J11 + J21*J21 + J31*J31); // 1,1
y(q,1,e) = c_detJ * (J12*J11 + J22*J21 + J32*J31); // 2,1
y(q,2,e) = c_detJ * (J13*J11 + J23*J21 + J33*J31); // 3,1
y(q,3,e) = c_detJ * (J12*J12 + J22*J22 + J32*J32); // 2,2
y(q,4,e) = c_detJ * (J13*J12 + J23*J22 + J33*J32); // 3,2
y(q,5,e) = c_detJ * (J13*J13 + J23*J23 + J33*J33); // 3,3
const double c_detJ = W[q] / detJ;
// (1/detJ) J^T C J
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
{
double M[3][3];
M[0][0] = C(0, q, e);
M[0][1] = C(1, q, e);
M[0][2] = C(2, q, e);
M[1][0] = (!symmetric) ? C(3, q, e) : M[0][1];
M[1][1] = (!symmetric) ? C(4, q, e) : C(3, q, e);
M[1][2] = (!symmetric) ? C(5, q, e) : C(4, q, e);
M[2][0] = (!symmetric) ? C(6, q, e) : M[0][2];
M[2][1] = (!symmetric) ? C(7, q, e) : M[1][2];
M[2][2] = (!symmetric) ? C(8, q, e) : C(5, q, e);
int idx = 0;
for (int i=0; i<3; ++i)
for (int j = (symmetric ? i : 0); j<3; ++j)
{
y(q,idx,e) = 0.0;
for (int k=0; k<3; ++k)
{
double MJ_kj = 0.0;
for (int l=0; l<3; ++l)
{
MJ_kj += M[k][l] * J(q,l,j,e);
}
y(q,idx,e) += J(q,k,i,e) * MJ_kj;
}
y(q,idx,e) *= c_detJ;
idx++;
}
}
else // Vector or scalar coefficient version
{
int idx = 0;
for (int i=0; i<3; ++i)
for (int j=i; j<3; ++j)
{
y(q,idx,e) = 0.0;
for (int k=0; k<3; ++k)
{
y(q,idx,e) += J(q,k,i,e) * C(coeffDim == 3 ? k : 0, q, e) * J(q,k,j,e);
}
y(q,idx,e) *= c_detJ;
idx++;
}
}
}
});
}
@@ -99,6 +177,7 @@ void PAHdivSetup3D(const int Q1D,
void PAHdivMassApply2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
@@ -115,7 +194,7 @@ void PAHdivMassApply2D(const int D1D,
auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
auto Bct = Reshape(Bct_.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, 3, NE);
auto op = Reshape(op_.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
auto x = Reshape(x_.Read(), 2*(D1D-1)*D1D, NE);
auto y = Reshape(y_.ReadWrite(), 2*(D1D-1)*D1D, NE);
@@ -178,11 +257,12 @@ void PAHdivMassApply2D(const int D1D,
{
const double O11 = op(qx,qy,0,e);
const double O12 = op(qx,qy,1,e);
const double O22 = op(qx,qy,2,e);
const double O21 = symmetric ? O12 : op(qx,qy,2,e);
const double O22 = symmetric ? op(qx,qy,2,e) : op(qx,qy,3,e);
const double massX = mass[qy][qx][0];
const double massY = mass[qy][qx][1];
mass[qy][qx][0] = (O11*massX)+(O12*massY);
mass[qy][qx][1] = (O12*massX)+(O22*massY);
mass[qy][qx][1] = (O21*massX)+(O22*massY);
}
}
@@ -225,9 +305,179 @@ void PAHdivMassApply2D(const int D1D,
}); // end of element loop
}
template<int T_D1D = 0, int T_Q1D = 0>
void SmemPAHdivMassApply2D(const int NE,
const bool symmetric,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_CONTRACT_VAR(Bot_);
MFEM_CONTRACT_VAR(Bct_);
static constexpr int VDIM = 2;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const auto bo = Reshape(Bo_.Read(), Q1D, D1D-1);
const auto bc = Reshape(Bc_.Read(), Q1D, D1D);
const auto D = Reshape(op_.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
const auto x = Reshape(x_.Read(), D1D*(D1D-1), VDIM, NE);
auto y = y_.ReadWrite();
MFEM_FORALL_3D(e, NE, Q1D, Q1D, VDIM,
{
const int tidz = MFEM_THREAD_ID(z);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : HDIV_MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : HDIV_MAX_D1D;
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
MFEM_SHARED double smo[MQ1*(MD1-1)];
DeviceMatrix Bo(smo, D1D-1, Q1D);
MFEM_SHARED double smc[MQ1*MD1];
DeviceMatrix Bc(smc, D1D, Q1D);
MFEM_SHARED double sm0[VDIM*MDQ*MDQ];
MFEM_SHARED double sm1[VDIM*MDQ*MDQ];
DeviceMatrix X(sm0, D1D*(D1D-1), VDIM);
DeviceCube QD(sm1, Q1D, D1D, VDIM);
DeviceCube QQ(sm0, Q1D, Q1D, VDIM);
// Load X, Bo and Bc into shared memory
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
if (qx < D1D && dy < (D1D-1)) { X(qx + dy*D1D,vd) = x(qx+dy*D1D,vd,e); }
if (tidz == 0)
{
if (dy < (D1D-1)) { Bo(dy,qx) = bo(qx,dy); }
Bc(dy,qx) = bc(qx,dy);
}
}
}
}
MFEM_SYNC_THREAD;
// Apply B operator
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
const int ny = (vd == 1) ? D1D : D1D-1;
DeviceCube Xxy(X, nx, ny, VDIM);
DeviceMatrix Bx = (vd == 0) ? Bc : Bo;
MFEM_FOREACH_THREAD(dy,y,ny)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double dq = 0.0;
for (int dx = 0; dx < nx; ++dx)
{
dq += Xxy(dx,dy,vd) * Bx(dx,qx);
}
QD(qx,dy,vd) = dq;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int ny = (vd == 1) ? D1D : D1D-1;
DeviceMatrix By = (vd == 1) ? Bc : Bo;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double qq = 0.0;
for (int dy = 0; dy < ny; ++dy)
{
qq += QD(qx,dy,vd) * By(dy,qy);
}
QQ(qx,qy,vd) = qq;
}
}
}
MFEM_SYNC_THREAD;
// Apply D operator
if (tidz == 0)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const double Qx = QQ(qx,qy,0);
const double Qy = QQ(qx,qy,1);
const double D11 = D(qx,qy,0,e);
const double D12 = D(qx,qy,1,e);
const double D21 = symmetric ? D12 : D(qx,qy,2,e);
const double D22 = symmetric ? D(qx,qy,2,e) : D(qx,qy,3,e);
QQ(qx,qy,0) = D11*Qx + D12*Qy;
QQ(qx,qy,1) = D21*Qx + D22*Qy;
}
}
}
MFEM_SYNC_THREAD;
// Apply Bt operator
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
DeviceMatrix Btx = (vd == 0) ? Bc : Bo;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,nx)
{
double qd = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
qd += QQ(qx,qy,vd) * Btx(dx,qx);
}
QD(dx,qy,vd) = qd;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
const int ny = (vd == 1) ? D1D : D1D-1;
DeviceMatrix Bty = (vd == 1) ? Bc : Bo;
DeviceTensor<4> Yxy(y, nx, ny, VDIM, NE);
MFEM_FOREACH_THREAD(dy,y,ny)
{
MFEM_FOREACH_THREAD(dx,x,nx)
{
double dd = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
dd += QD(dx,qy,vd) * Bty(dy,qy);
}
Yxy(dx,dy,vd,e) += dd;
}
}
}
MFEM_SYNC_THREAD;
});
}
void PAHdivMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Vector &op_,
@@ -238,7 +488,7 @@ void PAHdivMassAssembleDiagonal2D(const int D1D,
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, 3, NE);
auto op = Reshape(op_.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
auto diag = Reshape(diag_.ReadWrite(), 2*(D1D-1)*D1D, NE);
MFEM_FORALL(e, NE,
@@ -259,7 +509,7 @@ void PAHdivMassAssembleDiagonal2D(const int D1D,
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = (c == 1) ? Bc(qy,dy) : Bo(qy,dy);
mass[qx] += wy*wy*((c == 0) ? op(qx,qy,0,e) : op(qx,qy,2,e));
mass[qx] += wy*wy*((c == 0) ? op(qx,qy,0,e) : op(qx,qy,symmetric ? 2 : 3,e));
}
}
@@ -283,6 +533,7 @@ void PAHdivMassAssembleDiagonal2D(const int D1D,
void PAHdivMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Vector &op_,
@@ -294,7 +545,7 @@ void PAHdivMassAssembleDiagonal3D(const int D1D,
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, 6, NE);
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
auto diag = Reshape(diag_.ReadWrite(), 3*(D1D-1)*(D1D-1)*D1D, NE);
MFEM_FORALL(e, NE,
@@ -307,7 +558,8 @@ void PAHdivMassAssembleDiagonal3D(const int D1D,
const int D1Dy = (c == 1) ? D1D : D1D - 1;
const int D1Dx = (c == 0) ? D1D : D1D - 1;
const int opc = (c == 0) ? 0 : ((c == 1) ? 3 : 5);
const int opc = (c == 0) ? 0 : ((c == 1) ? (symmetric ? 3 : 4) :
(symmetric ? 5 : 8));
double mass[HDIV_MAX_Q1D];
@@ -350,6 +602,7 @@ void PAHdivMassAssembleDiagonal3D(const int D1D,
void PAHdivMassApply3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
@@ -366,7 +619,7 @@ void PAHdivMassApply3D(const int D1D,
auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
auto Bct = Reshape(Bct_.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, 6, NE);
auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
auto x = Reshape(x_.Read(), 3*(D1D-1)*(D1D-1)*D1D, NE);
auto y = Reshape(y_.ReadWrite(), 3*(D1D-1)*(D1D-1)*D1D, NE);
@@ -461,15 +714,19 @@ void PAHdivMassApply3D(const int D1D,
const double O11 = op(qx,qy,qz,0,e);
const double O12 = op(qx,qy,qz,1,e);
const double O13 = op(qx,qy,qz,2,e);
const double O22 = op(qx,qy,qz,3,e);
const double O23 = op(qx,qy,qz,4,e);
const double O33 = op(qx,qy,qz,5,e);
const double O21 = symmetric ? O12 : op(qx,qy,qz,3,e);
const double O22 = symmetric ? op(qx,qy,qz,3,e) : op(qx,qy,qz,4,e);
const double O23 = symmetric ? op(qx,qy,qz,4,e) : op(qx,qy,qz,5,e);
const double O31 = symmetric ? O13 : op(qx,qy,qz,6,e);
const double O32 = symmetric ? O23 : op(qx,qy,qz,7,e);
const double O33 = symmetric ? op(qx,qy,qz,5,e) : op(qx,qy,qz,8,e);
const double massX = mass[qz][qy][qx][0];
const double massY = mass[qz][qy][qx][1];
const double massZ = mass[qz][qy][qx][2];
mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
mass[qz][qy][qx][1] = (O12*massX)+(O22*massY)+(O23*massZ);
mass[qz][qy][qx][2] = (O13*massX)+(O23*massY)+(O33*massZ);
mass[qz][qy][qx][1] = (O21*massX)+(O22*massY)+(O23*massZ);
mass[qz][qy][qx][2] = (O31*massX)+(O32*massY)+(O33*massZ);
}
}
}
@@ -537,6 +794,337 @@ void PAHdivMassApply3D(const int D1D,
}); // end of element loop
}
template<int T_D1D = 0, int T_Q1D = 0>
void SmemPAHdivMassApply3D(const int NE,
const bool symmetric,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
MFEM_CONTRACT_VAR(Bot_);
MFEM_CONTRACT_VAR(Bct_);
static constexpr int VDIM = 3;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const auto bo = Reshape(Bo_.Read(), Q1D, D1D-1);
const auto bc = Reshape(Bc_.Read(), Q1D, D1D);
const auto D = Reshape(op_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
const auto x = Reshape(x_.Read(), D1D*(D1D-1)*(D1D-1), VDIM, NE);
auto y = y_.ReadWrite();
MFEM_FORALL_3D(e, NE, Q1D, Q1D, VDIM,
{
const int tidz = MFEM_THREAD_ID(z);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : HDIV_MAX_Q1D;
constexpr int MD1 = T_D1D ? T_D1D : HDIV_MAX_D1D;
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
MFEM_SHARED double smo[MQ1*(MD1-1)];
DeviceMatrix Bo(smo, D1D-1, Q1D);
MFEM_SHARED double smc[MQ1*MD1];
DeviceMatrix Bc(smc, D1D, Q1D);
MFEM_SHARED double sm0[VDIM*MDQ*MDQ*MDQ];
MFEM_SHARED double sm1[VDIM*MDQ*MDQ*MDQ];
DeviceMatrix X(sm0, D1D*(D1D-1)*(D1D-1), VDIM);
DeviceTensor<4> QDD(sm1, Q1D, D1D, D1D, VDIM);
DeviceTensor<4> QQD(sm0, Q1D, Q1D, D1D, VDIM);
DeviceTensor<4> QQQ(sm1, Q1D, Q1D, Q1D, VDIM);
DeviceTensor<4> DQQ(sm0, D1D, Q1D, Q1D, VDIM);
DeviceTensor<4> DDQ(sm1, D1D, D1D, Q1D, VDIM);
// Load X into shared memory
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
MFEM_FOREACH_THREAD(dz,y,D1D-1)
{
MFEM_FOREACH_THREAD(dy,x,D1D-1)
{
MFEM_UNROLL(MD1)
for (int dx = 0; dx < D1D; ++dx)
{
X(dx+(dy+dz*(D1D-1))*D1D,vd) = x(dx+(dy+dz*(D1D-1))*D1D,vd,e);
}
}
}
}
// Load Bo and Bc into shared memory
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D-1)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
Bo(d,q) = bo(q,d);
}
}
MFEM_FOREACH_THREAD(d,y,D1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
{
Bc(d,q) = bc(q,d);
}
}
}
MFEM_SYNC_THREAD;
// Apply B operator
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
const int ny = (vd == 1) ? D1D : D1D-1;
const int nz = (vd == 2) ? D1D : D1D-1;
DeviceTensor<4> Xxyz(X, nx, ny, nz, VDIM);
DeviceMatrix Bx = (vd == 0) ? Bc : Bo;
MFEM_FOREACH_THREAD(dy,y,ny)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { u[dz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dx = 0; dx < nx; ++dx)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz)
{
u[dz] += Xxyz(dx,dy,dz,vd) * Bx(dx,qx);
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { QDD(qx,dy,dz,vd) = u[dz]; }
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int ny = (vd == 1) ? D1D : D1D-1;
const int nz = (vd == 2) ? D1D : D1D-1;
DeviceMatrix By = (vd == 1) ? Bc : Bo;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { u[dz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dy = 0; dy < ny; ++dy)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz)
{
u[dz] += QDD(qx,dy,dz,vd) * By(dy,qy);
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { QQD(qx,qy,dz,vd) = u[dz]; }
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nz = (vd == 2) ? D1D : D1D-1;
DeviceMatrix Bz = (vd == 2) ? Bc : Bo;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += QQD(qx,qy,dz,vd) * Bz(dz,qz);
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { QQQ(qx,qy,qz,vd) = u[qz]; }
}
}
}
MFEM_SYNC_THREAD;
// Apply D operator
if (tidz == 0)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
const double Qx = QQQ(qx,qy,qz,0);
const double Qy = QQQ(qx,qy,qz,1);
const double Qz = QQQ(qx,qy,qz,2);
const double D11 = D(qx,qy,qz,0,e);
const double D12 = D(qx,qy,qz,1,e);
const double D13 = D(qx,qy,qz,2,e);
const double D21 = symmetric ? D12 : D(qx,qy,qz,3,e);
const double D22 = symmetric ? D(qx,qy,qz,3,e) : D(qx,qy,qz,4,e);
const double D23 = symmetric ? D(qx,qy,qz,4,e) : D(qx,qy,qz,5,e);
const double D31 = symmetric ? D13 : D(qx,qy,qz,6,e);
const double D32 = symmetric ? D23 : D(qx,qy,qz,7,e);
const double D33 = symmetric ? D(qx,qy,qz,5,e) : D(qx,qy,qz,8,e);
QQQ(qx,qy,qz,0) = D11*Qx + D12*Qy + D13*Qz;
QQQ(qx,qy,qz,1) = D21*Qx + D22*Qy + D23*Qz;
QQQ(qx,qy,qz,2) = D31*Qx + D32*Qy + D33*Qz;
}
}
}
}
MFEM_SYNC_THREAD;
// Apply Bt operator
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
DeviceMatrix Btx = (vd == 0) ? Bc : Bo;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,nx)
{
double u[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qx = 0; qx < Q1D; ++qx)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += QQQ(qx,qy,qz,vd) * Btx(dx,qx);
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { DQQ(dx,qy,qz,vd) = u[qz]; }
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
const int ny = (vd == 1) ? D1D : D1D-1;
DeviceMatrix Bty = (vd == 1) ? Bc : Bo;
MFEM_FOREACH_THREAD(dy,y,ny)
{
MFEM_FOREACH_THREAD(dx,x,nx)
{
double u[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qy = 0; qy < Q1D; ++qy)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += DQQ(dx,qy,qz,vd) * Bty(dy,qy);
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { DDQ(dx,dy,qz,vd) = u[qz]; }
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(vd,z,VDIM)
{
const int nx = (vd == 0) ? D1D : D1D-1;
const int ny = (vd == 1) ? D1D : D1D-1;
const int nz = (vd == 2) ? D1D : D1D-1;
DeviceTensor<5> Yxyz(y, nx, ny, nz, VDIM, NE);
DeviceMatrix Btz = (vd == 2) ? Bc : Bo;
MFEM_FOREACH_THREAD(dy,y,ny)
{
MFEM_FOREACH_THREAD(dx,x,nx)
{
double u[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { u[dz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz)
{
u[dz] += DDQ(dx,dy,qz,vd) * Btz(dz,qz);
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < nz; ++dz) { Yxyz(dx,dy,dz,vd,e) += u[dz]; }
}
}
}
MFEM_SYNC_THREAD;
});
}
void PAHdivMassApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo,
const Array<double> &Bc,
const Array<double> &Bot,
const Array<double> &Bct,
const Vector &op,
const Vector &x,
Vector &y)
{
const int id = (D1D << 4) | Q1D;
if (dim == 2)
{
switch (id)
{
case 0x22: return SmemPAHdivMassApply2D<2,2>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x33: return SmemPAHdivMassApply2D<3,3>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x44: return SmemPAHdivMassApply2D<4,4>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x55: return SmemPAHdivMassApply2D<5,5>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
default: // fallback
return PAHdivMassApply2D(D1D,Q1D,NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
}
}
else if (dim == 3)
{
switch (id)
{
case 0x23: return SmemPAHdivMassApply3D<2,3>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x34: return SmemPAHdivMassApply3D<3,4>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x45: return SmemPAHdivMassApply3D<4,5>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x56: return SmemPAHdivMassApply3D<5,6>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x67: return SmemPAHdivMassApply3D<6,7>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x78: return SmemPAHdivMassApply3D<7,8>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
default: // fallback
return PAHdivMassApply3D(D1D,Q1D,NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
}
}
}
// PA H(div) div-div assemble 2D kernel
// NOTE: this is identical to PACurlCurlSetup3D
static void PADivDivSetup2D(const int Q1D,
@@ -626,7 +1214,7 @@ static void PADivDivApply2D(const int D1D,
{
double div[MAX_Q1D][MAX_Q1D];
// div[qy][qx] will be computed as du_x/dx + duy_/dy
// div[qy][qx] will be computed as du_x/dx + du_y/dy
for (int qy = 0; qy < Q1D; ++qy)
{
@@ -1209,6 +1797,13 @@ VectorFEDivergenceIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
}
}
if (test_el->GetMapType() == FiniteElement::INTEGRAL)
{
const GeometricFactors *geom =
mesh->GetGeometricFactors(*ir, GeometricFactors::DETERMINANTS);
coeff /= geom->detJ;
}
if (trial_el->GetDerivType() == mfem::FiniteElement::DIV && dim == 3)
{
PADivL2Setup3D(quad1D, ne, ir->GetWeights(), coeff, pa_data);
+11 -2
View File
@@ -12,7 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/mass.hpp"
#include "ceed/integrators/mass/mass.hpp"
using namespace std;
@@ -31,7 +31,16 @@ void MassIntegrator::AssembleMF(const FiniteElementSpace &fes)
if (DeviceCanUseCeed())
{
delete ceedOp;
ceedOp = new ceed::MFMassIntegrator(fes, *ir, Q);
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedMFMassIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::MFMassIntegrator(fes, *ir, Q);
}
return;
}
MFEM_ABORT("Error: MassIntegrator::AssembleMF only implemented with"
+11 -2
View File
@@ -12,7 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/mass.hpp"
#include "ceed/integrators/mass/mass.hpp"
using namespace std;
@@ -38,7 +38,16 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
if (DeviceCanUseCeed())
{
delete ceedOp;
ceedOp = new ceed::PAMassIntegrator(fes, *ir, Q);
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedPAMassIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::PAMassIntegrator(fes, *ir, Q);
}
return;
}
int map_type = el.GetMapType();
+11 -2
View File
@@ -12,7 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/diffusion.hpp"
#include "ceed/integrators/diffusion/diffusion.hpp"
using namespace std;
@@ -149,7 +149,16 @@ void VectorDiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
if (DeviceCanUseCeed())
{
delete ceedOp;
ceedOp = new ceed::PADiffusionIntegrator(fes, *ir, Q);
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedPADiffusionIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::PADiffusionIntegrator(fes, *ir, Q);
}
return;
}
const int dims = el.GetDim();
+14 -2
View File
@@ -12,7 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/diffusion.hpp"
#include "ceed/integrators/diffusion/diffusion.hpp"
using namespace std;
@@ -30,7 +30,19 @@ void VectorDiffusionIntegrator::AssembleMF(const FiniteElementSpace &fes)
if (DeviceCanUseCeed())
{
delete ceedOp;
ceedOp = new ceed::MFDiffusionIntegrator(fes, *ir, Q);
MFEM_VERIFY(!VQ && !MQ,
"Only scalar coefficient supported for DiffusionIntegrator"
" with libCEED");
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedMFDiffusionIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::MFDiffusionIntegrator(fes, *ir, Q);
}
return;
}
MFEM_ABORT("Error: VectorDiffusionIntegrator::AssembleMF only implemented"
+11 -2
View File
@@ -12,7 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/mass.hpp"
#include "ceed/integrators/mass/mass.hpp"
using namespace std;
@@ -34,7 +34,16 @@ void VectorMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
if (DeviceCanUseCeed())
{
delete ceedOp;
ceedOp = new ceed::PAMassIntegrator(fes, *ir, Q);
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedPAMassIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::PAMassIntegrator(fes, *ir, Q);
}
return;
}
dim = mesh->Dimension();
+11 -2
View File
@@ -12,7 +12,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
#include "ceed/mass.hpp"
#include "ceed/integrators/mass/mass.hpp"
using namespace std;
@@ -34,7 +34,16 @@ void VectorMassIntegrator::AssembleMF(const FiniteElementSpace &fes)
if (DeviceCanUseCeed())
{
delete ceedOp;
ceedOp = new ceed::MFMassIntegrator(fes, *ir, Q);
const bool mixed = mesh->GetNumGeometries(mesh->Dimension()) > 1 ||
fes.IsVariableOrder();
if (mixed)
{
ceedOp = new ceed::MixedMFMassIntegrator(*this, fes, Q);
}
else
{
ceedOp = new ceed::MFMassIntegrator(fes, *ir, Q);
}
return;
}
MFEM_ABORT("Error: VectorMassIntegrator::AssembleMF only implemented with"
+98 -86
View File
@@ -11,6 +11,7 @@
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
@@ -89,6 +90,7 @@ void SmemPAHcurlMassApply3D(const int D1D,
Vector &y);
void PAHdivSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
@@ -96,6 +98,7 @@ void PAHdivSetup2D(const int Q1D,
Vector &op);
void PAHdivSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
const Vector &j,
@@ -149,6 +152,7 @@ void PAHcurlH1ApplyTranspose3D(const int D1D,
void PAHdivMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Vector &op_,
@@ -157,32 +161,24 @@ void PAHdivMassAssembleDiagonal2D(const int D1D,
void PAHdivMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Vector &op_,
Vector &diag_);
void PAHdivMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_);
void PAHdivMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &Bo_,
const Array<double> &Bc_,
const Array<double> &Bot_,
const Array<double> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_);
void PAHdivMassApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &Bo,
const Array<double> &Bc,
const Array<double> &Bot,
const Array<double> &Bct,
const Vector &op,
const Vector &x,
Vector &y);
void PAHcurlL2Setup(const int NQ,
const int coeffDim,
@@ -818,68 +814,79 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
pa_data.SetSize((symmetric ? symmDims : MQfullDim) * nq * ne,
Device::GetMemoryType());
Vector coeff(coeffDim * ne * nq);
coeff = 1.0;
auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
if (Q || DQ || MQ)
Vector coeff;
auto *qf_c = dynamic_cast<QuadratureFunctionCoefficient*>(Q);
if (qf_c)
{
Vector DM(DQ ? coeffDim : 0);
DenseMatrix M;
DenseSymmetricMatrix SM;
const QuadratureFunction &qf = qf_c->GetQuadFunction();
qf.Read();
coeff.MakeRef(const_cast<QuadratureFunction&>(qf), 0);
}
else
{
coeff.SetSize(coeffDim * ne * nq);
coeff = 1.0;
auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
if (Q || DQ || MQ)
{
Vector DM(DQ ? coeffDim : 0);
DenseMatrix M;
DenseSymmetricMatrix SM;
if (DQ)
{
MFEM_VERIFY(coeffDim == dim, "");
}
if (SMQ)
{
MFEM_VERIFY(SMQ->GetSize() == dim, "");
SM.SetSize(dim);
}
else if (MQ)
{
MFEM_VERIFY(coeffDim == MQdim, "");
MFEM_VERIFY(MQ->GetHeight() == dim && MQ->GetWidth() == dim, "");
M.SetSize(dim);
}
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
if (DQ)
{
if (SMQ)
{
SMQ->Eval(SM, *tr, ir->IntPoint(p));
int cnt = 0;
for (int i=0; i<dim; ++i)
for (int j=i; j<dim; ++j, ++cnt)
{
coeffh(cnt, p, e) = SM(i,j);
}
}
else if (MQ)
{
MQ->Eval(M, *tr, ir->IntPoint(p));
MFEM_VERIFY(coeffDim == dim, "");
}
if (SMQ)
{
MFEM_VERIFY(SMQ->GetSize() == dim, "");
SM.SetSize(dim);
}
else if (MQ)
{
MFEM_VERIFY(coeffDim == MQdim, "");
MFEM_VERIFY(MQ->GetHeight() == dim && MQ->GetWidth() == dim, "");
M.SetSize(dim);
}
for (int i=0; i<dim; ++i)
for (int j=0; j<dim; ++j)
{
coeffh(j+(i*dim), p, e) = M(i,j);
}
}
else if (DQ)
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
DQ->Eval(DM, *tr, ir->IntPoint(p));
for (int i=0; i<coeffDim; ++i)
if (SMQ)
{
coeffh(i, p, e) = DM[i];
SMQ->Eval(SM, *tr, ir->IntPoint(p));
int cnt = 0;
for (int i=0; i<dim; ++i)
for (int j=i; j<dim; ++j, ++cnt)
{
coeffh(cnt, p, e) = SM(i,j);
}
}
else if (MQ)
{
MQ->Eval(M, *tr, ir->IntPoint(p));
for (int i=0; i<dim; ++i)
for (int j=0; j<dim; ++j)
{
coeffh(j+(i*dim), p, e) = M(i,j);
}
}
else if (DQ)
{
DQ->Eval(DM, *tr, ir->IntPoint(p));
for (int i=0; i<coeffDim; ++i)
{
coeffh(i, p, e) = DM[i];
}
}
else
{
coeffh(0, p, e) = Q->Eval(*tr, ir->IntPoint(p));
}
}
else
{
coeffh(0, p, e) = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
@@ -897,12 +904,12 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
}
else if (trial_div && test_div && dim == 3)
{
PAHdivSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
PAHdivSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (trial_div && test_div && dim == 2)
{
PAHdivSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
PAHdivSetup2D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (((trial_curl && test_div) || (trial_div && test_curl)) &&
@@ -963,7 +970,7 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
else if (trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == trial_fetype)
{
PAHdivMassAssembleDiagonal3D(dofs1D, quad1D, ne,
PAHdivMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, pa_data, diag);
}
else
@@ -971,7 +978,7 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
MFEM_ABORT("Unknown kernel.");
}
}
else
else // 2D
{
if (trial_fetype == mfem::FiniteElement::CURL && test_fetype == trial_fetype)
{
@@ -981,7 +988,7 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
else if (trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == trial_fetype)
{
PAHdivMassAssembleDiagonal2D(dofs1D, quad1D, ne,
PAHdivMassAssembleDiagonal2D(dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, pa_data, diag);
}
else
@@ -1034,8 +1041,8 @@ void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
}
else if (trial_div && test_div)
{
PAHdivMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
PAHdivMassApply(3, dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if (trial_curl && test_div)
{
@@ -1056,7 +1063,7 @@ void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
MFEM_ABORT("Unknown kernel.");
}
}
else
else // 2D
{
if (trial_curl && test_curl)
{
@@ -1065,8 +1072,8 @@ void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
}
else if (trial_div && test_div)
{
PAHdivMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
PAHdivMassApply(2, dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if ((trial_curl && test_div) || (trial_div && test_curl))
{
@@ -1111,6 +1118,11 @@ void VectorFEMassIntegrator::AddMultTransposePA(const Vector &x,
if (symmetricSpaces)
{
if (MQ && dynamic_cast<SymmetricMatrixCoefficient*>(MQ) == NULL)
{
MFEM_ABORT("VectorFEMassIntegrator transpose not implemented for asymmetric MatrixCoefficient");
}
this->AddMultPA(x, y);
}
}
-222
View File
@@ -1,222 +0,0 @@
// Copyright (c) 2010-2022, 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_LIBCEED_COEFF
#define MFEM_LIBCEED_COEFF
#include "../../config/config.hpp"
#ifdef MFEM_USE_CEED
#include "util.hpp"
#include "../../linalg/vector.hpp"
#include "../../linalg/dtensor.hpp"
#include "../../mesh/mesh.hpp"
#include "../gridfunc.hpp"
#include "../../linalg/dtensor.hpp"
namespace mfem
{
class Mesh;
class IntegrationRule;
class Coefficient;
class VectorCoefficient;
class GridFunction;
namespace ceed
{
struct Coefficient
{
const int ncomp;
Coefficient(int ncomp_) : ncomp(ncomp_) { }
virtual bool IsConstant() const { return true; }
virtual ~Coefficient() { }
};
struct VariableCoefficient : Coefficient
{
CeedVector coeffVector = nullptr;
const CeedEvalMode emode;
VariableCoefficient(int ncomp_, CeedEvalMode emode_)
: Coefficient(ncomp_), emode(emode_) { }
virtual bool IsConstant() const override { return false; }
~VariableCoefficient()
{
CeedVectorDestroy(&coeffVector);
}
};
struct GridCoefficient : VariableCoefficient
{
const mfem::GridFunction &gf;
CeedBasis basis;
CeedElemRestriction restr;
GridCoefficient(const mfem::GridFunction &gf_)
: VariableCoefficient(gf_.VectorDim(), CEED_EVAL_INTERP),
gf(gf_)
{
InitVector(gf, coeffVector);
}
};
struct QuadCoefficient : VariableCoefficient
{
mfem::Vector coeff;
CeedElemRestriction restr;
QuadCoefficient(int ncomp_) : VariableCoefficient(ncomp_, CEED_EVAL_NONE) { }
};
/** @brief Initializes an mfem::ceed::Coefficient @a coeff_ptr from an
mfem::Coefficient @a Q, an mfem::Mesh @a mesh, and an mfem::IntegrationRule
@a ir. */
template <typename Context>
void InitCoefficient(mfem::Coefficient *Q, mfem::Mesh &mesh,
const mfem::IntegrationRule &ir,
Coefficient*& coeff_ptr, Context &ctx)
{
if ( Q == nullptr )
{
Coefficient *ceedCoeff = new Coefficient(1);
ctx.coeff = 1.0;
coeff_ptr = ceedCoeff;
}
else if (ConstantCoefficient *const_coeff =
dynamic_cast<ConstantCoefficient*>(Q))
{
Coefficient *ceedCoeff = new Coefficient(1);
ctx.coeff = const_coeff->constant;
coeff_ptr = ceedCoeff;
}
else if (GridFunctionCoefficient* gf_coeff =
dynamic_cast<GridFunctionCoefficient*>(Q))
{
GridCoefficient *ceedCoeff =
new GridCoefficient(*gf_coeff->GetGridFunction());
coeff_ptr = ceedCoeff;
}
else if (QuadratureFunctionCoefficient *cQ =
dynamic_cast<QuadratureFunctionCoefficient*>(Q))
{
QuadCoefficient *ceedCoeff = new QuadCoefficient(1);
const int ne = mesh.GetNE();
const int nq = ir.GetNPoints();
const mfem::QuadratureFunction &qFun = cQ->GetQuadFunction();
MFEM_VERIFY(qFun.Size() == nq * ne,
"Incompatible QuadratureFunction dimension \n");
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetElementIntRule(0),
"IntegrationRule used within integrator and in"
" QuadratureFunction appear to be different");
qFun.Read();
ceedCoeff->coeff.MakeRef(const_cast<mfem::QuadratureFunction &>(qFun),0);
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
else
{
QuadCoefficient *ceedCoeff = new QuadCoefficient(1);
const int ne = mesh.GetNE();
const int nq = ir.GetNPoints();
ceedCoeff->coeff.SetSize(nq * ne);
auto C = Reshape(ceedCoeff->coeff.HostWrite(), nq, ne);
for (int e = 0; e < ne; ++e)
{
mfem::ElementTransformation &T = *mesh.GetElementTransformation(e);
for (int q = 0; q < nq; ++q)
{
C(q,e) = Q->Eval(T, ir.IntPoint(q));
}
}
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
}
/** @brief Initializes an mfem::ceed::Coefficient @a coeff_ptr from an
mfem::VectorCoefficient @a Q, an mfem::Mesh @a mesh, and an
mfem::IntegrationRule @a ir. */
template <typename Context>
void InitCoefficient(mfem::VectorCoefficient *VQ, mfem::Mesh &mesh,
const mfem::IntegrationRule &ir,
Coefficient *&coeff_ptr, Context &ctx)
{
if (VectorConstantCoefficient *const_coeff =
dynamic_cast<VectorConstantCoefficient*>(VQ))
{
const int vdim = const_coeff->GetVDim();
const mfem::Vector &val = const_coeff->GetVec();
Coefficient *ceedCoeff = new Coefficient(vdim);
for (int i = 0; i < vdim; i++)
{
ctx.coeff[i] = val[i];
}
coeff_ptr = ceedCoeff;
}
else if (VectorGridFunctionCoefficient* vgf_coeff =
dynamic_cast<VectorGridFunctionCoefficient*>(VQ))
{
GridCoefficient *ceedCoeff =
new GridCoefficient(*vgf_coeff->GetGridFunction());
coeff_ptr = ceedCoeff;
}
else if (VectorQuadratureFunctionCoefficient *cQ =
dynamic_cast<VectorQuadratureFunctionCoefficient*>(VQ))
{
QuadCoefficient *ceedCoeff = new QuadCoefficient(cQ->GetVDim());
const int dim = mesh.Dimension();
const int ne = mesh.GetNE();
const int nq = ir.GetNPoints();
const mfem::QuadratureFunction &qFun = cQ->GetQuadFunction();
MFEM_VERIFY(qFun.Size() == dim * nq * ne,
"Incompatible QuadratureFunction dimension \n");
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetElementIntRule(0),
"IntegrationRule used within integrator and in"
" QuadratureFunction appear to be different");
qFun.Read();
ceedCoeff->coeff.MakeRef(const_cast<mfem::QuadratureFunction &>(qFun),0);
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
else
{
const int dim = mesh.Dimension();
QuadCoefficient *ceedCoeff = new QuadCoefficient(dim);
const int ne = mesh.GetNE();
const int nq = ir.GetNPoints();
ceedCoeff->coeff.SetSize(dim * nq * ne);
auto C = Reshape(ceedCoeff->coeff.HostWrite(), dim, nq, ne);
mfem::DenseMatrix Q_ir;
for (int e = 0; e < ne; ++e)
{
mfem::ElementTransformation &T = *mesh.GetElementTransformation(e);
VQ->Eval(Q_ir, T, ir);
for (int q = 0; q < nq; ++q)
{
for (int i = 0; i < dim; ++i)
{
C(i,q,e) = Q_ir(i,q);
}
}
}
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
}
} // namespace ceed
} // namespace mfem
#endif
#endif // MFEM_LIBCEED_COEFF
@@ -11,7 +11,7 @@
#include "convection.hpp"
#include "../../config/config.hpp"
#include "../../../../config/config.hpp"
#ifdef MFEM_USE_CEED
#include "convection_qf.h"
#endif
@@ -28,7 +28,7 @@ struct ConvectionOperatorInfo : public OperatorInfo
ConvectionContext ctx;
ConvectionOperatorInfo(int dim, double alpha)
{
header = "/convection_qf.h";
header = "/integrators/convection/convection_qf.h";
build_func_const = ":f_build_conv_const";
build_qf_const = &f_build_conv_const;
build_func_quad = ":f_build_conv_quad";
@@ -62,6 +62,20 @@ PAConvectionIntegrator::PAConvectionIntegrator(
#endif
}
MixedPAConvectionIntegrator::MixedPAConvectionIntegrator(
const ConvectionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::VectorCoefficient *Q,
const double alpha)
{
#ifdef MFEM_USE_CEED
ConvectionOperatorInfo info(fes.GetMesh()->Dimension(), alpha);
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
MFConvectionIntegrator::MFConvectionIntegrator(
const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
@@ -77,6 +91,20 @@ MFConvectionIntegrator::MFConvectionIntegrator(
#endif
}
MixedMFConvectionIntegrator::MixedMFConvectionIntegrator(
const ConvectionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::VectorCoefficient *Q,
const double alpha)
{
#ifdef MFEM_USE_CEED
ConvectionOperatorInfo info(fes.GetMesh()->Dimension(), alpha);
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
} // namespace ceed
} // namespace mfem
@@ -12,8 +12,9 @@
#ifndef MFEM_LIBCEED_CONV_HPP
#define MFEM_LIBCEED_CONV_HPP
#include "integrator.hpp"
#include "../fespace.hpp"
#include "../../interface/integrator.hpp"
#include "../../interface/mixed_integrator.hpp"
#include "../../../fespace.hpp"
namespace mfem
{
@@ -26,21 +27,39 @@ class PAConvectionIntegrator : public PAIntegrator
{
public:
PAConvectionIntegrator(const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
const mfem::IntegrationRule &ir,
mfem::VectorCoefficient *Q,
const double alpha);
};
class MixedPAConvectionIntegrator : public MixedIntegrator<PAIntegrator>
{
public:
MixedPAConvectionIntegrator(const ConvectionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::VectorCoefficient *Q,
const double alpha);
};
/// Represent a ConvectionIntegrator with AssemblyLevel::None using libCEED.
class MFConvectionIntegrator : public MFIntegrator
{
public:
MFConvectionIntegrator(const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
const mfem::IntegrationRule &ir,
mfem::VectorCoefficient *Q,
const double alpha);
};
class MixedMFConvectionIntegrator : public MixedIntegrator<MFIntegrator>
{
public:
MixedMFConvectionIntegrator(const ConvectionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::VectorCoefficient *Q,
const double alpha);
};
}
}
@@ -11,7 +11,7 @@
#include "diffusion.hpp"
#include "../../config/config.hpp"
#include "../../../../config/config.hpp"
#ifdef MFEM_USE_CEED
#include "diffusion_qf.h"
#endif
@@ -28,7 +28,7 @@ struct DiffusionOperatorInfo : public OperatorInfo
DiffusionContext ctx;
DiffusionOperatorInfo(int dim)
{
header = "/diffusion_qf.h";
header = "/integrators/diffusion/diffusion_qf.h";
build_func_const = ":f_build_diff_const";
build_qf_const = &f_build_diff_const;
build_func_quad = ":f_build_diff_quad";
@@ -60,6 +60,32 @@ PADiffusionIntegrator::PADiffusionIntegrator(
#endif
}
MixedPADiffusionIntegrator::MixedPADiffusionIntegrator(
const DiffusionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q)
{
#ifdef MFEM_USE_CEED
DiffusionOperatorInfo info(fes.GetMesh()->Dimension());
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
MixedPADiffusionIntegrator::MixedPADiffusionIntegrator(
const VectorDiffusionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q)
{
#ifdef MFEM_USE_CEED
DiffusionOperatorInfo info(fes.GetMesh()->Dimension());
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
MFDiffusionIntegrator::MFDiffusionIntegrator(
const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
@@ -74,6 +100,32 @@ MFDiffusionIntegrator::MFDiffusionIntegrator(
#endif
}
MixedMFDiffusionIntegrator::MixedMFDiffusionIntegrator(
const DiffusionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q)
{
#ifdef MFEM_USE_CEED
DiffusionOperatorInfo info(fes.GetMesh()->Dimension());
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
MixedMFDiffusionIntegrator::MixedMFDiffusionIntegrator(
const VectorDiffusionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q)
{
#ifdef MFEM_USE_CEED
DiffusionOperatorInfo info(fes.GetMesh()->Dimension());
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
} // namespace ceed
} // namespace mfem
@@ -12,8 +12,9 @@
#ifndef MFEM_LIBCEED_DIFF_HPP
#define MFEM_LIBCEED_DIFF_HPP
#include "integrator.hpp"
#include "../fespace.hpp"
#include "../../interface/integrator.hpp"
#include "../../interface/mixed_integrator.hpp"
#include "../../../fespace.hpp"
namespace mfem
{
@@ -26,19 +27,43 @@ class PADiffusionIntegrator : public PAIntegrator
{
public:
PADiffusionIntegrator(const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
const mfem::IntegrationRule &ir,
mfem::Coefficient *Q);
};
class MixedPADiffusionIntegrator : public MixedIntegrator<PAIntegrator>
{
public:
MixedPADiffusionIntegrator(const DiffusionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q);
MixedPADiffusionIntegrator(const VectorDiffusionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q);
};
/// Represent a DiffusionIntegrator with AssemblyLevel::None using libCEED.
class MFDiffusionIntegrator : public MFIntegrator
{
public:
MFDiffusionIntegrator(const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
const mfem::IntegrationRule &ir,
mfem::Coefficient *Q);
};
class MixedMFDiffusionIntegrator : public MixedIntegrator<MFIntegrator>
{
public:
MixedMFDiffusionIntegrator(const DiffusionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q);
MixedMFDiffusionIntegrator(const VectorDiffusionIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q);
};
}
}
@@ -11,7 +11,7 @@
#include "mass.hpp"
#include "../../config/config.hpp"
#include "../../../../config/config.hpp"
#ifdef MFEM_USE_CEED
#include "mass_qf.h"
#endif
@@ -28,7 +28,7 @@ struct MassOperatorInfo : public OperatorInfo
MassContext ctx;
MassOperatorInfo()
{
header = "/mass_qf.h";
header = "/integrators/mass/mass_qf.h";
build_func_const = ":f_build_mass_const";
build_qf_const = &f_build_mass_const;
build_func_quad = ":f_build_mass_quad";
@@ -59,6 +59,30 @@ PAMassIntegrator::PAMassIntegrator(const mfem::FiniteElementSpace &fes,
#endif
}
MixedPAMassIntegrator::MixedPAMassIntegrator(const MassIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q)
{
#ifdef MFEM_USE_CEED
MassOperatorInfo info;
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
MixedPAMassIntegrator::MixedPAMassIntegrator(const VectorMassIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q)
{
#ifdef MFEM_USE_CEED
MassOperatorInfo info;
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
MFMassIntegrator::MFMassIntegrator(const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
mfem::Coefficient *Q)
@@ -72,6 +96,30 @@ MFMassIntegrator::MFMassIntegrator(const mfem::FiniteElementSpace &fes,
#endif
}
MixedMFMassIntegrator::MixedMFMassIntegrator(const MassIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q)
{
#ifdef MFEM_USE_CEED
MassOperatorInfo info;
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
MixedMFMassIntegrator::MixedMFMassIntegrator(const VectorMassIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q)
{
#ifdef MFEM_USE_CEED
MassOperatorInfo info;
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
} // namespace ceed
} // namespace mfem
@@ -12,8 +12,9 @@
#ifndef MFEM_LIBCEED_MASS_HPP
#define MFEM_LIBCEED_MASS_HPP
#include "integrator.hpp"
#include "../fespace.hpp"
#include "../../interface/integrator.hpp"
#include "../../interface/mixed_integrator.hpp"
#include "../../../fespace.hpp"
namespace mfem
{
@@ -26,19 +27,43 @@ class PAMassIntegrator : public PAIntegrator
{
public:
PAMassIntegrator(const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
const mfem::IntegrationRule &ir,
mfem::Coefficient *Q);
};
class MixedPAMassIntegrator : public MixedIntegrator<PAIntegrator>
{
public:
MixedPAMassIntegrator(const MassIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q);
MixedPAMassIntegrator(const VectorMassIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q);
};
/// Represent a MassIntegrator with AssemblyLevel::None using libCEED.
class MFMassIntegrator : public MFIntegrator
{
public:
MFMassIntegrator(const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
const mfem::IntegrationRule &ir,
mfem::Coefficient *Q);
};
class MixedMFMassIntegrator : public MixedIntegrator<MFIntegrator>
{
public:
MixedMFMassIntegrator(const MassIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q);
MixedMFMassIntegrator(const VectorMassIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q);
};
}
}
@@ -11,7 +11,7 @@
#include "nlconvection.hpp"
#include "../../config/config.hpp"
#include "../../../../config/config.hpp"
#ifdef MFEM_USE_CEED
#include "nlconvection_qf.h"
#endif
@@ -28,7 +28,7 @@ struct NLConvectionOperatorInfo : public OperatorInfo
NLConvectionContext ctx;
NLConvectionOperatorInfo(int dim)
{
header = "/nlconvection_qf.h";
header = "/integrators/nlconvection/nlconvection_qf.h";
build_func_const = ":f_build_conv_const";
build_qf_const = &f_build_conv_const;
build_func_quad = ":f_build_conv_quad";
@@ -60,6 +60,19 @@ PAVectorConvectionNLFIntegrator::PAVectorConvectionNLFIntegrator(
#endif
}
MixedPAVectorConvectionNLIntegrator::MixedPAVectorConvectionNLIntegrator(
const VectorConvectionNLFIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q)
{
#ifdef MFEM_USE_CEED
NLConvectionOperatorInfo info(fes.GetMesh()->Dimension());
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
MFVectorConvectionNLFIntegrator::MFVectorConvectionNLFIntegrator(
const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
@@ -74,6 +87,19 @@ MFVectorConvectionNLFIntegrator::MFVectorConvectionNLFIntegrator(
#endif
}
MixedMFVectorConvectionNLIntegrator::MixedMFVectorConvectionNLIntegrator(
const VectorConvectionNLFIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q)
{
#ifdef MFEM_USE_CEED
NLConvectionOperatorInfo info(fes.GetMesh()->Dimension());
Assemble(integ, info, fes, Q);
#else
MFEM_ABORT("MFEM must be built with MFEM_USE_CEED=YES to use libCEED.");
#endif
}
} // namespace ceed
} // namespace mfem
@@ -12,8 +12,9 @@
#ifndef MFEM_LIBCEED_NLCONV_HPP
#define MFEM_LIBCEED_NLCONV_HPP
#include "integrator.hpp"
#include "../fespace.hpp"
#include "../../interface/integrator.hpp"
#include "../../interface/mixed_integrator.hpp"
#include "../../../fespace.hpp"
namespace mfem
{
@@ -31,6 +32,15 @@ public:
mfem::Coefficient *coeff);
};
class MixedPAVectorConvectionNLIntegrator : public MixedIntegrator<PAIntegrator>
{
public:
MixedPAVectorConvectionNLIntegrator(
const VectorConvectionNLFIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q);
};
/** Represent a VectorConvectionNLFIntegrator with AssemblyLevel::None
using libCEED. */
class MFVectorConvectionNLFIntegrator : public MFIntegrator
@@ -41,6 +51,15 @@ public:
mfem::Coefficient *coeff);
};
class MixedMFVectorConvectionNLIntegrator : public MixedIntegrator<MFIntegrator>
{
public:
MixedMFVectorConvectionNLIntegrator(
const VectorConvectionNLFIntegrator &integ,
const mfem::FiniteElementSpace &fes,
mfem::Coefficient *Q);
};
}
}
@@ -327,13 +327,13 @@ CEED_QFUNCTION(f_apply_conv_mf_const)(void *ctx, CeedInt Q,
const CeedScalar A33 = J11 * J22 - J12 * J21;
const CeedScalar w = qw[i] * coeff;
const CeedScalar qd00 = w * A11;
const CeedScalar qd01 = w * A21;
const CeedScalar qd02 = w * A31;
const CeedScalar qd10 = w * A12;
const CeedScalar qd10 = w * A21;
const CeedScalar qd20 = w * A31;
const CeedScalar qd01 = w * A12;
const CeedScalar qd11 = w * A22;
const CeedScalar qd12 = w * A32;
const CeedScalar qd20 = w * A13;
const CeedScalar qd21 = w * A23;
const CeedScalar qd21 = w * A32;
const CeedScalar qd02 = w * A13;
const CeedScalar qd12 = w * A23;
const CeedScalar qd22 = w * A33;
const CeedScalar u0 = u[i + Q * 0];
const CeedScalar u1 = u[i + Q * 1];
@@ -440,13 +440,13 @@ CEED_QFUNCTION(f_apply_conv_mf_quad)(void *ctx, CeedInt Q,
const CeedScalar A33 = J11 * J22 - J12 * J21;
const CeedScalar w = qw[i] * c[i];
const CeedScalar qd00 = w * A11;
const CeedScalar qd01 = w * A21;
const CeedScalar qd02 = w * A31;
const CeedScalar qd10 = w * A12;
const CeedScalar qd10 = w * A21;
const CeedScalar qd20 = w * A31;
const CeedScalar qd01 = w * A12;
const CeedScalar qd11 = w * A22;
const CeedScalar qd12 = w * A32;
const CeedScalar qd20 = w * A13;
const CeedScalar qd21 = w * A23;
const CeedScalar qd21 = w * A32;
const CeedScalar qd02 = w * A13;
const CeedScalar qd12 = w * A23;
const CeedScalar qd22 = w * A33;
const CeedScalar u0 = u[i + Q * 0];
const CeedScalar u1 = u[i + Q * 1];
+156
View File
@@ -0,0 +1,156 @@
// Copyright (c) 2010-2022, 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 "../../gridfunc.hpp"
#include "util.hpp"
namespace mfem
{
namespace ceed
{
#ifdef MFEM_USE_CEED
static CeedElemTopology GetCeedTopology(Geometry::Type geom)
{
switch (geom)
{
case Geometry::SEGMENT:
return CEED_TOPOLOGY_LINE;
case Geometry::TRIANGLE:
return CEED_TOPOLOGY_TRIANGLE;
case Geometry::SQUARE:
return CEED_TOPOLOGY_QUAD;
case Geometry::TETRAHEDRON:
return CEED_TOPOLOGY_TET;
case Geometry::CUBE:
return CEED_TOPOLOGY_HEX;
case Geometry::PRISM:
return CEED_TOPOLOGY_PRISM;
case Geometry::PYRAMID:
return CEED_TOPOLOGY_PYRAMID;
default:
MFEM_ABORT("This type of element is not supported");
return CEED_TOPOLOGY_PRISM; // Silence warning
}
}
static void InitNonTensorBasis(const mfem::FiniteElementSpace &fes,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
Ceed ceed, CeedBasis *basis)
{
const mfem::DofToQuad &maps = fe.GetDofToQuad(ir, mfem::DofToQuad::FULL);
mfem::Mesh *mesh = fes.GetMesh();
const int dim = mesh->Dimension();
const int ndofs = maps.ndof;
const int nqpts = maps.nqpt;
mfem::DenseMatrix qX(dim,nqpts);
mfem::Vector qW(nqpts);
for (int i = 0; i < nqpts; i++)
{
const mfem::IntegrationPoint &ip = ir.IntPoint(i);
qX(0,i) = ip.x;
if (dim>1) { qX(1,i) = ip.y; }
if (dim>2) { qX(2,i) = ip.z; }
qW(i) = ip.weight;
}
CeedBasisCreateH1(ceed, GetCeedTopology(fe.GetGeomType()),
fes.GetVDim(), ndofs, nqpts,
maps.Bt.GetData(), maps.Gt.GetData(),
qX.GetData(), qW.GetData(), basis);
}
static void InitTensorBasis(const mfem::FiniteElementSpace &fes,
const mfem::FiniteElement &fe,
const mfem::IntegrationRule &ir,
Ceed ceed, CeedBasis *basis)
{
const mfem::DofToQuad &maps = fe.GetDofToQuad(ir, mfem::DofToQuad::TENSOR);
mfem::Mesh *mesh = fes.GetMesh();
const int ndofs = maps.ndof;
const int nqpts = maps.nqpt;
mfem::Vector qX(nqpts), qW(nqpts);
// The x-coordinates of the first `nqpts` points of the integration rule are
// the points of the corresponding 1D rule. We also scale the weights
// accordingly.
double w_sum = 0.0;
for (int i = 0; i < nqpts; i++)
{
const mfem::IntegrationPoint &ip = ir.IntPoint(i);
qX(i) = ip.x;
qW(i) = ip.weight;
w_sum += ip.weight;
}
qW *= 1.0/w_sum;
CeedBasisCreateTensorH1(ceed, mesh->Dimension(), fes.GetVDim(), ndofs,
nqpts, maps.Bt.GetData(),
maps.Gt.GetData(), qX.GetData(),
qW.GetData(), basis);
}
static void InitBasisImpl(const FiniteElementSpace &fes,
const FiniteElement &fe,
const IntegrationRule &ir,
Ceed ceed, CeedBasis *basis)
{
// Check for FES -> basis, restriction in hash tables
const int P = fe.GetDof();
const int Q = ir.GetNPoints();
const int ncomp = fes.GetVDim();
BasisKey basis_key(&fes, &ir, ncomp, P, Q);
auto basis_itr = mfem::internal::ceed_basis_map.find(basis_key);
const bool tensor = dynamic_cast<const mfem::TensorBasisElement *>
(&fe) != nullptr;
// Init or retreive key values
if (basis_itr == mfem::internal::ceed_basis_map.end())
{
if ( tensor )
{
InitTensorBasis(fes, fe, ir, ceed, basis);
}
else
{
InitNonTensorBasis(fes, fe, ir, ceed, basis);
}
mfem::internal::ceed_basis_map[basis_key] = *basis;
}
else
{
*basis = basis_itr->second;
}
}
void InitBasis(const FiniteElementSpace &fes,
const IntegrationRule &ir,
Ceed ceed, CeedBasis *basis)
{
const mfem::FiniteElement &fe = *fes.GetFE(0);
InitBasisImpl(fes, fe, ir, ceed, basis);
}
void InitBasisWithIndices(const FiniteElementSpace &fes,
const IntegrationRule &ir,
int nelem,
const int* indices,
Ceed ceed, CeedBasis *basis)
{
const mfem::FiniteElement &fe = *fes.GetFE(indices[0]);
InitBasisImpl(fes, fe, ir, ceed, basis);
}
#endif
} // namespace ceed
} // namespace mfem
+57
View File
@@ -0,0 +1,57 @@
// Copyright (c) 2010-2022, 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_LIBCEED_BASIS
#define MFEM_LIBCEED_BASIS
#include "ceed.hpp"
namespace mfem
{
namespace ceed
{
#ifdef MFEM_USE_CEED
/** @brief Initialize a CeedBasis for non-mixed meshes.
@param[in] fes Input finite element space.
@param[in] ir Input integration rule.
@param[in] ceed Input Ceed object.
@param[out] basis The address of the initialized CeedBasis object.
*/
void InitBasis(const FiniteElementSpace &fes,
const IntegrationRule &ir,
Ceed ceed, CeedBasis *basis);
/** @brief Initialize a CeedBasis for mixed meshes.
@param[in] fes The finite element space.
@param[in] ir is the integration rule for the operator.
@param[in] nelem The number of elements.
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`.
@param[in] ceed The Ceed object.
@param[out] basis The `CeedBasis` to initialize. */
void InitBasisWithIndices(const FiniteElementSpace &fes,
const IntegrationRule &ir,
int nelem,
const int* indices,
Ceed ceed, CeedBasis *basis);
#endif
} // namespace ceed
} // namespace mfem
#endif // MFEM_LIBCEED_BASIS
+35
View File
@@ -0,0 +1,35 @@
// Copyright (c) 2010-2022, 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_LIBCEED_CEED
#define MFEM_LIBCEED_CEED
#ifdef MFEM_USE_CEED
#include <ceed.h>
#if !CEED_VERSION_GE(0,10,0)
#error MFEM requires a libCEED version >= 0.10.0
#endif
namespace mfem
{
namespace internal
{
extern Ceed ceed;
} // namespace internal
} // namespace mfem
#endif // MFEM_USE_CEED
#endif // MFEM_LIBCEED_CEED
+441
View File
@@ -0,0 +1,441 @@
// Copyright (c) 2010-2022, 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_LIBCEED_COEFF
#define MFEM_LIBCEED_COEFF
#ifdef MFEM_USE_CEED
#include "../../../general/forall.hpp"
#include "../../../config/config.hpp"
#include "../../../linalg/vector.hpp"
#include "../../../linalg/dtensor.hpp"
#include "../../../mesh/mesh.hpp"
#include "../../gridfunc.hpp"
#include "util.hpp"
#include "ceed.hpp"
namespace mfem
{
class Mesh;
class IntegrationRule;
class Coefficient;
class VectorCoefficient;
class GridFunction;
namespace ceed
{
struct Coefficient
{
const int ncomp;
Coefficient(int ncomp_) : ncomp(ncomp_) { }
virtual bool IsConstant() const { return true; }
virtual ~Coefficient() { }
};
struct VariableCoefficient : Coefficient
{
CeedVector coeffVector = nullptr;
const CeedEvalMode emode;
VariableCoefficient(int ncomp_, CeedEvalMode emode_)
: Coefficient(ncomp_), emode(emode_) { }
virtual bool IsConstant() const override { return false; }
~VariableCoefficient()
{
CeedVectorDestroy(&coeffVector);
}
};
struct GridCoefficient : VariableCoefficient
{
const mfem::GridFunction &gf;
CeedBasis basis;
CeedElemRestriction restr;
GridCoefficient(const mfem::GridFunction &gf_)
: VariableCoefficient(gf_.VectorDim(), CEED_EVAL_INTERP),
gf(gf_)
{
InitVector(gf, coeffVector);
}
};
struct QuadCoefficient : VariableCoefficient
{
mfem::Vector coeff;
CeedElemRestriction restr;
QuadCoefficient(int ncomp_) : VariableCoefficient(ncomp_, CEED_EVAL_NONE) { }
};
/** @brief Initializes an mfem::ceed::Coefficient @a coeff_ptr from an
mfem::Coefficient @a Q, an mfem::Mesh @a mesh, and an mfem::IntegrationRule
@a ir.
@param[in] Q is the coefficient from the `Integrator`.
@param[in] mesh is the mesh.
@param[in] ir is the integration rule.
@param[out] coeff_ptr is the structure to store the coefficient for the
`CeedOperator`.
@param[out] ctx is the Context associated to the QFunction. */
template <typename Context>
void InitCoefficient(mfem::Coefficient *Q, mfem::Mesh &mesh,
const mfem::IntegrationRule &ir,
Coefficient*& coeff_ptr, Context &ctx)
{
if ( Q == nullptr )
{
Coefficient *ceedCoeff = new Coefficient(1);
ctx.coeff = 1.0;
coeff_ptr = ceedCoeff;
}
else if (ConstantCoefficient *const_coeff =
dynamic_cast<ConstantCoefficient*>(Q))
{
Coefficient *ceedCoeff = new Coefficient(1);
ctx.coeff = const_coeff->constant;
coeff_ptr = ceedCoeff;
}
else if (GridFunctionCoefficient* gf_coeff =
dynamic_cast<GridFunctionCoefficient*>(Q))
{
GridCoefficient *ceedCoeff =
new GridCoefficient(*gf_coeff->GetGridFunction());
coeff_ptr = ceedCoeff;
}
else if (QuadratureFunctionCoefficient *cQ =
dynamic_cast<QuadratureFunctionCoefficient*>(Q))
{
QuadCoefficient *ceedCoeff = new QuadCoefficient(1);
const int ne = mesh.GetNE();
const int nq = ir.GetNPoints();
const mfem::QuadratureFunction &qFun = cQ->GetQuadFunction();
MFEM_VERIFY(qFun.Size() == nq * ne,
"Incompatible QuadratureFunction dimension \n");
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetElementIntRule(0),
"IntegrationRule used within integrator and in"
" QuadratureFunction appear to be different");
qFun.Read();
ceedCoeff->coeff.MakeRef(const_cast<mfem::QuadratureFunction &>(qFun),0);
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
else
{
QuadCoefficient *ceedCoeff = new QuadCoefficient(1);
const int ne = mesh.GetNE();
const int nq = ir.GetNPoints();
ceedCoeff->coeff.SetSize(nq * ne);
auto C = Reshape(ceedCoeff->coeff.HostWrite(), nq, ne);
for (int e = 0; e < ne; ++e)
{
mfem::ElementTransformation &T = *mesh.GetElementTransformation(e);
for (int q = 0; q < nq; ++q)
{
C(q,e) = Q->Eval(T, ir.IntPoint(q));
}
}
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
}
/** @brief Initializes an mfem::ceed::Coefficient @a coeff_ptr from an
mfem::VectorCoefficient @a VQ, an mfem::Mesh @a mesh, and an
mfem::IntegrationRule @a ir.
@param[in] VQ is the vector coefficient from the `Integrator`.
@param[in] mesh is the mesh.
@param[in] ir is the integration rule.
@param[out] coeff_ptr is the structure to store the coefficient for the
`CeedOperator`.
@param[out] ctx is the Context associated to the QFunction. */
template <typename Context>
void InitCoefficient(mfem::VectorCoefficient *VQ, mfem::Mesh &mesh,
const mfem::IntegrationRule &ir,
Coefficient *&coeff_ptr, Context &ctx)
{
if (VectorConstantCoefficient *const_coeff =
dynamic_cast<VectorConstantCoefficient*>(VQ))
{
const int vdim = const_coeff->GetVDim();
const mfem::Vector &val = const_coeff->GetVec();
Coefficient *ceedCoeff = new Coefficient(vdim);
for (int i = 0; i < vdim; i++)
{
ctx.coeff[i] = val[i];
}
coeff_ptr = ceedCoeff;
}
else if (VectorGridFunctionCoefficient* vgf_coeff =
dynamic_cast<VectorGridFunctionCoefficient*>(VQ))
{
GridCoefficient *ceedCoeff =
new GridCoefficient(*vgf_coeff->GetGridFunction());
coeff_ptr = ceedCoeff;
}
else if (VectorQuadratureFunctionCoefficient *cQ =
dynamic_cast<VectorQuadratureFunctionCoefficient*>(VQ))
{
QuadCoefficient *ceedCoeff = new QuadCoefficient(cQ->GetVDim());
const int dim = mesh.Dimension();
const int ne = mesh.GetNE();
const int nq = ir.GetNPoints();
const mfem::QuadratureFunction &qFun = cQ->GetQuadFunction();
MFEM_VERIFY(qFun.Size() == dim * nq * ne,
"Incompatible QuadratureFunction dimension \n");
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetElementIntRule(0),
"IntegrationRule used within integrator and in"
" QuadratureFunction appear to be different");
qFun.Read();
ceedCoeff->coeff.MakeRef(const_cast<mfem::QuadratureFunction &>(qFun),0);
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
else
{
const int dim = mesh.Dimension();
QuadCoefficient *ceedCoeff = new QuadCoefficient(dim);
const int ne = mesh.GetNE();
const int nq = ir.GetNPoints();
ceedCoeff->coeff.SetSize(dim * nq * ne);
auto C = Reshape(ceedCoeff->coeff.HostWrite(), dim, nq, ne);
mfem::DenseMatrix Q_ir;
for (int e = 0; e < ne; ++e)
{
mfem::ElementTransformation &T = *mesh.GetElementTransformation(e);
VQ->Eval(Q_ir, T, ir);
for (int q = 0; q < nq; ++q)
{
for (int i = 0; i < dim; ++i)
{
C(i,q,e) = Q_ir(i,q);
}
}
}
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
}
/** @brief Initializes an mfem::ceed::Coefficient @a coeff_ptr from an
mfem::Coefficient @a Q, an mfem::Mesh @a mesh, and an mfem::IntegrationRule
@a ir for the elements given by the indices @a indices.
@param[in] Q is the coefficient from the `Integrator`.
@param[in] mesh is the mesh.
@param[in] ir is the integration rule.
@param[in] nelem The number of elements.
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`.
@param[out] coeff_ptr is the structure to store the coefficient for the
`CeedOperator`.
@param[out] ctx is the Context associated to the QFunction. */
template <typename Context>
void InitCoefficientWithIndices(mfem::Coefficient *Q, mfem::Mesh &mesh,
const mfem::IntegrationRule &ir,
int nelem,
const int* indices,
Coefficient*& coeff_ptr, Context &ctx)
{
if ( Q == nullptr )
{
Coefficient *ceedCoeff = new Coefficient(1);
ctx.coeff = 1.0;
coeff_ptr = ceedCoeff;
}
else if (ConstantCoefficient *const_coeff =
dynamic_cast<ConstantCoefficient*>(Q))
{
Coefficient *ceedCoeff = new Coefficient(1);
ctx.coeff = const_coeff->constant;
coeff_ptr = ceedCoeff;
}
else if (GridFunctionCoefficient* gf_coeff =
dynamic_cast<GridFunctionCoefficient*>(Q))
{
GridCoefficient *ceedCoeff =
new GridCoefficient(*gf_coeff->GetGridFunction());
coeff_ptr = ceedCoeff;
}
else if (QuadratureFunctionCoefficient *cQ =
dynamic_cast<QuadratureFunctionCoefficient*>(Q))
{
QuadCoefficient *ceedCoeff = new QuadCoefficient(1);
const int ne = mesh.GetNE();
const int nq = ir.GetNPoints();
const mfem::QuadratureFunction &qFun = cQ->GetQuadFunction();
MFEM_VERIFY(qFun.Size() == nq * ne,
"Incompatible QuadratureFunction dimension \n");
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetElementIntRule(0),
"IntegrationRule used within integrator and in"
" QuadratureFunction appear to be different");
ceedCoeff->coeff.SetSize(nq * nelem);
Memory<int> m_indices((int*)indices, nelem, false);
auto in = Reshape(qFun.Read(), nq, ne);
auto d_indices = Read(m_indices, nelem);
auto out = Reshape(ceedCoeff->coeff.Write(), nq, nelem);
MFEM_FORALL(i, nelem * nq,
{
const int q = i%nq;
const int sub_e = i/nq;
const int e = d_indices[sub_e];
out(q, sub_e) = in(q, e);
});
m_indices.DeleteDevice();
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
else
{
QuadCoefficient *ceedCoeff = new QuadCoefficient(1);
const int nq = ir.GetNPoints();
ceedCoeff->coeff.SetSize(nq * nelem);
auto C = Reshape(ceedCoeff->coeff.HostWrite(), nq, nelem);
for (int i = 0; i < nelem; ++i)
{
const int e = indices[i];
mfem::ElementTransformation &T = *mesh.GetElementTransformation(e);
for (int q = 0; q < nq; ++q)
{
C(q, i) = Q->Eval(T, ir.IntPoint(q));
}
}
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
}
/** @brief Initializes an mfem::ceed::Coefficient @a coeff_ptr from an
mfem::VectorCoefficient @a Q, an mfem::Mesh @a mesh, and an
mfem::IntegrationRule @a ir for the elements given by the indices @a indices.
@param[in] VQ is the vector coefficient from the `Integrator`.
@param[in] mesh is the mesh.
@param[in] ir is the integration rule.
@param[in] nelem The number of elements.
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`.
@param[out] coeff_ptr is the structure to store the coefficient for the
`CeedOperator`.
@param[out] ctx is the Context associated to the QFunction. */
template <typename Context>
void InitCoefficientWithIndices(mfem::VectorCoefficient *VQ, mfem::Mesh &mesh,
const mfem::IntegrationRule &ir,
int nelem,
const int* indices,
Coefficient *&coeff_ptr, Context &ctx)
{
if (VectorConstantCoefficient *const_coeff =
dynamic_cast<VectorConstantCoefficient*>(VQ))
{
const int vdim = const_coeff->GetVDim();
const mfem::Vector &val = const_coeff->GetVec();
Coefficient *ceedCoeff = new Coefficient(vdim);
for (int i = 0; i < vdim; i++)
{
ctx.coeff[i] = val[i];
}
coeff_ptr = ceedCoeff;
}
else if (VectorGridFunctionCoefficient* vgf_coeff =
dynamic_cast<VectorGridFunctionCoefficient*>(VQ))
{
GridCoefficient *ceedCoeff =
new GridCoefficient(*vgf_coeff->GetGridFunction());
coeff_ptr = ceedCoeff;
}
else if (VectorQuadratureFunctionCoefficient *cQ =
dynamic_cast<VectorQuadratureFunctionCoefficient*>(VQ))
{
QuadCoefficient *ceedCoeff = new QuadCoefficient(cQ->GetVDim());
const int dim = mesh.Dimension();
const int ne = mesh.GetNE();
const int nq = ir.GetNPoints();
const mfem::QuadratureFunction &qFun = cQ->GetQuadFunction();
MFEM_VERIFY(qFun.Size() == dim * nq * ne,
"Incompatible QuadratureFunction dimension \n");
MFEM_VERIFY(&ir == &qFun.GetSpace()->GetElementIntRule(0),
"IntegrationRule used within integrator and in"
" QuadratureFunction appear to be different");
ceedCoeff->coeff.SetSize(dim * nq * nelem);
Memory<int> m_indices((int*)indices, nelem, false);
auto in = Reshape(qFun.Read(), dim, nq, ne);
auto d_indices = Read(m_indices, nelem);
auto out = Reshape(ceedCoeff->coeff.Write(), dim, nq, nelem);
MFEM_FORALL(i, nelem * nq,
{
const int q = i%nq;
const int sub_e = i/nq;
const int e = d_indices[sub_e];
for (int d = 0; d < dim; d++)
{
out(d, q, sub_e) = in(d, q, e);
}
});
m_indices.DeleteDevice();
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
else
{
const int dim = mesh.Dimension();
QuadCoefficient *ceedCoeff = new QuadCoefficient(dim);
const int nq = ir.GetNPoints();
ceedCoeff->coeff.SetSize(dim * nq * nelem);
auto C = Reshape(ceedCoeff->coeff.HostWrite(), dim, nq, nelem);
mfem::DenseMatrix Q_ir;
for (int i = 0; i < nelem; ++i)
{
const int e = indices[i];
mfem::ElementTransformation &T = *mesh.GetElementTransformation(e);
VQ->Eval(Q_ir, T, ir);
for (int q = 0; q < nq; ++q)
{
for (int d = 0; d < dim; ++d)
{
C(d, q, i) = Q_ir(d, q);
}
}
}
InitVector(ceedCoeff->coeff, ceedCoeff->coeffVector);
coeff_ptr = ceedCoeff;
}
}
template <typename Coeff, typename Context>
void InitCoefficient(Coeff *Q, mfem::Mesh &mesh,
const mfem::IntegrationRule &ir, int nelem,
const int* indices, Coefficient *&coeff_ptr, Context &ctx)
{
if (indices)
{
InitCoefficientWithIndices(Q, mesh, ir, nelem, indices, coeff_ptr, ctx);
}
else
{
InitCoefficient(Q, mesh, ir, coeff_ptr, ctx);
}
}
} // namespace ceed
} // namespace mfem
#endif
#endif // MFEM_LIBCEED_COEFF
@@ -9,14 +9,17 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_LIBCEED_PAINTEG
#define MFEM_LIBCEED_PAINTEG
#ifndef MFEM_LIBCEED_INTEG
#define MFEM_LIBCEED_INTEG
#include "../../../config/config.hpp"
#include "../../fespace.hpp"
#include "../../gridfunc.hpp"
#include "operator.hpp"
#include "../../config/config.hpp"
#include "coefficient.hpp"
#include "../fespace.hpp"
#include "../gridfunc.hpp"
#include "restriction.hpp"
#include "util.hpp"
#include "ceed.hpp"
namespace mfem
{
@@ -84,6 +87,7 @@ protected:
CeedQFunctionContext build_ctx;
CeedOperator build_oper;
public:
PAIntegrator()
: Operator(),
trial_basis(nullptr), test_basis(nullptr), mesh_basis(nullptr),
@@ -93,23 +97,51 @@ protected:
qdata(nullptr), coeff(nullptr), build_ctx(nullptr), build_oper(nullptr)
{ }
public:
/** This method assembles the PAIntegrator.
/** @brief This method assembles the `PAIntegrator` with the given
`CeedOperatorInfo` @a info, an `mfem::FiniteElementSpace` @a fes, an
`mfem::IntegrationRule` @a ir, and `mfem::Coefficient` or
`mfem::VectorCoefficient` @a Q.
The `CeedOperatorInfo` type is expected to inherit from `OperatorInfo`,
and contain a `Context` type relevant to the qFunctions.
@param[in] info the `CeedOperatorInfo` describing the `CeedOperator`,
the `CeedOperatorInfo` type is expected to inherit from
`OperatorInfo` and contain a `Context` type relevant to
the qFunctions.
@param[in] fes the `FiniteElementSpace` for the form,
@param[in] ir the `IntegrationRule` for the numerical integration,
@param[in] Q `Coefficient` or `VectorCoefficient`. */
@param[in] info is the structure describing the CeedOperator to assemble.
@param[in] fes is the finite element space.
@param[in] ir is the integration rule for the operator.
@param[in] Q is the coefficient from the `Integrator`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
const mfem::IntegrationRule &ir,
CoeffType *Q)
{
Assemble(info, fes, fes, irm, Q);
Assemble(info, fes, ir, fes.GetNE(), nullptr, Q);
}
/** @brief This method assembles the `PAIntegrator` with the given
`CeedOperatorInfo` @a info, an `mfem::FiniteElementSpace` @a fes, an
`mfem::IntegrationRule` @a ir, and `mfem::Coefficient` or
`mfem::VectorCoefficient` @a Q for the elements given by the indices
@a indices.
The `CeedOperatorInfo` type is expected to inherit from `OperatorInfo`,
and contain a `Context` type relevant to the qFunctions.
@param[in] info is the structure describing the CeedOperator to assemble.
@param[in] fes is the finite element space.
@param[in] ir is the integration rule for the operator.
@param[in] nelem The number of elements.
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`. If `indices == nullptr`, assumes
that the `FiniteElementSpace` is not mixed.
@param[in] Q is the coefficient from the `Integrator`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
int nelem,
const int* indices,
CoeffType *Q)
{
Assemble(info, fes, fes, ir, nelem, indices, Q);
}
/** This method assembles the PAIntegrator for mixed forms.
@@ -126,12 +158,40 @@ public:
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &trial_fes,
const mfem::FiniteElementSpace &test_fes,
const mfem::IntegrationRule &irm,
const mfem::IntegrationRule &ir,
CoeffType *Q)
{
Assemble(info, trial_fes, test_fes, ir, trial_fes.GetNE(), nullptr, Q);
}
/** This method assembles the PAIntegrator for mixed forms on mixed meshes.
@param[in] info the `CeedOperatorInfo` describing the `CeedOperator`,
the `CeedOperatorInfo` type is expected to inherit from
`OperatorInfo` and contain a `Context` type relevant to
the qFunctions.
@param[in] trial_fes the trial `FiniteElementSpace` for the form,
@param[in] test_fes the test `FiniteElementSpace` for the form,
@param[in] ir the `IntegrationRule` for the numerical integration,
@param[in] nelem The number of elements,
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`. If `indices == nullptr`, assumes
that the `FiniteElementSpace` is not mixed,
@param[in] Q `Coefficient` or `VectorCoefficient`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &trial_fes,
const mfem::FiniteElementSpace &test_fes,
const mfem::IntegrationRule &ir,
int nelem,
const int* indices,
CoeffType *Q)
{
Ceed ceed(internal::ceed);
mfem::Mesh &mesh = *trial_fes.GetMesh();
InitCoefficient(Q, mesh, irm, coeff, info.ctx);
MFEM_VERIFY(!(!indices && mesh.GetNumGeometries(mesh.Dimension()) > 1),
"Use ceed::MixedIntegrator on mixed meshes.");
InitCoefficient(Q, mesh, ir, nelem, indices, coeff, info.ctx);
bool const_coeff = coeff->IsConstant();
std::string build_func = const_coeff ? info.build_func_const
: info.build_func_quad;
@@ -143,7 +203,6 @@ public:
info.trial_op,
info.test_op
};
CeedInt nqpts, nelem = mesh.GetNE();
CeedInt dim = mesh.SpaceDimension();
CeedInt trial_vdim = trial_fes.GetVDim();
CeedInt test_vdim = test_fes.GetVDim();
@@ -151,23 +210,23 @@ public:
mesh.EnsureNodes();
if ( &trial_fes == &test_fes )
{
InitBasisAndRestriction(trial_fes, irm, ceed,
&trial_basis, &trial_restr);
InitBasisAndRestriction(trial_fes, ir, nelem, indices,
ceed, &trial_basis, &trial_restr);
test_basis = trial_basis;
test_restr = trial_restr;
}
else
{
InitBasisAndRestriction(trial_fes, irm, ceed,
&trial_basis, &trial_restr);
InitBasisAndRestriction(test_fes, irm, ceed,
&test_basis, &test_restr);
InitBasisAndRestriction(trial_fes, ir, nelem, indices,
ceed, &trial_basis, &trial_restr);
InitBasisAndRestriction(test_fes, ir, nelem, indices,
ceed, &test_basis, &test_restr);
}
const mfem::FiniteElementSpace *mesh_fes = mesh.GetNodalFESpace();
MFEM_VERIFY(mesh_fes, "the Mesh has no nodal FE space");
InitBasisAndRestriction(*mesh_fes, irm, ceed, &mesh_basis,
&mesh_restr);
InitBasisAndRestriction(*mesh_fes, ir, nelem, indices,
ceed, &mesh_basis, &mesh_restr);
CeedInt trial_nqpts, test_nqpts;
CeedBasisGetNumQuadraturePoints(trial_basis, &trial_nqpts);
@@ -175,7 +234,7 @@ public:
MFEM_VERIFY(trial_nqpts == test_nqpts,
"Trial and test basis must have the same number of quadrature"
" points.");
nqpts = trial_nqpts;
CeedInt nqpts = trial_nqpts;
const int qdatasize = op.qdatasize;
InitStridedRestriction(*mesh_fes, nelem, nqpts, qdatasize,
@@ -219,8 +278,10 @@ public:
CeedOperatorCreate(ceed, build_qfunc, NULL, NULL, &build_oper);
if (GridCoefficient *gridCoeff = dynamic_cast<GridCoefficient*>(coeff))
{
InitBasisAndRestriction(*gridCoeff->gf.FESpace(), irm, ceed,
&gridCoeff->basis, &gridCoeff->restr);
InitBasisAndRestriction(*gridCoeff->gf.FESpace(), ir,
nelem, indices, ceed,
&gridCoeff->basis,
&gridCoeff->restr);
CeedOperatorSetField(build_oper, "coeff", gridCoeff->restr,
gridCoeff->basis, gridCoeff->coeffVector);
}
@@ -229,7 +290,8 @@ public:
{
const int ncomp = quadCoeff->ncomp;
CeedInt strides[3] = {ncomp, 1, ncomp*nqpts};
InitStridedRestriction(*mesh_fes, nelem, nqpts, ncomp, strides,
InitStridedRestriction(*mesh.GetNodalFESpace(),
nelem, nqpts, ncomp, strides,
&quadCoeff->restr);
CeedOperatorSetField(build_oper, "coeff", quadCoeff->restr,
CEED_BASIS_COLLOCATED, quadCoeff->coeffVector);
@@ -252,22 +314,17 @@ public:
switch (op.trial_op)
{
case EvalMode::None:
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim,
CEED_EVAL_NONE);
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim, CEED_EVAL_NONE);
break;
case EvalMode::Interp:
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim,
CEED_EVAL_INTERP);
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim, CEED_EVAL_INTERP);
break;
case EvalMode::Grad:
CeedQFunctionAddInput(apply_qfunc, "gu", trial_vdim*dim,
CEED_EVAL_GRAD);
CeedQFunctionAddInput(apply_qfunc, "gu", trial_vdim*dim, CEED_EVAL_GRAD);
break;
case EvalMode::InterpAndGrad:
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim,
CEED_EVAL_INTERP);
CeedQFunctionAddInput(apply_qfunc, "gu", trial_vdim*dim,
CEED_EVAL_GRAD);
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim, CEED_EVAL_INTERP);
CeedQFunctionAddInput(apply_qfunc, "gu", trial_vdim*dim, CEED_EVAL_GRAD);
break;
}
// qdata
@@ -276,22 +333,17 @@ public:
switch (op.test_op)
{
case EvalMode::None:
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim,
CEED_EVAL_NONE);
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim, CEED_EVAL_NONE);
break;
case EvalMode::Interp:
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim,
CEED_EVAL_INTERP);
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim, CEED_EVAL_INTERP);
break;
case EvalMode::Grad:
CeedQFunctionAddOutput(apply_qfunc, "gv", test_vdim*dim,
CEED_EVAL_GRAD);
CeedQFunctionAddOutput(apply_qfunc, "gv", test_vdim*dim, CEED_EVAL_GRAD);
break;
case EvalMode::InterpAndGrad:
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim,
CEED_EVAL_INTERP);
CeedQFunctionAddOutput(apply_qfunc, "gv", test_vdim*dim,
CEED_EVAL_GRAD);
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim, CEED_EVAL_INTERP);
CeedQFunctionAddOutput(apply_qfunc, "gv", test_vdim*dim, CEED_EVAL_GRAD);
break;
}
CeedQFunctionSetContext(apply_qfunc, build_ctx);
@@ -306,18 +358,14 @@ public:
CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
break;
case EvalMode::Interp:
CeedOperatorSetField(oper, "u", trial_restr, trial_basis,
CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "u", trial_restr, trial_basis, CEED_VECTOR_ACTIVE);
break;
case EvalMode::Grad:
CeedOperatorSetField(oper, "gu", trial_restr, trial_basis,
CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "gu", trial_restr, trial_basis, CEED_VECTOR_ACTIVE);
break;
case EvalMode::InterpAndGrad:
CeedOperatorSetField(oper, "u", trial_restr, trial_basis,
CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "gu", trial_restr, trial_basis,
CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "u", trial_restr, trial_basis, CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "gu", trial_restr, trial_basis, CEED_VECTOR_ACTIVE);
break;
}
// qdata
@@ -331,18 +379,14 @@ public:
CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
break;
case EvalMode::Interp:
CeedOperatorSetField(oper, "v", test_restr, test_basis,
CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "v", test_restr, test_basis, CEED_VECTOR_ACTIVE);
break;
case EvalMode::Grad:
CeedOperatorSetField(oper, "gv", test_restr, test_basis,
CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "gv", test_restr, test_basis, CEED_VECTOR_ACTIVE);
break;
case EvalMode::InterpAndGrad:
CeedOperatorSetField(oper, "v", test_restr, test_basis,
CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "gv", test_restr, test_basis,
CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "v", test_restr, test_basis, CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "gv", test_restr, test_basis, CEED_VECTOR_ACTIVE);
break;
}
@@ -400,6 +444,7 @@ protected:
Coefficient *coeff;
CeedQFunctionContext build_ctx;
public:
MFIntegrator()
: Operator(),
trial_basis(nullptr), test_basis(nullptr), mesh_basis(nullptr),
@@ -408,23 +453,51 @@ protected:
apply_qfunc(nullptr), node_coords(nullptr),
qdata(nullptr), coeff(nullptr), build_ctx(nullptr) { }
public:
/** This method assembles the MFIntegrator.
/** @brief This method assembles the `MFIntegrator` with the given
`CeedOperatorInfo` @a info, an `mfem::FiniteElementSpace` @a fes, an
`mfem::IntegrationRule` @a ir, and `mfem::Coefficient` or
`mfem::VectorCoefficient` @a Q.
The `CeedOperatorInfo` type is expected to inherit from `OperatorInfo`,
and contain a `Context` type relevant to the qFunctions.
@param[in] info the `CeedOperatorInfo` describing the `CeedOperator`,
the `CeedOperatorInfo` type is expected to inherit from
`OperatorInfo` and contain a `Context` type relevant to
the qFunctions.
@param[in] fes the `FiniteElementSpace` for the form,
@param[in] ir the `IntegrationRule` for the numerical integration,
@param[in] Q `Coefficient` or `VectorCoefficient`. */
@param[in] info is the structure describing the CeedOperator to assemble.
@param[in] fes is the finite element space.
@param[in] ir is the integration rule for the operator.
@param[in] Q is the coefficient from the `Integrator`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &irm,
const mfem::IntegrationRule &ir,
CoeffType *Q)
{
Assemble(info, fes, fes, irm, Q);
Assemble(info, fes, ir, fes.GetNE(), nullptr, Q);
}
/** @brief This method assembles the `MFIntegrator` with the given
`CeedOperatorInfo` @a info, an `mfem::FiniteElementSpace` @a fes, an
`mfem::IntegrationRule` @a ir, and `mfem::Coefficient` or
`mfem::VectorCoefficient` @a Q for the elements given by the indices
@a indices.
The `CeedOperatorInfo` type is expected to inherit from `OperatorInfo`,
and contain a `Context` type relevant to the qFunctions.
@param[in] info is the structure describing the CeedOperator to assemble.
@param[in] fes is the finite element space.
@param[in] ir is the integration rule for the operator.
@param[in] nelem The number of elements.
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`. If `indices == nullptr`, assumes
that the `FiniteElementSpace` is not mixed.
@param[in] Q is the coefficient from the `Integrator`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
int nelem,
const int* indices,
CoeffType *Q)
{
Assemble(info, fes, fes, ir, nelem, indices, Q);
}
/** This method assembles the MFIntegrator for mixed forms.
@@ -441,12 +514,40 @@ public:
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &trial_fes,
const mfem::FiniteElementSpace &test_fes,
const mfem::IntegrationRule &irm,
const mfem::IntegrationRule &ir,
CoeffType *Q)
{
Assemble(info, trial_fes, test_fes, ir, trial_fes.GetNE(), nullptr, Q);
}
/** This method assembles the MFIntegrator for mixed forms.
@param[in] info the `CeedOperatorInfo` describing the `CeedOperator`,
the `CeedOperatorInfo` type is expected to inherit from
`OperatorInfo` and contain a `Context` type relevant to
the qFunctions.
@param[in] trial_fes the trial `FiniteElementSpace` for the form,
@param[in] test_fes the test `FiniteElementSpace` for the form,
@param[in] ir the `IntegrationRule` for the numerical integration,
@param[in] nelem The number of elements,
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`. If `indices == nullptr`, assumes
that the `FiniteElementSpace` is not mixed,
@param[in] Q `Coefficient` or `VectorCoefficient`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &trial_fes,
const mfem::FiniteElementSpace &test_fes,
const mfem::IntegrationRule &ir,
int nelem,
const int* indices,
CoeffType *Q)
{
Ceed ceed(internal::ceed);
Mesh &mesh = *trial_fes.GetMesh();
InitCoefficient(Q, mesh, irm, coeff, info.ctx);
MFEM_VERIFY(!(!indices && mesh.GetNumGeometries(mesh.Dimension()) > 1),
"Use ceed::MixedIntegrator on mixed meshes.");
InitCoefficient(Q, mesh, ir, nelem, indices, coeff, info.ctx);
bool const_coeff = coeff->IsConstant();
std::string apply_func = const_coeff ? info.apply_func_mf_const
: info.apply_func_mf_quad;
@@ -457,7 +558,7 @@ public:
info.trial_op,
info.test_op
};
CeedInt nqpts, nelem = mesh.GetNE();
CeedInt dim = mesh.SpaceDimension();
CeedInt trial_vdim = trial_fes.GetVDim();
CeedInt test_vdim = test_fes.GetVDim();
@@ -465,22 +566,22 @@ public:
mesh.EnsureNodes();
if ( &trial_fes == &test_fes )
{
InitBasisAndRestriction(trial_fes, irm, ceed,
InitBasisAndRestriction(trial_fes, ir, nelem, indices, ceed,
&trial_basis, &trial_restr);
test_basis = trial_basis;
test_restr = trial_restr;
}
else
{
InitBasisAndRestriction(trial_fes, irm, ceed,
InitBasisAndRestriction(trial_fes, ir, nelem, indices, ceed,
&trial_basis, &trial_restr);
InitBasisAndRestriction(test_fes, irm, ceed,
InitBasisAndRestriction(test_fes, ir, nelem, indices, ceed,
&test_basis, &test_restr);
}
const mfem::FiniteElementSpace *mesh_fes = mesh.GetNodalFESpace();
MFEM_VERIFY(mesh_fes, "the Mesh has no nodal FE space");
InitBasisAndRestriction(*mesh_fes, irm, ceed, &mesh_basis,
InitBasisAndRestriction(*mesh_fes, ir, nelem, indices, ceed, &mesh_basis,
&mesh_restr);
CeedInt trial_nqpts, test_nqpts;
@@ -489,7 +590,7 @@ public:
MFEM_VERIFY(trial_nqpts == test_nqpts,
"Trial and test basis must have the same number of quadrature"
" points.");
nqpts = trial_nqpts;
CeedInt nqpts = trial_nqpts;
InitVector(*mesh.GetNodes(), node_coords);
@@ -570,8 +671,8 @@ public:
// coefficient
if (GridCoefficient *gridCoeff = dynamic_cast<GridCoefficient*>(coeff))
{
InitBasisAndRestriction(*gridCoeff->gf.FESpace(), irm, ceed,
&gridCoeff->basis, &gridCoeff->restr);
InitBasisAndRestriction(*gridCoeff->gf.FESpace(), ir, nelem, indices,
ceed, &gridCoeff->basis, &gridCoeff->restr);
CeedOperatorSetField(oper, "coeff", gridCoeff->restr,
gridCoeff->basis, gridCoeff->coeffVector);
}
@@ -673,4 +774,4 @@ private:
} // namespace mfem
#endif // MFEM_LIBCEED_PAINTEG
#endif // MFEM_LIBCEED_INTEG
+32
View File
@@ -0,0 +1,32 @@
// Copyright (c) 2010-2022, 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_LIBCEED_INTERFACE
#define MFEM_LIBCEED_INTERFACE
// Object wrapping a CeedOperator in a mfem::Operator.
#include "operator.hpp"
// Functions to initialize CeedBasis objects.
#include "basis.hpp"
// Functions to initialize CeedRestriction objects.
#include "restriction.hpp"
// Functions to initialize coefficients.
#include "coefficient.hpp"
// PA or MF Operator using libCEED.
#include "integrator.hpp"
// PA Operator supporting mixed finite element spaces.
#include "mixed_integrator.hpp"
// Utility functions
#include "util.hpp"
// Wrapper to include <ceed.h>
#include "ceed.hpp"
#endif // MFEM_LIBCEED_INTERFACE
+126
View File
@@ -0,0 +1,126 @@
// Copyright (c) 2010-2022, 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_LIBCEED_MIXED_INTEGRATOR
#define MFEM_LIBCEED_MIXED_INTEGRATOR
#include "ceed.hpp"
#include "integrator.hpp"
#include <unordered_map>
namespace mfem
{
namespace ceed
{
/** @brief This class wraps a `ceed::PAIntegrator` or `ceed::MFIntegrator` to
support mixed finite element spaces. */
template <typename CeedInteg>
class MixedIntegrator : public ceed::Operator
{
#ifdef MFEM_USE_CEED
using ElementKey = std::pair<int, int>; //< Element::Type, Order >
struct key_hash
{
std::size_t operator()(const ElementKey& k) const
{
return k.first + 2 * k.second;
}
};
using ElementsMap = std::unordered_map<const ElementKey, int*, key_hash>;
std::vector<CeedInteg*> sub_ops;
public:
template <typename Integrator, typename CeedOperatorInfo, typename CoeffType>
void Assemble(const Integrator &integ,
CeedOperatorInfo &info,
const mfem::FiniteElementSpace &fes,
CoeffType *Q)
{
ElementsMap count;
ElementsMap element_indices;
ElementsMap offsets;
// Count the number of elements of each type
for (int i = 0; i < fes.GetNE(); i++)
{
ElementKey key(fes.GetElementType(i), fes.GetElementOrder(i));
auto value = count.find(key);
if (value == count.end())
{
count[key] = new int(1);
}
else
{
(*value->second)++;
}
}
// Initialization of the arrays
for ( const auto& value : count )
{
element_indices[value.first] = new int[*value.second];
offsets[value.first] = new int(0);
}
// Populates the indices arrays for each element type
for (int i = 0; i < fes.GetNE(); i++)
{
ElementKey key(fes.GetElementType(i), fes.GetElementOrder(i));
int &offset = *(offsets[key]);
int* indices_array = element_indices[key];
indices_array[offset] = i;
offset++;
}
// Create composite CeedOperator
CeedCompositeOperatorCreate(internal::ceed, &oper);
// Create each sub-CeedOperator
sub_ops.reserve(element_indices.size());
for (const auto& value : element_indices)
{
const int* indices = value.second;
const int first_index = indices[0];
const mfem::FiniteElement &el = *fes.GetFE(first_index);
auto &T = *fes.GetMesh()->GetElementTransformation(first_index);
MFEM_ASSERT(!integ.GetIntegrationRule(),
"Mixed mesh integrators should not have an"
" IntegrationRule.");
const IntegrationRule &ir = GetRule(integ, el, el, T);
auto sub_op = new CeedInteg();
int nelem = *count[value.first];
sub_op->Assemble(info, fes, ir, nelem, indices, Q);
sub_ops.push_back(sub_op);
CeedCompositeOperatorAddSub(oper, sub_op->GetCeedOperator());
}
const int ndofs = fes.GetVDim() * fes.GetNDofs();
CeedVectorCreate(internal::ceed, ndofs, &u);
CeedVectorCreate(internal::ceed, ndofs, &v);
}
virtual ~MixedIntegrator()
{
for (auto sub_op : sub_ops)
{
delete sub_op;
}
}
#endif
};
} // namespace ceed
} // namespace mfem
#endif // MFEM_LIBCEED_MIXED_INTEGRATOR
@@ -11,9 +11,11 @@
#include "operator.hpp"
#include "../../config/config.hpp"
#include "../../linalg/vector.hpp"
#include "../fespace.hpp"
#include "../../../config/config.hpp"
#include "../../../linalg/vector.hpp"
#include "../../fespace.hpp"
#include "util.hpp"
#include "ceed.hpp"
namespace mfem
{
@@ -12,8 +12,8 @@
#ifndef MFEM_LIBCEED_OPERATOR
#define MFEM_LIBCEED_OPERATOR
#include "util.hpp"
#include "../../linalg/operator.hpp"
#include "../../../linalg/operator.hpp"
#include "ceed.hpp"
namespace mfem
{
@@ -41,7 +41,6 @@ public:
void AddMult(const mfem::Vector &x, mfem::Vector &y) const;
void GetDiagonal(mfem::Vector &diag) const;
using mfem::Operator::SetupRAP;
virtual ~Operator()
{
#ifdef MFEM_USE_CEED
+301
View File
@@ -0,0 +1,301 @@
// Copyright (c) 2010-2022, 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 "../../../fem/gridfunc.hpp"
#include "ceed.hpp"
namespace mfem
{
namespace ceed
{
#ifdef MFEM_USE_CEED
static void InitNativeRestr(const mfem::FiniteElementSpace &fes,
Ceed ceed, CeedElemRestriction *restr)
{
const mfem::FiniteElement *fe = fes.GetFE(0);
const int P = fe->GetDof();
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
const mfem::Table &el_dof = fes.GetElementToDofTable();
mfem::Array<int> tp_el_dof(el_dof.Size_of_connections());
const mfem::TensorBasisElement * tfe =
dynamic_cast<const mfem::TensorBasisElement *>(fe);
const int stride = compstride == 1 ? fes.GetVDim() : 1;
const mfem::Array<int>& dof_map = tfe->GetDofMap();
for (int i = 0; i < fes.GetNE(); i++)
{
const int el_offset = P * i;
for (int j = 0; j < P; j++)
{
tp_el_dof[j+el_offset] = stride*el_dof.GetJ()[dof_map[j]+el_offset];
}
}
CeedElemRestrictionCreate(ceed, fes.GetNE(), P, fes.GetVDim(),
compstride, (fes.GetVDim())*(fes.GetNDofs()),
CEED_MEM_HOST, CEED_COPY_VALUES,
tp_el_dof.GetData(), restr);
}
static void InitLexicoRestr(const mfem::FiniteElementSpace &fes,
Ceed ceed, CeedElemRestriction *restr)
{
const mfem::FiniteElement *fe = fes.GetFE(0);
const int P = fe->GetDof();
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
const mfem::Table &el_dof = fes.GetElementToDofTable();
mfem::Array<int> tp_el_dof(el_dof.Size_of_connections());
const int stride = compstride == 1 ? fes.GetVDim() : 1;
for (int e = 0; e < fes.GetNE(); e++)
{
for (int i = 0; i < P; i++)
{
tp_el_dof[i + e*P] = stride*el_dof.GetJ()[i + e*P];
}
}
CeedElemRestrictionCreate(ceed, fes.GetNE(), P, fes.GetVDim(),
compstride, (fes.GetVDim())*(fes.GetNDofs()),
CEED_MEM_HOST, CEED_COPY_VALUES,
tp_el_dof.GetData(), restr);
}
static void InitRestrictionImpl(const mfem::FiniteElementSpace &fes,
Ceed ceed, CeedElemRestriction *restr)
{
const mfem::FiniteElement *fe = fes.GetFE(0);
const mfem::TensorBasisElement * tfe =
dynamic_cast<const mfem::TensorBasisElement *>(fe);
if ( tfe && tfe->GetDofMap().Size()>0 ) // Native ordering using dof_map
{
InitNativeRestr(fes, ceed, restr);
}
else // Lexicographic ordering
{
InitLexicoRestr(fes, ceed, restr);
}
}
static void InitNativeRestrWithIndices(
const mfem::FiniteElementSpace &fes,
int nelem,
const int* indices,
Ceed ceed, CeedElemRestriction *restr)
{
const mfem::FiniteElement *fe = fes.GetFE(indices[0]);
const int P = fe->GetDof();
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
mfem::Array<int> tp_el_dof(nelem*P);
const mfem::TensorBasisElement * tfe =
dynamic_cast<const mfem::TensorBasisElement *>(fe);
Array<int> dofs;
const int stride = compstride == 1 ? fes.GetVDim() : 1;
const mfem::Array<int>& dof_map = tfe->GetDofMap();
for (int i = 0; i < nelem; i++)
{
const int elem_index = indices[i];
fes.GetElementDofs(elem_index, dofs);
const int el_offset = P * i;
for (int j = 0; j < P; j++)
{
tp_el_dof[j + el_offset] = stride*dofs[dof_map[j]];
}
}
CeedElemRestrictionCreate(ceed, nelem, P, fes.GetVDim(),
compstride, (fes.GetVDim())*(fes.GetNDofs()),
CEED_MEM_HOST, CEED_COPY_VALUES,
tp_el_dof.GetData(), restr);
}
static void InitLexicoRestrWithIndices(
const mfem::FiniteElementSpace &fes,
int nelem,
const int* indices,
Ceed ceed, CeedElemRestriction *restr)
{
const mfem::FiniteElement *fe = fes.GetFE(indices[0]);
const int P = fe->GetDof();
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
mfem::Array<int> tp_el_dof(nelem*P);
Array<int> dofs;
const int stride = compstride == 1 ? fes.GetVDim() : 1;
for (int i = 0; i < nelem; i++)
{
const int elem_index = indices[i];
fes.GetElementDofs(elem_index, dofs);
const int el_offset = P * i;
for (int j = 0; j < P; j++)
{
tp_el_dof[j + el_offset] = stride*dofs[j];
}
}
CeedElemRestrictionCreate(ceed, nelem, P, fes.GetVDim(),
compstride, (fes.GetVDim())*(fes.GetNDofs()),
CEED_MEM_HOST, CEED_COPY_VALUES,
tp_el_dof.GetData(), restr);
}
static void InitRestrictionWithIndicesImpl(
const mfem::FiniteElementSpace &fes,
int nelem,
const int* indices,
Ceed ceed, CeedElemRestriction *restr)
{
const mfem::FiniteElement *fe = fes.GetFE(indices[0]);
const mfem::TensorBasisElement * tfe =
dynamic_cast<const mfem::TensorBasisElement *>(fe);
if ( tfe && tfe->GetDofMap().Size()>0 ) // Native ordering using dof_map
{
InitNativeRestrWithIndices(fes, nelem, indices, ceed, restr);
}
else // Lexicographic ordering
{
InitLexicoRestrWithIndices(fes, nelem, indices, ceed, restr);
}
}
static void InitCoeffRestrictionWithIndicesImpl(
const mfem::FiniteElementSpace &fes,
int nelem,
const int* indices,
int nquads,
int ncomp,
Ceed ceed,
CeedElemRestriction *restr)
{
mfem::Array<int> tp_el_dof(nelem*nquads);
const int stride_quad = ncomp;
const int stride_elem = ncomp*nquads;
// TODO generalize to support different #quads
for (int i = 0; i < nelem; i++)
{
const int elem_index = indices[i];
const int el_offset = elem_index * stride_elem;
for (int j = 0; j < nquads; j++)
{
tp_el_dof[j + nquads * i] = j * stride_quad + el_offset;
}
}
CeedElemRestrictionCreate(ceed, nelem, nquads, ncomp, 1,
ncomp*fes.GetNE()*nquads,
CEED_MEM_HOST, CEED_COPY_VALUES,
tp_el_dof.GetData(), restr);
}
void InitStridedRestriction(const mfem::FiniteElementSpace &fes,
CeedInt nelem, CeedInt nqpts, CeedInt qdatasize,
const CeedInt *strides,
CeedElemRestriction *restr)
{
RestrKey restr_key(&fes, nelem, nqpts, qdatasize, restr_type::Strided);
auto restr_itr = mfem::internal::ceed_restr_map.find(restr_key);
if (restr_itr == mfem::internal::ceed_restr_map.end())
{
CeedElemRestrictionCreateStrided(mfem::internal::ceed, nelem, nqpts, qdatasize,
nelem*nqpts*qdatasize,
strides,
restr);
// Will be automatically destroyed when @a fes gets destroyed.
mfem::internal::ceed_restr_map[restr_key] = *restr;
}
else
{
*restr = restr_itr->second;
}
}
void InitRestriction(const FiniteElementSpace &fes,
Ceed ceed,
CeedElemRestriction *restr)
{
// Check for FES -> basis, restriction in hash tables
const mfem::FiniteElement *fe = fes.GetFE(0);
const int P = fe->GetDof();
const int nelem = fes.GetNE();
const int ncomp = fes.GetVDim();
RestrKey restr_key(&fes, nelem, P, ncomp, restr_type::Standard);
auto restr_itr = mfem::internal::ceed_restr_map.find(restr_key);
// Init or retreive key values
if (restr_itr == mfem::internal::ceed_restr_map.end())
{
InitRestrictionImpl(fes, ceed, restr);
mfem::internal::ceed_restr_map[restr_key] = *restr;
}
else
{
*restr = restr_itr->second;
}
}
void InitRestrictionWithIndices(const FiniteElementSpace &fes,
int nelem,
const int* indices,
Ceed ceed,
CeedElemRestriction *restr)
{
// Check for FES -> basis, restriction in hash tables
const mfem::FiniteElement *fe = fes.GetFE(indices[0]);
const int P = fe->GetDof();
const int ncomp = fes.GetVDim();
RestrKey restr_key(&fes, nelem, P, ncomp, restr_type::Standard);
auto restr_itr = mfem::internal::ceed_restr_map.find(restr_key);
// Init or retreive key values
if (restr_itr == mfem::internal::ceed_restr_map.end())
{
InitRestrictionWithIndicesImpl(fes, nelem, indices, ceed, restr);
mfem::internal::ceed_restr_map[restr_key] = *restr;
}
else
{
*restr = restr_itr->second;
}
}
void InitCoeffRestrictionWithIndices(const FiniteElementSpace &fes,
int nelem,
const int* indices,
int nquads,
int ncomp,
Ceed ceed,
CeedElemRestriction *restr)
{
// Check for FES -> basis, restriction in hash tables
RestrKey restr_key(&fes, nelem, nquads, ncomp, restr_type::Coeff);
auto restr_itr = mfem::internal::ceed_restr_map.find(restr_key);
// Init or retreive key values
if (restr_itr == mfem::internal::ceed_restr_map.end())
{
InitCoeffRestrictionWithIndicesImpl(fes, nelem, indices, nquads, ncomp,
ceed, restr);
mfem::internal::ceed_restr_map[restr_key] = *restr;
}
else
{
*restr = restr_itr->second;
}
}
#endif
} // namespace ceed
} // namespace mfem
+88
View File
@@ -0,0 +1,88 @@
// Copyright (c) 2010-2022, 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_LIBCEED_RESTR
#define MFEM_LIBCEED_RESTR
#include "ceed.hpp"
namespace mfem
{
namespace ceed
{
#ifdef MFEM_USE_CEED
/** @brief Initialize a CeedElemRestriction for non-mixed meshes.
@param[in] fes Input finite element space.
@param[in] ceed Input Ceed object.
@param[out] restr The address of the initialized CeedElemRestriction object.
*/
void InitRestriction(const FiniteElementSpace &fes,
Ceed ceed,
CeedElemRestriction *restr);
/** @brief Initialize a CeedElemRestriction for mixed meshes.
@param[in] fes The finite element space.
@param[in] ceed The Ceed object.
@param[in] nelem The number of elements.
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`.
@param[out] restr The `CeedElemRestriction` to initialize. */
void InitRestrictionWithIndices(const FiniteElementSpace &fes,
int nelem,
const int* indices,
Ceed ceed,
CeedElemRestriction *restr);
/** @brief Initialize a strided CeedElemRestriction
@param[in] nelem is the number of elements.
@param[in] nqpts is the total number of quadrature points.
@param[in] qdatasize is the number of data per quadrature point.
@param[in] strides Array for strides between [nodes, components, elements].
Data for node i, component j, element k can be found in the L-vector at
index i*strides[0] + j*strides[1] + k*strides[2]. CEED_STRIDES_BACKEND may
be used with vectors created by a Ceed backend.
@param[out] restr The `CeedElemRestriction` to initialize. */
void InitStridedRestriction(const mfem::FiniteElementSpace &fes,
CeedInt nelem, CeedInt nqpts, CeedInt qdatasize,
const CeedInt *strides,
CeedElemRestriction *restr);
/** @brief Initialize a CeedElemRestriction for a mfem::Coefficient on a mixed
mesh.
@param[in] fes The finite element space.
@param[in] nelem is the number of elements.
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`.
@param[in] nquads is the total number of quadrature points
@param[in] ncomp is the number of data per quadrature point
@param[in] ceed The Ceed object.
@param[out] restr The `CeedElemRestriction` to initialize. */
void InitCoeffRestrictionWithIndices(const FiniteElementSpace &fes,
int nelem,
const int* indices,
int nquads,
int ncomp,
Ceed ceed,
CeedElemRestriction *restr);
#endif
} // namespace ceed
} // namespace mfem
#endif // MFEM_LIBCEED_RESTR
+281
View File
@@ -0,0 +1,281 @@
// Copyright (c) 2010-2022, 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/device.hpp"
#include "../../../fem/gridfunc.hpp"
#include "../../../linalg/dtensor.hpp"
#include "basis.hpp"
#include "restriction.hpp"
#include "ceed.hpp"
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
typedef struct stat struct_stat;
#else
#define stat(dir, buf) _stat(dir, buf)
#define S_ISDIR(mode) _S_IFDIR(mode)
typedef struct _stat struct_stat;
#endif
namespace mfem
{
bool DeviceCanUseCeed()
{
return Device::Allows(Backend::CEED_MASK);
}
namespace ceed
{
void RemoveBasisAndRestriction(const mfem::FiniteElementSpace *fes)
{
#ifdef MFEM_USE_CEED
auto itb = mfem::internal::ceed_basis_map.begin();
while (itb != mfem::internal::ceed_basis_map.end())
{
if (std::get<0>(itb->first)==fes)
{
CeedBasisDestroy(&itb->second);
itb = mfem::internal::ceed_basis_map.erase(itb);
}
else
{
itb++;
}
}
auto itr = mfem::internal::ceed_restr_map.begin();
while (itr != mfem::internal::ceed_restr_map.end())
{
if (std::get<0>(itr->first)==fes)
{
CeedElemRestrictionDestroy(&itr->second);
itr = mfem::internal::ceed_restr_map.erase(itr);
}
else
{
itr++;
}
}
#endif
}
#ifdef MFEM_USE_CEED
void InitVector(const mfem::Vector &v, CeedVector &cv)
{
CeedVectorCreate(mfem::internal::ceed, v.Size(), &cv);
CeedScalar *cv_ptr;
CeedMemType mem;
CeedGetPreferredMemType(mfem::internal::ceed, &mem);
if ( Device::Allows(Backend::DEVICE_MASK) && mem==CEED_MEM_DEVICE )
{
cv_ptr = const_cast<CeedScalar*>(v.Read());
}
else
{
cv_ptr = const_cast<CeedScalar*>(v.HostRead());
mem = CEED_MEM_HOST;
}
CeedVectorSetArray(cv, mem, CEED_USE_POINTER, cv_ptr);
}
void InitBasisAndRestriction(const FiniteElementSpace &fes,
const IntegrationRule &irm,
Ceed ceed, CeedBasis *basis,
CeedElemRestriction *restr)
{
InitBasis(fes, irm, ceed, basis);
InitRestriction(fes, ceed, restr);
}
void InitBasisAndRestrictionWithIndices(const FiniteElementSpace &fes,
const IntegrationRule &irm,
int nelem,
const int* indices,
Ceed ceed, CeedBasis *basis,
CeedElemRestriction *restr)
{
InitBasisWithIndices(fes, irm, nelem, indices, ceed, basis);
InitRestrictionWithIndices(fes, nelem, indices, ceed, restr);
}
void InitBasisAndRestriction(const FiniteElementSpace &fes,
const IntegrationRule &irm,
int nelem,
const int* indices,
Ceed ceed, CeedBasis *basis,
CeedElemRestriction *restr)
{
if (indices)
{
InitBasisAndRestrictionWithIndices(fes,irm,nelem,indices,ceed,basis,restr);
}
else
{
InitBasisAndRestriction(fes,irm,ceed,basis,restr);
}
}
// Assumes a tensor-product operator with one active field
int CeedOperatorGetActiveField(CeedOperator oper, CeedOperatorField *field)
{
int ierr;
Ceed ceed;
ierr = CeedOperatorGetCeed(oper, &ceed); CeedChk(ierr);
CeedQFunction qf;
bool isComposite;
ierr = CeedOperatorIsComposite(oper, &isComposite); CeedChk(ierr);
CeedOperator *subops;
if (isComposite)
{
ierr = CeedOperatorGetSubList(oper, &subops); CeedChk(ierr);
ierr = CeedOperatorGetQFunction(subops[0], &qf); CeedChk(ierr);
}
else
{
ierr = CeedOperatorGetQFunction(oper, &qf); CeedChk(ierr);
}
CeedInt numinputfields, numoutputfields;
ierr = CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
CeedOperatorField *inputfields;
if (isComposite)
{
ierr = CeedOperatorGetFields(subops[0], &numinputfields, &inputfields,
&numoutputfields, NULL); CeedChk(ierr);
}
else
{
ierr = CeedOperatorGetFields(oper, &numinputfields, &inputfields,
&numoutputfields, NULL); CeedChk(ierr);
}
CeedVector if_vector;
bool found = false;
int found_index = -1;
for (int i = 0; i < numinputfields; ++i)
{
ierr = CeedOperatorFieldGetVector(inputfields[i], &if_vector); CeedChk(ierr);
if (if_vector == CEED_VECTOR_ACTIVE)
{
if (found)
{
return CeedError(ceed, 1, "Multiple active vectors in CeedOperator!");
}
found = true;
found_index = i;
}
}
if (!found)
{
return CeedError(ceed, 1, "No active vector in CeedOperator!");
}
*field = inputfields[found_index];
return 0;
}
template <>
const IntegrationRule & GetRule<MassIntegrator>(
const MassIntegrator &integ,
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &trans)
{
return MassIntegrator::GetRule(trial_fe, test_fe, trans);
}
template <>
const IntegrationRule & GetRule<VectorMassIntegrator>(
const VectorMassIntegrator &integ,
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &trans)
{
return MassIntegrator::GetRule(trial_fe, test_fe, trans);
}
template <>
const IntegrationRule & GetRule<ConvectionIntegrator>(
const ConvectionIntegrator &integ,
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &trans)
{
return ConvectionIntegrator::GetRule(trial_fe, test_fe, trans);
}
template <>
const IntegrationRule & GetRule<VectorConvectionNLFIntegrator>(
const VectorConvectionNLFIntegrator &integ,
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &trans)
{
return VectorConvectionNLFIntegrator::GetRule(trial_fe, trans);
}
template <>
const IntegrationRule & GetRule<DiffusionIntegrator>(
const DiffusionIntegrator &integ,
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &trans)
{
return DiffusionIntegrator::GetRule(trial_fe, test_fe);
}
template <>
const IntegrationRule & GetRule<VectorDiffusionIntegrator>(
const VectorDiffusionIntegrator &integ,
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &trans)
{
return DiffusionIntegrator::GetRule(trial_fe, test_fe);
}
std::string ceed_path;
const std::string &GetCeedPath()
{
if (ceed_path.empty())
{
const char *install_dir = MFEM_INSTALL_DIR "/include/mfem/fem/ceed";
const char *source_dir = MFEM_SOURCE_DIR "/fem/ceed";
struct_stat m_stat;
if (stat(install_dir, &m_stat) == 0 && S_ISDIR(m_stat.st_mode))
{
ceed_path = install_dir;
}
else if (stat(source_dir, &m_stat) == 0 && S_ISDIR(m_stat.st_mode))
{
ceed_path = source_dir;
}
else
{
MFEM_ABORT("Cannot find libCEED kernels in MFEM_INSTALL_DIR or "
"MFEM_SOURCE_DIR");
}
// Could be useful for debugging:
// out << "Using libCEED dir: " << ceed_path << std::endl;
}
return ceed_path;
}
#endif
} // namespace ceed
} // namespace mfem
@@ -12,24 +12,23 @@
#ifndef MFEM_LIBCEED_UTIL
#define MFEM_LIBCEED_UTIL
#include "../../config/config.hpp"
#include "../../general/error.hpp"
#ifdef MFEM_USE_CEED
#include <ceed.h>
#include <ceed/hash.h>
#include <ceed/backend.h> // for CeedOperatorField
#if !CEED_VERSION_GE(0,10,0)
#error MFEM requires a libCEED version >= 0.10.0
#endif
#endif
#include "../../../config/config.hpp"
#include <tuple>
#include <unordered_map>
#include <string>
#include "ceed.hpp"
#ifdef MFEM_USE_CEED
#include <ceed/hash.h>
#include <ceed/backend.h> // for CeedOperatorField
#endif
namespace mfem
{
class FiniteElement;
class FiniteElementSpace;
class ElementTransformation;
class IntegrationRule;
class Vector;
@@ -58,31 +57,51 @@ void RemoveBasisAndRestriction(const mfem::FiniteElementSpace *fes);
/// Initialize a CeedVector from an mfem::Vector
void InitVector(const mfem::Vector &v, CeedVector &cv);
/// @brief Initialize a strided CeedElemRestriction
/** @a nelem is the number of elements,
@a nqpts is the total number of quadrature points
@a qdatasize is the number of data per quadrature point
@a strides Array for strides between [nodes, components, elements].
Data for node i, component j, element k can be found in the L-vector at
index i*strides[0] + j*strides[1] + k*strides[2]. CEED_STRIDES_BACKEND may
be used with vectors created by a Ceed backend. */
void InitStridedRestriction(const mfem::FiniteElementSpace &fes,
CeedInt nelem, CeedInt nqpts, CeedInt qdatasize,
const CeedInt *strides,
CeedElemRestriction *restr);
/** @brief Initialize a CeedBasis and a CeedElemRestriction based on an
mfem::FiniteElementSpace @a fes, and an mfem::IntegrationRule @a ir.
/** Initialize a CeedBasis and a CeedElemRestriction based on an
mfem::FiniteElementSpace @a fes, and an mfem::IntegrationRule @a ir. */
@param[in] fes The finite element space.
@param[in] ir The integration rule.
@param[in] ceed The Ceed object.
@param[out] basis The `CeedBasis` to initialize.
@param[out] restr The `CeedElemRestriction` to initialize.
@warning Only for non-mixed finite element spaces. */
void InitBasisAndRestriction(const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
Ceed ceed, CeedBasis *basis,
CeedElemRestriction *restr);
void InitTensorRestriction(const FiniteElementSpace &fes,
Ceed ceed, CeedElemRestriction *restr);
/** @brief Initialize a CeedBasis and a CeedElemRestriction based on an
mfem::FiniteElementSpace @a fes, and an mfem::IntegrationRule @a ir,
and a list of @a nelem elements of indices @a indices.
@param[in] fes The finite element space.
@param[in] ir The integration rule.
@param[in] nelem The number of elements.
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`. If `indices == nullptr`, assumes
that the `FiniteElementSpace` is not mixed.
@param[in] ceed The Ceed object.
@param[out] basis The `CeedBasis` to initialize.
@param[out] restr The `CeedElemRestriction` to initialize. */
void InitBasisAndRestriction(const FiniteElementSpace &fes,
const IntegrationRule &ir,
int nelem,
const int* indices,
Ceed ceed, CeedBasis *basis,
CeedElemRestriction *restr);
int CeedOperatorGetActiveField(CeedOperator oper, CeedOperatorField *field);
template <typename Integrator>
const IntegrationRule & GetRule(
const Integrator &integ,
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans);
/// Return the path to the libCEED q-function headers.
const std::string &GetCeedPath();
@@ -106,7 +125,7 @@ struct BasisHash
};
using BasisMap = std::unordered_map<const BasisKey, CeedBasis, BasisHash>;
enum restr_type {Standard, Strided};
enum restr_type {Standard, Strided, Coeff};
// Hash table for CeedElemRestriction
using RestrKey =
@@ -134,12 +153,15 @@ using RestrMap =
namespace internal
{
#ifdef MFEM_USE_CEED
extern Ceed ceed;
/** @warning These maps have a tendency to create bugs when adding new "types"
of CeedBasis and CeedElemRestriction. */
extern ceed::BasisMap ceed_basis_map;
extern ceed::RestrMap ceed_restr_map;
#endif
}
} // namespace internal
} // namespace mfem
@@ -11,12 +11,14 @@
#include "algebraic.hpp"
#include "../bilinearform.hpp"
#include "../fespace.hpp"
#include "../ceed/solvers-atpmg.hpp"
#include "../ceed/full-assembly.hpp"
#include "../pfespace.hpp"
#include "../../general/forall.hpp"
#include "../../bilinearform.hpp"
#include "../../fespace.hpp"
#include "../../pfespace.hpp"
#include "../../../general/forall.hpp"
#include "solvers-atpmg.hpp"
#include "full-assembly.hpp"
#include "../interface/restriction.hpp"
#include "../interface/ceed.hpp"
namespace mfem
{
@@ -631,7 +633,7 @@ AlgebraicSpaceHierarchy::AlgebraicSpaceHierarchy(FiniteElementSpace &fes)
current_order = order;
Ceed ceed = internal::ceed;
InitTensorRestriction(fes, ceed, &fine_er);
InitRestriction(fes, ceed, &fine_er);
CeedElemRestriction er = fine_er;
int dim = fes.GetMesh()->Dimension();
@@ -12,12 +12,10 @@
#ifndef MFEM_CEED_ALGEBRAIC_HPP
#define MFEM_CEED_ALGEBRAIC_HPP
#include "../../config/config.hpp"
#include "../fespacehierarchy.hpp"
#include "../multigrid.hpp"
#include "util.hpp"
#include "operator.hpp"
#include "../../fespacehierarchy.hpp"
#include "../../multigrid.hpp"
#include "../interface/operator.hpp"
#include "../interface/ceed.hpp"
namespace mfem
{
@@ -136,7 +134,6 @@ public:
}
~AlgebraicSpaceHierarchy()
{
CeedElemRestrictionDestroy(&fine_er);
for (int i=0; i<R_tr.Size(); ++i)
{
delete R_tr[i];
@@ -11,8 +11,11 @@
#include "full-assembly.hpp"
#include "../../../linalg/sparsemat.hpp"
#include "../interface/util.hpp"
#include "../interface/ceed.hpp"
#ifdef MFEM_USE_CEED
#include "util.hpp"
namespace mfem
{
@@ -12,11 +12,9 @@
#ifndef MFEM_CEED_ASSEMBLE_HPP
#define MFEM_CEED_ASSEMBLE_HPP
#include "../../config/config.hpp"
#include "../interface/ceed.hpp"
#ifdef MFEM_USE_CEED
#include <ceed.h>
#include "../../linalg/sparsemat.hpp"
namespace mfem
{
@@ -10,7 +10,9 @@
// CONTRIBUTING.md for details.
#include "solvers-atpmg.hpp"
#include "util.hpp"
#include "../interface/ceed.hpp"
#include "../interface/util.hpp"
#ifdef MFEM_USE_CEED
#include <ceed/backend.h>
@@ -12,12 +12,10 @@
#ifndef MFEM_CEEDSOLVERS_ATPMG_H
#define MFEM_CEEDSOLVERS_ATPMG_H
#include "../../config/config.hpp"
#include "../interface/ceed.hpp"
#ifdef MFEM_USE_CEED
#include <ceed.h>
namespace mfem
{
-415
View File
@@ -1,415 +0,0 @@
// Copyright (c) 2010-2022, 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 "util.hpp"
#include "../../general/device.hpp"
#include "../../fem/gridfunc.hpp"
#include "../../linalg/dtensor.hpp"
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
typedef struct stat struct_stat;
#else
#define stat(dir, buf) _stat(dir, buf)
#define S_ISDIR(mode) _S_IFDIR(mode)
typedef struct _stat struct_stat;
#endif
namespace mfem
{
bool DeviceCanUseCeed()
{
return Device::Allows(Backend::CEED_MASK);
}
namespace ceed
{
void RemoveBasisAndRestriction(const mfem::FiniteElementSpace *fes)
{
#ifdef MFEM_USE_CEED
auto itb = mfem::internal::ceed_basis_map.begin();
while (itb != mfem::internal::ceed_basis_map.end())
{
if (std::get<0>(itb->first)==fes)
{
CeedBasisDestroy(&itb->second);
itb = mfem::internal::ceed_basis_map.erase(itb);
}
else
{
itb++;
}
}
auto itr = mfem::internal::ceed_restr_map.begin();
while (itr != mfem::internal::ceed_restr_map.end())
{
if (std::get<0>(itr->first)==fes)
{
CeedElemRestrictionDestroy(&itr->second);
itr = mfem::internal::ceed_restr_map.erase(itr);
}
else
{
itr++;
}
}
#endif
}
#ifdef MFEM_USE_CEED
void InitVector(const mfem::Vector &v, CeedVector &cv)
{
CeedVectorCreate(mfem::internal::ceed, v.Size(), &cv);
CeedScalar *cv_ptr;
CeedMemType mem;
CeedGetPreferredMemType(mfem::internal::ceed, &mem);
if ( Device::Allows(Backend::DEVICE_MASK) && mem==CEED_MEM_DEVICE )
{
cv_ptr = const_cast<CeedScalar*>(v.Read());
}
else
{
cv_ptr = const_cast<CeedScalar*>(v.HostRead());
mem = CEED_MEM_HOST;
}
CeedVectorSetArray(cv, mem, CEED_USE_POINTER, cv_ptr);
}
static CeedElemTopology GetCeedTopology(Geometry::Type geom)
{
switch (geom)
{
case Geometry::SEGMENT:
return CEED_TOPOLOGY_LINE;
case Geometry::TRIANGLE:
return CEED_TOPOLOGY_TRIANGLE;
case Geometry::SQUARE:
return CEED_TOPOLOGY_QUAD;
case Geometry::TETRAHEDRON:
return CEED_TOPOLOGY_TET;
case Geometry::CUBE:
return CEED_TOPOLOGY_HEX;
case Geometry::PRISM:
return CEED_TOPOLOGY_PRISM;
default:
MFEM_ABORT("This type of element is not supported");
return CEED_TOPOLOGY_PRISM; // Silence warning
}
}
static void InitNonTensorBasis(const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
Ceed ceed, CeedBasis *basis)
{
const mfem::DofToQuad &maps = fes.GetFE(0)->
GetDofToQuad(ir,mfem::DofToQuad::FULL);
mfem::Mesh *mesh = fes.GetMesh();
const int dim = mesh->Dimension();
const int ndofs = maps.ndof;
const int nqpts = maps.nqpt;
mfem::DenseMatrix qX(dim,nqpts);
mfem::Vector qW(nqpts);
for (int i = 0; i < nqpts; i++)
{
const mfem::IntegrationPoint &ip = ir.IntPoint(i);
qX(0,i) = ip.x;
if (dim>1) { qX(1,i) = ip.y; }
if (dim>2) { qX(2,i) = ip.z; }
qW(i) = ip.weight;
}
CeedBasisCreateH1(ceed, GetCeedTopology(fes.GetFE(0)->GetGeomType()),
fes.GetVDim(), ndofs, nqpts,
maps.Bt.GetData(), maps.Gt.GetData(),
qX.GetData(), qW.GetData(), basis);
}
static void InitNonTensorRestriction(const mfem::FiniteElementSpace &fes,
Ceed ceed, CeedElemRestriction *restr)
{
mfem::Mesh *mesh = fes.GetMesh();
const mfem::FiniteElement *fe = fes.GetFE(0);
const int P = fe->GetDof();
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
const mfem::Table &el_dof = fes.GetElementToDofTable();
mfem::Array<int> tp_el_dof(el_dof.Size_of_connections());
const mfem::TensorBasisElement * tfe =
dynamic_cast<const mfem::TensorBasisElement *>(fe);
const int stride = compstride == 1 ? fes.GetVDim() : 1;
if (tfe) // Lexicographic ordering using dof_map
{
const mfem::Array<int>& dof_map = tfe->GetDofMap();
for (int i = 0; i < mesh->GetNE(); i++)
{
const int el_offset = P * i;
for (int j = 0; j < P; j++)
{
tp_el_dof[j+el_offset] = stride*el_dof.GetJ()[dof_map[j]+el_offset];
}
}
}
else // Native ordering
{
for (int e = 0; e < mesh->GetNE(); e++)
{
for (int i = 0; i < P; i++)
{
tp_el_dof[i + e*P] = stride*el_dof.GetJ()[i + e*P];
}
}
}
CeedElemRestrictionCreate(ceed, mesh->GetNE(), P, fes.GetVDim(),
compstride, (fes.GetVDim())*(fes.GetNDofs()),
CEED_MEM_HOST, CEED_COPY_VALUES,
tp_el_dof.GetData(), restr);
}
static void InitTensorBasis(const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
Ceed ceed, CeedBasis *basis)
{
const mfem::DofToQuad &maps =
fes.GetFE(0)->GetDofToQuad(ir, mfem::DofToQuad::TENSOR);
mfem::Mesh *mesh = fes.GetMesh();
const int ndofs = maps.ndof;
const int nqpts = maps.nqpt;
mfem::Vector qX(nqpts), qW(nqpts);
// The x-coordinates of the first `nqpts` points of the integration rule are
// the points of the corresponding 1D rule. We also scale the weights
// accordingly.
double w_sum = 0.0;
for (int i = 0; i < nqpts; i++)
{
const mfem::IntegrationPoint &ip = ir.IntPoint(i);
qX(i) = ip.x;
qW(i) = ip.weight;
w_sum += ip.weight;
}
qW *= 1.0/w_sum;
CeedBasisCreateTensorH1(ceed, mesh->Dimension(), fes.GetVDim(), ndofs,
nqpts, maps.Bt.GetData(),
maps.Gt.GetData(), qX.GetData(),
qW.GetData(), basis);
}
void InitTensorRestriction(const mfem::FiniteElementSpace &fes,
Ceed ceed, CeedElemRestriction *restr)
{
mfem::Mesh *mesh = fes.GetMesh();
const mfem::FiniteElement *fe = fes.GetFE(0);
const mfem::TensorBasisElement * tfe =
dynamic_cast<const mfem::TensorBasisElement *>(fe);
MFEM_VERIFY(tfe, "invalid FE");
const mfem::Array<int>& dof_map = tfe->GetDofMap();
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
const mfem::Table &el_dof = fes.GetElementToDofTable();
mfem::Array<int> tp_el_dof(el_dof.Size_of_connections());
const int dof = fe->GetDof();
const int stride = compstride == 1 ? fes.GetVDim() : 1;
if (dof_map.Size()>0)
{
for (int i = 0; i < mesh->GetNE(); i++)
{
const int el_offset = dof * i;
for (int j = 0; j < dof; j++)
{
tp_el_dof[j+el_offset] = stride*el_dof.GetJ()[dof_map[j]+el_offset];
}
}
}
else // dof_map.Size == 0, means dof_map[j]==j;
{
for (int i = 0; i < mesh->GetNE(); i++)
{
const int el_offset = dof * i;
for (int j = 0; j < dof; j++)
{
tp_el_dof[j+el_offset] = stride*el_dof.GetJ()[j+el_offset];
}
}
}
CeedElemRestrictionCreate(ceed, mesh->GetNE(), dof, fes.GetVDim(),
compstride, (fes.GetVDim())*(fes.GetNDofs()),
CEED_MEM_HOST, CEED_COPY_VALUES,
tp_el_dof.GetData(), restr);
}
void InitStridedRestriction(const mfem::FiniteElementSpace &fes,
CeedInt nelem, CeedInt nqpts, CeedInt qdatasize,
const CeedInt *strides,
CeedElemRestriction *restr)
{
RestrKey restr_key(&fes, nelem, nqpts, qdatasize, restr_type::Strided);
auto restr_itr = mfem::internal::ceed_restr_map.find(restr_key);
if (restr_itr == mfem::internal::ceed_restr_map.end())
{
CeedElemRestrictionCreateStrided(mfem::internal::ceed, nelem, nqpts, qdatasize,
nelem*nqpts*qdatasize,
strides,
restr);
// Will be automatically destroyed when @a fes gets destroyed.
mfem::internal::ceed_restr_map[restr_key] = *restr;
}
else
{
*restr = restr_itr->second;
}
}
void InitBasisAndRestriction(const FiniteElementSpace &fes,
const IntegrationRule &irm,
Ceed ceed, CeedBasis *basis,
CeedElemRestriction *restr)
{
// Check for FES -> basis, restriction in hash tables
const mfem::Mesh *mesh = fes.GetMesh();
const mfem::FiniteElement *fe = fes.GetFE(0);
const int P = fe->GetDof();
const int Q = irm.GetNPoints();
const int nelem = mesh->GetNE();
const int ncomp = fes.GetVDim();
BasisKey basis_key(&fes, &irm, ncomp, P, Q);
auto basis_itr = mfem::internal::ceed_basis_map.find(basis_key);
RestrKey restr_key(&fes, nelem, P, ncomp, restr_type::Standard);
auto restr_itr = mfem::internal::ceed_restr_map.find(restr_key);
// Init or retreive key values
if (basis_itr == mfem::internal::ceed_basis_map.end())
{
if (UsesTensorBasis(fes))
{
InitTensorBasis(fes, irm, ceed, basis);
}
else
{
InitNonTensorBasis(fes, irm, ceed, basis);
}
mfem::internal::ceed_basis_map[basis_key] = *basis;
}
else
{
*basis = basis_itr->second;
}
if (restr_itr == mfem::internal::ceed_restr_map.end())
{
if (UsesTensorBasis(fes))
{
InitTensorRestriction(fes, ceed, restr);
}
else
{
InitNonTensorRestriction(fes, ceed, restr);
}
mfem::internal::ceed_restr_map[restr_key] = *restr;
}
else
{
*restr = restr_itr->second;
}
}
// Assumes a tensor-product operator with one active field
int CeedOperatorGetActiveField(CeedOperator oper, CeedOperatorField *field)
{
int ierr;
Ceed ceed;
ierr = CeedOperatorGetCeed(oper, &ceed); CeedChk(ierr);
CeedQFunction qf;
bool isComposite;
ierr = CeedOperatorIsComposite(oper, &isComposite); CeedChk(ierr);
CeedOperator *subops;
if (isComposite)
{
ierr = CeedOperatorGetSubList(oper, &subops); CeedChk(ierr);
ierr = CeedOperatorGetQFunction(subops[0], &qf); CeedChk(ierr);
}
else
{
ierr = CeedOperatorGetQFunction(oper, &qf); CeedChk(ierr);
}
CeedInt numinputfields, numoutputfields;
ierr = CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
CeedOperatorField *inputfields;
if (isComposite)
{
ierr = CeedOperatorGetFields(subops[0], &numinputfields, &inputfields,
&numoutputfields, NULL); CeedChk(ierr);
}
else
{
ierr = CeedOperatorGetFields(oper, &numinputfields, &inputfields,
&numoutputfields, NULL); CeedChk(ierr);
}
CeedVector if_vector;
bool found = false;
int found_index = -1;
for (int i = 0; i < numinputfields; ++i)
{
ierr = CeedOperatorFieldGetVector(inputfields[i], &if_vector); CeedChk(ierr);
if (if_vector == CEED_VECTOR_ACTIVE)
{
if (found)
{
return CeedError(ceed, 1, "Multiple active vectors in CeedOperator!");
}
found = true;
found_index = i;
}
}
if (!found)
{
return CeedError(ceed, 1, "No active vector in CeedOperator!");
}
*field = inputfields[found_index];
return 0;
}
std::string ceed_path;
const std::string &GetCeedPath()
{
if (ceed_path.empty())
{
const char *install_dir = MFEM_INSTALL_DIR "/include/mfem/fem/ceed";
const char *source_dir = MFEM_SOURCE_DIR "/fem/ceed";
struct_stat m_stat;
if (stat(install_dir, &m_stat) == 0 && S_ISDIR(m_stat.st_mode))
{
ceed_path = install_dir;
}
else if (stat(source_dir, &m_stat) == 0 && S_ISDIR(m_stat.st_mode))
{
ceed_path = source_dir;
}
else
{
MFEM_ABORT("Cannot find libCEED kernels in MFEM_INSTALL_DIR or "
"MFEM_SOURCE_DIR");
}
// Could be useful for debugging:
// out << "Using libCEED dir: " << ceed_path << std::endl;
}
return ceed_path;
}
#endif
} // namespace ceed
} // namespace mfem
+2 -2
View File
@@ -1078,7 +1078,7 @@ void ParaViewDataCollection::SaveGFieldVTU(std::ostream &os, int ref_,
it->second->GetValues(i, RefG->RefPts, val, pmat);
for (int j = 0; j < val.Size(); j++)
{
WriteBinaryOrASCII(out, buf, val(j), "\n", pv_data_format);
WriteBinaryOrASCII(os, buf, val(j), "\n", pv_data_format);
}
}
}
@@ -1094,7 +1094,7 @@ void ParaViewDataCollection::SaveGFieldVTU(std::ostream &os, int ref_,
{
for (int ii = 0; ii < vval.Height(); ii++)
{
WriteBinaryOrASCII(out, buf, vval(ii,jj), " ", pv_data_format);
WriteBinaryOrASCII(os, buf, vval(ii,jj), " ", pv_data_format);
}
if (pv_data_format == VTKFormat::ASCII) { os << '\n'; }
}
+233 -1
View File
@@ -13,6 +13,7 @@
#include "fe_l2.hpp"
#include "fe_h1.hpp"
#include "../coefficient.hpp"
namespace mfem
{
@@ -38,6 +39,7 @@ L2_SegmentElement::L2_SegmentElement(const int p, const int btype)
void L2_SegmentElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
basis1d.ScaleIntegrated(map_type == VALUE);
basis1d.Eval(ip.x, shape);
}
@@ -49,6 +51,7 @@ void L2_SegmentElement::CalcDShape(const IntegrationPoint &ip,
#else
dshape_x.SetData(dshape.Data());
#endif
basis1d.ScaleIntegrated(map_type == VALUE);
basis1d.Eval(ip.x, shape_x, dshape_x);
}
@@ -104,6 +107,7 @@ void L2_QuadrilateralElement::CalcShape(const IntegrationPoint &ip,
Vector shape_x(p+1), shape_y(p+1);
#endif
basis1d.ScaleIntegrated(map_type == VALUE);
basis1d.Eval(ip.x, shape_x);
basis1d.Eval(ip.y, shape_y);
@@ -123,6 +127,7 @@ void L2_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1);
#endif
basis1d.ScaleIntegrated(map_type == VALUE);
basis1d.Eval(ip.x, shape_x, dshape_x);
basis1d.Eval(ip.y, shape_y, dshape_y);
@@ -182,6 +187,113 @@ void L2_QuadrilateralElement::ProjectDelta(int vertex, Vector &dofs) const
}
}
void L2_QuadrilateralElement::ProjectDiv(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &div) const
{
if (basis1d.IsIntegratedType())
{
// Compute subcell integrals of the divergence
const int fe_ndof = fe.GetDof();
Vector div_shape(fe_ndof);
div.SetSize(dof, fe_ndof);
div = 0.0;
const IntegrationRule &ir = IntRules.Get(geom_type, fe.GetOrder());
const double *gll_pts = poly1d.GetPoints(order+1, BasisType::GaussLobatto);
// Loop over subcells
for (int iy = 0; iy < order+1; ++iy)
{
const double hy = gll_pts[iy+1] - gll_pts[iy];
for (int ix = 0; ix < order+1; ++ix)
{
const int i = ix + iy*(order+1);
const double hx = gll_pts[ix+1] - gll_pts[ix];
// Loop over subcell quadrature points
for (int iq = 0; iq < ir.Size(); ++iq)
{
IntegrationPoint ip = ir[iq];
ip.x = gll_pts[ix] + hx*ip.x;
ip.y = gll_pts[iy] + hy*ip.y;
Trans.SetIntPoint(&ip);
fe.CalcDivShape(ip, div_shape);
double w = ip.weight;
if (map_type == VALUE)
{
const double detJ = Trans.Weight();
w /= detJ;
}
else if (map_type == INTEGRAL)
{
w *= hx*hy;
}
for (int j = 0; j < fe_ndof; j++)
{
const double div_j = div_shape(j);
div(i,j) += w*div_j;
}
}
}
}
// Filter small entries
for (int i = 0; i < dof; ++i)
{
for (int j = 0; j < fe_ndof; j++)
{
if (std::fabs(div(i,j)) < 1e-12) { div(i,j) = 0.0; }
}
}
}
else
{
// Fall back on standard nodal interpolation
NodalFiniteElement::ProjectDiv(fe, Trans, div);
}
}
void L2_QuadrilateralElement::Project(Coefficient &coeff,
ElementTransformation &Trans,
Vector &dofs) const
{
if (basis1d.IsIntegratedType())
{
const IntegrationRule &ir = IntRules.Get(geom_type, order);
const double *gll_pts = poly1d.GetPoints(order+1, BasisType::GaussLobatto);
dofs = 0.0;
// Loop over subcells
for (int iy = 0; iy < order+1; ++iy)
{
const double hy = gll_pts[iy+1] - gll_pts[iy];
for (int ix = 0; ix < order+1; ++ix)
{
const int i = ix + iy*(order+1);
const double hx = gll_pts[ix+1] - gll_pts[ix];
// Loop over subcell quadrature points
for (int iq = 0; iq < ir.Size(); ++iq)
{
IntegrationPoint ip = ir[iq];
ip.x = gll_pts[ix] + hx*ip.x;
ip.y = gll_pts[iy] + hy*ip.y;
Trans.SetIntPoint(&ip);
const double val = coeff.Eval(Trans, ip);
double w = ip.weight;
if (map_type == INTEGRAL)
{
w *= hx*hy*Trans.Weight();
}
dofs[i] += val*w;
}
}
}
}
else
{
NodalFiniteElement::Project(coeff, Trans, dofs);
}
}
L2_HexahedronElement::L2_HexahedronElement(const int p, const int btype)
: NodalTensorFiniteElement(3, p, VerifyOpen(btype), L2_DOF_MAP)
@@ -214,6 +326,7 @@ void L2_HexahedronElement::CalcShape(const IntegrationPoint &ip,
Vector shape_x(p+1), shape_y(p+1), shape_z(p+1);
#endif
basis1d.ScaleIntegrated(map_type == VALUE);
basis1d.Eval(ip.x, shape_x);
basis1d.Eval(ip.y, shape_y);
basis1d.Eval(ip.z, shape_z);
@@ -236,6 +349,7 @@ void L2_HexahedronElement::CalcDShape(const IntegrationPoint &ip,
Vector dshape_x(p+1), dshape_y(p+1), dshape_z(p+1);
#endif
basis1d.ScaleIntegrated(map_type == VALUE);
basis1d.Eval(ip.x, shape_x, dshape_x);
basis1d.Eval(ip.y, shape_y, dshape_y);
basis1d.Eval(ip.z, shape_z, dshape_z);
@@ -334,6 +448,124 @@ void L2_HexahedronElement::ProjectDelta(int vertex, Vector &dofs) const
}
}
void L2_HexahedronElement::ProjectDiv(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &div) const
{
if (basis1d.IsIntegratedType())
{
// Compute subcell integrals of the divergence
const int fe_ndof = fe.GetDof();
Vector div_shape(fe_ndof);
div.SetSize(dof, fe_ndof);
div = 0.0;
const IntegrationRule &ir = IntRules.Get(geom_type, fe.GetOrder());
const double *gll_pts = poly1d.GetPoints(order+1, BasisType::GaussLobatto);
// Loop over subcells
for (int iz = 0; iz < order+1; ++iz)
{
const double hz = gll_pts[iz+1] - gll_pts[iz];
for (int iy = 0; iy < order+1; ++iy)
{
const double hy = gll_pts[iy+1] - gll_pts[iy];
for (int ix = 0; ix < order+1; ++ix)
{
const int i = ix + iy*(order+1) + iz*(order+1)*(order+1);
const double hx = gll_pts[ix+1] - gll_pts[ix];
// Loop over subcell quadrature points
for (int iq = 0; iq < ir.Size(); ++iq)
{
IntegrationPoint ip = ir[iq];
ip.x = gll_pts[ix] + hx*ip.x;
ip.y = gll_pts[iy] + hy*ip.y;
ip.z = gll_pts[iz] + hz*ip.z;
Trans.SetIntPoint(&ip);
fe.CalcDivShape(ip, div_shape);
double w = ip.weight;
if (map_type == VALUE)
{
const double detJ = Trans.Weight();
w /= detJ;
}
else if (map_type == INTEGRAL)
{
w *= hx*hy*hz;
}
for (int j = 0; j < fe_ndof; j++)
{
const double div_j = div_shape(j);
div(i,j) += w*div_j;
}
}
}
}
}
// Filter small entries
for (int i = 0; i < dof; ++i)
{
for (int j = 0; j < fe_ndof; j++)
{
if (std::fabs(div(i,j)) < 1e-12) { div(i,j) = 0.0; }
}
}
}
else
{
// Fall back on standard nodal interpolation
NodalFiniteElement::ProjectDiv(fe, Trans, div);
}
}
void L2_HexahedronElement::Project(Coefficient &coeff,
ElementTransformation &Trans,
Vector &dofs) const
{
if (basis1d.IsIntegratedType())
{
const IntegrationRule &ir = IntRules.Get(geom_type, order);
const double *gll_pts = poly1d.GetPoints(order+1, BasisType::GaussLobatto);
dofs = 0.0;
// Loop over subcells
for (int iz = 0; iz < order+1; ++iz)
{
const double hz = gll_pts[iz+1] - gll_pts[iz];
for (int iy = 0; iy < order+1; ++iy)
{
const double hy = gll_pts[iy+1] - gll_pts[iy];
for (int ix = 0; ix < order+1; ++ix)
{
const double hx = gll_pts[ix+1] - gll_pts[ix];
const int i = ix + iy*(order+1) + iz*(order+1)*(order+1);
// Loop over subcell quadrature points
for (int iq = 0; iq < ir.Size(); ++iq)
{
IntegrationPoint ip = ir[iq];
ip.x = gll_pts[ix] + hx*ip.x;
ip.y = gll_pts[iy] + hy*ip.y;
ip.z = gll_pts[iz] + hz*ip.z;
Trans.SetIntPoint(&ip);
const double val = coeff.Eval(Trans, ip);
double w = ip.weight;
if (map_type == INTEGRAL)
{
const double detJ = Trans.Weight();
w *= detJ*hx*hy*hz;
}
dofs[i] += val*w;
}
}
}
}
}
else
{
NodalFiniteElement::Project(coeff, Trans, dofs);
}
}
L2_TriangleElement::L2_TriangleElement(const int p, const int btype)
: NodalFiniteElement(2, Geometry::TRIANGLE, ((p + 1)*(p + 2))/2, p,
@@ -464,7 +696,7 @@ L2_TetrahedronElement::L2_TetrahedronElement(const int p, const int btype)
: NodalFiniteElement(3, Geometry::TETRAHEDRON, ((p + 1)*(p + 2)*(p + 3))/6,
p, FunctionSpace::Pk)
{
const double *op = poly1d.OpenPoints(p, VerifyNodal(VerifyOpen(btype)));
const double *op = poly1d.OpenPoints(p, VerifyOpen(btype));
#ifndef MFEM_THREAD_SAFE
shape_x.SetSize(p + 1);
+12
View File
@@ -55,6 +55,12 @@ public:
ElementTransformation &Trans,
DenseMatrix &curl) const
{ ProjectCurl_2D(fe, Trans, curl); }
using FiniteElement::Project;
virtual void ProjectDiv(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &div) const;
virtual void Project(Coefficient &coeff,
ElementTransformation &Trans, Vector &dofs) const;
};
@@ -74,6 +80,12 @@ public:
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const;
using FiniteElement::Project;
virtual void ProjectDiv(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &div) const;
virtual void Project(Coefficient &coeff,
ElementTransformation &Trans, Vector &dofs) const;
};
+4
View File
@@ -322,6 +322,7 @@ void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
obasis1d.EvalIntegrated(dshape_cz, shape_oz);
@@ -409,6 +410,7 @@ void ND_HexahedronElement::CalcCurlShape(const IntegrationPoint &ip,
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
if (obasis1d.IsIntegratedType())
{
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
obasis1d.EvalIntegrated(dshape_cz, shape_oz);
@@ -661,6 +663,7 @@ void ND_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip,
{
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
}
@@ -721,6 +724,7 @@ void ND_QuadrilateralElement::CalcCurlShape(const IntegrationPoint &ip,
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
if (obasis1d.IsIntegratedType())
{
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
}
+4
View File
@@ -152,6 +152,7 @@ void RT_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip,
{
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
}
@@ -210,6 +211,7 @@ void RT_QuadrilateralElement::CalcDivShape(const IntegrationPoint &ip,
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
if (obasis1d.IsIntegratedType())
{
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
}
@@ -479,6 +481,7 @@ void RT_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
obasis1d.EvalIntegrated(dshape_cz, shape_oz);
@@ -566,6 +569,7 @@ void RT_HexahedronElement::CalcDivShape(const IntegrationPoint &ip,
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
if (obasis1d.IsIntegratedType())
{
obasis1d.ScaleIntegrated(false);
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
obasis1d.EvalIntegrated(dshape_cz, shape_oz);
+1 -1
View File
@@ -43,7 +43,7 @@
#include "transfer.hpp"
#include "fespacehierarchy.hpp"
#include "multigrid.hpp"
#include "ceed/algebraic.hpp"
#include "ceed/solvers/algebraic.hpp"
#include "lor/lor.hpp"
#ifdef MFEM_USE_MPI
+1 -1
View File
@@ -15,7 +15,7 @@
#include "../general/forall.hpp"
#include "../mesh/mesh_headers.hpp"
#include "fem.hpp"
#include "ceed/util.hpp"
#include "ceed/interface/util.hpp"
#include <cmath>
#include <cstdarg>
+5 -5
View File
@@ -980,14 +980,14 @@ public:
void Save(std::ostream &out) const;
};
/// @brief Return true if the mesh contains only one topology and the elements are tensor elements.
inline bool UsesTensorBasis(const FiniteElementSpace& fes)
{
// TODO: mixed meshes: return true if there is at least one tensor-product
// Geometry in the global mesh and the FE collection returns a
// TensorBasisElement for that Geometry?
Mesh & mesh = *fes.GetMesh();
const bool mixed = mesh.GetNumGeometries(mesh.Dimension()) > 1;
// Potential issue: empty local mesh --> no element 0.
return dynamic_cast<const mfem::TensorBasisElement *>(fes.GetFE(0))!=nullptr;
return !mixed &&
dynamic_cast<const mfem::TensorBasisElement *>(fes.GetFE(0))!=nullptr;
}
}
+2 -2
View File
@@ -4276,7 +4276,7 @@ void TensorProductLegendre(int dim, // input
poly1d.CalcLegendre(order, x3, poly_z);
}
int basis_dimension = pow(order+1,dim);
int basis_dimension = static_cast<int>(pow(order+1,dim));
poly.SetSize(basis_dimension);
switch (dim)
{
@@ -4458,7 +4458,7 @@ double LSZZErrorEstimator(BilinearFormIntegrator &blfi, // input
const int patch_order = max(ufes->GetElementOrder(el1),
ufes->GetElementOrder(el2));
int num_basis_functions = pow(patch_order+1,dim);
int num_basis_functions = static_cast<int>(pow(patch_order+1,dim));
int flux_order = 2*patch_order + 1;
DenseMatrix A(num_basis_functions);
Array<double> b(sdim * num_basis_functions);

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