Compare commits

..
Author SHA1 Message Date
Kenneth Weiss b86fb5308a style 2026-04-14 08:54:23 -07:00
Kenneth Weiss 4463d921f6 Updates CHANGELOG 2026-04-13 21:52:37 -07:00
Kenneth Weiss 20c657559d More fixes for building contact mini-app with make and cmake 2026-04-13 21:47:15 -07:00
Kenneth Weiss 7a999efb0d yAdds back FindAxom in support of contact mini-app 2026-04-13 18:54:17 -07:00
Kenneth Weiss 442ac18b65 Removes references to Axom in INSTALL 2026-04-13 12:40:24 -07:00
Kenneth Weiss 5097a44411 Removes Axom from make-based and cmake-based build systems 2026-04-13 12:37:18 -07:00
Kenneth Weiss e84fef4191 Removes SidreDataCollection from MFEM
This has been superseded by the MFEMSidreDataCollection in Axom.
2026-04-13 12:34:02 -07:00
Veselin Dobrev 64ef39bbe6 Merge pull request #5291 from lindsayad/fix-petsc-b-allocation
Don't attempt to allocate B if b is non-empty in PetscNonlinearSolver
2026-04-12 19:03:40 -07:00
Veselin Dobrev ec39b3509c Merge pull request #5292 from mfem/saveAsOneAttrs
Propagate named attribute sets in ParMesh::GetSerialMesh
2026-04-08 11:13:00 -07:00
Will Pazner 399d8e1e9b Merge pull request #5293 from mfem/ci-fix-brew-info
GitHub CI fix
2026-04-08 11:00:36 -07:00
Veselin Dobrev 10dbed9658 In GitHub CI, fix the parsing for the new formatting of 'brew info' 2026-04-07 17:23:31 -07:00
Will Pazner f09a062c04 Merge pull request #4800 from mfem/warn-gridfunc
Add VectorDim error checks for projecting coefficients onto a GridFunction
2026-04-07 11:13:31 -07:00
Alex Lindsay 0c97d6f375 Never allocate B 2026-04-06 20:21:41 -07:00
Veselin Dobrev aed9c8ef4a Merge pull request #5285 from mfem/uuid-fix
Fix signed char issue in Device::GetUUID
2026-04-06 15:52:32 -07:00
Veselin Dobrev e4e85e28ef Merge pull request #5289 from adam-sim-dev/fix_missing_parentheses
Fixed missing parenthesis in the comment
2026-04-06 15:43:19 -07:00
Veselin Dobrev fff973f192 Merge pull request #5246 from mfem/hughcars/simplex-quadrature-dev
Add positive-weight simplex quadrature rules for orders 0-20
2026-04-06 15:39:49 -07:00
Veselin Dobrev 775f06c43b Adjust seed values in sample runs in ex12p to ensure LOBPCG convergence in
older hypre versions.
2026-04-03 14:55:08 -07:00
schnmich 18ff1d8289 linting 2026-04-03 11:21:06 -06:00
schnmich 5a0962c674 add attributes to GetSerialMesh 2026-04-03 11:05:03 -06:00
Veselin Dobrev 0d999709e6 Merge pull request #4917 from Sbozzolo/master
Improve error message for gmsh versions != 2.2
2026-04-01 20:20:15 -07:00
Tzanio Kolev c2649eb998 Merge pull request #5245 from mfem/bugfix/chapman39/bilininteg-no-mod
bilininteg: eliminate usage of modulus to avoid llvm backend bug
2026-04-01 11:35:17 -07:00
Will Pazner a1ce49fb57 Merge pull request #5290 from mfem/ci-update-action-versions-2
Update the action `actions/cache/restore` to `v5`
2026-03-31 20:36:07 -07:00
Alex Lindsay f58cfc8170 Should not allocate B if b non-empty
Otherwise there will be an error in PlaceMemory
2026-03-31 20:25:34 -07:00
Alex Lindsay 6c837d2954 Add test of PetscNonlinearSolver with non-empty RHS 2026-03-31 20:24:22 -07:00
Veselin Dobrev 5b37c3b595 Update the action actions/cache/restore to v5 2026-03-31 16:45:21 -07:00
Will Pazner e49f9f7988 Merge pull request #5288 from mfem/ci-update-action-versions
Update some GitHub actions to new versions
2026-03-31 11:03:48 -07:00
adam-sim-dev 7c36b55628 Fixed missing parenthesis in the comment 2026-03-31 14:29:39 +08:00
Veselin Dobrev faa73ef554 Updated the github/codeql-action/* actions to the latest, v4 2026-03-30 11:50:40 -07:00
Veselin Dobrev ecb6b06aa0 Updated actions/checkout to the latest major version, v6 2026-03-30 11:44:41 -07:00
Veselin Dobrev af4649a088 Update actions/{checkout,cache} to v5
Update github/codeql-action/* to v3
2026-03-30 10:30:31 -07:00
Andrew Ho a9f58f3982 check for null 2026-03-30 09:31:37 -07:00
Andrew Ho 6de6675783 fix compiler complaints 2026-03-30 09:04:18 -07:00
Andrew Ho 085ee02a29 compile error 2026-03-30 08:56:18 -07:00
Andrew Ho 9a124335a7 redundant checks 2026-03-30 08:53:36 -07:00
Andrew Ho 91d5e490aa Merge branch 'master' into warn-gridfunc 2026-03-30 08:53:08 -07:00
Tzanio Kolev dd931b2584 Merge pull request #5219 from mfem/najlkin/project-bdr-coeff-rtnd
Projection of  scalar coefficients on RT grid functions
2026-03-29 12:53:11 -07:00
Tzanio Kolev 8a42ea2834 Merge pull request #5198 from mfem/najlkin/fix-ex22p-glvis
[BUG] Fixed visualization in example 22
2026-03-29 12:52:42 -07:00
Tzanio Kolev 24e5d5fc0a Merge pull request #4781 from mfem/najlkin/extrd-1d-vec
Extrusion of vector 1D grid functions
2026-03-29 12:51:54 -07:00
Tzanio Kolev 6722dd7a70 Merge pull request #5276 from mfem/bugfix/arrays-by-name-load
Adding bugfix and unit test which would have caught the bug
2026-03-29 12:51:15 -07:00
Tzanio Kolev cb862cbfa1 Merge pull request #5252 from mfem/assemble-face-integrator-fix
Added VDOFs transformation for boundary integration
2026-03-29 12:50:40 -07:00
Will Pazner f7445844ba Fix signed char issue in Device::GetUUID 2026-03-26 15:23:21 -07:00
Hugh Carson 672e2a442b Address PR feedback
- Use [IntegrationRules] test tag instead of [PositiveWeightRules]
- Remove redundant case 21: (default branch handles it via the overwrite guard)
- Remove trailing blank line
2026-03-26 12:18:59 -04:00
Veselin Dobrev 416536eb9d Merge pull request #4941 from mfem/globalvec_debug
GlobalVector bug fix
2026-03-24 12:04:48 -07:00
Andrew Ho f557e348da removed comments 2026-03-23 14:02:52 -07:00
Andrew Ho 881598e5da also ensure boundary element is a scalar range type 2026-03-23 13:29:46 -07:00
Andrew Ho 564b7ab4ec fixed error message 2026-03-23 13:12:53 -07:00
Andrew HoandJan Nikl 3f2f925400 Update fem/gridfunc.cpp
Co-authored-by: Jan Nikl <nikl1@llnl.gov>
2026-03-23 13:09:37 -07:00
Jan Nikl 463e34dc7f Fixed spelling of transverse. 2026-03-23 10:33:51 -07:00
Tzanio Kolev 55e42eeefe Merge pull request #5238 from mfem/face-nbr-restr-vdim-bugfix
Fix bug in ParL2FaceRestriction with vdim > 1
2026-03-22 10:24:53 -07:00
Stowell, Mark L. 9a456b908e Adding bugfix and unit test which would have caught the bug 2026-03-18 15:50:59 -07:00
Andrew HoandJan Nikl 616839388a Update tests/unit/fem/test_var_order.cpp
Co-authored-by: Jan Nikl <nikl1@llnl.gov>
2026-03-17 14:14:17 -07:00
Andrew HoandJan Nikl 2fda3db982 Update tests/unit/fem/test_var_order.cpp
Co-authored-by: Jan Nikl <nikl1@llnl.gov>
2026-03-17 14:13:57 -07:00
Andrew Ho 4823a33a6a fixed not checking the correct rangedim 2026-03-17 12:17:13 -07:00
Veselin Dobrev a96319e0be Small change in error message + formatting. 2026-03-17 12:16:46 -07:00
Andrew Ho 5f4283f512 fixed comment; vector coefficient is still spacedims 2026-03-17 11:37:02 -07:00
Andrew Ho 8735d28561 fixed GetPhysRangeDim and GetPhysCurlDim not being virtual 2026-03-17 11:33:55 -07:00
Andrew Ho a10c7a943b Merge branch 'master' into warn-gridfunc 2026-03-13 09:47:50 -07:00
Tzanio Kolev fa89c5e98c Merge pull request #4856 from mfem/phys-range-dim
Range and curl dimension in physical space
2026-03-13 07:44:40 -07:00
Tzanio Kolev 0980bda63b Merge pull request #5215 from balay/barry/update-for-petsc-v3.25-PetscCtx
Update to change in PETSc API (in v3.25) for PetscCtx and PetscCtxRt
2026-03-13 07:44:06 -07:00
Will Pazner a1758e51e5 Merge remote-tracking branch 'origin/master' into face-nbr-restr-vdim-bugfix 2026-03-12 18:02:19 -07:00
Will Pazner ccf84aab7c Use constexpr in unit test 2026-03-12 18:01:40 -07:00
Hugh Carson 96eff4684f Remove unused private helper methods from IntegrationRule
AddTriPoints3R, AddTetPoints4b, and AddTetPoints12bc are no longer
called after the legacy simplex rules were removed.
2026-03-11 16:58:36 -04:00
Hugh Carson b6255fc825 Use exact fractions for trivial quadrature weights and coordinates
For rules where the mathematical value is an exact simple fraction
(midpoint weights, equal-weight symmetric rules), use the fraction
directly rather than the Polyquad decimal expansion. Cleaner to read
and avoids any rounding from decimal-to-double conversion.
2026-03-11 16:55:28 -04:00
Hugh Carson 18d27f6ffb Restore original function order in intrules.cpp
Move TriangleIntegrationRule before SquareIntegrationRule to match
the original file layout, reducing diff noise against master.
2026-03-11 16:38:01 -04:00
Hugh Carson 7bfb57ef17 Remove legacy simplex rules; positive-weight rules are now the default
The positive-weight rules now cover the full tabulated range for both
triangles (0-25) and tetrahedra (0-20), so the old rules with negative
weights are no longer needed. Remove the SimplexQuadrature enum,
simplex_type member, and legacy rule functions — all simplex quadrature
now uses positive-weight rules by default, with Grundmann-Moller
fallback for higher orders.
2026-03-11 15:25:29 -04:00
Hugh Carson ab394d795e Add existing order 21-25 triangle rule to positive-weight rules
The 126-point degree-25 rule already has all positive weights.
Copy it into TrianglePositiveIntegrationRule so the positive-weight
path covers orders 0-25.
2026-03-11 15:25:25 -04:00
Will Pazner 82abd48bba Merge pull request #5080 from mfem/cmake-config
CMake config.mk for CUDA and HIP
2026-03-11 12:18:25 -04:00
Andrew Ho cad9cc4c82 fixed checks 2026-03-10 20:56:14 -07:00
Andrew Ho 4dc741ca48 fix merge with master
still need to update bdr project coefficient checks
2026-03-10 17:11:17 -07:00
Andrew Ho 918eb114d3 Merge branch 'phys-range-dim' into warn-gridfunc 2026-03-10 16:42:15 -07:00
chapman39 3341acf0f7 add comments showing each modulus replacement 2026-03-10 15:10:51 -07:00
Tucker Hartland 287cb24d0a Merge branch 'master' into globalvec_debug 2026-03-10 11:35:19 -07:00
Andrew Ho 70370b6241 Merge branch 'master' into warn-gridfunc 2026-03-10 11:21:36 -07:00
Tzanio Kolev d4374a9d5f Merge branch 'master' into cmake-config 2026-03-10 11:08:23 -07:00
Tzanio Kolev dcd3a25730 Merge branch 'master' into barry/update-for-petsc-v3.25-PetscCtx 2026-03-10 11:01:46 -07:00
Wouter Tonnon ea291fb157 Merge branch 'master' into assemble-face-integrator-fix 2026-03-10 11:02:32 +01:00
Wouter Tonnon fce4ae7bb0 extended to MixedBilinearForm 2026-03-10 11:00:51 +01:00
Alex Tyler Chapman ef44f047aa Merge branch 'master' into bugfix/chapman39/bilininteg-no-mod 2026-03-09 16:41:43 -07:00
chapman39 ae002f7369 added comment 2026-03-09 14:36:47 -07:00
Jan Nikl e4cd3f9e18 Merge branch 'master' into najlkin/project-bdr-coeff-rtnd 2026-03-05 14:48:38 -08:00
Andrew Ho 0f99528c62 Merge branch 'master' into phys-range-dim 2026-03-05 12:45:42 -08:00
Veselin Dobrev ddfd74e899 Merge pull request #5255 from mfem/catch-tests
fix clang compiler warning for __COUNTER__
2026-03-05 12:39:29 -08:00
Mark L. Stowell 0248720eeb Merge branch 'master' into phys-range-dim 2026-03-05 09:35:14 -08:00
Andrew Ho feded39641 Merge branch 'master' into catch-tests 2026-03-05 09:28:31 -08:00
Tzanio Kolev 09128b9a5d Merge pull request #5240 from mfem/bugfix/chapan39/use-mfem-abort-kernel-in-device
dfem integrate: use mfem abort kernel in device code
2026-03-04 09:55:23 -08:00
Tzanio Kolev 68383b462b Merge pull request #5231 from mfem/plasma-dir-dev
Plasma Miniapp Directory
2026-03-04 09:54:48 -08:00
Tzanio Kolev 24d5609585 Merge pull request #5212 from mfem/najlkin/fix-cmplx-assign
[BUG] Complex grid function copy assignment
2026-03-04 09:54:25 -08:00
Jan Nikl abdcf82d70 Added scalar unit test of ProjectBdrCoefficientNormal(). 2026-03-03 12:59:53 -08:00
Jan Nikl ad93d526b7 Added a unit test for vector ProjectBdrCoefficientNormal(). 2026-03-03 12:05:57 -08:00
Andrew Ho 670a3f9a45 comment on why TPL_LIBRARIES is reversed twice 2026-03-03 11:43:02 -08:00
Jan Nikl 87c1a5cb77 Made the ProjectBdrCoefficientNormal check non-debug. 2026-03-03 11:26:25 -08:00
Andrew Ho 7baae02d65 Merge remote-tracking branch 'base/cmake-config' into cmake-config 2026-03-02 16:31:18 -08:00
Andrew Ho 728a0f313b move cudart to MFEM_EXT_LIBS 2026-03-02 16:30:31 -08:00
Andrew Ho 1bb624e2a8 fix clang compiler warning for __COUNTER__ 2026-03-02 14:05:28 -08:00
Tzanio Kolev ee7ccd6464 Merge branch 'master' into plasma-dir-dev 2026-03-02 11:56:51 -08:00
Stowell, Mark L. a3ae5a6f01 Changing copyright date to pass CI checks 2026-03-02 09:22:29 -08:00
Tzanio Kolev 5ce6e90ceb Merge pull request #5253 from mfem/bugfix-nurbs-orientation
NURBS orientation bug fix
2026-03-01 11:46:34 -08:00
Tzanio Kolev 03ba184adb Merge pull request #4882 from mfem/debug-mem-silent
Add option to run debug memory backend without issuing errors
2026-03-01 11:46:15 -08:00
Tzanio Kolev cfa87477da Merge pull request #5248 from lindsayad/dont-do-math-with-enums
Don't do arithmetic with enums
2026-03-01 11:45:47 -08:00
Andrew HoandNuno Nobre 9243d00549 Update config/cmake/modules/MfemCmakeUtilities.cmake
Co-authored-by: Nuno Nobre <nuno.nobre@stfc.ac.uk>
2026-02-28 14:53:22 -08:00
Andrew HoandNuno Nobre 4fe3db5a5f Update config/cmake/modules/MfemCmakeUtilities.cmake
Co-authored-by: Nuno Nobre <nuno.nobre@stfc.ac.uk>
2026-02-28 14:53:15 -08:00
Andrew Ho 55bb710cba fixed wrong dir being marked as system 2026-02-27 14:02:24 -08:00
dylan-copeland 939932bc68 Merge branch 'master' of github.com:mfem/mfem into bugfix-nurbs-orientation 2026-02-27 13:59:37 -08:00
Tzanio Kolev d3ae34710c Merge pull request #5195 from mfem/flip-index
Index sign functions
2026-02-27 13:32:22 -08:00
Dylan Copeland 9b652996b2 Remove an unnecessary assertion. 2026-02-27 11:48:01 -08:00
Dylan Copeland 5cfbbe5fad Bug fix for NURBS orientation, when the same knotvector index is used on all edges of some patches. 2026-02-27 11:24:36 -08:00
Andrew HoandNuno Nobre 7ad6939454 Update config/cmake/modules/MfemCmakeUtilities.cmake
Co-authored-by: Nuno Nobre <nuno.nobre@stfc.ac.uk>
2026-02-27 07:06:16 -08:00
Wouter Tonnon 89ad250940 Merge branch 'master' into assemble-face-integrator-fix 2026-02-27 14:44:45 +01:00
60cc94e5a1 Update to use PetscCtxRt from (3,25,0), and cleanup duplicate code
Co-authored-by: Nuno Nobre <nuno.nobre@stfc.ac.uk>
Co-authored-by: Satish Balay <balay@mcs.anl.gov>
2026-02-26 11:57:27 -06:00
Satish Balay 9122ac1839 update KSPMonitorFn usage for < (3,24,0) 2026-02-26 11:57:22 -06:00
Satish Balay 864186117d update PetscCtxDestroyFn usage for < (3,23,0) 2026-02-26 11:56:15 -06:00
Ketan Mittal 35de169fd0 Merge branch 'master' into plasma-dir-dev 2026-02-26 09:42:51 -08:00
Tzanio Kolev 71909cd5e3 Merge pull request #5203 from mfem/bugfix/unit-test-cout
Changing std::cout to mfem::out in unit test
2026-02-26 05:50:05 -08:00
Alex Lindsay a5a3169064 Don't do arithmetic with enums
Else with gcc 13.3 with `-std=c++20` I get warnings
2026-02-25 13:35:10 -07:00
Hugh Carson d5dec97d23 Fix memory leak 2026-02-25 11:46:21 -05:00
Hugh Carson 2d401bcb74 Add positive-weight simplex quadrature rules for orders 0-20
Triangle rules from Witherden & Vincent (2015), tet rules d=0-13
from Witherden & Vincent, tet rules d=14-20 from Chuluunbaatar et al.
(2022). All rules have strictly positive weights and interior points,
replacing the legacy rules which use negative weights at several
orders and fall back to Grundmann-Moller (negative weights, high
point counts) for tets at d>=9.
2026-02-24 20:21:49 -05:00
Andrew Ho 0a3184ab31 MFEM_EXPORT_GPU_CONFIG should export CPU config.mk when set to off 2026-02-24 11:56:38 -08:00
Wouter Tonnon 4f383f4b19 added missing face orientation 2026-02-24 20:27:14 +01:00
Dylan Copeland afded067a7 Replace absdof. 2026-02-24 11:17:54 -08:00
Mark L. Stowell a438e09caf Merge branch 'master' into plasma-dir-dev 2026-02-24 11:02:04 -08:00
chapman39 7f35ecb8f5 eliminate usage of modulus to avoid llvm backend bug 2026-02-24 10:50:52 -08:00
Alex Tyler Chapman ea03a86df2 Merge branch 'master' into bugfix/chapan39/use-mfem-abort-kernel-in-device 2026-02-24 10:32:30 -08:00
chapman39 6ef7a9e6fb 80 chars/ line 2026-02-24 10:32:18 -08:00
John Camier 629e93afd9 Merge branch 'master' into debug-mem-silent 2026-02-24 09:20:59 -08:00
Tzanio Kolev 3e277808a9 Merge pull request #5210 from mfem/hughcars/array-move-assignment-bugfix
Fix Array non-owning move assignment
2026-02-24 08:41:48 -08:00
Tzanio Kolev 864fb1ce9e Merge pull request #5217 from mfem/quadrature-function-fix
Fix a bug in `QuadratureFunction::GetValues` that returns a `DenseMatrix` view
2026-02-24 08:40:53 -08:00
Tzanio Kolev ac7415cc69 Merge branch 'master' into bugfix/unit-test-cout 2026-02-24 08:38:11 -08:00
Veselin Dobrev 38030d4395 Merge pull request #5222 from mfem/bugfix/chapman39/rm-return-from-omp
Remove return from openmp section
2026-02-24 08:18:53 -08:00
Alex Tyler Chapman 2c96dc6a1f Merge branch 'master' into bugfix/chapman39/rm-return-from-omp 2026-02-23 11:53:58 -08:00
Alex Tyler Chapman db7dd30d32 Merge branch 'master' into bugfix/chapan39/use-mfem-abort-kernel-in-device 2026-02-23 09:33:23 -08:00
John Camier ecbc7bf8c2 Merge branch 'master' into bugfix/unit-test-cout 2026-02-23 08:00:52 -08:00
John Camier 5b5a21edac Merge branch 'master' into debug-mem-silent 2026-02-22 12:28:39 -08:00
Tzanio Kolev 1f84ba036e Merge pull request #5179 from izaid/pfes
Fixed NULL pointer segfault in GetSurfaceFittingErrors
2026-02-21 12:52:33 -08:00
Tzanio Kolev 76d0312309 Merge branch 'master' into hughcars/array-move-assignment-bugfix 2026-02-21 12:52:11 -08:00
Tzanio Kolev c7ed339260 Merge pull request #5228 from mfem/mesh-3d-part-fix
Improve 3d mesh partitions
2026-02-21 12:43:49 -08:00
Tzanio Kolev f1b3a33fb2 Merge pull request #5234 from mfem/few-small-fixes
A few small fixes
2026-02-21 12:43:02 -08:00
chapman39 a1fe3a19b1 dfem integrate: use mfem abort kernel in device code 2026-02-19 17:45:11 -08:00
Satish Balay 213ccd7a4e rework PetscContainerSetCtxDestroy() usage for < (3,23,0) 2026-02-18 15:51:42 -06:00
Veselin Dobrev e3dedbbd5b Increase a relative tolerance due to failures on some machines 2026-02-18 10:27:44 -08:00
Will Pazner 8e78471fdf Add comment about the shape of FaceNbrData 2026-02-18 09:13:16 -08:00
Will Pazner c0f8501950 Add unit test for parallel L2 face restriction with vdim > 1 2026-02-18 09:13:03 -08:00
Will Pazner c31510289f Fix bug in ParL2FaceRestriction with vdim > 1
The layout of the FaceNbrData vector was not handled properly
2026-02-17 21:07:17 -08:00
John Camier 261f3805b8 Merge branch 'master' into debug-mem-silent 2026-02-17 10:59:40 -08:00
John Camier b386b2d6b6 Merge branch 'master' into bugfix/chapman39/rm-return-from-omp 2026-02-17 08:28:34 -08:00
Tzanio Kolev 6e98055eb7 Merge branch 'master' into quadrature-function-fix 2026-02-17 08:28:12 -08:00
Tzanio Kolev 2b14134496 Merge branch 'master' into najlkin/fix-cmplx-assign 2026-02-17 08:27:01 -08:00
Tzanio Kolev 5abd44f212 Merge pull request #5227 from mfem/add-constexpr
Add if constexpr to Kernel Specializations
2026-02-17 08:25:11 -08:00
Veselin Dobrev 75012728db Formatting: re-wrap comment to 80 chars/line. 2026-02-14 13:10:30 -08:00
Dylan Copeland 1f094244f8 Typo 2026-02-13 10:37:58 -08:00
Dylan Copeland cc16ddadbf Merge branch 'master' of github.com:mfem/mfem into flip-index 2026-02-13 10:35:32 -08:00
Veselin Dobrev 8acd5cd3a2 Fix a size bug in thread-safe mode in H1_TriangleElement::CalcHessian.
Fix use-after-delete bug in nurbs_ex10p.cpp.

Use relative tolerance in the "Collocated Derivative Kernels" unit test
to resolve failures in some setups with the original absolute tolerance.
2026-02-13 10:29:22 -08:00
chapman39 1f5bc1c3d8 wording 2026-02-13 10:03:00 -08:00
chapman39 3588d47ec1 Merge remote-tracking branch 'origin/master' into bugfix/chapman39/rm-return-from-omp 2026-02-13 09:59:31 -08:00
Andrew Ho e7f5996bdf fix warnings with some compilers 2026-02-13 09:28:16 -08:00
Tzanio Kolev 560ad1b5a3 Merge pull request #5157 from mfem/plbound-extremum
Estimate function minimum/maximum using recursion + piecewise linear bounds
2026-02-13 07:08:57 -08:00
Alex Tyler Chapman f0fe5b0ec0 Merge branch 'master' into bugfix/chapman39/rm-return-from-omp 2026-02-11 15:14:48 -08:00
chapman39 a92983051a style 2026-02-11 15:14:23 -08:00
Stowell, Mark L. 794a5fbfc2 Adding miniapps/plasma subdirectory to build system 2026-02-11 11:56:06 -08:00
Stowell, Mark L. 746a62f017 Adding plasma miniapp directory 2026-02-11 11:53:01 -08:00
Will Pazner 37843b050c Add one more 'if constexpr' 2026-02-11 11:33:51 -08:00
camierjs 436714f5ef Revert unused included header 2026-02-11 11:18:02 -08:00
camierjs 1ceef4f786 Add few missing Kernel() constexpr 2026-02-11 11:11:35 -08:00
Vladimir Z Tomov 6bb6745c0e improve 3d partitions 2026-02-10 16:23:38 -08:00
Mittal, Ketan 60f47c287d CHANGELOG 2026-02-10 14:28:17 -08:00
Mittal, Ketan 164ee942c8 Merge branch 'plbound-extremum' of https://github.com/mfem/mfem into plbound-extremum 2026-02-10 10:59:44 -08:00
Mittal, Ketan 16c4fbdd29 reviewer comments 2026-02-10 10:59:33 -08:00
Ketan Mittal e28093274b Merge branch 'master' into plbound-extremum 2026-02-09 19:06:18 -08:00
Andrew Ho 87dd19e6c0 more constexprs 2026-02-09 17:35:17 -08:00
Andrew Ho 678f53c306 use constexpr to prevent unintended kernel Pinstantiations 2026-02-09 17:17:26 -08:00
Gabriele Bozzola 9e4d9799dc Improve error message for gmsh versions != 2.2
I am a new user of [palace](https://github.com/awslabs/palace). As I was
trying to set a simple mesh up (with gmsh), I kept getting indexing
errors that I could not decipher. I eventually
[learned](https://mfem.org/mesh-formats/) that supported version for
gmsh meshes is 2.2.

This commit catches this and adds an informative error.
2026-02-06 16:12:27 -08:00
chapman39 32fb4bf244 remove return from openmp section 2026-02-05 14:56:40 -08:00
Jan Nikl ac4e558164 Minor unification of docstrings. 2026-02-04 15:21:02 -08:00
Jan Nikl 691cd8a687 Generalized RT normal projection. 2026-02-04 15:20:03 -08:00
Jan Nikl cdc327a511 Removed unused code. 2026-02-04 13:10:45 -08:00
Veselin Dobrev 2d021685de Fix a bug in QuadratureFunction::GetValues when getting a reference to
the data for one mesh element as a DenseMatrix.

Added new methods:
- Array<T>::MakeRef(Memory<T> &base, int offset, int size_)
- DenseMatrix::MakeRef(Memory<real_t> &base, int offset, int h, int w)
2026-02-02 08:42:58 -08:00
Hugh Carson d6ea262498 Address PR feedback
- Hoist src deletion
- Remove unneeded explicit cast given src is named
2026-01-30 14:01:59 -05:00
Andrew Ho 26e9057f02 revert change, updated comment to why libdl gets special treatment 2026-01-30 07:27:04 -08:00
Dylan Copeland 6b147fd9ff Merge branch 'master' of github.com:mfem/mfem into flip-index 2026-01-29 15:45:52 -08:00
Jan Nikl 0d2e8f93e6 Fixed vis of the initial exact solution. 2026-01-28 18:14:44 -08:00
Jan Nikl 16dfa11f27 Minor docstring correction. 2026-01-28 15:45:20 -08:00
Jan Nikl c7774e3c1c Fixed complex grid function copy assignment. 2026-01-28 15:34:55 -08:00
Hugh Carson a0981cb363 Refactor test for showing equivalency of copy and move assignment 2026-01-27 14:15:08 -05:00
Hugh Carson 894de992da Move assignment of non-owned arrays must fallback to copy assignment 2026-01-27 14:01:23 -05:00
Tzanio Kolev 942249395b Merge branch 'master' into debug-mem-silent 2026-01-24 11:40:50 -08:00
Stowell, Mark L. a3f6d5b971 Changing std::cout to mfem::out 2026-01-22 15:37:51 -08:00
Andrew Ho 194f3d8140 suggestions from Veselin 2026-01-21 11:45:20 -08:00
Ketan Mittal 5546250963 Merge branch 'master' into plbound-extremum 2026-01-21 11:00:02 -08:00
Mark L. Stowell 3f9b44a9cd Merge branch 'master' into phys-range-dim 2026-01-21 10:38:56 -08:00
John Camier 5b065ad7f2 Merge branch 'master' into debug-mem-silent 2026-01-20 17:59:07 -08:00
Ketan Mittal 7f4d7b8f4e Merge branch 'master' into plbound-extremum 2026-01-16 12:54:56 -08:00
Jan Nikl 47c9ad2e34 Fixed visulization in ex22p. 2026-01-16 11:20:13 -08:00
Mittal, Ketan 6529372830 reviewer comments 2026-01-15 13:10:47 -08:00
Mittal, Ketan d66d799387 minor 2026-01-14 15:25:11 -08:00
Mittal, Ketan 51f205b273 reviewer comments 2026-01-14 14:14:31 -08:00
Dylan Copeland 0161ad9d92 Minor simplifications. 2026-01-14 12:22:47 -08:00
Dylan Copeland 3589479481 Merge branch 'master' of github.com:mfem/mfem into flip-index 2026-01-14 12:10:30 -08:00
Dylan Copeland e9acfeccda Using new sign functions. 2026-01-14 12:10:07 -08:00
Ketan Mittal ad7cf12cd5 Merge branch 'master' into plbound-extremum 2026-01-13 12:24:55 -08:00
John Camier caa973d6a0 Merge branch 'master' into cmake-config 2026-01-13 08:13:47 -08:00
Ketan Mittal abdb023ae3 Merge branch 'master' into plbound-extremum 2026-01-12 10:12:14 -08:00
izaid 5cd3ec521b applied astyle 2026-01-08 23:19:16 +00:00
Mittal, Ketan d1a9c6e62d format miniapp output 2026-01-08 10:53:49 -08:00
Mittal, Ketan 8f0b57138b Merge branch 'master' of https://github.com/mfem/mfem into plbound-extremum 2026-01-08 10:37:40 -08:00
Mittal, Ketan 3167a1c98b remove default value from tol in pgridfunc.hpp 2026-01-08 10:31:19 -08:00
Tzanio Kolev 9488637956 Merge branch 'master' into pfes 2026-01-07 14:20:49 -08:00
Mittal, Ketan f429737c12 change 0.0 to 0_r 2026-01-06 12:22:27 -08:00
Andrew Ho ad40704e20 Merge branch 'master' into cmake-config 2026-01-06 11:55:40 -08:00
Mittal, Ketan 04fd683e9c doxygen fix 2026-01-06 11:38:42 -08:00
Mittal, Ketan 4b9f46a6b0 Merge branch 'plbound-extremum' of https://github.com/mfem/mfem into plbound-extremum 2026-01-06 11:30:04 -08:00
Mittal, Ketan 793a5b6d60 minor 2026-01-06 11:29:47 -08:00
Mittal, Ketan 4e6e9a13b6 Merge branch 'master' of https://github.com/mfem/mfem into plbound-extremum 2026-01-06 11:15:53 -08:00
Dylan Copeland 6f280d81b5 Introducing new functions for flipping index signs. 2026-01-05 18:46:25 -08:00
izaid 90353c437e Fixed bug in GetSurfaceFittingErrors 2026-01-01 23:09:09 +01:00
John Camier fbb50af208 Merge branch 'master' into debug-mem-silent 2025-12-30 12:50:33 -08:00
Andrew Ho d3470c07c9 Merge branch 'master' into cmake-config 2025-12-16 12:05:27 -08:00
Ketan Mittal 5b917af59b Merge branch 'master' into plbound-extremum 2025-12-15 12:59:44 -08:00
Mittal, Ketan f956c6b2de function for pargridfunction 2025-12-14 16:33:38 -08:00
Mittal, Ketan 62dbc570b2 add functions to compute min/max over all elements 2025-12-14 15:57:05 -08:00
Mittal, Ketan c221f5a29d initial commit 2025-12-13 15:20:43 -08:00
Andrew Ho 06a15cb7a9 missed one old unsetting of shared_link_flag 2025-12-01 17:02:05 -08:00
Andrew Ho d19ff6c676 Merge branch 'master' into cmake-config 2025-12-01 12:33:24 -08:00
Andrew Ho d85fbc6504 review suggestions 2025-11-25 14:35:38 -08:00
Andrew Ho 29346a87b6 Merge branch 'master' into cmake-config 2025-11-25 14:31:21 -05:00
Andrew Ho 3464f7a004 Merge branch 'master' into cmake-config 2025-10-28 11:08:38 -07:00
John Camier ce8cd01cfd Merge branch 'master' into debug-mem-silent 2025-10-28 10:20:51 -07:00
John Camier a60baf8ce6 Merge branch 'master' into debug-mem-silent 2025-10-25 11:28:07 -07:00
Andrew Ho 7de48e47ad Merge branch 'master' into cmake-config 2025-10-24 09:24:50 -07:00
Andrew Ho 70814c640b fixes for hip 2025-10-20 14:01:50 -07:00
Andrew Ho e9d3ae80f7 remove debug printout 2025-10-20 13:30:20 -07:00
Andrew Ho c8efc23c12 seems to be building external laghos now 2025-10-20 13:26:04 -07:00
Andrew Ho f26eb33252 Merge remote-tracking branch 'base/cmake-gpu' into cmake-config 2025-10-20 10:25:58 -07:00
John Camier 96bba18449 Merge branch 'master' into debug-mem-silent 2025-10-20 09:36:28 -07:00
Andrew Ho 05e622f837 improving config.mk file generated by cmake to work with hip/cuda
Still need to export compiler flags
2025-10-20 08:33:17 -07:00
Mark L. Stowell e9f84b033f Merge branch 'master' into phys-range-dim 2025-10-15 06:49:33 -07:00
John Camier f9cce3ab62 Merge branch 'master' into debug-mem-silent 2025-09-29 09:25:14 -07:00
John Camier 292700bb52 Merge branch 'master' into debug-mem-silent 2025-09-25 15:58:22 -07:00
John Camier fd2f0df34f Merge branch 'master' into debug-mem-silent 2025-09-21 20:13:41 -07:00
John Camier 4ac41a6427 Merge branch 'master' into debug-mem-silent 2025-09-21 10:27:05 -07:00
Andrew Ho ed862050b2 Merge branch 'master' into warn-gridfunc 2025-09-17 10:51:29 -07:00
Tzanio Kolev 3c6c1eb634 Merge branch 'master' into najlkin/extrd-1d-vec 2025-09-17 03:30:23 -07:00
Jan Nikl 22851a9463 Merge branch 'master' into najlkin/extrd-1d-vec 2025-09-16 15:30:43 -07:00
Jan Nikl 38df8156b9 Added documentation and checks to the extrusion classes. 2025-09-16 01:46:22 -07:00
Tzanio Kolev 58826d64c9 Merge branch 'master' into debug-mem-silent 2025-08-31 15:32:36 -07:00
Victor DeCaria a126203ccd implement suggested change 2025-08-21 15:08:57 -06:00
victor-decaria-nnl 6656a7ef72 Merge branch 'master' into debug-mem-silent 2025-08-20 15:50:34 -04:00
Veselin Dobrev 542467fd6a Merge branch 'master' into globalvec_debug 2025-08-16 16:26:36 -07:00
thartland 5986542e3d VERIFY instead of ASSERT 2025-07-16 16:02:21 -07:00
Tucker Hartland 5163313285 style 2025-07-16 15:46:46 -07:00
thartland 2201f3354a adding a check to make sure that each process owns at least one entry of the HypreParVector prior to calling GlobalVector 2025-07-16 15:36:57 -07:00
Mark L. Stowell 83fd119b95 Merge branch 'master' into phys-range-dim 2025-07-01 10:16:58 -07:00
John Camier 8804df317d Merge branch 'master' into debug-mem-silent 2025-07-01 09:51:06 -07:00
John Camier 95408b0fae Merge branch 'master' into debug-mem-silent 2025-06-22 20:25:51 -07:00
John Camier 79819a5563 Merge branch 'master' into debug-mem-silent 2025-06-18 10:22:04 -07:00
Andrew Ho f5b03af9d6 Merge branch 'master' into warn-gridfunc 2025-06-16 12:20:24 -07:00
John Camier d57fc7c0d9 Merge branch 'master' into debug-mem-silent 2025-06-16 08:33:43 -07:00
John Camier 9fb590d79d Merge branch 'master' into debug-mem-silent 2025-06-13 08:48:05 -07:00
Victor DeCaria cb4ca9228f add option to disable protection with debug backend 2025-06-05 09:34:25 -06:00
Andrew Ho 80c7823ac7 Merge branch 'master' into warn-gridfunc 2025-06-03 11:26:09 -07:00
Andrew Ho a443f003bb Merge pull request #4851 from mfem/najlkin/warn-gridfunc
Vector dimension for bdr/face elements
2025-06-02 11:45:47 -07:00
Mark L. Stowell 4aecb86d71 Merge branch 'master' into phys-range-dim 2025-05-19 17:51:08 -07:00
Andrew Ho 1730b05078 Merge branch 'master' into warn-gridfunc 2025-05-12 14:04:42 -07:00
Stowell, Mark L. 776a4c1815 Updating unit tests 2025-05-11 14:40:05 -07:00
Stowell, Mark L. c870d7dc1c Using new MapType entries and implementing new GetPhys*Dim methods 2025-05-11 14:39:49 -07:00
Stowell, Mark L. 8519889074 Adding new MapType entries for R2D and R1D classes 2025-05-11 14:38:50 -07:00
Jan Nikl 8a522f5e7d Fixed submesh unit test. 2025-05-07 16:26:34 -07:00
Jan Nikl fcbd105b82 Fixed ParGridFunction projection checks. 2025-05-07 15:28:54 -07:00
Jan Nikl b82dcf1387 Fixed variable order vector element unit tests. 2025-05-07 15:16:36 -07:00
Jan Nikl d3471aef59 Cosmetic change in FiniteElementSpace::GetTypicalBE(). 2025-05-07 14:35:50 -07:00
Jan Nikl 822555df0b Fixed boundary projection checks in GridFunction. 2025-05-07 14:23:33 -07:00
Jan Nikl 4626d65ac1 Added *VectorDim shortcuts to GridFunction. 2025-05-07 13:37:35 -07:00
Jan Nikl 38a80ea0e4 Added methods for typical elements and vector dimension for bdr/face. 2025-05-07 13:28:46 -07:00
Jan Nikl 590f954d6f Replaced the special case for trace spaces in GetVectorDim() by a check. 2025-05-07 11:58:01 -07:00
Jan Nikl bc5fc2b0f3 Revert "fixed ProjectBdrCoefficient vdim verify check"
This reverts commit feecd75ff3.
2025-05-07 11:55:25 -07:00
Tzanio Kolev 0f78d8aa5c Merge branch 'master' into najlkin/extrd-1d-vec 2025-04-15 13:46:39 -07:00
Andrew Ho 3f98aa1cfb Merge branch 'master' into warn-gridfunc 2025-04-14 16:15:59 -07:00
Andrew Ho feecd75ff3 fixed ProjectBdrCoefficient vdim verify check 2025-04-11 22:39:33 -07:00
Andrew Ho 248bdcc149 revert change in GridFunction::GetGradient 2025-04-11 20:49:28 -07:00
Andrew HoandVeselin Dobrev e4e354834d Update fem/gridfunc.cpp
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2025-04-11 20:47:15 -07:00
Andrew Ho d64a6d6255 Change GetVectorDim so it works for trace spaces.
Re-added boundary projection vector dim checks
2025-04-11 18:58:09 -07:00
Andrew Ho 510387a605 remove checks in Bdr projections
I think something more clever needs to be done here for projecting
onto trace elements
2025-04-11 17:23:44 -07:00
Andrew Ho e99b2a8410 Switched to VectorDim(), added checks for VectorCoefficient projection 2025-04-11 16:07:31 -07:00
Andrew Ho 6608111315 Added error checks for scalar coefficient projection onto a vector GridFunction 2025-04-11 14:39:06 -07:00
Jan Nikl b7253275fc Added extrusion of vector 1D grid functions. 2025-04-01 17:49:16 -07:00
127 changed files with 3750 additions and 3180 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ runs:
steps:
- uses: ./.github/actions/sanitize/config
- uses: actions/cache@v4
- uses: actions/cache@v5
if: ${{env.DEBUG == 'true'}}
id: debug
with:
+1 -1
View File
@@ -36,7 +36,7 @@ runs:
steps:
- uses: ./.github/actions/sanitize/config
- uses: actions/cache@v4
- uses: actions/cache@v5
if: ${{env.DEBUG == 'true' && inputs.cache-skip != 'true'}}
id: debug
with:
+5 -5
View File
@@ -23,7 +23,7 @@ inputs:
runs:
using: 'composite'
steps:
- uses: actions/cache/restore@v4 # Cache for LLVM libcxx
- uses: actions/cache/restore@v5 # Cache for LLVM libcxx
with:
path: ${{env.LLVM_DIR}}
fail-on-cache-miss: true
@@ -32,14 +32,14 @@ runs:
- uses: ./.github/actions/sanitize/mpi
if: ${{inputs.par == 'true'}}
- uses: actions/cache/restore@v4 # Cache for Hypre
- uses: actions/cache/restore@v5 # Cache for Hypre
if: ${{inputs.par == 'true'}}
with:
path: ${{env.HYPRE_DIR}}
fail-on-cache-miss: true
key: ${{runner.os}}-ompi-build-${{env.HYPRE_DIR}}-int32-fp64-v2.5
- uses: actions/cache/restore@v4 # Cache for Metis
- uses: actions/cache/restore@v5 # Cache for Metis
if: ${{inputs.par == 'true'}}
with:
path: ${{env.METIS_DIR}}
@@ -51,13 +51,13 @@ runs:
run: ln -s -f ${{env.HYPRE_DIR}} hypre && ln -s -f ${{env.METIS_DIR}} metis-4.0
shell: bash
- uses: actions/cache/restore@v4 # Cache for LSAN suppression file
- uses: actions/cache/restore@v5 # Cache for LSAN suppression file
with:
path: ${{env.LSAN_DIR}}
fail-on-cache-miss: true
key: build-lsan-suppression-file
- uses: actions/checkout@v4 # Checkout the repository
- uses: actions/checkout@v6 # Checkout the repository
with:
path: mfem
# ref: ${{env.BRANCH}}
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
remove-docker-images: 'true'
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
# It's easier to reference named variables than indexes of the matrix
- name: Set Environment
+6 -5
View File
@@ -153,7 +153,7 @@ jobs:
# /home/runner/work/mfem/mfem/mfem
# Note: Done now to access "install-hypre" and "install-metis" actions.
- name: checkout mfem
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
path: ${{ env.MFEM_TOP_DIR }}
# Fetch the complete history for codecov to access commits ID
@@ -225,7 +225,7 @@ jobs:
- name: cache hypre
id: hypre-cache
if: matrix.mpi == 'par'
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-ompi-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-${{ matrix.precision }}-v2.5
@@ -255,7 +255,7 @@ jobs:
- name: cache metis
id: metis-cache
if: matrix.mpi == 'par' && matrix.os != 'windows-latest'
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.5
@@ -270,7 +270,7 @@ jobs:
- name: cache vcpkg (Windows)
id: vcpkg-cache
if: matrix.os == 'windows-latest'
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: vcpkg_cache
key: ${{ runner.os }}-${{ matrix.mpi }}-vcpkg-v1
@@ -295,7 +295,8 @@ jobs:
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew update
brew install enzyme
ENZYME_LLVM=$(brew info enzyme | sed -n 's/^Required:.*\(llvm[^ ]*\).*/\1/p')
ENZYME_LLVM=$(brew info enzyme | sed -n 's/^Required.*:.*\(llvm[^ ]*\).*/\1/p')
echo "ENZYME_LLVM=$ENZYME_LLVM"
LLVM_PREFIX=$(brew --prefix $ENZYME_LLVM)
echo "LLVM_PREFIX=$LLVM_PREFIX" >> $GITHUB_ENV
echo "OMPI_CC=$LLVM_PREFIX/bin/clang" >> $GITHUB_ENV
+4 -4
View File
@@ -40,11 +40,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -57,7 +57,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v4
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -70,4 +70,4 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v4
+3 -3
View File
@@ -39,7 +39,7 @@ jobs:
steps:
- name: checkout MFEM
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
path: mfem
@@ -50,7 +50,7 @@ jobs:
- name: Cache Hypre Install
id: hypre-cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-ompi-build-${{ env.HYPRE_TOP_DIR }}-v2.5
@@ -65,7 +65,7 @@ jobs:
- name: Cache Metis Install
id: metis-cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.5
+4 -4
View File
@@ -38,7 +38,7 @@ jobs:
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: copyright check
id: copyright
@@ -93,7 +93,7 @@ jobs:
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: get astyle
run: |
@@ -110,7 +110,7 @@ jobs:
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: get doxygen and graphviz
run: |
@@ -135,7 +135,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout mfem
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
+2 -2
View File
@@ -17,11 +17,11 @@ jobs:
runs-on: ubuntu-latest
name: 2.19.0
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: ./.github/actions/sanitize/config
- name: Cache
id: cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ${{env.HYPRE_DIR}}
key: ${{runner.os}}-ompi-build-${{env.HYPRE_DIR}}-int32-fp64-v2.5
+2 -2
View File
@@ -27,13 +27,13 @@ jobs:
llvm_use_sanitizer: "Undefined"
name: ${{matrix.sanitizer}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: ./.github/actions/sanitize/config
with:
NO_FLAGS: true
- name: Cache
id: cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ${{env.LLVM_DIR}}
key: build-libcxx-${{env.LLVM_VER}}-${{matrix.sanitizer}}
+2 -2
View File
@@ -17,11 +17,11 @@ jobs:
runs-on: ubuntu-latest
name: lsan.supp
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: ./.github/actions/sanitize/config
- name: Cache
id: cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ${{env.LSAN_DIR}}
key: build-lsan-suppression-file
+2 -2
View File
@@ -17,11 +17,11 @@ jobs:
runs-on: ubuntu-latest
name: 4.0.3
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: ./.github/actions/sanitize/config
- name: Cache
id: cache
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ${{env.METIS_DIR}}
key: ${{runner.os}}-build-${{env.METIS_DIR}}-v2.5
+7 -7
View File
@@ -28,7 +28,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: ./.github/actions/sanitize/mfem
with:
par: ${{inputs.par}}
@@ -40,7 +40,7 @@ jobs:
env:
ex: ${{inputs.par && 'ex1p' || 'ex1'}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: ./.github/actions/sanitize/restore
id: restore
with:
@@ -58,7 +58,7 @@ jobs:
env:
exclude: ${{inputs.par && '-E "_ser"' || ''}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: ./.github/actions/sanitize/restore
id: restore
with:
@@ -82,7 +82,7 @@ jobs:
env:
exclude: ${{inputs.par && '-E "_ser"' || ''}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: ./.github/actions/sanitize/restore
id: restore
with:
@@ -107,7 +107,7 @@ jobs:
run: ${{inputs.par && '-R "_cpu_np"' || ''}}
exclude: ${{inputs.par && '"unit_tests|debug"' || '"^unit_tests$|debug"'}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: ./.github/actions/sanitize/restore
id: restore
with:
@@ -131,7 +131,7 @@ jobs:
env:
unit_tests: ${{inputs.par && 'punit_tests' || 'unit_tests'}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: ./.github/actions/sanitize/restore
id: restore
with:
@@ -165,7 +165,7 @@ jobs:
unit_tests: ${{inputs.par && 'punit_tests' || 'unit_tests'}}
np: ${{inputs.par && '_np=2' || ''}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: ./.github/actions/sanitize/restore
id: restore
with:
+23
View File
@@ -8,6 +8,21 @@
https://mfem.org
Version 4.10 (development)
==========================
Discretization improvements
---------------------------
- Replaced legacy simplex quadrature rules with symmetric positive-weight
rules for triangles (orders 0-25) and tetrahedra (orders 0-20). These
rules guarantee all-positive weights and interior quadrature points,
improving numerical stability. Higher orders fall back to Grundmann-Moller.
Triangle rules: Witherden & Vincent, Comput. Math. Appl. 69(10):1232-1241,
2015.
Tet rules (d=1-13): Witherden & Vincent (ibid).
Tet rules (d=14-20): Chuluunbaatar et al., Comput. Math. Appl. 124:89-97,
2022.
Version 4.9.1 (development)
===========================
@@ -17,6 +32,9 @@ Discretization improvements
Vector and VectorFE, also NURBS versions. Optionally different types of
projections can be selected, default behaviour has not changed.
- Added methods to estimate function extremum using piecewise linear bounds +
recursive subdivision.
Meshing improvements
--------------------
- Improved support for 1D NURBS meshes with variable order, including using
@@ -27,6 +45,11 @@ New and updated examples and miniapps
- Electromagnetics/lorentz miniapp has been updated to leverage the ParticleSet
capability.
Miscellaneous
-------------
- Removes the SidreDataCollection class from MFEM in favor of the
MFEMSidreDataCollection class in the Axom library (https://github.com/llnl/axom).
Version 4.9, released on Dec 11, 2025
=====================================
+7 -10
View File
@@ -75,12 +75,10 @@ set(XSDK_ENABLE_Fortran OFF)
# Check if we need to enable C or Fortran.
if (MFEM_USE_CONDUIT OR
MFEM_USE_SIDRE OR
MFEM_USE_PETSC)
# This seems to be needed by:
# * find_package(BLAS REQUIRED) and
# * find_package(HDF5 REQUIRED) needed, in turn, by:
# - find_package(AXOM REQUIRED)
# * find_package(HDF5 REQUIRED) and
# * find_package(PETSc REQUIRED)
set(XSDK_ENABLE_C ON)
endif()
@@ -478,11 +476,6 @@ if (MFEM_USE_FMS)
find_package(FMS REQUIRED fms)
endif()
# Axom/Sidre
if (MFEM_USE_SIDRE)
find_package(Axom REQUIRED Axom)
endif()
# PUMI
if (MFEM_USE_PUMI)
# If PUMI_DIR was specified, only link to that directory,
@@ -629,7 +622,7 @@ find_package(Threads REQUIRED)
# integers, the METIS header (with 32-bit indices, as used by mfem) needs to
# be before SuiteSparse.
set(MFEM_TPLS OPENMP HYPRE LAPACK BLAS SuperLUDist STRUMPACK METIS SuiteSparse
SUNDIALS PETSC SLEPC MUMPS AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB HDF5
SUNDIALS PETSC SLEPC MUMPS FMS CONDUIT Ginkgo GNUTLS GSLIB HDF5
NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
ADIOS2 MKL_CPARDISO MKL_PARDISO AMGX MAGMA CUSPARSE CUBLAS CALIPER CODIPACK
BENCHMARK PARELAG TRIBOL MPI_CXX HIP HIPBLAS HIPSPARSE MOONOLITH BLITZ
@@ -652,6 +645,8 @@ foreach(TPL IN LISTS MFEM_TPLS)
endif()
endforeach(TPL)
# reverse to remove the first instance of entries in TPL_LIBRARIES
# so later duplicates are kept (for dependency ordering)
list(REVERSE TPL_LIBRARIES)
list(REMOVE_DUPLICATES TPL_LIBRARIES)
list(REVERSE TPL_LIBRARIES)
@@ -1015,5 +1010,7 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data
# Create 'config.mk' from 'config.mk.in' for the build and install locations and
# define install rules for 'config.mk' and 'test.mk'
#-------------------------------------------------------------------------------
if (MFEM_USE_CUDA OR MFEM_USE_HIP)
option(MFEM_EXPORT_GPU_CONFIG "Export config.mk for GPU-enabled downstream packages" ON)
endif()
mfem_export_mk_files()
-17
View File
@@ -452,13 +452,6 @@ MFEM_USE_MPFR = YES/NO
quadrature rules. When enabled, this option uses the MPFR_* library options,
see below.
MFEM_USE_SIDRE = YES/NO
Sidre is a component of LLNL's axom project, https://github.com/LLNL/axom,
that provides an HDF5-based file format for visualization or restart
capability following the Conduit (https://github.com/LLNL/conduit) mesh
blueprint specification. When enabled, this option requires installation of
HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project.
MFEM_USE_SIMD = YES/NO
Enables the high performance templated classes to use architecture dependent
SIMD intrinsics instead of the generic implementation of class AutoSIMD in
@@ -778,14 +771,6 @@ The specific libraries and their options are:
Options: SLEPC_OPT, SLEPC_LIB.
Versions: SLEPc >= 3.8.0.
- Sidre (optional), part of LLNL's axom project, used when MFEM_USE_SIDRE = YES.
Starting with MFEM v4.1, Axom version 0.3.1 or later is required.
URL: https://github.com/LLNL/axom
https://github.com/LLNL/conduit (Conduit)
https://support.hdfgroup.org/HDF5 (HDF5)
Options: SIDRE_OPT, SIDRE_LIB.
Versions: Axom >= 0.3.1.
- Conduit (optional), used when MFEM_USE_CONDUIT = YES. Conduit Mesh Blueprint
support requires Conduit >= v0.3.1 and VisIt >= v2.13.1 to read the output.
URL: https://github.com/LLNL/conduit (Conduit)
@@ -1069,7 +1054,6 @@ MFEM_USE_OCCA
MFEM_USE_CEED
MFEM_USE_RAJA
MFEM_USE_UMPIRE
MFEM_USE_SIDRE
MFEM_USE_MOONOLITH
MFEM_USE_CALIPER
MFEM_USE_FMS
@@ -1133,7 +1117,6 @@ The CMake build system adds auto-detection for the following packages/libraries:
- OCCA
- RAJA
- UMPIRE
- AXOM - Used when MFEM_USE_SIDRE is enabled
- MOONOLITH
- CALIPER
- FMS
-4
View File
@@ -248,10 +248,6 @@ IF (DEFINED TPL_ENABLE_MPFR)
SET(MFEM_USE_MPFR ${TPL_ENABLE_MPFR} CACHE BOOL "Enable MPFR usage." FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_SIDRE)
SET(MFEM_USE_SIDRE ${TPL_ENABLE_SIDRE} CACHE BOOL "Enable Axom/Sidre usage" FORCE)
ENDIF()
IF (DEFINED TPL_ENABLE_FMS)
SET(MFEM_USE_FMS ${TPL_ENABLE_FMS} CACHE BOOL "Enable FMS usage" FORCE)
ENDIF()
-1
View File
@@ -46,7 +46,6 @@ set(MFEM_USE_NETCDF @MFEM_USE_NETCDF@)
set(MFEM_USE_PETSC @MFEM_USE_PETSC@)
set(MFEM_USE_SLEPC @MFEM_USE_SLEPC@)
set(MFEM_USE_MPFR @MFEM_USE_MPFR@)
set(MFEM_USE_SIDRE @MFEM_USE_SIDRE@)
set(MFEM_USE_FMS @MFEM_USE_FMS@)
set(MFEM_USE_CONDUIT @MFEM_USE_CONDUIT@)
set(MFEM_USE_PUMI @MFEM_USE_PUMI@)
-3
View File
@@ -120,9 +120,6 @@
// Enable secure socket streams based on the GNUTLS library.
#cmakedefine MFEM_USE_GNUTLS
// Enable Sidre support.
#cmakedefine MFEM_USE_SIDRE
// Enable the use of SIMD in the high performance templated classes.
#cmakedefine MFEM_USE_SIMD
+24
View File
@@ -0,0 +1,24 @@
# Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Defines the following variables:
# - ADIAK_FOUND
# - ADIAK_LIBRARIES
# - ADIAK_INCLUDE_DIRS
include(MfemCmakeUtilities)
mfem_find_package(Adiak ADIAK ADIAK_DIR
"include" "adiak.h"
"lib" "adiak"
"Paths to headers required by Adiak."
"Libraries required by Adiak.")
+3
View File
@@ -13,6 +13,9 @@
# - AXOM_FOUND
# - AXOM_LIBRARIES
# - AXOM_INCLUDE_DIRS
#
# MFEM itself does not depend on Axom, however Tribol does. This module exists
# to support MFEM's Tribol integration (e.g. the contact miniapp).
include(MfemCmakeUtilities)
# Note: components are enabled based on the find_package() parameters.
+36
View File
@@ -0,0 +1,36 @@
# Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Defines the following variables:
# - CAMP_FOUND
# - CAMP_LIBRARIES
# - CAMP_INCLUDE_DIRS
include(MfemCmakeUtilities)
mfem_find_package(CAMP CAMP CAMP_DIR
"include" "camp/camp.hpp"
"lib" "camp"
"Paths to headers required by CAMP."
"Libraries required by CAMP.")
# RAJA commonly lists "camp" in INTERFACE_LINK_LIBRARIES. If there is no CMake
# target named "camp", CMake treats it as a bare library name (-lcamp).
if (CAMP_FOUND AND NOT TARGET camp)
list(GET CAMP_LIBRARIES 0 _camp_lib0)
add_library(camp UNKNOWN IMPORTED)
set_target_properties(camp PROPERTIES
IMPORTED_LOCATION "${_camp_lib0}"
INTERFACE_INCLUDE_DIRECTORIES "${CAMP_INCLUDE_DIRS}")
set(CAMP_LIBRARIES "camp" CACHE STRING "CAMP imported target." FORCE)
unset(_camp_lib0)
endif()
+15
View File
@@ -21,6 +21,21 @@ mfem_find_package(Caliper CALIPER CALIPER_DIR
"Paths to headers required by Caliper."
"Libraries required by Caliper.")
# Some downstream CMake packages (notably RAJA) may list "caliper" in their
# INTERFACE_LINK_LIBRARIES. If there is no CMake target named "caliper", CMake
# treats it as a bare library name and will pass -lcaliper to the linker.
# Create a minimal imported target when we only located the library by path.
if (CALIPER_FOUND AND NOT TARGET caliper)
list(GET CALIPER_LIBRARIES 0 _caliper_lib0)
add_library(caliper UNKNOWN IMPORTED)
set_target_properties(caliper PROPERTIES
IMPORTED_LOCATION "${_caliper_lib0}"
INTERFACE_INCLUDE_DIRECTORIES "${CALIPER_INCLUDE_DIRS}")
# Prefer linking via the target.
set(CALIPER_LIBRARIES "caliper" CACHE STRING "Caliper imported target." FORCE)
unset(_caliper_lib0)
endif()
# Append adiak path/lib if the user provided ADIAK_DIR
if(ADIAK_DIR AND EXISTS ${ADIAK_DIR})
find_package(adiak NO_DEFAULT_PATH REQUIRED PATHS ${ADIAK_DIR}/lib/cmake/adiak ${ADIAK_DIR})
+90 -18
View File
@@ -701,7 +701,6 @@ endfunction(mfem_find_library)
# Extract compile and link options needed by the given target.
#
function(mfem_get_target_options Target CompileOptsVar LinkOptsVar)
if (NOT TARGET ${Target})
return()
endif()
@@ -799,7 +798,12 @@ function(mfem_get_target_options Target CompileOptsVar LinkOptsVar)
# message(STATUS "Lib = ${Lib}")
# Filter-out generator expressions
if (NOT ("${Lib}" MATCHES "^\\$"))
list(APPEND LinkOpts "${Lib}")
if(NOT ("${Lib}" STREQUAL "dl"))
list(APPEND LinkOpts "${Lib}")
else()
# for some reason libdl doesn't include the "-l"
list(APPEND LinkOpts "-ldl")
endif()
endif()
else()
mfem_get_target_options(${Lib} COpts LOpts)
@@ -874,7 +878,7 @@ function(mfem_export_mk_files)
MFEM_USE_SUITESPARSE MFEM_USE_SUPERLU MFEM_USE_SUPERLU5 MFEM_USE_MUMPS
MFEM_USE_STRUMPACK MFEM_USE_GINKGO MFEM_USE_AMGX MFEM_USE_MAGMA
MFEM_USE_GNUTLS MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_SLEPC
MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_FMS MFEM_USE_CONDUIT MFEM_USE_PUMI
MFEM_USE_MPFR MFEM_USE_FMS MFEM_USE_CONDUIT MFEM_USE_PUMI
MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA 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_MKL_PARDISO
@@ -888,9 +892,18 @@ function(mfem_export_mk_files)
set(${var} NO)
endif()
endforeach()
# TODO: Add support for MFEM_USE_CUDA=YES
set(MFEM_CXX ${CMAKE_CXX_COMPILER})
set(MFEM_HOST_CXX ${MFEM_CXX})
if (MFEM_USE_CUDA AND MFEM_EXPORT_GPU_CONFIG)
set(MFEM_CXX ${CMAKE_CUDA_COMPILER})
if(MFEM_CUDA_COMPILER_IS_NVCC)
set(MFEM_HOST_CXX ${CMAKE_CUDA_HOST_COMPILER})
else()
set(MFEM_HOST_CXX ${CMAKE_CXX_COMPILER})
endif()
else()
# mfem doesn't use enable_language(HIP)
set(MFEM_CXX ${CMAKE_CXX_COMPILER})
set(MFEM_HOST_CXX ${CMAKE_CXX_COMPILER})
endif()
set(MFEM_CPPFLAGS "")
get_target_property(cxx_std mfem CXX_STANDARD)
# For now, we ignore the setting of the CXX_EXTENSIONS property. If this
@@ -900,6 +913,50 @@ function(mfem_export_mk_files)
string(STRIP
"${cxx_std_flag} ${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}"
MFEM_CXXFLAGS)
if(MFEM_EXPORT_GPU_CONFIG)
if (MFEM_USE_CUDA)
set(MFEM_CXXFLAGS "${MFEM_CXXFLAGS} ${CMAKE_CUDA_FLAGS}")
if (MFEM_CUDA_COMPILER_IS_NVCC)
set(MFEM_CXXFLAGS "-x=cu ${MFEM_CXXFLAGS} -ccbin ${CMAKE_CXX_COMPILER} --forward-unknown-to-host-compiler")
# The following intentionally hides CUDA deprecation warnings
foreach(ENTRY IN LISTS CUDAToolkit_INCLUDE_DIRS)
set(MFEM_CXXFLAGS "${MFEM_CXXFLAGS} -isystem ${ENTRY}")
endforeach()
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18.0)
# architecture flags not part of CMAKE_CUDA_FLAGS
if ("all" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}"
OR "native" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}"
OR "all-major" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}")
set(MFEM_CXXFLAGS "${MFEM_CXXFLAGS} -arch=${CMAKE_CUDA_ARCHITECTURES}")
else()
foreach (ENTRY IN LISTS CMAKE_CUDA_ARCHITECTURES)
set(MFEM_CXXFLAGS
"${MFEM_CXXFLAGS} -gencode arch=compute_${ENTRY},code=sm_${ENTRY}")
endforeach()
endif()
endif()
else()
set(MFEM_CXXFLAGS "${MFEM_CXXFLAGS} -xcuda --cuda-path=${CUDAToolkit_LIBRARY_ROOT}")
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.18.0)
# architecture flags not part of CMAKE_CUDA_FLAGS
if ("all" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}"
OR "native" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}"
OR "all-major" STREQUAL "${CMAKE_CUDA_ARCHITECTURES}")
# TODO: not supported
else()
foreach(ENTRY IN LISTS CMAKE_CUDA_ARCHITECTURES)
set(MFEM_CXXFLAGS "-cuda-gpu-arch=sm_${ENTRY} ${MFEM_CXXFLAGS}")
endforeach()
endif()
endif()
endif()
elseif (MFEM_USE_HIP)
set(MFEM_CXXFLAGS "${MFEM_CXXFLAGS} -xhip")
foreach(ENTRY IN LISTS CMAKE_HIP_ARCHITECTURES)
set(MFEM_CXXFLAGS "--offload-arch=${ENTRY} ${MFEM_CXXFLAGS}")
endforeach()
endif()
endif()
set(MFEM_TPLFLAGS "")
foreach(dir ${TPL_INCLUDE_DIRS})
set(MFEM_TPLFLAGS "${MFEM_TPLFLAGS} -I${dir}")
@@ -930,6 +987,9 @@ function(mfem_export_mk_files)
set(MFEM_SHARED NO)
set(MFEM_STATIC YES)
endif()
if (MFEM_USE_CUDA)
set(MFEM_EXT_LIBS "${MFEM_EXT_LIBS} -lcudart")
endif()
set(MFEM_BUILD_TAG "${CMAKE_SYSTEM}")
set(MFEM_PREFIX "${CMAKE_INSTALL_PREFIX}")
# For the next 4 variables, these are the values for the build-tree version of
@@ -938,8 +998,15 @@ function(mfem_export_mk_files)
set(MFEM_LIB_DIR "${PROJECT_BINARY_DIR}")
set(MFEM_TEST_MK "${PROJECT_SOURCE_DIR}/config/test.mk")
set(MFEM_CONFIG_EXTRA "MFEM_BUILD_DIR ?= ${PROJECT_BINARY_DIR}")
# TODO: CUDA/HIP support:
set(MFEM_XLINKER "${CMAKE_CXX_LINKER_WRAPPER_FLAG}")
if (MFEM_USE_CUDA AND MFEM_EXPORT_GPU_CONFIG)
if (MFEM_CUDA_COMPILER_IS_NVCC)
set(MFEM_XLINKER "-Xlinker=")
else()
set(MFEM_XLINKER "${CMAKE_CUDA_LINKER_WRAPPER_FLAG}")
endif()
else()
set(MFEM_XLINKER "${CMAKE_CXX_LINKER_WRAPPER_FLAG}")
endif()
set(MFEM_MPIEXEC ${MPIEXEC})
if (NOT MFEM_MPIEXEC)
set(MFEM_MPIEXEC "mpirun")
@@ -987,16 +1054,21 @@ function(mfem_export_mk_files)
# handle interfaces (e.g., SCOREC::apf)
if ("${lib}" MATCHES "SCOREC::.*" OR "${lib}" MATCHES "Ginkgo::.*" OR "${lib}" MATCHES "ParMoonolith::.*")
elseif (TARGET "${lib}")
mfem_get_target_options(${lib} CompileOpts LinkOpts)
mfem_get_target_options(${lib} CompileOpts2 LinkOpts2)
# remove generator expressions
string(GENEX_STRIP "${CompileOpts2}" CompileOpts)
string(GENEX_STRIP "${LinkOpts2}" LinkOpts)
# Removing duplicates may lead to issues:
# list(REMOVE_DUPLICATES CompileOpts)
# list(REMOVE_DUPLICATES LinkOpts)
string(REPLACE ";" " " COpts "${CompileOpts}")
string(REPLACE ";" " " LOpts "${LinkOpts}")
# message(STATUS "${lib}[COpts]: '${COpts}'")
# message(STATUS "${lib}[LOpts]: '${LOpts}'")
set(MFEM_TPLFLAGS "${MFEM_TPLFLAGS} ${COpts}")
set(MFEM_EXT_LIBS "${MFEM_EXT_LIBS} ${LOpts}")
# message(WARNING "${lib}[LinkOpts]: ${LinkOpts}")
# message(WARNING "${lib}[CompileOpts]: ${CompileOpts}")
foreach(LOpt IN LISTS LinkOpts)
set(MFEM_EXT_LIBS "${MFEM_EXT_LIBS} ${LOpt}")
endforeach()
foreach(COpt IN LISTS CompileOpts)
set(MFEM_TPLFLAGS "${MFEM_TPLFLAGS} ${COpt}")
endforeach()
# message(FATAL_ERROR "***** interface lib found ... exiting *****")
# handle static and shared libs
elseif ("${suffix}" STREQUAL "${CMAKE_SHARED_LIBRARY_SUFFIX}")
@@ -1004,7 +1076,7 @@ function(mfem_export_mk_files)
get_filename_component(fullLibName ${lib} NAME_WE)
string(REGEX REPLACE "^lib" "" libname ${fullLibName})
set(MFEM_EXT_LIBS
"${MFEM_EXT_LIBS} ${shared_link_flag}${dir} -L${dir} -l${libname}")
"${MFEM_EXT_LIBS} ${shared_link_flag}${dir} -L${dir} -l${libname}")
else()
set(MFEM_EXT_LIBS "${MFEM_EXT_LIBS} ${lib}")
endif()
@@ -1013,7 +1085,7 @@ function(mfem_export_mk_files)
# Create the build-tree version of 'config.mk'
configure_file(
"${PROJECT_SOURCE_DIR}/config/config.mk.in"
"${PROJECT_BINARY_DIR}/config/config.mk")
"${PROJECT_BINARY_DIR}/config/config.mk" @ONLY)
# Copy 'test.mk' from the source-tree to the build-tree
configure_file(
"${PROJECT_SOURCE_DIR}/config/test.mk"
@@ -1031,7 +1103,7 @@ function(mfem_export_mk_files)
# Create the install-tree version of 'config.mk'
configure_file(
"${PROJECT_SOURCE_DIR}/config/config.mk.in"
"${PROJECT_BINARY_DIR}/config/config-install.mk")
"${PROJECT_BINARY_DIR}/config/config-install.mk" @ONLY)
# Install rules for 'config.mk' and 'test.mk'
install(FILES ${PROJECT_SOURCE_DIR}/config/test.mk
-3
View File
@@ -120,9 +120,6 @@
// Enable secure socket streams based on the GNUTLS library.
// #define MFEM_USE_GNUTLS
// Enable Sidre support.
// #define MFEM_USE_SIDRE
// Enable the use of SIMD in the high performance templated classes.
// #define MFEM_USE_SIMD
-1
View File
@@ -45,7 +45,6 @@ MFEM_USE_NETCDF = @MFEM_USE_NETCDF@
MFEM_USE_PETSC = @MFEM_USE_PETSC@
MFEM_USE_SLEPC = @MFEM_USE_SLEPC@
MFEM_USE_MPFR = @MFEM_USE_MPFR@
MFEM_USE_SIDRE = @MFEM_USE_SIDRE@
MFEM_USE_FMS = @MFEM_USE_FMS@
MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@
MFEM_USE_PUMI = @MFEM_USE_PUMI@
+9 -14
View File
@@ -48,7 +48,6 @@ option(MFEM_USE_NETCDF "Enable NETCDF usage" OFF)
option(MFEM_USE_PETSC "Enable PETSc support." OFF)
option(MFEM_USE_SLEPC "Enable SLEPc support." OFF)
option(MFEM_USE_MPFR "Enable MPFR usage." OFF)
option(MFEM_USE_SIDRE "Enable Axom/Sidre usage" OFF)
option(MFEM_USE_FMS "Enable FMS usage" OFF)
option(MFEM_USE_CONDUIT "Enable Conduit usage" OFF)
option(MFEM_USE_PUMI "Enable PUMI" OFF)
@@ -224,17 +223,8 @@ set(FMS_DIR "${MFEM_DIR}/../fms" CACHE PATH
set(CONDUIT_DIR "${MFEM_DIR}/../conduit" CACHE PATH
"Path to the Conduit library.")
set(AXOM_DIR "${MFEM_DIR}/../axom" CACHE PATH "Path to the Axom library.")
# May need to add "Boost" as requirement.
if (MFEM_USE_SIDRE)
if (MFEM_USE_MPI)
set(Axom_REQUIRED_PACKAGES "Conduit/blueprint/blueprint_mpi/relay/relay_mpi" CACHE STRING
"Additional packages required by Axom.")
elseif()
set(Axom_REQUIRED_PACKAGES "Conduit/blueprint/relay" CACHE STRING
"Additional packages required by Axom.")
endif()
endif()
set(AXOM_DIR "${MFEM_DIR}/../axom" CACHE PATH
"Path to the Axom library (required by Tribol for the contact mini-app).")
set(PUMI_DIR "${MFEM_DIR}/../pumi-2.1.0" CACHE STRING
"Directory where PUMI is installed")
@@ -252,6 +242,7 @@ set(MKL_PARDISO_DIR "" CACHE STRING "MKL installation path.")
set(OCCA_DIR "${MFEM_DIR}/../occa" CACHE PATH "Path to OCCA")
set(RAJA_DIR "${MFEM_DIR}/../raja" CACHE PATH "Path to RAJA")
set(CAMP_DIR "${MFEM_DIR}/../camp" CACHE PATH "Path to CAMP (required by RAJA/Umpire)")
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")
@@ -272,8 +263,12 @@ set(PARELAG_LIBRARIES "${PARELAG_DIR}/build/src/libParELAG.a" CACHE STRING
"The ParELAG library.")
set(TRIBOL_DIR "${MFEM_DIR}/../tribol" CACHE PATH "Path to Tribol")
set(Tribol_REQUIRED_PACKAGES "Axom/core/mint/slam/slic" CACHE STRING
"Additional packages required by Tribol")
# Tribol requires Axom. Many Tribol builds also enable optional TPLs like
# RAJA/UMPIRE/Caliper, and may pull additional Axom components (e.g. quest,
# lumberjack) via its exported targets.
set(Tribol_REQUIRED_PACKAGES
"REQUIRED:;Axom/core/primal/mint/slam/slic/quest/lumberjack;OPTIONAL:;Adiak;CAMP;RAJA;UMPIRE;Caliper"
CACHE STRING "Additional packages required by Tribol")
set(ENZYME_DIR "${MFEM_DIR}/../enzyme" CACHE PATH "Path to Enzyme")
+78 -15
View File
@@ -162,7 +162,6 @@ MFEM_USE_NETCDF = NO
MFEM_USE_PETSC = NO
MFEM_USE_SLEPC = NO
MFEM_USE_MPFR = NO
MFEM_USE_SIDRE = NO
MFEM_USE_FMS = NO
MFEM_USE_CONDUIT = NO
MFEM_USE_PUMI = NO
@@ -249,6 +248,15 @@ endif
# METIS library configuration
ifeq ($(MFEM_USE_SUPERLU)$(MFEM_USE_STRUMPACK)$(MFEM_USE_MUMPS),NONONO)
# MFEM_USE_METIS_5: when the user supplies METIS_DIR, try to auto-detect
# METIS 5 installs that follow the common <prefix>/{include,lib,lib64} layout.
ifeq ($(MFEM_USE_METIS_5),NO)
ifneq ($(wildcard $(METIS_DIR)/include/metis.h),)
ifneq ($(wildcard $(METIS_DIR)/lib/libmetis.* $(METIS_DIR)/lib64/libmetis.*),)
MFEM_USE_METIS_5 = YES
endif
endif
endif
ifeq ($(MFEM_USE_METIS_5),NO)
METIS_DIR = @MFEM_DIR@/../metis-4.0
METIS_OPT =
@@ -487,17 +495,6 @@ ifneq (,$(wildcard $(CONDUIT_HDF5_HEADER)))
-lhdf5 $(ZLIB_LIB)
endif
# Sidre and required libraries configuration
# Be sure to check the HDF5_DIR (set above) is correct
SIDRE_DIR = @MFEM_DIR@/../axom
SIDRE_OPT = -I$(SIDRE_DIR)/include -I$(CONDUIT_DIR)/include/conduit\
-I$(HDF5_DIR)/include
SIDRE_LIB = \
$(XLINKER)-rpath,$(SIDRE_DIR)/lib -L$(SIDRE_DIR)/lib \
$(XLINKER)-rpath,$(CONDUIT_DIR)/lib -L$(CONDUIT_DIR)/lib \
$(XLINKER)-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib \
-laxom -lconduit -lconduit_relay -lconduit_blueprint -lhdf5 $(ZLIB_LIB) -ldl
# PUMI
# Note that PUMI_DIR is needed -- it is used to check for gmi_sim.h
PUMI_DIR = @MFEM_DIR@/../pumi-2.1.0
@@ -579,7 +576,13 @@ ifdef CUB_DIR
RAJA_OPT += -I$(CUB_DIR)
endif
# CAMP library configuration (required by RAJA/Umpire for most installs)
CAMP_LIB = -lcamp
# If the common sibling layout exists, use it as a default (handles versioned
# directories like camp-<hash>).
ifneq ($(wildcard $(RAJA_DIR)/../camp*/include/camp/camp.hpp),)
CAMP_DIR ?= $(patsubst %/include/camp/camp.hpp,%,$(firstword $(wildcard $(RAJA_DIR)/../camp*/include/camp/camp.hpp)))
endif
ifdef CAMP_DIR
RAJA_OPT += -I$(CAMP_DIR)/include
CAMP_LIB = $(XLINKER)-rpath,$(CAMP_DIR)/lib -L$(CAMP_DIR)/lib -lcamp
@@ -589,7 +592,12 @@ RAJA_LIB = $(XLINKER)-rpath,$(RAJA_DIR)/lib -L$(RAJA_DIR)/lib -lRAJA $(CAMP_LIB)
# UMPIRE library configuration
UMPIRE_DIR = @MFEM_DIR@/../umpire
UMPIRE_OPT = -I$(UMPIRE_DIR)/include $(if $(CAMP_DIR), -I$(CAMP_DIR)/include)
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -L$(UMPIRE_DIR)/lib64 -lumpire $(CAMP_LIB)
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -L$(UMPIRE_DIR)/lib64 -lumpire $(CAMP_LIB) -lpthread
# If the common sibling layout exists, use it as a default (handles versioned
# directories like fmt-<hash>).
ifneq ($(wildcard $(UMPIRE_DIR)/../fmt*/include/fmt/format.h),)
FMT_DIR ?= $(patsubst %/include/fmt/format.h,%,$(firstword $(wildcard $(UMPIRE_DIR)/../fmt*/include/fmt/format.h)))
endif
ifdef FMT_DIR
UMPIRE_OPT += -I$(FMT_DIR)/include
UMPIRE_LIB += -L$(FMT_DIR)/lib -L$(FMT_DIR)/lib64 -lfmt
@@ -621,8 +629,63 @@ PARELAG_LIB = -L$(PARELAG_DIR)/build/src -lParELAG
AXOM_DIR = @MFEM_DIR@/../axom
TRIBOL_DIR = @MFEM_DIR@/../tribol
TRIBOL_OPT = -I$(TRIBOL_DIR)/include -I$(AXOM_DIR)/include
TRIBOL_LIB = -L$(TRIBOL_DIR)/lib -ltribol -lredecomp -L$(AXOM_DIR)/lib -laxom_mint\
-laxom_slam -laxom_slic -laxom_core
# Tribol may be built with optional dependencies (e.g. RAJA/UMPIRE/CALIPER).
# Add those options only when the corresponding headers/libraries exist.
ifneq ($(wildcard $(RAJA_DIR)/include/RAJA/RAJA.hpp),)
TRIBOL_OPT += $(RAJA_OPT)
endif
ifneq ($(wildcard $(UMPIRE_DIR)/include/umpire/Umpire.hpp),)
TRIBOL_OPT += $(UMPIRE_OPT)
endif
ifneq ($(wildcard $(CALIPER_DIR)/include/caliper/cali.h),)
TRIBOL_OPT += $(CALIPER_OPT)
endif
TRIBOL_LIB = -L$(TRIBOL_DIR)/lib -L$(TRIBOL_DIR)/lib64
ifneq ($(wildcard $(TRIBOL_DIR)/lib/libtribol.* $(TRIBOL_DIR)/lib64/libtribol.*),)
TRIBOL_LIB += -ltribol
endif
ifneq ($(wildcard $(TRIBOL_DIR)/lib/libtribol_shared.* $(TRIBOL_DIR)/lib64/libtribol_shared.*),)
TRIBOL_LIB += -ltribol_shared
endif
ifneq ($(wildcard $(TRIBOL_DIR)/lib/libredecomp.* $(TRIBOL_DIR)/lib64/libredecomp.*),)
TRIBOL_LIB += -lredecomp
endif
TRIBOL_LIB += -L$(AXOM_DIR)/lib -L$(AXOM_DIR)/lib64
ifneq ($(wildcard $(AXOM_DIR)/lib/libaxom_quest.* $(AXOM_DIR)/lib64/libaxom_quest.*),)
TRIBOL_LIB += -laxom_quest
endif
ifneq ($(wildcard $(AXOM_DIR)/lib/libaxom_mint.* $(AXOM_DIR)/lib64/libaxom_mint.*),)
TRIBOL_LIB += -laxom_mint
endif
ifneq ($(wildcard $(AXOM_DIR)/lib/libaxom_slam.* $(AXOM_DIR)/lib64/libaxom_slam.*),)
TRIBOL_LIB += -laxom_slam
endif
ifneq ($(wildcard $(AXOM_DIR)/lib/libaxom_slic.* $(AXOM_DIR)/lib64/libaxom_slic.*),)
TRIBOL_LIB += -laxom_slic
endif
ifneq ($(wildcard $(AXOM_DIR)/lib/libaxom_lumberjack.* $(AXOM_DIR)/lib64/libaxom_lumberjack.*),)
TRIBOL_LIB += -laxom_lumberjack
endif
ifneq ($(wildcard $(AXOM_DIR)/lib/libaxom_core.* $(AXOM_DIR)/lib64/libaxom_core.*),)
TRIBOL_LIB += -laxom_core
endif
# Add common optional Tribol TPLs when their libraries are present.
ifneq ($(wildcard $(ADIAK_DIR)/lib/libadiak.* $(ADIAK_DIR)/lib64/libadiak.*),)
TRIBOL_LIB += $(XLINKER)-rpath,$(ADIAK_DIR)/lib64 $(XLINKER)-rpath,$(ADIAK_DIR)/lib \
-L$(ADIAK_DIR)/lib64 -L$(ADIAK_DIR)/lib -ladiak -ldl
endif
ifneq ($(wildcard $(UMPIRE_DIR)/lib/libumpire.* $(UMPIRE_DIR)/lib64/libumpire.*),)
TRIBOL_LIB += $(UMPIRE_LIB)
endif
ifneq ($(wildcard $(RAJA_DIR)/lib/libRAJA.* $(RAJA_DIR)/lib64/libRAJA.*),)
TRIBOL_LIB += $(RAJA_LIB)
endif
ifneq ($(wildcard $(CALIPER_DIR)/lib/libcaliper.* $(CALIPER_DIR)/lib64/libcaliper.*),)
TRIBOL_LIB += $(CALIPER_LIB)
endif
# Enzyme configuration
ENZYME_DIR = @MFEM_DIR@/../enzyme
+2 -2
View File
@@ -5,9 +5,9 @@
// Sample runs:
// mpirun -np 4 ex12p -m ../data/beam-tri.mesh
// mpirun -np 4 ex12p -m ../data/beam-quad.mesh
// mpirun -np 4 ex12p -m ../data/beam-tet.mesh -s 462 -n 10 -o 2 -elast
// mpirun -np 4 ex12p -m ../data/beam-tet.mesh -s 464 -n 10 -o 2 -elast
// mpirun -np 4 ex12p -m ../data/beam-hex.mesh -s 3878
// mpirun -np 4 ex12p -m ../data/beam-wedge.mesh -s 81
// mpirun -np 4 ex12p -m ../data/beam-wedge.mesh -s 82
// mpirun -np 4 ex12p -m ../data/beam-tri.mesh -s 3877 -o 2 -sys
// mpirun -np 4 ex12p -m ../data/beam-quad.mesh -s 4544 -n 6 -o 3 -elast
// mpirun -np 4 ex12p -m ../data/beam-quad-nurbs.mesh
+27 -9
View File
@@ -302,15 +302,21 @@ int main(int argc, char *argv[])
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock_r(vishost, visport);
socketstream sol_sock_i(vishost, visport);
sol_sock_r << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_r.precision(8);
sol_sock_i.precision(8);
sol_sock_r << "solution\n" << *pmesh << u_exact->real()
<< "window_title 'Exact: Real Part'" << flush;
// Make sure all ranks have sent their real solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
socketstream sol_sock_i(vishost, visport);
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i.precision(8);
sol_sock_i << "solution\n" << *pmesh << u_exact->imag()
<< "window_title 'Exact: Imaginary Part'" << flush;
// Make sure all ranks have sent their imaginary solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
}
// 11. Set up the parallel sesquilinear form a(.,.) on the finite element
@@ -534,15 +540,21 @@ int main(int argc, char *argv[])
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock_r(vishost, visport);
socketstream sol_sock_i(vishost, visport);
sol_sock_r << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_r.precision(8);
sol_sock_i.precision(8);
sol_sock_r << "solution\n" << *pmesh << u.real()
<< "window_title 'Solution: Real Part'" << flush;
// Make sure all ranks have sent their real solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
socketstream sol_sock_i(vishost, visport);
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i.precision(8);
sol_sock_i << "solution\n" << *pmesh << u.imag()
<< "window_title 'Solution: Imaginary Part'" << flush;
// Make sure all ranks have sent their imaginary solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
}
if (visualization && exact_sol)
{
@@ -551,15 +563,21 @@ int main(int argc, char *argv[])
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock_r(vishost, visport);
socketstream sol_sock_i(vishost, visport);
sol_sock_r << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_r.precision(8);
sol_sock_i.precision(8);
sol_sock_r << "solution\n" << *pmesh << u_exact->real()
<< "window_title 'Error: Real Part'" << flush;
// Make sure all ranks have sent their real solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
socketstream sol_sock_i(vishost, visport);
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i.precision(8);
sol_sock_i << "solution\n" << *pmesh << u_exact->imag()
<< "window_title 'Error: Imaginary Part'" << flush;
// Make sure all ranks have sent their imaginary solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
}
if (visualization)
{
+6 -4
View File
@@ -433,16 +433,18 @@ int main(int argc, char *argv[])
u.ProjectCoefficient(*u0);
// Create data collection for solution output: either VisItDataCollection for
// ascii data files, or SidreDataCollection for binary data files.
// ascii data files, or ConduitDataCollection for binary data files.
DataCollection *dc = NULL;
if (visit)
{
if (binary)
{
#ifdef MFEM_USE_SIDRE
dc = new SidreDataCollection("Example41", &mesh);
#ifdef MFEM_USE_CONDUIT
auto conduit_dc = new ConduitDataCollection("Example41", &mesh);
conduit_dc->SetProtocol("hdf5");
dc = conduit_dc;
#else
MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
MFEM_ABORT("Must build with MFEM_USE_CONDUIT=YES for binary output.");
#endif
}
else
+5 -3
View File
@@ -518,10 +518,12 @@ int main(int argc, char *argv[])
{
if (binary)
{
#ifdef MFEM_USE_SIDRE
dc = new SidreDataCollection("Example41-Parallel", pmesh);
#ifdef MFEM_USE_CONDUIT
auto conduit_dc = new ConduitDataCollection("Example41-Parallel", pmesh);
conduit_dc->SetProtocol("hdf5");
dc = conduit_dc;
#else
MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
MFEM_ABORT("Must build with MFEM_USE_CONDUIT=YES for binary output.");
#endif
}
else
+6 -4
View File
@@ -305,16 +305,18 @@ int main(int argc, char *argv[])
}
// Create data collection for solution output: either VisItDataCollection for
// ascii data files, or SidreDataCollection for binary data files.
// ascii data files, or ConduitDataCollection for binary data files.
DataCollection *dc = NULL;
if (visit)
{
if (binary)
{
#ifdef MFEM_USE_SIDRE
dc = new SidreDataCollection("Example9", &mesh);
#ifdef MFEM_USE_CONDUIT
auto conduit_dc = new ConduitDataCollection("Example9", &mesh);
conduit_dc->SetProtocol("hdf5");
dc = conduit_dc;
#else
MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
MFEM_ABORT("Must build with MFEM_USE_CONDUIT=YES for binary output.");
#endif
}
else
+6 -4
View File
@@ -441,16 +441,18 @@ int main(int argc, char *argv[])
}
// Create data collection for solution output: either VisItDataCollection for
// ascii data files, or SidreDataCollection for binary data files.
// ascii data files, or ConduitDataCollection for binary data files.
DataCollection *dc = NULL;
if (visit)
{
if (binary)
{
#ifdef MFEM_USE_SIDRE
dc = new SidreDataCollection("Example9-Parallel", pmesh);
#ifdef MFEM_USE_CONDUIT
auto conduit_dc = new ConduitDataCollection("Example9-Parallel", pmesh);
conduit_dc->SetProtocol("hdf5");
dc = conduit_dc;
#else
MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
MFEM_ABORT("Must build with MFEM_USE_CONDUIT=YES for binary output.");
#endif
}
else
+6 -4
View File
@@ -354,16 +354,18 @@ int main(int argc, char *argv[])
}
// Create data collection for solution output: either VisItDataCollection for
// ascii data files, or SidreDataCollection for binary data files.
// ascii data files, or ConduitDataCollection for binary data files.
DataCollection *dc = NULL;
if (visit)
{
if (binary)
{
#ifdef MFEM_USE_SIDRE
dc = new SidreDataCollection("Example9", mesh);
#ifdef MFEM_USE_CONDUIT
auto conduit_dc = new ConduitDataCollection("Example9", mesh);
conduit_dc->SetProtocol("hdf5");
dc = conduit_dc;
#else
MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
MFEM_ABORT("Must build with MFEM_USE_CONDUIT=YES for binary output.");
#endif
}
else
+6 -4
View File
@@ -414,16 +414,18 @@ int main(int argc, char *argv[])
}
// Create data collection for solution output: either VisItDataCollection for
// ascii data files, or SidreDataCollection for binary data files.
// ascii data files, or ConduitDataCollection for binary data files.
DataCollection *dc = NULL;
if (visit)
{
if (binary)
{
#ifdef MFEM_USE_SIDRE
dc = new SidreDataCollection("Example9-Parallel", pmesh);
#ifdef MFEM_USE_CONDUIT
auto conduit_dc = new ConduitDataCollection("Example9-Parallel", pmesh);
conduit_dc->SetProtocol("hdf5");
dc = conduit_dc;
#else
MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
MFEM_ABORT("Must build with MFEM_USE_CONDUIT=YES for binary output.");
#endif
}
else
+6 -4
View File
@@ -368,16 +368,18 @@ int main(int argc, char *argv[])
}
// Create data collection for solution output: either VisItDataCollection for
// ascii data files, or SidreDataCollection for binary data files.
// ascii data files, or ConduitDataCollection for binary data files.
DataCollection *dc = NULL;
if (visit)
{
if (binary)
{
#ifdef MFEM_USE_SIDRE
dc = new SidreDataCollection("Example9-Parallel", pmesh);
#ifdef MFEM_USE_CONDUIT
auto conduit_dc = new ConduitDataCollection("Example9-Parallel", pmesh);
conduit_dc->SetProtocol("hdf5");
dc = conduit_dc;
#else
MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
MFEM_ABORT("Must build with MFEM_USE_CONDUIT=YES for binary output.");
#endif
}
else
+6 -4
View File
@@ -316,16 +316,18 @@ int main(int argc, char *argv[])
}
// Create data collection for solution output: either VisItDataCollection for
// ascii data files, or SidreDataCollection for binary data files.
// ascii data files, or ConduitDataCollection for binary data files.
DataCollection *dc = NULL;
if (visit)
{
if (binary)
{
#ifdef MFEM_USE_SIDRE
dc = new SidreDataCollection("Example9", &mesh);
#ifdef MFEM_USE_CONDUIT
auto conduit_dc = new ConduitDataCollection("Example9", &mesh);
conduit_dc->SetProtocol("hdf5");
dc = conduit_dc;
#else
MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
MFEM_ABORT("Must build with MFEM_USE_CONDUIT=YES for binary output.");
#endif
}
else
+6 -4
View File
@@ -453,16 +453,18 @@ int main(int argc, char *argv[])
}
// Create data collection for solution output: either VisItDataCollection for
// ascii data files, or SidreDataCollection for binary data files.
// ascii data files, or ConduitDataCollection for binary data files.
DataCollection *dc = NULL;
if (visit)
{
if (binary)
{
#ifdef MFEM_USE_SIDRE
dc = new SidreDataCollection("Example9-Parallel", pmesh);
#ifdef MFEM_USE_CONDUIT
auto conduit_dc = new ConduitDataCollection("Example9-Parallel", pmesh);
conduit_dc->SetProtocol("hdf5");
dc = conduit_dc;
#else
MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
MFEM_ABORT("Must build with MFEM_USE_CONDUIT=YES for binary output.");
#endif
}
else
-5
View File
@@ -312,11 +312,6 @@ set(HDRS
particleset.hpp
)
if (MFEM_USE_SIDRE)
list(APPEND SRCS sidredatacollection.cpp)
list(APPEND HDRS sidredatacollection.hpp)
endif()
if (MFEM_USE_CONDUIT)
list(APPEND SRCS conduitdatacollection.cpp)
list(APPEND HDRS conduitdatacollection.hpp)
+7 -3
View File
@@ -729,7 +729,8 @@ void BilinearForm::Assemble(int skip_zeros)
tr = mesh -> GetBdrFaceTransformations (i);
if (tr != NULL)
{
fes -> GetElementVDofs (tr -> Elem1No, vdofs);
mfem::DofTransformation doftrans;
fes -> GetElementVDofs (tr -> Elem1No, vdofs, doftrans);
fe1 = fes -> GetFE (tr -> Elem1No);
// The fe2 object is really a dummy and not used on the boundaries,
// but we can't dereference a NULL pointer, and we don't want to
@@ -743,6 +744,7 @@ void BilinearForm::Assemble(int skip_zeros)
boundary_face_integs[k] -> AssembleFaceMatrix (*fe1, *fe2, *tr,
elemmat);
doftrans.TransformDual(elemmat);
mat -> AddSubMatrix (vdofs, vdofs, elemmat, skip_zeros);
}
}
@@ -1723,6 +1725,7 @@ void MixedBilinearForm::Assemble(int skip_zeros)
}
}
DofTransformation dom_dof_trans, ran_dof_trans;
for (int i = 0; i < trial_fes -> GetNBE(); i++)
{
const int bdr_attr = mesh->GetBdrAttribute(i);
@@ -1731,8 +1734,8 @@ void MixedBilinearForm::Assemble(int skip_zeros)
ftr = mesh -> GetBdrFaceTransformations (i);
if (ftr != NULL)
{
trial_fes->GetElementVDofs(ftr->Elem1No, trial_vdofs);
test_fes->GetElementVDofs(ftr->Elem1No, test_vdofs);
trial_fes->GetElementVDofs(ftr->Elem1No, trial_vdofs, dom_dof_trans);
test_fes->GetElementVDofs(ftr->Elem1No, test_vdofs, ran_dof_trans);
trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
test_fe1 = test_fes->GetFE(ftr->Elem1No);
// The test_fe2 object is really a dummy and not used on the
@@ -1748,6 +1751,7 @@ void MixedBilinearForm::Assemble(int skip_zeros)
boundary_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
*test_fe2,
*ftr, elemmat);
TransformDual(ran_dof_trans, dom_dof_trans, elemmat);
mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
}
}
+1 -1
View File
@@ -2710,7 +2710,7 @@ public:
/** Integrator for $(-Q u, \nabla v)$ for Nedelec ($u$) and $H^1$ ($v$) elements.
This is equivalent to a weak divergence of the $H(curl$ basis functions. */
This is equivalent to a weak divergence of the $H(curl)$ basis functions. */
class VectorFEWeakDivergenceIntegrator: public BilinearFormIntegrator
{
protected:
+67 -28
View File
@@ -39,8 +39,8 @@ void PLBound::Setup(const int nb_i, const int ncp_i,
b_type = b_type_i;
cp_type = cp_type_i;
tol = tol_i;
lbound.SetSize(nb, ncp);
ubound.SetSize(nb, ncp);
lbound.SetSize(ncp, nb);
ubound.SetSize(ncp, nb);
nodes.SetSize(nb);
weights.SetSize(nb);
control_points.SetSize(ncp);
@@ -125,21 +125,25 @@ void PLBound::Setup(const int nb_i, const int ncp_i,
{
if (j == 0)
{
lbound(i, j) = bv(i);
ubound(i, j) = bv(i);
lbound(j,i) = bv(i);
ubound(j,i) = bv(i);
}
else if (j == ncp-1)
{
lbound(i, j) = bv(i);
ubound(i, j) = bv(i);
lbound(j,i) = bv(i);
ubound(j,i) = bv(i);
}
else
{
vals(0) = bv(i);
vals(1) = bmv(i) + dm*bdmv(i);
vals(2) = bpv(i) + dp*bdpv(i);
lbound(i, j) = vals.Min()-tol; // tolerance for good measure
ubound(i, j) = vals.Max()+tol; // tolerance for good measure
lbound(j,i) = vals.Min()-tol; // tolerance for good measure
ubound(j,i) = vals.Max()+tol; // tolerance for good measure
if (b_type == 2)
{
lbound(j,i) = std::max(lbound(j,i),0_r);
}
}
}
}
@@ -273,8 +277,7 @@ void PLBound::Get1DBounds(const Vector &coeff, Vector &intmin,
intmax.SetSize(ncp);
intmin = 0.0;
intmax = 0.0;
Vector coeffm(nb);
coeffm = 0.0;
Vector coeffm;
real_t a0 = 0.0;
real_t a1 = 0.0;
@@ -302,6 +305,8 @@ void PLBound::Get1DBounds(const Vector &coeff, Vector &intmin,
// compute L2 projection for linear bases: a0 + a1*x
if (proj)
{
coeffm.SetSize(nb);
coeffm = 0.0;
for (int i = 0; i < nb; i++)
{
x = 2.0*nodes_int(i)-1;
@@ -342,8 +347,8 @@ void PLBound::Get1DBounds(const Vector &coeff, Vector &intmin,
real_t c = coeffm(i);
for (int j = 0; j < ncp; j++)
{
intmin(j) += min(lbound(i,j)*c, ubound(i,j)*c);
intmax(j) += max(lbound(i,j)*c, ubound(i,j)*c);
intmin(j) += min(lbound(j,i)*c, ubound(j,i)*c);
intmax(j) += max(lbound(j,i)*c, ubound(j,i)*c);
}
}
}
@@ -474,10 +479,10 @@ void PLBound::Get2DBounds(const Vector &coeff, Vector &intmin,
real_t w1 = intmaxT(id2++);
for (int k = 0; k < ncp; k++) // kth row
{
vals(0) = w0*lbound(j,k);
vals(1) = w0*ubound(j,k);
vals(2) = w1*lbound(j,k);
vals(3) = w1*ubound(j,k);
vals(0) = w0*lbound(k,j);
vals(1) = w0*ubound(k,j);
vals(2) = w1*lbound(k,j);
vals(3) = w1*ubound(k,j);
intmin(k*ncp+i) += vals.Min();
intmax(k*ncp+i) += vals.Max();
}
@@ -553,17 +558,17 @@ void PLBound::Get3DBounds(const Vector &coeff, Vector &intmin,
for (int i = 0; i < nb; i++)
{
x = 2.0*nodes(i)-1; // x-coordinate
minBounds(i) -= a0V(j) + a1V(j)*x;
maxBounds(i) -= a0V(j) + a1V(j)*x;
minNodalVals(i) -= a0V(j) + a1V(j)*x;
maxNodalVals(i) -= a0V(j) + a1V(j)*x;
}
// Compute Bernstein coefficients
LUFactors lu(basisMatLU.GetData(), lu_ip.GetData());
lu.Solve(nb, 1, minBounds.GetData());
lu.Solve(nb, 1, maxBounds.GetData());
lu.Solve(nb, 1, minNodalVals.GetData());
lu.Solve(nb, 1, maxNodalVals.GetData());
for (int i = 0; i < nb; i++)
{
intminT(i*ncp2+j) = minBounds(i);
intmaxT(i*ncp2+j) = maxBounds(i);
intminT(i*ncp2+j) = minNodalVals(i);
intmaxT(i*ncp2+j) = maxNodalVals(i);
}
}
}
@@ -617,10 +622,10 @@ void PLBound::Get3DBounds(const Vector &coeff, Vector &intmin,
real_t w1 = intmaxT(id2++);
for (int k = 0; k < ncp; k++) // kth slice
{
vals(0) = w0*lbound(j,k);
vals(1) = w0*ubound(j,k);
vals(2) = w1*lbound(j,k);
vals(3) = w1*ubound(j,k);
vals(0) = w0*lbound(k,j);
vals(1) = w0*ubound(k,j);
vals(2) = w1*lbound(k,j);
vals(3) = w1*ubound(k,j);
intmin(k*ncp2+i) += vals.Min();
intmax(k*ncp2+i) += vals.Max();
}
@@ -653,7 +658,8 @@ void PLBound::SetupBernsteinBasisMat(DenseMatrix &basisMat,
Vector &nodesBern) const
{
const int nbern = nodesBern.Size();
L2_SegmentElement el(nbern-1, 2); // we use L2 to leverage lexicographic order
L2_SegmentElement el(nbern-1, 2);
// we use L2 to leverage lexicographic order
Array<int> ordering = el.GetLexicographicOrdering();
basisMat.SetSize(nbern, nbern);
Vector shape(nbern);
@@ -666,6 +672,39 @@ void PLBound::SetupBernsteinBasisMat(DenseMatrix &basisMat,
}
}
DenseMatrix PLBound::GetBoundingMatrix(int dim, bool is_lower) const
{
if (dim > 1)
{
const int ncpd = static_cast<int>(std::pow(ncp, dim));
const int nbd = static_cast<int>(std::pow(nb, dim));
DenseMatrix boundND(ncpd, nbd);
Vector phimin, phimax, col;
Vector coeffs(nbd);
coeffs = 0.0;
for (int j = 0; j < nbd; j++)
{
coeffs(j) = 1.0;
boundND.GetColumnReference(j, col);
GetNDBounds(dim, coeffs, phimin, phimax);
col = is_lower ? phimin : phimax;
coeffs(j) = 0.0;
}
return boundND;
}
return is_lower ? lbound : ubound;
}
DenseMatrix PLBound::GetLowerBoundMatrix(int dim) const
{
return GetBoundingMatrix(dim, true);
}
DenseMatrix PLBound::GetUpperBoundMatrix(int dim) const
{
return GetBoundingMatrix(dim, false);
}
constexpr int PLBound::min_ncp_gl_x[2][11];
constexpr int PLBound::min_ncp_gll_x[2][11];
constexpr int PLBound::min_ncp_pos_x[2][11];
@@ -716,4 +755,4 @@ void PLBound::Print(std::ostream &outp) const
ubound.Print(outp);
}
}
}
+71 -20
View File
@@ -19,14 +19,18 @@ namespace mfem
{
/** @name Piecewise linear bounds of bases
\brief Piecewise linear bounds of bases can be used to compute bounds on the grid function in each element. The bounds for the bases are constructed based on the following parameters:
\brief Piecewise linear bounds of bases can be used to compute bounds on
the grid function in each element. The bounds for the bases are constructed
based on the following parameters:
(i) @b nb: number of bases/nodes in 1D (i.e. polynomial order+1),
(ii) @b b_type: bases type, 0 - Lagrange interpolants on Gauss-Legendre nodes, 1 - Lagrange interpolants on Gauss-Lobatto-Legendre nodes, and
(ii) @b b_type: bases type, 0 - Lagrange interpolants on Gauss-Legendre
nodes, 1 - Lagrange interpolants on Gauss-Lobatto-Legendre nodes, and
2 - Positive/Bernstein bases on uniformly distributed nodes,
(iii) @b ncp: number of control points used to construct the piecewise linear bounds
(iii) @b ncp: number of control points used to construct the piecewise
linear bounds
(iv) @b cp_type: control point distribution. 0 - GL + end-points,
1 - Chebyshev.
@@ -35,7 +39,9 @@ namespace mfem
If the user does not specify @b ncp and @b cp_type, the minimum value of
@b ncp is used that would bound the bases for the @b cp_type. We default
to @b cp_type = 0 as it requires fewer number of points to bound the bases. Typically, @b ncp = 2 @b nb is sufficient to get fairly compact bounds, and increasing @b ncp results in tighter bounds.
to @b cp_type = 0 as it requires fewer number of points to bound the bases.
Typically, @b ncp = 2 @b nb is sufficient to get fairly compact bounds, and
increasing @b ncp results in tighter bounds.
Finally, only tensor-product elements are currently supported.
@@ -54,7 +60,7 @@ private:
bool proj = true; // Use linear projection to compute bounds.
real_t tol = 0.0; // offset bounds to avoid round-off errors
Vector nodes, weights, control_points;
DenseMatrix lbound, ubound; // nb x ncp matrices with bounds of all bases
DenseMatrix lbound, ubound; // ncp x nb matrices with bounds of all bases
// Some auxillary storage for computing the bounds with Bernstein
DenseMatrix basisMatNodes; // Bernstein bases at equispaced nodes
DenseMatrix basisMatInt; // Bernstein bases at GLL nodes
@@ -80,6 +86,9 @@ private:
{3,5,8,9,11,12,13,13,14,15,16}
};
/// Helper function to extract lower or upper bounding matrix
DenseMatrix GetBoundingMatrix(int dim, bool is_lower) const;
public:
// Constructor
PLBound(const int nb_i, const int ncp_i, const int b_type_i,
@@ -92,40 +101,82 @@ public:
PLBound(const FiniteElementSpace *fes,
const int ncp_i = -1, const int cp_type_i = 0);
// Get minimum number of control points needed to bound the given bases
/// Get minimum number of control points needed to bound the given bases
int GetMinimumPointsForGivenBases(int nb_i, int b_type_i,
int cp_type_i) const;
// Print information about the bounds
/// Print information about the bounds
void Print(std::ostream &outp = mfem::out) const;
// Enable (default) or disable linear projection before bounding.
// This projection increases the computational cost but results in tighter
// bounds.
/** @brief Enable (default) or disable linear projection before bounding.
*
* @details This projection increases the computational cost but results in
* tighter bounds.
*/
void SetProjectionFlagForBounding(bool proj_) { proj = proj_; }
/// Compute piecewise linear bounds for the lexicographically-ordered
/// coefficients in @a coeff in 1D/2D/3D.
/** @brief Compute piecewise linear bounds for the lexicographically-ordered
* nodal coefficients in @a coeff in 1D/2D/3D.
*
* @param[in] rdim The spatial dimension of the element (1, 2, or 3).
* @param[in] coeff The vector of lexicographically-ordered coefficients.
* Should be of size nb^rdim, where nb is the number of
* bases/nodes in 1D. These coefficients must correspond
* to the bases type and number of bases, used in the
* constructor of PLBound.
*
* @param[out] intmin The vector of minimum bound for all control points.
* @param[out] intmax The vector of maximum bound for all control points.
* Both intmin and intmax are of size ncp^rdim, where
* ncp is the number of control points in 1D, and are
* ordered lexicographically.
*/
void GetNDBounds(const int rdim, const Vector &coeff,
Vector &intmin, Vector &intmax) const;
/// Get number of control points used to compute the bounds.
int GetNControlPoints() const { return ncp; }
/// Get 1D control point locations (lexicographic order) in [0,1].
const Vector &GetControlPoints() const { return control_points; }
/** @brief Get lower and upper bounding matrix (ncp^dim x nb^dim)
*
* @details The matrices can be used to compute the bounds at control points
* by a simple matrix-vector product with the
* lexicographically-ordered nodal coefficients.
* The resulting output is also lexicographically-ordered.
*
* @note These matrices do not account for the linear projection step that
* is optionally done in GetNDBounds before bounding the function.
*/
///@{
DenseMatrix GetLowerBoundMatrix(int dim = 1) const;
DenseMatrix GetUpperBoundMatrix(int dim = 1) const;
///@}
private:
/// Compute piecewise linear bounds for the lexicographically-ordered
/// coefficients in @a coeff in 1D.
/** @brief Compute piecewise linear bounds for the lexicographically-ordered
* nodal coefficients in @a coeff in 1D.
* See GetNDBounds for details of the input and output parameters.
*/
void Get1DBounds(const Vector &coeff, Vector &intmin, Vector &intmax) const;
/// Compute piecewise linear bounds for the lexicographically-ordered
/// coefficients in @a coeff in 2D.
/** @brief Compute piecewise linear bounds for the lexicographically-ordered
* nodal coefficients in @a coeff in 2D.
* See GetNDBounds for details of the input and output parameters.
*/
void Get2DBounds(const Vector &coeff, Vector &intmin, Vector &intmax) const;
/// Compute piecewise linear bounds for the lexicographically-ordered
/// coefficients in @a coeff in 3D.
/** @brief Compute piecewise linear bounds for the lexicographically-ordered
* nodal coefficients in @a coeff in 3D.
* See GetNDBounds for details of the input and output parameters.
*/
void Get3DBounds(const Vector &coeff, Vector &intmin, Vector &intmax) const;
/// Setup matrix used to compute values at given 1D locations in [0,1]
/// for Bernstein bases.
/** @brief Setup matrix used to compute values at given 1D locations in [0,1]
* for Bernstein bases.
*/
void SetupBernsteinBasisMat(DenseMatrix &basisMat, Vector &nodesBern) const;
void Setup(const int nb_i, const int ncp_i, const int b_type_i,
+19
View File
@@ -82,6 +82,25 @@ public:
/// underlying #fes
int VectorDim() const;
/// Copy assignment. Only the data of the base class Vector is copied.
/** It is assumed that this object and @a rhs use FiniteElementSpace%s that
have the same size.
@note Defining this method overwrites the implicitly defined copy
assignment operator. */
ComplexGridFunction &operator=(const ComplexGridFunction &rhs)
{ return operator=((const Vector &)rhs); }
/// Copy the data from @a v.
/** The size of @a v must be equal to double of the size of the associated
FiniteElementSpace #fes. */
ComplexGridFunction &operator=(const Vector &v)
{
MFEM_ASSERT(fes && v.Size() == 2*fes->GetVSize(), "");
Vector::operator=(v);
return *this;
}
/// Assign constant values to the ComplexGridFunction data.
ComplexGridFunction &operator=(const std::complex<real_t> & value)
{ *gfr = value.real(); *gfi = value.imag(); return *this; }
-2
View File
@@ -1453,8 +1453,6 @@ ConduitDataCollection::LoadMeshAndFields(int domain_id,
std::string
ConduitDataCollection::ElementTypeToShapeName(Element::Type element_type)
{
// Adapted from SidreDataCollection
// Note -- the mapping from Element::Type to string is based on
// enum Element::Type { POINT, SEGMENT, TRIANGLE, QUADRILATERAL,
// TETRAHEDRON, HEXAHEDRON };
+4 -4
View File
@@ -34,10 +34,10 @@ namespace mfem
- HDF5 library, https://support.hdfgroup.org/HDF5
@note The ConduitDataCollection only wraps the mfem objects to save them and
creates them on load, Conduit does not own any of the data. The
SidreDataCollection provides more features, for example the
SidreDataCollection allocates and will own the data backing the mfem objects
in the data collection.
creates them on load, Conduit does not own any of the data.
The MFEMSidreDataCollection in the Axom package (https://github.com/LLNL/axom)
derives from mfem::DataCollection and provides more features, for example
it allocates and will own the data backing the mfem objects in the data collection.
This class also provides public static methods that convert between MFEM
Meshes and GridFunctions and Conduit Mesh Blueprint descriptions.
+11 -8
View File
@@ -90,8 +90,8 @@ void map_quadrature_data_to_fields_impl(
}
else
{
MFEM_ABORT("quadrature data mapping to field is not implemented for"
" this field descriptor");
MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
" for this field descriptor");
}
}
@@ -169,8 +169,9 @@ void map_quadrature_data_to_fields_tensor_impl_1d(
}
else
{
MFEM_ABORT("quadrature data mapping to field is not implemented for"
" this field descriptor with sum factorization on tensor product elements");
MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
"for this field descriptor with sum factorization on"
" tensor product elements");
}
}
@@ -306,8 +307,9 @@ void map_quadrature_data_to_fields_tensor_impl_2d(
}
else
{
MFEM_ABORT("quadrature data mapping to field is not implemented for"
" this field descriptor with sum factorization on tensor product elements");
MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
" for this field descriptor with sum factorization on"
" tensor product elements");
}
}
@@ -492,8 +494,9 @@ void map_quadrature_data_to_fields_tensor_impl_3d(
}
else
{
MFEM_ABORT("quadrature data mapping to field is not implemented for"
" this field descriptor with sum factorization on tensor product elements");
MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
" for this field descriptor with sum factorization on"
" tensor product elements");
}
}
+122 -44
View File
@@ -663,58 +663,59 @@ const
#pragma omp critical (DofToQuad)
#endif
{
// If the new Dof2Quad is already present, e.g. added in a previous call
// or added by another omp thread, return.
// Do not run if the new Dof2Quad is already present, e.g. added in a
// previous call or added by another omp thread.
if (DofToQuad::SearchArray(dof2quad_array, ir,
DofToQuad::LEXICOGRAPHIC_FULL))
{ return; }
// Undo the native ordering which is what FiniteElement::GetDofToQuad
// returns.
auto *d2q_new = new DofToQuad(d2q);
d2q_new->mode = DofToQuad::LEXICOGRAPHIC_FULL;
const int nqpt = ir.GetNPoints();
const int b_dim = (range_type == VECTOR) ? dim : 1;
for (int i = 0; i < nqpt; i++)
DofToQuad::LEXICOGRAPHIC_FULL) == nullptr)
{
for (int d = 0; d < b_dim; d++)
// Undo the native ordering which is what FiniteElement::GetDofToQuad
// returns.
auto *d2q_new = new DofToQuad(d2q);
d2q_new->mode = DofToQuad::LEXICOGRAPHIC_FULL;
const int nqpt = ir.GetNPoints();
const int b_dim = (range_type == VECTOR) ? dim : 1;
for (int i = 0; i < nqpt; i++)
{
for (int j = 0; j < dof; j++)
for (int d = 0; d < b_dim; d++)
{
const double val = d2q.B[i + nqpt*(d+b_dim*lex_ordering[j])];
d2q_new->B[i+nqpt*(d+b_dim*j)] = val;
d2q_new->Bt[j+dof*(i+nqpt*d)] = val;
for (int j = 0; j < dof; j++)
{
const double val = d2q.B[i + nqpt*(d+b_dim*lex_ordering[j])];
d2q_new->B[i+nqpt*(d+b_dim*j)] = val;
d2q_new->Bt[j+dof*(i+nqpt*d)] = val;
}
}
}
}
const int g_dim = [this]()
{
switch (deriv_type)
const int g_dim = [this]()
{
case GRAD: return dim;
case DIV: return 1;
case CURL: return cdim;
default: return 0;
}
}();
for (int i = 0; i < nqpt; i++)
{
for (int d = 0; d < g_dim; d++)
{
for (int j = 0; j < dof; j++)
switch (deriv_type)
{
const double val = d2q.G[i + nqpt*(d+g_dim*lex_ordering[j])];
d2q_new->G[i+nqpt*(d+g_dim*j)] = val;
d2q_new->Gt[j+dof*(i+nqpt*d)] = val;
case GRAD: return dim;
case DIV: return 1;
case CURL: return cdim;
default: return 0;
}
}();
for (int i = 0; i < nqpt; i++)
{
for (int d = 0; d < g_dim; d++)
{
for (int j = 0; j < dof; j++)
{
const double val = d2q.G[i + nqpt*(d+g_dim*lex_ordering[j])];
d2q_new->G[i+nqpt*(d+g_dim*j)] = val;
d2q_new->Gt[j+dof*(i+nqpt*d)] = val;
}
}
}
dof2quad_array.Append(d2q_new);
}
dof2quad_array.Append(d2q_new);
}
}
@@ -1043,9 +1044,50 @@ void VectorFiniteElement::SetDerivMembers()
switch (map_type)
{
case H_DIV:
deriv_type = DIV;
deriv_range_type = SCALAR;
deriv_map_type = INTEGRAL;
switch (dim)
{
case 3: // div: 3D H_DIV -> 3D INTEGRAL
deriv_type = DIV;
deriv_range_type = SCALAR;
deriv_map_type = INTEGRAL;
break;
case 2: // div: 2D H_DIV -> 2D INTEGRAL
deriv_type = DIV;
deriv_range_type = SCALAR;
deriv_map_type = INTEGRAL;
break;
default:
MFEM_ABORT("Invalid dimension, Dim = " << dim);
}
break;
case H_DIV_R2D:
switch (dim)
{
case 2: // div: 2D H_DIV_R2D -> 2D INTEGRAL
deriv_type = DIV;
deriv_range_type = SCALAR;
deriv_map_type = INTEGRAL;
break;
case 1: // div: 1D H_DIV_R2D -> 1D INTEGRAL
deriv_type = DIV;
deriv_range_type = SCALAR;
deriv_map_type = INTEGRAL;
break;
default:
MFEM_ABORT("Invalid dimension, Dim = " << dim);
}
break;
case H_DIV_R1D:
switch (dim)
{
case 1: // div: 1D H_DIV_R1D -> 1D INTEGRAL
deriv_type = DIV;
deriv_range_type = SCALAR;
deriv_map_type = INTEGRAL;
break;
default:
MFEM_ABORT("Invalid dimension, Dim = " << dim);
}
break;
case H_CURL:
switch (dim)
@@ -1063,13 +1105,49 @@ void VectorFiniteElement::SetDerivMembers()
break;
case 1:
deriv_type = NONE;
deriv_range_type = SCALAR;
deriv_map_type = INTEGRAL;
deriv_range_type = UNKNOWN_RANGE_TYPE;
deriv_map_type = UNKNOWN_MAP_TYPE;
break;
default:
MFEM_ABORT("Invalid dimension, Dim = " << dim);
}
break;
case H_CURL_R2D:
switch (dim)
{
case 2:
// curl: 2D H_CURL_R2D -> H_DIV_R2D
deriv_type = CURL;
deriv_range_type = VECTOR;
deriv_map_type = H_DIV_R2D;
break;
case 1:
// curl: 1D H_CURL_R2D -> H_DIV_R2D
deriv_type = CURL;
deriv_range_type = VECTOR;
deriv_map_type = H_DIV_R2D;
break;
default:
MFEM_ABORT("Invalid dimension, Dim = " << dim);
}
break;
case H_CURL_R1D:
switch (dim)
{
case 1:
// curl: 1D H_CURL_R1D -> H_DIV_R1D
deriv_type = CURL;
deriv_range_type = VECTOR;
deriv_map_type = H_DIV_R1D;
break;
case 0:
deriv_type = NONE;
deriv_range_type = UNKNOWN_RANGE_TYPE;
deriv_map_type = UNKNOWN_MAP_TYPE;
default:
MFEM_ABORT("Invalid dimension, Dim = " << dim);
}
break;
default:
MFEM_ABORT("Invalid MapType = " << map_type);
}
+31 -3
View File
@@ -295,10 +295,20 @@ public:
$ u(x) = (1/w) \hat u(\hat x) $ */
H_DIV, /**< For vector fields; preserves surface integrals of the
normal component $ u(x) = (J/w) \hat u(\hat x) $ */
H_CURL /**< For vector fields; preserves line integrals of the
H_CURL, /**< For vector fields; preserves line integrals of the
tangential component
$ u(x) = J^{-t} \hat u(\hat x) $ (square J),
$ u(x) = J(J^t J)^{-1} \hat u(\hat x) $ (general J) */
H_DIV_R2D, /**< For 3-component vector fields in 2D; equivalent to a
direct sum of an H_DIV basis and an INTEGRAL basis */
H_CURL_R2D,/**< For 3-component vector fields in 2D; equivalent to a
direct sum of an H_CURL basis and a VALUE basis */
H_DIV_R1D, /**< For 3-component vector fields in 1D; equivalent to a
direct sum of a VALUE basis and a pair of INTEGRAL
bases */
H_CURL_R1D /**< For 3-component vector fields in 1D; equivalent to a
direct sum of an INTEGRAL basis and a pair of VALUE
bases */
};
/** @brief Enumeration for DerivType: defines which derivative method
@@ -330,12 +340,28 @@ public:
int GetDim() const { return dim; }
/** @brief Returns the vector dimension for vector-valued finite elements,
which is also the dimension of the interpolation operation. */
which is also the dimension of the interpolation operation and the
width of the DenseMatrix argument in
CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape). */
int GetRangeDim() const { return vdim; }
/// Returns the dimension of the curl for vector-valued finite elements.
/** @brief Returns the vector dimension, in physical space, for
vector-valued finite elements, which is also the width of the
DenseMatrix argument in
CalcPhysVShape(ElementTransformation &Trans, DenseMatrix &shape). */
virtual int GetPhysRangeDim(int /* space_dim */) const { return vdim; }
/** Returns the dimension of the curl for vector-valued finite elements,
which is also the width of the DenseMatrix argument in
CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape). */
int GetCurlDim() const { return cdim; }
/** Returns the dimension, in physical space, of the curl for vector-valued
finite elements, which is also the width of the DenseMatrix argument in
CalcPhysCurlShape(ElementTransformation &Trans, DenseMatrix &curl_shape).
*/
virtual int GetPhysCurlDim(int /* space_dim */) const { return cdim; }
/// Returns the Geometry::Type of the reference element.
Geometry::Type GetGeomType() const { return geom_type; }
@@ -990,6 +1016,8 @@ protected:
public:
VectorFiniteElement(int D, Geometry::Type G, int Do, int O, int M,
int F = FunctionSpace::Pk);
int GetPhysRangeDim(int space_dim) const override { return space_dim; }
};
/// @brief Class for computing 1D special polynomials and their associated basis
+1 -1
View File
@@ -589,7 +589,7 @@ void H1_TriangleElement::CalcHessian(const IntegrationPoint &ip,
Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1);
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_l(p + 1);
Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_l(p + 1);
DenseMatrix ddu(dof, dim);
DenseMatrix ddu(dof, (dim*(dim+1))/2);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x);
+4 -4
View File
@@ -2531,7 +2531,7 @@ void ND_FuentesPyramidElement::calcCurlBasis(const int p,
ND_R1D_PointElement::ND_R1D_PointElement(int p)
: VectorFiniteElement(1, Geometry::POINT, 2, p,
H_CURL, FunctionSpace::Pk)
H_CURL_R1D, FunctionSpace::Pk)
{
// VectorFiniteElement::SetDerivMembers doesn't support 0D H_CURL elements
// so we mimic a 1D element and then correct the dimension here.
@@ -2562,7 +2562,7 @@ ND_R1D_SegmentElement::ND_R1D_SegmentElement(const int p,
const int cb_type,
const int ob_type)
: VectorFiniteElement(1, Geometry::SEGMENT, 3 * p + 2, p,
H_CURL, FunctionSpace::Pk),
H_CURL_R1D, FunctionSpace::Pk),
dof2tk(dof),
cbasis1d(poly1d.GetBasis(p, VerifyClosed(cb_type))),
obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(ob_type)))
@@ -2839,7 +2839,7 @@ ND_R2D_SegmentElement::ND_R2D_SegmentElement(const int p,
const int cb_type,
const int ob_type)
: VectorFiniteElement(1, Geometry::SEGMENT, 2 * p + 1, p,
H_CURL, FunctionSpace::Pk),
H_CURL_R2D, FunctionSpace::Pk),
dof2tk(dof),
cbasis1d(poly1d.GetBasis(p, VerifyClosed(cb_type))),
obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(ob_type)))
@@ -3023,7 +3023,7 @@ void ND_R2D_SegmentElement::Project(VectorCoefficient &vc,
ND_R2D_FiniteElement::ND_R2D_FiniteElement(int p, Geometry::Type G, int Do,
const real_t *tk_fe)
: VectorFiniteElement(2, G, Do, p,
H_CURL, FunctionSpace::Pk),
H_CURL_R2D, FunctionSpace::Pk),
tk(tk_fe),
dof_map(dof),
dof2tk(dof)
+6
View File
@@ -663,6 +663,9 @@ public:
const int cb_type = BasisType::GaussLobatto,
const int ob_type = BasisType::GaussLegendre);
int GetPhysRangeDim(int space_dim) const override { return 2; }
int GetPhysCurlDim(int space_dim) const override { return 1; }
void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const override;
@@ -705,6 +708,9 @@ private:
DenseMatrix &I) const;
public:
int GetPhysRangeDim(int space_dim) const override { return 3; }
int GetPhysCurlDim(int space_dim) const override { return 3; }
using FiniteElement::CalcVShape;
using FiniteElement::CalcPhysCurlShape;
+3 -3
View File
@@ -2006,7 +2006,7 @@ RT_R1D_SegmentElement::RT_R1D_SegmentElement(const int p,
const int cb_type,
const int ob_type)
: VectorFiniteElement(1, Geometry::SEGMENT, 3 * p + 4, p + 1,
H_DIV, FunctionSpace::Pk),
H_DIV_R1D, FunctionSpace::Pk),
dof2nk(dof),
cbasis1d(poly1d.GetBasis(p + 1, VerifyClosed(cb_type))),
obasis1d(poly1d.GetBasis(p, VerifyOpen(ob_type)))
@@ -2281,7 +2281,7 @@ const real_t RT_R2D_SegmentElement::nk[2] = { 0.,1.};
RT_R2D_SegmentElement::RT_R2D_SegmentElement(const int p,
const int ob_type)
: VectorFiniteElement(1, Geometry::SEGMENT, p + 1, p + 1,
H_DIV, FunctionSpace::Pk),
H_DIV_R2D, FunctionSpace::Pk),
dof2nk(dof),
obasis1d(poly1d.GetBasis(p, VerifyOpen(ob_type)))
{
@@ -2392,7 +2392,7 @@ void RT_R2D_SegmentElement::LocalInterpolation(const VectorFiniteElement &cfe,
RT_R2D_FiniteElement::RT_R2D_FiniteElement(int p, Geometry::Type G, int Do,
const real_t *nk_fe)
: VectorFiniteElement(2, G, Do, p + 1,
H_DIV, FunctionSpace::Pk),
H_DIV_R2D, FunctionSpace::Pk),
nk(nk_fe),
dof_map(dof),
dof2nk(dof)
+6
View File
@@ -510,6 +510,9 @@ public:
RT_R2D_SegmentElement(const int p,
const int ob_type = BasisType::GaussLegendre);
int GetPhysRangeDim(int space_dim) const override { return 2; }
int GetPhysCurlDim(int space_dim) const override { return 0; }
void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const override;
@@ -547,6 +550,9 @@ private:
DenseMatrix &I) const;
public:
int GetPhysRangeDim(int space_dim) const override { return 3; }
int GetPhysCurlDim(int space_dim) const override { return 0; }
using FiniteElement::CalcVShape;
void CalcVShape(ElementTransformation &Trans,
-4
View File
@@ -62,10 +62,6 @@
#include "pnonlinearform.hpp"
#endif
#ifdef MFEM_USE_SIDRE
#include "sidredatacollection.hpp"
#endif
#ifdef MFEM_USE_CONDUIT
#include "conduitdatacollection.hpp"
#endif
+28 -19
View File
@@ -282,14 +282,7 @@ int FiniteElementSpace::DofToVDof(int dof, int vd, int ndofs_) const
void FiniteElementSpace::AdjustVDofs(Array<int> &vdofs)
{
int n = vdofs.Size(), *vdof = vdofs;
for (int i = 0; i < n; i++)
{
int j;
if ((j = vdof[i]) < 0)
{
vdof[i] = -1-j;
}
}
for (int i = 0; i < n; i++) { vdof[i] = UnsignIndex(vdof[i]); }
}
void FiniteElementSpace::GetElementVDofs(int i, Array<int> &vdofs,
@@ -483,13 +476,14 @@ void FiniteElementSpace::ReorderElementToDofTable()
for (int k = 0, dof_counter = 0; k < nnz; k++)
{
const int sdof = J[k]; // signed dof
const int dof = (sdof < 0) ? -1-sdof : sdof;
const int dof = UnsignIndex(sdof);
int new_dof = dof_marker[dof];
if (new_dof < 0)
{
dof_marker[dof] = new_dof = dof_counter++;
}
J[k] = (sdof < 0) ? -1-new_dof : new_dof; // preserve the sign of sdof
// Preserve the sign of sdof
J[k] = (sdof < 0) ? FlipIndexSign(new_dof) : new_dof;
}
}
@@ -547,7 +541,7 @@ void MarkDofs(const Array<int> &dofs, Array<int> &mark_array)
{
for (auto d : dofs)
{
mark_array[d >= 0 ? d : -1 - d] = -1;
mark_array[UnsignIndex(d)] = -1;
}
}
@@ -931,7 +925,7 @@ void FiniteElementSpace::AddDependencies(
if (std::abs(coef) > 1e-12)
{
const int mdof = master_dofs[j];
if (mdof != sdof && mdof != (-1-sdof))
if (mdof != sdof && mdof != FlipIndexSign(sdof))
{
deps.Add(sdof, mdof, coef);
}
@@ -1024,7 +1018,7 @@ int FiniteElementSpace::GetDegenerateFaceDofs(int index, Array<int> &dofs,
// FiniteElementSpace::AddDependencies.
Array<int> edof;
int order = GetEdgeDofs(-1 - index, edof, variant);
int order = GetEdgeDofs(FlipIndexSign(index), edof, variant);
int nv = fec->DofForGeometry(Geometry::POINT);
int ne = fec->DofForGeometry(Geometry::SEGMENT);
@@ -1710,8 +1704,8 @@ SparseMatrix *FiniteElementSpace::RefinementMatrix_main(
for (int i = 0; i < fine_ldof; i++)
{
int r = DofToVDof(dofs[i], vd);
int m = (r >= 0) ? r : (-1 - r);
const int r = DofToVDof(dofs[i], vd);
const int m = UnsignIndex(r);
if (!mark[m])
{
@@ -1772,7 +1766,7 @@ SparseMatrix *FiniteElementSpace::VariableOrderRefinementMatrix(
for (int i = 0; i < fine_ldof; i++)
{
const int r = DofToVDof(dofs[i], vd);
int m = (r >= 0) ? r : (-1 - r);
const int m = UnsignIndex(r);
if (!mark[m])
{
@@ -2482,8 +2476,8 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
{
if (!std::isfinite(lR(i, 0))) { continue; }
int r = DofToVDof(dofs[i], vd);
int m = (r >= 0) ? r : (-1 - r);
const int r = DofToVDof(dofs[i], vd);
const int m = UnsignIndex(r);
if (is_dg || !mark[m])
{
@@ -3201,7 +3195,7 @@ void FiniteElementSpace::CalcEdgeFaceVarOrders(
else
{
// degenerate face (i.e., edge-face constraint)
slave_orders |= edge_orders[-1 - slave.index];
slave_orders |= edge_orders[FlipIndexSign(slave.index)];
}
}
@@ -3940,6 +3934,16 @@ const FiniteElement *FiniteElementSpace::GetBE(int i) const
return BE;
}
const FiniteElement *FiniteElementSpace::GetTypicalBE() const
{
if (mesh->GetNBE() > 0) { return GetBE(0); }
Geometry::Type geom = mesh->GetTypicalFaceGeometry();
const FiniteElement *be = fec->FiniteElementForGeometry(geom);
MFEM_VERIFY(be != nullptr, "Could not determine a typical BE!");
return be;
}
const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const
{
MFEM_VERIFY(!IsVariableOrder(), "not implemented");
@@ -3970,6 +3974,11 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const
return fe;
}
const FiniteElement *FiniteElementSpace::GetTypicalFaceElement() const
{
return fec->FiniteElementForGeometry(mesh->GetTypicalFaceGeometry());
}
const FiniteElement *FiniteElementSpace::GetEdgeElement(int i,
int variant) const
{
+14 -2
View File
@@ -839,7 +839,7 @@ public:
Note: For vector-valued elements, the results pads up the range dimension
to the spatial dimension. E.g., consider a stack of 5 vector-valued
elements each representing 2D vectors, living in a 3 dimensional space.
Then this fucntion would give 15, not 10.
Then this function would give 15, not 10.
*/
int GetVectorDim() const;
@@ -1150,7 +1150,7 @@ public:
/// Helper to return the DOF associated with a sign encoded DOF
static inline int DecodeDof(int dof)
{ return (dof >= 0) ? dof : (-1 - dof); }
{ return UnsignIndex(dof); }
/// Helper to determine the DOF and sign of a sign encoded DOF
static inline int DecodeDof(int dof, real_t& sign)
@@ -1323,12 +1323,24 @@ public:
associated with i'th boundary face in the mesh object. */
const FiniteElement *GetBE(int i) const;
/// @brief Return a "typical" boundary element.
///
/// This can be used in situations where the local mesh partition may be
/// empty.
const FiniteElement *GetTypicalBE() const;
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th face in the mesh object. Faces in this case refer
to the MESHDIM-1 primitive so in 2D they are segments and in 1D they are
points.*/
const FiniteElement *GetFaceElement(int i) const;
/// @brief Return a "typical" face element.
///
/// This can be used in situations where the local mesh partition may be
/// empty.
const FiniteElement *GetTypicalFaceElement() const;
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th edge in the mesh object. */
const FiniteElement *GetEdgeElement(int i, int variant = 0) const;
+633 -64
View File
@@ -30,6 +30,7 @@
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
namespace mfem
{
@@ -344,27 +345,6 @@ void GridFunction::ComputeFlux(BilinearFormIntegrator &blfi,
}
}
int GridFunction::VectorDim() const
{
const FiniteElement *fe = fes->GetTypicalFE();
if (!fe || fe->GetRangeType() == FiniteElement::SCALAR)
{
return fes->GetVDim();
}
return fes->GetVDim()*std::max(fes->GetMesh()->SpaceDimension(),
fe->GetRangeDim());
}
int GridFunction::CurlDim() const
{
const FiniteElement *fe = fes->GetTypicalFE();
if (!fe || fe->GetRangeType() == FiniteElement::SCALAR)
{
return 2 * fes->GetMesh()->SpaceDimension() - 3;
}
return fes->GetVDim()*fe->GetCurlDim();
}
void GridFunction::GetTrueDofs(Vector &tv) const
{
const SparseMatrix *R = fes->GetRestrictionMatrix();
@@ -2049,6 +2029,18 @@ void GridFunction::AccumulateAndCountBdrValues(
Coefficient *coeff[], VectorCoefficient *vcoeff, const Array<int> &attr,
Array<int> &values_counter)
{
if (vcoeff)
{
MFEM_VERIFY(fes->GetVDim() == vcoeff->GetVDim(),
"vcoeff vdim != fes VDim");
MFEM_VERIFY(fes->GetTypicalBE()->GetMapType() == FiniteElement::VALUE &&
fes->GetTypicalBE()->GetRangeType() ==
FiniteElement::SCALAR,
"Can only call ProjectBdrCoefficient on scalar value-type "
"boundary elements. "
"Did you intended to call ProjectBdrCoefficientNormal or "
"ProjectBdrCoefficientTangent for vector finite elements?");
}
Array<int> vdofs;
Vector vc;
@@ -2201,6 +2193,9 @@ void GridFunction::AccumulateAndCountBdrTangentValues(
VectorCoefficient &vcoeff, const Array<int> &bdr_attr,
Array<int> &values_counter)
{
MFEM_VERIFY(fes->GetTypicalBE()->GetPhysRangeDim(
fes->GetMesh()->SpaceDimension()) == vcoeff.GetVDim(),
"vcoeff vdim != PhysRangeDim");
const FiniteElement *fe;
ElementTransformation *T;
Array<int> dofs;
@@ -2354,6 +2349,9 @@ void GridFunction::ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff,
void GridFunction::ProjectCoefficient(Coefficient &coeff, ProjectType type)
{
MFEM_VERIFY(
VectorDim() == 1,
"Cannot project scalar Coefficient onto vector GridFunction");
DeltaCoefficient *delta_c = dynamic_cast<DeltaCoefficient *>(&coeff);
DofTransformation doftrans;
Array<int> vdofs;
@@ -2629,6 +2627,7 @@ void GridFunction::ProjectCoefficient(
void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff,
ProjectType type)
{
MFEM_VERIFY(VectorDim() == vcoeff.GetVDim(), "vcoeff vdim != VectorDim()");
Array<int> vdofs;
Vector vals;
DofTransformation doftrans;
@@ -2944,6 +2943,7 @@ void GridFunction::ProjectCoefficientElementL2(VectorCoefficient &vcoeff)
void GridFunction::ProjectCoefficient(
VectorCoefficient &vcoeff, Array<int> &dofs)
{
MFEM_VERIFY(VectorDim() == vcoeff.GetVDim(), "vcoeff vdim != VectorDim()");
int el = -1;
ElementTransformation *T = NULL;
const FiniteElement *fe = NULL;
@@ -2973,6 +2973,7 @@ void GridFunction::ProjectCoefficient(
void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff, int attribute)
{
MFEM_VERIFY(VectorDim() == vcoeff.GetVDim(), "vcoeff vdim != VectorDim()");
int i;
Array<int> vdofs;
Vector vals;
@@ -3032,6 +3033,7 @@ void GridFunction::ProjectCoefficient(Coefficient *coeff[])
void GridFunction::ProjectDiscCoefficient(VectorCoefficient &coeff,
Array<int> &dof_attr)
{
MFEM_VERIFY(VectorDim() == coeff.GetVDim(), "coeff vdim != VectorDim()");
Array<int> vdofs;
Vector vals;
@@ -3063,6 +3065,7 @@ void GridFunction::ProjectDiscCoefficient(VectorCoefficient &coeff,
void GridFunction::ProjectDiscCoefficient(VectorCoefficient &coeff)
{
MFEM_VERIFY(VectorDim() == coeff.GetVDim(), "coeff vdim != VectorDim()");
Array<int> dof_attr;
ProjectDiscCoefficient(coeff, dof_attr);
}
@@ -3072,6 +3075,10 @@ void GridFunction::ProjectDiscCoefficient(Coefficient &coeff, AvgType type)
// Harmonic (x1 ... xn) = [ (1/x1 + ... + 1/xn) / n ]^-1.
// Arithmetic(x1 ... xn) = (x1 + ... + xn) / n.
MFEM_VERIFY(
VectorDim() == 1,
"Cannot project a scalar coefficient onto a vector GridFunction");
Array<int> zones_per_vdof;
AccumulateAndCountZones(coeff, type, zones_per_vdof);
@@ -3081,6 +3088,7 @@ void GridFunction::ProjectDiscCoefficient(Coefficient &coeff, AvgType type)
void GridFunction::ProjectDiscCoefficient(VectorCoefficient &coeff,
AvgType type)
{
MFEM_VERIFY(VectorDim() == coeff.GetVDim(), "coeff vdim != VectorDim()");
Array<int> zones_per_vdof;
AccumulateAndCountZones(coeff, type, zones_per_vdof);
@@ -3136,52 +3144,33 @@ void GridFunction::ProjectBdrCoefficient(Coefficient *coeff[],
}
void GridFunction::ProjectBdrCoefficientNormal(
VectorCoefficient &vcoeff, const Array<int> &bdr_attr)
Coefficient *coeff, VectorCoefficient *vcoeff, const Array<int> &bdr_attr)
{
#if 0
// implementation for the case when the face dofs are integrals of the
// normal component.
const FiniteElement *fe;
ElementTransformation *T;
Array<int> dofs;
int dim = vcoeff.GetVDim();
Vector vc(dim), nor(dim), lvec, shape;
for (int i = 0; i < fes->GetNBE(); i++)
MFEM_VERIFY(fes->GetVDim() == 1, "fespace VDim != 1");
MFEM_VERIFY(fes->GetTypicalBE()->GetRangeType() == FiniteElement::SCALAR &&
fes->GetTypicalBE()->GetMapType() == FiniteElement::INTEGRAL,
"Not an RT FE space!");
if (vcoeff)
{
if (bdr_attr[fes->GetBdrAttribute(i)-1] == 0)
{
continue;
}
fe = fes->GetBE(i);
T = fes->GetBdrElementTransformation(i);
int intorder = 2*fe->GetOrder(); // !!!
const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), intorder);
int nd = fe->GetDof();
lvec.SetSize(nd);
shape.SetSize(nd);
lvec = 0.0;
for (int j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
T->SetIntPoint(&ip);
vcoeff.Eval(vc, *T, ip);
CalcOrtho(T->Jacobian(), nor);
fe->CalcShape(ip, shape);
lvec.Add(ip.weight * (vc * nor), shape);
}
fes->GetBdrElementDofs(i, dofs);
SetSubVector(dofs, lvec);
MFEM_VERIFY(vcoeff->GetVDim() == fes->GetMesh()->SpaceDimension(),
"vcoeff vdim (" << vcoeff->GetVDim()
<< ") != SpaceDimension ("
<< fes->GetMesh()->SpaceDimension() << ")");
}
#else
// implementation for the case when the face dofs are scaled point
// values of the normal component.
const FiniteElement *fe;
ElementTransformation *T;
Array<int> dofs;
int dim = vcoeff.GetVDim();
Vector vc(dim), nor(dim), lvec;
Vector vc, nor, lvec;
DofTransformation doftrans;
if (vcoeff)
{
const int dim = vcoeff->GetVDim();
vc.SetSize(dim);
nor.SetSize(dim);
}
for (int i = 0; i < fes->GetNBE(); i++)
{
@@ -3197,15 +3186,22 @@ void GridFunction::ProjectBdrCoefficientNormal(
{
const IntegrationPoint &ip = ir.IntPoint(j);
T->SetIntPoint(&ip);
vcoeff.Eval(vc, *T, ip);
CalcOrtho(T->Jacobian(), nor);
lvec(j) = (vc * nor);
if (coeff)
{
const real_t c = coeff->Eval(*T, ip);
lvec(j) = c * T->Weight();
}
else if (vcoeff)
{
vcoeff->Eval(vc, *T, ip);
CalcOrtho(T->Jacobian(), nor);
lvec(j) = (vc * nor);
}
}
fes->GetBdrElementDofs(i, dofs, doftrans);
doftrans.TransformPrimal(lvec);
SetSubVector(dofs, lvec);
}
#endif
}
void GridFunction::ProjectBdrCoefficientTangent(
@@ -5006,6 +5002,14 @@ real_t ExtrudeCoefficient::Eval(ElementTransformation &T,
return sol_in.Eval(*T_in, ip);
}
void VectorExtrudeCoefficient::Eval(Vector &v, ElementTransformation &T,
const IntegrationPoint &ip)
{
ElementTransformation *T_in =
mesh_in->GetElementTransformation(T.ElementNo / n);
T_in->SetIntPoint(&ip);
sol_in.Eval(v, *T_in, ip);
}
GridFunction *Extrude1DGridFunction(Mesh *mesh, Mesh *mesh2d,
GridFunction *sol, const int ny)
@@ -5056,10 +5060,17 @@ GridFunction *Extrude1DGridFunction(Mesh *mesh, Mesh *mesh2d,
return NULL;
}
FiniteElementSpace *solfes2d;
// assuming sol is scalar
solfes2d = new FiniteElementSpace(mesh2d, solfec2d);
const int vdim = sol->FESpace()->GetVDim();
solfes2d = new FiniteElementSpace(mesh2d, solfec2d, vdim);
sol2d = new GridFunction(solfes2d);
sol2d->MakeOwner(solfec2d);
if (vdim > 1)
{
VectorGridFunctionCoefficient vcsol(sol);
VectorExtrudeCoefficient vc2d(mesh, vcsol, ny);
sol2d->ProjectCoefficient(vc2d);
}
else
{
GridFunctionCoefficient csol(sol);
ExtrudeCoefficient c2d(mesh, csol, ny);
@@ -5117,6 +5128,103 @@ void GridFunction::GetElementBoundsAtControlPoints(const int elem,
}
}
void GridFunction::GetElementBoundsAtControlPoints(const int elem,
const PLBound &plb,
const Vector &ref_range,
const int vdim,
Vector &lower, Vector &upper,
Vector &control_pos) const
{
const FiniteElement *fe = fes->GetFE(elem);
const IntegrationRule ir_in = fe->GetNodes();
IntegrationRule ir_new(ir_in.GetNPoints());
const int dim = fes->GetMesh()->Dimension();
const L2_FECollection *l2fec = dynamic_cast<const L2_FECollection *>
(fes->FEColl());
const TensorBasisElement *tbe =
dynamic_cast<const TensorBasisElement *>(fe);
MFEM_VERIFY(tbe != NULL, "TensorBasis FiniteElement expected.");
const Array<int> &dof_map = tbe->GetDofMap();
bool lexico = (dof_map.Size() == 0);
bool bern = (tbe->GetBasisType() == BasisType::Positive);
bool h1 = (l2fec == nullptr);
Vector loc_data; // gridfunction values
// Construct an integration rule to evaluate the gridfunction in
// subinterval.
for (int i = 0; i < ir_in.GetNPoints(); i++)
{
IntegrationPoint &ip_new = ir_new.IntPoint(i);
const IntegrationPoint &ip_old =
ir_in.IntPoint((lexico || bern) ? i : dof_map[i]);
Vector ip_coord(dim);
ip_old.Get(ip_coord.GetData(), dim);
for (int d = 0; d < dim; d++)
{
ip_coord(d) = ref_range(d) +
(ref_range(dim+d) - ref_range(d)) * ip_coord(d);
}
ip_new.Set(ip_coord.GetData(), dim);
}
GetValues(elem, ir_new, loc_data, vdim);
// At this point, the loc_data contains function values ordered
// lexicographically, unless we are using Bernstein bases.
// For Bernstein, we need to project and get coefficients first.
// For bernstein, we get coefficients corresponding to these function values
if (bern)
{
int bt = 4; // BasisType::ClosedUniform
int o = fe->GetOrder();
DenseMatrix projmat;
NodalTensorFiniteElement *ntfe = nullptr;
if (dim == 1)
{
if (h1) { ntfe = new H1_SegmentElement(o, bt); }
else { ntfe = new L2_SegmentElement(o, bt); }
}
else if (dim == 2)
{
if (h1) { ntfe = new H1_QuadrilateralElement(o, bt); }
else { ntfe = new L2_QuadrilateralElement(o, bt); }
}
else if (dim == 3)
{
if (h1) { ntfe = new H1_HexahedronElement(o, bt); }
else { ntfe = new L2_HexahedronElement(o, bt); }
}
// projection matrix from H1 to Positive
ElementTransformation *eltran = fes->GetElementTransformation(elem);
fe->Project(*ntfe, *eltran, projmat);
Vector loc_data_temp(loc_data.Size());
projmat.Mult(loc_data, loc_data_temp);
for (int i = 0; i < dof_map.Size(); i++)
{
loc_data(i) = loc_data_temp(dof_map[i]);
}
if (dof_map.Size() == 0) { loc_data = loc_data_temp; }
delete ntfe;
}
// Get bounds at control points
plb.GetNDBounds(dim, loc_data, lower, upper);
// Save control point positions
int ncp = plb.GetNControlPoints();
control_pos.SetSize(dim * ncp);
const Vector control_pos_1D = plb.GetControlPoints();
for (int i = 0; i < ncp; i++)
{
for (int d = 0; d < dim; d++)
{
control_pos(i + d*ncp) =
ref_range(d) + (ref_range(dim+d)-ref_range(d))*control_pos_1D(i);
}
}
}
void GridFunction::GetElementBounds(const int elem, const PLBound &plb,
Vector &lower, Vector &upper,
const int vdim) const
@@ -5197,6 +5305,467 @@ PLBound GridFunction::GetBounds(Vector &lower, Vector &upper,
return plb;
}
struct IntervalNode
{
real_t val_min;
real_t val_max;
Array<IntervalNode *> child;
IntervalNode(real_t vmin, real_t vmax)
: val_min(vmin), val_max(vmax)
{
child.SetSize(0);
}
void AddChild(IntervalNode *ch) { child.Append(ch); }
real_t GetChildMinLower()
{
if (child.Size() == 0)
{
return val_min;
}
real_t valmin = numeric_limits<real_t>::max();
for (int i = 0; i < child.Size(); i++)
{
real_t candidate = child[i]->GetChildMinLower();
valmin = std::min(valmin, candidate);
}
return valmin;
}
real_t GetChildMinUpper()
{
if (child.Size() == 0)
{
return val_max;
}
real_t valmax = numeric_limits<real_t>::max();
for (int i = 0; i < child.Size(); i++)
{
real_t candidate = child[i]->GetChildMinUpper();
valmax = std::min(valmax, candidate);
}
return valmax;
}
real_t GetChildMaxLower()
{
if (child.Size() == 0)
{
return val_min;
}
real_t valmin = numeric_limits<real_t>::lowest();
for (int i = 0; i < child.Size(); i++)
{
real_t candidate = child[i]->GetChildMaxLower();
valmin = std::max(valmin, candidate);
}
return valmin;
}
real_t GetChildMaxUpper()
{
if (child.Size() == 0)
{
return val_max;
}
real_t valmax = numeric_limits<real_t>::lowest();
for (int i = 0; i < child.Size(); i++)
{
real_t candidate = child[i]->GetChildMaxUpper();
valmax = std::max(valmax, candidate);
}
return valmax;
}
void DeleteChildren()
{
for (int i = 0; i < child.Size(); i++)
{
child[i]->DeleteChildren();
delete child[i];
}
child.SetSize(0);
}
};
struct SearchInterval
{
Vector ref_range;
int depth;
IntervalNode *node;
SearchInterval(const Vector &ref_range_in, int d, IntervalNode *n)
: ref_range(ref_range_in), depth(d), node(n)
{ }
};
struct IntervalCompareMin
{
bool operator()(const SearchInterval *a, const SearchInterval *b) const
{
return a->node->val_min > b->node->val_min;
}
};
struct IntervalCompareMax
{
bool operator()(const SearchInterval *a, const SearchInterval *b) const
{
return a->node->val_max < b->node->val_max;
}
};
std::pair<real_t, real_t> GridFunction::EstimateFunctionMinimum(
const int elem, const PLBound &plb, const int vdim,
const int max_depth, const real_t tol) const
{
real_t min_threshold = std::numeric_limits<real_t>::max();
return EstimateFunctionMinimum(elem, plb, vdim, max_depth, tol,
min_threshold);
}
std::pair<real_t, real_t> GridFunction::EstimateFunctionMinimum(
const int elem, const PLBound &plb, const int vdim,
const int max_depth, const real_t tol, real_t &min_threshold) const
{
const int dim = this->FESpace()->GetMesh()->Dimension();
const int ncp = plb.GetNControlPoints();
Vector pos_range(2*dim); pos_range = 0.0;
for (int d = 0; d < dim; d++) { pos_range(d+dim) = 1.0; }
Vector lower, upper, cp_ref_loc;
GetElementBoundsAtControlPoints(elem, plb, lower, upper, vdim);
real_t val_min = lower.Min();
real_t val_max = upper.Min();
min_threshold = std::min(min_threshold, val_max);
// Pruning: if the element's lower bound is greater than the current global
// upper bound, this element cannot contain the global minimum.
if (val_min >= min_threshold)
{
return std::make_pair(val_min, val_max);
}
if (val_min == val_max || max_depth == 0)
{
min_threshold = std::min(min_threshold, val_min);
return std::make_pair(val_min, val_max);
}
real_t abs_tol = tol*(val_max-val_min);
IntervalNode *initial_node = new IntervalNode(val_min, val_max);
SearchInterval *initial_interval = new SearchInterval(pos_range, 0,
initial_node);
std::priority_queue<SearchInterval*,
std::vector<SearchInterval*>, IntervalCompareMin> pq;
pq.push(initial_interval);
real_t min_upper_bound = upper.Min();
real_t min_lower_bound = lower.Min();
while (!pq.empty())
{
SearchInterval *current = pq.top();
pq.pop();
int curr_depth = current->depth;
// Reached max depth or this interval cannot contain the global minimum
if (current->node->val_min >= min_threshold || curr_depth >= max_depth)
{
delete current;
continue;
}
min_lower_bound = initial_node->GetChildMinLower();
if (min_upper_bound - min_lower_bound < abs_tol)
{
delete current;
break;
}
// Subdivide the interval and get bounds on it
GetElementBoundsAtControlPoints(elem, plb, current->ref_range,
vdim, lower, upper, cp_ref_loc);
// process the bounds and create sub-intervals
for (int k = 0; k < (dim == 3 ? ncp-1 : 1); k++)
{
for (int j = 0; j < (dim >= 2 ? ncp-1 : 1); j++)
{
for (int i = 0; i < ncp-1; i++)
{
real_t lv = 0.0, uv = 0.0;
if (dim == 1)
{
lv = std::min(lower(i), lower(i+1));
uv = std::min(upper(i), upper(i+1));
}
else if (dim == 2)
{
lv = std::min({lower(i + j*ncp), lower((i+1) + j*ncp),
lower(i + (j+1)*ncp),
lower((i+1) + (j+1)*ncp)});
uv = std::min({upper(i + j*ncp), upper((i+1) + j*ncp),
upper(i + (j+1)*ncp),
upper((i+1) + (j+1)*ncp)});
}
else if (dim == 3)
{
lv = std::min({lower(i + j*ncp + k*ncp*ncp),
lower((i+1) + j*ncp + k*ncp*ncp),
lower(i + (j+1)*ncp + k*ncp*ncp),
lower((i+1) + (j+1)*ncp + k*ncp*ncp),
lower(i + j*ncp + (k+1)*ncp*ncp),
lower((i+1) + j*ncp + (k+1)*ncp*ncp),
lower(i + (j+1)*ncp + (k+1)*ncp*ncp),
lower((i+1) + (j+1)*ncp + (k+1)*ncp*ncp)});
uv = std::min({upper(i + j*ncp + k*ncp*ncp),
upper((i+1) + j*ncp + k*ncp*ncp),
upper(i + (j+1)*ncp + k*ncp*ncp),
upper((i+1) + (j+1)*ncp + k*ncp*ncp),
upper(i + j*ncp + (k+1)*ncp*ncp),
upper((i+1) + j*ncp + (k+1)*ncp*ncp),
upper(i + (j+1)*ncp + (k+1)*ncp*ncp),
upper((i+1) + (j+1)*ncp + (k+1)*ncp*ncp)});
}
IntervalNode *child_node = new IntervalNode(lv, uv);
current->node->AddChild(child_node);
if (lv < min_threshold)
{
min_upper_bound = std::min(min_upper_bound, uv);
min_threshold = std::min(min_threshold, uv);
if (curr_depth < max_depth)
{
pos_range(0) = cp_ref_loc(i);
pos_range(0+dim) = cp_ref_loc(i+1);
if (dim >= 2)
{
pos_range(1) = cp_ref_loc(ncp + j);
pos_range(1+dim) = cp_ref_loc(ncp + j+1);
}
if (dim == 3)
{
pos_range(2) = cp_ref_loc(2*ncp + k);
pos_range(2+dim) = cp_ref_loc(2*ncp + k+1);
}
SearchInterval *child_interval =
new SearchInterval(pos_range, curr_depth + 1,
child_node);
pq.push(child_interval);
}
}
}
}
}
delete current;
}
// clean up remaining intervals in queue
while (!pq.empty())
{
delete pq.top();
pq.pop();
}
min_lower_bound = initial_node->GetChildMinLower();
initial_node->DeleteChildren();
delete initial_node;
min_threshold = std::min(min_threshold, min_lower_bound);
return std::make_pair(min_lower_bound, min_upper_bound);
}
std::pair<real_t, real_t> GridFunction::EstimateFunctionMaximum(
const int elem, const PLBound &plb, const int vdim,
const int max_depth, const real_t tol) const
{
real_t max_threshold = std::numeric_limits<real_t>::lowest();
return EstimateFunctionMaximum(elem, plb, vdim, max_depth, tol,
max_threshold);
}
std::pair<real_t, real_t> GridFunction::EstimateFunctionMaximum(
const int elem, const PLBound &plb, const int vdim,
const int max_depth, const real_t tol, real_t &max_threshold) const
{
const int dim = this->FESpace()->GetMesh()->Dimension();
const int ncp = plb.GetNControlPoints();
Vector pos_range(2*dim); pos_range = 0.0;
for (int d = 0; d < dim; d++) { pos_range(d+dim) = 1.0; }
Vector lower, upper, cp_ref_loc;
GetElementBoundsAtControlPoints(elem, plb, lower, upper, vdim);
real_t val_min = lower.Max();
real_t val_max = upper.Max();
max_threshold = std::max(max_threshold, val_min);
// Pruning: if the element's upper bound is less than the current global
// lower bound, this element cannot contain the global maximum.
if (val_max <= max_threshold)
{
return std::make_pair(val_min, val_max);
}
if (val_min == val_max || max_depth == 0)
{
max_threshold = std::max(max_threshold, val_max);
return std::make_pair(val_min, val_max);
}
real_t abs_tol = tol*(val_max-val_min);
IntervalNode *initial_node = new IntervalNode(val_min, val_max);
SearchInterval *initial_interval = new SearchInterval(pos_range, 0,
initial_node);
std::priority_queue<SearchInterval*,
std::vector<SearchInterval*>, IntervalCompareMax> pq;
pq.push(initial_interval);
real_t max_lower_bound = val_min;
real_t max_upper_bound = val_max;
while (!pq.empty())
{
SearchInterval *current = pq.top();
pq.pop();
int curr_depth = current->depth;
// Reached max depth or this interval cannot contain the global maximum.
if (current->node->val_max <= max_threshold || curr_depth >= max_depth)
{
delete current;
continue;
}
max_upper_bound = initial_node->GetChildMaxUpper();
if (max_upper_bound - max_lower_bound < abs_tol)
{
delete current;
break;
}
// Subdivide the interval and get bounds on it
GetElementBoundsAtControlPoints(elem, plb, current->ref_range,
vdim, lower, upper, cp_ref_loc);
// process the bounds and create sub-intervals
for (int k = 0; k < (dim == 3 ? ncp-1 : 1); k++)
{
for (int j = 0; j < (dim >= 2 ? ncp-1 : 1); j++)
{
for (int i = 0; i < ncp-1; i++)
{
real_t lv = 0.0, uv = 0.0;
if (dim == 1)
{
lv = std::max(lower(i), lower(i+1));
uv = std::max(upper(i), upper(i+1));
}
else if (dim == 2)
{
lv = std::max({lower(i + j*ncp), lower((i+1) + j*ncp),
lower(i + (j+1)*ncp),
lower((i+1) + (j+1)*ncp)});
uv = std::max({upper(i + j*ncp), upper((i+1) + j*ncp),
upper(i + (j+1)*ncp),
upper((i+1) + (j+1)*ncp)});
}
else if (dim == 3)
{
lv = std::max({lower(i + j*ncp + k*ncp*ncp),
lower((i+1) + j*ncp + k*ncp*ncp),
lower(i + (j+1)*ncp + k*ncp*ncp),
lower((i+1) + (j+1)*ncp + k*ncp*ncp),
lower(i + j*ncp + (k+1)*ncp*ncp),
lower((i+1) + j*ncp + (k+1)*ncp*ncp),
lower(i + (j+1)*ncp + (k+1)*ncp*ncp),
lower((i+1) + (j+1)*ncp + (k+1)*ncp*ncp)});
uv = std::max({upper(i + j*ncp + k*ncp*ncp),
upper((i+1) + j*ncp + k*ncp*ncp),
upper(i + (j+1)*ncp + k*ncp*ncp),
upper((i+1) + (j+1)*ncp + k*ncp*ncp),
upper(i + j*ncp + (k+1)*ncp*ncp),
upper((i+1) + j*ncp + (k+1)*ncp*ncp),
upper(i + (j+1)*ncp + (k+1)*ncp*ncp),
upper((i+1) + (j+1)*ncp + (k+1)*ncp*ncp)});
}
IntervalNode *child_node = new IntervalNode(lv, uv);
current->node->AddChild(child_node);
if (uv > max_threshold)
{
max_lower_bound = std::max(max_lower_bound, lv);
max_threshold = std::max(max_threshold, lv);
if (curr_depth < max_depth)
{
pos_range(0) = cp_ref_loc(i);
pos_range(0+dim) = cp_ref_loc(i+1);
if (dim >= 2)
{
pos_range(1) = cp_ref_loc(ncp + j);
pos_range(1+dim) = cp_ref_loc(ncp + j+1);
}
if (dim == 3)
{
pos_range(2) = cp_ref_loc(2*ncp + k);
pos_range(2+dim) = cp_ref_loc(2*ncp + k+1);
}
SearchInterval *child_interval =
new SearchInterval(pos_range, curr_depth + 1,
child_node);
pq.push(child_interval);
}
}
}
}
}
delete current;
}
// clean up remaining intervals in queue
while (!pq.empty())
{
delete pq.top();
pq.pop();
}
max_upper_bound = initial_node->GetChildMaxUpper();
initial_node->DeleteChildren();
delete initial_node;
max_threshold = std::max(max_threshold, max_upper_bound);
return std::make_pair(max_lower_bound, max_upper_bound);
}
std::pair<real_t, real_t> GridFunction::EstimateFunctionMinimum(
const int vdim, const PLBound &plb, const int max_depth,
const real_t tol) const
{
real_t global_min_lower = std::numeric_limits<real_t>::max();
real_t global_min_upper = std::numeric_limits<real_t>::max();
for (int i = 0; i < fes->GetNE(); i++)
{
std::pair<real_t, real_t> min_pair =
EstimateFunctionMinimum(i, plb, vdim, max_depth, tol,
global_min_lower);
global_min_upper = std::min(global_min_upper, min_pair.second);
}
return std::make_pair(global_min_lower, global_min_upper);
}
std::pair<real_t, real_t> GridFunction::EstimateFunctionMaximum(
const int vdim, const PLBound &plb, const int max_depth,
const real_t tol) const
{
real_t global_max_lower = std::numeric_limits<real_t>::lowest();
real_t global_max_upper = std::numeric_limits<real_t>::lowest();
for (int i = 0; i < fes->GetNE(); i++)
{
std::pair<real_t, real_t> max_pair =
EstimateFunctionMaximum(i, plb, vdim, max_depth, tol,
global_max_upper);
global_max_lower = std::max(global_max_lower, max_pair.first);
}
return std::make_pair(global_max_lower, global_max_upper);
}
}
+186 -20
View File
@@ -150,11 +150,13 @@ public:
FiniteElementCollection *OwnFEC() { return fec_owned; }
/// Shortcut for calling FiniteElementSpace::GetVectorDim() on the underlying #fes
int VectorDim() const;
/** @brief Shortcut for calling FiniteElementSpace::GetVectorDim() on the
underlying #fes */
int VectorDim() const { return fes->GetVectorDim(); }
/// Shortcut for calling FiniteElementSpace::GetCurlDim() on the underlying #fes
int CurlDim() const;
/** @brief Shortcut for calling FiniteElementSpace::GetCurlDim() on the
underlying #fes */
int CurlDim() const { return fes->GetCurlDim(); }
/// Read only access to the (optional) internal true-dof Vector.
const Vector &GetTrueVector() const
@@ -532,6 +534,9 @@ public:
std::unique_ptr<GridFunction> ProlongateToMaxOrder() const;
protected:
void ProjectBdrCoefficientNormal(Coefficient *coeff, VectorCoefficient *vcoeff,
const Array<int> &attr);
/** @brief Accumulates (depending on @a type) the values of @a coeff at all
shared vdofs and counts in how many zones each vdof appears. */
void AccumulateAndCountZones(Coefficient &coeff, AvgType type,
@@ -564,6 +569,70 @@ protected:
/// P-refinement version of Update().
void UpdatePRef();
/** @brief Estimate the minimum value of the GridFunction in element @a elem
* if it is below a certain @a min_threshold.
*
* @details For a given element \p elem and grid function component \p vdim
* an estimate of the function minimum is the minimum of the piecewise
* linear lower bound obtained using the given PLBound object. The actual
* minimum is between [minimum lower bound, minimum upper bound]. We
* improve the estimate of the function minimum by recursively
* subdividing the interval with the lowest lower bound, and computing
* bounds on the sub-intervals.
* This process continues until (i) the maximum recursion depth is reached
* or (ii) the difference between the minimum upper bound and minimum lower
* bound is less than a certain tolerance (\p tol * [initial maximum
* upper bound - initial minimum lower bound]).
* The function also terminates if the lowest minima estimate is found
* to be above the given threshold \p min_threshold. This is useful when
* we are interested in computing the global minimum of the function
* over all elements. In this case we can reject elements where the lowest
* bound is above the current global minimum. In case the function
* minimum on the element is below the global minimum, we update
* \p min_threshold.
*
* We return a pair of values that bracket the actual minimum, i.e.
* [min_lower_bound, min_upper_bound].
*/
std::pair<real_t,real_t> EstimateFunctionMinimum(const int elem,
const PLBound &plb,
const int vdim,
const int max_depth,
const real_t tol,
real_t &min_threshold)const;
/** @brief Estimate the maximum value of the GridFunction in element @a elem
* if it is below a certain @a max_threshold.
*
* @details For a given element \p elem and grid function component \p vdim
* an estimate of the function maximum is the maximum of the piecewise
* linear upper bound obtained using the given PLBound object. The actual
* maximum is between [maximum lower bound, maximum upper bound]. We
* improve the estimate of the function maximum by recursively
* subdividing the interval with the highest upper bound, and computing
* bounds on the sub-intervals.
* This process continues until (i) the maximum recursion depth is reached
* or (ii) the difference between the maximum upper bound and maximum lower
* bound is less than a certain tolerance (\p tol * [initial maximum
* upper bound - initial maximum lower bound]).
* The function also terminates if the highest maxima estimate is found
* to be below the given threshold \p max_threshold. This is useful when
* we are interested in computing the global maximum of the function
* over all elements. In this case we can reject elements where the upper
* bound is below the current global maximum. In case the function
* maximum on the element is above the global maximum, we update
* \p max_threshold.
*
* We return a pair of values that bracket the actual maximum, i.e.
* [max_lower_bound, max_upper_bound].
*/
std::pair<real_t,real_t> EstimateFunctionMaximum(const int elem,
const PLBound &plb,
const int vdim,
const int max_depth,
const real_t tol,
real_t &max_threshold)const;
public:
/** @brief For each vdof, counts how many elements contain the vdof,
as containment is determined by FiniteElementSpace::GetElementVDofs(). */
@@ -592,15 +661,26 @@ public:
virtual void ProjectBdrCoefficient(Coefficient *coeff[],
const Array<int> &attr);
/** Project the normal component of the given VectorCoefficient on
the boundary. Only boundary attributes that are marked in
'bdr_attr' are projected. Assumes RT-type VectorFE GridFunction. */
/** @brief Project the normal component of the given VectorCoefficient on
the boundary. */
/** Only boundary attributes that are marked in @a bdr_attr are
projected. Assumes RT-type vector finite element GridFunction. */
void ProjectBdrCoefficientNormal(VectorCoefficient &vcoeff,
const Array<int> &bdr_attr);
const Array<int> &bdr_attr)
{ ProjectBdrCoefficientNormal(NULL, &vcoeff, bdr_attr); }
/** @brief Project the given Coefficient in the normal direction on the
boundary. */
/** Only boundary attributes that are marked in @a bdr_attr are projected.
Assumes RT-type vector finite element GridFunction. */
void ProjectBdrCoefficientNormal(Coefficient &coeff,
const Array<int> &bdr_attr)
{ ProjectBdrCoefficientNormal(&coeff, NULL, bdr_attr); }
/** @brief Project the tangential components of the given VectorCoefficient
on the boundary. Only boundary attributes that are marked in @a bdr_attr
are projected. Assumes ND-type VectorFE GridFunction. */
on the boundary. */
/** Only boundary attributes that are marked in @a bdr_attr
are projected. Assumes ND-type vector finite element GridFunction. */
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
const Array<int> &bdr_attr);
@@ -1662,21 +1742,21 @@ public:
*/
///@{
/// Computes the \ref PLBound for the gridfunction with number of control
/// points based on @a ref_factor, and returns the overall bounds for each
/// vdim (across all elements) in @b lower and @b upper. We also return the
/// points based on \p ref_factor, and returns the overall bounds for each
/// vdim (across all elements) in \p lower and \p upper. We also return the
/// PLBound object used to compute the bounds.
/// We compute the bounds for each vdim if @a vdim < 1.
/// We compute the bounds for each vdim if \p vdim < 1.
/// Note: For most cases, this method/interface will be sufficient.
virtual PLBound GetBounds(Vector &lower, Vector &upper,
const int ref_factor=1, const int vdim=-1) const;
/// Computes the \ref PLBound for the gridfunction with number of control
/// points based on @a ref_factor, and returns the bounds for each element
/// ordered byVDim:
/// points based on \p ref_factor, and returns the bounds for each element
/// ordered byNodes:
/// lower_{0,0}, lower_{1,0}, ..., lower_{ne-1,0},
/// lower_{0,1}, ..., lower_{ne-1,vdim-1}. We also return the
/// PLBound object used to compute the bounds.
/// We compute the bounds for each vdim if @a vdim < 1.
/// We compute the bounds for each vdim if \p vdim < 1.
PLBound GetElementBounds(Vector &lower, Vector &upper,
const int ref_factor=1, const int vdim=-1) const;
@@ -1687,6 +1767,18 @@ public:
Vector &lower, Vector &upper,
const int vdim = -1) const;
/** @brief Gets the bounds on given reference range inside an element.
*
* @details @a ref_range is a vector of size 2*dim that specifies the
* lower and upper limits in each dimension of the reference element.
* For example, in 2D, ref_range = [rmin, smin, rmax, smax].
*/
void GetElementBoundsAtControlPoints(const int elem, const PLBound &plb,
const Vector &ref_range,
const int vdim,
Vector &lower, Vector &upper,
Vector &control_pos) const;
/// Compute bounds on the grid function for the given element.
/// The bounds are stored in @b lower and @b upper.
void GetElementBounds(const int elem, const PLBound &plb,
@@ -1694,11 +1786,45 @@ public:
const int vdim = -1) const;
/// Compute bounds on the grid function for all the elements. The bounds
/// are returned in @b lower and @b upper, ordered byVDim:
/// are returned in @b lower and @b upper, ordered byNodes:
/// lower_{0,0}, lower_{1,0}, ..., lower_{ne-1,0},
/// lower_{0,1}, ..., lower_{ne-1,vdim-1}
void GetElementBounds(const PLBound &plb, Vector &lower, Vector &upper,
const int vdim=-1) const;
/** @brief Estimate the minimum value of the GridFunction in element @a elem.
*
* @details See the protected version of EstimateFunctionMinimum for
* details.
*/
std::pair<real_t, real_t> EstimateFunctionMinimum(const int elem,
const PLBound &plb,
const int vdim,
const int max_depth,
const real_t tol) const;
/** @brief Estimate the minimum value of the GridFunction in element @a elem.
*
* @details See the protected version of EstimateFunctionMaximum for
* details.
*/
std::pair<real_t, real_t> EstimateFunctionMaximum(const int elem,
const PLBound &plb,
const int vdim,
const int max_depth,
const real_t tol) const;
/** @brief Estimate the GridFunction minimum across all elements. */
virtual std::pair<real_t,real_t> EstimateFunctionMinimum(const int vdim,
const PLBound &plb,
const int max_depth,
const real_t tol) const;
/** @brief Estimate the GridFunction maximum across all elements. */
virtual std::pair<real_t,real_t> EstimateFunctionMaximum(const int vdim,
const PLBound &plb,
const int max_depth,
const real_t tol) const;
///@}
/// Destroys grid function.
@@ -1804,7 +1930,7 @@ real_t ComputeElementLpDistance(real_t p, int i,
GridFunction& gf1, GridFunction& gf2);
/// Class used for extruding scalar GridFunctions
/// Class used for extruding a scalar coefficient
class ExtrudeCoefficient : public Coefficient
{
private:
@@ -1812,13 +1938,53 @@ private:
Mesh *mesh_in;
Coefficient &sol_in;
public:
/// Constructs an instance of VectorExtrudeCoefficient
/**
* @param m 1D mesh
* @param s 1D vector coefficient
* @param n_ number of transverse elements of the extruded mesh
*/
ExtrudeCoefficient(Mesh *m, Coefficient &s, int n_)
: n(n_), mesh_in(m), sol_in(s) { }
: n(n_), mesh_in(m), sol_in(s)
{ MFEM_VERIFY(n > 0, "Number of transverse elements must be positive!"); }
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override;
virtual ~ExtrudeCoefficient() { }
};
/// Extrude a scalar 1D GridFunction, after extruding the mesh with Extrude1D.
/// Class used for extruding a vector coefficient
class VectorExtrudeCoefficient : public VectorCoefficient
{
private:
int n;
Mesh *mesh_in;
VectorCoefficient &sol_in;
public:
/// Constructs an instance of VectorExtrudeCoefficient
/**
* @param m 1D mesh
* @param s 1D vector coefficient
* @param n_ number of transverse elements of the extruded mesh
*/
VectorExtrudeCoefficient(Mesh *m, VectorCoefficient &s, int n_)
: VectorCoefficient(s.GetVDim()), n(n_), mesh_in(m), sol_in(s)
{ MFEM_VERIFY(n > 0, "Number of transverse elements must be positive!"); }
void Eval(Vector &v, ElementTransformation &T,
const IntegrationPoint &ip) override;
using VectorCoefficient::Eval;
virtual ~VectorExtrudeCoefficient() { }
};
/// Extrude a 1D GridFunction, after extruding the mesh with Extrude1D()
/**
* @param mesh 1D mesh
* @param mesh2d extruded mesh
* @param sol grid function
* @param ny number of transverse elements of the extruded mesh
*/
GridFunction *Extrude1DGridFunction(Mesh *mesh, Mesh *mesh2d,
GridFunction *sol, const int ny);
+18 -8
View File
@@ -197,15 +197,21 @@ static void EAHdivAssemble3D(const int NE,
// Assemble (one row per thread)
MFEM_FOREACH_THREAD(idx_i, x, NDOF)
{
// NOTE: due to an llvm backend bug, usage of the modulus operator
// has been removed from this foreach section.
const int ic = idx_i / NDOF_C;
const int idx_ii = idx_i % NDOF_C;
const int idx_ii = idx_i - ic * NDOF_C; // idx_i % NDOF_C
const int nx_i = (ic == 0) ? D1D : D1D-1;
const int ny_i = (ic == 1) ? D1D : D1D-1;
const int ix = idx_ii % nx_i;
const int iy = (idx_ii / nx_i) % ny_i;
const int iz = (idx_ii / nx_i) / ny_i;
const int qx_i = idx_ii / nx_i;
const int ix = idx_ii - qx_i * nx_i; // idx_ii % nx_i
const int qy_i = qx_i / ny_i;
const int iy = qx_i - qy_i * ny_i; // (idx_ii / nx_i) % ny_i
const int iz = qy_i; // (idx_ii / nx_i) / ny_i
const real_t (&Bi1)[MQ1][MD1] = (ic == 0) ? r_Bc : r_Bo;
const real_t (&Bi2)[MQ1][MD1] = (ic == 1) ? r_Bc : r_Bo;
@@ -214,14 +220,18 @@ static void EAHdivAssemble3D(const int NE,
for (int idx_j = 0; idx_j < NDOF; ++idx_j)
{
const int jc = idx_j / NDOF_C;
const int idx_jj = idx_j % NDOF_C;
const int idx_jj = idx_j - jc * NDOF_C; // idx_j % NDOF_C
const int nx_j = (jc == 0) ? D1D : D1D-1;
const int ny_j = (jc == 1) ? D1D : D1D-1;
const int jx = idx_jj % nx_j;
const int jy = (idx_jj / nx_j) % ny_j;
const int jz = (idx_jj / nx_j) / ny_j;
const int qx_j = idx_jj / nx_j;
const int jx = idx_jj - qx_j * nx_j; // idx_jj % nx_j
const int qy_j = qx_j / ny_j;
const int jy = qx_j - qy_j * ny_j; // (idx_jj / nx_j) % ny_j
const int jz = qy_j; // (idx_jj / nx_j) / ny_j
const real_t (&Bj1)[MQ1][MD1] = (jc == 0) ? r_Bc : r_Bo;
const real_t (&Bj2)[MQ1][MD1] = (jc == 1) ? r_Bc : r_Bo;
+3 -3
View File
@@ -171,15 +171,15 @@ template<int DIM, int T_SDIM, int T_D1D, int T_Q1D>
VectorDiffusionIntegrator::ApplyKernelType
VectorDiffusionIntegrator::ApplyPAKernels::Kernel()
{
if (DIM == 2)
if constexpr (DIM == 2)
{
return internal::SmemPAVectorDiffusionApply2D<T_SDIM, T_D1D, T_Q1D>;
}
else if (DIM == 3)
else if constexpr (DIM == 3)
{
return internal::SmemPAVectorDiffusionApply3D<T_SDIM, T_D1D, T_Q1D>;
}
else { MFEM_ABORT("Unsupported kernel"); }
MFEM_ABORT("Unsupported kernel");
}
inline VectorDiffusionIntegrator::ApplyKernelType
+3 -3
View File
@@ -182,15 +182,15 @@ template<int DIM, int T_D1D, int T_Q1D>
VectorMassIntegrator::VectorMassAddMultPAType
VectorMassIntegrator::VectorMassAddMultPA::Kernel()
{
if (DIM == 2)
if constexpr (DIM == 2)
{
return internal::SmemPAVectorMassApply2D<T_D1D,T_Q1D>;
}
else if (DIM == 3)
else if constexpr (DIM == 3)
{
return internal::SmemPAVectorMassApply3D<T_D1D, T_Q1D>;
}
else { MFEM_ABORT("Unsupported kernel"); }
MFEM_ABORT("Unsupported kernel");
}
inline VectorMassIntegrator::VectorMassAddMultPAType
+6 -10
View File
@@ -301,18 +301,14 @@ template <int DIM, int T_D1D, int T_Q1D>
DomainLFIntegrator::AssembleKernelType
DomainLFIntegrator::AssembleKernels::Kernel()
{
switch (DIM)
{
case 1:
return DLFEvalAssemble1D<T_D1D, T_Q1D>;
case 2:
return DLFEvalAssemble2D<T_D1D, T_Q1D>;
case 3:
return DLFEvalAssemble3D<T_D1D, T_Q1D>;
}
if constexpr (DIM == 1) { return DLFEvalAssemble1D<T_D1D, T_Q1D>; }
if constexpr (DIM == 2) { return DLFEvalAssemble2D<T_D1D, T_Q1D>; }
if constexpr (DIM == 3) { return DLFEvalAssemble3D<T_D1D, T_Q1D>; }
MFEM_ABORT("");
}
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
#endif
#endif // MFEM_LININTEG_DOMAIN_KERNELS_HPP
+811 -327
View File
File diff suppressed because it is too large Load Diff
+30 -27
View File
@@ -125,18 +125,6 @@ private:
void AddTriPoints3b(const int off, const real_t b, const real_t weight)
{ AddTriPoints3(off, (1. - b)/2., b, weight); }
void AddTriPoints3R(const int off, const real_t a, const real_t b,
const real_t c, const real_t weight)
{
IntPoint(off + 0).Set2w(a, b, weight);
IntPoint(off + 1).Set2w(c, a, weight);
IntPoint(off + 2).Set2w(b, c, weight);
}
void AddTriPoints3R(const int off, const real_t a, const real_t b,
const real_t weight)
{ AddTriPoints3R(off, a, b, 1. - a - b, weight); }
void AddTriPoints6(const int off, const real_t a, const real_t b,
const real_t c, const real_t weight)
{
@@ -183,14 +171,6 @@ private:
AddTetPoints3(off + 1, a, 1. - 3.*a, weight);
}
// given b, add the permutations of (a,a,a,b), where 3*a + b = 1
void AddTetPoints4b(const int off, const real_t b, const real_t weight)
{
const real_t a = (1. - b)/3.;
IntPoint(off).Set(a, a, a, weight);
AddTetPoints3(off + 1, a, b, weight);
}
// add the permutations of (a,a,b,b), 2*(a + b) = 1
void AddTetPoints6(const int off, const real_t a, const real_t weight)
{
@@ -209,14 +189,37 @@ private:
AddTetPoints6(off + 6, a, bc, cb, weight);
}
// given (b,c), add the permutations of (a,a,b,c), 2*a + b + c = 1
void AddTetPoints12bc(const int off, const real_t b, const real_t c,
const real_t weight)
// add all 24 permutations of (a,b,c,d) where a+b+c+d = 1, all distinct
void AddTetPoints24(const int off, const real_t a, const real_t b,
const real_t c, const real_t weight)
{
const real_t a = (1. - b - c)/2.;
AddTetPoints3(off, a, b, weight);
AddTetPoints3(off + 3, a, c, weight);
AddTetPoints6(off + 6, a, b, c, weight);
const real_t d = 1. - a - b - c;
// all 24 permutations of 4 distinct barycentric coordinates
// permuting which coordinate goes to x, y, z (4th is 1-x-y-z)
IntPoint(off + 0).Set(a, b, c, weight);
IntPoint(off + 1).Set(a, b, d, weight);
IntPoint(off + 2).Set(a, c, b, weight);
IntPoint(off + 3).Set(a, c, d, weight);
IntPoint(off + 4).Set(a, d, b, weight);
IntPoint(off + 5).Set(a, d, c, weight);
IntPoint(off + 6).Set(b, a, c, weight);
IntPoint(off + 7).Set(b, a, d, weight);
IntPoint(off + 8).Set(b, c, a, weight);
IntPoint(off + 9).Set(b, c, d, weight);
IntPoint(off + 10).Set(b, d, a, weight);
IntPoint(off + 11).Set(b, d, c, weight);
IntPoint(off + 12).Set(c, a, b, weight);
IntPoint(off + 13).Set(c, a, d, weight);
IntPoint(off + 14).Set(c, b, a, weight);
IntPoint(off + 15).Set(c, b, d, weight);
IntPoint(off + 16).Set(c, d, a, weight);
IntPoint(off + 17).Set(c, d, b, weight);
IntPoint(off + 18).Set(d, a, b, weight);
IntPoint(off + 19).Set(d, a, c, weight);
IntPoint(off + 20).Set(d, b, a, weight);
IntPoint(off + 21).Set(d, b, c, weight);
IntPoint(off + 22).Set(d, c, a, weight);
IntPoint(off + 23).Set(d, c, b, weight);
}
public:
+3 -1
View File
@@ -297,7 +297,8 @@ void LinearForm::Assemble()
tr = mesh->GetBdrFaceTransformations(i);
if (tr != NULL)
{
fes -> GetElementVDofs (tr -> Elem1No, vdofs);
mfem::DofTransformation doftrans;
fes -> GetElementVDofs (tr -> Elem1No, vdofs, doftrans);
for (int k = 0; k < boundary_face_integs.Size(); k++)
{
if (boundary_face_integs_marker[k] &&
@@ -307,6 +308,7 @@ void LinearForm::Assemble()
boundary_face_integs[k]->
AssembleRHSElementVect(*fes->GetFE(tr->Elem1No),
*tr, elemvect);
doftrans.TransformDual(elemvect);
AddElementVector (vdofs, elemvect);
}
}
+6 -5
View File
@@ -158,15 +158,16 @@ void LORBase::ConstructLocalDofPermutation(Array<int> &perm_) const
int i;
i = dofmap_lor[off_lor + i1 + i2*2];
int s1 = i < 0 ? -1 : 1;
int idof_lor = vdof_lor[absdof(i)];
int idof_lor = vdof_lor[UnsignIndex(i)];
i = dofmap_ho[off_ho + i1*n1 + i2*n2];
int s2 = i < 0 ? -1 : 1;
int idof_ho = vdof_ho[absdof(i)];
int idof_ho = vdof_ho[UnsignIndex(i)];
int s3 = idof_lor < 0 ? -1 : 1;
int s4 = idof_ho < 0 ? -1 : 1;
int s = s1*s2*s3*s4;
i = absdof(idof_ho);
perm_[absdof(idof_lor)] = s < 0 ? -1-absdof(i) : absdof(i);
i = UnsignIndex(idof_ho);
perm_[UnsignIndex(idof_lor)] = s < 0 ? -1-UnsignIndex(i) :
UnsignIndex(i);
}
}
};
@@ -232,7 +233,7 @@ void LORBase::ConstructDofPermutation() const
int j = l_perm[i];
int s = j < 0 ? -1 : 1;
int t_i = pfes_lor->GetLocalTDofNumber(i);
int t_j = pfes_ho->GetLocalTDofNumber(absdof(j));
int t_j = pfes_ho->GetLocalTDofNumber(UnsignIndex(j));
// Either t_i and t_j both -1, or both non-negative
if ((t_i < 0 && t_j >=0) || (t_j < 0 && t_i >= 0))
{
-2
View File
@@ -57,8 +57,6 @@ private:
/// values (after temporarily changing them for LOR assembly).
void ResetIntegrationRules(GetIntegratorsFn get_integrators);
static inline int absdof(int i) { return i < 0 ? -1-i : i; }
protected:
enum FESpaceType { H1, ND, RT, L2, INVALID };
+41 -47
View File
@@ -424,7 +424,7 @@ void ParFiniteElementSpace::GetGroupComm(
{
if (ind[l] < 0)
{
dofs[l] = m + (-1-ind[l]);
dofs[l] = m + FlipIndexSign(ind[l]);
if (g_ldof_sign)
{
(*g_ldof_sign)[dofs[l]] = -1;
@@ -462,7 +462,7 @@ void ParFiniteElementSpace::GetGroupComm(
{
if (ind[l] < 0)
{
dofs[l] = m + (-1-ind[l]);
dofs[l] = m + FlipIndexSign(ind[l]);
if (g_ldof_sign)
{
(*g_ldof_sign)[dofs[l]] = -1;
@@ -500,7 +500,7 @@ void ParFiniteElementSpace::GetGroupComm(
{
if (ind[l] < 0)
{
dofs[l] = m + (-1-ind[l]);
dofs[l] = m + FlipIndexSign(ind[l]);
if (g_ldof_sign)
{
(*g_ldof_sign)[dofs[l]] = -1;
@@ -538,16 +538,16 @@ void ParFiniteElementSpace::ApplyLDofSigns(Array<int> &dofs) const
{
if (dofs[i] < 0)
{
if (ldof_sign[-1-dofs[i]] < 0)
if (ldof_sign[FlipIndexSign(dofs[i])] < 0)
{
dofs[i] = -1-dofs[i];
dofs[i] = FlipIndexSign(dofs[i]);
}
}
else
{
if (ldof_sign[dofs[i]] < 0)
{
dofs[i] = -1-dofs[i];
dofs[i] = FlipIndexSign(dofs[i]);
}
}
}
@@ -699,7 +699,8 @@ void ParFiniteElementSpace::GetSharedEdgeDofs(
for (int i = 0; i < dofs.Size(); i++)
{
const int di = dofs[i];
dofs[i] = (di >= 0) ? rdofs[di] : -1-rdofs[-1-di];
dofs[i] = di >= 0 ? rdofs[di] :
FlipIndexSign(rdofs[FlipIndexSign(di)]);
}
}
}
@@ -723,7 +724,8 @@ void ParFiniteElementSpace::GetSharedTriangleDofs(
for (int i = 0; i < dofs.Size(); i++)
{
const int di = dofs[i];
dofs[i] = (di >= 0) ? rdofs[di] : -1-rdofs[-1-di];
dofs[i] = di >= 0 ? rdofs[di] :
FlipIndexSign(rdofs[FlipIndexSign(di)]);
}
}
}
@@ -747,7 +749,8 @@ void ParFiniteElementSpace::GetSharedQuadrilateralDofs(
for (int i = 0; i < dofs.Size(); i++)
{
const int di = dofs[i];
dofs[i] = (di >= 0) ? rdofs[di] : -1-rdofs[-1-di];
dofs[i] = (di >= 0) ? rdofs[di] :
FlipIndexSign(rdofs[FlipIndexSign(di)]);
}
}
}
@@ -1487,7 +1490,7 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
GetElementVDofs(my_elems[i], ldofs);
for (int j = 0; j < ldofs.Size(); j++)
{
int ldof = (ldofs[j] >= 0 ? ldofs[j] : -1-ldofs[j]);
int ldof = UnsignIndex(ldofs[j]);
if (ldof_marker[ldof] != fn)
{
@@ -1548,7 +1551,7 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
GetElementVDofs(my_elems[i], ldofs);
for (int j = 0; j < ldofs.Size(); j++)
{
int ldof = (ldofs[j] >= 0 ? ldofs[j] : -1-ldofs[j]);
int ldof = UnsignIndex(ldofs[j]);
if (ldof_marker[ldof] != fn)
{
@@ -1573,14 +1576,15 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
for (int i = 0; i < num_ldofs; i++)
{
int ldof = (ldofs_fn[i] >= 0 ? ldofs_fn[i] : -1-ldofs_fn[i]);
int ldof = UnsignIndex(ldofs_fn[i]);
ldof_marker[ldof] = i;
}
for ( ; j < j_end; j++)
{
int ldof = (send_J[j] >= 0 ? send_J[j] : -1-send_J[j]);
send_J[j] = (send_J[j] >= 0 ? ldof_marker[ldof] : -1-ldof_marker[ldof]);
const int ldof = UnsignIndex(send_J[j]);
send_J[j] = (send_J[j] >= 0 ? ldof_marker[ldof] :
FlipIndexSign(ldof_marker[ldof]));
}
}
@@ -1672,12 +1676,7 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
{
for (int j_end = face_nbr_ldof.GetI()[fn+1]; j < j_end; j++)
{
int ldof = face_nbr_ldof.GetJ()[j];
if (ldof < 0)
{
ldof = -1-ldof;
}
const int ldof = UnsignIndex(face_nbr_ldof.GetJ()[j]);
face_nbr_glob_dof_map[j] = dof_face_nbr_offsets[fn] + ldof;
}
}
@@ -1721,7 +1720,7 @@ void ParFiniteElementSpace::GetFaceNbrFaceVDofs(int i, Array<int> &vdofs) const
MFEM_ASSERT(Nonconforming() && i >= pmesh->GetNumFaces(), "");
int el1, el2, inf1, inf2;
pmesh->GetFaceElements(i, &el1, &el2);
el2 = -1 - el2;
el2 = FlipIndexSign(el2);
pmesh->GetFaceInfos(i, &inf1, &inf2);
MFEM_ASSERT(0 <= el2 && el2 < face_nbr_element_dof.Size(), "");
const int nd = face_nbr_element_dof.RowSize(el2);
@@ -1737,7 +1736,8 @@ void ParFiniteElementSpace::GetFaceNbrFaceVDofs(int i, Array<int> &vdofs) const
for (int j = 0; j < vdofs.Size(); j++)
{
const int ldof = vdofs[j];
vdofs[j] = (ldof >= 0) ? vol_vdofs[ldof] : -1-vol_vdofs[-1-ldof];
vdofs[j] = (ldof >= 0) ? vol_vdofs[ldof] :
FlipIndexSign(vol_vdofs[FlipIndexSign(ldof)]);
}
}
@@ -2061,8 +2061,8 @@ void ParFiniteElementSpace::GetGhostFaceDofs(const MeshId &face_id,
for (int j = 0; j < ne; j++)
{
dofs[offset++] = (ind[j] >= 0) ? (first + ind[j])
/* */ : (-1 - (first + (-1 - ind[j])));
dofs[offset++] = (ind[j] >= 0) ? (first + ind[j]) :
FlipIndexSign(first + FlipIndexSign(ind[j]));
}
}
else
@@ -2072,8 +2072,8 @@ void ParFiniteElementSpace::GetGhostFaceDofs(const MeshId &face_id,
const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[i]);
for (int j = 0; j < ne; j++)
{
dofs[offset++] = (ind[j] >= 0) ? (first + ind[j])
/* */ : (-1 - (first + (-1 - ind[j])));
dofs[offset++] = (ind[j] >= 0) ? (first + ind[j]) :
FlipIndexSign(first + FlipIndexSign(ind[j]));
}
}
}
@@ -2866,7 +2866,7 @@ void NeighborRowMessage::Encode(int rank)
if (ind && (edof = ind[edof]) < 0)
{
edof = -1 - edof;
edof = FlipIndexSign(edof);
s = -1;
}
@@ -3067,10 +3067,10 @@ void NeighborRowMessage::Decode(int rank)
// If edof arrived with a negative index, flip it, and the scaling.
real_t s = (edof < 0) ? -1.0 : 1.0;
edof = (edof < 0) ? -1 - edof : edof;
edof = UnsignIndex(edof);
if (ind && (edof = ind[edof]) < 0)
{
edof = -1 - edof;
edof = FlipIndexSign(edof);
s *= -1.0;
}
@@ -3121,10 +3121,10 @@ void NeighborRowMessage::Decode(int rank)
// If edof arrived with a negative index, flip it, and the scaling.
s = (edof < 0) ? -1.0 : 1.0;
edof = (edof < 0) ? -1 - edof : edof;
edof = UnsignIndex(edof);
if (ind && (edof = ind[edof]) < 0)
{
edof = -1 - edof;
edof = FlipIndexSign(edof);
s *= -1.0;
}
@@ -4405,12 +4405,9 @@ ParFiniteElementSpace::RebalanceMatrix(int old_ndofs,
{
for (int j = 0; j < dofs.Size(); j++)
{
int row = DofToVDof(dofs[j], vd);
if (row < 0) { row = -1 - row; }
int col = DofToVDof(old_dofs[j], vd, old_ndofs);
if (col < 0) { col = -1 - col; }
const int row = UnsignIndex(DofToVDof(dofs[j], vd));
const int col = UnsignIndex(DofToVDof(old_dofs[j], vd,
old_ndofs));
i_diag[row] = col;
}
}
@@ -4435,9 +4432,7 @@ ParFiniteElementSpace::RebalanceMatrix(int old_ndofs,
{
for (int j = 0; j < dofs.Size(); j++)
{
int row = DofToVDof(dofs[j], vd);
if (row < 0) { row = -1 - row; }
const int row = UnsignIndex(DofToVDof(dofs[j], vd));
if (i_diag[row] == i_diag[row+1]) // diag row empty?
{
i_offd[row] = old_dofs[j + vd * dofs.Size()];
@@ -4546,9 +4541,9 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
{
const Embedding &emb = dtrans.embeddings[k];
int fine_rank = old_ranks[k];
int coarse_rank = (emb.parent < 0) ? (-1 - emb.parent)
: old_pncmesh->ElementRank(emb.parent);
const int fine_rank = old_ranks[k];
const int coarse_rank = (emb.parent < 0) ? FlipIndexSign(emb.parent)
: old_pncmesh->ElementRank(emb.parent);
if (coarse_rank != MyRank && fine_rank == MyRank)
{
@@ -4636,8 +4631,8 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
{
if (!std::isfinite(lR(i, 0))) { continue; }
int r = DofToVDof(dofs[i], vd);
int m = (r >= 0) ? r : (-1 - r);
const int r = DofToVDof(dofs[i], vd);
const int m = UnsignIndex(r);
if (is_dg || !mark[m])
{
@@ -4686,8 +4681,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
{
if (!std::isfinite(lR(i, 0))) { continue; }
int r = DofToVDof(dofs[i], vd);
int m = (r >= 0) ? r : (-1 - r);
const int m = UnsignIndex(DofToVDof(dofs[i], vd));
if (is_dg || !mark[m])
{
+47
View File
@@ -545,6 +545,8 @@ void ParGridFunction::GetElementDofValues(int el, Vector &dof_vals) const
void ParGridFunction::ProjectCoefficient(Coefficient &coeff, ProjectType type)
{
MFEM_VERIFY(VectorDim() == 1,
"Cannot project scalar coefficient onto vector ParGridFunction");
DeltaCoefficient *delta_c = dynamic_cast<DeltaCoefficient *>(&coeff);
if (delta_c == NULL)
@@ -717,6 +719,7 @@ void ParGridFunction::ProjectCoefficientElementL2(VectorCoefficient &vcoeff)
void ParGridFunction::ProjectDiscCoefficient(VectorCoefficient &coeff)
{
MFEM_VERIFY(VectorDim() == coeff.GetVDim(), "coeff vdim != VectorDim()");
// local maximal element attribute for each dof
Array<int> ldof_attr;
@@ -761,6 +764,9 @@ void ParGridFunction::ProjectDiscCoefficient(VectorCoefficient &coeff)
void ParGridFunction::ProjectDiscCoefficient(Coefficient &coeff, AvgType type)
{
MFEM_VERIFY(
VectorDim() == 1,
"Cannot project scalar coefficient onto a vector ParGridFunction");
// Harmonic (x1 ... xn) = [ (1/x1 + ... + 1/xn) / n ]^-1.
// Arithmetic(x1 ... xn) = (x1 + ... + xn) / n.
@@ -786,6 +792,8 @@ void ParGridFunction::ProjectDiscCoefficient(VectorCoefficient &vcoeff,
// Harmonic (x1 ... xn) = [ (1/x1 + ... + 1/xn) / n ]^-1.
// Arithmetic(x1 ... xn) = (x1 + ... + xn) / n.
MFEM_VERIFY(VectorDim() == vcoeff.GetVDim(), "vcoeff vdim != VectorDim()");
// Number of zones that contain a given dof.
Array<int> zones_per_vdof;
AccumulateAndCountZones(vcoeff, type, zones_per_vdof);
@@ -858,6 +866,12 @@ void ParGridFunction::ProjectBdrCoefficient(
#endif
}
void ParGridFunction::ProjectBdrCoefficient(VectorCoefficient &vcoeff,
const Array<int> &attr)
{
ProjectBdrCoefficient(NULL, &vcoeff, attr);
}
void ParGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
const Array<int> &bdr_attr)
{
@@ -1568,6 +1582,39 @@ PLBound ParGridFunction::GetBounds(Vector &lower, Vector &upper,
return plb;
}
std::pair<real_t, real_t> ParGridFunction::EstimateFunctionMinimum(
const int vdim, const PLBound &plb, const int max_depth,
const real_t tol) const
{
std::pair<real_t, real_t> minmax =
GridFunction::EstimateFunctionMinimum(vdim, plb, max_depth, tol);
real_t glob_min_lower = minmax.first;
real_t glob_min_upper = minmax.second;
MPI_Allreduce(MPI_IN_PLACE, &glob_min_lower, 1,
MFEM_MPI_REAL_T, MPI_MIN, pfes->GetComm());
MPI_Allreduce(MPI_IN_PLACE, &glob_min_upper, 1,
MFEM_MPI_REAL_T, MPI_MIN, pfes->GetComm());
return std::make_pair(glob_min_lower, glob_min_upper);
}
std::pair<real_t, real_t> ParGridFunction::EstimateFunctionMaximum(
const int vdim, const PLBound &plb, const int max_depth,
const real_t tol) const
{
std::pair<real_t, real_t> minmax =
GridFunction::EstimateFunctionMaximum(vdim, plb, max_depth, tol);
real_t glob_max_lower = minmax.first;
real_t glob_max_upper = minmax.second;
MPI_Allreduce(MPI_IN_PLACE, &glob_max_lower, 1,
MFEM_MPI_REAL_T, MPI_MAX, pfes->GetComm());
MPI_Allreduce(MPI_IN_PLACE, &glob_max_upper, 1,
MFEM_MPI_REAL_T, MPI_MAX, pfes->GetComm());
return std::make_pair(glob_max_lower, glob_max_upper);
}
} // namespace mfem
#endif // MFEM_USE_MPI
+13 -2
View File
@@ -280,8 +280,7 @@ public:
using GridFunction::ProjectBdrCoefficient;
void ProjectBdrCoefficient(VectorCoefficient &vcoeff,
const Array<int> &attr) override
{ ProjectBdrCoefficient(NULL, &vcoeff, attr); }
const Array<int> &attr) override;
void ProjectBdrCoefficient(Coefficient *coeff[],
const Array<int> &attr) override
@@ -609,6 +608,18 @@ public:
PLBound GetBounds(Vector &lower, Vector &upper,
const int ref_factor=1, const int vdim=-1) const override;
/** @brief Estimate the GridFunction minimum across all elements. */
std::pair<real_t, real_t> EstimateFunctionMinimum(const int vdim,
const PLBound &plb,
const int max_depth,
const real_t tol) const override;
/** @brief Estimate the GridFunction maximum across all elements. */
std::pair<real_t, real_t> EstimateFunctionMaximum(const int vdim,
const PLBound &plb,
const int max_depth,
const real_t tol) const override;
/** Save the local portion of the ParGridFunction. This differs from the
serial GridFunction::Save in that it takes into account the signs of
the local dofs. */
+11 -5
View File
@@ -321,12 +321,17 @@ void ParL2FaceRestriction::DoubleValuedConformingMult(
const int vd = vdim;
const bool t = byvdim;
const int threshold = ndofs;
const int nsdofs = pfes.GetFaceNbrVSize();
const int nsdofs = pfes.GetFaceNbrVSize() / vd;
auto d_indices1 = scatter_indices1.Read();
auto d_indices2 = scatter_indices2.Read();
auto d_x = Reshape(x.Read(), t?vd:ndofs, t?ndofs:vd);
auto d_x_shared = Reshape(face_nbr_data.Read(),
t?vd:nsdofs, t?nsdofs:vd);
const int ne_shared = nsdofs / elem_dofs;
const int nedof = elem_dofs;
// Note: the shape of face_nbr_data, as determined by
// ParFiniteElementSpace::ExchangeFaceNbrData, is (elem_dofs, vdim,
// ne_shared), independent of the ordering (byNODES or byVDIM) of the finite
// element space.
auto d_x_shared = Reshape(face_nbr_data.Read(), elem_dofs, vd, ne_shared);
auto d_y = Reshape(y.Write(), nface_dofs, vd, 2, nf);
mfem::forall(nfdofs, [=] MFEM_HOST_DEVICE (int i)
{
@@ -346,8 +351,9 @@ void ParL2FaceRestriction::DoubleValuedConformingMult(
}
else if (idx2>=threshold) // shared boundary
{
d_y(dof, c, 1, face) = d_x_shared(t?c:(idx2-threshold),
t?(idx2-threshold):c);
const int e_shared = (idx2 - threshold) / nedof;
const int i_shared = (idx2 - threshold) % nedof;
d_y(dof, c, 1, face) = d_x_shared(i_shared,c,e_shared);
}
else // true boundary
{
+1 -4
View File
@@ -271,10 +271,7 @@ inline void QuadratureFunction::GetValues(
const int s_offset = qspace->Offset(idx);
const int sl_size = qspace->Offset(idx + 1) - s_offset;
// Make the values matrix memory an alias of the quadrature function memory
Memory<real_t> &values_mem = values.GetMemory();
values_mem.Delete();
values_mem.MakeAlias(GetMemory(), vdim*s_offset, vdim*sl_size);
values.SetSize(vdim, sl_size);
values.MakeRef(GetMemory(), vdim*s_offset, vdim, sl_size);
}
inline void QuadratureFunction::GetValues(
+8 -9
View File
@@ -334,17 +334,16 @@ template<int DIM, int SDIM, int D1D, int Q1D>
QuadratureInterpolator::DetKernelType
QuadratureInterpolator::DetKernels::Kernel()
{
if (DIM == 1)
if constexpr (DIM == 1)
{
if (SDIM == 1) { return internal::quadrature_interpolator::Det1D; }
else if (SDIM == 2) { return internal::quadrature_interpolator::Det1DSurface<D1D, Q1D, 2>; }
else if (SDIM == 3) { return internal::quadrature_interpolator::Det1DSurface<D1D, Q1D, 3>; }
else { MFEM_ABORT(""); }
if constexpr (SDIM == 1) { return internal::quadrature_interpolator::Det1D; }
else if constexpr (SDIM == 2) { return internal::quadrature_interpolator::Det1DSurface<D1D, Q1D, 2>; }
else if constexpr (SDIM == 3) { return internal::quadrature_interpolator::Det1DSurface<D1D, Q1D, 3>; }
}
else if (DIM == 2 && SDIM == 2) { return internal::quadrature_interpolator::Det2D<D1D, Q1D>; }
else if (DIM == 2 && SDIM == 3) { return internal::quadrature_interpolator::Det2DSurface<D1D, Q1D>; }
else if (DIM == 3) { return internal::quadrature_interpolator::Det3D<D1D, Q1D>; }
else { MFEM_ABORT(""); }
else if constexpr (DIM == 2 && SDIM == 2) { return internal::quadrature_interpolator::Det2D<D1D, Q1D>; }
else if constexpr (DIM == 2 && SDIM == 3) { return internal::quadrature_interpolator::Det2DSurface<D1D, Q1D>; }
else if constexpr (DIM == 3) { return internal::quadrature_interpolator::Det3D<D1D, Q1D>; }
MFEM_ABORT("");
}
/// @endcond
+4 -4
View File
@@ -203,10 +203,10 @@ template<int DIM, QVectorLayout Q_LAYOUT,
QuadratureInterpolator::TensorEvalKernelType
QuadratureInterpolator::TensorEvalKernels::Kernel()
{
if (DIM == 1) { return internal::quadrature_interpolator::Values1D<Q_LAYOUT>; }
else if (DIM == 2) { return internal::quadrature_interpolator::Values2D<Q_LAYOUT, VDIM, D1D, Q1D, NBZ>; }
else if (DIM == 3) { return internal::quadrature_interpolator::Values3D<Q_LAYOUT, VDIM, D1D, Q1D>; }
else { MFEM_ABORT(""); }
if constexpr (DIM == 1) { return internal::quadrature_interpolator::Values1D<Q_LAYOUT>; }
else if constexpr (DIM == 2) { return internal::quadrature_interpolator::Values2D<Q_LAYOUT, VDIM, D1D, Q1D, NBZ>; }
else if constexpr (DIM == 3) { return internal::quadrature_interpolator::Values3D<Q_LAYOUT, VDIM, D1D, Q1D>; }
MFEM_ABORT("");
}
/// @endcond
+9 -2
View File
@@ -453,8 +453,15 @@ QuadratureInterpolator::TensorEvalHDivKernels::Kernel()
{
using namespace internal::quadrature_interpolator;
static_assert(DIM == 2 || DIM == 3, "only DIM=2 and DIM=3 are implemented!");
if (DIM == 2) { return EvalHDiv2D<Q_LAYOUT, FLAGS, D1D, Q1D>; }
return EvalHDiv3D<Q_LAYOUT, FLAGS, D1D, Q1D>;
if constexpr (DIM == 2)
{
return EvalHDiv2D<Q_LAYOUT, FLAGS, D1D, Q1D>;
}
else if constexpr (DIM == 3)
{
return EvalHDiv3D<Q_LAYOUT, FLAGS, D1D, Q1D>;
}
MFEM_ABORT("only DIM=2 and DIM=3 are implemented!");
}
/// @endcond
+8 -8
View File
@@ -592,10 +592,10 @@ template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int VDIM, int D1D,
QuadratureInterpolator::GradKernelType
QuadratureInterpolator::GradKernels::Kernel()
{
if (DIM == 1) { return internal::quadrature_interpolator::Derivatives1D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 2) { return internal::quadrature_interpolator::Derivatives2D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, Q1D, NBZ>; }
else if (DIM == 3) { return internal::quadrature_interpolator::Derivatives3D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, Q1D>; }
else { MFEM_ABORT(""); }
if constexpr (DIM == 1) { return internal::quadrature_interpolator::Derivatives1D<Q_LAYOUT, GRAD_PHYS>; }
else if constexpr (DIM == 2) { return internal::quadrature_interpolator::Derivatives2D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, Q1D, NBZ>; }
else if constexpr (DIM == 3) { return internal::quadrature_interpolator::Derivatives3D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, Q1D>; }
MFEM_ABORT("");
}
template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int VDIM, int D1D,
@@ -603,10 +603,10 @@ template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int VDIM, int D1D,
QuadratureInterpolator::CollocatedGradKernelType
QuadratureInterpolator::CollocatedGradKernels::Kernel()
{
if (DIM == 1) { return internal::quadrature_interpolator::CollocatedDerivatives1D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 2) { return internal::quadrature_interpolator::CollocatedDerivatives2D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, NBZ>; }
else if (DIM == 3) { return internal::quadrature_interpolator::CollocatedDerivatives3D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D>; }
else { MFEM_ABORT(""); }
if constexpr (DIM == 1) { return internal::quadrature_interpolator::CollocatedDerivatives1D<Q_LAYOUT, GRAD_PHYS>; }
else if constexpr (DIM == 2) { return internal::quadrature_interpolator::CollocatedDerivatives2D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, NBZ>; }
else if constexpr (DIM == 3) { return internal::quadrature_interpolator::CollocatedDerivatives3D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D>; }
MFEM_ABORT("");
}
/// @endcond
+4 -4
View File
@@ -752,10 +752,10 @@ template <int DIM, int VDIM, int ND, int NQ>
EvalKernel QuadratureInterpolator::EvalKernels::Kernel()
{
using namespace internal::quadrature_interpolator;
if (DIM == 1) { return Eval1D; }
else if (DIM == 2) { return Eval2D<VDIM,ND,NQ>; }
else if (DIM == 3) { return Eval3D<VDIM,ND,NQ>; }
else { MFEM_ABORT(""); }
if constexpr (DIM == 1) { return Eval1D; }
else if constexpr (DIM == 2) { return Eval2D<VDIM,ND,NQ>; }
else if constexpr (DIM == 3) { return Eval3D<VDIM,ND,NQ>; }
MFEM_ABORT("");
}
template <int DIM>
+7 -12
View File
@@ -844,8 +844,6 @@ void ConformingFaceRestriction::ComputeGatherIndices(
gather_offsets[0] = 0;
}
static inline int absdof(int i) { return i < 0 ? -1-i : i; }
void ConformingFaceRestriction::SetFaceDofsScatterIndices(
const Mesh::FaceInformation &face,
const int face_index,
@@ -868,9 +866,9 @@ void ConformingFaceRestriction::SetFaceDofsScatterIndices(
{
const int lex_volume_dof = face_map[face_dof];
const int s_volume_dof = AsConst(vol_dof_map)[lex_volume_dof]; // signed
const int volume_dof = absdof(s_volume_dof);
const int volume_dof = UnsignIndex(s_volume_dof);
const int s_global_dof = elem_map[elem_index*elem_dofs + volume_dof];
const int global_dof = absdof(s_global_dof);
const int global_dof = UnsignIndex(s_global_dof);
const int restriction_dof = face_dofs*face_index + face_dof;
scatter_indices[restriction_dof] = s_global_dof;
++gather_offsets[global_dof + 1];
@@ -897,10 +895,10 @@ void ConformingFaceRestriction::SetFaceDofsGatherIndices(
{
const int lex_volume_dof = face_map[face_dof];
const int s_volume_dof = AsConst(vol_dof_map)[lex_volume_dof];
const int volume_dof = absdof(s_volume_dof);
const int volume_dof = UnsignIndex(s_volume_dof);
const int s_global_dof = elem_map[elem_index*elem_dofs + volume_dof];
const int sgn = (s_global_dof >= 0) ? 1 : -1;
const int global_dof = absdof(s_global_dof);
const int global_dof = UnsignIndex(s_global_dof);
const int restriction_dof = face_dofs*face_index + face_dof;
const int s_restriction_dof = (sgn >= 0) ? restriction_dof : -1 -
restriction_dof;
@@ -1400,20 +1398,17 @@ void L2FaceRestriction::PermuteAndSetSharedFaceDofsScatterIndices2(
const int dim = fes.GetMesh()->Dimension();
const int dof1d = fes.GetTypicalFE()->GetOrder()+1;
fes.GetTypicalFE()->GetFaceMap(face_id2, face_map);
Array<int> face_nbr_dofs;
const ParFiniteElementSpace &pfes =
static_cast<const ParFiniteElementSpace&>(this->fes);
pfes.GetFaceNbrElementVDofs(elem_index, face_nbr_dofs);
for (int face_dof_elem1 = 0; face_dof_elem1 < face_dofs; ++face_dof_elem1)
{
const int face_dof_elem2 = PermuteFaceL2(dim, face_id1, face_id2,
orientation, dof1d, face_dof_elem1);
const int volume_dof_elem2 = face_map[face_dof_elem2];
const int global_dof_elem2 = face_nbr_dofs[volume_dof_elem2];
// Encode the volume DOF index and element index
const int global_dof_elem2 = elem_index*elem_dofs + volume_dof_elem2;
const int restriction_dof_elem2 = face_dofs*face_index + face_dof_elem1;
// Trick to differentiate dof location inter/shared
scatter_indices2[restriction_dof_elem2] = ndofs+global_dof_elem2;
scatter_indices2[restriction_dof_elem2] = ndofs + global_dof_elem2;
}
#endif
}
File diff suppressed because it is too large Load Diff
-539
View File
@@ -1,539 +0,0 @@
// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_SIDREDATACOLLECTION
#define MFEM_SIDREDATACOLLECTION
#include "../config/config.hpp"
#ifdef MFEM_USE_SIDRE
#include "datacollection.hpp"
// Ignore warnings from the axom/sidre header (GCC + Clang versions)
#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
# pragma GCC diagnostic push
# if defined(__clang__)
# pragma GCC diagnostic ignored "-Wextra-semi"
# else // real GCC?
# pragma GCC diagnostic ignored "-Wpedantic"
# endif
#endif
#include <axom/sidre.hpp>
#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
# pragma GCC diagnostic pop
#endif
namespace mfem
{
/** @brief Data collection with Sidre routines following the Conduit mesh
blueprint specification. */
/** SidreDataCollection provides an HDF5-based file format for visualization or
restart capability. This functionality is aimed primarily at customers of
LLNL's axom project that run problems at extreme scales.
For more information, see:
- Sidre component of LLNL's axom project (to be open-sourced), http://goo.gl/cZyJdn
- LLNL conduit/blueprint library, https://github.com/LLNL/conduit
- HDF5 library, https://support.hdfgroup.org/HDF5
The layout created in the Sidre DataStore is: (`"──"` denote groups,
`"─•"` denote views, `"─>"` denote links, i.e. shallow-copy view)
<root>
<collection-name>_global (global group)
blueprint_index
<collection-name> (bp_index group)
state
cycle
time
number_of_domains = <mesh-mpi-comm-size>
coordsets
coords
path = "<bp-path>/coordsets/coords"
type > <bp-grp>/coordsets/coords/type = "explicit"
coord_system = "x"|"xy"|"xyz"
topologies
mesh
path = "<bp-path>/topologies/mesh"
type > <bp-grp>/topologies/mesh/type = "unstructured"
coordset > <bp-grp>/topologies/mesh/coordset = "coords"
grid_function > <bp-grp>/topologies/mesh/grid_function = "<nodes-field-name>"
boundary_topology > <bp-grp>/topologies/mesh/boundary_topology = "boundary"
boundary
path = "<bp-path>/topologies/mesh"
type > <bp-grp>/topologies/boundary/type = "unstructured"
coordset > <bp-grp>/topologies/boundary/coordset = "coords"
fields
mesh_material_attribute
path = "<bp-path>/fields/mesh_material_attribute"
association > <bp-grp>/fields/mesh_material_attribute/association = "element"
topology > <bp-grp>/fields/mesh_material_attribute/topology = "mesh"
number_of_components = 1
boundary_material_attribute
path = "<bp-path>/fields/boundary_material_attribute"
association > <bp-grp>/fields/boundary_material_attribute/association = "element"
topology > <bp-grp>/fields/boundary_material_attribute/topology = "boundary"
number_of_components = 1
grid-function-1
path = "<bp-path>/fields/grid-function-1"
basis > <bp-grp>/fields/grid-function-1/basis = "<fe-coll-name>"
topology > <bp-grp>/fields/grid-function-1/topology = "mesh"
number_of_components = gf1->VectorDim()
grid-function-2
path = "<bp-path>/fields/grid-function-2"
basis > <bp-grp>/fields/grid-function-2/basis = "<fe-coll-name>"
topology > <bp-grp>/fields/grid-function-2/topology = "mesh"
number_of_components = gf2->VectorDim()
...
...
<collection-name> (domain group)
blueprint (blueprint group)
state
cycle
time
domain = <mesh-mpi-rank>
time_step
coordsets
coords
type = "explicit"
values
x = view in <vertex-coords-buffer>/<ext-double-data>
y = view in <vertex-coords-buffer>/<ext-double-data>
z = view in <vertex-coords-buffer>/<ext-double-data>
topologies
mesh
type = "unstructured"
elements
shape = "points"|"lines"|...
connectivity = <vert-idx-array>
coordset = "coords"
grid_function = "<nodes-field-name>"
boundary_topology = "boundary"
boundary
type = "unstructured"
elements
shape = "points"|"lines"|...
connectivity = <vert-idx-array>
coordset = "coords"
fields
mesh_material_attribute
association = "element"
topology = "mesh"
values = <attr-array>
boundary_material_attribute
association = "element"
topology = "boundary"
values = <attr-array>
grid-function-1 (name can include path)
basis = "<fe-coll-name>"
topology = "mesh"
values = <ext-double-array>/<named-buffer> (vdim == 1)
grid-function-2 (name can include path)
basis = "<fe-coll-name>"
topology = "mesh"
values (vdim > 1)
x0 = view into <ext-double-array>/<named-buffer>
x1 = view into <ext-double-array>/<named-buffer>
x2 = view into <ext-double-array>/<named-buffer>
...
...
named_buffers (named_buffers group)
vertex_coords = <double-array>
grid-function-1 = <double-array>
grid-function-2 = <double-array>
...
@note blueprint_index is used both in serial and in parallel. In parallel,
only rank 0 will add entries to the blueprint index.
@note QuadratureFunction%s (q-fields) are not supported.
@note SidreDataCollection does not manage the FiniteElementSpace%s and
FiniteElementCollection%s associated with registered GridFunction%s.
Therefore, field registration is left to the user of SidreDataCollection and
there are no methods that automatically register GridFunction%s using just
the content of the Sidre DataStore. Such capabilities can be implemented in
a derived class, adding any desired object management routines.
@warning This class is still _experimental_, meaning that in future
releases, it may not be backward compatible, and the output files generated
by the current version may become unreadable.
*/
class SidreDataCollection : public DataCollection
{
public:
typedef NamedFieldsMap< Array<int> > AttributeFieldMap;
AttributeFieldMap attr_map;
public:
/// Constructor that allocates and initializes a Sidre DataStore.
/**
@param[in] collection_name Name of the collection used as a file name
when saving
@param[in] the_mesh Mesh shared by all grid functions in the
collection (can be NULL)
@param[in] owns_mesh_data Does the SidreDC own the mesh vertices?
With this constructor, the SidreDataCollection owns the allocated Sidre
DataStore.
*/
SidreDataCollection(const std::string& collection_name,
Mesh *the_mesh = NULL,
bool owns_mesh_data = false);
/// Constructor that links to an external Sidre DataStore.
/** Specifically, the global and domain groups can be at arbitrary paths.
@param[in] collection_name Name of the collection used as a file name
when saving
@param[in] bp_index_grp Pointer to the blueprint index group in the
datastore, see the above schematic
@param[in] domain_grp Pointer to the domain group in the datastore,
see the above schematic
@param[in] owns_mesh_data Does the SidreDC own the mesh vertices?
With this constructor, the SidreDataCollection does not own the Sidre
DataStore.
@note No mesh or fields are read from the given Groups. The mesh has
to be set with SetMesh() and fields registered with RegisterField().
*/
SidreDataCollection(const std::string& collection_name,
axom::sidre::Group * bp_index_grp,
axom::sidre::Group * domain_grp,
bool owns_mesh_data = false);
#ifdef MFEM_USE_MPI
/// Associate an MPI communicator with the collection.
/** If no mesh was associated with the collection, this method should be
called before using any of the Load() methods to read parallel data. */
void SetComm(MPI_Comm comm);
#endif
/// Register a GridFunction in the Sidre DataStore.
/** This method is a shortcut for the call
`RegisterField(field_name, gf, field_name, 0)`.
*/
virtual void RegisterField(const std::string &field_name, GridFunction *gf)
{
RegisterField(field_name, gf, field_name, 0);
}
/// Register a GridFunction in the Sidre DataStore.
/** The registration procedure is as follows:
- if (@a gf's data is NULL), allocate named buffer with the name
@a buffer_name with size _offset + gf->FESpace()->GetVSize()_ and use
its data (plus the given @a offset) to set @a gf's data;
- else, if (DataStore has a named buffer @a buffer_name), replace @a gf's
data array with that named buffer plus the given @a offset;
- else, use @a gf's data as external data associated with @a field_name
in the DataStore;
- register @a field_name in #field_map.
Both the @a field_name and @a buffer_name can contain a path prefix.
@note If @a field_name or @a buffer_name is empty, the method does
nothing.
@note If the GridFunction pointer @a gf or it's FiniteElementSpace
pointer are NULL, the method does nothing.
*/
void RegisterField(const std::string &field_name, GridFunction *gf,
const std::string &buffer_name,
axom::sidre::IndexType offset);
/// Registers an attribute field in the Sidre DataStore
/** The registration process is similar to that of RegisterField()
The attribute field is associated with the elements of the mesh
when @a is_bdry is false, and with the boundary elements, when
@a is_bdry is true.
@sa RegisterField() */
void RegisterAttributeField(const std::string& name, bool is_bdry);
void DeregisterAttributeField(const std::string& name);
/** Returns a pointer to the attribute field associated with
@a field_name, or NULL when there is no associated field */
Array<int>* GetAttributeField(const std::string& field_name) const
{ return attr_map.Get(field_name); }
/** Checks if there is an attribute field associated with @a field_name */
bool HasAttributeField(const std::string& field_name) const
{ return attr_map.Has(field_name); }
/** Checks if any rank in the mesh has boundary elements */
bool HasBoundaryMesh() const;
/// Set the name of the mesh nodes field.
/** This name will be used by SetMesh() to register the mesh nodes, if not
already registered. Also, this method should be called if the mesh nodes
GridFunction was or will be registered directly by the user. The default
value for the name is "mesh_nodes". */
void SetMeshNodesName(const std::string &nodes_name)
{
if (!nodes_name.empty()) { m_meshNodesGFName = nodes_name; }
}
/// De-register @a field_name from the SidreDataCollection.
/** The field is removed from the #field_map and the DataStore, including
deleting it from the named_buffers group, if allocated. */
virtual void DeregisterField(const std::string& field_name);
/// Delete all owned data.
virtual ~SidreDataCollection();
/// Set/change the mesh associated with the collection
/** Uses the field name "mesh_nodes" or the value set by SetMeshNodesName()
to register the mesh nodes GridFunction, if the mesh uses nodes. */
virtual void SetMesh(Mesh *new_mesh);
#ifdef MFEM_USE_MPI
/// Set/change the mesh associated with the collection
/** Uses the field name "mesh_nodes" or the value set by SetMeshNodesName()
to register the mesh nodes GridFunction, if the mesh uses nodes. */
virtual void SetMesh(MPI_Comm comm, Mesh *new_mesh);
#endif
/// Reset the domain and global datastore group pointers.
/** These are set in the constructor, but if a host code changes the
datastore contents ( such as wiping out the datastore and loading in new
contents from a file, i.e. a restart ) these pointers will need to be
reset to valid groups in the datastore.
@sa Load(const std::string &path, const std::string &protocol).
*/
void SetGroupPointers(axom::sidre::Group * global_grp,
axom::sidre::Group * domain_grp);
axom::sidre::Group * GetBPGroup() { return m_bp_grp; }
axom::sidre::Group * GetBPIndexGroup() { return m_bp_index_grp; }
/// Prepare the DataStore for writing
virtual void PrepareToSave();
/// Save the collection to file.
/** This method calls `Save(collection_name, "sidre_hdf5")`. */
virtual void Save();
/// Save the collection to @a filename.
/** The collection path prefix is prepended to the @a filename and the
current cycle is appended, if cycle >= 0. */
void Save(const std::string& filename, const std::string& protocol);
/// Load the Sidre DataStore from file.
/** No mesh or fields are read from the loaded DataStore.
If the data collection created the datastore, it knows the layout of
where the domain and global groups are, and can restore them after the
Load().
If, however, the data collection does not own the datastore (e.g. it did
not create the datastore), the host code must reset these pointers after
the load operation, using SetGroupPointers(), and also reset the state
variables, using UpdateStateFromDS().
*/
void Load(const std::string& path, const std::string& protocol);
/// Load SidreDataCollection from file.
/** The used file path is based on the current prefix path, collection name,
and the given @a cycle_. The protocol is "sidre_hdf5".
@sa Load(const std::string &path, const std::string &protocol).
*/
virtual void Load(int cycle_ = 0)
{
SetCycle(cycle_);
Load(get_file_path(name), "sidre_hdf5");
}
/// Load external data after registering externally owned fields.
void LoadExternalData(const std::string& path);
/** @brief Updates the DataCollection's cycle, time, and time-step variables
with the values from the data store. */
void UpdateStateFromDS();
/** @brief Updates the data store's cycle, time, and time-step variables with
the values from the SidreDataCollection. */
void UpdateStateToDS();
/** @name Methods for named buffer access and manipulation. */
///@{
/** @brief Get a pointer to the sidre::View holding the named buffer for
@a buffer_name. */
/** If such named buffer is not allocated, the method returns NULL.
@note To access the underlying pointer, use View::getData().
@note To query the size of the buffer, use View::getNumElements().
*/
axom::sidre::View *
GetNamedBuffer(const std::string& buffer_name) const
{
return named_buffers_grp()->hasView(buffer_name)
? named_buffers_grp()->getView(buffer_name)
: NULL;
}
/// Return newly allocated or existing named buffer for @a buffer_name.
/** The buffer is stored in the named_buffers group. If the currently
allocated buffer size is smaller than @a sz, then the buffer is
reallocated with size @a sz, destroying its contents.
@note To access the underlying pointer, use View::getData().
*/
axom::sidre::View *
AllocNamedBuffer(const std::string& buffer_name,
axom::sidre::IndexType sz,
axom::sidre::TypeID type =
axom::sidre::DOUBLE_ID);
/// Deallocate the named buffer @a buffer_name.
void FreeNamedBuffer(const std::string& buffer_name)
{ named_buffers_grp()->destroyViewAndData(buffer_name); }
///@}
private:
// Used if the Sidre data collection is providing the datastore itself.
const bool m_owns_datastore;
// TODO - Need to evaluate if this bool member can be combined with own_data
// in parent data collection class. m_owns_mesh_data indicates whether the
// Sidre dc owns the mesh element data and node positions gf. The DC base
// class own_data indicates if the dc owns the mesh object pointer itself and
// GF objects. Can we use one flag and just have DC own all objects vs none?
const bool m_owns_mesh_data;
// Name to be used for registering the mesh nodes in the SidreDataCollection.
// This name is used by SetMesh() and can be overwritten by the method
// SetMeshNodesName().
// Default value: "mesh_nodes".
std::string m_meshNodesGFName;
// If the data collection owns the datastore, it will store a pointer to it.
// Otherwise, this pointer is NULL.
axom::sidre::DataStore * m_datastore_ptr;
protected:
axom::sidre::Group *named_buffers_grp() const;
axom::sidre::View *
alloc_view(axom::sidre::Group *grp,
const std::string &view_name);
axom::sidre::View *
alloc_view(axom::sidre::Group *grp,
const std::string &view_name,
const axom::sidre::DataType &dtype);
axom::sidre::Group *
alloc_group(axom::sidre::Group *grp,
const std::string &group_name);
// return the filename based on prefix_path, collection name and cycle.
std::string get_file_path(const std::string &filename) const;
private:
// If the data collection does not own the datastore, it will need pointers
// to the blueprint and blueprint index group to use.
axom::sidre::Group * m_bp_grp;
axom::sidre::Group * m_bp_index_grp;
// This is stored for convenience.
axom::sidre::Group * m_named_bufs_grp;
// Private helper functions
void RegisterFieldInBPIndex(const std::string& field_name,
GridFunction *gf);
void DeregisterFieldInBPIndex(const std::string & field_name);
void RegisterAttributeFieldInBPIndex(const std::string& attr_name);
void DeregisterAttributeFieldInBPIndex(const std::string& attr_name);
/** @brief Return a string with the conduit blueprint name for the given
Element::Type. */
std::string getElementName( Element::Type elementEnum );
/**
* \brief A private helper function to set up the views associated with the
data of a scalar valued grid function in the blueprint style.
* \pre gf is not null
* \note This function is expected to be called by RegisterField()
* \note Handles cases where hierarchy is already set up,
* where the data was allocated by this data collection
* and where the grid function data is external to Sidre
*/
void addScalarBasedGridFunction(const std::string& field_name,
GridFunction* gf,
const std::string &buffer_name,
axom::sidre::IndexType offset);
/**
* \brief A private helper function to set up the views associated with the
data of a vector valued grid function in the blueprint style.
* \pre gf is not null
* \note This function is expected to be called by RegisterField()
* \note Handles cases where hierarchy is already set up,
* where the data was allocated by this data collection
* and where the grid function data is external to Sidre
*/
void addVectorBasedGridFunction(const std::string& field_name,
GridFunction* gf,
const std::string &buffer_name,
axom::sidre::IndexType offset);
/** @brief A private helper function to set up the Views associated with
attribute field named @a field_name */
void addIntegerAttributeField(const std::string& field_name, bool is_bdry);
/// Sets up the four main mesh blueprint groups.
/**
* \param hasBP Indicates whether the blueprint has already been set up.
*/
void createMeshBlueprintStubs(bool hasBP);
/// Sets up the mesh blueprint 'state' group.
/**
* \param hasBP Indicates whether the blueprint has already been set up.
*/
void createMeshBlueprintState(bool hasBP);
/// Sets up the mesh blueprint 'coordsets' group.
/**
* \param hasBP Indicates whether the blueprint has already been set up.
*/
void createMeshBlueprintCoordset(bool hasBP);
/// Sets up the mesh blueprint 'topologies' group.
/**
* This method is called from SetMesh().
* \param hasBP Indicates whether the blueprint has already been set up.
* \param mesh_name The name of the topology.
* \note Valid values for @a mesh_name are "mesh" and "boundary" and the
former has to be created with this method before the latter.
*/
void createMeshBlueprintTopologies(bool hasBP, const std::string& mesh_name);
#ifdef MFEM_USE_MPI
/// Sets up the mesh blueprint 'adjacencies' group.
/**
* \param hasBP Indicates whether the blueprint has already been set up.
* \note Only valid when using parallel meshes
*/
void createMeshBlueprintAdjacencies(bool hasBP);
#endif
/// Verifies that the contents of the mesh blueprint data is valid.
void verifyMeshBlueprint();
};
} // end namespace mfem
#endif
#endif
+5 -2
View File
@@ -4102,8 +4102,11 @@ void TMOP_Integrator::GetSurfaceFittingErrors(const Vector &d_loc,
#ifdef MFEM_USE_MPI
// Don't count the overlapping DOFs in parallel.
// The pfes might be ordered byVDIM, while the loop goes consecutively.
const int dof_i = pfes->DofToVDof(i, 0);
if (parallel && pfes->GetLocalTDofNumber(dof_i) < 0) { continue; }
if (parallel)
{
const int dof_i = pfes->DofToVDof(i, 0);
if (pfes->GetLocalTDofNumber(dof_i) < 0) { continue; }
}
#endif
dof_cnt++;
+24 -1
View File
@@ -114,10 +114,22 @@ public:
Array<T> &operator=(const Array<T> &src) { src.Copy(*this); return *this; }
/// Move assignment operator
/** If *this is a non-owning view (e.g., from MakeRef()), the data is copied
so that the base is also modified. */
Array<T> &operator=(Array<T> &&src)
{
if (this == &src) { return *this; }
Swap(src); // Swap does not use move assignment!
// If *this is a non-owning view (alias), and its capacity is sufficient
// to contain src, then copy into *this so that the alias's base memory is
// modified.
if (!OwnsData() && Capacity() >= src.Size())
{
*this = src; // Copy assignment.
}
else
{
Swap(src); // Swap the pointers only.
}
src.DeleteAll();
return *this;
}
@@ -251,6 +263,9 @@ public:
/// Make this Array a reference to 'master'.
inline void MakeRef(const Array &master);
/// Make this Array a reference to the given sub-Memory of @a base.
inline void MakeRef(Memory<T> &base, int offset, int size_);
/// Reset the Array to use the given external Memory @a mem and size @a s.
/** If @a own_mem is false, the Array will not own any of the pointers of
@a mem.
@@ -1073,6 +1088,14 @@ inline void Array<T>::MakeRef(const Array &master)
data.MakeAlias(master.GetMemory(), 0, size);
}
template <class T>
inline void Array<T>::MakeRef(Memory<T> &base, int offset, int size_)
{
data.Delete();
size = size_;
data.MakeAlias(base, offset, size_);
}
template <class T>
inline void Array<T>::NewMemoryAndSize(
const Memory<T> &mem, int s, bool own_mem)
+12 -3
View File
@@ -278,9 +278,18 @@ void ArraysByName<T>::Load(std::istream &in)
q1 = ArrayLine.find(' ');
ArrayName = ArrayLine.substr(0,q1-1);
}
// Ignore the remainder of the line which may contain explanatory comments
data[ArrayName].Load(in, 0);
if (q1+2 < ArrayLine.size())
{
// Read the remainder of the line which contains the array data
std::istringstream ArrayDataStream(ArrayLine.substr(q1+2,
ArrayLine.size()));
data[ArrayName].Load(ArrayDataStream, 0);
}
else
{
// Read the array data starting on the next line
data[ArrayName].Load(in, 0);
}
}
}
+4 -4
View File
@@ -726,16 +726,16 @@ std::string Device::GetUUID(const int device_id)
MFEM_GPU_CHECK(cudaGetDeviceProperties(&prop, device_id));
for (int i = 0; i < 16; ++i)
{
res << std::setfill('0') << std::setw(2) << std::hex
<< static_cast<unsigned>(prop.uuid.bytes[i]);
const unsigned b = static_cast<unsigned char>(prop.uuid.bytes[i]);
res << std::setfill('0') << std::setw(2) << std::hex << b;
}
#elif defined(MFEM_USE_HIP)
hipUUID uuid;
MFEM_GPU_CHECK(hipDeviceGetUuid(&uuid, device_id));
for (int i = 0; i < 16; ++i)
{
res << std::setfill('0') << std::setw(2) << std::hex
<< static_cast<unsigned>(uuid.bytes[i]);
const unsigned b = static_cast<unsigned char>(uuid.bytes[i]);
res << std::setfill('0') << std::setw(2) << std::hex << b;
}
#endif
return res.str();
+4
View File
@@ -113,6 +113,10 @@ void SetGlobalMPI_Comm(MPI_Comm comm);
/// to suppress the warning.
const char* GetEnv(const char* name);
/// Signed indices i -> -1 - i are used as a convention to encode orientation.
inline MFEM_HOST_DEVICE int FlipIndexSign(int i) { return -1 - i; }
inline MFEM_HOST_DEVICE int UnsignIndex(int i) { return i < 0 ? -1 - i : i; }
} // namespace mfem
#endif
+6 -2
View File
@@ -759,7 +759,9 @@ private:
{
switch (mt)
{
case MT::HOST_DEBUG: return new MmuHostMemorySpace();
case MT::HOST_DEBUG:
if (GetEnv("MFEM_MMU_STD")) { return new StdHostMemorySpace(); }
return new MmuHostMemorySpace();
#ifdef MFEM_USE_UMPIRE
case MT::HOST_UMPIRE:
return new UmpireHostMemorySpace(
@@ -788,7 +790,9 @@ private:
case MT::DEVICE_UMPIRE: return new NoDeviceMemorySpace();
case MT::DEVICE_UMPIRE_2: return new NoDeviceMemorySpace();
#endif
case MT::DEVICE_DEBUG: return new MmuDeviceMemorySpace();
case MT::DEVICE_DEBUG:
if (GetEnv("MFEM_MMU_STD")) { return new StdDeviceMemorySpace(); }
return new MmuDeviceMemorySpace();
case MT::DEVICE:
{
#if defined(MFEM_USE_CUDA)
-3
View File
@@ -160,9 +160,6 @@ const char *GetConfigStr()
#ifdef MFEM_USE_RAJA
"MFEM_USE_RAJA\n"
#endif
#ifdef MFEM_USE_SIDRE
"MFEM_USE_SIDRE\n"
#endif
#ifdef MFEM_USE_SIMD
"MFEM_USE_SIMD\n"
#endif
-1
View File
@@ -55,7 +55,6 @@ list(APPEND HDRS
dinvariants.hpp
dtensor.hpp
dual.hpp
eigensolver.hpp
filteredsolver.hpp
handle.hpp
invariants.hpp
+9
View File
@@ -82,6 +82,15 @@ public:
}
}
/// Make the DenseMatrix to reference the given sub-Memory of @a base.
/** The DenseMatrix does not assume ownership of the data array, i.e. it will
not delete the @a base Memory. */
void MakeRef(Memory<real_t> &base, int offset, int h, int w)
{
data.MakeRef(base, offset, h*w);
height = h; width = w;
}
/// Change the data array and the size of the DenseMatrix.
/** The DenseMatrix does not assume ownership of the data array, i.e. it will
not delete the data array @a d. */
-203
View File
@@ -1,203 +0,0 @@
// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
/**
* @file eigensolver.hpp
*
* @brief This file contains a common interface for all eigensolver classes
*/
#ifndef MFEM_EIGENSOLVER
#define MFEM_EIGENSOLVER
#ifdef MFEM_HYPRE
#include "hypre.hpp"
#endif
#ifdef MFEM_SLEPC
#include "slepc.hpp"
#endif
namespace mfem
{
enum class EigenSolverType
{
HYPRE,
SLEPC,
INVALID_TYPE
};
/// Provides base class for MFEM Eigensolvers
class EigenSolverBase
{
public:
EigenSolverBase() {}
/// Destructor
virtual ~EigenSolverBase() = default;
/// Solves the eigenvalue problem
virtual void Solve() = 0;
/// Set the required number of modes
virtual void SetNumModes(int num_Modes)
{
numModes=num_Modes;
}
/// @brief Set the operator to the eigenvalue problem
/// @param A - operator
virtual void SetOperator(Operator& A) = 0;
/// @brief Sets operators for the generalized eigenvalue problem
/// @param A - operator
/// @param M - mass matrix
virtual void SetOperator(Operator& A, Operator& M)
{
MFEM_ABORT("Generalized eigensolver is not supported!");
}
/// Optional method - sets preconditioner for the
/// eigenvalue solver.
virtual void SetPreconditioner(Solver& precond)
{
MFEM_ABORT("Preconditioner is not supported!");
}
/// Returns the converged eigenvalues
virtual void GetEigenvalues(Array<real_t>& eigen_vals) = 0;
/// Returns the vec_index eigenvector.
virtual void GetEigenvector(int vec_index, Vector& vector) = 0;
/// Returns the eigensolver type.
EigenSolverType GetSolverType() { return eigSolverType; }
protected:
int numModes = 0;
EigenSolverType eigSolverType = EigenSolverType::INVALID_TYPE;
};
#ifdef MFEM_HYPRE
class EigenSolverHypreLOBPCG : public EigenSolverBase
{
public:
EigenSolverHypreLOBPCG(MPI_Comm comm)
{
eigenSolver = std::make_unique<HypreLOBPCG>(comm);
eigSolverType = EigenSolverType::HYPRE;
}
~EigenSolverHypreLOBPCG() {}
void Solve() override { eigenSolver->Solve(); }
void SetNumModes(int num_Modes) override
{
eigenSolver->SetNumModes(num_Modes);
numModes = num_Modes;
}
void SetOperator(Operator& A) override { eigenSolver->SetOperator(A); }
void SetOperator(Operator& A, Operator& M) override
{
eigenSolver->SetOperator(A);
eigenSolver->SetMassMatrix(M);
}
void SetPreconditioner(Solver& precond) override { eigenSolver->SetPreconditioner(precond); }
void GetEigenvalues(Array<real_t>& eigen_vals) override { eigenSolver->GetEigenvalues(eigen_vals); }
void GetEigenvector(int vec_index, Vector& vector) override
{
const HypreParVector& eigenvec = eigenSolver->GetEigenvector(vec_index);
vector = eigenvec;
}
void SetTol(real_t tol) { eigenSolver->SetTol(tol); }
void SetRelTol(real_t rel_tol) { eigenSolver->SetRelTol(rel_tol); }
void SetMaxIter(int max_iter) { eigenSolver->SetMaxIter(max_iter); }
void SetPrintLevel(int logging) { eigenSolver->SetPrintLevel(logging); }
void SetRandomSeed(int seed) { eigenSolver->SetRandomSeed(seed); }
void SetPrecondUsageMode(int usage_mode) { eigenSolver->SetPrecondUsageMode(usage_mode); }
private:
std::unique_ptr<HypreLOBPCG> eigenSolver = nullptr;
};
#endif
#ifdef MFEM_SLEPC
class EigenSolverSlepc : public EigenSolverBase
{
public:
EigenSolverSlepc(MPI_Comm comm)
{
eigSolverType = EigenSolverType::SLEPC;
eigenSolver = std::make_unique<SlepcEigenSolver>(comm);
eigenSolver->SetWhichEigenpairs(SlepcEigenSolver::TARGET_REAL);
eigenSolver->SetTarget(0.0);
eigenSolver->SetSpectralTransformation(SlepcEigenSolver::SHIFT_INVERT);
}
~EigenSolverSlepc() {}
void Solve() override { eigenSolver->Solve(); }
void SetNumModes(int num_Modes) override
{
eigenSolver->SetNumModes(num_Modes);
numModes = num_Modes;
}
/// @brief Set the operator to the slepc eigenvalue problem. This method deep copies data to create a PetscParMatrix
/// @param A - operator, must be of type HypreParMatrix.
void SetOperator(Operator& A) override
{
petscMatA = std::make_unique<PetscParMatrix>
(dynamic_cast<HypreParMatrix*>(&A));
eigenSolver->SetOperator(*petscMatA);
}
/// @brief Set the operators to the slepc eigenvalue problem. This method deep copies data to create a PetscParMatrix
/// @param A - operator, must be of type HypreParMatrix.
/// @param M - operator, must be of type HypreParMatrix.
void SetOperator(Operator& A, Operator& M) override
{
petscMatA = std::make_unique<PetscParMatrix>
(dynamic_cast<const HypreParMatrix*>(&A));
petscMatM = std::make_unique<PetscParMatrix>
(dynamic_cast<const HypreParMatrix*>(&M));
eigenSolver->SetOperators(*petscMatA, *petscMatM);
}
void SetPreconditioner([[maybe_unused]] Solver& precond) override {}
void GetEigenvalues(Array<real_t>& eigen_vals) override
{
eigen_vals.SetSize(numModes);
for (int ik = 0; ik < numModes; ik++)
{
eigenSolver->GetEigenvalue(static_cast<unsigned int>(ik), eigen_vals[ik]);
}
}
void GetEigenvector( int vec_index, Vector& vector) override
{ eigenSolver->GetEigenvector(vec_index, vector); }
void SetTol(real_t tol) { eigenSolver->SetTol(tol); }
void SetMaxIter(int max_iter) { eigenSolver->SetMaxIter(max_iter); }
private:
std::unique_ptr<SlepcEigenSolver> eigenSolver = nullptr;
std::unique_ptr<PetscParMatrix> petscMatA = nullptr;
std::unique_ptr<PetscParMatrix> petscMatM = nullptr;
};
#endif
} // namespace mfem
#endif
+3
View File
@@ -317,6 +317,9 @@ void HypreParVector::WrapHypreParVector(hypre_ParVector *y, bool owner)
Vector * HypreParVector::GlobalVector() const
{
MFEM_VERIFY(size > 0,
"GlobalVector method can only be called on vectors wherein each "
"process owns one or more entries");
hypre_Vector *hv = hypre_ParVectorToVectorAll(*this);
Vector *v = new Vector(hv->data, internal::to_int(hv->size));
v->MakeDataOwner();
+61 -84
View File
@@ -38,6 +38,13 @@
#if PETSC_VERSION_LT(3,19,0)
#define PETSC_SUCCESS 0
#endif
#if PETSC_VERSION_LT(3,23,0)
#define PetscContainerSetCtxDestroy(A,B) PetscContainerSetUserDestroy(A,B)
typedef PetscErrorCode (PetscCtxDestroyFn)(void**);
#endif
#if PETSC_VERSION_LT(3,24,0)
typedef PetscErrorCode KSPMonitorFn(KSP,PetscInt,PetscReal,void*);
#endif
#include <fstream>
#include <iomanip>
@@ -77,13 +84,17 @@ static PetscErrorCode __mfem_mat_shell_apply_transpose(Mat,Vec,Vec);
static PetscErrorCode __mfem_mat_shell_destroy(Mat);
static PetscErrorCode __mfem_mat_shell_copy(Mat,Mat,MatStructure);
#if PETSC_VERSION_LT(3,23,0)
static PetscErrorCode __mfem_array_container_destroy(void*);
static PetscErrorCode __mfem_matarray_container_destroy(void *);
#else
static PetscErrorCode __mfem_array_container_destroy(void**);
static PetscErrorCode __mfem_matarray_container_destroy(void**);
typedef void *PetscCtxRt;
#elif PETSC_VERSION_LT(3,25,0)
typedef void **PetscCtxRt;
#endif
static PetscErrorCode __mfem_array_container_destroy(PetscCtxRt);
static PetscErrorCode __mfem_matarray_container_destroy(PetscCtxRt);
#if PETSC_VERSION_LT(3,23,0)
static PetscErrorCode __mfem_monitor_ctx_destroy(void**);
#else
static PetscErrorCode __mfem_monitor_ctx_destroy(PetscCtxRt);
#endif
// auxiliary functions
static PetscErrorCode Convert_Array_IS(MPI_Comm,bool,const mfem::Array<int>*,
@@ -1317,11 +1328,7 @@ BlockDiagonalConstructor(MPI_Comm comm,
ierr = PetscContainerCreate(comm,&c); CCHKERRQ(comm,ierr);
ierr = PetscContainerSetPointer(c,ptrs[i]); CCHKERRQ(comm,ierr);
#if PETSC_VERSION_LT(3,23,0)
ierr = PetscContainerSetUserDestroy(c,__mfem_array_container_destroy);
#else
ierr = PetscContainerSetCtxDestroy(c,__mfem_array_container_destroy);
#endif
CCHKERRQ(comm,ierr);
ierr = PetscObjectCompose((PetscObject)A,names[i],(PetscObject)c);
CCHKERRQ(comm,ierr);
@@ -1648,11 +1655,7 @@ void PetscParMatrix::ConvertOperator(MPI_Comm comm, const Operator &op, Mat* A,
PetscContainer c;
ierr = PetscContainerCreate(comm,&c); CCHKERRQ(comm,ierr);
ierr = PetscContainerSetPointer(c,vmatsl2l); PCHKERRQ(c,ierr);
#if PETSC_VERSION_LT(3,23,0)
ierr = PetscContainerSetUserDestroy(c,__mfem_matarray_container_destroy);
#else
ierr = PetscContainerSetCtxDestroy(c,__mfem_matarray_container_destroy);
#endif
PCHKERRQ(c,ierr);
ierr = PetscObjectCompose((PetscObject)(*A),"_MatIS_PtAP_l2l",(PetscObject)c);
PCHKERRQ((*A),ierr);
@@ -1748,11 +1751,7 @@ void PetscParMatrix::ConvertOperator(MPI_Comm comm, const Operator &op, Mat* A,
ierr = PetscContainerCreate(PETSC_COMM_SELF,&c); PCHKERRQ(B,ierr);
ierr = PetscContainerSetPointer(c,ptrs[i]); PCHKERRQ(B,ierr);
#if PETSC_VERSION_LT(3,23,0)
ierr = PetscContainerSetUserDestroy(c,__mfem_array_container_destroy);
#else
ierr = PetscContainerSetCtxDestroy(c,__mfem_array_container_destroy);
#endif
PCHKERRQ(B,ierr);
ierr = PetscObjectCompose((PetscObject)(B),names[i],(PetscObject)c);
PCHKERRQ(B,ierr);
@@ -2198,11 +2197,7 @@ PetscParMatrix * RAP(PetscParMatrix *Rt, PetscParMatrix *A, PetscParMatrix *P)
ierr = PetscContainerCreate(PetscObjectComm((PetscObject)B),&c);
PCHKERRQ(B,ierr);
ierr = PetscContainerSetPointer(c,vmatsl2l); PCHKERRQ(c,ierr);
#if PETSC_VERSION_LT(3,23,0)
ierr = PetscContainerSetUserDestroy(c,__mfem_matarray_container_destroy);
#else
ierr = PetscContainerSetCtxDestroy(c,__mfem_matarray_container_destroy);
#endif
PCHKERRQ(c,ierr);
ierr = PetscObjectCompose((PetscObject)B,"_MatIS_PtAP_l2l",(PetscObject)c);
PCHKERRQ(B,ierr);
@@ -2485,7 +2480,6 @@ void PetscSolver::SetMaxIter(int max_iter)
void PetscSolver::SetPrintLevel(int plev)
{
typedef PetscErrorCode (*myPetscFunc)(void**);
PetscViewerAndFormat *vf = NULL;
PetscViewer viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm(obj));
@@ -2498,7 +2492,6 @@ void PetscSolver::SetPrintLevel(int plev)
{
// there are many other options, see the function KSPSetFromOptions() in
// src/ksp/ksp/interface/itcl.c
typedef PetscErrorCode (*myMonitor)(KSP,PetscInt,PetscReal,void*);
KSP ksp = (KSP)obj;
if (plev >= 0)
{
@@ -2507,29 +2500,29 @@ void PetscSolver::SetPrintLevel(int plev)
if (plev == 1)
{
#if PETSC_VERSION_LT(3,15,0)
ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorDefault,vf,
ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorDefault,vf,
#else
ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorResidual,vf,
ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorResidual,vf,
#endif
(myPetscFunc)PetscViewerAndFormatDestroy);
(PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
PCHKERRQ(ksp,ierr);
}
else if (plev > 1)
{
ierr = KSPSetComputeSingularValues(ksp,PETSC_TRUE); PCHKERRQ(ksp,ierr);
ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorSingularValue,vf,
(myPetscFunc)PetscViewerAndFormatDestroy);
ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorSingularValue,vf,
(PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
PCHKERRQ(ksp,ierr);
if (plev > 2)
{
ierr = PetscViewerAndFormatCreate(viewer,PETSC_VIEWER_DEFAULT,&vf);
PCHKERRQ(viewer,ierr);
#if PETSC_VERSION_LT(3,15,0)
ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorTrueResidualNorm,vf,
ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorTrueResidualNorm,vf,
#else
ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorTrueResidual,vf,
ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorTrueResidual,vf,
#endif
(myPetscFunc)PetscViewerAndFormatDestroy);
(PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
PCHKERRQ(ksp,ierr);
}
}
@@ -2545,7 +2538,7 @@ void PetscSolver::SetPrintLevel(int plev)
if (plev > 0)
{
ierr = SNESMonitorSet(snes,(myMonitor)SNESMonitorDefault,vf,
(myPetscFunc)PetscViewerAndFormatDestroy);
(PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
PCHKERRQ(snes,ierr);
}
}
@@ -4163,20 +4156,31 @@ void PetscNonlinearSolver::SetUpdate(void (*update)(Operator *,int,
void PetscNonlinearSolver::Mult(const Vector &b, Vector &x) const
{
SNES snes = (SNES)obj;
MPI_Comm comm = PetscObjectComm(obj);
bool b_nonempty = b.Size();
if (!B) { B = new PetscParVector(PetscObjectComm(obj), *this, true); }
if (!X) { X = new PetscParVector(PetscObjectComm(obj), *this, false, false); }
// Reduction needed: some processes may have null local size while others don't,
// and VecPlaceArray (used by PlaceMemory) is a logically collective operation.
PetscBool b_nonempty = b.Size() ? PETSC_TRUE : PETSC_FALSE;
#if PETSC_VERSION_LT(3,24,0)
mpiierr = MPI_Allreduce(MPI_IN_PLACE,&b_nonempty,1,MPIU_BOOL,MPI_LOR,comm);
#else
mpiierr = MPI_Allreduce(MPI_IN_PLACE,&b_nonempty,1,MPI_C_BOOL,MPI_LOR,comm);
#endif
CCHKERRQ(comm,mpiierr);
// Always create B with allocate=false so that PlaceMemory can be called on
// it regardless of whether b was empty on a previous call.
if (!B) { B = new PetscParVector(comm, *this, true, false); }
if (!X) { X = new PetscParVector(comm, *this, false, false); }
X->PlaceMemory(x.GetMemory(),iterative_mode);
if (b_nonempty) { B->PlaceMemory(b.GetMemory()); }
else { *B = 0.0; }
Customize();
if (!iterative_mode) { *X = 0.; }
// Solve the system.
ierr = SNESSolve(snes, B->x, X->x); PCHKERRQ(snes, ierr);
// Solve the system. Pass nullptr for b when empty (PETSc treats it as zero RHS).
ierr = SNESSolve(snes, b_nonempty ? B->x : nullptr, X->x); PCHKERRQ(snes, ierr);
X->ResetMemory();
if (b_nonempty) { B->ResetMemory(); }
}
@@ -5329,21 +5333,27 @@ static PetscErrorCode __mfem_pc_shell_destroy(PC pc)
PetscFunctionReturn(PETSC_SUCCESS);
}
static PetscErrorCode __mfem_array_container_destroy(PetscCtxRt ptr)
{
PetscErrorCode ierr;
PetscFunctionBeginUser;
#if PETSC_VERSION_LT(3,23,0)
static PetscErrorCode __mfem_array_container_destroy(void *ptr)
{
PetscErrorCode ierr;
PetscFunctionBeginUser;
ierr = PetscFree(ptr); CHKERRQ(ierr);
#else
ierr = PetscFree(*(void**)ptr); CHKERRQ(ierr);
#endif
PetscFunctionReturn(PETSC_SUCCESS);
}
static PetscErrorCode __mfem_matarray_container_destroy(void *ptr)
static PetscErrorCode __mfem_matarray_container_destroy(PetscCtxRt ptr)
{
#if PETSC_VERSION_LT(3,23,0)
mfem::Array<Mat> *a = (mfem::Array<Mat>*)ptr;
PetscErrorCode ierr;
#else
mfem::Array<Mat> *a = *(mfem::Array<Mat>**)ptr;
#endif
PetscErrorCode ierr;
PetscFunctionBeginUser;
for (int i=0; i<a->Size(); i++)
@@ -5356,41 +5366,16 @@ static PetscErrorCode __mfem_matarray_container_destroy(void *ptr)
PetscFunctionReturn(PETSC_SUCCESS);
}
#if PETSC_VERSION_LT(3,23,0)
static PetscErrorCode __mfem_monitor_ctx_destroy(void **ctx)
#else
static PetscErrorCode __mfem_array_container_destroy(void **ptr)
static PetscErrorCode __mfem_monitor_ctx_destroy(PetscCtxRt ctx)
#endif
{
PetscErrorCode ierr;
PetscFunctionBeginUser;
ierr = PetscFree(*ptr); CHKERRQ(ierr);
PetscFunctionReturn(PETSC_SUCCESS);
}
static PetscErrorCode __mfem_matarray_container_destroy(void **ptr)
{
mfem::Array<Mat> *a = (mfem::Array<Mat>*)*ptr;
PetscErrorCode ierr;
PetscFunctionBeginUser;
for (int i=0; i<a->Size(); i++)
{
Mat M = (*a)[i];
MPI_Comm comm = PetscObjectComm((PetscObject)M);
ierr = MatDestroy(&M); CCHKERRQ(comm,ierr);
}
delete a;
PetscFunctionReturn(PETSC_SUCCESS);
}
#endif
static PetscErrorCode __mfem_monitor_ctx_destroy(void **ctx)
{
PetscErrorCode ierr;
PetscFunctionBeginUser;
ierr = PetscFree(*ctx); CHKERRQ(ierr);
ierr = PetscFree(*(void**)ctx); CHKERRQ(ierr);
PetscFunctionReturn(PETSC_SUCCESS);
}
@@ -5635,11 +5620,7 @@ static PetscErrorCode MatConvert_hypreParCSR_AIJ(hypre_ParCSRMatrix* hA,Mat* pA)
ierr = PetscContainerCreate(comm,&c); CHKERRQ(ierr);
ierr = PetscContainerSetPointer(c,ptrs[i]); CHKERRQ(ierr);
#if PETSC_VERSION_LT(3,23,0)
ierr = PetscContainerSetUserDestroy(c,__mfem_array_container_destroy);
#else
ierr = PetscContainerSetCtxDestroy(c,__mfem_array_container_destroy);
#endif
CHKERRQ(ierr);
ierr = PetscObjectCompose((PetscObject)(*pA),names[i],(PetscObject)c);
CHKERRQ(ierr);
@@ -5733,11 +5714,7 @@ static PetscErrorCode MatConvert_hypreParCSR_IS(hypre_ParCSRMatrix* hA,Mat* pA)
ierr = PetscContainerCreate(PETSC_COMM_SELF,&c); CHKERRQ(ierr);
ierr = PetscContainerSetPointer(c,ptrs[i]); CHKERRQ(ierr);
#if PETSC_VERSION_LT(3,23,0)
ierr = PetscContainerSetUserDestroy(c,__mfem_array_container_destroy);
#else
ierr = PetscContainerSetCtxDestroy(c,__mfem_array_container_destroy);
#endif
CHKERRQ(ierr);
ierr = PetscObjectCompose((PetscObject)lA,names[i],(PetscObject)c);
CHKERRQ(ierr);
+4 -5
View File
@@ -126,11 +126,11 @@ EXAMPLE_TEST_DIRS := examples
MINIAPP_SUBDIRS = common electromagnetics meshing performance tools \
toys nurbs gslib adjoint solvers shifted mtop parelag tribol autodiff dfem \
hooke multidomain dpg hdiv-linear-solver spde diag-smoothers contact \
fluids/navier fluids/schrodinger-flow
fluids/navier fluids/schrodinger-flow plasma
MINIAPP_DIRS := $(addprefix miniapps/,$(MINIAPP_SUBDIRS))
MINIAPP_TEST_DIRS := $(filter-out %/common,$(MINIAPP_DIRS))
MINIAPP_USE_COMMON := $(addprefix miniapps/,electromagnetics meshing tools \
toys shifted dpg diag-smoothers fluids/navier)
toys shifted dpg diag-smoothers fluids/navier plasma)
EM_DIRS = $(EXAMPLE_DIRS) $(MINIAPP_DIRS)
@@ -299,7 +299,7 @@ ifeq ($(MFEM_USE_LEGACY_OPENMP),YES)
endif
# List of MFEM dependencies, that require the *_LIB variable to be non-empty
MFEM_REQ_LIB_DEPS = SUPERLU MUMPS METIS FMS CONDUIT SIDRE LAPACK SUNDIALS\
MFEM_REQ_LIB_DEPS = SUPERLU MUMPS METIS FMS CONDUIT LAPACK SUNDIALS\
SUITESPARSE STRUMPACK GINKGO GNUTLS HDF5 NETCDF SLEPC PETSC MPFR PUMI HIOP\
GSLIB OCCA CEED RAJA UMPIRE MKL_CPARDISO MKL_PARDISO AMGX MAGMA CALIPER PARELAG\
TRIBOL BENCHMARK MOONOLITH ALGOIM
@@ -365,7 +365,7 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\
MFEM_USE_LEGACY_OPENMP MFEM_USE_MEMALLOC MFEM_TIMER_TYPE MFEM_USE_SUNDIALS\
MFEM_USE_SUITESPARSE MFEM_USE_GINKGO MFEM_USE_SUPERLU MFEM_USE_SUPERLU5\
MFEM_USE_STRUMPACK MFEM_USE_GNUTLS MFEM_USE_HDF5 MFEM_USE_NETCDF MFEM_USE_PETSC\
MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_FMS MFEM_USE_CONDUIT\
MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_FMS MFEM_USE_CONDUIT\
MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\
MFEM_USE_OCCA MFEM_USE_MOONOLITH MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE\
MFEM_USE_SIMD MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO MFEM_USE_MKL_PARDISO MFEM_USE_AMGX\
@@ -746,7 +746,6 @@ status info:
$(info MFEM_USE_PETSC = $(MFEM_USE_PETSC))
$(info MFEM_USE_SLEPC = $(MFEM_USE_SLEPC))
$(info MFEM_USE_MPFR = $(MFEM_USE_MPFR))
$(info MFEM_USE_SIDRE = $(MFEM_USE_SIDRE))
$(info MFEM_USE_FMS = $(MFEM_USE_FMS))
$(info MFEM_USE_CONDUIT = $(MFEM_USE_CONDUIT))
$(info MFEM_USE_PUMI = $(MFEM_USE_PUMI))
+58 -52
View File
@@ -493,8 +493,7 @@ void Mesh::GetBdrElementTransformation(int i,
{
for (int j = 0; j < n; j++)
{
int idx = vdofs[n*k+j];
pm(k,j) = nodes((idx<0)? -1-idx:idx);
pm(k,j) = nodes(UnsignIndex(vdofs[n*k+j]));
}
}
ElTr->SetFE(bdr_el);
@@ -1356,7 +1355,7 @@ Mesh::FaceInformation Mesh::GetFaceInformation(int f) const
face.element[0].conformity = ElementConformity::Coincident;
face.element[1].conformity = ElementConformity::Coincident;
face.element[1].location = ElementLocation::FaceNbr;
face.element[1].index = -1 - e2;
face.element[1].index = FlipIndexSign(e2);
face.element[1].orientation = inf2%64;
}
}
@@ -1379,7 +1378,7 @@ Mesh::FaceInformation Mesh::GetFaceInformation(int f) const
face.element[1].location = ElementLocation::FaceNbr;
face.element[0].conformity = ElementConformity::Coincident;
face.element[1].conformity = ElementConformity::Superset;
face.element[1].index = -1 - e2;
face.element[1].index = FlipIndexSign(e2);
face.element[1].orientation = inf2%64;
}
face.point_matrix = nc_faces_info[ncface].PointMatrix;
@@ -1405,7 +1404,7 @@ Mesh::FaceInformation Mesh::GetFaceInformation(int f) const
face.element[1].location = ElementLocation::FaceNbr;
face.element[0].conformity = ElementConformity::Superset;
face.element[1].conformity = ElementConformity::Coincident;
face.element[1].index = -1 - e2;
face.element[1].index = FlipIndexSign(e2);
face.element[1].orientation = inf2%64;
face.point_matrix = nc_faces_info[ncface].PointMatrix;
}
@@ -1438,7 +1437,7 @@ Mesh::FaceInformation::operator Mesh::FaceInfo() const
break;
case FaceInfoTag::SharedConforming:
res.Elem1No = element[0].index;
res.Elem2No = -1 - element[1].index;
res.Elem2No = FlipIndexSign(element[1].index);
res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
break;
@@ -1448,7 +1447,7 @@ Mesh::FaceInformation::operator Mesh::FaceInfo() const
break;
case FaceInfoTag::SharedSlaveNonconforming:
res.Elem1No = element[0].index;
res.Elem2No = -1 - element[1].index;
res.Elem2No = FlipIndexSign(element[1].index);
res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
break;
@@ -1456,7 +1455,7 @@ Mesh::FaceInformation::operator Mesh::FaceInfo() const
break;
case FaceInfoTag::GhostSlave:
res.Elem1No = element[0].index;
res.Elem2No = -1 - element[1].index;
res.Elem2No = FlipIndexSign(element[1].index);
res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
break;
@@ -6514,7 +6513,7 @@ void Mesh::LoadPatchTopo(std::istream &input, Array<int> &edge_to_ukv)
input >> edge_to_ukv[j] >> v[0] >> v[1];
if (v[0] > v[1])
{
edge_to_ukv[j] = -1 - edge_to_ukv[j];
edge_to_ukv[j] = FlipIndexSign(edge_to_ukv[j]);
}
}
}
@@ -6551,9 +6550,6 @@ void Mesh::GetEdgeToUniqueKnotvector(Array<int> &edge_to_ukv,
const int NP = NumOfElements; // number of patches
const int NPKV = NP * dim; // number of patch knotvectors
constexpr int notset = -9999999;
// Sign convention
auto flipSign = [](int i) { return -1 - i; };
auto unSign = [](int i) { return (i < 0) ? -1 - i : i; };
// Local edge index -> dimension convention
auto edge_to_dim = [](int i) { return (i < 8) ? ((i & 1) ? 1 : 0) : 2; };
@@ -6569,7 +6565,7 @@ void Mesh::GetEdgeToUniqueKnotvector(Array<int> &edge_to_ukv,
{
GetElementVertices(i, v);
// Sign is based on the edge's vertex indices
edge_to_ukv[i] = (v[1] > v[0]) ? i : flipSign(i);
edge_to_ukv[i] = (v[1] > v[0]) ? i : FlipIndexSign(i);
ukv_to_rpkv[i] = i;
}
return;
@@ -6619,14 +6615,14 @@ void Mesh::GetEdgeToUniqueKnotvector(Array<int> &edge_to_ukv,
// We've set this edge already - link this index to it
if (edge_to_pkv[edge] != notset)
{
const int pkv_other = unSign(edge_to_pkv[edge]);
const int pkv_other = UnsignIndex(edge_to_pkv[edge]);
unite(pkv, pkv_other);
}
else
{
GetEdgeVertices(edge, v);
// Sign is based on the edge's vertex indices
edge_to_pkv[edge] = (v[1] > v[0]) ? pkv : flipSign(pkv);
edge_to_pkv[edge] = (v[1] > v[0]) ? pkv : FlipIndexSign(pkv);
}
}
}
@@ -6653,10 +6649,10 @@ void Mesh::GetEdgeToUniqueKnotvector(Array<int> &edge_to_ukv,
edge_to_ukv.SetSize(NumOfEdges);
for (int i = 0; i < NumOfEdges; i++)
{
const int pkv = unSign(edge_to_pkv[i]);
const int pkv = UnsignIndex(edge_to_pkv[i]);
const int rpkv = pkv_to_rpkv[pkv];
const int ukv = rpkv_to_ukv[rpkv];
edge_to_ukv[i] = (edge_to_pkv[i] < 0) ? flipSign(ukv) : ukv;
edge_to_ukv[i] = (edge_to_pkv[i] < 0) ? FlipIndexSign(ukv) : ukv;
}
CorrectPatchTopoOrientations(edge_to_ukv);
@@ -6667,9 +6663,6 @@ void Mesh::CorrectPatchTopoOrientations(Array<int> &edge_to_ukv) const
const int dim = Dimension(); // Topological (not physical) dimension
if (dim == 1) { return; }
// Sign convention
auto flipSign = [](int i) { return -1 - i; };
const Table *face2elem = GetFaceToElementTable();
Array<int> pfaces, orient;
Array<int> fe, feo;
@@ -6688,7 +6681,7 @@ void Mesh::CorrectPatchTopoOrientations(Array<int> &edge_to_ukv) const
for (auto e : fe)
{
const int skv = edge_to_ukv[e];
if (skv == kv || flipSign(skv) == kv) { hasKV = true; }
if (skv == kv || FlipIndexSign(skv) == kv) { hasKV = true; }
}
if (hasKV)
{
@@ -6718,7 +6711,7 @@ void Mesh::CorrectPatchTopoOrientations(Array<int> &edge_to_ukv) const
};
}
Array<int> ukvs((dim==2) ? 4 : 12);
Array<int> ukvs((dim == 2) ? 4 : 12);
Array<int> pe, oe;
bool initKV = false;
@@ -6732,7 +6725,7 @@ void Mesh::CorrectPatchTopoOrientations(Array<int> &edge_to_ukv) const
for (int i = 0; i < pe.Size(); i++)
{
ukvs[i] = edge_to_ukv[pe[i]];
ukvs[i] = (oe[i] < 0) ? flipSign(ukvs[i]) : ukvs[i];
ukvs[i] = (oe[i] < 0) ? FlipIndexSign(ukvs[i]) : ukvs[i];
}
// Find the direction with this kv.
@@ -6740,12 +6733,19 @@ void Mesh::CorrectPatchTopoOrientations(Array<int> &edge_to_ukv) const
for (int d=0; d<dim; ++d) // Loop over directions.
{
const int skv = edge_to_ukv[pe[dir_edges[d][0]]];
if (skv == kv || flipSign(skv) == kv)
if (skv == kv || FlipIndexSign(skv) == kv)
{
thisDir = d;
for (auto e : dir_edges[d])
if (!edgeSet[pe[e]])
{
thisDir = d;
}
}
}
MFEM_VERIFY(thisDir >= 0, "");
if (thisDir == -1)
{
return false;
}
// For this direction, find any edge already set. If no edge is set, we
// arbitrarily take the first.
@@ -6777,12 +6777,12 @@ void Mesh::CorrectPatchTopoOrientations(Array<int> &edge_to_ukv) const
}
const int edge = pe[i];
if ((dim == 2 && ukvs[i] != flipSign(ukvs[ref_edge0])) ||
(dim == 3 && ukvs[i] == flipSign(ukvs[ref_edge0])))
if ((dim == 2 && ukvs[i] != FlipIndexSign(ukvs[ref_edge0])) ||
(dim == 3 && ukvs[i] == FlipIndexSign(ukvs[ref_edge0])))
{
// Flip the sign of this edge
MFEM_VERIFY(!edgeSet[edge], "");
edge_to_ukv[edge] = flipSign(edge_to_ukv[edge]);
MFEM_ASSERT(!edgeSet[edge], "");
edge_to_ukv[edge] = FlipIndexSign(edge_to_ukv[edge]);
}
edgeSet[edge] = true;
@@ -6827,10 +6827,11 @@ void Mesh::CorrectPatchTopoOrientations(Array<int> &edge_to_ukv) const
int unsetDim = -1;
for (int d=0; d<dim; ++d) // Loop over dimensions.
{
if (!edgeSet[pe[dir_edges[d][0]]])
{
unsetDim = d;
}
for (auto e : dir_edges[d])
if (!edgeSet[pe[e]])
{
unsetDim = d;
}
}
if (unsetDim == -1)
@@ -6839,9 +6840,7 @@ void Mesh::CorrectPatchTopoOrientations(Array<int> &edge_to_ukv) const
continue;
}
const int kv_signed = edge_to_ukv[pe[dir_edges[unsetDim][0]]];
const int kv = kv_signed < 0 ? flipSign(kv_signed) : kv_signed;
MFEM_VERIFY(!edgeSet[pe[dir_edges[unsetDim][0]]], "");
const int kv = UnsignIndex(edge_to_ukv[pe[dir_edges[unsetDim][0]]]);
initKV = false;
@@ -6891,6 +6890,7 @@ void Mesh::CorrectPatchTopoOrientations(Array<int> &edge_to_ukv) const
}
}
#ifdef MFEM_DEBUG
bool allSet = true;
for (auto eset : edgeSet)
{
@@ -6899,7 +6899,8 @@ void Mesh::CorrectPatchTopoOrientations(Array<int> &edge_to_ukv) const
allSet = false;
}
}
MFEM_VERIFY(allSet && unset.size() == 0, "Some edge is not set");
MFEM_ASSERT(allSet && unset.size() == 0, "Some edge is not set");
#endif
delete face2elem;
}
@@ -6941,7 +6942,7 @@ void Mesh::LoadNonconformingPatchTopo(std::istream &input,
if (v[0] > v[1])
{
ukv = -1 - ukv;
ukv = FlipIndexSign(ukv);
}
edge_to_ukv[j] = ukv;
}
@@ -12438,11 +12439,7 @@ void Mesh::PrintTopoEdges(std::ostream &os, const Array<int> &e_to_k,
for (int i = 0; i < NumOfEdges; i++)
{
edge_vertex->GetRow(i, vert);
int ki = e_to_k[i];
if (ki < 0)
{
ki = -1 - ki;
}
const int ki = UnsignIndex(e_to_k[i]);
if (vmap)
{
@@ -15751,9 +15748,18 @@ Mesh PartitionMPI(int dim, int mpi_cnt, int elem_per_mpi, bool print,
{
MFEM_VERIFY(dim > 1, "Not implemented for 1D meshes.");
auto factor = [&](int N)
// Closest int divisor to the cubit root, going down.
auto factor3 = [](int N)
{
for (int i = static_cast<int>(sqrt(N)); i > 0; i--)
for (int i = static_cast<int>(round(cbrt(N))); i > 0; i--)
{ if (N % i == 0) { return i; } }
return 1;
};
// Closest int divisor to the square root, going down.
auto factor2 = [](int N)
{
for (int i = static_cast<int>(round(sqrt(N))); i > 0; i--)
{ if (N % i == 0) { return i; } }
return 1;
};
@@ -15777,22 +15783,22 @@ Mesh PartitionMPI(int dim, int mpi_cnt, int elem_per_mpi, bool print,
int el0_x, el0_y, el0_z;
if (dim == 2)
{
mpi_x = factor(mpi_cnt);
mpi_x = factor2(mpi_cnt);
mpi_y = mpi_cnt / mpi_x;
// Switch order for better balance.
el0_y = factor(el0);
el0_y = factor2(el0);
el0_x = el0 / el0_y;
}
else
{
mpi_x = factor(mpi_cnt);
mpi_y = factor(mpi_cnt / mpi_x);
mpi_x = factor3(mpi_cnt);
mpi_y = factor2(mpi_cnt / mpi_x);
mpi_z = mpi_cnt / mpi_x / mpi_y;
// Switch order for better balance.
el0_z = factor(el0);
el0_y = factor(el0 / el0_z);
el0_z = factor3(el0);
el0_y = factor2(el0 / el0_z);
el0_x = el0 / el0_y / el0_z;
}
+12
View File
@@ -3206,10 +3206,22 @@ public:
/// Extrude a 1D mesh
/**
* @param mesh 1D mesh
* @param ny number of transverse elements of the extruded mesh
* @param sy physical size in the direction of extrusion
* @param closed if false, only the original boundaries are extruded,
* otherwise boundaries are generated all around the domain
*/
Mesh *Extrude1D(Mesh *mesh, const int ny, const real_t sy,
const bool closed = false);
/// Extrude a 2D mesh
/**
* @param mesh 2D mesh
* @param nz number of transverse elements of the extruded mesh
* @param sz physical size in the direction of extrusion
*/
Mesh *Extrude2D(Mesh *mesh, const int nz, const real_t sz);
/** @brief Constructs the smallest possible [0,1]^dim serial mesh that can be
+4 -4
View File
@@ -143,7 +143,7 @@ int ThresholdRefiner::ApplyImpl(Mesh &mesh)
if (num_marked_elements == 0LL) { return STOP; }
mesh.GeneralRefinement(marked_elements, non_conforming, nc_limit);
return CONTINUE + REFINED;
return static_cast<int>(CONTINUE) + static_cast<int>(REFINED);
}
void ThresholdRefiner::Reset()
@@ -162,7 +162,7 @@ int ThresholdDerefiner::ApplyImpl(Mesh &mesh)
const Vector &local_err = estimator.GetLocalErrors();
bool derefs = mesh.DerefineByError(local_err, threshold, nc_limit, op);
return derefs ? CONTINUE + DEREFINED : NONE;
return derefs ? static_cast<int>(CONTINUE) + static_cast<int>(DEREFINED) : NONE;
}
@@ -290,7 +290,7 @@ int CoefficientRefiner::PreprocessMesh(Mesh &mesh, int max_it)
}
delete l2fes;
delete gf;
return CONTINUE + REFINED;
return static_cast<int>(CONTINUE) + static_cast<int>(REFINED);
}
@@ -310,7 +310,7 @@ int Rebalancer::ApplyImpl(Mesh &mesh)
if (pmesh && pmesh->Nonconforming())
{
pmesh->Rebalance();
return CONTINUE + REBALANCED;
return static_cast<int>(CONTINUE) + static_cast<int>(REBALANCED);
}
#endif
return NONE;
+6 -3
View File
@@ -1516,12 +1516,15 @@ void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges)
void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
{
string buff;
real_t version;
string version;
int binary, dsize;
input >> version >> binary >> dsize;
if (version < 2.2)
if (version != "2.2")
{
MFEM_ABORT("Gmsh file version < 2.2");
MFEM_ABORT("Gmsh file version must be 2.2, found version "
<< version << ".\n"
"To convert your mesh to the required format, use:\n"
" gmsh -format msh22 -save -o output.msh input.msh");
}
if (dsize != sizeof(double))
{
+2 -2
View File
@@ -3542,7 +3542,7 @@ void NCMesh::TraverseQuadFace(int vn0, int vn1, int vn2, int vn3,
// create a slave face record with a degenerate point matrix
face_list.slaves.Append(
Slave(-1 - enode.edge_index,
Slave(FlipIndexSign(enode.edge_index),
eid[0].element, eid[0].local, Geometry::SQUARE));
Slave &sl = face_list.slaves.Last();
@@ -3589,7 +3589,7 @@ void NCMesh::TraverseTetEdge(int vn0, int vn1, const Point &p0, const Point &p1,
// non-slave edge is really a (face-)slave itself.
const MeshId &eid = *eid_and_type.id;
face_list.slaves.Append(
Slave(-1 - eid.index, eid.element, eid.local, Geometry::TRIANGLE));
Slave(FlipIndexSign(eid.index), eid.element, eid.local, Geometry::TRIANGLE));
int v0index = nodes[vn0].vert_index;
int v1index = nodes[vn1].vert_index;

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