Compare commits

...
Author SHA1 Message Date
Stowell, Mark L 872822da4f Merge remote-tracking branch 'origin/master' into entity-sets-dev 2021-12-07 19:11:39 -08:00
Veselin Dobrev 7e8d8b1d55 Merge pull request #2592 from mfem/pw-coefs-dev
Adding Piecewise coefficient classes [pw-coefs-dev]
2021-12-07 17:39:34 -08:00
Stowell, Mark L fd5505407d Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/pncmesh.hpp
2021-12-07 15:01:43 -08:00
Stowell, Mark L d5c48cb3cc Improving comment for new classes 2021-12-07 13:54:45 -08:00
Veselin Dobrev acb9cfa321 Merge pull request #2631 from white238/task/white238/guard_add_test
Guard add_test calls with MFEM_ENABLE_TESTING
2021-12-07 12:49:58 -08:00
Tzanio Kolev 7ef0a77597 Merge pull request #2668 from mfem/refine-operator-bug-fix
Bug-fix: Adding appropriate doftransformations for high-order ND tet elements in RefineOperator/PRefineOperator Mult and MultTranspose
2021-12-05 19:35:37 -08:00
Tzanio Kolev 539f663fe6 Merge pull request #2570 from mdeuse/complex_fem-improvement
Added AddDomainIntegrator with marker for (Par)ComplexLinearForm and (Par)SesquilinearForm
2021-11-30 14:21:05 -08:00
mdeuse 104abd56e1 Merge branch 'master' into complex_fem-improvement 2021-11-30 21:25:29 +01:00
Socratis Petrides 6a86ca8d49 typo 2021-11-30 11:43:47 -08:00
Socratis Petrides c08b31c078 Merge branch 'master' into refine-operator-bug-fix 2021-11-30 11:38:22 -08:00
Socratis Petrides 54e78ee991 removing test from examples and adding ND and RT case in trasfer unit tests 2021-11-30 11:37:49 -08:00
Will Pazner 68b4445893 Merge remote-tracking branch 'origin/master' into complex_fem-improvement 2021-11-30 11:04:45 -08:00
Tzanio Kolev de9110300d Merge pull request #2383 from mfem/pr_autodiff
AD capabilities in mfem - autodiff
2021-11-30 09:59:27 -08:00
Will Pazner cbff87a616 Merge pull request #2639 from mfem/hyperparvec-move-dev
Add move constructors/assignment for Vector and HypreParVector [hypreparvec-move-dev]
2021-11-30 09:48:10 -08:00
blaz 139ce00846 new .gitignore 2021-11-24 22:11:45 -08:00
blaz 465459bc94 new .gitignore 2021-11-24 21:54:58 -08:00
blaz 0487599b56 .gitignore 2021-11-24 21:38:05 -08:00
blaz a85687d0cb move caliper configuration 2021-11-24 21:14:07 -08:00
blaz 03b9eb4b53 style 2021-11-24 17:45:20 -08:00
blaz 293acb99d9 small amendments 2021-11-24 17:32:44 -08:00
Veselin Dobrev edb69e0180 Add missing newline at the end of a file 2021-11-22 22:10:52 -08:00
Josh Essman 8c5e3c4e08 Merge branch 'master' into hyperparvec-move-dev 2021-11-22 10:25:05 -06:00
Josh Essman 620b2590a3 tests: make sure that moved-from hpvec is empty 2021-11-22 10:24:10 -06:00
Socratis Petrides ad96dc5c61 adding checks for TensorProductElementPRefineOperator which is not implemented for ND/RT 2021-11-18 11:17:35 -08:00
Socratis Petrides de58c7ae08 minor 2021-11-17 18:54:24 -08:00
Socratis Petrides e9412379ce adding CG instead of UMFPack in the test. Adding quantitative error measure 2021-11-17 18:53:54 -08:00
Socratis Petrides 330b94fd41 Additional unit tests for InvTransformDual 2021-11-17 17:48:37 -08:00
Socratis Petrides 15cc865fba Adding DofTransformations in PrefinementOperator::Mult/MultTranspose 2021-11-17 17:47:57 -08:00
Socratis Petrides f60e6a6ac3 Bug fix RefinementOperator::MultTranspose 2021-11-17 17:47:19 -08:00
Socratis Petrides 75ae4e2c9b adding DofTransformation::InvTransformDual 2021-11-17 17:44:16 -08:00
Socratis Petrides f6c10448f2 small bug-fix refine-operatorr::MultTranspose() 2021-11-17 14:10:49 -08:00
Tzanio 247818aaa6 More styling 2021-11-14 12:36:43 -08:00
Tzanio e5e4a7e753 Merge branch 'master' into pr_autodiff 2021-11-14 12:08:07 -08:00
Tzanio 20cb878f5f Styling 2021-11-14 12:07:15 -08:00
Tzanio 4cc03b4238 Small adjustments 2021-11-14 11:54:02 -08:00
Tzanio Kolev 0843a87d79 Merge pull request #2661 from mfem/gitlab-disable-rebaseline
In Gitlab CI, disable the `rebaseline` job for `master`
2021-11-12 08:11:57 -08:00
Tzanio Kolev 9c34c32ae6 Merge pull request #2652 from mfem/hypre-update
Update with latest changes in hypre
2021-11-12 08:10:42 -08:00
Tzanio Kolev 9a12cedd5e Merge pull request #2358 from mfem/yohann/mem/min-default-constr
Use `Reset()` in default constructor of `Memory<T>`.
2021-11-11 16:21:12 -08:00
Tzanio Kolev f9f3f11818 Merge pull request #2638 from mfem/diffusion-kernel-dev
More threads/block for SmemPADiffusionApply3D
2021-11-11 16:20:44 -08:00
Tzanio Kolev b2df200f3d Merge pull request #2659 from mfem/deps-flags
Allow for customizing compiler flags for generating dependencies
2021-11-11 15:39:52 -08:00
Veselin Dobrev 6d102971c9 In Gitlab CI, disable the rebaseline job for 'master' 2021-11-11 14:28:49 -08:00
Victor A. P. Magri ba1e213c19 Add check on hypre version 2021-11-11 11:05:03 -08:00
Will Pazner acbe45ea91 Allow for customizing compiler flags for generating dependencies
On Mac, by default, add the flag -Wno-unused-command-line-argument
2021-11-10 14:34:52 -08:00
Tzanio 0cc104331c Merge branch 'master' into yohann/mem/min-default-constr 2021-11-10 12:52:15 -08:00
Tzanio Kolev d7e87fda54 Merge pull request #2366 from xjrc/ciurej/feature/conduit-data-collection-adjsets
extend `ConduitDataCollection` to support `adjsets` exporting
2021-11-10 11:21:12 -08:00
Stowell, Mark L f58ad62b48 Adding new unit test to cmake file 2021-11-09 16:14:10 -08:00
Stowell, Mark L 64dd0fc417 Add unit tests for piecewise coefficients 2021-11-09 15:31:23 -08:00
Stowell, Mark L 2607e5fd98 Adding methods to remove entries from piecewise coefficients 2021-11-09 15:30:45 -08:00
Stowell, Mark L f569c190b6 Renaming AddCoefficient methods as UpdateCoefficient 2021-11-09 15:30:21 -08:00
Josh Essman bd1dbd3754 refactor: add CreateCompatibleVector method to HypreParVector 2021-11-09 15:45:39 -06:00
Stowell, Mark L 131f8cc308 Switching to "const" variable to aid compiler optimizations 2021-11-09 12:07:41 -08:00
Stowell, Mark L 601a780a11 Switching to MFEM_VERIFY in initializers 2021-11-09 12:07:11 -08:00
Stowell, Mark L 23be84b089 Fixing typos (thanks @dylan-copeland!) 2021-11-09 12:06:26 -08:00
Tzanio Kolev d6924d1b3f Merge pull request #2649 from mfem/gh-actions-fix
Small fix in Github actions
2021-11-08 20:11:38 -08:00
Victor A. P. Magri 7a6758a53b Update prepocessor macros 2021-11-08 15:27:06 -08:00
Josh Essman 143b0378e5 cleanup: remove redundant code 2021-11-08 17:11:01 -06:00
Victor A. P. Magri 39b2f27dc2 Merge branch 'master' into hypre-update 2021-11-08 14:50:15 -08:00
Tzanio f9e9f5b22e minor 2021-11-08 10:36:31 -08:00
Cyrus Harrison 882883a650 Update CHANGELOG 2021-11-08 10:35:58 -08:00
Tzanio Kolev 2519a91d01 Merge pull request #2645 from mfem/omp-macos
Include `omp` header on macOS [omp-macos]
2021-11-08 07:39:10 -08:00
Josh Essman 12cc340afb cleanup: apply suggestions from @pazner 2021-11-08 08:08:30 -06:00
Veselin Dobrev 88a190e034 In Github CI, remove testing change 'v2.0-tweak' -> 'v2.0' 2021-11-06 18:51:36 -07:00
Veselin Dobrev 9f64008a55 Fix the 'gitignore' github action.
Test with the external github action (remove before merge):
   mfem/github-actions/build-mfem@v2.0-tweak
2021-11-06 17:30:26 -07:00
Tzanio Kolev 7127265fde Merge pull request #2634 from mfem/gitlab-ci-updates
Gitlab CI updates
2021-11-06 15:57:22 -07:00
mdeuse f6f702c522 Minor, updated comment 2021-11-06 14:48:56 +01:00
Veselin Dobrev 29fc4c45b6 In Gitlab CI, apply another set of tweaks 2021-11-05 12:16:09 -07:00
Veselin Dobrev f6f802e0cd In Gitlab CI, test another tweak 2021-11-05 11:26:22 -07:00
Tobias Duswald 0ccc63af04 Include omp headers on macOS 2021-11-05 08:43:30 +01:00
Veselin Dobrev 2ec5efc7d5 In Gitlab CI, in sub-pipeline definitions, explicitly pass
some global variables
2021-11-04 20:37:10 -07:00
Veselin Dobrev c8a8ab5cba In Gitlab CI, attempt to explicitly inherit global variables
in the sub-pipelines
2021-11-04 20:21:35 -07:00
Veselin Dobrev aeac01c130 In Gitlab CI, add some debug "echo" commands 2021-11-04 19:15:29 -07:00
Veselin Dobrev a25c9c575b In Gitlab CI, move the definitions of some global variables from
.gitlab/configs/common.yml to .gitlab-ci.yml
2021-11-04 18:48:38 -07:00
Will Pazner 2900a6ecd0 Remove testing data_dir symlink if it exists 2021-11-04 16:25:17 -07:00
Will Pazner 134780da77 Try to fix hipcc errors in shifted miniapp 2021-11-04 12:37:05 -07:00
Josh Essman c85f81f9b4 fix: update hypreparvec copy ctor to copy local data 2021-11-04 12:22:25 -05:00
Josh Essman 72331717c7 tests: add tests for new functionality and fix other hypreparvec test 2021-11-04 10:15:23 -05:00
Josh Essman e96e88d543 feat: add vector move ctor/assignment 2021-11-04 09:01:28 -05:00
Veselin Dobrev a0172dfeb3 In Gitlab CI, remove some debug output 2021-11-03 21:42:47 -07:00
Tom Stitt 2efaaaaffa remove added blank lines 2021-11-03 17:07:12 -07:00
Tom Stitt 70422ccf14 switch threading order 2021-11-03 17:04:57 -07:00
Tom Stitt 716df18263 Merge remote-tracking branch 'origin/master' into diffusion-kernel-dev 2021-11-03 16:23:50 -07:00
Josh Essman 2337137f33 feat: add move constructor for hypreparvec 2021-11-03 17:31:19 -05:00
Tzanio Kolev 167ff72edc Merge pull request #2406 from SCOREC/installExamples
cmake: install examples when enabled
2021-11-03 08:02:37 -07:00
Veselin Dobrev 3f036b943e Add a new Gitlab CI file forgotten in the previous commit 2021-11-03 02:32:28 -07:00
Veselin Dobrev 5565b5066f Update Gitlab CI to fix some issues:
- Use a single (per user) clone of the internal MFEM/autotests repo
- Use a single (per user) clone of the Github MFEM/data repo
- Properly set the location for the pipeline-common temporary directory,
  BUILD_ROOT; add a cleanup step for BUILD_ROOT
- Various other small tweaks and additions
2021-11-03 02:15:58 -07:00
blaz 269eb6b7d1 fix in the makefile configuration 2021-11-02 17:51:24 -07:00
Tom Stitt 2558593206 threads in z; seems like ~10% faster on v100... 2021-11-02 17:19:22 -07:00
Chris White 586659c973 guard add_test with MFEM_ENABLE_TESTING 2021-11-02 15:46:06 -07:00
Stowell, Mark L 678cceaf1e Merge remote-tracking branch 'origin/master' into pw-coefs-dev
# Conflicts:
#	fem/coefficient.cpp
2021-11-02 12:08:00 -07:00
Tzanio Kolev d09ab725b5 Merge pull request #2367 from mfem/yohann/mem/delete-reset
Make `Memory<T>::Delete()` reset the `Memory<T>` object.
2021-11-02 06:45:51 -07:00
Tzanio Kolev 41bb7c5d4e Merge pull request #2423 from mfem/additional-device-kernels
Additional Device Kernels
2021-11-02 06:44:46 -07:00
Tzanio Kolev a0166719e6 Merge pull request #2607 from mfem/size-mt-array-ctor
Add Size & MemoryType Array Constructor
2021-11-02 06:44:01 -07:00
Tzanio Kolev 26200dafed Merge pull request #2611 from mfem/hypre-par-vector-read
Add HypreParVector::Read
2021-11-02 06:43:24 -07:00
Tzanio b8b2d23087 Merge branch 'master' into ciurej/feature/conduit-data-collection-adjsets 2021-10-31 14:44:55 -07:00
Tzanio Kolev ef656f03e9 Merge pull request #2507 from mfem/coarse-fine-map-fix-dev
Proposed fix for GetCoarseFineMap() for Derefinement in parallel
2021-10-31 14:40:38 -07:00
Tzanio Kolev c1c98ca52c Merge pull request #2448 from mfem/shifted-dirichletplusneumann
Shifted boundary method - Neumann boundary condition + multiple level sets
2021-10-31 14:40:00 -07:00
Tzanio 405a6d2f0d Merge branch 'master' into yohann/mem/delete-reset 2021-10-29 18:16:09 -07:00
Veselin Dobrev ba73a40ce9 Merge pull request #2598 from mfem/ceed-int-rule-fix
Fix bug in CEED integration
2021-10-29 16:04:36 -07:00
Ketan Mittal fa2e6fa2f4 minor 2021-10-29 13:58:29 -07:00
blaz a42ee48079 interface modifications and fixes 2021-10-29 12:13:33 -07:00
blaz bfafa6c97e fixed kapa -> kappa 2021-10-29 11:24:44 -07:00
blaz eeb0ede002 Merge branch 'master' into pr_autodiff 2021-10-29 11:21:47 -07:00
blaz ef5cc5aa5d Merge branch 'pr_autodiff' of https://github.com/mfem/mfem into pr_autodiff 2021-10-29 11:11:07 -07:00
Ketan Mittal b8590d7c0f set level set if none is specified 2021-10-29 09:02:46 -07:00
Tzanio Kolev bf616ac6ec Merge pull request #2493 from mfem/vqfluxfix
Bug fix for DiffusionIntegrator
2021-10-29 08:17:55 -07:00
Tzanio Kolev 0526a67b92 Merge pull request #2612 from mfem/yohann/wrapwrap
Improved device compilation.
2021-10-29 08:05:25 -07:00
Tzanio Kolev 59a950e1c6 Merge pull request #2616 from mfem/additional-template-instances
additional template instances
2021-10-29 07:57:33 -07:00
Ketan Mittal 26fdb711bc remove default dirichlet level set 2021-10-27 16:45:13 -07:00
Joseph Ciurej 8d76e7462a fixed the wording in a code comment 2021-10-27 13:40:09 -07:00
mdeuse 92710559c0 Merge branch 'master' of https://github.com/mfem/mfem into complex_fem-improvement 2021-10-27 22:28:49 +02:00
Tzanio Kolev 17537c506f Merge pull request #1915 from mfem/tmop-align-surface
Initial surface alignment TMOP capability
2021-10-27 09:05:00 -07:00
Will Pazner d9eec2acd8 Merge pull request #2619 from mfem/PrintMatlab
Fixed function signature which creates PyMFEM conflict
2021-10-25 16:09:53 -07:00
Tzanio 7d5bf6e3e1 square01_tri.mesh -> square01-tri.mesh; other minor 2021-10-25 10:17:05 -07:00
Tzanio Kolev 4d6c90d4fc Merge pull request #2511 from mfem/contrib-doc-mod
Proposed changes to documentation requirements [contrib-doc-mod]
2021-10-24 20:04:32 -07:00
Tzanio Kolev efb97380e3 Merge pull request #2510 from mfem/nonlinearform-doftrans-dev
Adding DofTransformations NonlinearForm methods [nonlinearform-doftrans-dev]
2021-10-24 19:58:54 -07:00
Tzanio Kolev 1f7e9f0f23 Merge pull request #2433 from mfem/oscillation
Data oscillation refinement / mesh pre-processing
2021-10-24 19:57:12 -07:00
Tzanio Kolev ca612b872f Update ex30p.cpp 2021-10-24 19:52:46 -07:00
Tzanio Kolev f991e44f2e Update ex30.cpp 2021-10-24 19:51:52 -07:00
Tzanio Kolev 3b232cd0c1 Update CHANGELOG 2021-10-24 19:50:19 -07:00
Joseph Ciurej cecda6b411 fixed a few bugs w/ neighbor/rank distinction between MFEM and Blueprint 2021-10-24 11:52:17 -07:00
Joseph Ciurej 8145b4c377 removed invalid boundary topology and added a note about its exclusion 2021-10-21 12:29:36 -07:00
Joseph Ciurej 2c1a39031e extend 'ConduitDataCollection' adjacency information to include shared boundaries 2021-10-21 12:29:36 -07:00
Joseph Ciurej ded707375a add basic support to 'ConduitDataCollection' for outputting adjacency information 2021-10-21 12:29:35 -07:00
Keith be505c9af0 fixed function signature which creates PyMFEM conflict 2021-10-20 17:00:50 -07:00
Tom Stitt 4056c529a1 additional template instances 2021-10-19 15:06:15 -07:00
Tzanio Kolev 23f110f9b7 Adding Mark and Will as MFEM editors 2021-10-19 12:13:59 -07:00
Keith 1ed1a29e68 PR checklist 2021-10-18 12:07:22 -07:00
Yohann Dudouit ddf40b7909 Use static method. 2021-10-15 16:34:54 -07:00
Yohann Dudouit 21417add4b Dim -> DIM. 2021-10-15 16:32:35 -07:00
Yohann Dudouit 5f68f31a73 Wrap exec policies to avoid triple compilation. 2021-10-15 16:30:54 -07:00
Will Pazner 407a3321aa Add unit test for HypreParVector::Read 2021-10-15 13:25:23 -07:00
Will Pazner c76cbfa010 Add HypreParVector::Read 2021-10-15 13:03:13 -07:00
Tom Stitt 320bf0a980 add new ctor to array that takes a size and a memorytype 2021-10-14 10:48:43 -07:00
Stowell, Mark L 47008f92fb Adding statement about documenting pointer arguments/return values 2021-10-12 11:40:30 -07:00
Will Pazner d72cd3f5f7 Small modifications to CEED convection unit test 2021-10-09 09:32:23 -06:00
Julian AndrejandYohann 8bb634ffcb Update tests/unit/ceed/test_ceed.cpp
Co-authored-by: Yohann <dudouit1@llnl.gov>
2021-10-08 13:44:58 -07:00
Vladimir Z Tomov af6426d240 Addressed reviewer comments. 2021-10-08 13:09:17 -07:00
Julian Andrej 15b9085ad5 add unit test 2021-10-08 11:39:33 -07:00
Will Pazner cbc44b22b6 Fix bug in CEED integration
The requested integration rule was assumed to be GaussLegendre, but this is not
always the case.
2021-10-08 11:07:52 -07:00
Victor A. P. Magri 28369b9be2 Update BoomerAMGCoarseParms call 2021-10-07 13:54:25 -07:00
Stowell, Mark L 594711d99f Fixing Doxygen comments 2021-10-05 18:55:25 -07:00
Stowell, Mark L c8cb364d86 Adding Piecewise coefficient classes 2021-10-05 18:45:00 -07:00
Keith d6a5eea4e7 const member function fix 2021-09-29 14:37:32 -07:00
Keith 3b325a597c supress warnings by default 2021-09-29 13:02:24 -07:00
Vladimir Z Tomov 1e5602f139 Removed the mesh curvature output, as it doesn't take
into account the user-selected mesh order.
2021-09-28 22:41:50 -07:00
Vladimir Z Tomov bb085f9866 Aborts for unsupported setups, mem leak. 2021-09-28 22:24:40 -07:00
Vladimir Z Tomov e7a7bfe3fb Removed unused function.
Better computation and output of fitting errors.
2021-09-28 18:11:45 -07:00
Vladimir Z Tomov 76617db79e Serial miniapp and some comments. 2021-09-28 17:24:23 -07:00
Vladimir Z Tomov a1ba9f93c4 Reverted changes in pmesh.cpp. 2021-09-28 16:09:21 -07:00
Vladimir Z Tomov 211a221c50 Fixed a merge issue. 2021-09-28 16:00:10 -07:00
Vladimir Z Tomov a194cdacce Merge branch 'master' into tmop-align-surface 2021-09-28 15:54:35 -07:00
Vladimir Z Tomov 3829693441 Better triangular mesh, added parallel sample runs. 2021-09-28 15:35:26 -07:00
Keith 5231ec314a Socratis's comments 2021-09-27 15:01:01 -07:00
Keith a33f29549a Merge branch 'master' into oscillation 2021-09-27 15:00:11 -07:00
Stowell, Mark L 0e48fd5f94 Fixing a small typo 2021-09-27 09:29:20 -07:00
Tzanio 946ab2a893 Incorporate suggestion from Denis 2021-09-26 19:02:31 -07:00
Tzanio b34831a308 Incorporate Aaron suggestions 2021-09-26 18:48:00 -07:00
Tzanio c753e3bf8e Incorporater PR review rules in CONTRIBUTING.md 2021-09-26 18:35:02 -07:00
Tzanio f25aa615da Merge branch 'master' into contrib-doc-mod 2021-09-26 18:34:52 -07:00
Tzanio Kolev a303bcdf0a Merge branch 'master' into pr_autodiff 2021-09-26 17:28:25 -07:00
Tzanio f7b7c5388b make style 2021-09-26 17:26:44 -07:00
Tzanio b704fa15b1 Merge branch 'master' into additional-device-kernels 2021-09-26 17:25:53 -07:00
mdeuse e533a91560 Added AddDomainIntegrator with marker for (Par)ComplexLinearForm and (Par)SesquilinearForm 2021-09-26 22:14:01 +02:00
Tom Stitt b74049fff1 MultT -> MultTranspose 2021-09-24 14:46:12 -07:00
Tom StittandYohann 7e9dd26f57 fix empty mat check
Co-authored-by: Yohann <dudouit1@llnl.gov>
2021-09-24 14:45:09 -07:00
Vladimir Z Tomov 621a7842b1 AMR - sample run for the distance app, abort for the diffusion app. 2021-09-24 14:43:56 -07:00
Vladimir Z Tomov 7cf96edc2f Makefile improvements to avoid extra recompilation. 2021-09-24 14:23:22 -07:00
Vladimir Z Tomov c216a86943 Minor edits. 2021-09-21 18:06:44 -07:00
Vladimir Z Tomov 3562662d93 Revert ex1p. 2021-09-20 14:50:17 -07:00
Vladimir Z Tomov a13a1bf95c Merge branch 'par-get-deriv' into shifted-dirichletplusneumann 2021-09-20 14:48:32 -07:00
Jakub Červený 6708f9c19b Fix Doxygen error 2021-09-17 14:17:32 +02:00
Jakub Červený 4f0c54ff06 Updated derefinement test in test_derefine.cpp 2021-09-17 14:12:23 +02:00
Jakub Červený a53706b57c Simplified CoarseFineTransformations::MakeCoarseToFineTable. 2021-09-17 13:53:45 +02:00
Jakub Červený 61e9c368d7 DerefinementOperator: uses original GetCoarseToFineMap, now in fespace.cpp. 2021-09-17 12:52:20 +02:00
Jakub Červený a747244a6f WIP refactoring DerefinementOperator constructor 2021-09-14 13:08:58 +02:00
Jakub Červený 9b05700cb5 Initialization of Embedding::geom and ::ghost in NCMesh and Mesh. 2021-09-14 11:23:49 +02:00
Vladimir Z Tomov 27dfa26f0d Improved the marking algorithm. 2021-09-13 14:12:21 -07:00
Jakub Červený 83c11c4ea5 Refactoring coarse/fine: added MakeCoarseToFineTable, Embedding::geom/ghost. 2021-09-13 16:01:36 +02:00
Stowell, Mark L 09b5b1f184 Mention of new function usage 2021-09-09 14:48:58 -07:00
Stowell, Mark L 7b64d8739a Adjusting statements based on input obtained during MFEM developer meeting 2021-09-09 14:29:17 -07:00
Vladimir Z Tomov 36e2e4d37f Some additional tests. 2021-09-08 14:38:39 -07:00
Ketan Mittal 44d71cfdbf Merge branch 'master' of https://github.com/mfem/mfem into shifted-dirichletplusneumann 2021-09-08 13:58:37 -07:00
Ketan Mittal 4806441a03 make sure normal vector is pointing outside the domain 2021-09-08 13:58:20 -07:00
Tucker Babcock 5ad64b058b fix compile error, changed ComputeGradientBlocked doftrans usage to be similar to MixedBilinearForm::Assemble. 2021-09-07 14:35:00 -06:00
Tucker Babcock dd5f50bb40 store DofTransformations in Array for BlockNonlinearForm::MultBlocked and ::ComputeGradientBlocked since they need to be reused 2021-09-07 14:24:33 -06:00
Tucker Babcock 3a8908e6bf add DofTransformation to BlockNonlinearForm methods 2021-09-07 14:16:08 -06:00
Stowell, Mark L f53e14016d Separate statements for public and private entities. 2021-09-03 19:20:07 -07:00
Stowell, Mark L 70bb02a0c7 Proposed changes to documentation requirements 2021-09-03 17:37:03 -07:00
Tucker Babcock 091ff0c475 adding DofTransformation objects to NonlinearForm Mult, GetGridFunctionEnergy, and GetGradient methods similar to those used in BilinearForm::Assemble and LinearForm::Assemble 2021-09-03 18:13:19 -06:00
Robert W. Anderson 583024eaa7 keep track of # of nonghost elements in derefinement, use this to fix GetCoarseFineMap in the case of derefinement 2021-09-03 17:12:18 -07:00
Dylan Copeland 3c82571b68 Small comment. 2021-09-03 09:55:32 -07:00
Dylan Copeland 3388160761 Fixing some unsupported coefficients in ComputeFluxEnergy. 2021-09-02 21:25:49 -07:00
Keith c8f6d1ad4f Socratis's comments 2021-09-02 12:40:36 -07:00
blaz 7b9d5d0084 Merge branch 'master' into pr_autodiff 2021-09-02 12:40:08 -07:00
blaz d41b7f7e83 Documentation 2021-09-02 12:37:18 -07:00
Vladimir Z Tomov 1459c4f5a6 Minor. 2021-09-01 18:14:25 -07:00
Keith 6b33ad4abf Jakub's changes 2021-08-31 12:58:44 -07:00
Keith 5f6fda1bf3 Jakub's changes 2021-08-31 11:55:22 -07:00
Vladimir Z Tomov d0831c2f11 Minor edits in the miniapp. 2021-08-31 10:46:21 -07:00
Jakub Červený cfd1442180 Minor whitespace and typos. 2021-08-31 16:55:27 +02:00
Dylan Copeland 08715a83cf Fixing with_coef logic in flux calculation. 2021-08-28 12:54:47 -07:00
Dylan Copeland 4aaa441d70 Fixing a bug in DiffusionIntegrator in the case of a vector (diagonal matrix) coefficient. 2021-08-27 15:40:21 -07:00
Vladimir Z Tomov bba6e27f85 Minor edits. 2021-08-27 14:57:23 -07:00
Keith 4d48ddb566 fix unit tests after constructor redefinition 2021-08-26 13:53:47 -07:00
Keith 6bdd079b40 fix style 2021-08-26 13:37:07 -07:00
Keith 71c4967e80 added Coefficient & as argument in constructor 2021-08-26 13:34:08 -07:00
Keith 165f4301d8 make gf local 2021-08-26 13:09:40 -07:00
Keith 7d309b3d9e initialize gf 2021-08-26 12:30:58 -07:00
Keith 7246251b52 const Vector & GetLocalOscs() const 2021-08-26 12:24:34 -07:00
Keith 4d40b7536f make GetOsc at const member function 2021-08-26 11:47:40 -07:00
Keith eb195d1cb3 Addressing comments: Change default value 2021-08-26 09:30:52 -07:00
Brendan Keith ebddfa7114 Addressing comments: Added period for conformity. 2021-08-26 09:12:50 -07:00
Brendan Keith a5be9f36ed Addressing comments: Added period for conformity. 2021-08-26 09:09:47 -07:00
blaz 1c4602cf64 More documentation 2021-08-25 09:34:03 -07:00
blaz 2fd06ce867 documentation 2021-08-24 23:48:26 -07:00
blaz 435d542208 All functors are created as private objects 2021-08-24 20:32:06 -07:00
blaz bd155a672e FDual documentation 2021-08-24 18:07:18 -07:00
blaz afacaa7cad Documentation 2021-08-24 17:36:17 -07:00
blaz f9811d774c FDual name changed for FDualNumber 2021-08-24 16:58:25 -07:00
blaz 3e0b76a048 Changed names for the vector and the matrix classes 2021-08-24 16:53:16 -07:00
blaz 59151dbe58 documentation and small changes 2021-08-13 20:13:40 -07:00
blaz 002514c2e0 Merge branch 'master' into pr_autodiff 2021-08-13 16:20:11 -07:00
Ketan Mittal b133ec754e minor 2021-08-06 14:31:48 -07:00
blaz 23cd7f75bb changed back miniapp CMakefile 2021-08-06 11:12:32 -07:00
blaz 09b67ab18d Merge branch 'master' into pr_autodiff 2021-08-06 11:01:22 -07:00
blaz 6327127cdc cosmetics 2021-08-06 10:56:23 -07:00
Ketan Mittal d4c102b94c enable high-order terms for Neumann 2021-08-05 17:02:11 -07:00
Ketan Mittal bbba4d863f minor fix for inhomogeneous Neumann 2021-08-04 10:05:49 -07:00
Ketan Mittal 9bf2e813b0 make style 2021-08-03 14:13:58 -07:00
Ketan Mittal 838ac0cf36 improved documentation and other misc changes 2021-08-03 14:13:34 -07:00
Keith 7ec56ca61f FIX: Removed too much in last commit 2021-08-03 09:17:55 -07:00
Keith 1cd7bfb28d remove unused variables 2021-08-03 09:12:50 -07:00
Keith 6a63b46bd4 typo in comment 2021-08-02 23:34:33 -07:00
Ketan Mittal 81aacd2c9e documentation 2021-08-02 15:28:13 -07:00
Ketan Mittal 2077b076c8 Merge branch 'master' of https://github.com/mfem/mfem into shifted-dirichletplusneumann 2021-08-02 15:08:35 -07:00
Ketan Mittal 93be96fcc0 make style 2021-08-02 14:25:31 -07:00
Ketan Mittal 2cb619d9cf minor change to how level sets are indicated 2021-08-02 14:22:19 -07:00
Keith 6f2c580774 fixed style 2021-08-02 12:54:54 -07:00
Keith c0912fe75e added support to return local oscs 2021-08-02 12:53:29 -07:00
Keith 5ffd03a2da updated unit tests 2021-08-02 12:13:56 -07:00
Keith ec09fe54e4 style 2021-07-30 23:13:23 -07:00
Keith 2a09088fb0 added some simple unit tests 2021-07-30 23:12:56 -07:00
Keith e93a3542c0 example files written 2021-07-30 21:14:04 -07:00
Keith bdcbfafb42 cleaning code 2021-07-30 20:39:02 -07:00
Keith b9eaa8c309 fix style 2021-07-30 19:45:52 -07:00
Keith 96a10dfa2e finalize serial examples 2021-07-30 19:44:54 -07:00
Keith e4cebc0f6a merged with bug fix 2021-07-30 17:20:52 -07:00
Keith 865b2facc2 verification with embedded meshes 2021-07-30 16:54:15 -07:00
Keith 8877f99da8 Fixed Mesh::GetElementSize(), which did not work for embedded meshes 2021-07-30 16:54:15 -07:00
Keith 8a61b3e27b adding extra features 2021-07-30 16:54:15 -07:00
psocratis 54676a17c2 Fixed bug for serial builds. Fixed comments 2021-07-30 16:54:15 -07:00
psocratis f47244859a fixing parallel implementation 2021-07-30 16:54:15 -07:00
Keith 2e6583650f debugging parallel implementation 2021-07-30 16:54:15 -07:00
Keith 2bc6f6146a cleaned up files 2021-07-30 16:54:15 -07:00
psocratis d2b8fa35bb Fixing setting intrule. Adding parallel example 2021-07-30 16:54:15 -07:00
Keith 1fdfa6d39a code compiles. Needs debugging 2021-07-30 16:54:15 -07:00
Tom Stitt f89d359d06 add MultAtB and MultT(vector)
and const qualifier to Mult(vector)
2021-07-22 15:58:54 -07:00
Ketan Mittal 31ce22595b work for multiple Dirichlet and Neumann conditions 2021-07-22 10:02:09 -07:00
Keith a6270b2582 update osc file 2021-07-19 19:52:33 -07:00
Ketan Mittal 1d84ae004c working dirichlet+neumann 2021-07-19 10:51:02 -07:00
Ketan Mittal 1f35f2580d WIP - initial commit 2021-07-14 12:47:29 -07:00
blaz 86a297b34f Merge branch 'pr_autodiff' of https://github.com/mfem/mfem into pr_autodiff 2021-07-14 12:02:07 -07:00
blaz a9d6514fb6 cleaned version 2021-07-14 11:59:52 -07:00
Cameron Smith 4d51a907cf install examples if enabled
I don't think this has other significant side effects...
2021-07-14 16:16:58 +00:00
Cameron Smith a10fb1f421 install examples to examples dir 2021-07-14 16:14:01 +00:00
Cameron Smith afee0acf50 exes are RUNTIME comps, cmake sets the prefix 2021-07-14 13:18:11 +00:00
Cameron Smith 1d5ff54f4c install examples 2021-07-13 20:08:24 +00:00
Stowell, Mark L ccf27151f5 Remove a warning 2021-07-06 17:12:03 -07:00
Stowell, Mark L ae9f953b20 Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	fem/fespace.cpp
#	fem/fespace.hpp
#	general/sets.hpp
#	general/stable3d.hpp
#	mesh/mesh.cpp
#	mesh/mesh_readers.cpp
#	mesh/ncmesh.cpp
#	mesh/ncmesh.hpp
#	mesh/pmesh.cpp
#	mesh/pncmesh.cpp
2021-07-06 17:11:43 -07:00
blaz 7fcd181280 modified INSTALL 2021-07-03 23:47:06 -07:00
blaz d7ae085678 license check 2021-07-02 16:10:14 -07:00
blaz e967c8a7ef copyright check 2021-07-02 15:52:26 -07:00
blaz 1a6c24c5f2 bug in makefile 2021-07-02 15:42:31 -07:00
blaz 340e3ed188 autodiff makefile 2021-07-02 15:30:46 -07:00
blaz 1382ed617a Merge remote-tracking branch 'origin/master' into pr_autodiff 2021-07-02 15:08:41 -07:00
blaz 4d834ca852 cleaned code 2021-07-02 15:05:28 -07:00
blaz c8a8562ea4 modification and examples 2021-07-02 11:21:48 -07:00
Yohann Dudouit 330f67cedc Reset with current MemoryType. 2021-06-30 10:06:23 -07:00
Yohann Dudouit 6651c80b27 Make Delete reset the Memory object. 2021-06-28 17:35:25 -07:00
Yohann Dudouit 3ac9eff225 Improve documentation. 2021-06-28 17:06:42 -07:00
Yohann Dudouit 3d399d8eb3 Remove unnecessary Reset. 2021-06-25 11:16:09 -07:00
Yohann Dudouit 216e0dfe08 Use Reset() in default constructor. 2021-06-24 19:08:38 -07:00
blaz a32ca0cb89 Another Lambda example 2021-05-26 15:53:39 -07:00
blaz 2e92b44070 Lambda function differentiation 2021-05-26 15:11:05 -07:00
blaz 2aa374efe8 Example of auto diff 2021-05-25 21:00:57 -07:00
blaz 476e642935 added cmake and make files for Eigen and CoDiPack 2021-05-25 17:53:33 -07:00
blaz 0da14179f7 initial copy frm fadg branch 2021-05-25 16:38:32 -07:00
Ketan Mittal ff940b8254 Merge branch 'tmop-align-surface' of https://github.com/mfem/mfem into tmop-align-surface 2021-02-04 10:04:32 -08:00
Ketan Mittal ec9c967b88 adding 3D combo metrics 2021-02-04 10:03:43 -08:00
Vladimir Z Tomov 966071f5ce Minor. 2021-02-02 22:55:28 -08:00
Vladimir Z Tomov ff6dc50d7f Computation of surface fitting errors. Changed the normalization. 2021-02-02 22:51:03 -08:00
Ketan Mittal a39f7635f5 bug fix for writing attribute 2021-01-25 10:42:04 -08:00
Ketan Mittal 7d2ce53a63 write element attribute in mesh file 2021-01-25 09:26:28 -08:00
Vladimir Z Tomov feca2f59dc Minor. 2021-01-14 12:26:28 -08:00
Vladimir Z Tomov 5e296c39c6 Minor. 2021-01-12 09:48:57 -08:00
Vladimir Z Tomov ec306e7166 Merge branch 'master' into tmop-align-surface 2021-01-12 08:49:06 -08:00
Vladimir Z Tomov 7588076853 3D surface fitting test. 2021-01-10 17:06:42 -08:00
Vladimir Z Tomov fbcc7406a7 Another option to diffuse fields. 2021-01-10 16:36:24 -08:00
Vladimir Z Tomov 06b40d8f9e Added a 2D triangle mesh. 2021-01-05 15:10:55 -08:00
Vladimir Z Tomov 944de5d51c Merge branch 'master' into tmop-align-surface 2021-01-04 16:05:28 -08:00
Vladimir Z Tomov 438fd06639 Minor. 2021-01-01 23:28:50 -08:00
Vladimir Z Tomov be26f52385 Improved the output for initial-vs-final energy. 2020-12-31 11:42:30 -08:00
Vladimir Z Tomov 94e16907c9 Minor. 2020-12-30 22:45:51 -08:00
Vladimir Z Tomov dd1fe9e7c3 Added FD support for surface fitting. 2020-12-30 22:39:39 -08:00
Vladimir Z Tomov caeecc0e6d Improved function arguments. 2020-12-30 22:12:43 -08:00
Vladimir Z Tomov 69f70eca5e Found a bug. 2020-12-29 15:10:10 -08:00
Vladimir Z Tomov dbbbf1f443 Merge branch 'master' into tmop-align-surface 2020-12-18 18:35:42 -08:00
Vladimir Z Tomov 2d39d300d1 Updated the fitting method. 2020-12-18 18:34:36 -08:00
Vladimir Z Tomov be3fb993f1 Non-variational form of the fitting term. 2020-11-02 10:06:18 -08:00
Vladimir Z Tomov 6e88331f87 Objective function, derivatives, normalization. 2020-10-28 22:51:43 -07:00
Tomov 0e195e2f87 wip surface alignment. 2020-09-21 22:21:47 -07:00
Stowell, Mark L 7667f4c3f1 make style 2020-02-20 11:20:03 -08:00
Stowell, Mark L 092bf6c883 Using the new triangle face support 2020-02-20 11:18:15 -08:00
Stowell, Mark L fe921e8c83 Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/mesh.cpp
#	mesh/ncmesh.cpp
#	mesh/ncmesh.hpp
#	mesh/pncmesh.cpp
2020-02-20 11:02:35 -08:00
Stowell, Mark L 1dbdfe33e0 Merge remote-tracking branch 'origin/master' into entity-sets-dev 2019-05-01 10:07:25 -07:00
Stowell, Mark L f23d0a333d Merge remote-tracking branch 'origin/master' into entity-sets-dev 2019-04-12 14:46:26 -07:00
Stowell, Mark L a7ceecdcca Merge remote-tracking branch 'origin/master' into entity-sets-dev 2019-04-09 14:46:06 -07:00
Stowell, Mark L 5ed4c7b407 Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/ncmesh.cpp
2019-04-01 11:07:50 -07:00
Stowell, Mark L 99ae185c6a Adding user defined AMR limit 2019-03-17 17:46:56 -07:00
Stowell, Mark L d29134d0e7 Adding checks for non-null pointers before accessing same 2019-03-17 17:46:13 -07:00
Stowell, Mark L 180ee2a9c6 Adding AMR test code 2019-03-17 10:45:22 -07:00
Stowell, Mark L 207efd476d Merge remote-tracking branch 'origin/master' into entity-sets-dev 2019-01-20 00:02:39 -08:00
Stowell, Mark L 88f5ec5fec Merge remote-tracking branch 'origin/master' into entity-sets-dev 2018-12-23 17:26:43 -08:00
Stowell, Mark L 0ee86ac277 Merge remote-tracking branch 'origin/master' into entity-sets-dev 2018-11-26 14:59:10 -08:00
Stowell, Mark L 4268ec6a55 Post merge bugfix 2018-11-12 21:08:45 -08:00
Stowell, Mark L dfa9340302 Test meshes for mixed meshes with entity sets 2018-11-11 14:20:08 -08:00
Stowell, Mark L c2004e4eb4 Merge remote-tracking branch 'origin/master' into entity-sets-dev 2018-11-08 17:59:05 -08:00
Stowell, Mark L 2afa90dd44 make style 2018-11-08 09:21:36 -08:00
Stowell, Mark L dbb0d57f10 Starting mixed mesh refinement in entity sets 2018-11-08 09:20:44 -08:00
Stowell, Mark L 13f205f111 Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/pmesh.cpp
#	mesh/pncmesh.hpp
2018-11-07 22:59:17 -08:00
Stowell, Mark L 7f0c88bfaa Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/mesh.cpp
2018-10-10 21:56:22 -07:00
Stowell, Mark L b2a89fefbc no message 2018-09-25 13:23:08 -07:00
Stowell, Mark L 3ac0168600 Adding "Tier" to STable3D::Print output 2018-09-08 17:34:20 -07:00
Stowell, Mark L 68db9e6ea9 Cleaning up merge conflicts 2018-09-08 17:22:45 -07:00
Stowell, Mark L 3d6227f2cf Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	mesh/mesh.hpp
#	mesh/mesh_readers.cpp
#	mesh/ncmesh.cpp
#	mesh/ncmesh.hpp
#	mesh/pncmesh.cpp
#	mesh/pncmesh.hpp
2018-09-08 15:09:02 -07:00
Stowell, Mark L 67bfaa60d4 file format change 2017-08-22 19:58:53 -07:00
Stowell, Mark L c434761551 Style and debugging changes 2017-08-22 19:58:23 -07:00
Stowell, Mark L 710f6bd8e6 Adding two example codes for testing 2017-08-14 15:54:58 -07:00
Stowell, Mark L 9175575dcb Added CollectFaceVertices to entity set closure method. 2017-08-14 10:23:46 -07:00
Stowell, Mark L 3de54b7d06 Merge remote-tracking branch 'origin/master' into entity-sets-dev
# Conflicts:
#	fem/pfespace.cpp
2017-08-11 14:47:52 -07:00
Stowell, Mark L 1a721e699a Closure seems to work on 2D meshes though I suspect it is still incomplete 2017-07-21 16:02:58 -07:00
Stowell, Mark L 607cf3c355 Run through "make style" 2017-07-21 09:12:32 -07:00
Stowell, Mark L b32c0d9430 Nearly working. There is still an issue related to missing dofs from neighboring processors. 2017-07-20 16:03:52 -07:00
Stowell, Mark L dd6f843634 This commit is a mess but I need to move the code to another platform for debugging 2017-07-17 15:04:21 -07:00
Stowell, Mark L 911fb9925d Changed internal data structure to std::set<int> rather from std::vector<int> 2017-07-08 22:27:17 -07:00
Stowell, Mark L 58f39f31fe Small updates to serial test driver. 2017-07-07 15:40:19 -07:00
Stowell, Mark L 40da819bc6 Adding an NCEntitySet class to store and manage NCMesh specific data. 2017-07-07 15:39:51 -07:00
Stowell, Mark L 802c6f11f1 Moving NCMesh specific data related to Entity Sets into a separate class to keep NCMesh clean. 2017-07-07 15:39:13 -07:00
Stowell, Mark L 08369c3086 Test programs for validating EntitySet behavior 2017-06-29 15:25:39 -07:00
Stowell, Mark L 4002955677 Preliminary support for Entity Sets in NCMesh class. This contains a lot of debugging output which will be removed once the parallel implementation is finished. 2017-06-29 15:25:03 -07:00
Stowell, Mark L 4283d54ad9 Fixing Mesh::Swap so that it is aware of the EntitySet member data in the Mesh class 2017-06-29 15:23:32 -07:00
Stowell, Mark L c6e3427808 Storing the coarse set information for use with the NCMesh class 2017-06-29 15:22:02 -07:00
Stowell, Mark L 7a927ae3b6 Merge remote-tracking branch 'origin/master' into entity-sets-dev 2017-06-22 15:13:12 -07:00
Tzanio aa334eb386 Sets of mesh entities feature developed internally at LLNL.
This pull request introduces two new classes; EntitySet and ParEntitySet. These
are intended to provide additional flexibility to the way MFEM tags groups of
mesh entities. These groups can be used for applying sources, boundary
conditions, post processing, etc..

MFEM currently assigns an integer attribute to each element or boundary
element. These attributes are then used by looping over all elements and
searching for attributes of interest. This is fine for large groups of elements
but for small groups this involves a large loop to locate a small number of
things.

EntitySets provide a way to loop over small groups of entities more
efficiently. They also generalize to groups of vertices, edges, faces, or
elements which can be very convenient.

The current implementation works for sets defined on quadrilateral or hexahedral
meshes in serial and parallel, with or without uniform refinement. Triangle and
tetrahedral meshes have not been tested. Support for non-conforming meshes has
not been started. If I can convince others of the value of these entity sets
then we can add support for these other mesh types.

Based on the following commits by Mark Stowell:

- Adding element access operators.

- Declaring "Size()" methods as "const".

- Added a comment for clarification.

- First draft of EntitySets class.

- Run through astyle.

- Adding methods to lookup VDofs and TrueDofs by set information.

- Adding a method to compute a Vertex to Edge table.

- Adding a non-const operator[] method.

- Adding a Load method.

- Testing the EntitySets::Load method.

- Mesh::NumOfEdges is not set even when the edge_vertex Table has been created.

- Adding Vertex to Face table.

- Testing face sets.

- Switched to using the STable3D face_tbl rather than creating a vertex to face
  table.

- Switched to using the Vertex to Vertex table.

- Adding support for QuadUniformRefinement with entity sets.

- Added copy constructor

- Adding support for entity sets in ParFiniteElementSpace

- Initial changes to support entity sets in parallel.

- Testing QuadUniformRefinement in parallel

- Adding test codes for entity sets.

- Adding parallel version of entity set code.

- Adding test meshes

- Improveing the way edge_vertex is protecgted in the mesh class.

- Adding support for parallel uniform refinement of quad meshes.

- Adding a method to return the number of rows in a table.

- Adding a RowIterator like the one in DSTable.

- Adding a fourth integer to the STable3D so that we don't lose the fourth value
  supplied to Push4.

- Changed the behavior when an entry is not found to match the behavior of
  DSTable and Table which return -1. Previously this object would issue an abort
  upon failure.

- Building faces array if face sets are read from disk.

- Adding a face_vertex table similar to the edge_vertex table.

- Adding support for face sets. This does not quite work yet but I don't want to
  lose these changes.

- Adding face sets for testing.

- Added a Print method to STable3D for debugging purposes.

- Fixed face sets in parallel with uniform refinement.

- Adding options to select the traditional boundary condition or one based on
  entity sets.

- Cleaned up the mesh file by adding more interesting sets rather than test
  sets.

- Adding code to display information about the entity sets.
2017-05-02 17:33:45 -07:00
151 changed files with 16954 additions and 1355 deletions
+2 -2
View File
@@ -82,9 +82,9 @@ jobs:
uses: mfem/github-actions/build-mfem@v2.0
with:
os: ${{ runner.os }}
target: optim
target: opt
codecov: NO
mpi: parallel
mpi: par
build-system: make
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
+10
View File
@@ -51,6 +51,8 @@ examples/ex1[04-9]
examples/ex1[0-9]p
examples/ex2[0-9]
examples/ex2[0-9]p
examples/ex30
examples/ex30p
examples/refined.mesh
examples/displaced.mesh
@@ -223,6 +225,14 @@ miniapps/mtop/ParHeat*
miniapps/mtop/seqheat
miniapps/mtop/SeqHeat*
miniapps/autodiff/paradiff
miniapps/autodiff/seqadiff
miniapps/autodiff/seqtest
miniapps/autodiff/par_example
miniapps/autodiff/seq_example
miniapps/autodiff/seq_test
miniapps/autodiff/Exampl*
miniapps/navier/navier_mms
miniapps/navier/navier_kovasznay
miniapps/navier/navier_kovasznay_vs
+36 -4
View File
@@ -29,12 +29,34 @@ stages:
variables:
CUSTOM_CI_BUILDS_DIR: "/usr/workspace/mfem/gitlab-runner"
USER_CI_TOP_DIR: "${CUSTOM_CI_BUILDS_DIR}/${GITLAB_USER_LOGIN}"
SHARED_REPOS_DIR: "${USER_CI_TOP_DIR}/repos"
AUTOTEST_ROOT: "${SHARED_REPOS_DIR}"
# MFEM_DATA_DIR is setup in '.gitlab/configs/setup-build-and-test.yml' and
# used in '.gitlab/configs/<machine>-config.yml':
MFEM_DATA_DIR: "${SHARED_REPOS_DIR}/mfem-data"
# Defines the default choice for updating the saved baseline results. By default
# the baseline can only be updated from the master branch. This variable offers
# the option to manually ask for rebaselining from another branch if necessary.
REBASELINE: "NO"
AUTOTEST: "NO"
# AUTOTEST_COMMIT: used only when AUTOTEST is set to YES.
# * If AUTOTEST_COMMIT is NOT set to NO, reporting jobs will commit their
# files to the MFEM/autotest repo.
# * If AUTOTEST_COMMIT is set to NO, reporting jobs will NOT commit their
# files to the MFEM/autotest repo. Instead they will just show the contents
# of the report files and remove them.
AUTOTEST_COMMIT: "YES"
# Trigger subpipelines:
quartz-build-and-test:
stage: sub-pipelines
variables:
_AUTOTEST: $AUTOTEST
# Explicitly pass down values that we want to be able to set when triggering
# pipelines manually or using scheduling
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
trigger:
include: .gitlab/quartz-build-and-test.yml
strategy: depend
@@ -42,7 +64,11 @@ quartz-build-and-test:
quartz-baseline:
stage: sub-pipelines
variables:
_AUTOTEST: $AUTOTEST
# Explicitly pass down values that we want to be able to set when triggering
# pipelines manually or using scheduling
REBASELINE: "${REBASELINE}"
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
trigger:
include: .gitlab/quartz-baseline.yml
strategy: depend
@@ -50,7 +76,10 @@ quartz-baseline:
lassen-build-and-test:
stage: sub-pipelines
variables:
_AUTOTEST: $AUTOTEST
# Explicitly pass down values that we want to be able to set when triggering
# pipelines manually or using scheduling
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
trigger:
include: .gitlab/lassen-build-and-test.yml
strategy: depend
@@ -58,7 +87,10 @@ lassen-build-and-test:
corona-build-and-test:
stage: sub-pipelines
variables:
_AUTOTEST: $AUTOTEST
# Explicitly pass down values that we want to be able to set when triggering
# pipelines manually or using scheduling
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
trigger:
include: .gitlab/corona-build-and-test.yml
strategy: depend
+1 -9
View File
@@ -18,19 +18,13 @@ variables:
# the pipeline, preventing any form of concurrency with other pipelines. This
# also means that the BUILD_ROOT directory will never be cleaned.
# TODO: add a clean-up mechanism
BUILD_ROOT: ${CI_BUILDS_DIR}/MFEM_${MACHINE_NAME}/${CI_PROJECT_NAME}_${CI_COMMIT_REF_SLUG}_${CI_PIPELINE_ID}
BUILD_ROOT: ${USER_CI_TOP_DIR}/${CI_PROJECT_NAME}-${MACHINE_NAME}-pipeline-${CI_PIPELINE_ID}
# On LLNL's quartz, there is only one allocation shared among jobs in order to
# save time and resource. This allocation has to be uniquely named so that we
# are sure to retrieve it.
ALLOC_NAME: ${CI_PROJECT_NAME}_ci_${CI_PIPELINE_ID}
# Defines the default choice for updating the saved baseline results. By default
# the baseline can only be updated from the master branch. This variable offers
# the option to manually ask for rebaselining from another branch if necessary.
_REBASELINE: "NO"
_AUTOTEST: "NO"
# Git repositories used in the pipeline
TPLS_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/tpls.git
TESTS_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/tests.git
@@ -40,5 +34,3 @@ variables:
# Directory used to place artifacts.
ARTIFACTS_DIR: artifacts
SLURM_OVERLAP: 1
+10 -5
View File
@@ -26,17 +26,20 @@ variables:
- if: '$CI_COMMIT_BRANCH =~ /_cnone/ || $ON_CORONA != "ON"'
when: never
# Dont run autotest update if...
- if: '$CI_JOB_NAME =~ /report/ && $_AUTOTEST != "YES"'
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
when: never
# Report success on success status
- if: '$CI_JOB_NAME =~ /report_job_success/ && $_AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_success/ && $AUTOTEST == "YES"'
when: on_success
# Report failure on failure status
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $_AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $AUTOTEST == "YES"'
when: on_failure
# Always release resource
- if: '$CI_JOB_NAME =~ /release_resource/'
when: always
# Always cleanup
- if: '$CI_JOB_NAME =~ /cleanup/'
when: always
# Default is to run if previous stage succeeded
- when: on_success
@@ -46,9 +49,11 @@ variables:
extends: [.on_corona]
stage: build_and_test
script:
# THREADS is used by 'tests/gitlab/build_and_test', run below
- export THREADS=12
- echo ${ALLOC_NAME}
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
- echo ${JOBID}
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 15 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --build-root "${BUILD_ROOT}" --data
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 15 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
+10 -4
View File
@@ -21,14 +21,17 @@ variables:
- if: '$CI_COMMIT_BRANCH =~ /_lnone/ || $ON_LASSEN == "OFF"' #run except if ...
when: never
# Don't run autotest update if...
- if: '$CI_JOB_NAME =~ /report/ && $_AUTOTEST != "YES"'
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
when: never
# Report success on success status
- if: '$CI_JOB_NAME =~ /report_job_success/ && $_AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_success/ && $AUTOTEST == "YES"'
when: on_success
# Report failure on failure status
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $_AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $AUTOTEST == "YES"'
when: on_failure
# Always cleanup
- if: '$CI_JOB_NAME =~ /cleanup/'
when: always
- when: on_success
# Lassen uses a different job scheduler (spectrum lsf) that does not allow
@@ -39,5 +42,8 @@ variables:
extends: [.on_lassen]
stage: build_and_test
script:
- lalloc 1 -W 30 -q pdebug tests/gitlab/build_and_test --spec "${SPEC}" --build-root "${BUILD_ROOT}" --data
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
# Next script uses 'THREADS': leaving it empty --> it uses 'make all -j'
- lalloc 1 -W 30 -q pdebug tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
needs: [setup]
+10 -5
View File
@@ -22,17 +22,20 @@ variables:
- if: '$CI_COMMIT_BRANCH =~ /_qnone/ || $ON_QUARTZ == "OFF"'
when: never
# Don't run autotest update if...
- if: '$CI_JOB_NAME =~ /report/ && $_AUTOTEST != "YES"'
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
when: never
# Report success on success status
- if: '$CI_JOB_NAME =~ /report_job_success/ && $_AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_success/ && $AUTOTEST == "YES"'
when: on_success
# Report failure on failure status
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $_AUTOTEST == "YES"'
- if: '$CI_JOB_NAME =~ /report_job_failure/ && $AUTOTEST == "YES"'
when: on_failure
# Always release resource
- if: '$CI_JOB_NAME =~ /release_resource/'
when: always
# Always cleanup
- if: '$CI_JOB_NAME =~ /cleanup/'
when: always
# Default is to run if previous stage succeeded
- when: on_success
@@ -42,9 +45,11 @@ variables:
extends: [.on_quartz]
stage: build_and_test
script:
# THREADS is used by 'tests/gitlab/build_and_test', run below
- export THREADS=12
- echo ${ALLOC_NAME}
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
- echo ${JOBID}
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 30 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --build-root "${BUILD_ROOT}" --data
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 30 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
+81
View File
@@ -0,0 +1,81 @@
# Copyright (c) 2010-2021, 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.
# Jobs report
.report_job_success:
script:
- echo ${MACHINE_NAME}
- echo ${AUTOTEST}
- echo ${AUTOTEST_COMMIT}
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
- cd ${AUTOTEST_ROOT}
- |
(
date
echo "Waiting to aquire lock on '$PWD/autotest.lock' ..."
# try to get an excusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/autotest.lock'"
date
# Report SUCCESS while holding the file lock on 'autotest.lock'.
# The next script uses the following environment variables:
# - MACHINE_NAME, AUTOTEST_ROOT, AUTOTEST_COMMIT
# - CI_COMMIT_REF_SLUG, CI_PROJECT_DIR, CI_PIPELINE_URL
# It also calls the script '.gitlab/scripts/safe_create_rundir'.
${CI_PROJECT_DIR}/.gitlab/scripts/report_build_and_test_success
err=$?
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> autotest.lock
.report_job_failure:
script:
- echo ${MACHINE_NAME}
- echo ${AUTOTEST}
- echo ${AUTOTEST_COMMIT}
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
- cd ${AUTOTEST_ROOT}
- |
(
date
echo "Waiting to aquire lock on '$PWD/autotest.lock' ..."
# try to get an excusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/autotest.lock'"
date
# Report FAILURE while holding the file lock on 'autotest.lock'.
# The next script uses the following environment variables:
# - MACHINE_NAME, AUTOTEST_ROOT, AUTOTEST_COMMIT
# - CI_COMMIT_REF_SLUG, CI_PROJECT_DIR, CI_PIPELINE_URL
# It also calls the script '.gitlab/scripts/safe_create_rundir'.
${CI_PROJECT_DIR}/.gitlab/scripts/report_build_and_test_failure
err=$?
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> autotest.lock
+39 -9
View File
@@ -9,13 +9,6 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# TPLS_DIR is used in .gitlab/scripts/baseline to provide the tpls location
# when call the runtest script in MFEM test repo.
# Note: the value must be consistent with what setup_baseline does.
variables:
TPLS_DIR: ${BUILD_ROOT}/tpls
AUTOTEST_ROOT: ${CI_BUILDS_DIR}/MFEM_${MACHINE_NAME}_baseline
# The setup_baseline job doesn't rely on MFEM git repo. It prepares a
# pipeline-wide working directory downloading/updating external repos.
# TODO:
@@ -30,13 +23,50 @@ setup_baseline:
variables:
GIT_STRATEGY: none
script:
#
# Setup ${BUILD_ROOT}/tpls and ${BUILD_ROOT}/tests:
#
- echo "MACHINE_NAME = ${MACHINE_NAME}"
- echo "REBASELINE = ${REBASELINE}"
- echo "AUTOTEST = ${AUTOTEST}"
- echo "AUTOTEST_COMMIT = ${AUTOTEST_COMMIT}"
- echo "BUILD_ROOT ${BUILD_ROOT}"
- mkdir -p ${BUILD_ROOT} && cd ${BUILD_ROOT}
- if [ ! -d "tpls" ]; then git clone ${TPLS_REPO}; fi
- if [ ! -d "tests" ]; then git clone ${TESTS_REPO}; fi
- cd tpls && git pull && cd ..
- cd tests && git pull origin && cd ..
#
# Setup ${AUTOTEST_ROOT}/autotest:
#
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
- mkdir -p ${AUTOTEST_ROOT} && cd ${AUTOTEST_ROOT}
- if [ ! -d "autotest" ]; then git clone ${AUTOTEST_REPO}; fi
- cd autotest && git pull && cd ..
- command -v flock || echo "Required command 'flock' not found"
- |
(
date
echo "Waiting to aquire lock on '$PWD/autotest.lock' ..."
# try to get an excusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/autotest.lock'"
date
# clone/update the autotest repo while holding the file lock on
# 'autotest.lock'
err=0
if [[ ! -d "autotest" ]]; then
git clone ${AUTOTEST_REPO}
else
cd autotest && git pull && cd ..
fi || err=1
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> autotest.lock
+73 -13
View File
@@ -9,13 +9,10 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
variables:
AUTOTEST_ROOT: ${CI_BUILDS_DIR}/MFEM_${MACHINE_NAME}_build_and_test
# setup clones the mfem/data repo in ${BUILD_ROOT}. The build_and_test script
# then symlinks the repo to the parent directory of the MFEM source directory.
# Unit tests that depend on the mfem/data repo will then detect that this
# directory is present and be enabled.
# Setup clones the mfem/data repo in ${SHARED_REPOS_DIR}. The build_and_test
# script then symlinks the repo to the parent directory of the MFEM source
# directory. Unit tests that depend on the mfem/data repo will then detect that
# this directory is present and be enabled.
setup:
tags:
- shell
@@ -24,11 +21,74 @@ setup:
variables:
GIT_STRATEGY: none
script:
- echo "BUILD_ROOT ${BUILD_ROOT}"
- mkdir -p ${BUILD_ROOT} && cd ${BUILD_ROOT}
- if [ ! -d data ]; then git clone ${MFEM_DATA_REPO}; fi
#
# Setup MFEM_DATA_DIR=${SHARED_REPOS_DIR}/mfem-data, see '.gitlab-ci.yml'
# and '.gitlab/configs/<machine>-config.yml'
#
- echo "MACHINE_NAME = ${MACHINE_NAME}"
- echo "AUTOTEST = ${AUTOTEST}"
- echo "AUTOTEST_COMMIT = ${AUTOTEST_COMMIT}"
- echo "SHARED_REPOS_DIR ${SHARED_REPOS_DIR}"
- mkdir -p ${SHARED_REPOS_DIR} && cd ${SHARED_REPOS_DIR}
- command -v flock || echo "Required command 'flock' not found"
- |
(
date
echo "Waiting to aquire lock on '$PWD/mfem-data.lock' ..."
# try to get an excusive lock on fd 9 (mfem-data.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/mfem-data.lock'"
date
# clone/update the mfem/data repo while holding the file lock on
# 'mfem-data.lock'
err=0
if [[ ! -d "mfem-data" ]]; then
git clone ${MFEM_DATA_REPO} "mfem-data"
else
cd "mfem-data" && git pull && cd ..
fi || err=1
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> mfem-data.lock
#
# Setup ${AUTOTEST_ROOT}/autotest:
#
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
- mkdir -p ${AUTOTEST_ROOT} && cd ${AUTOTEST_ROOT}
- if [ ! -d "autotest" ]; then git clone ${AUTOTEST_REPO}; fi
- cd autotest && git pull && cd ..
- |
(
date
echo "Waiting to aquire lock on '$PWD/autotest.lock' ..."
# try to get an excusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/autotest.lock'"
date
# clone/update the autotest repo while holding the file lock on
# 'autotest.lock'
err=0
if [[ ! -d "autotest" ]]; then
git clone ${AUTOTEST_REPO}
else
cd autotest && git pull && cd ..
fi || err=1
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> autotest.lock
+10 -6
View File
@@ -22,6 +22,7 @@ allocate_resource:
extends: .on_corona
stage: allocate_resource
script:
- echo ${ALLOC_NAME}
- salloc --exclusive --nodes=1 --partition=mi60 --time=30 --no-shell --job-name=${ALLOC_NAME}
timeout: 6h
needs: [setup]
@@ -40,24 +41,27 @@ release_resource:
extends: .on_corona
stage: release_resource_and_report
script:
- echo ${ALLOC_NAME}
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
- echo ${JOBID}
- ([[ -n "${JOBID}" ]] && scancel ${JOBID})
needs: [rocm_gcc_8.3.1]
# Jobs report
report_job_success:
extends: .on_corona
stage: release_resource_and_report
script:
- .gitlab/scripts/report_build_and_test_success
extends:
- .on_corona
- .report_job_success
report_job_failure:
extends: .on_corona
stage: release_resource_and_report
script:
- .gitlab/scripts/report_build_and_test_failure
extends:
- .on_corona
- .report_job_failure
include:
- local: .gitlab/configs/common.yml
- local: .gitlab/configs/corona-config.yml
- local: .gitlab/configs/setup-build-and-test.yml
- local: .gitlab/configs/report-build-and-test.yml
+7 -6
View File
@@ -21,18 +21,19 @@ opt_mpi_cuda_xl_16_1_1_8:
# Jobs report
report_job_success:
extends: .on_lassen
stage: report
script:
- .gitlab/scripts/report_build_and_test_success
extends:
- .on_lassen
- .report_job_success
report_job_failure:
extends: .on_lassen
stage: report
script:
- .gitlab/scripts/report_build_and_test_failure
extends:
- .on_lassen
- .report_job_failure
include:
- local: .gitlab/configs/common.yml
- local: .gitlab/configs/lassen-config.yml
- local: .gitlab/configs/setup-build-and-test.yml
- local: .gitlab/configs/report-build-and-test.yml
+84 -15
View File
@@ -16,12 +16,26 @@ stages:
- setup
- baseline_check
- baseline_report
- cleanup
- baseline_publish
baselinecheck_mfem_intel_quartz:
extends: [.on_quartz]
stage: baseline_check
variables:
# TPLS_DIR is used in .gitlab/scripts/baseline to provide the tpls location
# when call the runtest script in MFEM test repo.
# Note: the value must be consistent with the setup performed in
# .gitlab/configs/setup-baseline.yml.
TPLS_DIR: ${BUILD_ROOT}/tpls
script:
- echo ${BUILD_ROOT}
- echo ${TPLS_DIR}
# Used by the tests in MFEM/tests:
- export MFEM_TEST_NP=32
# The next script uses the following environment variables:
# * BASELINE_TEST, SYS_TYPE, CI_PROJECT_DIR, ARTIFACTS_DIR,
# * BUILD_ROOT, TPLS_DIR, MACHINE_NAME
- .gitlab/scripts/baseline
artifacts:
when: always
@@ -29,33 +43,88 @@ baselinecheck_mfem_intel_quartz:
- ${ARTIFACTS_DIR}
allow_failure: true
cleanup:
extends: .on_quartz
stage: cleanup
variables:
GIT_STRATEGY: none
script:
- echo "BUILD_ROOT=${BUILD_ROOT}"
- rm -rf "${BUILD_ROOT}" || true
report_baseline:
extends: [.on_quartz]
stage: baseline_report
script:
- cd ${AUTOTEST_ROOT}/autotest && git pull
- mkdir -p ${MACHINE_NAME}
- rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-${BASELINE_TEST}-${CI_COMMIT_REF_SLUG}"
- rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir ${rundir})
- cp ${CI_PROJECT_DIR}/${ARTIFACTS_DIR}/* ${rundir}
# We create an autotest-email.html file, because that's how we signal that there was a diff (temporary).
- echo ${MACHINE_NAME}
- echo ${AUTOTEST}
- echo ${AUTOTEST_COMMIT}
- echo "AUTOTEST_ROOT ${AUTOTEST_ROOT}"
- cd ${AUTOTEST_ROOT}
- |
if [[ -f ${rundir}/*.err ]]
then
echo "See the pipeline here -> $CI_PIPELINE_URL" >> ${rundir}/*.err
cp ${rundir}/*.err ${rundir}/autotest-email.html
fi
- git add ${rundir}
- git commit -am "GitLab CI log for ${BASELINE_TEST} on ${MACHINE_NAME} with intel ($(date +%Y-%m-%d))"
- git push origin master
(
date
echo "Waiting to aquire lock on '$PWD/autotest.lock' ..."
# try to get an excusive lock on fd 9 (autotest.lock) repeating the try
# every 5 seconds; simply using no timeout, i.e. 'flock 9', causes the
# command to hang indefinitely sometimes, so we use the timeout & retry
# as a workaround; we may want to add a counter for the number of
# retries to interrupt a potential infinite loop
while ! flock -w 5 9; do
true
done
echo "Aquired lock on '$PWD/autotest.lock'"
date
# ----------------------
cd ${AUTOTEST_ROOT}/autotest || \
{ echo "Invalid 'autotest' dir: ${AUTOTEST_ROOT}/autotest"; exit 1; }
mkdir -p ${MACHINE_NAME}
rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-${BASELINE_TEST}-${CI_COMMIT_REF_SLUG}"
rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir ${rundir})
cp ${CI_PROJECT_DIR}/${ARTIFACTS_DIR}/* ${rundir}
# We create an autotest-email.html file, because that's how we signal that there was a diff (temporary).
if [[ -f ${rundir}/${BASELINE_TEST}.err ]]; then
cp ${rundir}/${BASELINE_TEST}.err ${rundir}/autotest-email.html
fi
printf "%s\n" "" "Pipeline URL:" "$CI_PIPELINE_URL" \
>> ${rundir}/pipeline.txt
msg="GitLab CI log for ${BASELINE_TEST} on ${MACHINE_NAME} ($(date +%Y-%m-%d))"
if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
echo "Content of '$file'"
echo "******************************"
cat $file
echo "******************************"
done
rm -rf ${rundir} || true
fi
err=$?
# ----------------------
# sleep for a period to allow NFS to propagate the above changes;
# clearly, there is no guarantee that other NFS clients will see the
# changes even after the timeout
sleep 10
exit $err
) 9> autotest.lock
baselinepublish_mfem_quartz:
extends: [.on_quartz]
stage: baseline_publish
rules:
- if: '$CI_COMMIT_BRANCH == "master" || $REBASELINE == "YES"'
# - if: '$CI_COMMIT_BRANCH == "master" || $REBASELINE == "YES"'
- if: '$REBASELINE == "YES"'
when: manual
script:
- echo ${BUILD_ROOT}
- echo ${PWD}
- echo ${ARTIFACTS_DIR}
- ls -lA ${ARTIFACTS_DIR}
- .gitlab/scripts/rebaseline
include:
+10 -6
View File
@@ -22,6 +22,7 @@ allocate_resource:
extends: .on_quartz
stage: allocate_resource
script:
- echo ${ALLOC_NAME}
- salloc --exclusive --nodes=1 --partition=pdebug --time=30 --no-shell --job-name=${ALLOC_NAME}
timeout: 6h
@@ -73,23 +74,26 @@ release_resource:
extends: .on_quartz
stage: release_resource_and_report
script:
- echo ${ALLOC_NAME}
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
- echo ${JOBID}
- ([[ -n "${JOBID}" ]] && scancel ${JOBID})
# Jobs report
report_job_success:
extends: .on_quartz
stage: release_resource_and_report
script:
- .gitlab/scripts/report_build_and_test_success
extends:
- .on_quartz
- .report_job_success
report_job_failure:
extends: .on_quartz
stage: release_resource_and_report
script:
- .gitlab/scripts/report_build_and_test_failure
extends:
- .on_quartz
- .report_job_failure
include:
- local: .gitlab/configs/common.yml
- local: .gitlab/configs/quartz-config.yml
- local: .gitlab/configs/setup-build-and-test.yml
- local: .gitlab/configs/report-build-and-test.yml
+9 -1
View File
@@ -20,7 +20,8 @@ base_out=${base}.out
artifacts_path=${CI_PROJECT_DIR}/${ARTIFACTS_DIR}
# prepare
cd ${BUILD_ROOT}
cd ${BUILD_ROOT} || \
{ echo "Invalid BUILD_ROOT=$BUILD_ROOT"; exit 1; }
ln -snf ${CI_PROJECT_DIR} mfem
cd tests
[[ -d _${BASELINE_TEST} ]] && rm -rf _${BASELINE_TEST}
@@ -33,6 +34,9 @@ elif [[ ${MACHINE_NAME} == "corona" ]]; then
srun --nodes=1 -t 60 -p mi60 ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
elif [[ ${MACHINE_NAME} == "lassen" ]]; then
lalloc 1 -q pdebug ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
else
echo "Unknown machine: MACHINE_NAME=$MACHINE_NAME"
exit 1
fi
# post
@@ -60,6 +64,10 @@ then
cp ${base_out} ${artifacts_path}/${base_out}
fi
if [[ -f ${BASELINE_TEST}.out ]]; then
cp ${BASELINE_TEST}.out ${artifacts_path}
fi
# base_diff won't even exist if there is no difference.
if [[ -f ${base_diff} ]]
then
+20 -7
View File
@@ -13,20 +13,33 @@
echo "Runs if there was at least one failure on ${MACHINE_NAME}"
cd ${AUTOTEST_ROOT}/autotest && git pull
cd ${AUTOTEST_ROOT}/autotest || \
{ echo "Invalid 'autotest' dir: ${AUTOTEST_ROOT}/autotest"; exit 1; }
mkdir -p ${MACHINE_NAME}
rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-ci-${CI_COMMIT_REF_SLUG}"
rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir $rundir)
echo "There was an error while running CI on ${MACHINE_NAME}" > ${rundir}/gitlab.err
echo "See the pipeline here -> $CI_PIPELINE_URL" >> ${rundir}/gitlab.err
printf "%s\n" "Some 'build-and-test' jobs on ${MACHINE_NAME} FAILED." \
"Pipeline URL:" "$CI_PIPELINE_URL" > ${rundir}/gitlab.err
msg="GitLab CI log for build-and-test on ${MACHINE_NAME} ($(date +%Y-%m-%d))"
# Create 'autotest-email.html' to indicate failure:
cp ${rundir}/gitlab.err ${rundir}/autotest-email.html
git pull
git add ${rundir}
git commit -am "${msg}"
git push origin master
if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
echo "Content of '$file'"
echo "******************************"
cat $file
echo "******************************"
done
rm -rf ${rundir} || true
fi
+19 -7
View File
@@ -13,18 +13,30 @@
echo "Can only run if all the ${MACHINE_NAME} jobs passed"
cd ${AUTOTEST_ROOT}/autotest && git pull
cd ${AUTOTEST_ROOT}/autotest || \
{ echo "Invalid 'autotest' dir: ${AUTOTEST_ROOT}/autotest"; exit 1; }
mkdir -p ${MACHINE_NAME}
rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-ci-${CI_COMMIT_REF_SLUG}"
rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir $rundir)
echo "The ${MACHINE_NAME} jobs were successful" > ${rundir}/gitlab.out
echo "See the pipeline here -> $CI_PIPELINE_URL" >> ${rundir}/gitlab.err
printf "%s\n" "The 'build-and-test' jobs on ${MACHINE_NAME} were SUCCESSFUL." \
"Pipeline URL:" "$CI_PIPELINE_URL" > ${rundir}/gitlab.out
msg="GitLab CI log for build-and-test on ${MACHINE_NAME} ($(date +%Y-%m-%d))"
git pull
git add ${rundir}
git commit -am "${msg}"
git push origin master
if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
git pull && \
git add ${rundir} && \
git commit -m "${msg}" && \
git push origin master
else
for file in ${rundir}/*; do
echo "------------------------------"
echo "Content of '$file'"
echo "******************************"
cat $file
echo "******************************"
done
rm -rf ${rundir} || true
fi
+19
View File
@@ -10,6 +10,15 @@
Version 4.3.1 (development)
===========================
- Added support for automatic differentiation. Users can select between
native implementation and external library implementation at the
configuration phase. A parallel and two serial examples are implemented
in the autodiff miniapp directory.
- Added support for mesh preprocessing to resolve fine scale problem data
before simulation. This feature uses adaptive mesh refinement to control the
associated data oscillation error. See the new Example 30/30p.
- Switched from Artistic Style (astyle) version 2.05.1 to version 3.1 for code
formatting. See the "make style" target.
@@ -60,6 +69,16 @@ Version 4.3.1 (development)
- Remove the 'u' flag in the ar command, to update all files in the archive,
avoiding file name collisions from different subdirectories.
- Added initial TMOP-based capabilities for surface fitting and tangential
relaxation in the mesh-optimizer and pmesh-optimizer miniapps.
- Added ParMesh Adjaceny Set (adjset) creation support to the Conduit Mesh
Blueprint MFEM wrapper functions in ConduitDataCollection.
- `HypreParVector` and `Vector` now support move semantics, and the copy
constructor for `HypreParVector` now copies the local vector data.
Version 4.3, released on July 29, 2021
======================================
+17 -2
View File
@@ -252,6 +252,11 @@ if (MFEM_USE_OPENMP OR MFEM_USE_LEGACY_OPENMP)
endif()
find_package(OpenMP REQUIRED)
set(OPENMP_LIBRARIES ${OpenMP_CXX_LIBRARIES})
if(APPLE)
# On macOS, the compiler needs additional help to find the <omp.h> header.
# See issue #2642 for more information.
include_directories(${OpenMP_CXX_INCLUDE_DIRS})
endif(APPLE)
endif()
# SuiteSparse (before SUNDIALS which may depend on KLU)
@@ -367,6 +372,12 @@ if (MFEM_USE_HIOP)
# find_package updates HIOP_FOUND, HIOP_INCLUDE_DIRS, HIOP_LIBRARIES
endif()
# CoDiPack package
if (MFEM_USE_CODIPACK)
find_package(CODIPACK REQUIRED)
# find_package updates CODIPACK_FOUND, CODIPACK_INCLUDE_DIRS, CODIPACK_LIBRARIES
endif()
# OCCA
if (MFEM_USE_OCCA)
find_package(OCCA REQUIRED)
@@ -446,7 +457,7 @@ endif()
set(MFEM_TPLS OPENMP HYPRE BLAS LAPACK SuperLUDist METIS SuiteSparse SUNDIALS PETSC
SLEPC MESQUITE MUMPS STRUMPACK AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB NETCDF
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2
CUSPARSE MKL_CPARDISO AMGX CALIPER BENCHMARK PARELAG MPI_CXX)
CUSPARSE MKL_CPARDISO AMGX CALIPER CODIPACK BENCHMARK PARELAG MPI_CXX)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
@@ -576,7 +587,11 @@ add_custom_target(${MFEM_EXEC_PREREQUISITES_TARGET_NAME})
# Create a target for all examples and, optionally, enable it.
set(MFEM_ALL_EXAMPLES_TARGET_NAME examples)
add_mfem_target(${MFEM_ALL_EXAMPLES_TARGET_NAME} ${MFEM_ENABLE_EXAMPLES})
add_subdirectory(examples EXCLUDE_FROM_ALL)
if (MFEM_ENABLE_EXAMPLES)
add_subdirectory(examples) #install examples if enabled
else()
add_subdirectory(examples EXCLUDE_FROM_ALL)
endif()
# Create a target for all miniapps and, optionally, enable it.
set(MFEM_ALL_MINIAPPS_TARGET_NAME miniapps)
+101 -5
View File
@@ -42,6 +42,7 @@ back to them before issuing pull requests:
- [New Feature Development](#new-feature-development)
- [Developer Guidelines](#developer-guidelines)
- [Pull Requests](#pull-requests)
- [MFEM PR Rules](#mfem-pr-rules)
- [Pull Request Checklist](#pull-request-checklist)
- [Master/Next Workflow](#masternext-workflow)
- [Releases](#releases)
@@ -67,8 +68,9 @@ Origin](#developers-certificate-of-origin-11) at the end of this file.*
with regards to documentation and code styling.
- Please do not commit large/binary files to the central repository (use a fork
instead).
- Pull requests should be issued toward `mfem:master`. Make sure
to check the items off the [Pull Request Checklist](#pull-request-checklist).
- Pull requests should be issued toward `mfem:master`. Make sure
to check the items off the [Pull Request Checklist](#pull-request-checklist) and
follow the [MFEM PR Rules](#mfem-pr-rules).
- When your contribution is fully working and ready to be reviewed, add
the `ready-for-review` label.
- PRs are treated similarly to journal submission with an "editor" assigning two
@@ -121,6 +123,7 @@ The MFEM source code has the following structure:
├── mesh
├── miniapps
│ ├── adjoint
│ ├── autodiff
│ ├── common
│ ├── electromagnetics
│ ├── gslib
@@ -326,8 +329,12 @@ Before you can start, you need a GitHub account, here are a few suggestions:
change the code by default.
- Code specifics
- All significant new classes, methods and functions have Doxygen-style
documentation in source comments.
- All new public, protected, and private classes, methods, data members, and
functions have Doxygen-style documentation in source comments.
- In addition to arguments and functionality, documentation should include the
current limitations of the code, any background information that is
implicitly assumed in the implementation, and the ownership and lifetime
of data.
- Consistent code styling is enforced with `make style` in the top-level
directory. This requires [Artistic Style](http://astyle.sourceforge.net) (we
specifically use version 3.1). See also the file `config/mfem.astylerc`.
@@ -335,6 +342,9 @@ Before you can start, you need a GitHub account, here are a few suggestions:
internal library code. (You can use `std` in examples and miniapps.)
- When manually resolving conflicts during a merge, make sure to mention the
conflicted files in the commit message.
- All significant new features and changes should be documented in CHANGELOG.
- New examples and miniapps should have documentation on the MFEM webpage.
### Pull Requests
@@ -400,6 +410,83 @@ Before you can start, you need a GitHub account, here are a few suggestions:
- If triggered, track the status of the LLNL GitLab tests. If failing, ask
one of the _LLNL developers_ for details.
### MFEM PR Rules
The Pull Request (PR) approval process in MFEM is similar to the approval of papers in a peer-reviewed journal. In particular:
1. There is an MFEM board of "editors" that evaluates new PRs and assigns "reviewers" for each PR.
2. The assigned reviewers are responsible to carefully review and test the proposed PR.
3. A PR can be (manually) merged in the *next* branch only if 2 of the assigned reviewers have approved it and it has passed internal testing. This merge can be performed by any of the assigned reviewers or by any of the editors.
4. A PR can be merged in the *master* branch only if it has been tested successfully for a week in *next* and an editor has (optionally) taken a final look. This merge can be performed only by one of the editors.
#### Responsibilities of Editors
The current list of MFEM editors is:
- @v-dobrev (Veselin Dobrev)
- @tzanio (Tzanio Kolev)
- @pazner (Will Pazner)
- @mlstowell (Mark Stowell)
**The responsibilities of the editors are:**
1. To assign appropriate milestone and labels for new PRs, e.g. *bugfix*, *minor*, *api-change*, *high-impact*, etc.
2. To assign at least 2 reviewers for new PRs. An editor can also be a reviewer. The editor, reviewers, and author should be listed as "Assignees" on the GitHub PR page. After assignment, the `in-review` label should be added.
3. To complete the initial PR evaluation and assignments in a timely manner: 1 week from submission.
4. To assist reviewers when they need help with their reviews (but also to stay out of the way when they don't).
5. To remind the reviewers about timely completion of their review.
6. To take a final look and complete the PR merge in *master*. The final look step is optional and shouldn't take more than 3 days.
7. The assignment of bugfixes should be expedited proportional to their importance, e.g. in some cases the editor can assign much shorter review window.
#### Responsibilities of Reviewers
Everyone on the MFEM team can be asked to serve as a reviewer on a PR in their area of expertise.
**The responsibilities of the reviewers are:**
1. To let the editors know if the proposed assignment is not a good match for them.
2. To communicate with the PR author, provide feedback and work with them to resolve issues.
3. To ensure the quality of the PR by making sure that the code adheres to the [Developer Guidelines](#developer-guidelines), e.g. all methods, data members, and functions have documentation, including data ownership and lifetime, new examples/miniapps have a corresponding PR in mfem/web, major features have `CHANGELOG` entries, etc.
3. To seek help from the editors in case of difficulties.
4. To complete the review in a timely manner: 3 weeks from assignment.
5. To test the PR thoroughly before merging in *next*. The PR author is also encouraged to perform testing and inform the reviewers about the results.
6. To monitor the PR impact on the testing in the *next* branch and alert the editors that the PR is ready for merging in *master*.
7. The review of bugfixes should be expedited proportional to their importance. The review window can be much less than three weeks in such cases.
#### Responsibilities of Authors
Authors should clearly indicate when a PR is ready for review (before that the PR should be marked as `Draft` or `[WIP]`).
**The responsibilities of the authors are:**
1. To follow the instructions and PR checklist in the `CONTRIBUTING.md` document in the MFEM repository.
2. To respond to reviewer feedback in a timely manner.
3. Authors are encouraged to perform testing and inform the reviewers about the results.
4. Authors can use the "Reviewers" section of the GitHub PR page to suggest reviewers, but the "Assignees" section will show who the editor has assigned to do the reviews.
5. To indicate when the PR is ready for review by adding the `ready-for-review` label.
### Pull Request Checklist
Before a PR can be merged, it should satisfy the following:
@@ -453,7 +540,9 @@ Before a PR can be merged, it should satisfy the following:
- [ ] The miniapps go at the end of the page, and are usually listed only under a specific "Application (PDE)" category.
- [ ] Add a short description of the miniapp in the "Extensive Examples" section of `features.md`.
- [ ] New capability:
- [ ] All significant new classes, methods and functions have Doxygen-style documentation in source comments.
- [ ] All new public, protected, and private classes, methods, data members, and functions have full Doxygen-style documentation in source comments. Documentation should include descriptions of member data, function arguments and return values, template parameters, and prerequisites for calling new functions.
- [ ] Pointer arguments and return values must specify whether ownership is being transferred or lent with the call.
- [ ] Any new functions should include descriptions of their intended use e.g. for internal use only, user-facing, etc., along with references to example code whenever possible/appropriate.
- [ ] Consider adding new sample runs in existing examples to highlight the new capability.
- [ ] Consider saving cool simulation pictures with the new capability in the Confluence gallery (LLNL only) or submitting them, via pull request, to the gallery section of the `mfem/web` repo.
- [ ] If this is a major new feature, consider mentioning it in the short summary inside `README` *(rare)*.
@@ -464,6 +553,7 @@ Before a PR can be merged, it should satisfy the following:
- [ ] (LLNL only) After merging:
- [ ] Update internal tests to include the new features.
### Master/Next Workflow
MFEM uses a `master`/`next`-branch workflow as described below:
@@ -555,8 +645,10 @@ MFEM uses a `master`/`next`-branch workflow as described below:
- Update version and shortlinks in `src/index.md` and `src/download.md`.
- Use [cloc-1.62.pl](http://cloc.sourceforge.net/) and `ls -lh` to estimate the SLOC and the tarball size in `src/download.md`.
## LLNL Workflow
### Mirroring on Bitbucket
- The GitHub `master` and `next` branches are mirrored to the LLNL institutional
@@ -576,6 +668,7 @@ MFEM uses a `master`/`next`-branch workflow as described below:
- `mfem:gh-next` -- Bleeding-edge development version, may be broken, use at
your own risk.
### Mirroring on GitLab
- MFEM repository is also mirrored on the LLNL GitLab instance, in a
@@ -598,6 +691,7 @@ In addition, developers can set local git hooks to run some quick checks on
commit or push, see the [README](config/githooks/README.md) in the `config/githooks`
directory.
### Linux and Mac smoke tests
We use GitHub Actions to drive the default tests on the `master` and `next`
branches. See the `.github/workflows` files and the logs at
@@ -609,6 +703,7 @@ constraint on jobs. Two virtual machines are configured - Mac (OS X) and Linux.
- Tests on the `master` branch are triggered whenever a PR is issued on this branch.
- Tests on the `next` branch are currently scheduled to run each night.
### Windows smoke test
We use Appveyor to test building with the MS Visual C++ compiler in a Windows
environment, as well as to test the CMake build. See the `.appveyor` file and the
@@ -618,6 +713,7 @@ build logs at
CMake is used to generate the MSVC Project files and drive the build. A release
and debug build is performed with a simple run of `ex1` to verify the executable.
### Tests at LLNL
- We mirror the `master` and `next` branches internally (to `gh-master` and
+16
View File
@@ -467,6 +467,14 @@ MFEM_USE_HIOP = YES/NO
Enable the usage of HiOp (https://github.com/LLNL/hiop) in MFEM. HiOp is an
HPC solver for nonlinear optimization problems.
MFEM_USE_CODIPACK = YES/NO
Enable automatic differentiation using the CoDiPack library.
www.scicomp.uni-kl.de/codi/
MFEM_USE_ADFORWARD = YES/NO
Enable forward mode for AD packages. This option is valid
only if the AD package supports two modes (backward/forward).
MFEM_USE_CUDA = YES/NO
Enables support for CUDA devices in MFEM. CUDA is a parallel computing
platform and programming model for general computing on graphical processing
@@ -703,6 +711,11 @@ The specific libraries and their options are:
Options: HIOP_OPT, HIOP_LIB.
Versions: HIOP >= 0.4.6.
- CoDiPack (optiobal), used with MFEM_USE_CODIPACK = YES
URL: https://www.scicomp.uni-kl.de/codi/
Options: CODIPACK_OPT
Versions: 1.9.3
- GSLIB (optional), used when MFEM_USE_GSLIB = YES. The gslib library must be
built prior to the MFEM build, as follows: download gslib-1.0.7, untar it at
the same level as MFEM and create a symbolic link: "ln -s gslib-1.0.7 gslib".
@@ -908,6 +921,8 @@ MFEM_USE_MPFR
MFEM_USE_ZLIB
MFEM_USE_PUMI
MFEM_USE_HIOP
MFEM_USE_CODIPACK
MFEM_USE_ADFORWARD
MFEM_USE_CUDA
MFEM_USE_OCCA
MFEM_USE_CEED
@@ -967,6 +982,7 @@ The CMake build system adds auto-detection for the following packages/libraries:
- POSIXCLOCKS
- PUMI
- HIOP
- CoDiPack
- OCCA
- RAJA
- UMPIRE
+2
View File
@@ -54,6 +54,8 @@ set(MFEM_USE_CEED @MFEM_USE_CEED@)
set(MFEM_USE_UMPIRE @MFEM_USE_UMPIRE@)
set(MFEM_USE_SIMD @MFEM_USE_SIMD@)
set(MFEM_USE_ADIOS2 @MFEM_USE_ADIOS2@)
set(MFEM_USE_CODIPACK @MFEM_USE_CODIPACK@)
set(MFEM_USE_ADFORWARD @MFEM_USE_ADFORWARD@)
set(MFEM_USE_CALIPER @MFEM_USE_CALIPER@)
set(MFEM_USE_BENCHMARK @MFEM_USE_BENCHMARK@)
set(MFEM_USE_PARELAG @MFEM_USE_PARELAG@)
+6
View File
@@ -175,6 +175,12 @@
// Enable interface to the MKL CPardiso library.
#cmakedefine MFEM_USE_MKL_CPARDISO
// Use forward mode for automatic differentiation
#cmakedefine MFEM_USE_ADFORWARD
// Enable the use of the CoDiPack library for AD
#cmakedefine MFEM_USE_CODIPACK
// Enable MFEM functionality based on the Google Benchmark library.
#cmakedefine MFEM_USE_BENCHMARK
+24
View File
@@ -0,0 +1,24 @@
# Copyright (c) 2010-2021, 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.
# Automatic differentiation using the CoDiPack library.
# www.scicomp.uni-kl.de/codi/
# Sets the following variables:
# - CODIPACK_FOUND
# - CODIPACK_INCLUDE_DIRS
# - CODIPACK_LIBRARIES
include(MfemCmakeUtilities)
mfem_find_package(CODIPACK CODIPACK CODIPACK_DIR
"include" "codi.h"
"lib" ""
"Paths to headers required by CODIPACK."
"Libraries required by CODIPACK.")
@@ -100,6 +100,8 @@ macro(add_mfem_examples EXE_SRCS)
string(REPLACE ".cpp" "" EXE_NAME "${EXE_PREFIX}${SRC_FILENAME}")
mfem_add_executable(${EXE_NAME} ${SRC_FILE})
install(TARGETS ${EXE_NAME}
RUNTIME DESTINATION examples)
add_dependencies(${MFEM_ALL_EXAMPLES_TARGET_NAME} ${EXE_NAME})
if (EXE_NEEDED_BY)
add_dependencies(${EXE_NEEDED_BY} ${EXE_NAME})
+6
View File
@@ -180,6 +180,12 @@
// Enable interface to the MKL CPardiso library.
// #define MFEM_USE_MKL_CPARDISO
// Use forward mode for automatic differentiation
// #define MFEM_USE_ADFORWARD
// Enable the use of the CoDiPack library for AD
// #define MFEM_USE_CODIPACK
// Enable functionality based on the Google Benchmark library.
// #define MFEM_USE_BENCHMARK
+2
View File
@@ -58,6 +58,8 @@ MFEM_USE_UMPIRE = @MFEM_USE_UMPIRE@
MFEM_USE_SIMD = @MFEM_USE_SIMD@
MFEM_USE_ADIOS2 = @MFEM_USE_ADIOS2@
MFEM_USE_MKL_CPARDISO = @MFEM_USE_MKL_CPARDISO@
MFEM_USE_ADFORWARD = @MFEM_USE_ADFORWARD@
MFEM_USE_CODIPACK = @MFEM_USE_CODIPACK@
MFEM_USE_BENCHMARK = @MFEM_USE_BENCHMARK@
MFEM_USE_PARELAG = @MFEM_USE_PARELAG@
+5
View File
@@ -58,6 +58,8 @@ option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" OFF)
option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
option(MFEM_USE_CALIPER "Enable Caliper support" OFF)
option(MFEM_USE_MKL_CPARDISO "Enable MKL CPardiso" OFF)
option(MFEM_USE_ADFORWARD "Enable forward mode for AD" OFF)
option(MFEM_USE_CODIPACK "Enable automatic differentiation (AD) using CoDiPack" OFF)
option(MFEM_USE_BENCHMARK "Enable Google Benchmark" OFF)
option(MFEM_USE_PARELAG "Enable ParELAG" OFF)
@@ -243,6 +245,9 @@ set(BLAS_LIBRARIES "" CACHE STRING "The BLAS library.")
set(LAPACK_INCLUDE_DIRS "" CACHE STRING "Path to LAPACK headers.")
set(LAPACK_LIBRARIES "" CACHE STRING "The LAPACK library.")
set(CODIPACK_INCLUDE_DIRS "${MFEM_DIR}/../CoDiPack/inlude" CACHE STRING "Path to CoDiPack headers.")
set(CODIPACK_LIBRARIES "")
# Some useful variables:
set(CMAKE_SKIP_PREPROCESSED_SOURCE_RULES ON) # Skip *.i rules
set(CMAKE_SKIP_ASSEMBLY_SOURCE_RULES ON) # Skip *.s rules
+13
View File
@@ -59,6 +59,9 @@ HIP_FLAGS = --amdgpu-target=$(HIP_ARCH)
HIP_XCOMPILER =
HIP_XLINKER = -Wl,
# Flags for generating dependencies.
DEP_FLAGS = -MM -MT
ifneq ($(NOTMAC),)
AR = ar
ARFLAGS = crv
@@ -86,6 +89,9 @@ else
BUILD_RPATH = $(XLINKER)-undefined,dynamic_lookup
INSTALL_SOFLAGS = $(subst $1 ,,$(call MAKE_SOFLAGS,$(MFEM_LIB_DIR)))
INSTALL_RPATH = $(XLINKER)-undefined,dynamic_lookup
# Silence unused command line argument warnings when generating dependencies
# with mpicxx and clang
DEP_FLAGS := -Wno-unused-command-line-argument $(DEP_FLAGS)
endif
# Set CXXFLAGS to overwrite the default selection of DEBUG_FLAGS/OPTIM_FLAGS
@@ -151,6 +157,8 @@ MFEM_USE_UMPIRE = NO
MFEM_USE_SIMD = NO
MFEM_USE_ADIOS2 = NO
MFEM_USE_MKL_CPARDISO = NO
MFEM_USE_ADFORWARD = NO
MFEM_USE_CODIPACK = NO
MFEM_USE_BENCHMARK = NO
MFEM_USE_PARELAG = NO
@@ -408,6 +416,11 @@ HIOP_DIR = @MFEM_DIR@/../hiop/install
HIOP_OPT = -I$(HIOP_DIR)/include
HIOP_LIB = -L$(HIOP_DIR)/lib -lhiop $(LAPACK_LIB)
# CoDiPack
CODIPACK_DIR = @MFEM_DIR@/../CoDiPack
CODIPACK_OPT = -I$(CODIPACK_DIR)
CODIPACK_LIB =
# GSLIB library
GSLIB_DIR = @MFEM_DIR@/../gslib/build
GSLIB_OPT = -I$(GSLIB_DIR)/include
+1
View File
@@ -781,6 +781,7 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/miniapps/gslib \
@MFEM_SOURCE_DIR@/miniapps/meshing \
@MFEM_SOURCE_DIR@/miniapps/mtop \
@MFEM_SOURCE_DIR@/miniapps/autodiff \
@MFEM_SOURCE_DIR@/miniapps/navier \
@MFEM_SOURCE_DIR@/miniapps/nurbs \
@MFEM_SOURCE_DIR@/miniapps/performance \
+2
View File
@@ -194,6 +194,8 @@ namespace mfem {
* - <a class="el" href="parheat_8cpp_source.html">Optimization gradients</a>: Gradients of PDE-constrained function
* - <a class="el" href="miniapps_2performance_2ex1_8cpp_source.html">HPC Example 1</a>: high-performance nodal H1 FEM for the Laplace problem
* - <a class="el" href="miniapps_2performance_2ex1p_8cpp_source.html">HPC Example 1p</a>: high-performance parallel nodal H1 FEM for the Laplace problem
* - <a class="el" href="par__example_8cpp_source.html">Parallel pLaplacian example using AD</a>: Parallel pLaplacian example
* - <a class="el" href="seq__example_8cpp_source.html">Serial pLaplacian example using AD</a>: Serial pLaplacian example
*
* See also the <a class="el" href="https://mfem.org/examples/">examples documentation</a> online.
*/
+64 -60
View File
@@ -37,6 +37,7 @@ list(APPEND ALL_EXE_SRCS
ex27.cpp
ex28.cpp
ex29.cpp
ex30.cpp
)
if (MFEM_USE_MPI)
@@ -70,6 +71,7 @@ if (MFEM_USE_MPI)
ex27p.cpp
ex28p.cpp
ex29p.cpp
ex30p.cpp
)
endif()
@@ -80,78 +82,80 @@ include_directories(BEFORE ${PROJECT_BINARY_DIR})
add_mfem_examples(ALL_EXE_SRCS)
# Add a test for each example
foreach(SRC_FILE ${ALL_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
if (MFEM_ENABLE_TESTING)
foreach(SRC_FILE ${ALL_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
set(THIS_TEST_OPTIONS "-no-vis")
if (${TEST_NAME} MATCHES "ex0p?")
set(THIS_TEST_OPTIONS)
endif()
if (${TEST_NAME} MATCHES "ex10p*")
list(APPEND THIS_TEST_OPTIONS "-tf" "5")
elseif(${TEST_NAME} MATCHES "ex15p*")
list(APPEND THIS_TEST_OPTIONS "-e" "1")
elseif(${TEST_NAME} MATCHES "ex27p*")
list(APPEND THIS_TEST_OPTIONS "-dg")
endif()
set(THIS_TEST_OPTIONS "-no-vis")
if (${TEST_NAME} MATCHES "ex0p?")
set(THIS_TEST_OPTIONS)
endif()
if (${TEST_NAME} MATCHES "ex10p*")
list(APPEND THIS_TEST_OPTIONS "-tf" "5")
elseif(${TEST_NAME} MATCHES "ex15p*")
list(APPEND THIS_TEST_OPTIONS "-e" "1")
elseif(${TEST_NAME} MATCHES "ex27p*")
list(APPEND THIS_TEST_OPTIONS "-dg")
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
# Add CUDA/HIP tests.
set(DEVICE_EXAMPLES
# serial examples with device support:
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26
# parallel examples with device support:
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p)
set(MFEM_TEST_DEVICE)
if (MFEM_USE_CUDA)
set(MFEM_TEST_DEVICE "cuda")
elseif (MFEM_USE_HIP)
set(MFEM_TEST_DEVICE "hip")
endif()
if (MFEM_TEST_DEVICE)
foreach(TEST_NAME ${DEVICE_EXAMPLES})
set(THIS_TEST_OPTIONS "-no-vis" "-d" "${MFEM_TEST_DEVICE}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_ser
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
elseif (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_np=${MFEM_MPI_NP}
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
# If STRUMPACK is enabled, add a test run that uses it.
if (MFEM_USE_STRUMPACK)
add_test(NAME ex11p_strumpack_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--strumpack"
${MPIEXEC_POSTFLAGS})
endif()
# Add CUDA/HIP tests.
set(DEVICE_EXAMPLES
# serial examples with device support:
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26
# parallel examples with device support:
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p)
set(MFEM_TEST_DEVICE)
if (MFEM_USE_CUDA)
set(MFEM_TEST_DEVICE "cuda")
elseif (MFEM_USE_HIP)
set(MFEM_TEST_DEVICE "hip")
endif()
if (MFEM_TEST_DEVICE)
foreach(TEST_NAME ${DEVICE_EXAMPLES})
set(THIS_TEST_OPTIONS "-no-vis" "-d" "${MFEM_TEST_DEVICE}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
elseif (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
# If SuperLU_DIST is enabled, add a test run that uses it.
if (MFEM_USE_SUPERLU)
add_test(NAME ex11p_superlu_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--superlu"
${MPIEXEC_POSTFLAGS})
# If STRUMPACK is enabled, add a test run that uses it.
if (MFEM_USE_STRUMPACK)
add_test(NAME ex11p_strumpack_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--strumpack"
${MPIEXEC_POSTFLAGS})
endif()
# If SuperLU_DIST is enabled, add a test run that uses it.
if (MFEM_USE_SUPERLU)
add_test(NAME ex11p_superlu_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex11p> "-no-vis" "--superlu"
${MPIEXEC_POSTFLAGS})
endif()
endif()
# Include the examples/amgx directory if AmgX is enabled
+26 -24
View File
@@ -50,30 +50,32 @@ add_mfem_examples(AMGX_EXAMPLES_SRCS ${PFX} copy_amgx_json_files test_amgx)
# which builds the examples and runs:
# ctest -R amgx
# Command line options for the tests.
# Example 1/1p:
set(EX1_TEST_OPTS)
set(EX1P_TEST_OPTS)
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 1/1p:
set(EX1_TEST_OPTS)
set(EX1P_TEST_OPTS)
# Add the tests: one test per source file.
foreach(SRC_FILE ${AMGX_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${AMGX_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+17 -17
View File
@@ -30,22 +30,22 @@ set(PREFIX caliper_)
add_mfem_examples(CALIPER_EXE_SRCS ${PREFIX})
# Add a test for each example
foreach(SRC_FILE ${CALIPER_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
set(THIS_TEST_OPTIONS "-no-vis")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (MFEM_ENABLE_TESTING)
foreach(SRC_FILE ${CALIPER_EXE_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
set(THIS_TEST_OPTIONS "-no-vis")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+266
View File
@@ -0,0 +1,266 @@
// MFEM Example 1
//
// Compile with: make ex1
//
// Sample runs: ex1 -m ../data/square-disc.mesh
// ex1 -m ../data/star.mesh
// ex1 -m ../data/escher.mesh
// ex1 -m ../data/fichera.mesh
// ex1 -m ../data/square-disc-p2.vtk -o 2
// ex1 -m ../data/square-disc-p3.mesh -o 3
// ex1 -m ../data/square-disc-nurbs.mesh -o -1
// ex1 -m ../data/disc-nurbs.mesh -o -1
// ex1 -m ../data/pipe-nurbs.mesh -o -1
// ex1 -m ../data/star-surf.mesh
// ex1 -m ../data/square-disc-surf.mesh
// ex1 -m ../data/inline-segment.mesh
// ex1 -m ../data/amr-quad.mesh
// ex1 -m ../data/amr-hex.mesh
// ex1 -m ../data/fichera-amr.mesh
// ex1 -m ../data/mobius-strip.mesh
// ex1 -m ../data/mobius-strip.mesh -o -1 -sc
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int rs = -1;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 50,000
// elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
cout << "Calling RandomRefinement " << ra << " times." << endl;
for (int l = 0; l < ra; l++)
{
mesh->RandomRefinement(0.2);
}
cout << "Done with refinement" << endl;
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
if ( mesh->ncmesh )
{
mesh->ncmesh->PrintStats(cout);
ofstream ofsV("vp.out");
ofstream ofsE("ce.out");
mesh->ncmesh->PrintVertexParents(ofsV);
mesh->ncmesh->PrintCoarseElements(ofsE);
}
// 4. Define a finite element space on the mesh. Here we use continuous
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
cout << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
LinearForm *b = new LinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 7. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
GridFunction x(fespace);
x = 0.0;
// 8. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 9. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A.Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 10. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
PCG(A, M, B, X, 1, 200, 1e-12, 0.0);
#else
// 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
#endif
// 11. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 12. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
// 13. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 14. Free the used memory.
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete mesh;
return 0;
}
+388
View File
@@ -0,0 +1,388 @@
// MFEM Example 1 - Parallel Version
//
// Compile with: make ex1p
//
// Sample runs: mpirun -np 4 ex1p -m ../data/square-disc.mesh
// mpirun -np 4 ex1p -m ../data/star.mesh
// mpirun -np 4 ex1p -m ../data/escher.mesh
// mpirun -np 4 ex1p -m ../data/fichera.mesh
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3
// mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/pipe-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/ball-nurbs.mesh -o 2
// mpirun -np 4 ex1p -m ../data/star-surf.mesh
// mpirun -np 4 ex1p -m ../data/square-disc-surf.mesh
// mpirun -np 4 ex1p -m ../data/inline-segment.mesh
// mpirun -np 4 ex1p -m ../data/amr-quad.mesh
// mpirun -np 4 ex1p -m ../data/amr-hex.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh -o -1 -sc
//
// The following are examples of using EntitySets to define
// homogeneous Dirichlet boundary condition. These examples
// require a modified mesh file and a specialized version of
// example 1 called "ex1p_es".
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 0 -bs Origin
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 1 -bs Axes
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 1 -bs "Negative Axes"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 2 -bs "Interior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 2 -bs "Exterior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 3 -bs "Interior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 3 -bs "Exterior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 3 -bs "Steps"
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 10,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
cout << "creating ParMesh from serial mesh" << endl;
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
cout << "done creating ParMesh from serial mesh" << endl;
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
/*
We now have a ParEntitySets object which marshals the data stored
in EntitySets objects. The data has now been pruned so that each
rank only contains indices of local entities.
The NCEntitySets object remains unchanged...
If we have an NC mesh a different path is taken and the
EntitySets are ignored.
1) ParNCMesh is created from NCMesh
a) Creates a ParNCEntitySets object from ncmesh (every rank contains
information to find every entity)
2) ParNCMesh is pruned which involves renumbering elements and vertices
3) ParMesh is initialized from ParNCMesh
4) ParNCMesh::OnMeshUpdated is called
5) Mesh::GenerateNCFaceInfo is called
*/
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
/*
RandomRefinement will end up calling
ParMesh::NonconformingRefinement which will create a new ParMesh
object using the ParNCMesh object and then call
ParMesh::OnMeshUpdated on this new mesh.
*/
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (pmesh->GetNodes())
{
fec = pmesh->GetNodes()->OwnFEC();
if (myid == 0)
{
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
for (int i=0; i<num_procs; i++)
{
if (myid == i)
{
cout << "Number of Dirichlet dofs on proc " << i << ": "
<< ess_tdof_list.Size() << endl;
}
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (1,phi_i) where phi_i are the basis functions in fespace.
ParLinearForm *b = new ParLinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(fespace);
x = 0.0;
// 10. Set up the parallel bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
// 12. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
HypreSolver *amg = new HypreBoomerAMG(A);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(200);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*amg);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// 14. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 15. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 16. Free the used memory.
delete pcg;
delete amg;
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete pmesh;
MPI_Finalize();
return 0;
}
+195
View File
@@ -0,0 +1,195 @@
// MFEM Example 30
//
// Compile with: make ex30
//
// Sample runs: ex30 -m ../data/square-disc.mesh -o 1
// ex30 -m ../data/square-disc.mesh -o 2
// ex30 -m ../data/square-disc.mesh -o 2 -me 1e3
// ex30 -m ../data/square-disc-nurbs.mesh -o 2
// ex30 -m ../data/star.mesh -o 2 -eo 4
// ex30 -m ../data/fichera.mesh -o 2 -me 1e4
// ex30 -m ../data/disc-nurbs.mesh -o 2
// ex30 -m ../data/ball-nurbs.mesh -o 2 -eo 3 -e 1e-2 -me 1e4
// ex30 -m ../data/star-surf.mesh -o 2
// ex30 -m ../data/square-disc-surf.mesh -o 2
// ex30 -m ../data/amr-quad.mesh -l 2
//
// Description: This is an example of adaptive mesh refinement preprocessing
// which lowers the data oscillation [1] to a user-defined
// relative threshold. There is no PDE being solved.
//
// MFEM's capability to work with both conforming and
// nonconforming meshes is demonstrated in example 6. In some
// problems, the material data or loading data is not sufficiently
// resolved on the initial mesh. This missing fine scale data
// reduces the accuracy of the solution as well as the accuracy
// of some local error estimators. By preprocessing the mesh
// before solving the PDE, many issues can be avoided.
//
// [1] Morin, P., Nochetto, R. H., & Siebert, K. G. (2000).
// Data oscillation and convergence of adaptive FEM. SIAM
// Journal on Numerical Analysis, 38(2), 466-488.
//
// [2] Mitchell, W. F. (2013). A collection of 2D elliptic
// problems for testing adaptive grid refinement algorithms.
// Applied mathematics and computation, 220, 350-364.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Piecewise-affine function which is sometimes mesh-conforming
double affine_function(const Vector &p)
{
double x = p(0), y = p(1);
if (x < 0.0)
{
return 1.0 + x + y;
}
else
{
return 1.0;
}
}
// Piecewise-constant function which is never mesh-conforming
double jump_function(const Vector &p)
{
if (p.Normlp(2.0) > 0.4 && p.Normlp(2.0) < 0.6) { return 1.0; }
return 5.0;
}
// Singular function derived from the Laplacian of the "steep wavefront"
// problem in [2].
double singular_function(const Vector &p)
{
double x = p(0), y = p(1);
double alpha = 1000.0;
double xc = 0.75, yc = 0.5;
double r0 = 0.7;
double r = sqrt(pow(x - xc,2.0) + pow(y - yc,2.0));
double num = - ( alpha - pow(alpha,3) * (pow(r,2) - pow(r0,2)) );
double denom = pow(r * ( pow(alpha,2) * pow(r0,2) + pow(alpha,2) * pow(r,2) \
- 2 * pow(alpha,2) * r0 * r + 1.0 ),2);
denom = max(denom,1e-8);
return num / denom;
}
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
int nc_limit = 1;
int max_elems = 1e5;
double double_max_elems = double(max_elems);
bool visualization = true;
double osc_threshold = 1e-3;
int enriched_order = 5;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&nc_limit, "-l", "--nc-limit",
"Maximum level of hanging nodes.");
args.AddOption(&double_max_elems, "-me", "--max-elems",
"Stop after reaching this many elements.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&osc_threshold, "-e", "--error",
"relative data oscillation threshold.");
args.AddOption(&enriched_order, "-eo", "--enriched_order",
"Enriched quadrature order.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
max_elems = int(double_max_elems);
Mesh mesh(mesh_file, 1, 1);
// 2. Since a NURBS mesh can currently only be refined uniformly, we need to
// convert it to a piecewise-polynomial curved mesh. First we refine the
// NURBS mesh a bit more and then project the curvature to quadratic Nodes.
if (mesh.NURBSext)
{
for (int i = 0; i < 2; i++)
{
mesh.UniformRefinement();
}
mesh.SetCurvature(2);
}
// 3. Define functions and refiner.
FunctionCoefficient affine_coeff(affine_function);
FunctionCoefficient jump_coeff(jump_function);
FunctionCoefficient singular_coeff(singular_function);
CoefficientRefiner coeffrefiner(affine_coeff, order);
// 4. Connect to GLVis.
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock;
if (visualization)
{
sol_sock.open(vishost, visport);
}
// 5. Define custom integration rule (optional).
const IntegrationRule *irs[Geometry::NumGeom];
int order_quad = 2*order + enriched_order;
for (int i = 0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
// 6. Apply custom refiner settings.
coeffrefiner.SetIntRule(irs);
coeffrefiner.SetMaxElements(max_elems);
coeffrefiner.SetThreshold(osc_threshold);
coeffrefiner.SetNCLimit(nc_limit);
coeffrefiner.PrintWarnings();
// 7. Preprocess mesh to control osc (piecewise-affine function).
// This is mostly just a verification check. The oscillation should
// be zero if the function is mesh-conforming and order > 0.
coeffrefiner.PreprocessMesh(mesh);
mfem::out << "\n";
mfem::out << "Function 0 (affine) \n";
mfem::out << "Number of Elements " << mesh.GetNE() << "\n";
mfem::out << "Osc error " << coeffrefiner.GetOsc() << "\n";
// 8. Preprocess mesh to control osc (jump function).
coeffrefiner.ResetCoefficient(jump_coeff);
coeffrefiner.PreprocessMesh(mesh);
mfem::out << "\n";
mfem::out << "Function 1 (discontinuous) \n";
mfem::out << "Number of Elements " << mesh.GetNE() << "\n";
mfem::out << "Osc error " << coeffrefiner.GetOsc() << "\n";
// 9. Preprocess mesh to control osc (singular function).
coeffrefiner.ResetCoefficient(singular_coeff);
coeffrefiner.PreprocessMesh(mesh);
mfem::out << "\n";
mfem::out << "Function 2 (singular) \n";
mfem::out << "Number of Elements " << mesh.GetNE() << "\n";
mfem::out << "Osc error " << coeffrefiner.GetOsc() << "\n";
sol_sock.precision(8);
sol_sock << "mesh\n" << mesh << flush;
return 0;
}
+241
View File
@@ -0,0 +1,241 @@
// MFEM Example 30 - Parallel Version
//
// Compile with: make ex30p
//
// Sample runs: mpirun -np 4 ex30p -m ../data/square-disc.mesh -o 1
// mpirun -np 4 ex30p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex30p -m ../data/square-disc.mesh -o 2 -me 1e3
// mpirun -np 4 ex30p -m ../data/square-disc-nurbs.mesh -o 2
// mpirun -np 4 ex30p -m ../data/star.mesh -o 2 -eo 4
// mpirun -np 4 oscp -m ../data/fichera.mesh -o 2 -me 1e4
// mpirun -np 4 ex30p -m ../data/disc-nurbs.mesh -o 2
// mpirun -np 4 ex30p -m ../data/ball-nurbs.mesh -o 2 -eo 3 -e 1e-2
// mpirun -np 4 ex30p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex30p -m ../data/square-disc-surf.mesh -o 2
// mpirun -np 4 ex30p -m ../data/amr-quad.mesh -l 2
//
// Description: This is an example of adaptive mesh refinement preprocessing
// which lowers the data oscillation [1] to a user-defined
// relative threshold. There is no PDE being solved.
//
// MFEM's capability to work with both conforming and
// nonconforming meshes is demonstrated in example 6. In some
// problems, the material data or loading data is not sufficiently
// resolved on the initial mesh. This missing fine scale data
// reduces the accuracy of the solution as well as the accuracy
// of some local error estimators. By preprocessing the mesh
// before solving the PDE, many issues can be avoided.
//
// [1] Morin, P., Nochetto, R. H., & Siebert, K. G. (2000).
// Data oscillation and convergence of adaptive FEM. SIAM
// Journal on Numerical Analysis, 38(2), 466-488.
//
// [2] Mitchell, W. F. (2013). A collection of 2D elliptic
// problems for testing adaptive grid refinement algorithms.
// Applied mathematics and computation, 220, 350-364.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Piecewise-affine function which is sometimes mesh-conforming
double affine_function(const Vector &p)
{
double x = p(0), y = p(1);
if (x < 0.0)
{
return 1.0 + x + y;
}
else
{
return 1.0;
}
}
// Piecewise-constant function which is never mesh-conforming
double jump_function(const Vector &p)
{
if (p.Normlp(2.0) > 0.4 && p.Normlp(2.0) < 0.6) { return 1.0; }
return 5.0;
}
// Singular function derived from the Laplacian of the "steep wavefront"
// problem in [2].
double singular_function(const Vector &p)
{
double x = p(0), y = p(1);
double alpha = 1000.0;
double xc = 0.75, yc = 0.5;
double r0 = 0.7;
double r = sqrt(pow(x - xc,2.0) + pow(y - yc,2.0));
double num = - ( alpha - pow(alpha,3) * (pow(r,2) - pow(r0,2)) );
double denom = pow(r * ( pow(alpha,2) * pow(r0,2) + pow(alpha,2) * pow(r,2) \
- 2 * pow(alpha,2) * r0 * r + 1.0 ),2);
denom = max(denom,1e-8);
return num / denom;
}
int main(int argc, char *argv[])
{
// 0. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
int nc_limit = 1;
int max_elems = 1e5;
double double_max_elems = double(max_elems);
bool visualization = true;
bool nc_simplices = true;
double osc_threshold = 1e-3;
int enriched_order = 5;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&nc_limit, "-l", "--nc-limit",
"Maximum level of hanging nodes.");
args.AddOption(&double_max_elems, "-me", "--max-elems",
"Stop after reaching this many elements.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&osc_threshold, "-e", "--error",
"relative data oscillation threshold.");
args.AddOption(&enriched_order, "-eo", "--enriched_order",
"Enriched quadrature order.");
args.AddOption(&nc_simplices, "-ns", "--nonconforming-simplices",
"-cs", "--conforming-simplices",
"For simplicial meshes, enable/disable nonconforming"
" refinement");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
max_elems = int(double_max_elems);
Mesh mesh(mesh_file, 1, 1);
// 2. Since a NURBS mesh can currently only be refined uniformly, we need to
// convert it to a piecewise-polynomial curved mesh. First we refine the
// NURBS mesh a bit more and then project the curvature to quadratic Nodes.
if (mesh.NURBSext)
{
for (int i = 0; i < 2; i++)
{
mesh.UniformRefinement();
}
mesh.SetCurvature(2);
}
// 3. Make sure the mesh is in the non-conforming mode to enable local
// refinement of quadrilaterals/hexahedra. Simplices can be refined
// either in conforming or in non-conforming mode. The conforming
// mode however does not support dynamic partitioning.
mesh.EnsureNCMesh(nc_simplices);
// 4. Define a parallel mesh by partitioning the serial mesh.
// Once the parallel mesh is defined, the serial mesh can be deleted.
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
// 5. Define functions and refiner.
FunctionCoefficient affine_coeff(affine_function);
FunctionCoefficient jump_coeff(jump_function);
FunctionCoefficient singular_coeff(singular_function);
CoefficientRefiner coeffrefiner(affine_coeff,order);
// 6. Connect to GLVis.
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock;
if (visualization)
{
sol_sock.open(vishost, visport);
}
// 7. Define custom integration rule (optional).
const IntegrationRule *irs[Geometry::NumGeom];
int order_quad = 2*order + enriched_order;
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
// 8. Apply custom refiner settings.
coeffrefiner.SetIntRule(irs);
coeffrefiner.SetMaxElements(max_elems);
coeffrefiner.SetThreshold(osc_threshold);
coeffrefiner.SetNCLimit(nc_limit);
coeffrefiner.PrintWarnings();
// 9. Preprocess mesh to control osc (piecewise-affine function).
// This is mostly just a verification check. The oscillation should
// be zero if the function is mesh-conforming and order > 0.
coeffrefiner.PreprocessMesh(pmesh);
int globalNE = pmesh.GetGlobalNE();
double osc = coeffrefiner.GetOsc();
if (myid == 0)
{
mfem::out << "\n";
mfem::out << "Function 0 (affine) \n";
mfem::out << "Number of Elements " << globalNE << "\n";
mfem::out << "Osc error " << osc << "\n";
}
// 10. Preprocess mesh to control osc (jump function).
coeffrefiner.ResetCoefficient(jump_coeff);
coeffrefiner.PreprocessMesh(pmesh);
globalNE = pmesh.GetGlobalNE();
osc = coeffrefiner.GetOsc();
if (myid == 0)
{
mfem::out << "\n";
mfem::out << "Function 1 (discontinuous) \n";
mfem::out << "Number of Elements " << globalNE << "\n";
mfem::out << "Osc error " << osc << "\n";
}
// 11. Preprocess mesh to control osc (singular function).
coeffrefiner.ResetCoefficient(singular_coeff);
coeffrefiner.PreprocessMesh(pmesh);
globalNE = pmesh.GetGlobalNE();
osc = coeffrefiner.GetOsc();
if (myid == 0)
{
mfem::out << "\n";
mfem::out << "Function 2 (singular) \n";
mfem::out << "Number of Elements " << globalNE << "\n";
mfem::out << "Osc error " << osc << "\n";
}
sol_sock.precision(8);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock << "mesh\n" << pmesh << flush;
MPI_Finalize();
return 0;
}
+411
View File
@@ -0,0 +1,411 @@
// MFEM Example 3 - Parallel Version
//
// Compile with: make ex3p
//
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
// mpirun -np 4 ex3p -m ../data/escher.mesh
// mpirun -np 4 ex3p -m ../data/fichera.mesh
// mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
// mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
// mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
//
// Description: This example code solves a simple electromagnetic diffusion
// problem corresponding to the second order definite Maxwell
// equation curl curl E + E = f with boundary condition
// E x n = <given tangential field>. Here, we use a given exact
// solution E and compute the corresponding r.h.s. f.
// We discretize with Nedelec finite elements in 2D or 3D.
//
// The example demonstrates the use of H(curl) finite element
// spaces with the curl-curl and the (vector finite element) mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Static condensation is
// also illustrated.
//
// We recommend viewing examples 1-2 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Exact solution, E, and r.h.s., f. See below for implementation.
//void E_exact(const Vector &, Vector &);
//void f_exact(const Vector &, Vector &);
//double freq = 1.0, kappa;
void f_const(const Vector &, Vector &);
int dim;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../data/beam-tet.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
/*
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
" solution.");
*/
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// kappa = freq * M_PI;
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
pmesh->ReorientTetMesh();
pmesh->ent_sets->PrintSetInfo(cout);
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
if (myid == 0)
{
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
VectorFunctionCoefficient f(sdim, f_const);
ParLinearForm *b = new ParLinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
// VectorFunctionCoefficient E(sdim, E_exact);
// x.ProjectCoefficient(E);
x = 0.0;
// 10. Set up the parallel bilinear form corresponding to the EM diffusion
// operator curl muinv curl + sigma I, by adding the curl-curl and the
// mass domain integrators.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
// 12. Define and apply a parallel PCG solver for AX=B with the AMS
// preconditioner from hypre.
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
HypreSolver *ams = new HypreAMS(A, prec_fespace);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*ams);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
/*
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(E);
if (myid == 0)
{
cout << "\n|| E_h - E ||_{L^2} = " << err << '\n' << endl;
}
}
*/
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
delete pcg;
delete ams;
delete a;
delete sigma;
delete muinv;
delete b;
delete fespace;
delete fec;
delete pmesh;
MPI_Finalize();
return 0;
}
/*
void E_exact(const Vector &x, Vector &E)
{
if (dim == 3)
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(2));
E(2) = sin(kappa * x(0));
}
else
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(0));
if (x.Size() == 3) { E(2) = 0.0; }
}
}
void f_exact(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
}
else
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
if (x.Size() == 3) { f(2) = 0.0; }
}
}
*/
void f_const(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = 1.0;
f(1) = 1.0;
f(2) = 1.0;
}
else
{
f(0) = 1.0;
f(1) = 1.0;
if (x.Size() == 3) { f(2) = 0.0; }
}
}
+438
View File
@@ -0,0 +1,438 @@
// MFEM Example 4 - Parallel Version
//
// Compile with: make ex4p
//
// Sample runs: mpirun -np 4 ex4p -m ../data/square-disc.mesh
// mpirun -np 4 ex4p -m ../data/star.mesh
// mpirun -np 4 ex4p -m ../data/beam-tet.mesh
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh
// mpirun -np 4 ex4p -m ../data/escher.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/fichera.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/fichera-q2.vtk
// mpirun -np 4 ex4p -m ../data/fichera-q3.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/square-disc-nurbs.mesh -o 3
// mpirun -np 4 ex4p -m ../data/beam-hex-nurbs.mesh -o 3
// mpirun -np 4 ex4p -m ../data/periodic-square.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/periodic-cube.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/amr-quad.mesh
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
//
// Description: This example code solves a simple 2D/3D H(div) diffusion
// problem corresponding to the second order definite equation
// -grad(alpha div F) + beta F = f with boundary condition F dot n
// = <given normal field>. Here, we use a given exact solution F
// and compute the corresponding r.h.s. f. We discretize with
// Raviart-Thomas finite elements.
//
// The example demonstrates the use of H(div) finite element
// spaces with the grad-div and H(div) vector finite element mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Bilinear form
// hybridization and static condensation are also illustrated.
//
// We recommend viewing examples 1-3 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Exact solution, F, and r.h.s., f. See below for implementation.
//void F_exact(const Vector &, Vector &);
//void f_exact(const Vector &, Vector &);
//double freq = 1.0, kappa;
void f_const(const Vector &, Vector &);
int dim;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool set_bc = true;
bool static_cond = false;
bool hybridization = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
"Impose or not essential boundary conditions.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
// args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
// " solution.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
"--no-hybridization", "Enable hybridization.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// kappa = freq * M_PI;
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume, as well as periodic meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them (this is needed in the ADS solver below).
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
}
pmesh->ReorientTetMesh();
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *fec = new RT_FECollection(order-1, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = set_bc ? 1 : 0;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
if (myid == 0)
{
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
VectorFunctionCoefficient f(sdim, f_const);
ParLinearForm *b = new ParLinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary faces will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
// VectorFunctionCoefficient F(sdim, F_exact);
// x.ProjectCoefficient(F);
x = 0.0;
// 10. Set up the parallel bilinear form corresponding to the H(div)
// diffusion operator grad alpha div + beta I, by adding the div-div and
// the mass domain integrators.
Coefficient *alpha = new ConstantCoefficient(1.0);
Coefficient *beta = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation,
// hybridization, etc.
FiniteElementCollection *hfec = NULL;
ParFiniteElementSpace *hfes = NULL;
if (static_cond)
{
a->EnableStaticCondensation();
}
else if (hybridization)
{
hfec = new DG_Interface_FECollection(order-1, dim);
hfes = new ParFiniteElementSpace(pmesh, hfec);
a->EnableHybridization(hfes, new NormalTraceJumpIntegrator(),
ess_tdof_list);
}
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
HYPRE_Int glob_size = A.GetGlobalNumRows();
if (myid == 0)
{
cout << "Size of linear system: " << glob_size << endl;
}
// 12. Define and apply a parallel PCG solver for A X = B with the 2D AMS or
// the 3D ADS preconditioners from hypre. If using hybridization, the
// system is preconditioned with hypre's BoomerAMG.
HypreSolver *prec = NULL;
CGSolver *pcg = new CGSolver(A.GetComm());
pcg->SetOperator(A);
pcg->SetRelTol(1e-12);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(1);
if (hybridization) { prec = new HypreBoomerAMG(A); }
else
{
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
if (dim == 2) { prec = new HypreAMS(A, prec_fespace); }
else { prec = new HypreADS(A, prec_fespace); }
}
pcg->SetPreconditioner(*prec);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
/*
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(F);
if (myid == 0)
{
cout << "\n|| F_h - F ||_{L^2} = " << err << '\n' << endl;
}
}
*/
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
delete pcg;
delete prec;
delete hfes;
delete hfec;
delete a;
delete alpha;
delete beta;
delete b;
delete fespace;
delete fec;
delete pmesh;
MPI_Finalize();
return 0;
}
/*
// The exact solution (for non-surface meshes)
void F_exact(const Vector &p, Vector &F)
{
int dim = p.Size();
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
if (dim == 3)
{
F(2) = 0.0;
}
}
// The right hand side
void f_exact(const Vector &p, Vector &f)
{
int dim = p.Size();
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
double temp = 1 + 2*kappa*kappa;
f(0) = temp*cos(kappa*x)*sin(kappa*y);
f(1) = temp*cos(kappa*y)*sin(kappa*x);
if (dim == 3)
{
f(2) = 0;
}
}
*/
void f_const(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = 1.0;
f(1) = 1.0;
f(2) = 1.0;
}
else
{
f(0) = 1.0;
f(1) = 1.0;
if (x.Size() == 3) { f(2) = 0.0; }
}
}
+325
View File
@@ -0,0 +1,325 @@
// MFEM Example 6 - Parallel Version
//
// Compile with: make ex6p
//
// Sample runs: mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 1
// mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex6p -m ../data/square-disc-nurbs.mesh -o 2
// mpirun -np 4 ex6p -m ../data/star.mesh -o 3
// mpirun -np 4 ex6p -m ../data/escher.mesh -o 2
// mpirun -np 4 ex6p -m ../data/fichera.mesh -o 2
// mpirun -np 4 ex6p -m ../data/disc-nurbs.mesh -o 2
// mpirun -np 4 ex6p -m ../data/ball-nurbs.mesh
// mpirun -np 4 ex6p -m ../data/pipe-nurbs.mesh
// mpirun -np 4 ex6p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex6p -m ../data/square-disc-surf.mesh -o 2
// mpirun -np 4 ex6p -m ../data/amr-quad.mesh
//
// Description: This is a version of Example 1 with a simple adaptive mesh
// refinement loop. The problem being solved is again the Laplace
// equation -Delta u = 1 with homogeneous Dirichlet boundary
// conditions. The problem is solved on a sequence of meshes which
// are locally refined in a conforming (triangles, tetrahedrons)
// or non-conforming (quadrilaterals, hexahedra) manner according
// to a simple ZZ error estimator.
//
// The example demonstrates MFEM's capability to work with both
// conforming and nonconforming refinements, in 2D and 3D, on
// linear, curved and surface meshes. Interpolation of functions
// from coarse to fine meshes, as well as persistent GLVis
// visualization are also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
static int max_dofs = 100000;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int bt = EntitySets::INVALID;
const char *bs = "";
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&max_dofs, "-md", "--max-dofs",
"Maximum number of degrees of freedom.");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution.
// Also project a NURBS mesh to a piecewise-quadratic curved mesh. Make
// sure that the mesh is non-conforming.
if (mesh->NURBSext)
{
mesh->UniformRefinement();
mesh->SetCurvature(2);
}
mesh->EnsureNCMesh();
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
// 5. Define a parallel mesh by partitioning the serial mesh.
// Once the parallel mesh is defined, the serial mesh can be deleted.
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh.pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh.pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
// 6. Define a finite element space on the mesh. The polynomial order is
// one (linear) by default, but this can be changed on the command line.
H1_FECollection fec(order, dim);
ParFiniteElementSpace fespace(&pmesh, &fec);
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace.GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
// 7. As in Example 1p, we set up bilinear and linear forms corresponding to
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
// problem yet, this will be done in the main loop.
ParBilinearForm a(&fespace);
ParLinearForm b(&fespace);
ConstantCoefficient one(1.0);
BilinearFormIntegrator *integ = new DiffusionIntegrator(one);
a.AddDomainIntegrator(integ);
b.AddDomainIntegrator(new DomainLFIntegrator(one));
// 8. The solution vector x and the associated finite element grid function
// will be maintained over the AMR iterations. We initialize it to zero.
ParGridFunction x(&fespace);
x = 0;
// 9. Connect to GLVis.
char vishost[] = "localhost";
int visport = 19916;
socketstream sout;
if (visualization)
{
sout.open(vishost, visport);
if (!sout)
{
if (myid == 0)
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
cout << "GLVis visualization disabled.\n";
}
visualization = false;
}
sout.precision(8);
}
// 10. Set up an error estimator. Here we use the Zienkiewicz-Zhu estimator
// with L2 projection in the smoothing step to better handle hanging
// nodes and parallel partitioning. We need to supply a space for the
// discontinuous flux (L2) and a space for the smoothed flux (H(div) is
// used here).
L2_FECollection flux_fec(order, dim);
ParFiniteElementSpace flux_fes(&pmesh, &flux_fec, sdim);
RT_FECollection smooth_flux_fec(order-1, dim);
ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec);
// Another possible option for the smoothed flux space:
// H1_FECollection smooth_flux_fec(order, dim);
// ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec, dim);
L2ZienkiewiczZhuEstimator estimator(*integ, x, flux_fes, smooth_flux_fes);
// 11. A refiner selects and refines elements based on a refinement strategy.
// The strategy here is to refine elements with errors larger than a
// fraction of the maximum element error. Other strategies are possible.
// The refiner will call the given error estimator.
ThresholdRefiner refiner(estimator);
refiner.SetTotalErrorFraction(0.7);
// 12. The main AMR loop. In each iteration we solve the problem on the
// current mesh, visualize the solution, and refine the mesh.
// const int max_dofs = 100000;
for (int it = 0; ; it++)
{
HYPRE_Int global_dofs = fespace.GlobalTrueVSize();
if (myid == 0)
{
cout << "\nAMR iteration " << it << endl;
cout << "Number of unknowns: " << global_dofs << endl;
}
// 13. Assemble the stiffness matrix and the right-hand side. Note that
// MFEM doesn't care at this point that the mesh is nonconforming
// and parallel. The FE space is considered 'cut' along hanging
// edges/faces, and also across processor boundaries.
a.Assemble();
b.Assemble();
// 14. Create the parallel linear system: eliminate boundary conditions,
// constrain hanging nodes and nodes across processor boundaries.
// The system will be solved for true (unconstrained/unique) DOFs only.
// Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace.GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
HypreParMatrix A;
Vector B, X;
const int copy_interior = 1;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
// 15. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
HypreBoomerAMG amg;
amg.SetPrintLevel(0);
CGSolver pcg(A.GetComm());
pcg.SetPreconditioner(amg);
pcg.SetOperator(A);
pcg.SetRelTol(1e-6);
pcg.SetMaxIter(200);
pcg.SetPrintLevel(3); // print the first and the last iterations only
pcg.Mult(B, X);
// 16. Extract the parallel grid function corresponding to the finite element
// approximation X. This is the local solution on each processor.
a.RecoverFEMSolution(X, b, x);
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
sout << "parallel " << num_procs << " " << myid << "\n";
sout << "solution\n" << pmesh << x << flush;
}
if (global_dofs > max_dofs)
{
if (myid == 0)
{
cout << "Reached the maximum number of dofs. Stop." << endl;
}
break;
}
// 18. Call the refiner to modify the mesh. The refiner calls the error
// estimator to obtain element errors, then it selects elements to be
// refined and finally it modifies the mesh. The Stop() method can be
// used to determine if a stopping criterion was met.
refiner.Apply(pmesh);
if (refiner.Stop())
{
if (myid == 0)
{
cout << "Stopping criterion satisfied. Stop." << endl;
}
break;
}
// 19. Update the finite element space (recalculate the number of DOFs,
// etc.) and create a grid function update matrix. Apply the matrix
// to any GridFunctions over the space. In this case, the update
// matrix is an interpolation matrix so the updated GridFunction will
// still represent the same function as before refinement.
fespace.Update();
x.Update();
// 20. Load balance the mesh, and update the space and solution. Currently
// available only for nonconforming meshes.
if (pmesh.Nonconforming())
{
pmesh.Rebalance();
// Update the space and the GridFunction. This time the update matrix
// redistributes the GridFunction among the processors.
fespace.Update();
x.Update();
}
// 21. Inform also the bilinear and linear forms that the space has
// changed.
a.Update();
b.Update();
}
MPI_Finalize();
return 0;
}
+162
View File
@@ -0,0 +1,162 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
3
elements
14
1 4 13 15 21 25
1 4 12 13 15 21
1 4 13 21 22 25
1 4 15 24 21 25
1 4 13 15 25 16
1 5 0 1 4 3 9 10 13 12
1 5 8 9 12 11 17 18 21 20
1 5 2 3 6 5 11 12 15 14
1 6 3 4 6 12 13 15
1 6 4 7 6 13 16 15
1 6 12 13 21 9 10 18
1 6 13 22 21 10 19 18
1 6 11 14 20 12 15 21
1 6 15 21 24 14 20 23
boundary
30
1 3 5 6 3 2
2 2 3 6 4
2 2 4 6 7
3 3 3 4 1 0
4 3 11 12 9 8
5 3 2 3 12 11
6 3 0 1 10 9
7 2 9 10 18
7 2 10 19 18
8 3 8 9 18 17
9 3 1 4 13 10
10 3 4 7 16 13
11 2 13 16 25
11 2 13 25 22
12 3 10 13 22 19
13 3 7 6 15 16
14 3 6 5 14 15
15 3 15 14 23 24
16 2 16 15 25
16 2 15 24 25
17 3 5 2 11 14
18 3 3 0 9 12
19 3 11 8 17 20
20 2 11 20 14
20 2 14 20 23
21 3 17 18 21 20
22 3 18 19 22 21
23 2 21 22 25
23 2 21 25 24
24 3 20 21 24 23
vertices
26
3
0 -1 -1
1 -1 -1
-1 0 -1
0 0 -1
1 0 -1
-1 1 -1
0 1 -1
1 1 -1
-1 -1 0
0 -1 0
1 -1 0
-1 0 0
0 0 0
1 0 0
-1 1 0
0 1 0
1 1 0
-1 -1 1
0 -1 1
1 -1 1
-1 0 1
0 0 1
1 0 1
-1 1 1
0 1 1
1 1 1
MFEM sets v1.0
vertex_sets
1
Origin
1
12
edge_sets
2
Axes
3
12 13
12 15
12 21
Negative Axes
3
12 9
12 11
12 3
face_sets
2
Interior Corner
3
3 11 12 9 8
3 2 3 12 11
3 3 0 9 12
Exterior Corner
15
2 13 16 25
2 13 25 22
2 16 15 25
2 15 24 25
2 21 22 25
2 21 25 24
3 10 13 22 19
3 4 7 16 13
3 1 4 13 10
3 7 6 15 16
3 6 5 14 15
3 15 14 23 24
3 20 21 24 23
3 18 19 22 21
3 17 18 21 20
element_sets
3
Interior Corner
3
5 6 7
Exterior Corner
5
0 1 2 3 4
Steps
3
6 8 9
+145
View File
@@ -0,0 +1,145 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
3
elements
7
1 5 0 1 4 3 9 10 13 12
1 5 3 4 7 6 12 13 16 15
1 5 2 3 6 5 11 12 15 14
1 5 8 9 12 11 17 18 21 20
1 5 9 10 13 12 18 19 22 21
1 5 12 13 16 15 21 22 25 24
1 5 11 12 15 14 20 21 24 23
boundary
24
1 3 5 6 3 2
2 3 6 7 4 3
3 3 3 4 1 0
4 3 11 12 9 8
5 3 2 3 12 11
6 3 0 1 10 9
7 3 9 10 19 18
8 3 8 9 18 17
9 3 1 4 13 10
10 3 4 7 16 13
11 3 13 16 25 22
12 3 10 13 22 19
13 3 7 6 15 16
14 3 6 5 14 15
15 3 15 14 23 24
16 3 16 15 24 25
17 3 5 2 11 14
18 3 3 0 9 12
19 3 11 8 17 20
20 3 14 11 20 23
21 3 17 18 21 20
22 3 18 19 22 21
23 3 21 22 25 24
24 3 20 21 24 23
vertices
26
3
0 -1 -1
1 -1 -1
-1 0 -1
0 0 -1
1 0 -1
-1 1 -1
0 1 -1
1 1 -1
-1 -1 0
0 -1 0
1 -1 0
-1 0 0
0 0 0
1 0 0
-1 1 0
0 1 0
1 1 0
-1 -1 1
0 -1 1
1 -1 1
-1 0 1
0 0 1
1 0 1
-1 1 1
0 1 1
1 1 1
MFEM sets v1.0
vertex_sets
1
Origin
1
12
edge_sets
2
Axes
3
12 13
12 15
12 21
Negative Axes
3
12 9
12 11
12 3
face_sets
2
Interior Corner
3
3 11 12 9 8
3 2 3 12 11
3 3 0 9 12
Exterior Corner
12
3 13 16 25 22
3 16 15 24 25
3 21 22 25 24
3 10 13 22 19
3 4 7 16 13
3 1 4 13 10
3 7 6 15 16
3 6 5 14 15
3 15 14 23 24
3 20 21 24 23
3 18 19 22 21
3 17 18 21 20
element_sets
3
Interior Corner
3
0 2 3
Exterior Corner
1
5
Steps
2
1 3
+25 -23
View File
@@ -31,29 +31,31 @@ add_mfem_examples(GINKGO_EXAMPLES_SRCS ${PFX} "" test_ginkgo)
# which builds the examples and runs:
# ctest -R ginkgo
# Command line options for the tests.
set(EX1_COMMON_OPTS ex1 -m ../data/star.mesh --use_gko_solver)
set(EX1_TEST_OPTS ${EX9_COMMON_OPTS})
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
set(EX1_COMMON_OPTS ex1 -m ../data/star.mesh --use_gko_solver)
set(EX1_TEST_OPTS ${EX9_COMMON_OPTS})
# Add the tests: one test per source file.
foreach(SRC_FILE ${GINKGO_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${GINKGO_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+27 -25
View File
@@ -33,31 +33,33 @@ add_mfem_examples(HIOP_EXAMPLES_SRCS ${PFX} "" test_hiop)
# which builds the examples and runs:
# ctest -R hiop
# Command line options for the tests.
# Example 9:
set(EX9_COMMON_OPTS -m ../../data/periodic-segment.mesh -p 0 -dt 0.005)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 )
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS})
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 9:
set(EX9_COMMON_OPTS -m ../../data/periodic-segment.mesh -p 0 -dt 0.005)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 )
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS})
# Add the tests: one test per source file.
foreach(SRC_FILE ${HIOP_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${HIOP_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+2 -2
View File
@@ -22,10 +22,10 @@ MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_EXAMPLES = ex0 ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 \
ex17 ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex28 ex29
ex17 ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex28 ex29 ex30
PAR_EXAMPLES = ex0p ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p \
ex12p ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p \
ex25p ex26p ex27p ex28p ex29p
ex25p ex26p ex27p ex28p ex29p ex30p
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p \
ex24p ex25p ex26p
+28 -26
View File
@@ -94,30 +94,32 @@ if (MFEM_USE_SLEPC)
endif()
# Add the tests: one test per command-line-variable.
set(TEST_OPTIONS_VARS
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
if (MFEM_USE_SLEPC)
list(APPEND TEST_OPTIONS_VARS EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
endif()
foreach(TEST_OPTIONS_VAR ${TEST_OPTIONS_VARS})
string(REGEX REPLACE "^(.+)_ARGS" "\\1" TEST_NAME_UC ${TEST_OPTIONS_VAR})
string(REGEX REPLACE "^([^_]+)" "\\1P" TEST_NAME_UC ${TEST_NAME_UC})
string(TOLOWER ${TEST_NAME_UC} TEST_NAME_FULL)
string(REGEX REPLACE "^([^_]+).*" "\\1" TEST_NAME ${TEST_NAME_FULL})
set(TEST_NAME_FULL ${PFX}${TEST_NAME_FULL})
set(TEST_NAME ${PFX}${TEST_NAME})
set(TEST_OPTIONS "-no-vis" ${${TEST_OPTIONS_VAR}})
# message(STATUS "${TEST_NAME_FULL} --> ${TEST_NAME} ${TEST_OPTIONS}")
# All PETSC tests are parallel.
if (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME_FULL}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
if (MFEM_ENABLE_TESTING)
set(TEST_OPTIONS_VARS
EX1_ARGS_W EX1_ARGS_P EX2_ARGS EX3_ARGS EX4_ARGS EX4_HYB_ARGS
EX5_BDDC_LB_ARGS EX5_BDDC_GB_ARGS EX5_FSPL_ARGS EX6_ARGS EX6_NONOVL_ARGS
EX9_E_ARGS EX9_ES_ARGS EX9_IS_ARGS EX10_ARGS)
if (MFEM_USE_SLEPC)
list(APPEND TEST_OPTIONS_VARS EX11_ARGS_SINV EX11_ARGS_LOBPCG EX11_ARGS_GD)
endif()
endforeach()
foreach(TEST_OPTIONS_VAR ${TEST_OPTIONS_VARS})
string(REGEX REPLACE "^(.+)_ARGS" "\\1" TEST_NAME_UC ${TEST_OPTIONS_VAR})
string(REGEX REPLACE "^([^_]+)" "\\1P" TEST_NAME_UC ${TEST_NAME_UC})
string(TOLOWER ${TEST_NAME_UC} TEST_NAME_FULL)
string(REGEX REPLACE "^([^_]+).*" "\\1" TEST_NAME ${TEST_NAME_FULL})
set(TEST_NAME_FULL ${PFX}${TEST_NAME_FULL})
set(TEST_NAME ${PFX}${TEST_NAME})
set(TEST_OPTIONS "-no-vis" ${${TEST_OPTIONS_VAR}})
# message(STATUS "${TEST_NAME_FULL} --> ${TEST_NAME} ${TEST_OPTIONS}")
# All PETSC tests are parallel.
if (MFEM_USE_MPI)
add_test(NAME ${TEST_NAME_FULL}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+32 -30
View File
@@ -37,37 +37,39 @@ add_mfem_examples(PUMI_EXAMPLES_SRCS ${PFX} "" test_pumi)
# which builds the examples and runs:
# ctest -R pumi
# Command line options for the tests.
# TODO...
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# TODO...
# Set the number of processors for the parallel examples. The value of
# MFEM_MPI_NP is ignored.
set(EX1_TEST_NP 1)
set(EX1P_TEST_NP 8)
set(EX2_TEST_NP 1)
set(EX6P_TEST_NP 8)
# Set the number of processors for the parallel examples. The value of
# MFEM_MPI_NP is ignored.
set(EX1_TEST_NP 1)
set(EX1P_TEST_NP 8)
set(EX2_TEST_NP 1)
set(EX6P_TEST_NP 8)
# Add the tests: one test per source file.
foreach(SRC_FILE ${PUMI_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${PUMI_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
# All PUMI examples require MPI
if (FALSE)
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
set(TEST_NP ${${UP_TEST_NAME}_TEST_NP})
add_test(NAME ${TEST_NAME}_np=${TEST_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${TEST_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
# All PUMI examples require MPI
if (FALSE)
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
set(TEST_NP ${${UP_TEST_NAME}_TEST_NP})
add_test(NAME ${TEST_NAME}_np=${TEST_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${TEST_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+158
View File
@@ -0,0 +1,158 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
2
elements
30
1 3 0 11 26 14
1 3 0 14 27 17
1 3 0 17 28 20
1 3 0 20 29 23
1 3 0 23 30 11
1 2 11 1 26
1 2 1 12 26
1 3 26 12 3 13
1 2 26 13 2
1 2 14 26 2
1 2 14 2 27
1 2 2 15 27
1 3 27 15 5 16
1 2 27 16 4
1 2 17 27 4
1 2 17 4 28
1 2 4 18 28
1 3 28 18 7 19
1 2 28 19 6
1 2 20 28 6
1 2 20 6 29
1 2 6 21 29
1 3 29 21 9 22
1 2 29 22 8
1 2 23 29 8
1 2 23 8 30
1 2 8 24 30
1 3 30 24 10 25
1 2 30 25 1
1 2 11 30 1
boundary
20
1 1 13 2
1 1 12 3
1 1 16 4
1 1 15 5
1 1 19 6
1 1 18 7
1 1 22 8
1 1 21 9
1 1 25 1
1 1 24 10
1 1 3 13
1 1 1 12
1 1 5 16
1 1 2 15
1 1 7 19
1 1 4 18
1 1 9 22
1 1 6 21
1 1 10 25
1 1 8 24
vertices
31
2
0 0
1 0
0.309017 0.951057
1.30902 0.951057
-0.809017 0.587785
-0.5 1.53884
-0.809017 -0.587785
-1.61803 0
0.309017 -0.951057
-0.5 -1.53884
1.30902 -0.951057
0.5 0
1.15451 0.475529
0.809019 0.951057
0.154508 0.475529
-0.0954915 1.24495
-0.654508 1.06331
-0.404508 0.293893
-1.21352 0.293893
-1.21352 -0.293892
-0.404508 -0.293893
-0.654508 -1.06331
-0.0954915 -1.24495
0.154508 -0.475529
0.809019 -0.951057
1.15451 -0.475529
0.654509 0.475529
-0.25 0.769421
-0.809016 0
-0.25 -0.76942
0.654509 -0.475529
MFEM sets v1.0
vertex_sets
3
Origin
1
0
Tent
5
1 2 4 6 8
Gazebo
5
3 5 7 9 10
edge_sets
2
Columbine
5
1 11
2 14
4 17
6 20
8 23
Lily
5
0 11
0 14
0 17
0 20
0 23
element_sets
3
Flying Squirrel
3
7 17 27
Sea Lion
4
12 17 22 27
Pinwheel
5
8 13 18 23 28
+143
View File
@@ -0,0 +1,143 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
2
elements
20
1 3 0 11 26 14
1 3 0 14 27 17
1 3 0 17 28 20
1 3 0 20 29 23
1 3 0 23 30 11
1 3 11 1 12 26
1 3 26 12 3 13
1 3 14 26 13 2
1 3 14 2 15 27
1 3 27 15 5 16
1 3 17 27 16 4
1 3 17 4 18 28
1 3 28 18 7 19
1 3 20 28 19 6
1 3 20 6 21 29
1 3 29 21 9 22
1 3 23 29 22 8
1 3 23 8 24 30
1 3 30 24 10 25
1 3 11 30 25 1
boundary
20
1 1 13 2
1 1 12 3
1 1 16 4
1 1 15 5
1 1 19 6
1 1 18 7
1 1 22 8
1 1 21 9
1 1 25 1
1 1 24 10
1 1 3 13
1 1 1 12
1 1 5 16
1 1 2 15
1 1 7 19
1 1 4 18
1 1 9 22
1 1 6 21
1 1 10 25
1 1 8 24
vertices
31
2
0 0
1 0
0.309017 0.951057
1.30902 0.951057
-0.809017 0.587785
-0.5 1.53884
-0.809017 -0.587785
-1.61803 0
0.309017 -0.951057
-0.5 -1.53884
1.30902 -0.951057
0.5 0
1.15451 0.475529
0.809019 0.951057
0.154508 0.475529
-0.0954915 1.24495
-0.654508 1.06331
-0.404508 0.293893
-1.21352 0.293893
-1.21352 -0.293892
-0.404508 -0.293893
-0.654508 -1.06331
-0.0954915 -1.24495
0.154508 -0.475529
0.809019 -0.951057
1.15451 -0.475529
0.654509 0.475529
-0.25 0.769421
-0.809016 0
-0.25 -0.76942
0.654509 -0.475529
MFEM sets v1.0
vertex_sets
3
Origin
1
0
Tent
5
1 2 4 6 8
Gazebo
5
3 5 7 9 10
edge_sets
2
Columbine
5
1 11
2 14
4 17
6 20
8 23
Lily
5
0 11
0 14
0 17
0 20
0 23
element_sets
2
Flying Squirrel
3
6 12 18
Sea Lion
4
9 12 15 18
+32 -30
View File
@@ -41,36 +41,38 @@ add_mfem_examples(SUNDIALS_EXAMPLES_SRCS ${PFX} "" test_sundials)
# which builds the examples and runs:
# ctest -R sundials
# Command line options for the tests.
# Example 9: test CVODE with CV_ADAMS (non-stiff implicit) time stepping
set(EX9_COMMON_OPTS -m ../../data/periodic-hexagon.mesh -p 0 -s 7)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 -dt 0.0018 -vs 25)
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS} -rp 1 -dt 0.0009 -vs 50)
# Example 10: test CVODE with CV_BDF (stiff implicit) time stepping
set(EX10_COMMON_OPTS -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -tf 6 -vs 10)
set(EX10_TEST_OPTS ${EX10_COMMON_OPTS} -r 2)
set(EX10P_TEST_OPTS ${EX10_COMMON_OPTS} -rp 1)
# Example 16: use the default options
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 9: test CVODE with CV_ADAMS (non-stiff implicit) time stepping
set(EX9_COMMON_OPTS -m ../../data/periodic-hexagon.mesh -p 0 -s 7)
set(EX9_TEST_OPTS ${EX9_COMMON_OPTS} -r 2 -dt 0.0018 -vs 25)
set(EX9P_TEST_OPTS ${EX9_COMMON_OPTS} -rp 1 -dt 0.0009 -vs 50)
# Example 10: test CVODE with CV_BDF (stiff implicit) time stepping
set(EX10_COMMON_OPTS -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -tf 6 -vs 10)
set(EX10_TEST_OPTS ${EX10_COMMON_OPTS} -r 2)
set(EX10P_TEST_OPTS ${EX10_COMMON_OPTS} -rp 1)
# Example 16: use the default options
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+26 -25
View File
@@ -32,31 +32,32 @@ add_mfem_examples(SUPERLU_EXAMPLES_SRCS ${PFX} "" test_superlu)
# The SuperLU tests can be run separately using the target "test_superlu"
# which builds the examples and runs:
# ctest -R superlu
if (MFEM_ENABLE_TESTING)
# Command line options for the tests.
# Example 1: Test SuperLU on the simple Poisson problem
set(EX1_COMMON_OPTS -m ../../data/star.mesh -p 2)
set(EX1P_TEST_OPTS ${EX1_COMMON_OPTS})
# Command line options for the tests.
# Example 1: Test SuperLU on the simple Poisson problem
set(EX1_COMMON_OPTS -m ../../data/star.mesh -p 2)
set(EX1P_TEST_OPTS ${EX1_COMMON_OPTS})
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUPERLU_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
# Add the tests: one test per source file.
foreach(SRC_FILE ${SUPERLU_EXAMPLES_SRCS})
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
set(TEST_NAME ${PFX}${TEST_NAME})
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
set(THIS_TEST_OPTIONS "-no-vis")
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
else()
add_test(NAME ${TEST_NAME}_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
${MPIEXEC_POSTFLAGS})
endif()
endforeach()
endif()
+50 -28
View File
@@ -985,6 +985,8 @@ void DiffusionIntegrator::ComputeElementFlux
"Unexpected height for MatrixCoefficient");
}
MFEM_VERIFY(!SMQ, "SymmetricMatrixCoefficient not supported here");
#ifdef MFEM_THREAD_SAFE
DenseMatrix dshape(nd,dim), invdfdx(dim, spaceDim);
DenseMatrix M(MQ ? spaceDim : 0);
@@ -997,7 +999,7 @@ void DiffusionIntegrator::ComputeElementFlux
#endif
vec.SetSize(dim);
vecdxt.SetSize(spaceDim);
pointflux.SetSize(MQ ? spaceDim : 0);
pointflux.SetSize(MQ || VQ ? spaceDim : 0);
const IntegrationRule &ir = fluxelem.GetNodes();
fnd = ir.GetNPoints();
@@ -1013,36 +1015,45 @@ void DiffusionIntegrator::ComputeElementFlux
CalcInverse(Trans.Jacobian(), invdfdx);
invdfdx.MultTranspose(vec, vecdxt);
if (!MQ && !VQ)
if (with_coef)
{
if (Q && with_coef)
if (!MQ && !VQ)
{
vecdxt *= Q->Eval(Trans,ip);
if (Q)
{
vecdxt *= Q->Eval(Trans,ip);
}
for (j = 0; j < spaceDim; j++)
{
flux(fnd*j+i) = vecdxt(j);
}
}
for (j = 0; j < spaceDim; j++)
else
{
flux(fnd*j+i) = vecdxt(j);
if (MQ)
{
MQ->Eval(M, Trans, ip);
M.Mult(vecdxt, pointflux);
}
else
{
VQ->Eval(D, Trans, ip);
for (int j=0; j<spaceDim; ++j)
{
pointflux[j] = D[j] * vecdxt[j];
}
}
for (j = 0; j < spaceDim; j++)
{
flux(fnd*j+i) = pointflux(j);
}
}
}
else
{
if (MQ)
{
MQ->Eval(M, Trans, ip);
M.Mult(vecdxt, pointflux);
}
else
{
VQ->Eval(D, Trans, ip);
for (int j=0; j<spaceDim; ++j)
{
pointflux[j] = D[j] * vecdxt[j];
}
}
for (j = 0; j < spaceDim; j++)
{
flux(fnd*j+i) = pointflux(j);
flux(fnd*j+i) = vecdxt(j);
}
}
}
@@ -1058,8 +1069,13 @@ double DiffusionIntegrator::ComputeFluxEnergy
#ifdef MFEM_THREAD_SAFE
DenseMatrix M;
Vector D(VQ ? VQ->GetVDim() : 0);
#else
D.SetSize(VQ ? VQ->GetVDim() : 0);
#endif
MFEM_VERIFY(!SMQ, "SymmetricMatrixCoefficient not supported here");
shape.SetSize(nd);
pointflux.SetSize(spaceDim);
if (d_energy) { vec.SetSize(spaceDim); }
@@ -1088,17 +1104,23 @@ double DiffusionIntegrator::ComputeFluxEnergy
Trans.SetIntPoint(&ip);
double w = Trans.Weight() * ip.weight;
if (!MQ)
if (MQ)
{
MQ->Eval(M, Trans, ip);
energy += w * M.InnerProduct(pointflux, pointflux);
}
else if (VQ)
{
VQ->Eval(D, Trans, ip);
D *= pointflux;
energy += w * (D * pointflux);
}
else
{
double e = (pointflux * pointflux);
if (Q) { e *= Q->Eval(Trans, ip); }
energy += w * e;
}
else
{
MQ->Eval(M, Trans, ip);
energy += w * M.InnerProduct(pointflux, pointflux);
}
if (d_energy)
{
@@ -1108,7 +1130,7 @@ double DiffusionIntegrator::ComputeFluxEnergy
{
(*d_energy)[k] += w * vec[k] * vec[k];
}
// TODO: Q, MQ
// TODO: Q, VQ, MQ
}
}
+152 -183
View File
@@ -903,9 +903,11 @@ static void PADiffusionAssembleDiagonal(const int dim,
{
switch ((D1D << 4 ) | Q1D)
{
case 0x22: return SmemPADiffusionDiagonal3D<2,2>(NE,symm,B,G,D,Y);
case 0x23: return SmemPADiffusionDiagonal3D<2,3>(NE,symm,B,G,D,Y);
case 0x34: return SmemPADiffusionDiagonal3D<3,4>(NE,symm,B,G,D,Y);
case 0x45: return SmemPADiffusionDiagonal3D<4,5>(NE,symm,B,G,D,Y);
case 0x46: return SmemPADiffusionDiagonal3D<4,6>(NE,symm,B,G,D,Y);
case 0x56: return SmemPADiffusionDiagonal3D<5,6>(NE,symm,B,G,D,Y);
case 0x67: return SmemPADiffusionDiagonal3D<6,7>(NE,symm,B,G,D,Y);
case 0x78: return SmemPADiffusionDiagonal3D<7,8>(NE,symm,B,G,D,Y);
@@ -1554,7 +1556,7 @@ static void SmemPADiffusionApply3D(const int NE,
auto d = Reshape(d_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, 1,
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
@@ -1583,118 +1585,102 @@ static void SmemPADiffusionApply3D(const int NE,
double (*QDD0)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+0);
double (*QDD1)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+1);
double (*QDD2)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+2);
MFEM_FOREACH_THREAD(dy,y,D1D)
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
MFEM_FOREACH_THREAD(dx,x,D1D)
{
X[dz][dy][dx] = x(dx,dy,dz,e);
}
}
MFEM_FOREACH_THREAD(qx,x,Q1D)
}
if (MFEM_THREAD_ID(z) == 0)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
const int i = qi(qx,dy,Q1D);
const int j = dj(qx,dy,D1D);
const int k = qk(qx,dy,Q1D);
const int l = dl(qx,dy,D1D);
B[i][j] = b(qx,dy);
G[k][l] = g(qx,dy) * sign(qx,dy);
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const int i = qi(qx,dy,Q1D);
const int j = dj(qx,dy,D1D);
const int k = qk(qx,dy,Q1D);
const int l = dl(qx,dy,D1D);
B[i][j] = b(qx,dy);
G[k][l] = g(qx,dy) * sign(qx,dy);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
MFEM_FOREACH_THREAD(dy,y,D1D)
{
double u[D1D], v[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++) { u[dz] = v[dz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dx = 0; dx < D1D; ++dx)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const int i = qi(qx,dx,Q1D);
const int j = dj(qx,dx,D1D);
const int k = qk(qx,dx,Q1D);
const int l = dl(qx,dx,D1D);
const double s = sign(qx,dx);
double u = 0.0, v = 0.0;
MFEM_UNROLL(MD1)
for (int dx = 0; dx < D1D; ++dx)
{
const int i = qi(qx,dx,Q1D);
const int j = dj(qx,dx,D1D);
const int k = qk(qx,dx,Q1D);
const int l = dl(qx,dx,D1D);
const double s = sign(qx,dx);
const double coords = X[dz][dy][dx];
u += coords * B[i][j];
v += coords * G[k][l] * s;
}
DDQ0[dz][dy][qx] = u;
DDQ1[dz][dy][qx] = v;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u = 0.0, v = 0.0, w = 0.0;
MFEM_UNROLL(MD1)
for (int dy = 0; dy < D1D; ++dy)
{
const int i = qi(qy,dy,Q1D);
const int j = dj(qy,dy,D1D);
const int k = qk(qy,dy,Q1D);
const int l = dl(qy,dy,D1D);
const double s = sign(qy,dy);
u += DDQ1[dz][dy][qx] * B[i][j];
v += DDQ0[dz][dy][qx] * G[k][l] * s;
w += DDQ0[dz][dy][qx] * B[i][j];
}
DQQ0[dz][qy][qx] = u;
DQQ1[dz][qy][qx] = v;
DQQ2[dz][qy][qx] = w;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u = 0.0, v = 0.0, w = 0.0;
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
const double coords = X[dz][dy][dx];
u[dz] += coords * B[i][j];
v[dz] += coords * G[k][l] * s;
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
DDQ0[dz][dy][qx] = u[dz];
DDQ1[dz][dy][qx] = v[dz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[D1D], v[D1D], w[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++) { u[dz] = v[dz] = w[dz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dy = 0; dy < D1D; ++dy)
{
const int i = qi(qy,dy,Q1D);
const int j = dj(qy,dy,D1D);
const int k = qk(qy,dy,Q1D);
const int l = dl(qy,dy,D1D);
const double s = sign(qy,dy);
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++)
{
u[dz] += DDQ1[dz][dy][qx] * B[i][j];
v[dz] += DDQ0[dz][dy][qx] * G[k][l] * s;
w[dz] += DDQ0[dz][dy][qx] * B[i][j];
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; dz++)
{
DQQ0[dz][qy][qx] = u[dz];
DQQ1[dz][qy][qx] = v[dz];
DQQ2[dz][qy][qx] = w[dz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
double u[Q1D], v[Q1D], w[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++) { u[qz] = v[qz] = w[qz] = 0.0; }
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++)
{
const int i = qi(qz,dz,Q1D);
const int j = dj(qz,dz,D1D);
const int k = qk(qz,dz,Q1D);
const int l = dl(qz,dz,D1D);
const double s = sign(qz,dz);
u[qz] += DQQ0[dz][qy][qx] * B[i][j];
v[qz] += DQQ1[dz][qy][qx] * B[i][j];
w[qz] += DQQ2[dz][qy][qx] * G[k][l] * s;
u += DQQ0[dz][qy][qx] * B[i][j];
v += DQQ1[dz][qy][qx] * B[i][j];
w += DQQ2[dz][qy][qx] * G[k][l] * s;
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; qz++)
{
const double O11 = d(qx,qy,qz,0,e);
const double O12 = d(qx,qy,qz,1,e);
const double O13 = d(qx,qy,qz,2,e);
@@ -1704,9 +1690,9 @@ static void SmemPADiffusionApply3D(const int NE,
const double O31 = symmetric ? O13 : d(qx,qy,qz,6,e);
const double O32 = symmetric ? O23 : d(qx,qy,qz,7,e);
const double O33 = symmetric ? d(qx,qy,qz,5,e) : d(qx,qy,qz,8,e);
const double gX = u[qz];
const double gY = v[qz];
const double gZ = w[qz];
const double gX = u;
const double gY = v;
const double gZ = w;
QQQ0[qz][qy][qx] = (O11*gX) + (O12*gY) + (O13*gZ);
QQQ1[qz][qy][qx] = (O21*gX) + (O22*gY) + (O23*gZ);
QQQ2[qz][qy][qx] = (O31*gX) + (O32*gY) + (O33*gZ);
@@ -1714,112 +1700,94 @@ static void SmemPADiffusionApply3D(const int NE,
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(d,y,D1D)
if (MFEM_THREAD_ID(z) == 0)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
MFEM_FOREACH_THREAD(d,y,D1D)
{
const int i = qi(q,d,Q1D);
const int j = dj(q,d,D1D);
const int k = qk(q,d,Q1D);
const int l = dl(q,d,D1D);
Bt[j][i] = b(q,d);
Gt[l][k] = g(q,d) * sign(q,d);
MFEM_FOREACH_THREAD(q,x,Q1D)
{
const int i = qi(q,d,Q1D);
const int j = dj(q,d,D1D);
const int k = qk(q,d,Q1D);
const int l = dl(q,d,D1D);
Bt[j][i] = b(q,d);
Gt[l][k] = g(q,d) * sign(q,d);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy,y,Q1D)
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
double u[Q1D], v[Q1D], w[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = v[qz] = w[qz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qx = 0; qx < Q1D; ++qx)
MFEM_FOREACH_THREAD(dx,x,D1D)
{
const int i = qi(qx,dx,Q1D);
const int j = dj(qx,dx,D1D);
const int k = qk(qx,dx,Q1D);
const int l = dl(qx,dx,D1D);
const double s = sign(qx,dx);
double u = 0.0, v = 0.0, w = 0.0;
MFEM_UNROLL(MQ1)
for (int qx = 0; qx < Q1D; ++qx)
{
const int i = qi(qx,dx,Q1D);
const int j = dj(qx,dx,D1D);
const int k = qk(qx,dx,Q1D);
const int l = dl(qx,dx,D1D);
const double s = sign(qx,dx);
u += QQQ0[qz][qy][qx] * Gt[l][k] * s;
v += QQQ1[qz][qy][qx] * Bt[j][i];
w += QQQ2[qz][qy][qx] * Bt[j][i];
}
QQD0[qz][qy][dx] = u;
QQD1[qz][qy][dx] = v;
QQD2[qz][qy][dx] = w;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u = 0.0, v = 0.0, w = 0.0;
MFEM_UNROLL(Q1D)
for (int qy = 0; qy < Q1D; ++qy)
{
const int i = qi(qy,dy,Q1D);
const int j = dj(qy,dy,D1D);
const int k = qk(qy,dy,Q1D);
const int l = dl(qy,dy,D1D);
const double s = sign(qy,dy);
u += QQD0[qz][qy][dx] * Bt[j][i];
v += QQD1[qz][qy][dx] * Gt[l][k] * s;
w += QQD2[qz][qy][dx] * Bt[j][i];
}
QDD0[qz][dy][dx] = u;
QDD1[qz][dy][dx] = v;
QDD2[qz][dy][dx] = w;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1D)
{
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u = 0.0, v = 0.0, w = 0.0;
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += QQQ0[qz][qy][qx] * Gt[l][k] * s;
v[qz] += QQQ1[qz][qy][qx] * Bt[j][i];
w[qz] += QQQ2[qz][qy][qx] * Bt[j][i];
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
QQD0[qz][qy][dx] = u[qz];
QQD1[qz][qy][dx] = v[qz];
QQD2[qz][qy][dx] = w[qz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[Q1D], v[Q1D], w[Q1D];
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz) { u[qz] = v[qz] = w[qz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qy = 0; qy < Q1D; ++qy)
{
const int i = qi(qy,dy,Q1D);
const int j = dj(qy,dy,D1D);
const int k = qk(qy,dy,Q1D);
const int l = dl(qy,dy,D1D);
const double s = sign(qy,dy);
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
u[qz] += QQD0[qz][qy][dx] * Bt[j][i];
v[qz] += QQD1[qz][qy][dx] * Gt[l][k] * s;
w[qz] += QQD2[qz][qy][dx] * Bt[j][i];
}
}
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
QDD0[qz][dy][dx] = u[qz];
QDD1[qz][dy][dx] = v[qz];
QDD2[qz][dy][dx] = w[qz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
{
double u[D1D], v[D1D], w[D1D];
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz) { u[dz] = v[dz] = w[dz] = 0.0; }
MFEM_UNROLL(MQ1)
for (int qz = 0; qz < Q1D; ++qz)
{
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
const int i = qi(qz,dz,Q1D);
const int j = dj(qz,dz,D1D);
const int k = qk(qz,dz,Q1D);
const int l = dl(qz,dz,D1D);
const double s = sign(qz,dz);
u[dz] += QDD0[qz][dy][dx] * Bt[j][i];
v[dz] += QDD1[qz][dy][dx] * Bt[j][i];
w[dz] += QDD2[qz][dy][dx] * Gt[l][k] * s;
u += QDD0[qz][dy][dx] * Bt[j][i];
v += QDD1[qz][dy][dx] * Bt[j][i];
w += QDD2[qz][dy][dx] * Gt[l][k] * s;
}
}
MFEM_UNROLL(MD1)
for (int dz = 0; dz < D1D; ++dz)
{
y(dx,dy,dz,e) += (u[dz] + v[dz] + w[dz]);
y(dx,dy,dz,e) += (u + v + w);
}
}
}
@@ -1877,6 +1845,7 @@ static void PADiffusionApply(const int dim,
{
switch (ID)
{
case 0x22: return SmemPADiffusionApply3D<2,2>(NE,symm,B,G,D,X,Y);
case 0x23: return SmemPADiffusionApply3D<2,3>(NE,symm,B,G,D,X,Y);
case 0x34: return SmemPADiffusionApply3D<3,4>(NE,symm,B,G,D,X,Y);
case 0x45: return SmemPADiffusionApply3D<4,5>(NE,symm,B,G,D,X,Y);
+2
View File
@@ -1203,8 +1203,10 @@ static void PAMassApply(const int dim,
{
switch (id)
{
case 0x22: return SmemPAMassApply3D<2,2>(NE,B,Bt,D,X,Y);
case 0x23: return SmemPAMassApply3D<2,3>(NE,B,Bt,D,X,Y);
case 0x24: return SmemPAMassApply3D<2,4>(NE,B,Bt,D,X,Y);
case 0x26: return SmemPAMassApply3D<2,6>(NE,B,Bt,D,X,Y);
case 0x34: return SmemPAMassApply3D<3,4>(NE,B,Bt,D,X,Y);
case 0x35: return SmemPAMassApply3D<3,5>(NE,B,Bt,D,X,Y);
case 0x36: return SmemPAMassApply3D<3,6>(NE,B,Bt,D,X,Y);
+7 -3
View File
@@ -186,14 +186,18 @@ static void InitTensorBasis(const mfem::FiniteElementSpace &fes,
const int ndofs = maps.ndof;
const int nqpts = maps.nqpt;
mfem::Vector qX(nqpts), qW(nqpts);
const mfem::IntegrationRule &ir1d =
IntRules.Get(Geometry::SEGMENT, ir.GetOrder());
// The x-coordinates of the first `nqpts` points of the integration rule are
// the points of the corresponding 1D rule. We also scale the weights
// accordingly.
double w_sum = 0.0;
for (int i = 0; i < nqpts; i++)
{
const mfem::IntegrationPoint &ip = ir1d.IntPoint(i);
const mfem::IntegrationPoint &ip = ir.IntPoint(i);
qX(i) = ip.x;
qW(i) = ip.weight;
w_sum += ip.weight;
}
qW *= 1.0/w_sum;
CeedBasisCreateTensorH1(ceed, mesh->Dimension(), fes.GetVDim(), ndofs,
nqpts, maps.Bt.GetData(),
maps.Gt.GetData(), qX.GetData(),
+169
View File
@@ -28,6 +28,52 @@ double PWConstCoefficient::Eval(ElementTransformation & T,
return (constants(att-1));
}
void PWCoefficient::InitMap(const Array<int> & attr,
const Array<Coefficient*> & coefs)
{
MFEM_VERIFY(attr.Size() == coefs.Size(),
"PWCoefficient: "
"Attribute and coefficient arrays have incompatible "
"dimensions.");
for (int i=0; i<attr.Size(); i++)
{
if (coefs[i] != NULL)
{
UpdateCoefficient(attr[i], *coefs[i]);
}
}
}
void PWCoefficient::SetTime(double t)
{
Coefficient::SetTime(t);
std::map<int, Coefficient*>::iterator p = pieces.begin();
for (; p != pieces.end(); p++)
{
if (p->second != NULL)
{
p->second->SetTime(t);
}
}
}
double PWCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
const int att = T.Attribute;
std::map<int, Coefficient*>::const_iterator p = pieces.find(att);
if (p != pieces.end())
{
if ( p->second != NULL)
{
return p->second->Eval(T, ip);
}
}
return 0.0;
}
double FunctionCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
@@ -120,6 +166,63 @@ void VectorCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
}
}
void PWVectorCoefficient::InitMap(const Array<int> & attr,
const Array<VectorCoefficient*> & coefs)
{
MFEM_VERIFY(attr.Size() == coefs.Size(),
"PWVectorCoefficient: "
"Attribute and coefficient arrays have incompatible "
"dimensions.");
for (int i=0; i<attr.Size(); i++)
{
if (coefs[i] != NULL)
{
UpdateCoefficient(attr[i], *coefs[i]);
}
}
}
void PWVectorCoefficient::UpdateCoefficient(int attr, VectorCoefficient & coef)
{
MFEM_VERIFY(coef.GetVDim() == vdim,
"PWVectorCoefficient::UpdateCoefficient: "
"VectorCoefficient has incompatible dimension.");
pieces[attr] = &coef;
}
void PWVectorCoefficient::SetTime(double t)
{
VectorCoefficient::SetTime(t);
std::map<int, VectorCoefficient*>::iterator p = pieces.begin();
for (; p != pieces.end(); p++)
{
if (p->second != NULL)
{
p->second->SetTime(t);
}
}
}
void PWVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
const int att = T.Attribute;
std::map<int, VectorCoefficient*>::const_iterator p = pieces.find(att);
if (p != pieces.end())
{
if ( p->second != NULL)
{
p->second->Eval(V, T, ip);
return;
}
}
V.SetSize(vdim);
V = 0.0;
}
void VectorFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
@@ -331,6 +434,72 @@ void VectorRestrictedCoefficient::Eval(
}
}
void PWMatrixCoefficient::InitMap(const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs)
{
MFEM_VERIFY(attr.Size() == coefs.Size(),
"PWMatrixCoefficient: "
"Attribute and coefficient arrays have incompatible "
"dimensions.");
for (int i=0; i<attr.Size(); i++)
{
if (coefs[i] != NULL)
{
UpdateCoefficient(attr[i], *coefs[i]);
}
}
}
void PWMatrixCoefficient::UpdateCoefficient(int attr, MatrixCoefficient & coef)
{
MFEM_VERIFY(coef.GetHeight() == height,
"PWMatrixCoefficient::UpdateCoefficient: "
"MatrixCoefficient has incompatible height.");
MFEM_VERIFY(coef.GetWidth() == width,
"PWMatrixCoefficient::UpdateCoefficient: "
"MatrixCoefficient has incompatible width.");
if (symmetric)
{
MFEM_VERIFY(coef.IsSymmetric(),
"PWMatrixCoefficient::UpdateCoefficient: "
"MatrixCoefficient has incompatible symmetry.");
}
pieces[attr] = &coef;
}
void PWMatrixCoefficient::SetTime(double t)
{
MatrixCoefficient::SetTime(t);
std::map<int, MatrixCoefficient*>::iterator p = pieces.begin();
for (; p != pieces.end(); p++)
{
if (p->second != NULL)
{
p->second->SetTime(t);
}
}
}
void PWMatrixCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
const int att = T.Attribute;
std::map<int, MatrixCoefficient*>::const_iterator p = pieces.find(att);
if (p != pieces.end())
{
if ( p->second != NULL)
{
p->second->Eval(K, T, ip);
return;
}
}
K.SetSize(height, width);
K = 0.0;
}
void MatrixFunctionCoefficient::SetTime(double t)
{
if (Q) { Q->SetTime(t); }
+269
View File
@@ -125,6 +125,87 @@ public:
const IntegrationPoint &ip);
};
/** @brief A piecewise coefficient with the pieces keyed off the element
attribute numbers.
A value of zero will be returned for any missing attribute numbers.
This object will not assume ownership of any Coefficient objects
passed to it. Consequently, the caller must ensure that the
individual Coefficient objects are not deleted while this
PWCoefficient is still in use.
\note The keys may either be domain attribute numbers or boundary
attribute numbers. If the PWCoefficient is used with a domain
integrator the keys are assumed to be domain attribute
numbers. Similarly, if the PWCoefficient is used with a boundary
integrator the keys are assumed to be boundary attribute numbers.
*/
class PWCoefficient : public Coefficient
{
private:
/** Internal data structure to store pointers to the appropriate
coefficients for different regions of the mesh. The keys used
in the map are the mesh attribute numbers (either element
attribute or boundary element attribute depending upon
context). The values returned for any missing attributes will
be zero. The coefficient pointers may be NULL in which case a
value of zero is returned.
The Coefficient objects contained in this map are NOT owned by
this PWCoefficient object. This means that they will not be
deleted when this object is deleted also the caller must ensure
that the various Coefficient objects are not deleted while this
PWCoefficient is still needed.
*/
std::map<int, Coefficient*> pieces;
/** Convenience function to check for compatible array lengths,
loop over the arrays, and add their attribute/Coefficient pairs
to the internal data structure.
*/
void InitMap(const Array<int> & attr,
const Array<Coefficient*> & coefs);
public:
/// Constructs a piecewise coefficient
explicit PWCoefficient() {}
/// Construct the coefficient using arrays describing the pieces
/** \param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of Coefficient pointers
Any missing attributes or NULL coefficient pointers will result in a
value of zero being returned for that attribute.
\note Ownership of the Coefficient objects will NOT be
transferred to this object.
*/
PWCoefficient(const Array<int> & attr,
const Array<Coefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Set the time for time dependent coefficients
virtual void SetTime(double t);
/// Replace a set of coefficients
void UpdateCoefficients(const Array<int> & attr,
const Array<Coefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Replace a single Coefficient for a particular attribute
void UpdateCoefficient(int attr, Coefficient & coef)
{ pieces[attr] = &coef; }
/// Remove a single Coefficient for a particular attribute
void ZeroCoefficient(int attr)
{ pieces.erase(attr); }
/// Evaluate the coefficient.
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
/// A general function coefficient
class FunctionCoefficient : public Coefficient
{
@@ -413,6 +494,88 @@ public:
const Vector& GetVec() { return vec; }
};
/** @brief A piecewise vector-valued coefficient with the pieces keyed off the
element attribute numbers.
A value of zero will be returned for any missing attribute numbers.
This object will not assume ownership of any VectorCoefficient
objects passed to it. Consequently, the caller must ensure that
the individual VectorCoefficient objects are not deleted while
this PWVectorCoefficient is still in use.
\note The keys may either be domain attribute numbers or boundary
attribute numbers. If the PWVectorCoefficient is used with a
domain integrator the keys are assumed to be domain attribute
numbers. Similarly, if the PWVectorCoefficient is used with a
boundary integrator the keys are assumed to be boundary attribute
numbers.
*/
class PWVectorCoefficient : public VectorCoefficient
{
private:
/** Internal data structure to store pointers to the appropriate
coefficients for different regions of the mesh. The keys used
in the map are the mesh attribute numbers (either element
attribute or boundary element attribute depending upon
context). The values returned for any missing attributes will
be zero. The coefficient pointers may be NULL in which case a
value of zero is returned.
The VectorCoefficient objects contained in this map are NOT
owned by this PWVectorCoefficient object. This means that they
will not be deleted when this object is deleted also the caller
must ensure that the various VectorCoefficient objects are not
deleted while this PWVectorCoefficient is still needed.
*/
std::map<int, VectorCoefficient*> pieces;
/** Convenience function to check for compatible array lengths,
loop over the arrays, and add their attribute/VectorCoefficient
pairs to the internal data structure.
*/
void InitMap(const Array<int> & attr,
const Array<VectorCoefficient*> & coefs);
public:
/// Constructs a piecewise vector coefficient of dimension vd
explicit PWVectorCoefficient(int vd): VectorCoefficient(vd) {}
/// Construct the coefficient using arrays describing the pieces
/** \param vd - dimension of the vector-valued result
\param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of VectorCoefficient pointers
Any missing attributes or NULL coefficient pointers will result in a
zero vector being returned for that attribute.
\note Ownership of the VectorCoefficient objects will NOT be
transferred to this object.
*/
PWVectorCoefficient(int vd, const Array<int> & attr,
const Array<VectorCoefficient*> & coefs)
: VectorCoefficient(vd) { InitMap(attr, coefs); }
/// Set the time for time dependent coefficients
virtual void SetTime(double t);
/// Replace a set of coefficients
void UpdateCoefficients(const Array<int> & attr,
const Array<VectorCoefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Replace a single Coefficient for a particular attribute
void UpdateCoefficient(int attr, VectorCoefficient & coef);
/// Remove a single VectorCoefficient for a particular attribute
void ZeroCoefficient(int attr)
{ pieces.erase(attr); }
/// Evaluate the coefficient.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
};
/// A general vector function coefficient
class VectorFunctionCoefficient : public VectorCoefficient
{
@@ -782,6 +945,112 @@ public:
};
/** @brief A piecewise matrix-valued coefficient with the pieces keyed off the
element attribute numbers.
A value of zero will be returned for any missing attribute numbers.
This object will not assume ownership of any MatrixCoefficient
objects passed to it. Consequently, the caller must ensure that
the individual MatrixCoefficient objects are not deleted while
this PWMatrixCoefficient is still in use.
\note The keys may either be domain attribute numbers or boundary
attribute numbers. If the PWMatrixCoefficient is used with a
domain integrator the keys are assumed to be domain attribute
numbers. Similarly, if the PWMatrixCoefficient is used with a
boundary integrator the keys are assumed to be boundary attribute
numbers.
*/
class PWMatrixCoefficient : public MatrixCoefficient
{
private:
/** Internal data structure to store pointers to the appropriate
coefficients for different regions of the mesh. The keys used
in the map are the mesh attribute numbers (either element
attribute or boundary element attribute depending upon
context). The values returned for any missing attributes will
be zero. The coefficient pointers may be NULL in which case a
value of zero is returned.
The MatrixCoefficient objects contained in this map are NOT
owned by this PWMatrixCoefficient object. This means that they
will not be deleted when this object is deleted also the caller
must ensure that the various MatrixCoefficient objects are not
deleted while this PWMatrixCoefficient is still needed.
*/
std::map<int, MatrixCoefficient*> pieces;
/** Convenience function to check for compatible array lengths,
loop over the arrays, and add their attribute/MatrixCoefficient
pairs to the internal data structure.
*/
void InitMap(const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs);
public:
/// Constructs a piecewise matrix coefficient of dimension dim by dim
explicit PWMatrixCoefficient(int dim, bool symm = false)
: MatrixCoefficient(dim, symm) {}
/// Constructs a piecewise matrix coefficient of dimension h by w
explicit PWMatrixCoefficient(int h, int w, bool symm = false)
: MatrixCoefficient(h, w, symm) {}
/// Construct the coefficient using arrays describing the pieces
/** \param dim - size of the square matrix-valued result
\param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of MatrixCoefficient pointers
\param symm - true if the result will be symmetric, false otherwise
Any missing attributes or NULL coefficient pointers will result in a
zero matrix being returned.
\note Ownership of the MatrixCoefficient objects will NOT be
transferred to this object.
*/
PWMatrixCoefficient(int dim, const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs,
bool symm=false)
: MatrixCoefficient(dim, symm) { InitMap(attr, coefs); }
/// Construct the coefficient using arrays describing the pieces
/** \param h - height of the matrix-valued result
\param w - width of the matrix-valued result
\param attr - an array of attribute numbers for each piece
\param coefs - the corresponding array of MatrixCoefficient pointers
\param symm - true if the result will be symmetric, false otherwise
Any missing attributes or NULL coefficient pointers will result in a
zero matrix being returned for that attribute.
\note Ownership of the MatrixCoefficient objects will NOT be
transferred to this object.
*/
PWMatrixCoefficient(int h, int w, const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs,
bool symm=false)
: MatrixCoefficient(h, w, symm) { InitMap(attr, coefs); }
/// Set the time for time dependent coefficients
virtual void SetTime(double t);
/// Replace a set of coefficients
void UpdateCoefficients(const Array<int> & attr,
const Array<MatrixCoefficient*> & coefs)
{ InitMap(attr, coefs); }
/// Replace a single coefficient for a particular attribute
void UpdateCoefficient(int attr, MatrixCoefficient & coef);
/// Remove a single MatrixCoefficient for a particular attribute
void ZeroCoefficient(int attr)
{ pieces.erase(attr); }
/// Evaluate the coefficient.
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
};
/** @brief A matrix coefficient with an optional scalar coefficient multiplier
\a q. The matrix function can either be represented by a std function or
a constant matrix provided when constructing this object. */
+34
View File
@@ -195,6 +195,15 @@ ComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
if ( lfi_imag ) { lfi->AddDomainIntegrator(lfi_imag); }
}
void
ComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &elem_attr_marker)
{
if ( lfi_real ) { lfr->AddDomainIntegrator(lfi_real, elem_attr_marker); }
if ( lfi_imag ) { lfi->AddDomainIntegrator(lfi_imag, elem_attr_marker); }
}
void
ComplexLinearForm::AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag)
@@ -317,6 +326,14 @@ void SesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
if (bfi_imag) { blfi->AddDomainIntegrator(bfi_imag); }
}
void SesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> & elem_marker)
{
if (bfi_real) { blfr->AddDomainIntegrator(bfi_real, elem_marker); }
if (bfi_imag) { blfi->AddDomainIntegrator(bfi_imag, elem_marker); }
}
void
SesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
@@ -879,6 +896,15 @@ ParComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
if ( lfi_imag ) { plfi->AddDomainIntegrator(lfi_imag); }
}
void
ParComplexLinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &elem_attr_marker)
{
if ( lfi_real ) { plfr->AddDomainIntegrator(lfi_real, elem_attr_marker); }
if ( lfi_imag ) { plfi->AddDomainIntegrator(lfi_imag, elem_attr_marker); }
}
void
ParComplexLinearForm::AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag)
@@ -1040,6 +1066,14 @@ void ParSesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
if (bfi_imag) { pblfi->AddDomainIntegrator(bfi_imag); }
}
void ParSesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> & elem_marker)
{
if (bfi_real) { pblfr->AddDomainIntegrator(bfi_real, elem_marker); }
if (bfi_imag) { pblfi->AddDomainIntegrator(bfi_imag, elem_marker); }
}
void
ParSesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
+20
View File
@@ -128,6 +128,11 @@ public:
void AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag);
/// Adds new Domain Integrator, restricted to the given attributes.
void AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &elem_attr_marker);
/// Adds new Boundary Integrator.
void AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag);
@@ -260,6 +265,11 @@ public:
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag);
/// Adds new Domain Integrator, restricted to the given attributes.
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> &elem_marker);
/// Adds new Boundary Integrator.
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag);
@@ -464,6 +474,11 @@ public:
void AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag);
/// Adds new Domain Integrator, restricted to specific attributes.
void AddDomainIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag,
Array<int> &elem_attr_marker);
/// Adds new Boundary Integrator.
void AddBoundaryIntegrator(LinearFormIntegrator *lfi_real,
LinearFormIntegrator *lfi_imag);
@@ -598,6 +613,11 @@ public:
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag);
/// Adds new Domain Integrator, restricted to specific attributes.
void AddDomainIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> &elem_marker);
/// Adds new Boundary Integrator.
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag);
+79 -1
View File
@@ -645,7 +645,8 @@ ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
Node &n_mesh,
const std::string &coordset_name,
const std::string &main_topology_name,
const std::string &boundary_topology_name)
const std::string &boundary_topology_name,
const std::string &main_adjset_name)
{
int dim = mesh->SpaceDimension();
@@ -815,6 +816,83 @@ ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
bndry_att_vals[i] = mesh->GetBdrAttribute(i);
}
}
////////////////////////////////////////////
// Setup adjsets
////////////////////////////////////////////
#ifdef MFEM_USE_MPI
ParMesh *pmesh = dynamic_cast<ParMesh*>(mesh);
if (pmesh)
{
////////////////////////////////////////////
// Setup main adjset
////////////////////////////////////////////
Node &n_adjset = n_mesh["adjsets"][main_adjset_name];
n_adjset["association"] = "vertex";
n_adjset["topology"] = main_topology_name;
n_adjset["groups"].set(DataType::object());
const GroupTopology &pmesh_gtopo = pmesh->gtopo;
const int local_rank = pmesh->GetMyRank();
const int num_groups = pmesh_gtopo.NGroups();
// NOTE: skip the first group since its the local-only group
for (int i = 1; i < num_groups; i++)
{
const int num_group_nbrs = pmesh_gtopo.GetGroupSize(i);
const int *group_nbrs = pmesh_gtopo.GetGroup(i);
const int num_group_verts = pmesh->GroupNVertices(i);
// NOTE: 'neighbor' values are local to this processor, but Blueprint
// expects global domain identifiers, so we collapse this layer of
// indirection
Array<int> group_ranks(num_group_nbrs);
std::string group_name = "group";
{
for (int j = 0; j < num_group_nbrs; j++)
{
group_ranks[j] = pmesh_gtopo.GetNeighborRank(group_nbrs[j]);
}
group_ranks.Sort();
for (int j = 0; j < num_group_nbrs; j++)
{
group_name += "_" + std::to_string(group_ranks[j]);
}
// NOTE: Blueprint only wants remote ranks in its neighbor list,
// so we remove the local rank after the canonicalized Blueprint
// group name is formed
group_ranks.DeleteFirst(local_rank);
}
Node &n_group = n_adjset["groups"][group_name];
n_group["neighbors"].set(group_ranks.GetData(), group_ranks.Size());
n_group["values"].set(DataType::c_int(num_group_verts));
int_array group_vals = n_group["values"].value();
for (int j = 0; j < num_group_verts; j++)
{
group_vals[j] = pmesh->GroupVertex(i, j);
}
}
// NOTE: We don't create an adjset for face neighbor data because
// these faces aren't listed in the 'boundary_topology_name' topology
// (this topology only covers the faces between 'main_topology_name'
// elements and void). To include a face neighbor data adjset, this
// function would need to export a topology with either (1) all faces
// in the mesh topology or (2) all boundary faces, including neighbors.
////////////////////////////////////////////
// Setup distributed state
////////////////////////////////////////////
Node &n_domid = n_mesh["state/domain_id"];
n_domid.set(local_rank);
}
#endif
}
//---------------------------------------------------------------------------//
+2 -1
View File
@@ -166,7 +166,8 @@ public:
conduit::Node &out,
const std::string &coordset_name = "coords",
const std::string &main_topology_name = "main",
const std::string &boundary_topology_name = "boundary");
const std::string &boundary_topology_name = "boundary",
const std::string &main_adjset_name = "main_adjset");
/// Describes a MFEM grid function using the mesh blueprint
/** Sets up passed conduit::Node out to describe the given grid function
+74
View File
@@ -85,6 +85,11 @@ void TransformPrimal(const DofTransformation *ran_dof_trans,
}
}
void DofTransformation::InvTransformDual(Vector &v) const
{
InvTransformDual(v.GetData());
}
void TransformDual(const DofTransformation *ran_dof_trans,
const DofTransformation *dom_dof_trans,
DenseMatrix &elmat)
@@ -195,6 +200,35 @@ void VDofTransformation::TransformDual(double *v) const
}
}
void VDofTransformation::InvTransformDual(double *v) const
{
int size = doftrans_->Size();
if ((Ordering::Type)ordering_ == Ordering::byNODES)
{
for (int i=0; i<vdim_; i++)
{
doftrans_->InvTransformDual(&v[i*size]);
}
}
else
{
Vector vec(size);
for (int i=0; i<vdim_; i++)
{
for (int j=0; j<size; j++)
{
vec(j) = v[j*vdim_+i];
}
doftrans_->InvTransformDual(vec);
for (int j=0; j<size; j++)
{
v[j*vdim_+i] = vec(j);
}
}
}
}
const double ND_DofTransformation::T_data[24] =
{
1.0, 0.0, 0.0, 1.0,
@@ -291,6 +325,26 @@ ND_TriDofTransformation::TransformDual(double *v) const
}
}
void
ND_TriDofTransformation::InvTransformDual(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<1; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[3*nedofs + f*nfdofs + 2*i];
T(Fo[f]).MultTranspose(v2, &v[3*nedofs + f*nfdofs + 2*i]);
}
}
}
ND_TetDofTransformation::ND_TetDofTransformation(int p)
: ND_DofTransformation(p*(p + 2)*(p + 3)/2, p)
{
@@ -355,4 +409,24 @@ ND_TetDofTransformation::TransformDual(double *v) const
}
}
void
ND_TetDofTransformation::InvTransformDual(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<4; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[6*nedofs + f*nfdofs + 2*i];
T(Fo[f]).MultTranspose(v2, &v[6*nedofs + f*nfdofs + 2*i]);
}
}
}
} // namespace mfem
+15
View File
@@ -102,6 +102,10 @@ public:
virtual void TransformDual(double *v) const = 0;
virtual void TransformDual(Vector &v) const;
/** Inverse Transform dual DoFs */
virtual void InvTransformDual(double *v) const = 0;
virtual void InvTransformDual(Vector &v) const;
/** Transform a matrix of dual DoFs entries as computed by a
BilinearFormIntegrator before summing into a BilinearForm object. */
virtual void TransformDual(DenseMatrix &V) const;
@@ -183,10 +187,12 @@ public:
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
/** Abstract base class for high-order Nedelec spaces on elements with
@@ -235,6 +241,8 @@ public:
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
/// DoF transformation implementation for the Nedelec basis on tetrahedra
@@ -246,12 +254,15 @@ public:
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
/// DoF transformation implementation for the Nedelec basis on wedge elements
@@ -264,12 +275,16 @@ public:
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
using DofTransformation::InvTransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
};
} // namespace mfem
+302 -7
View File
@@ -561,6 +561,155 @@ void FiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
}
}
void FiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_vdofs,
int component) const
{
Array<int> vdofs, dofs;
ess_vdofs.SetSize(GetVSize());
ess_vdofs = 0;
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
if (!mesh->ent_sets->SetExists(type, set_index))
{
ostringstream oss; oss << "Entity set of type \""
<< EntitySets::GetTypeName(type)
<< "\" and index " << set_index
<< " was not found.";
MFEM_VERIFY(false, oss.str().c_str());
}
set<int>::iterator it;
for (it=(*mesh->ent_sets)(type, set_index).begin();
it!=(*mesh->ent_sets)(type, set_index).end(); it++)
{
int ent_index = *it;
cout << "collecting vdofs for entity " << ent_index << "->";
if (component < 0)
{
switch (type)
{
case EntitySets::VERTEX:
GetVertexVDofs(ent_index, vdofs);
break;
case EntitySets::EDGE:
GetEdgeVDofs(ent_index, vdofs);
break;
case EntitySets::FACE:
GetFaceVDofs(ent_index, vdofs);
break;
case EntitySets::ELEMENT:
GetElementVDofs(ent_index, vdofs);
break;
default:
mfem_error("GetEssentialVDofs: Invalid entity type");
}
vdofs.Print(cout);
mark_dofs(vdofs, ess_vdofs);
}
else
{
switch (type)
{
case EntitySets::VERTEX:
GetVertexDofs(ent_index, dofs);
break;
case EntitySets::EDGE:
GetEdgeDofs(ent_index, dofs);
break;
case EntitySets::FACE:
GetFaceDofs(ent_index, dofs);
break;
case EntitySets::ELEMENT:
GetElementDofs(ent_index, dofs);
break;
default:
mfem_error("GetEssentialDofs: Invalid entity type");
}
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
if (mesh->ncmesh)
{
Array<int> es_verts, es_edges, es_faces;
mesh->ncmesh->GetEntitySetClosure(type, set_index,
es_verts, es_edges, es_faces);
cout << "returned from get closure" << endl;
for (int i = 0; i < es_verts.Size(); i++)
{
if (es_verts[i] < GetNV())
{
if (component < 0)
{
GetVertexVDofs(es_verts[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetVertexDofs(es_verts[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
for (int i = 0; i < es_edges.Size(); i++)
{
if (es_edges[i] < GetMesh()->GetNEdges())
{
if (component < 0)
{
GetEdgeVDofs(es_edges[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetEdgeDofs(es_edges[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
for (int i = 0; i < es_faces.Size(); i++)
{
if (es_faces[i] < GetMesh()->GetNFaces())
{
if (component < 0)
{
GetFaceVDofs(es_faces[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetFaceDofs(es_faces[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
}
}
void FiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_vdofs,
int component) const
{
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
GetEssentialVDofs(type, mesh->ent_sets->GetSetIndex(type, set_name),
ess_vdofs, component);
}
void FiniteElementSpace::GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
Array<int> &ess_tdof_list,
int component)
@@ -579,6 +728,36 @@ void FiniteElementSpace::GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
MarkerToList(ess_tdofs, ess_tdof_list);
}
void FiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_tdof_list,
int component)
{
Array<int> ess_vdofs, ess_tdofs;
GetEssentialVDofs(type, set_index, ess_vdofs, component);
const SparseMatrix *R = GetConformingRestriction();
if (!R)
{
ess_tdofs.MakeRef(ess_vdofs);
}
else
{
R->BooleanMult(ess_vdofs, ess_tdofs);
}
MarkerToList(ess_tdofs, ess_tdof_list);
}
void FiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_tdof_list,
int component)
{
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
GetEssentialTrueDofs(type, mesh->ent_sets->GetSetIndex(type, set_name),
ess_tdof_list, component);
}
void FiniteElementSpace::GetBoundaryTrueDofs(Array<int> &boundary_dofs,
int component)
{
@@ -1709,8 +1888,7 @@ void FiniteElementSpace::RefinementOperator
fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
x.GetSubVector(f_vdofs, subX);
old_DoFTrans[geom]->InvTransformPrimal(subX);
doftrans->InvTransformDual(subX);
for (int p = 0; p < f_dofs.Size(); ++p)
{
if (processed[DecodeDof(f_dofs[p])])
@@ -1719,9 +1897,9 @@ void FiniteElementSpace::RefinementOperator
}
}
lP.MultTranspose(subX, subY);
doftrans->TransformPrimal(subY);
y.AddElementVector(c_vdofs, subY);
lP.MultTranspose(subX, subYt);
old_DoFTrans[geom]->TransformDual(subYt);
y.AddElementVector(c_vdofs, subYt);
}
if (vdoftrans)
@@ -1737,6 +1915,122 @@ void FiniteElementSpace::RefinementOperator
}
}
namespace internal
{
// Used in GetCoarseToFineMap() below.
struct RefType
{
Geometry::Type geom;
int num_children;
const Pair<int,int> *children;
RefType(Geometry::Type g, int n, const Pair<int,int> *c)
: geom(g), num_children(n), children(c) { }
bool operator<(const RefType &other) const
{
if (geom < other.geom) { return true; }
if (geom > other.geom) { return false; }
if (num_children < other.num_children) { return true; }
if (num_children > other.num_children) { return false; }
for (int i = 0; i < num_children; i++)
{
if (children[i].one < other.children[i].one) { return true; }
if (children[i].one > other.children[i].one) { return false; }
}
return false; // everything is equal
}
};
void GetCoarseToFineMap(const CoarseFineTransformations &cft,
const mfem::Mesh &fine_mesh,
Table &coarse_to_fine,
Array<int> &coarse_to_ref_type,
Table &ref_type_to_matrix,
Array<Geometry::Type> &ref_type_to_geom)
{
const int fine_ne = cft.embeddings.Size();
int coarse_ne = -1;
for (int i = 0; i < fine_ne; i++)
{
coarse_ne = std::max(coarse_ne, cft.embeddings[i].parent);
}
coarse_ne++;
coarse_to_ref_type.SetSize(coarse_ne);
coarse_to_fine.SetDims(coarse_ne, fine_ne);
Array<int> cf_i(coarse_to_fine.GetI(), coarse_ne+1);
Array<Pair<int,int> > cf_j(fine_ne);
cf_i = 0;
for (int i = 0; i < fine_ne; i++)
{
cf_i[cft.embeddings[i].parent+1]++;
}
cf_i.PartialSum();
MFEM_ASSERT(cf_i.Last() == cf_j.Size(), "internal error");
for (int i = 0; i < fine_ne; i++)
{
const Embedding &e = cft.embeddings[i];
cf_j[cf_i[e.parent]].one = e.matrix; // used as sort key below
cf_j[cf_i[e.parent]].two = i;
cf_i[e.parent]++;
}
std::copy_backward(cf_i.begin(), cf_i.end()-1, cf_i.end());
cf_i[0] = 0;
for (int i = 0; i < coarse_ne; i++)
{
std::sort(&cf_j[cf_i[i]], cf_j.GetData() + cf_i[i+1]);
}
for (int i = 0; i < fine_ne; i++)
{
coarse_to_fine.GetJ()[i] = cf_j[i].two;
}
using std::map;
using std::pair;
map<RefType,int> ref_type_map;
for (int i = 0; i < coarse_ne; i++)
{
const int num_children = cf_i[i+1]-cf_i[i];
MFEM_ASSERT(num_children > 0, "");
const int fine_el = cf_j[cf_i[i]].two;
// Assuming the coarse and the fine elements have the same geometry:
const Geometry::Type geom = fine_mesh.GetElementBaseGeometry(fine_el);
const RefType ref_type(geom, num_children, &cf_j[cf_i[i]]);
pair<map<RefType,int>::iterator,bool> res =
ref_type_map.insert(
pair<const RefType,int>(ref_type, (int)ref_type_map.size()));
coarse_to_ref_type[i] = res.first->second;
}
ref_type_to_matrix.MakeI((int)ref_type_map.size());
ref_type_to_geom.SetSize((int)ref_type_map.size());
for (map<RefType,int>::iterator it = ref_type_map.begin();
it != ref_type_map.end(); ++it)
{
ref_type_to_matrix.AddColumnsInRow(it->second, it->first.num_children);
ref_type_to_geom[it->second] = it->first.geom;
}
ref_type_to_matrix.MakeJ();
for (map<RefType,int>::iterator it = ref_type_map.begin();
it != ref_type_map.end(); ++it)
{
const RefType &rt = it->first;
for (int j = 0; j < rt.num_children; j++)
{
ref_type_to_matrix.AddConnection(it->second, rt.children[j].one);
}
}
ref_type_to_matrix.ShiftUpI();
}
} // namespace internal
/// TODO: Implement DofTransformation support
FiniteElementSpace::DerefinementOperator::DerefinementOperator(
const FiniteElementSpace *f_fes, const FiniteElementSpace *c_fes,
@@ -1778,8 +2072,9 @@ FiniteElementSpace::DerefinementOperator::DerefinementOperator(
}
Table ref_type_to_matrix;
rtrans.GetCoarseToFineMap(*f_mesh, coarse_to_fine, coarse_to_ref_type,
ref_type_to_matrix, ref_type_to_geom);
internal::GetCoarseToFineMap(rtrans, *f_mesh, coarse_to_fine,
coarse_to_ref_type, ref_type_to_matrix,
ref_type_to_geom);
MFEM_ASSERT(coarse_to_fine.Size() == c_fes->GetNE(), "");
const int total_ref_types = ref_type_to_geom.Size();
+26
View File
@@ -778,6 +778,19 @@ public:
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_vdofs,
int component = -1) const;
/** @brief Get a list of essential true dofs, ess_tdof_list, corresponding to the
boundary attributes marked in the array bdr_attr_is_ess.
For spaces with 'vdim' > 1, the 'component' parameter can be used
@@ -786,6 +799,19 @@ public:
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set index. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set name. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_tdof_list,
int component = -1);
/** @brief Get a list of all boundary true dofs, @a boundary_dofs. For spaces
with 'vdim' > 1, the 'component' parameter can be used to restricts the
marked tDOFs to the specified component. Equivalent to
+25 -6
View File
@@ -96,6 +96,7 @@ double NonlinearForm::GetGridFunctionEnergy(const Vector &x) const
Vector el_x;
const FiniteElement *fe;
ElementTransformation *T;
DofTransformation *doftrans;
double energy = 0.0;
if (dnfi.Size())
@@ -103,9 +104,10 @@ double NonlinearForm::GetGridFunctionEnergy(const Vector &x) const
for (int i = 0; i < fes->GetNE(); i++)
{
fe = fes->GetFE(i);
fes->GetElementVDofs(i, vdofs);
doftrans = fes->GetElementVDofs(i, vdofs);
T = fes->GetElementTransformation(i);
x.GetSubVector(vdofs, el_x);
if (doftrans) {doftrans->InvTransformPrimal(el_x); }
for (int k = 0; k < dnfi.Size(); k++)
{
energy += dnfi[k]->GetElementEnergy(*fe, *T, el_x);
@@ -166,6 +168,7 @@ void NonlinearForm::Mult(const Vector &x, Vector &y) const
Vector el_x, el_y;
const FiniteElement *fe;
ElementTransformation *T;
DofTransformation *doftrans;
Mesh *mesh = fes->GetMesh();
py = 0.0;
@@ -175,12 +178,14 @@ void NonlinearForm::Mult(const Vector &x, Vector &y) const
for (int i = 0; i < fes->GetNE(); i++)
{
fe = fes->GetFE(i);
fes->GetElementVDofs(i, vdofs);
doftrans = fes->GetElementVDofs(i, vdofs);
T = fes->GetElementTransformation(i);
px.GetSubVector(vdofs, el_x);
if (doftrans) {doftrans->InvTransformPrimal(el_x); }
for (int k = 0; k < dnfi.Size(); k++)
{
dnfi[k]->AssembleElementVector(*fe, *T, el_x, el_y);
if (doftrans) {doftrans->TransformDual(el_y); }
py.AddElementVector(vdofs, el_y);
}
}
@@ -302,6 +307,7 @@ Operator &NonlinearForm::GetGradient(const Vector &x) const
DenseMatrix elmat;
const FiniteElement *fe;
ElementTransformation *T;
DofTransformation *doftrans;
Mesh *mesh = fes->GetMesh();
const Vector &px = Prolongate(x);
@@ -319,12 +325,14 @@ Operator &NonlinearForm::GetGradient(const Vector &x) const
for (int i = 0; i < fes->GetNE(); i++)
{
fe = fes->GetFE(i);
fes->GetElementVDofs(i, vdofs);
doftrans = fes->GetElementVDofs(i, vdofs);
T = fes->GetElementTransformation(i);
px.GetSubVector(vdofs, el_x);
if (doftrans) {doftrans->InvTransformPrimal(el_x); }
for (int k = 0; k < dnfi.Size(); k++)
{
dnfi[k]->AssembleElementGrad(*fe, *T, el_x, elmat);
if (doftrans) { doftrans->TransformDual(elmat); }
Grad->AddSubMatrix(vdofs, vdofs, elmat, skip_zeros);
// Grad->AddSubMatrix(vdofs, vdofs, elmat, 1);
}
@@ -583,6 +591,7 @@ double BlockNonlinearForm::GetEnergyBlocked(const BlockVector &bx) const
Array<const Vector *> el_x_const(fes.Size());
Array<const FiniteElement *> fe(fes.Size());
ElementTransformation *T;
DofTransformation *doftrans;
double energy = 0.0;
for (int i=0; i<fes.Size(); ++i)
@@ -598,8 +607,9 @@ double BlockNonlinearForm::GetEnergyBlocked(const BlockVector &bx) const
for (int s=0; s<fes.Size(); ++s)
{
fe[s] = fes[s]->GetFE(i);
fes[s]->GetElementVDofs(i, *vdofs[s]);
doftrans = fes[s]->GetElementVDofs(i, *vdofs[s]);
bx.GetBlock(s).GetSubVector(*vdofs[s], *el_x[s]);
if (doftrans) {doftrans->InvTransformPrimal(*el_x[s]); }
}
for (int k = 0; k < dnfi.Size(); ++k)
@@ -645,6 +655,7 @@ void BlockNonlinearForm::MultBlocked(const BlockVector &bx,
Array<const FiniteElement *> fe(fes.Size());
Array<const FiniteElement *> fe2(fes.Size());
ElementTransformation *T;
Array<DofTransformation *> doftrans(fes.Size()); doftrans = nullptr;
by.UseDevice(true);
by = 0.0;
@@ -664,9 +675,10 @@ void BlockNonlinearForm::MultBlocked(const BlockVector &bx,
T = fes[0]->GetElementTransformation(i);
for (int s = 0; s < fes.Size(); ++s)
{
fes[s]->GetElementVDofs(i, *(vdofs[s]));
doftrans[s] = fes[s]->GetElementVDofs(i, *(vdofs[s]));
fe[s] = fes[s]->GetFE(i);
bx.GetBlock(s).GetSubVector(*(vdofs[s]), *el_x[s]);
if (doftrans[s]) {doftrans[s]->InvTransformPrimal(*el_x[s]); }
}
for (int k = 0; k < dnfi.Size(); ++k)
@@ -677,6 +689,7 @@ void BlockNonlinearForm::MultBlocked(const BlockVector &bx,
for (int s=0; s<fes.Size(); ++s)
{
if (el_y[s]->Size() == 0) { continue; }
if (doftrans[s]) {doftrans[s]->TransformDual(*el_y[s]); }
by.GetBlock(s).AddElementVector(*(vdofs[s]), *el_y[s]);
}
}
@@ -844,6 +857,7 @@ void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx) const
Array<const FiniteElement *>fe(fes.Size());
Array<const FiniteElement *>fe2(fes.Size());
ElementTransformation * T;
Array<DofTransformation *> doftrans(fes.Size()); doftrans = nullptr;
for (int i=0; i<fes.Size(); ++i)
{
@@ -880,8 +894,9 @@ void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx) const
for (int s = 0; s < fes.Size(); ++s)
{
fe[s] = fes[s]->GetFE(i);
fes[s]->GetElementVDofs(i, *vdofs[s]);
doftrans[s] = fes[s]->GetElementVDofs(i, *vdofs[s]);
bx.GetBlock(s).GetSubVector(*vdofs[s], *el_x[s]);
if (doftrans[s]) {doftrans[s]->InvTransformPrimal(*el_x[s]); }
}
for (int k = 0; k < dnfi.Size(); ++k)
@@ -893,6 +908,10 @@ void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx) const
for (int l=0; l<fes.Size(); ++l)
{
if (elmats(j,l)->Height() == 0) { continue; }
if (doftrans[j] || doftrans[l])
{
TransformDual(doftrans[j], doftrans[l], *elmats(j,l));
}
Grads(j,l)->AddSubMatrix(*vdofs[j], *vdofs[l],
*elmats(j,l), skip_zeros);
}
+47
View File
@@ -23,6 +23,8 @@
#include <limits>
#include <list>
using namespace std;
namespace mfem
{
@@ -1018,6 +1020,30 @@ void ParFiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
}
}
void ParFiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_dofs,
int component) const
{
FiniteElementSpace::GetEssentialVDofs(type, set_index, ess_dofs, component);
if (Conforming())
{
// Make sure that processors without boundary elements mark
// their boundary dofs (if they have any).
Synchronize(ess_dofs);
}
}
void ParFiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_vdofs,
int component) const
{
GetEssentialVDofs(type, pmesh->ent_sets->GetSetIndex(type, set_name),
ess_vdofs, component);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(const Array<int>
&bdr_attr_is_ess,
Array<int> &ess_tdof_list,
@@ -1047,6 +1073,27 @@ void ParFiniteElementSpace::GetEssentialTrueDofs(const Array<int>
MarkerToList(true_ess_dofs, ess_tdof_list);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_tdof_list,
int component)
{
Array<int> ess_dofs, true_ess_dofs;
GetEssentialVDofs(type, set_index, ess_dofs, component);
GetRestrictionMatrix()->BooleanMult(ess_dofs, true_ess_dofs);
MarkerToList(true_ess_dofs, ess_tdof_list);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_tdof_list,
int component)
{
GetEssentialTrueDofs(type, pmesh->ent_sets->GetSetIndex(type, set_name),
ess_tdof_list, component);
}
int ParFiniteElementSpace::GetLocalTDofNumber(int ldof) const
{
if (Nonconforming())
+26
View File
@@ -355,12 +355,38 @@ public:
Array<int> &ess_dofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_vdofs,
int component = -1) const;
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
boundary attributes marked in the array bdr_attr_is_ess. */
virtual void GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set index. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set name. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_tdof_list,
int component = -1);
/** If the given ldof is owned by the current processor, return its local
tdof number, otherwise return -1 */
int GetLocalTDofNumber(int ldof) const;
-2
View File
@@ -40,8 +40,6 @@ StaticCondensation::StaticCondensation(FiniteElementSpace *fespace)
#endif
S = S_e = NULL;
symm = false;
A_data.Reset();
A_ipiv.Reset();
Array<int> vdofs;
const int NE = fes->GetNE();
+323 -38
View File
@@ -2326,6 +2326,8 @@ TMOP_Integrator::~TMOP_Integrator()
{
delete lim_func;
delete zeta;
delete sigma;
delete sigma_bar;
for (int i = 0; i < ElemDer.Size(); i++)
{
delete ElemDer[i];
@@ -2393,6 +2395,87 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &z0,
}
#endif
void TMOP_Integrator::EnableSurfaceFitting(const GridFunction &s0,
const Array<bool> &smarker,
Coefficient &coeff,
AdaptivityEvaluator &ae)
{
delete sigma;
sigma = new GridFunction(s0);
sigma_marker = &smarker;
coeff_sigma = &coeff;
sigma_eval = &ae;
// Compute the restricted sigma.
delete sigma_bar;
sigma_bar = new GridFunction(*sigma);
for (int i = 0; i < sigma_marker->Size(); i++)
{
if ((*sigma_marker)[i] == false) { (*sigma_bar)(i) = 0.0; }
}
sigma_eval->SetSerialMetaInfo(*s0.FESpace()->GetMesh(),
*s0.FESpace()->FEColl(), 1);
sigma_eval->SetInitialField
(*sigma->FESpace()->GetMesh()->GetNodes(), *sigma);
}
#ifdef MFEM_USE_MPI
void TMOP_Integrator::EnableSurfaceFitting(const ParGridFunction &s0,
const Array<bool> &smarker,
Coefficient &coeff,
AdaptivityEvaluator &ae)
{
delete sigma;
sigma = new GridFunction(s0);
sigma_marker = &smarker;
coeff_sigma = &coeff;
sigma_eval = &ae;
// Compute the restricted sigma.
delete sigma_bar;
sigma_bar = new GridFunction(*sigma);
for (int i = 0; i < sigma_marker->Size(); i++)
{
if ((*sigma_marker)[i] == false) { (*sigma_bar)(i) = 0.0; }
}
sigma_eval->SetParMetaInfo(*s0.ParFESpace()->GetParMesh(),
*s0.ParFESpace()->FEColl(), 1);
sigma_eval->SetInitialField
(*sigma->FESpace()->GetMesh()->GetNodes(), *sigma);
}
#endif
void TMOP_Integrator::GetSurfaceFittingErrors(double &err_avg, double &err_max)
{
MFEM_VERIFY(sigma, "Surface fitting has not been enabled.");
int loc_cnt = 0;
double loc_max = 0.0, loc_sum = 0.0;
for (int i = 0; i < sigma_marker->Size(); i++)
{
if ((*sigma_marker)[i] == true)
{
loc_cnt++;
loc_max = std::max(loc_max, std::abs((*sigma_bar)(i)));
loc_sum += std::abs((*sigma_bar)(i));
}
}
err_avg = loc_sum / loc_cnt;
err_max = loc_max;
#ifdef MFEM_USE_MPI
if (targetC->Parallel() == false) { return; }
int glob_cnt;
MPI_Comm comm = targetC->GetComm();
MPI_Allreduce(&loc_max, &err_max, 1, MPI_DOUBLE, MPI_MAX, comm);
MPI_Allreduce(&loc_cnt, &glob_cnt, 1, MPI_INT, MPI_SUM, comm);
MPI_Allreduce(&loc_sum, &err_avg, 1, MPI_DOUBLE, MPI_SUM, comm);
err_avg = err_avg / glob_cnt;
#endif
}
void TMOP_Integrator::UpdateAfterMeshTopologyChange()
{
if (zeta)
@@ -2419,16 +2502,19 @@ void TMOP_Integrator::ParUpdateAfterMeshTopologyChange()
}
#endif
double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun)
{
const int dof = el.GetDof(), dim = el.GetDim();
const int el_id = T.ElementNo;
double energy;
// No adaptive limiting terms if this is a FD computation.
// No adaptive limiting / surface fitting terms if the function is called
// as part of a FD derivative computation (because we include the exact
// derivatives of these terms in FD computations).
const bool adaptive_limiting = (zeta && fd_call_flag == false);
const bool surface_fit = (sigma && fd_call_flag == false);
DSh.SetSize(dof, dim);
Jrt.SetSize(dim);
@@ -2440,7 +2526,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
energy = 0.0;
DenseTensor Jtr(dim, dim, ir.GetNPoints());
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
targetC->ComputeElementTargets(el_id, el, ir, elfun, Jtr);
// Limited case.
Vector shape, p, p0, d_vals;
@@ -2453,11 +2539,11 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
pos0.SetSize(dof, dim);
Vector pos0V(pos0.Data(), dof * dim);
Array<int> pos_dofs;
nodes0->FESpace()->GetElementVDofs(T.ElementNo, pos_dofs);
nodes0->FESpace()->GetElementVDofs(el_id, pos_dofs);
nodes0->GetSubVector(pos_dofs, pos0V);
if (lim_dist)
{
lim_dist->GetValues(T.ElementNo, ir, d_vals);
lim_dist->GetValues(el_id, ir, d_vals);
}
else
{
@@ -2467,11 +2553,11 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
// Define ref->physical transformation, when a Coefficient is specified.
IsoparametricTransformation *Tpr = NULL;
if (coeff1 || coeff0 || adaptive_limiting)
if (coeff1 || coeff0 || adaptive_limiting || surface_fit)
{
Tpr = new IsoparametricTransformation;
Tpr->SetFE(&el);
Tpr->ElementNo = T.ElementNo;
Tpr->ElementNo = el_id;
Tpr->ElementType = ElementTransformation::ELEMENT;
Tpr->Attribute = T.Attribute;
Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
@@ -2487,13 +2573,17 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
Vector zeta_q, zeta0_q;
if (adaptive_limiting)
{
zeta->GetValues(T.ElementNo, ir, zeta_q);
zeta_0->GetValues(T.ElementNo, ir, zeta0_q);
zeta->GetValues(el_id, ir, zeta_q);
zeta_0->GetValues(el_id, ir, zeta0_q);
}
Vector sigma_bar_q;
if (surface_fit) { sigma_bar->GetValues(el_id, ir, sigma_bar_q); }
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
const DenseMatrix &Jtr_i = Jtr(i);
metric->SetTargetJacobian(Jtr_i);
CalcInverse(Jtr_i, Jrt);
@@ -2516,16 +2606,24 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
coeff0->Eval(*Tpr, ip);
}
// Contribution from the adaptive limiting term.
if (adaptive_limiting)
{
const double diff = zeta_q(i) - zeta0_q(i);
val += coeff_zeta->Eval(*Tpr, ip) * lim_normal * diff * diff;
}
// Contribution from the surface fitting term.
if (surface_fit)
{
val += coeff_sigma->Eval(*Tpr, ip) * sigma_normal *
sigma_bar_q(i) * sigma_bar_q(i);
}
energy += weight * val;
}
delete Tpr;
delete Tpr;
return energy;
}
@@ -2747,7 +2845,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
// Define ref->physical transformation, when a Coefficient is specified.
IsoparametricTransformation *Tpr = NULL;
if (coeff1 || coeff0 || zeta || exact_action)
if (coeff1 || coeff0 || zeta || sigma || exact_action)
{
Tpr = new IsoparametricTransformation;
Tpr->SetFE(&el);
@@ -2829,7 +2927,8 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
}
}
if (zeta) { AssembleElemVecAdaptLim(el, weights, *Tpr, ir, PMatO); }
if (zeta) { AssembleElemVecAdaptLim(el, *Tpr, ir, weights, PMatO); }
if (sigma) { AssembleElemVecSurfFit(el, *Tpr, ir, weights, PMatO); }
delete Tpr;
}
@@ -2881,7 +2980,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
// Define ref->physical transformation, when a Coefficient is specified.
IsoparametricTransformation *Tpr = NULL;
if (coeff1 || coeff0 || zeta)
if (coeff1 || coeff0 || zeta || sigma)
{
Tpr = new IsoparametricTransformation;
Tpr->SetFE(&el);
@@ -2935,21 +3034,20 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
}
}
if (zeta) { AssembleElemGradAdaptLim(el, weights, *Tpr, ir, elmat); }
if (zeta) { AssembleElemGradAdaptLim(el, *Tpr, ir, weights, elmat); }
if (sigma) { AssembleElemGradSurfFit(el, *Tpr, ir, weights, elmat); }
delete Tpr;
}
void TMOP_Integrator::AssembleElemVecAdaptLim(const FiniteElement &el,
const Vector &weights,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir,
const Vector &weights,
DenseMatrix &mat)
{
if (zeta == NULL) { return; }
const int dof = el.GetDof(), dim = el.GetDim();
Vector shape(dof), zeta_e, zeta_q, zeta0_q;
const int dof = el.GetDof(), dim = el.GetDim(), nqp = weights.Size();
Vector shape(dof), zeta_e, zeta_q, zeta0_q(nqp);
Array<int> dofs;
zeta->FESpace()->GetElementDofs(Tpr.ElementNo, dofs);
@@ -2967,7 +3065,6 @@ void TMOP_Integrator::AssembleElemVecAdaptLim(const FiniteElement &el,
Vector zeta_grad_q(dim);
const int nqp = weights.Size();
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir.IntPoint(q);
@@ -2980,15 +3077,13 @@ void TMOP_Integrator::AssembleElemVecAdaptLim(const FiniteElement &el,
}
void TMOP_Integrator::AssembleElemGradAdaptLim(const FiniteElement &el,
const Vector &weights,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir,
const Vector &weights,
DenseMatrix &mat)
{
if (zeta == NULL) { return; }
const int dof = el.GetDof(), dim = el.GetDim();
Vector shape(dof), zeta_e, zeta_q, zeta0_q;
const int dof = el.GetDof(), dim = el.GetDim(), nqp = weights.Size();
Vector shape(dof), zeta_e, zeta_q, zeta0_q(nqp);
Array<int> dofs;
zeta->FESpace()->GetElementDofs(Tpr.ElementNo, dofs);
@@ -3014,7 +3109,6 @@ void TMOP_Integrator::AssembleElemGradAdaptLim(const FiniteElement &el,
Vector zeta_grad_q(dim);
DenseMatrix zeta_grad_grad_q(dim, dim);
const int nqp = weights.Size();
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir.IntPoint(q);
@@ -3043,6 +3137,169 @@ void TMOP_Integrator::AssembleElemGradAdaptLim(const FiniteElement &el,
}
}
void TMOP_Integrator::AssembleElemVecSurfFit(const FiniteElement &el_x,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir_quad,
const Vector &weights,
DenseMatrix &mat)
{
const int el_id = Tpr.ElementNo;
const FiniteElement &el_s = *sigma->FESpace()->GetFE(el_id);
const int dof_x = el_x.GetDof(), dim = el_x.GetDim(),
dof_s = el_s.GetDof(), nqp = ir_quad.GetNPoints();
Vector sigma_e, sigma_bar_e;
Vector sigma_bar_q;
Array<int> dofs;
sigma->FESpace()->GetElementDofs(el_id, dofs);
sigma->GetSubVector(dofs, sigma_e);
sigma_bar->GetSubVector(dofs, sigma_bar_e);
sigma_bar->GetValues(el_id, ir_quad, sigma_bar_q);
// Project the gradient of sigma in the same space.
// The FE coefficients of the gradient go in sigma_grad_e.
DenseMatrix sigma_grad_e(dof_s, dim);
DenseMatrix grad_phys; // This will be (dof x dim, dof).
el_s.ProjectGrad(el_s, Tpr, grad_phys);
Vector grad_ptr(sigma_grad_e.GetData(), dof_s * dim);
grad_phys.Mult(sigma_e, grad_ptr);
// Gradient of sigma_bar.
DenseMatrix sigma_bar_grad_e(dof_s, dim);
Vector ptr(sigma_bar_grad_e.GetData(), dof_s * dim);
grad_phys.Mult(sigma_bar_e, ptr);
Vector shape_x(dof_x), shape_s(dof_s), grad_q(dim);
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir_quad.IntPoint(q);
Tpr.SetIntPoint(&ip);
el_s.CalcShape(ip, shape_s);
// Grad of sigma_bar at the current quad point.
sigma_bar_grad_e.MultTranspose(shape_s, grad_q);
for (int s = 0; s < dof_s; s++)
{
if ((*sigma_marker)[dofs[s]] == false) { continue; }
for (int d = 0; d < dim; d++)
{
// Grad of sigma must be taken at the active DOFs.
grad_q(d) += sigma_grad_e(s, d) * shape_s(s);
}
}
grad_q *= 2.0 * sigma_normal * coeff_sigma->Eval(Tpr, ip) *
weights(q) * sigma_bar_q(q);
el_x.CalcShape(ip, shape_x);
AddMultVWt(shape_x, grad_q, mat);
}
}
void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir_quad,
const Vector &weights,
DenseMatrix &mat)
{
const int el_id = Tpr.ElementNo, nqp = ir_quad.GetNPoints();
const FiniteElement &el_s = *sigma->FESpace()->GetFE(el_id);
const int dof_x = el_x.GetDof(), dim = el_x.GetDim(),
dof_s = el_s.GetDof();
Vector sigma_e, sigma_bar_e;
Vector sigma_bar_q;
Array<int> dofs;
sigma->FESpace()->GetElementDofs(el_id, dofs);
sigma->GetSubVector(dofs, sigma_e);
sigma_bar->GetSubVector(dofs, sigma_bar_e);
sigma_bar->GetValues(el_id, ir_quad, sigma_bar_q);
// Project the gradient of sigma in the same space.
// The FE coefficients of the gradient go in sigma_grad_e.
DenseMatrix sigma_grad_e(dof_s, dim);
DenseMatrix grad_phys; // This will be (dof x dim, dof).
el_s.ProjectGrad(el_s, Tpr, grad_phys);
Vector grad_ptr(sigma_grad_e.GetData(), dof_s * dim);
grad_phys.Mult(sigma_e, grad_ptr);
// Gradient of sigma_bar.
DenseMatrix sigma_bar_grad_e(dof_s, dim);
Vector ptr(sigma_bar_grad_e.GetData(), dof_s * dim);
grad_phys.Mult(sigma_bar_e, ptr);
// Project the gradient of each gradient of sigma in the same space.
// The FE coefficients of the second derivatives go in sigma_grad_grad_e.
DenseMatrix sigma_grad_grad_e(dof_s * dim, dim);
Mult(grad_phys, sigma_grad_e, sigma_grad_grad_e);
// Project the gradient of each gradient of sigma in the same space.
// The FE coefficients of the second derivatives go in sigma_grad_grad_e.
DenseMatrix sigma_bar_grad_grad_e(dof_s * dim, dim);
Mult(grad_phys, sigma_bar_grad_e, sigma_bar_grad_grad_e);
// Reshape to be more convenient later (no change in the data).
sigma_bar_grad_grad_e.SetSize(dof_s, dim * dim);
DenseMatrix sigma_bar_grad_grad_q(dim, dim);
Vector shape_x(dof_x), shape_s(dof_s), sigma_bar_grad_q(dim);
DenseMatrix dshape_s(dof_s, dim);
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir_quad.IntPoint(q);
Tpr.SetIntPoint(&ip);
el_s.CalcShape(ip, shape_s);
el_x.CalcShape(ip, shape_x);
// We could reuse grad_phys, but this is more accurate.
el_s.CalcPhysDShape(Tpr, dshape_s);
// Grad of sigma_bar at the current quad point.
sigma_bar_grad_e.MultTranspose(shape_s, sigma_bar_grad_q);
// Grad-grad of sigma_bar at the current quad point.
Vector gg_ptr(sigma_bar_grad_grad_q.GetData(), dim * dim);
sigma_bar_grad_grad_e.MultTranspose(shape_s, gg_ptr);
// Loops over the local matrix.
const double w = 2.0 * sigma_normal *
coeff_sigma->Eval(Tpr, ip) * weights(q);
for (int i = 0; i < dof_x * dim; i++)
{
const int idof = i % dof_x, idim = i / dof_x;
for (int j = 0; j <= i; j++)
{
const int jdof = j % dof_x, jdim = j / dof_x;
double Di = sigma_bar_grad_q(idim),
Dj = sigma_bar_grad_q(jdim),
DD = sigma_bar_grad_grad_q(idim, jdim);
for (int s = 0; s < dof_s; s++)
{
if ((*sigma_marker)[dofs[s]] == false) { continue; }
Di += sigma_grad_e(s, idim) * shape_s(s);
Dj += sigma_grad_e(s, jdim) * shape_s(s);
DD += sigma_grad_e(s, idim) * dshape_s(s, jdim) +
sigma_grad_grad_e(dof_s * idim + s, jdim) * shape_s(s) +
sigma_grad_e(s, jdim) * dshape_s(s, idim);
}
const double entry = w * (Di * Dj + sigma_bar_q(q) * DD) *
shape_x(idof) * shape_x(jdof);
mat(i, j) += entry;
if (i != j) { mat(j, i) += entry; }
}
}
}
}
double TMOP_Integrator::GetFDDerivative(const FiniteElement &el,
ElementTransformation &T,
Vector &elfun, const int dofidx,
@@ -3103,8 +3360,8 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el,
}
fd_call_flag = false;
// Contributions from adaptive limiting (exact derivatives).
if (zeta)
// Contributions from adaptive limiting, surface fitting (exact derivatives).
if (zeta || sigma)
{
const IntegrationRule &ir = ActionIntegrationRule(el);
const int nqp = ir.GetNPoints();
@@ -3125,7 +3382,8 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el,
}
PMatO.UseExternalData(elvect.GetData(), dof, dim);
AssembleElemVecAdaptLim(el, weights, Tpr, ir, PMatO);
if (zeta) { AssembleElemVecAdaptLim(el, Tpr, ir, weights, PMatO); }
if (sigma) { AssembleElemVecSurfFit(el, Tpr, ir, weights, PMatO); }
}
}
@@ -3200,7 +3458,7 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
fd_call_flag = false;
// Contributions from adaptive limiting.
if (zeta)
if (zeta || sigma)
{
const IntegrationRule &ir = GradientIntegrationRule(el);
const int nqp = ir.GetNPoints();
@@ -3220,35 +3478,41 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
weights(q) = ir.IntPoint(q).weight * Jtr(q).Det();
}
AssembleElemGradAdaptLim(el, weights, Tpr, ir, elmat);
if (zeta) { AssembleElemGradAdaptLim(el, Tpr, ir, weights, elmat); }
if (sigma) { AssembleElemGradSurfFit(el, Tpr, ir, weights, elmat); }
}
}
void TMOP_Integrator::EnableNormalization(const GridFunction &x)
{
ComputeNormalizationEnergies(x, metric_normal, lim_normal);
ComputeNormalizationEnergies(x, metric_normal, lim_normal, sigma_normal);
metric_normal = 1.0 / metric_normal;
lim_normal = 1.0 / lim_normal;
//if (sigma) { sigma_normal = 1.0 / sigma_normal; }
if (sigma) { sigma_normal = lim_normal; }
}
#ifdef MFEM_USE_MPI
void TMOP_Integrator::ParEnableNormalization(const ParGridFunction &x)
{
double loc[2];
ComputeNormalizationEnergies(x, loc[0], loc[1]);
double rdc[2];
MPI_Allreduce(loc, rdc, 2, MPI_DOUBLE, MPI_SUM, x.ParFESpace()->GetComm());
double loc[3];
ComputeNormalizationEnergies(x, loc[0], loc[1], loc[2]);
double rdc[3];
MPI_Allreduce(loc, rdc, 3, MPI_DOUBLE, MPI_SUM, x.ParFESpace()->GetComm());
metric_normal = 1.0 / rdc[0];
lim_normal = 1.0 / rdc[1];
// if (sigma) { sigma_normal = 1.0 / rdc[2]; }
if (sigma) { sigma_normal = lim_normal; }
}
#endif
void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x,
double &metric_energy,
double &lim_energy)
double &lim_energy,
double &sigma_energy)
{
Array<int> vdofs;
Vector x_vals;
Vector x_vals, sigma_bar_q;
const FiniteElementSpace* const fes = x.FESpace();
const int dim = fes->GetMesh()->Dimension();
@@ -3258,6 +3522,7 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x,
metric_energy = 0.0;
lim_energy = 0.0;
sigma_energy = 0.0;
for (int i = 0; i < fes->GetNE(); i++)
{
const FiniteElement *fe = fes->GetFE(i);
@@ -3273,6 +3538,8 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x,
targetC->ComputeElementTargets(i, *fe, ir, x_vals, Jtr);
if (sigma) { sigma_bar->GetValues(i, ir, sigma_bar_q); }
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir.IntPoint(q);
@@ -3286,8 +3553,15 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x,
metric_energy += weight * metric->EvalW(Jpt);
lim_energy += weight;
// Normalization of the surface fitting term.
if (sigma)
{
sigma_energy += weight * sigma_bar_q(q) * sigma_bar_q(q);
}
}
}
if (targetC->ContainsVolumeInfo() == false)
{
// Special case when the targets don't contain volumetric information.
@@ -3336,6 +3610,17 @@ void TMOP_Integrator::UpdateAfterMeshPositionChange(const Vector &new_x)
}
// Update zeta if adaptive limiting is enabled.
if (zeta) { adapt_eval->ComputeAtNewPosition(new_x, *zeta); }
// Update sigma if surface fitting is enabled.
if (sigma)
{
sigma_eval->ComputeAtNewPosition(new_x, *sigma);
// Update the restricted sigma.
for (int i = 0; i < sigma_marker->Size(); i++)
{
(*sigma_bar)(i) = ((*sigma_marker)[i] == true) ? (*sigma)(i) : 0.0;
}
}
}
void TMOP_Integrator::ComputeFDh(const Vector &x, const FiniteElementSpace &fes)
+105 -12
View File
@@ -592,6 +592,27 @@ public:
virtual int Id() const { return 321; }
};
/// 3D barrier Shape+Size (VS) metric (polyconvex).
class TMOP_Metric_328 : public TMOP_Combo_QualityMetric
{
protected:
mutable InvariantsEvaluator2D<double> ie;
double gamma;
TMOP_QualityMetric *sh_metric, *sz_metric;
public:
TMOP_Metric_328(double gamma_) : gamma(gamma_),
sh_metric(new TMOP_Metric_301),
sz_metric(new TMOP_Metric_316)
{
// (1-gamma) mu_301 + gamma mu_316
AddQualityMetric(sh_metric, 1.-gamma_);
AddQualityMetric(sz_metric, gamma_);
}
virtual ~TMOP_Metric_328() { delete sh_metric; delete sz_metric; }
};
/// 3D barrier Shape+Size (VS) metric (polyconvex).
class TMOP_Metric_332 : public TMOP_Combo_QualityMetric
{
@@ -619,6 +640,7 @@ public:
class TMOP_Metric_333 : public TMOP_Combo_QualityMetric
{
protected:
mutable InvariantsEvaluator2D<double> ie;
double gamma;
TMOP_QualityMetric *sh_metric, *sz_metric;
@@ -632,12 +654,30 @@ public:
AddQualityMetric(sz_metric, gamma_);
}
virtual int Id() const { return 333; }
double GetGamma() const { return gamma; }
virtual ~TMOP_Metric_333() { delete sh_metric; delete sz_metric; }
};
/// 3D barrier Shape+Size (VS) metric (polyconvex).
class TMOP_Metric_334 : public TMOP_Combo_QualityMetric
{
protected:
mutable InvariantsEvaluator2D<double> ie;
double gamma;
TMOP_QualityMetric *sh_metric, *sz_metric;
public:
TMOP_Metric_334(double gamma_) : gamma(gamma_),
sh_metric(new TMOP_Metric_303),
sz_metric(new TMOP_Metric_316)
{
// (1-gamma) mu_303 + gamma mu_316
AddQualityMetric(sh_metric, 1.-gamma_);
AddQualityMetric(sz_metric, gamma_);
}
virtual ~TMOP_Metric_334() { delete sh_metric; delete sz_metric; }
};
/// Shifted barrier form of 3D metric 16 (volume, ideal barrier metric), 3D
class TMOP_Metric_352 : public TMOP_QualityMetric
{
@@ -897,9 +937,6 @@ protected:
#ifdef MFEM_USE_MPI
MPI_Comm comm;
bool Parallel() const { return (comm != MPI_COMM_NULL); }
#else
bool Parallel() const { return false; }
#endif
// should be called only if avg_volume == 0.0, i.e. avg_volume is not
@@ -936,6 +973,13 @@ public:
#endif
virtual ~TargetConstructor() { }
#ifdef MFEM_USE_MPI
bool Parallel() const { return (comm != MPI_COMM_NULL); }
MPI_Comm GetComm() const { return comm; }
#else
bool Parallel() const { return false; }
#endif
/** @brief Set the nodes to be used in the target-matrix construction.
This method should be called every time the target nodes are updated
@@ -1296,6 +1340,13 @@ protected:
Coefficient *coeff_zeta; // Not owned.
AdaptivityEvaluator *adapt_eval; // Not owned.
// Surface fitting.
GridFunction *sigma, *sigma_bar; // Owned. Updated by sigma_eval.
const Array<bool> *sigma_marker; // Not owned.
Coefficient *coeff_sigma; // Not owned.
AdaptivityEvaluator *sigma_eval; // Not owned.
double sigma_normal;
DiscreteAdaptTC *discr_tc;
// Parameters for FD-based Gradient & Hessian calculation.
@@ -1364,7 +1415,8 @@ protected:
} PA;
void ComputeNormalizationEnergies(const GridFunction &x,
double &metric_energy, double &lim_energy);
double &metric_energy, double &lim_energy,
double &sigma_energy);
void AssembleElementVectorExact(const FiniteElement &el,
ElementTransformation &T,
@@ -1383,12 +1435,25 @@ protected:
ElementTransformation &T,
const Vector &elfun, DenseMatrix &elmat);
void AssembleElemVecAdaptLim(const FiniteElement &el, const Vector &weights,
void AssembleElemVecAdaptLim(const FiniteElement &el,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir, DenseMatrix &m);
void AssembleElemGradAdaptLim(const FiniteElement &el, const Vector &weights,
const IntegrationRule &ir,
const Vector &weights, DenseMatrix &mat);
void AssembleElemGradAdaptLim(const FiniteElement &el,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir, DenseMatrix &m);
const IntegrationRule &ir,
const Vector &weights, DenseMatrix &m);
// First derivative of the surface fitting term.
void AssembleElemVecSurfFit(const FiniteElement &el_x,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir_quad,
const Vector &weights, DenseMatrix &mat);
// Second derivative of the surface fitting term.
void AssembleElemGradSurfFit(const FiniteElement &el_x,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir_quad,
const Vector &weights, DenseMatrix &mat);
double GetFDDerivative(const FiniteElement &el,
ElementTransformation &T,
@@ -1470,6 +1535,8 @@ public:
nodes0(NULL), coeff0(NULL),
lim_dist(NULL), lim_func(NULL), lim_normal(1.0),
zeta_0(NULL), zeta(NULL), coeff_zeta(NULL), adapt_eval(NULL),
sigma(NULL), sigma_bar(NULL), sigma_marker(NULL), coeff_sigma(NULL),
sigma_eval(NULL), sigma_normal(1.0),
discr_tc(dynamic_cast<DiscreteAdaptTC *>(tc)),
fdflag(false), dxscale(1.0e3), fd_call_flag(false), exact_action(false)
{ PA.enabled = false; }
@@ -1522,7 +1589,7 @@ public:
Adds the term @f$ \int c (z(x) - z_0(x_0))^2 @f$, where z0(x0) is a given
function on the starting mesh, and z(x) is its image on the new mesh.
Minimizing this, means that a node at x0 is allowed to move to a
Minimizing this term means that a node at x0 is allowed to move to a
position x(x0) only if z(x) ~ z0(x0).
Such term can be used for tangential mesh relaxation.
@@ -1537,6 +1604,32 @@ public:
AdaptivityEvaluator &ae);
#endif
/** @brief Fitting of certain DOFs to the zero level set of a function.
Having a level set function s0(x0) on the starting mesh, and a set of
marked nodes (or DOFs), we move these nodes to the zero level set of s0.
If s(x) is the image of s0(x0) on the current mesh, this function adds to
the TMOP functional the term @f$ \int c \bar{s}(x))^2 @f$, where
@f$\bar{s}(x)@f$ is the restriction of s(x) on the aligned DOFs.
Minimizing this term means that a marked node at x0 is allowed to move to
a position x(x0) only if s(x) ~ 0.
Such term can be used for surface fitting and tangential relaxation.
@param[in] s0 The level set function on the initial mesh.
@param[in] smarker Indicates which DOFs will be aligned.
@param[in] coeff Coefficient c for the above integral.
@param[in] ae AdaptivityEvaluator to compute s(x) from s0(x0). */
void EnableSurfaceFitting(const GridFunction &s0,
const Array<bool> &smarker, Coefficient &coeff,
AdaptivityEvaluator &ae);
#ifdef MFEM_USE_MPI
/// Parallel support for surface fitting.
void EnableSurfaceFitting(const ParGridFunction &s0,
const Array<bool> &smarker, Coefficient &coeff,
AdaptivityEvaluator &ae);
#endif
void GetSurfaceFittingErrors(double &err_avg, double &err_max);
/// Update the original/reference nodes used for limiting.
void SetLimitingNodes(const GridFunction &n0) { nodes0 = &n0; }
+8 -6
View File
@@ -394,12 +394,13 @@ bool TMOPDeRefinerEstimator::GetDerefineEnergyForIntegrator(
const CoarseFineTransformations &dtrans =
meshcopy.ncmesh->GetDerefinementTransforms();
Table coarse_to_fine;
dtrans.GetCoarseToFineMap(meshcopy, coarse_to_fine);
Table coarse_to_fine;
dtrans.MakeCoarseToFineTable(coarse_to_fine);
Array<int> tabrow;
for (int pe = 0; pe < coarse_to_fine.Size(); pe++)
{
Array<int> tabrow;
coarse_to_fine.GetRow(pe, tabrow);
int nchild = tabrow.Size();
double parent_energy = coarse_energy(pe);
@@ -446,12 +447,13 @@ bool TMOPDeRefinerEstimator::GetDerefineEnergyForIntegrator(
const CoarseFineTransformations &dtrans =
meshcopy.pncmesh->GetDerefinementTransforms();
Table coarse_to_fine;
dtrans.GetCoarseToFineMap(meshcopy, coarse_to_fine);
Table coarse_to_fine;
dtrans.MakeCoarseToFineTable(coarse_to_fine);
Array<int> tabrow;
for (int pe = 0; pe < meshcopy.GetNE(); pe++)
{
Array<int> tabrow;
coarse_to_fine.GetRow(pe, tabrow);
int nchild = tabrow.Size();
double parent_energy = coarse_energy(pe);
+27 -6
View File
@@ -913,7 +913,11 @@ TransferOperator::TransferOperator(const FiniteElementSpace& lFESpace_,
else if (lFESpace_.GetMesh()->GetNE() > 0
&& hFESpace_.GetMesh()->GetNE() > 0
&& dynamic_cast<const TensorBasisElement*>(lFESpace_.GetFE(0))
&& dynamic_cast<const TensorBasisElement*>(hFESpace_.GetFE(0)))
&& dynamic_cast<const TensorBasisElement*>(hFESpace_.GetFE(0))
&& (hFESpace_.FEColl()->GetContType() ==
mfem::FiniteElementCollection::CONTINUOUS ||
hFESpace_.FEColl()->GetContType() ==
mfem::FiniteElementCollection::DISCONTINUOUS))
{
opr = new TensorProductPRefinementTransferOperator(lFESpace_, hFESpace_);
}
@@ -961,8 +965,8 @@ void PRefinementTransferOperator::Mult(const Vector& x, Vector& y) const
for (int i = 0; i < mesh->GetNE(); i++)
{
hFESpace.GetElementDofs(i, h_dofs);
lFESpace.GetElementDofs(i, l_dofs);
DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
DofTransformation * doftrans_l = lFESpace.GetElementDofs(i, l_dofs);
const Geometry::Type geom = mesh->GetElementBaseGeometry(i);
if (geom != cached_geom)
@@ -982,7 +986,15 @@ void PRefinementTransferOperator::Mult(const Vector& x, Vector& y) const
h_dofs.Copy(h_vdofs);
hFESpace.DofsToVDofs(vd, h_vdofs);
x.GetSubVector(l_vdofs, subX);
if (doftrans_l)
{
doftrans_l->InvTransformPrimal(subX);
}
loc_prol.Mult(subX, subY);
if (doftrans_h)
{
doftrans_h->TransformPrimal(subY);
}
y.SetSubVector(h_vdofs, subY);
}
}
@@ -1010,8 +1022,8 @@ void PRefinementTransferOperator::MultTranspose(const Vector& x,
for (int i = 0; i < mesh->GetNE(); i++)
{
hFESpace.GetElementDofs(i, h_dofs);
lFESpace.GetElementDofs(i, l_dofs);
DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
DofTransformation * doftrans_l = lFESpace.GetElementDofs(i, l_dofs);
const Geometry::Type geom = mesh->GetElementBaseGeometry(i);
if (geom != cached_geom)
@@ -1033,6 +1045,10 @@ void PRefinementTransferOperator::MultTranspose(const Vector& x,
hFESpace.DofsToVDofs(vd, h_vdofs);
x.GetSubVector(h_vdofs, subX);
if (doftrans_h)
{
doftrans_h->InvTransformDual(subX);
}
for (int p = 0; p < h_dofs.Size(); ++p)
{
if (processed[lFESpace.DecodeDof(h_dofs[p])])
@@ -1042,6 +1058,10 @@ void PRefinementTransferOperator::MultTranspose(const Vector& x,
}
loc_prol.Mult(subX, subY);
if (doftrans_l)
{
doftrans_l->TransformDual(subY);
}
y.AddElementVector(l_vdofs, subY);
}
@@ -1085,7 +1105,8 @@ TensorProductPRefinementTransferOperator(
// must be sorted in lexicographical order
for (int i = 0; i < ir.GetNPoints(); ++i)
{
irLex.IntPoint(i) = ir.IntPoint(hdofmap[i]);
int j = hdofmap[i] >=0 ? hdofmap[i] : -1 - hdofmap[i];
irLex.IntPoint(i) = ir.IntPoint(j);
}
NE = lFESpace.GetNE();
+4
View File
@@ -70,6 +70,10 @@ public:
explicit inline Array(int asize)
: size(asize) { asize > 0 ? data.New(asize) : data.Reset(); }
/// Creates array of @a asize elements with a given MemoryType
inline Array(int asize, MemoryType mt)
: size(asize) { asize > 0 ? data.New(asize, mt) : data.Reset(mt); }
/** @brief Creates array using an existing c-array of asize elements;
allocsize is set to -asize to indicate that the data will not
be deleted. */
+149 -12
View File
@@ -183,6 +183,42 @@ void RajaCuWrap3D(const int N, DBODY &&d_body,
MFEM_GPU_CHECK(cudaGetLastError());
}
template <int Dim>
struct RajaCuWrap;
template <>
struct RajaCuWrap<1>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
RajaCuWrap1D<BLCK>(N, d_body);
}
};
template <>
struct RajaCuWrap<2>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
RajaCuWrap2D(N, d_body, X, Y, Z);
}
};
template <>
struct RajaCuWrap<3>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
RajaCuWrap3D(N, d_body, X, Y, Z, G);
}
};
#endif
#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_HIP)
@@ -248,6 +284,43 @@ void RajaHipWrap3D(const int N, DBODY &&d_body,
MFEM_GPU_CHECK(hipGetLastError());
}
template <int Dim>
struct RajaHipWrap;
template <>
struct RajaHipWrap<1>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
RajaHipWrap1D<BLCK>(N, d_body);
}
};
template <>
struct RajaHipWrap<2>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
RajaHipWrap2D(N, d_body, X, Y, Z);
}
};
template <>
struct RajaHipWrap<3>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
RajaHipWrap3D(N, d_body, X, Y, Z, G);
}
};
#endif
/// RAJA OpenMP backend
@@ -333,6 +406,42 @@ void CuWrap3D(const int N, DBODY &&d_body,
MFEM_GPU_CHECK(cudaGetLastError());
}
template <int Dim>
struct CuWrap;
template <>
struct CuWrap<1>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
CuWrap1D<BLCK>(N, d_body);
}
};
template <>
struct CuWrap<2>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
CuWrap2D(N, d_body, X, Y, Z);
}
};
template <>
struct CuWrap<3>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
CuWrap3D(N, d_body, X, Y, Z, G);
}
};
#endif // MFEM_USE_CUDA
@@ -392,6 +501,42 @@ void HipWrap3D(const int N, DBODY &&d_body,
MFEM_GPU_CHECK(hipGetLastError());
}
template <int Dim>
struct HipWrap;
template <>
struct HipWrap<1>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
HipWrap1D<BLCK>(N, d_body);
}
};
template <>
struct HipWrap<2>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
HipWrap2D(N, d_body, X, Y, Z);
}
};
template <>
struct HipWrap<3>
{
template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
static void run(const int N, DBODY &&d_body,
const int X, const int Y, const int Z, const int G)
{
HipWrap3D(N, d_body, X, Y, Z, G);
}
};
#endif // MFEM_USE_HIP
@@ -413,9 +558,7 @@ inline void ForallWrap(const bool use_dev, const int N,
// If Backend::RAJA_CUDA is allowed, use it
if (Device::Allows(Backend::RAJA_CUDA))
{
if (DIM == 1) { return RajaCuWrap1D(N, d_body); }
if (DIM == 2) { return RajaCuWrap2D(N, d_body, X, Y, Z); }
if (DIM == 3) { return RajaCuWrap3D(N, d_body, X, Y, Z, G); }
return RajaCuWrap<DIM>::run(N, d_body, X, Y, Z, G);
}
#endif
@@ -423,9 +566,7 @@ inline void ForallWrap(const bool use_dev, const int N,
// If Backend::RAJA_HIP is allowed, use it
if (Device::Allows(Backend::RAJA_HIP))
{
if (DIM == 1) { return RajaHipWrap1D(N, d_body); }
if (DIM == 2) { return RajaHipWrap2D(N, d_body, X, Y, Z); }
if (DIM == 3) { return RajaHipWrap3D(N, d_body, X, Y, Z, G); }
return RajaHipWrap<DIM>::run(N, d_body, X, Y, Z, G);
}
#endif
@@ -433,9 +574,7 @@ inline void ForallWrap(const bool use_dev, const int N,
// If Backend::CUDA is allowed, use it
if (Device::Allows(Backend::CUDA))
{
if (DIM == 1) { return CuWrap1D(N, d_body); }
if (DIM == 2) { return CuWrap2D(N, d_body, X, Y, Z); }
if (DIM == 3) { return CuWrap3D(N, d_body, X, Y, Z, G); }
return CuWrap<DIM>::run(N, d_body, X, Y, Z, G);
}
#endif
@@ -443,9 +582,7 @@ inline void ForallWrap(const bool use_dev, const int N,
// If Backend::HIP is allowed, use it
if (Device::Allows(Backend::HIP))
{
if (DIM == 1) { return HipWrap1D(N, d_body); }
if (DIM == 2) { return HipWrap2D(N, d_body, X, Y, Z); }
if (DIM == 3) { return HipWrap3D(N, d_body, X, Y, Z, G); }
return HipWrap<DIM>::run(N, d_body, X, Y, Z, G);
}
#endif
+5 -4
View File
@@ -175,8 +175,9 @@ protected:
// Copy{From,To}, {ReadWrite,Read,Write}.
public:
/// Default constructor: no initialization.
Memory() { }
/** Default constructor, sets the host pointer to nullptr and the metadata to
meaningful default values. */
Memory() { Reset(); }
/// Copy constructor: default.
Memory(const Memory &orig) = default;
@@ -368,8 +369,7 @@ public:
be updated as described above. */
inline void SetDeviceMemoryType(MemoryType d_mt);
/** @brief Delete the owned pointers. The Memory is not reset by this method,
i.e. it will, generally, not be Empty() after this call. */
/** @brief Delete the owned pointers and reset the Memory object. */
inline void Delete();
/** @brief Delete the device pointer, if owned. If @a copy_to_host is true
@@ -986,6 +986,7 @@ inline void Memory<T>::Delete()
{
if (flags & OWNS_HOST) { delete [] h_ptr; }
}
Reset(h_mt);
}
template <typename T>
+1
View File
@@ -69,6 +69,7 @@ void IntegerSet::Recreate(const int n, const int *p)
me.Sort();
// Remove duplicate entries
for (j = 0, i = 1; i < n; i++)
if (me[i] != me[j])
{
+7 -2
View File
@@ -36,7 +36,7 @@ public:
IntegerSet(const int n, const int *p) { Recreate(n, p); }
/// Return the size of the set.
int Size() { return me.Size(); }
int Size() const { return me.Size(); }
/// Return a reference to the sorted array of all the set entries.
operator Array<int>& () { return me; }
@@ -50,6 +50,8 @@ public:
/// Return 1 if the sets are equal and 0 otherwise.
int operator==(IntegerSet &s);
inline const int & operator[](int i) const { return me[i]; }
/** @brief Create an integer set from C-array 'p' of 'n' integers.
Overwrites any existing set data. */
void Recreate(const int n, const int *p);
@@ -64,7 +66,7 @@ private:
public:
/// Return the number of integer sets in the list.
int Size() { return TheList.Size(); }
int Size() const { return TheList.Size(); }
/// Return the value of the first element of the ith set.
int PickElementInSet(int i) { return TheList[i]->PickElement(); }
@@ -84,6 +86,9 @@ public:
/// Write the list of sets into table 't'.
void AsTable(Table &t);
inline const IntegerSet & operator[](int i) const { return *TheList[i]; }
inline IntegerSet & operator[](int i) { return *TheList[i]; }
~ListOfIntegerSets();
};
+9 -7
View File
@@ -61,7 +61,7 @@ inline void Sort3 (int &r, int &c, int &f)
}
}
int STable3D::Push (int r, int c, int f)
int STable3D::Push (int r, int c, int f, int t)
{
STable3DNode *node;
@@ -86,6 +86,7 @@ int STable3D::Push (int r, int c, int f)
#endif
node->Column = c;
node->Floor = f;
node->Tier = t;
node->Number = NElem;
node->Prev = Rows[r];
Rows[r] = node;
@@ -109,9 +110,9 @@ int STable3D::operator() (int r, int c, int f) const
}
}
MFEM_ABORT("(r,c,f) = (" << r << "," << c << "," << f << ")");
// MFEM_ABORT("(r,c,f) = (" << r << "," << c << "," << f << ")");
return 0;
return -1;
}
int STable3D::Index (int r, int c, int f) const
@@ -152,13 +153,13 @@ int STable3D::Push4 (int r, int c, int f, int t)
switch (i)
{
case 0:
return Push (c,f,t);
return Push (c,f,t,r);
case 1:
return Push (r,f,t);
return Push (r,f,t,c);
case 2:
return Push (r,c,t);
return Push (r,c,t,f);
case 3:
return Push (r,c,f);
return Push (r,c,f,t);
}
return -1;
@@ -218,6 +219,7 @@ void STable3D::Print(std::ostream & out) const
out << row
<< ' ' << node_p->Column
<< ' ' << node_p->Floor
<< ' ' << node_p->Tier
<< ' ' << node_p->Number
<< endl;
node_p = node_p->Prev;
+22 -3
View File
@@ -15,6 +15,8 @@
#include "mem_alloc.hpp"
#include "../general/globals.hpp"
#include <iostream>
namespace mfem
{
@@ -22,7 +24,7 @@ class STable3DNode
{
public:
STable3DNode *Prev;
int Column, Floor, Number;
int Column, Floor, Tier, Number;
};
/** @brief Symmetric 3D Table stored as an array of rows each of which has a
@@ -47,7 +49,7 @@ public:
/** @brief Check to see if this entry is in the table and add it to the table
if it is not there. Returns the number assigned to the table entry. */
int Push (int r, int c, int f);
int Push (int r, int c, int f, int t = -1);
/// Return the number assigned to the table entry. Abort if it's not there.
int operator() (int r, int c, int f) const;
@@ -66,13 +68,30 @@ public:
not there. */
int operator() (int r, int c, int f, int t) const;
/// Return the number of rows added to the table.
int NumberOfRows() const { return Size; }
/// Return the number of elements added to the table.
int NumberOfElements() { return NElem; }
int NumberOfElements() const { return NElem; }
/// Print out all of the table elements.
void Print(std::ostream &out = mfem::out) const;
~STable3D ();
class RowIterator
{
private:
STable3DNode *n;
public:
RowIterator (const STable3D &t, int r) { n = t.Rows[r]; }
int operator!() { return (n != NULL); }
void operator++() { n = n->Prev; }
int Column() { return (n->Column); }
int Floor() { return (n->Floor); }
int Tier() { return (n->Tier); }
int Index() { return (n->Number); }
};
};
}
-4
View File
@@ -35,10 +35,6 @@ Table::Table(const Table &table)
I.CopyFrom(table.I, size+1);
J.CopyFrom(table.J, nnz);
}
else
{
I.Reset(); J.Reset();
}
}
Table& Table::operator=(const Table &rhs)
+2 -2
View File
@@ -53,7 +53,7 @@ protected:
public:
/// Creates an empty table
Table() { size = -1; I.Reset(); J.Reset(); }
Table() { size = -1; }
/// Copy constructor
Table(const Table &);
@@ -66,7 +66,7 @@ public:
/** Create a table from a list of connections, see MakeFromList(). */
Table(int nrows, Array<Connection> &list) : size(-1)
{ I.Reset(); J.Reset(); MakeFromList(nrows, list); }
{ MakeFromList(nrows, list); }
/** Create a table with one entry per row with column indices given
by 'partitioning'. */
+1 -20
View File
@@ -70,10 +70,7 @@ namespace mfem
using namespace std;
DenseMatrix::DenseMatrix() : Matrix(0)
{
data.Reset();
}
DenseMatrix::DenseMatrix() : Matrix(0) { }
DenseMatrix::DenseMatrix(const DenseMatrix &m) : Matrix(m.height, m.width)
{
@@ -84,10 +81,6 @@ DenseMatrix::DenseMatrix(const DenseMatrix &m) : Matrix(m.height, m.width)
data.New(hw);
std::memcpy(data, m.data, sizeof(double)*hw);
}
else
{
data.Reset();
}
}
DenseMatrix::DenseMatrix(int s) : Matrix(s)
@@ -98,10 +91,6 @@ DenseMatrix::DenseMatrix(int s) : Matrix(s)
data.New(s*s);
*this = 0.0; // init with zeroes
}
else
{
data.Reset();
}
}
DenseMatrix::DenseMatrix(int m, int n) : Matrix(m, n)
@@ -114,10 +103,6 @@ DenseMatrix::DenseMatrix(int m, int n) : Matrix(m, n)
data.New(capacity);
*this = 0.0; // init with zeroes
}
else
{
data.Reset();
}
}
DenseMatrix::DenseMatrix(const DenseMatrix &mat, char ch)
@@ -137,10 +122,6 @@ DenseMatrix::DenseMatrix(const DenseMatrix &mat, char ch)
}
}
}
else
{
data.Reset();
}
}
void DenseMatrix::SetSize(int h, int w)
-5
View File
@@ -753,7 +753,6 @@ public:
DenseTensor()
{
nk = 0;
tdata.Reset();
}
DenseTensor(int i, int j, int k)
@@ -787,10 +786,6 @@ public:
tdata.New(size, other.tdata.GetMemoryType());
tdata.CopyFrom(other.tdata, size);
}
else
{
tdata.Reset();
}
}
int SizeI() const { return Mk.Height(); }
+62 -11
View File
@@ -127,18 +127,19 @@ HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size,
own_ParVector = 1;
}
HypreParVector::HypreParVector(const HypreParVector &y) : Vector()
// Call the move constructor on the "compatible" temp vector
HypreParVector::HypreParVector(const HypreParVector &y) : HypreParVector(
y.CreateCompatibleVector())
{
x = hypre_ParVectorCreate(y.x -> comm, y.x -> global_size,
y.x -> partitioning);
hypre_ParVectorInitialize(x);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParVectorSetPartitioningOwner(x,0);
#endif
hypre_ParVectorSetDataOwner(x,1);
hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
_SetDataAndSize_();
own_ParVector = 1;
// Deep copy the local data
hypre_SeqVectorCopy(hypre_ParVectorLocalVector(y.x),
hypre_ParVectorLocalVector(x));
}
HypreParVector::HypreParVector(HypreParVector &&y)
{
own_ParVector = 0;
*this = std::move(y);
}
HypreParVector::HypreParVector(const HypreParMatrix &A,
@@ -178,6 +179,23 @@ HypreParVector::HypreParVector(ParFiniteElementSpace *pfes)
own_ParVector = 1;
}
HypreParVector HypreParVector::CreateCompatibleVector() const
{
HypreParVector result;
result.x = hypre_ParVectorCreate(x -> comm, x -> global_size,
x -> partitioning);
hypre_ParVectorInitialize(result.x);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParVectorSetPartitioningOwner(result.x,0);
#endif
hypre_ParVectorSetDataOwner(result.x,1);
hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(result.x),1);
result._SetDataAndSize_();
result.own_ParVector = 1;
return result;
}
void HypreParVector::WrapHypreParVector(hypre_ParVector *y, bool owner)
{
if (own_ParVector) { hypre_ParVectorDestroy(x); }
@@ -216,6 +234,18 @@ HypreParVector& HypreParVector::operator=(const HypreParVector &y)
return *this;
}
HypreParVector& HypreParVector::operator=(HypreParVector &&y)
{
// If the argument vector owns its data, then the calling vector will as well
WrapHypreParVector(static_cast<hypre_ParVector*>(y), y.own_ParVector);
// Either way the argument vector will no longer own its data
y.own_ParVector = 0;
y.x = nullptr;
y.data.Reset();
y.size = 0;
return *this;
}
void HypreParVector::SetData(double *data_)
{
hypre_VectorData(hypre_ParVectorLocalVector(x)) = data_;
@@ -303,6 +333,18 @@ void HypreParVector::Print(const char *fname) const
hypre_ParVectorPrint(x,fname);
}
void HypreParVector::Read(MPI_Comm comm, const char *fname)
{
if (own_ParVector)
{
hypre_ParVectorDestroy(x);
}
data.Delete();
x = hypre_ParVectorRead(comm, fname);
own_ParVector = true;
_SetDataAndSize_();
}
HypreParVector::~HypreParVector()
{
if (own_ParVector)
@@ -1561,9 +1603,16 @@ HypreParMatrix *HypreParMatrix::ExtractSubmatrix(const Array<int> &indices,
}
// Construct cpts_global array on hypre matrix structure
#if (MFEM_HYPRE_VERSION > 22300) || (MFEM_HYPRE_VERSION == 22300 && HYPRE_DEVELOP_NUMBER >=8)
HYPRE_BigInt cpts_global[2];
hypre_BoomerAMGCoarseParms(MPI_COMM_WORLD, local_num_vars, 1, NULL,
CF_marker, NULL, cpts_global);
#else
HYPRE_BigInt *cpts_global;
hypre_BoomerAMGCoarseParms(MPI_COMM_WORLD, local_num_vars, 1, NULL,
CF_marker, NULL, &cpts_global);
#endif
// Extract submatrix into *submat
#ifdef hypre_IntArrayData
@@ -1575,7 +1624,9 @@ HypreParMatrix *HypreParMatrix::ExtractSubmatrix(const Array<int> &indices,
"FF", &submat, threshold);
#endif
#if (MFEM_HYPRE_VERSION <= 22300) && !(MFEM_HYPRE_VERSION == 22300 && HYPRE_DEVELOP_NUMBER >=8)
mfem_hypre_TFree(cpts_global);
#endif
#ifdef hypre_IntArrayData
hypre_IntArrayDestroy(CF_marker);
#endif
+12 -1
View File
@@ -141,8 +141,10 @@ public:
allocated in the memory location HYPRE_MEMORY_DEVICE. */
HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size, double *data_,
HYPRE_BigInt *col, bool is_device_ptr = false);
/// Creates vector compatible with y
/// Creates a deep copy of @a y
HypreParVector(const HypreParVector &y);
/// Move constructor for HypreParVector. "Steals" data from its argument.
HypreParVector(HypreParVector&& other);
/// Creates vector compatible with (i.e. in the domain of) A or A^T
explicit HypreParVector(const HypreParMatrix &A, int transpose = 0);
/// Creates vector wrapping y
@@ -150,6 +152,10 @@ public:
/// Create a true dof parallel vector on a given ParFiniteElementSpace
explicit HypreParVector(ParFiniteElementSpace *pfes);
/// \brief Constructs a @p HypreParVector *compatible* with the calling vector
/// - meaning that it will be the same size and have the same partitioning.
HypreParVector CreateCompatibleVector() const;
/// MPI communicator
MPI_Comm GetComm() const { return x->comm; }
@@ -192,6 +198,8 @@ public:
HypreParVector& operator= (double d);
/// Define '=' for hypre vectors.
HypreParVector& operator= (const HypreParVector &y);
/// Move assignment
HypreParVector& operator= (HypreParVector &&y);
using Vector::Read;
@@ -252,6 +260,9 @@ public:
/// Prints the locally owned rows in parallel
void Print(const char *fname) const;
/// Reads a HypreParVector from files saved with HypreParVector::Print
void Read(MPI_Comm comm, const char *fname);
/// Calls hypre's destroy function
~HypreParVector();
+55 -2
View File
@@ -160,7 +160,7 @@ double Norml2(const int size, const T *data)
data of the input and output vectors. */
template<typename TA, typename TX, typename TY>
MFEM_HOST_DEVICE inline
void Mult(const int height, const int width, TA *data, const TX *x, TY *y)
void Mult(const int height, const int width, const TA *data, const TX *x, TY *y)
{
if (width == 0)
{
@@ -170,7 +170,7 @@ void Mult(const int height, const int width, TA *data, const TX *x, TY *y)
}
return;
}
TA *d_col = data;
const TA *d_col = data;
TX x_col = x[0];
for (int row = 0; row < height; row++)
{
@@ -188,6 +188,35 @@ void Mult(const int height, const int width, TA *data, const TX *x, TY *y)
}
}
/** @brief Matrix transpose vector multiplication: y = At x, where the matrix A
is of size @a height x @a width with given @a data, while @a x and @a y
specify the data of the input and output vectors. */
template<typename TA, typename TX, typename TY>
MFEM_HOST_DEVICE inline
void MultTranspose(const int height, const int width, const TA *data,
const TX *x, TY *y)
{
if (height == 0)
{
for (int row = 0; row < width; row++)
{
y[row] = 0.0;
}
return;
}
TY *y_off = y;
for (int i = 0; i < width; ++i)
{
TY val = 0.0;
for (int j = 0; j < height; ++j)
{
val += x[j] * data[i * height + j];
}
*y_off = val;
y_off++;
}
}
/// Symmetrize a square matrix with given @a size and @a data: A -> (A+A^T)/2.
template<typename T>
MFEM_HOST_DEVICE inline
@@ -353,6 +382,30 @@ void MultABt(const int Aheight, const int Awidth, const int Bheight,
}
}
/** @brief Multiply the transpose of a matrix of size @a Aheight x @a Awidth
and data @a Adata with a matrix of size @a Aheight x @a Bwidth and data @a
Bdata: At * B. Return the result in a matrix with data @a AtBdata. */
template<typename TA, typename TB, typename TC>
MFEM_HOST_DEVICE inline
void MultAtB(const int Aheight, const int Awidth, const int Bwidth,
const TA *Adata, const TB *Bdata, TC *AtBdata)
{
TC *c = AtBdata;
for (int i = 0; i < Bwidth; ++i)
{
for (int j = 0; j < Awidth; ++j)
{
TC val = 0.0;
for (int k = 0; k < Aheight; ++k)
{
val += Adata[j * Aheight + k] * Bdata[i * Aheight + k];
}
*c = val;
c++;
}
}
}
/// Compute the spectrum of the matrix of size dim with given @a data, returning
/// the eigenvalues in the array @a lambda and the eigenvectors in the array @a
/// vec (listed consecutively).
+1 -1
View File
@@ -242,7 +242,7 @@ public:
void FormDiscreteOperator(Operator* &A);
/// Prints operator with input size n and output size m in Matlab format.
void PrintMatlab(std::ostream & out, int n = 0, int m = 0) const;
void PrintMatlab(std::ostream & out, int n, int m = 0) const;
/// Prints operator in Matlab format.
virtual void PrintMatlab(std::ostream & out) const;
-4
View File
@@ -558,8 +558,6 @@ PetscParVector::PetscParVector(MPI_Comm comm, const Operator &op,
else /* Vector intended to be used with Place/ResetMemory calls */
{
size = loc;
pdata.Reset();
data.Reset();
}
}
@@ -581,8 +579,6 @@ PetscParVector::PetscParVector(const PetscParMatrix &A,
PetscInt n;
ierr = VecGetLocalSize(x,&n); PCHKERRQ(x,ierr);
size = n;
pdata.Reset();
data.Reset();
}
else
{
+6 -6
View File
@@ -84,9 +84,9 @@ SparseMatrix::SparseMatrix(int nrows, int ncols)
isSorted(false)
{
// We probably do not need to set the ownership flags here.
I.Reset(); I.SetHostPtrOwner(true);
J.Reset(); J.SetHostPtrOwner(true);
A.Reset(); A.SetHostPtrOwner(true);
I.SetHostPtrOwner(true);
J.SetHostPtrOwner(true);
A.SetHostPtrOwner(true);
for (int i = 0; i < nrows; i++)
{
@@ -229,9 +229,9 @@ SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph,
}
// We probably do not need to set the ownership flags here.
I.Reset(); I.SetHostPtrOwner(true);
J.Reset(); J.SetHostPtrOwner(true);
A.Reset(); A.SetHostPtrOwner(true);
I.SetHostPtrOwner(true);
J.SetHostPtrOwner(true);
A.SetHostPtrOwner(true);
}
current_row = -1;
+1 -8
View File
@@ -17,10 +17,7 @@
namespace mfem
{
DenseSymmetricMatrix::DenseSymmetricMatrix() : Matrix(0)
{
data.Reset();
}
DenseSymmetricMatrix::DenseSymmetricMatrix() : Matrix(0) { }
DenseSymmetricMatrix::DenseSymmetricMatrix(int s) : Matrix(s)
{
@@ -30,10 +27,6 @@ DenseSymmetricMatrix::DenseSymmetricMatrix(int s) : Matrix(s)
data.New((s*(s+1))/2);
*this = 0.0; // init with zeroes
}
else
{
data.Reset();
}
}
void DenseSymmetricMatrix::SetSize(int s)
+15 -6
View File
@@ -39,21 +39,21 @@ namespace mfem
Vector::Vector(const Vector &v)
{
const int s = v.Size();
size = s;
if (s > 0)
{
MFEM_ASSERT(!v.data.Empty(), "invalid source vector");
size = s;
data.New(s, v.data.GetMemoryType());
data.CopyFrom(v.data, s);
}
else
{
size = 0;
data.Reset();
}
UseDevice(v.UseDevice());
}
Vector::Vector(Vector &&v)
{
*this = std::move(v);
}
void Vector::Load(std::istream **in, int np, int *dim)
{
int i, j, s;
@@ -146,6 +146,15 @@ Vector &Vector::operator=(const Vector &v)
return *this;
}
Vector &Vector::operator=(Vector &&v)
{
data = std::move(v.data);
size = v.size;
v.data.Reset();
v.size = 0;
return *this;
}
Vector &Vector::operator=(double value)
{
const bool use_dev = UseDevice();
+11 -8
View File
@@ -66,12 +66,16 @@ protected:
public:
/// Default constructor for Vector. Sets size = 0 and data = NULL.
Vector() { data.Reset(); size = 0; }
/** Default constructor for Vector. Sets size = 0, and calls Memory::Reset on
data through Memory<double>'s default constructor. */
Vector(): size(0) { }
/// Copy constructor. Allocates a new data array and copies the data.
Vector(const Vector &);
/// Move constructor. "Steals" data from its argument.
Vector(Vector&& v);
/// @brief Creates vector of size s.
/// @warning Entries are not initialized to zero!
explicit Vector(int s);
@@ -278,6 +282,9 @@ public:
assignment operator. */
Vector &operator=(const Vector &v);
/// Move assignment
Vector &operator=(Vector&& v);
/// Redefine '=' for vector = constant.
Vector &operator=(double value);
@@ -503,16 +510,12 @@ inline int CheckFinite(const double *v, const int n)
inline Vector::Vector(int s)
{
MFEM_ASSERT(s>=0,"Unexpected negative size.");
size = s;
if (s > 0)
{
size = s;
data.New(s);
}
else
{
size = 0;
data.Reset();
}
}
inline void Vector::SetSize(int s)
+7 -5
View File
@@ -123,7 +123,7 @@ EXAMPLE_SUBDIRS = amgx caliper ginkgo hiop petsc pumi sundials superlu
EXAMPLE_DIRS := examples $(addprefix examples/,$(EXAMPLE_SUBDIRS))
EXAMPLE_TEST_DIRS := examples
MINIAPP_SUBDIRS = common electromagnetics meshing navier performance tools toys nurbs gslib adjoint solvers shifted mtop parelag
MINIAPP_SUBDIRS = common electromagnetics meshing navier performance tools toys nurbs gslib adjoint solvers shifted mtop parelag autodiff
MINIAPP_DIRS := $(addprefix miniapps/,$(MINIAPP_SUBDIRS))
MINIAPP_TEST_DIRS := $(filter-out %/common,$(MINIAPP_DIRS))
MINIAPP_USE_COMMON := $(addprefix miniapps/,electromagnetics meshing tools toys shifted)
@@ -274,7 +274,7 @@ 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 MESQUITE\
SUITESPARSE STRUMPACK GINKGO GNUTLS NETCDF PETSC SLEPC MPFR PUMI HIOP GSLIB\
OCCA CEED RAJA UMPIRE MKL_CPARDISO AMGX CALIPER PARELAG BENCHMARK
OCCA CEED RAJA UMPIRE MKL_CPARDISO AMGX CALIPER PARELAG BENCHMARK
PETSC_ERROR_MSG = $(if $(PETSC_FOUND),,. PETSC config not found: $(PETSC_VARS))
SLEPC_ERROR_MSG = $(if $(SLEPC_FOUND),,. SLEPC config not found: $(SLEPC_VARS))
@@ -340,8 +340,8 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\
MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\
MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE MFEM_USE_SIMD\
MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO MFEM_USE_AMGX MFEM_USE_MUMPS\
MFEM_USE_CALIPER MFEM_USE_BENCHMARK MFEM_USE_PARELAG\
MFEM_SOURCE_DIR MFEM_INSTALL_DIR
MFEM_USE_ADFORWARD MFEM_USE_CODIPACK MFEM_USE_CALIPER MFEM_USE_BENCHMARK\
MFEM_USE_PARELAG MFEM_SOURCE_DIR MFEM_INSTALL_DIR
# List of makefile variables that will be written to config.mk:
MFEM_CONFIG_VARS = MFEM_CXX MFEM_HOST_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS\
@@ -500,7 +500,7 @@ hpc:
deps:
rm -f $(BLD)deps.mk
for i in $(RELSRC_FILES:.cpp=); do \
$(DEP_CXX) $(MFEM_BUILD_FLAGS) -MM -MT $(BLD)$${i}.o $(SRC)$${i}.cpp\
$(DEP_CXX) $(MFEM_BUILD_FLAGS) $(DEP_FLAGS) $(BLD)$${i}.o $(SRC)$${i}.cpp\
>> $(BLD)deps.mk; done
check: lib
@@ -679,6 +679,8 @@ status info:
$(info MFEM_USE_SIMD = $(MFEM_USE_SIMD))
$(info MFEM_USE_ADIOS2 = $(MFEM_USE_ADIOS2))
$(info MFEM_USE_MKL_CPARDISO = $(MFEM_USE_MKL_CPARDISO))
$(info MFEM_USE_ADFORWARD = $(MFEM_USE_ADFORWARD))
$(info MFEM_USE_CODIPACK = $(MFEM_USE_CODIPACK))
$(info MFEM_USE_BENCHMARK = $(MFEM_USE_BENCHMARK))
$(info MFEM_USE_PARELAG = $(MFEM_USE_PARELAG))
$(info MFEM_CXX = $(value MFEM_CXX))
+1295
View File
File diff suppressed because it is too large Load Diff
+219
View File
@@ -0,0 +1,219 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_ENTITY_SETS
#define MFEM_ENTITY_SETS
#include "../config/config.hpp"
#include "../general/table.hpp"
#include "../general/stable3d.hpp"
#include <limits>
#include <map>
#include <set>
#include <string>
#include <vector>
namespace mfem
{
class Mesh;
class NCMesh;
class NCEntitySets;
class EntitySets
{
friend class Mesh;
friend class NCMesh;
friend class NCEntitySets;
public:
enum EntityType {INVALID = -1, VERTEX = 0, EDGE = 1, FACE = 2, ELEMENT = 3};
static std::map<EntityType,std::string> EntityTypeNames;
EntitySets(Mesh & mesh);
EntitySets(const EntitySets & ent_sets);
EntitySets(Mesh & mesh, NCMesh &ncmesh);
virtual ~EntitySets();
static const std::string & GetTypeName(EntityType t);
bool SetExists(EntityType t, unsigned int s) const;
bool SetExists(EntityType t, const std::string & s) const;
void Load(std::istream &input);
void Print(std::ostream &output) const;
virtual void PrintSetInfo(std::ostream &output) const;
inline Mesh *GetMesh() const { return mesh_; }
unsigned int GetNumSets(EntityType t) const;
const std::string & GetSetName(EntityType t, unsigned int s) const;
unsigned int GetNumEntities(EntityType t, unsigned int s) const;
int GetSetIndex(EntityType t, const std::string & s) const;
unsigned int GetNumEntities(EntityType t, const std::string & s) const;
inline std::set<int> & operator()(EntityType t, unsigned int s)
{ return sets_[t][s]; }
inline const std::set<int> & operator()(EntityType t, unsigned int s) const
{ return sets_[t][s]; }
const Table * GetEdgeVertexTable() const { return edge_vertex_; }
const Table * GetFaceVertexTable() const { return face_vertex_; }
const Table * GetFaceEdgeTable() const { return face_edge_; }
// void Prune(int nelems);
protected:
void SetNumSets(EntityType t, unsigned int n)
{ sets_[t].resize(n); set_names_[t].resize(n); }
void SetSetName(EntityType t, int s, const std::string & name)
{ set_names_[t][s] = name; set_index_by_name_[t][name] = s; }
/// Make local copies of edge_vertex, face_vertex, and face_edge tables.
void CopyMeshTables();
/// Refine quadrilateral mesh.
virtual void QuadUniformRefinement();
/// Refine hexahedral mesh.
virtual void HexUniformRefinement();
/// Refine 2D mesh.
virtual void UniformRefinement2D();
/// Refine 3D mesh.
virtual void UniformRefinement3D();
private:
static void skip_comment_lines(std::istream &is, const char comment_char)
{
while (1)
{
is >> std::ws;
if (is.peek() != comment_char) { break; }
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
// Check for, and remove, a trailing '\r'.
static void filter_dos(std::string &line)
{
if (!line.empty() && *line.rbegin() == '\r')
{ line.resize(line.size()-1); }
}
static std::map<EntityType,std::string> init_type_names();
void LoadEntitySets(std::istream &input, EntityType t,
const std::string & header);
void PrintEntitySets(std::ostream &output, EntityType t,
const std::string & header) const;
void PrintEdgeSets(std::ostream &output) const;
void PrintFaceSets(std::ostream &output) const;
void PrintEntitySetInfo(std::ostream & output, EntityType t,
const std::string & ent_name) const;
void CopyEntitySets(const EntitySets & ent_sets, EntityType t);
void BuildEntitySets(NCMesh &ncmesh, EntityType t);
protected:
Mesh * mesh_;
Table * edge_vertex_;
Table * face_vertex_;
Table * face_edge_;
int NumOfVertices_;
int NumOfEdges_;
int NumOfElements_;
/** The node/edge/face/element indices needed by the finite element
space to look up DoFs. */
std::vector<std::vector<std::set<int> > > sets_;
/// Names of each entity set
std::vector<std::vector<std::string> > set_names_;
/// Indices of each entity set indexed by set name
std::vector<std::map<std::string, int> > set_index_by_name_;
};
class NCEntitySets
{
friend class EntitySets;
public:
NCEntitySets(const EntitySets & ent_sets, NCMesh &ncmesh);
NCEntitySets(const NCEntitySets & ncent_sets);
bool SetExists(EntitySets::EntityType t, unsigned int s) const;
bool SetExists(EntitySets::EntityType t, const std::string & s) const;
unsigned int GetNumSets(EntitySets::EntityType t) const;
static int GetEntitySize(EntitySets::EntityType t);
const std::string & GetSetName(EntitySets::EntityType t, int s) const;
unsigned int GetNumEntities(EntitySets::EntityType t, int s) const;
void GetEntityIndex(EntitySets::EntityType t, int s,
int i, Array<int> & inds) const;
int GetSetIndex(EntitySets::EntityType t,
const std::string & s) const;
unsigned int GetNumEntities(EntitySets::EntityType t,
const std::string & s) const;
void GetEntityIndex(EntitySets::EntityType t,
const std::string & s, int i,
Array<int> & inds) const;
inline std::vector<int> & operator()(EntitySets::EntityType t, int s)
{ return sets_[t][s]; }
inline const std::vector<int> & operator()(EntitySets::EntityType t,
int s) const
{ return sets_[t][s]; }
inline int & operator()(EntitySets::EntityType t, int s, int i)
{ return sets_[t][s][i]; }
inline int operator()(EntitySets::EntityType t, int s, int i) const
{ return sets_[t][s][i]; }
private:
void CopyNCEntitySets(const NCEntitySets & ncent_sets,
EntitySets::EntityType t);
protected:
NCMesh * ncmesh_;
/// The nodes defining the node/edge/face/element sets
std::vector<std::vector<std::vector<int> > > sets_;
/// Names of each entity set
std::vector<std::vector<std::string> > set_names_;
/// Indices of each entity set indexed by set name
std::vector<std::map<std::string, int> > set_index_by_name_;
/// Number of indices per entity
static const int entity_size_[4];
};
} // namespace mfem
#endif // MFEM_ENTITY_SETS
+81 -14
View File
@@ -75,7 +75,7 @@ void Mesh::GetElementCenter(int i, Vector &center)
double Mesh::GetElementSize(ElementTransformation *T, int type)
{
DenseMatrix J(spaceDim,Dim);
DenseMatrix J(spaceDim, Dim);
Geometry::Type geom = T->GetGeometryType();
T->SetIntPoint(&Geometries.GetCenter(geom));
@@ -102,7 +102,7 @@ double Mesh::GetElementSize(int i, int type)
double Mesh::GetElementSize(int i, const Vector &dir)
{
DenseMatrix J(spaceDim,Dim);
DenseMatrix J(spaceDim, Dim);
Vector d_hat(Dim);
GetElementJacobian(i, J);
J.MultTranspose(dir, d_hat);
@@ -1177,13 +1177,15 @@ void Mesh::Init()
own_nodes = 1;
NURBSext = NULL;
ncmesh = NULL;
ent_sets = NULL;
last_operation = Mesh::NONE;
}
void Mesh::InitTables()
{
el_to_edge =
el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
el_to_face = el_to_el = bel_to_edge = face_edge =
face_vertex = edge_vertex = NULL;
}
void Mesh::SetEmpty()
@@ -1205,6 +1207,7 @@ void Mesh::DestroyTables()
}
delete face_edge;
delete face_vertex;
delete edge_vertex;
}
@@ -1212,6 +1215,8 @@ void Mesh::DestroyPointers()
{
if (own_nodes) { delete Nodes; }
delete ent_sets;
delete ncmesh;
delete NURBSext;
@@ -3346,6 +3351,12 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
// Copy the edge-to-vertex Table, edge_vertex
edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
// Copy the face-to-vertex Table, edge_vertex
face_vertex = (mesh.face_vertex) ? new Table(*mesh.face_vertex) : NULL;
// Do not copy any of the coarse (c_*), fine (f_*) or fine/coarse (fc_*)
// data members.
// Copy the attributes and bdr_attributes
mesh.attributes.Copy(attributes);
mesh.bdr_attributes.Copy(bdr_attributes);
@@ -3396,6 +3407,9 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
Nodes = mesh.Nodes;
own_nodes = 0;
}
// Copy entity sets if present in the input mesh
ent_sets = (mesh.ent_sets) ? new EntitySets(*mesh.ent_sets) : NULL;
}
Mesh::Mesh(Mesh &&mesh) : Mesh()
@@ -5768,6 +5782,38 @@ Table *Mesh::GetEdgeVertexTable() const
return edge_vertex;
}
Table *Mesh::GetFaceVertexTable() const
{
if (face_vertex)
{
return face_vertex;
}
STable3D * faces_tbl = GetFacesTable();
int nfaces = faces_tbl->NumberOfElements();
face_vertex = new Table(nfaces, 4);
for (int i = 0; i < NumOfVertices; i++)
{
for (STable3D::RowIterator it(*faces_tbl, i); !it; ++it)
{
int j = it.Index();
face_vertex->Push(j, i);
face_vertex->Push(j, it.Column());
face_vertex->Push(j, it.Floor());
if ( it.Tier() > 0 )
{
face_vertex->Push(j, it.Tier());
}
}
}
face_vertex->Finalize();
delete faces_tbl;
return face_vertex;
}
Table *Mesh::GetVertexToElementTable()
{
int i, j, nv, *v;
@@ -6402,7 +6448,7 @@ void Mesh::GenerateNCFaceInfo()
}
}
STable3D *Mesh::GetFacesTable()
STable3D *Mesh::GetFacesTable() const
{
STable3D *faces_tbl = new STable3D(NumOfVertices);
for (int i = 0; i < NumOfElements; i++)
@@ -7657,6 +7703,11 @@ void Mesh::UniformRefinement2D_base(bool update_nodes)
NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
}
if ( ent_sets )
{
ent_sets->CopyMeshTables();
}
int quad_counter = 0;
for (int i = 0; i < NumOfElements; i++)
{
@@ -7792,6 +7843,11 @@ void Mesh::UniformRefinement2D_base(bool update_nodes)
if (update_nodes) { UpdateNodes(); }
if ( ent_sets )
{
ent_sets->UniformRefinement2D();
}
#ifdef MFEM_DEBUG
if (!Nodes || update_nodes)
{
@@ -7822,6 +7878,11 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
GetElementToFaceTable();
}
if ( ent_sets )
{
ent_sets->CopyMeshTables();
}
Array<int> f2qf_loc;
Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
f2qf.SetSize(0);
@@ -8148,7 +8209,6 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
}
AverageVertices(vv, 4, oface + f2qf[f[fi]]);
}
for (int ei = 0; ei < 9; ei++)
{
for (int k = 0; k < 2; k++)
@@ -8492,6 +8552,11 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
sequence++;
if (update_nodes) { UpdateNodes(); }
if (ent_sets)
{
ent_sets->UniformRefinement3D();
}
}
void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
@@ -8527,8 +8592,8 @@ void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
elements[new_e] = new Segment(new_v, vert[1], attr);
vert[1] = new_v;
CoarseFineTr.embeddings[i] = Embedding(i, 1);
CoarseFineTr.embeddings[new_e] = Embedding(i, 2);
CoarseFineTr.embeddings[i] = Embedding(i, Geometry::SEGMENT, 1);
CoarseFineTr.embeddings[new_e] = Embedding(i, Geometry::SEGMENT, 2);
}
static double seg_children[3*2] = { 0.0,1.0, 0.0,0.5, 0.5,1.0 };
@@ -8961,6 +9026,8 @@ void Mesh::Swap(Mesh& other, bool non_geometry)
mfem::Swap(geom_factors, other.geom_factors);
mfem::Swap(ent_sets, other.ent_sets);
#ifdef MFEM_USE_MEMALLOC
TetMemory.Swap(other.TetMemory);
#endif
@@ -9276,7 +9343,7 @@ void Mesh::Bisection(int i, const DSTable &v_to_v,
int coarse = FindCoarseElement(i);
CoarseFineTr.embeddings[i].parent = coarse;
CoarseFineTr.embeddings.Append(Embedding(coarse));
CoarseFineTr.embeddings.Append(Embedding(coarse, Geometry::TRIANGLE));
// 3. edge1 and edge2 may have to be changed for the second triangle.
if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows())
@@ -9396,7 +9463,7 @@ void Mesh::Bisection(int i, HashTable<Hashed2> &v_to_v)
int coarse = FindCoarseElement(i);
CoarseFineTr.embeddings[i].parent = coarse;
CoarseFineTr.embeddings.Append(Embedding(coarse));
CoarseFineTr.embeddings.Append(Embedding(coarse, Geometry::TETRAHEDRON));
// 3. Set the bisection flag
switch (type)
@@ -9534,10 +9601,10 @@ void Mesh::UniformRefinement(int i, const DSTable &v_to_v,
// set parent indices
int coarse = FindCoarseElement(i);
CoarseFineTr.embeddings[i] = Embedding(coarse);
CoarseFineTr.embeddings.Append(Embedding(coarse));
CoarseFineTr.embeddings.Append(Embedding(coarse));
CoarseFineTr.embeddings.Append(Embedding(coarse));
CoarseFineTr.embeddings[i] = Embedding(coarse, Geometry::TRIANGLE);
CoarseFineTr.embeddings.Append(Embedding(coarse, Geometry::TRIANGLE));
CoarseFineTr.embeddings.Append(Embedding(coarse, Geometry::TRIANGLE));
CoarseFineTr.embeddings.Append(Embedding(coarse, Geometry::TRIANGLE));
NumOfElements += 3;
}
@@ -9555,7 +9622,7 @@ void Mesh::InitRefinementTransforms()
for (int i = 0; i < NumOfElements; i++)
{
elements[i]->ResetTransform(0);
CoarseFineTr.embeddings[i] = Embedding(i);
CoarseFineTr.embeddings[i] = Embedding(i, GetElementGeometry(i));
}
}
+11 -2
View File
@@ -20,6 +20,7 @@
#include "vertex.hpp"
#include "vtk.hpp"
#include "ncmesh.hpp"
#include "entsets.hpp"
#include "../fem/eltrans.hpp"
#include "../fem/coefficient.hpp"
#include "../general/zstr.hpp"
@@ -54,9 +55,11 @@ class Mesh
#ifdef MFEM_USE_MPI
friend class ParMesh;
friend class ParNCMesh;
friend class ParEntitySets;
#endif
friend class NCMesh;
friend class NURBSExtension;
friend class EntitySets;
#ifdef MFEM_USE_ADIOS2
friend class adios2stream;
@@ -166,6 +169,7 @@ protected:
Array<int> be_to_face;
mutable Table *face_edge;
mutable Table *edge_vertex;
mutable Table *face_vertex;
IsoparametricTransformation Transformation, Transformation2;
IsoparametricTransformation BdrTransformation;
@@ -216,6 +220,8 @@ public:
Array<FaceGeometricFactors*>
face_geom_factors; ///< Optional face geometric factors.
EntitySets *ent_sets;
// Global parameter that can be used to control the removal of unused
// vertices performed when reading a mesh in MFEM format. The default value
// (true) is set in mesh_readers.cpp.
@@ -287,7 +293,7 @@ protected:
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert);
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert);
STable3D *GetFacesTable();
STable3D *GetFacesTable() const;
STable3D *GetElementToFaceTable(int ret_ftbl = 0);
/** Red refinement. Element with index i is refined. The default
@@ -1067,9 +1073,12 @@ public:
/// Returns the face-to-edge Table (3D)
Table *GetFaceEdgeTable() const;
/// Returns the edge-to-vertex Table (3D)
/// Returns the edge-to-vertex Table (2D or 3D)
Table *GetEdgeVertexTable() const;
/// Returns the face-to-vertex Table (2d or 3D)
Table *GetFaceVertexTable() const;
/// Return the indices and the orientations of all faces of element i.
void GetElementFaces(int i, Array<int> &faces, Array<int> &ori) const;
+136
View File
@@ -157,6 +157,142 @@ int ThresholdDerefiner::ApplyImpl(Mesh &mesh)
}
int CoefficientRefiner::ApplyImpl(Mesh &mesh)
{
int max_it = 1;
return PreprocessMesh(mesh, max_it);
}
int CoefficientRefiner::PreprocessMesh(Mesh &mesh, int max_it)
{
int rank = 0;
MFEM_VERIFY(max_it > 0, "max_it must be strictly positive")
int dim = mesh.Dimension();
L2_FECollection l2fec(order, dim);
FiniteElementSpace* l2fes = NULL;
bool par = false;
GridFunction *gf = NULL;
#ifdef MFEM_USE_MPI
ParMesh* pmesh = dynamic_cast<ParMesh*>(&mesh);
if (pmesh && pmesh->Nonconforming())
{
par = true;
l2fes = new ParFiniteElementSpace(pmesh, &l2fec);
gf = new ParGridFunction(static_cast<ParFiniteElementSpace*>(l2fes));
}
#endif
if (!par)
{
l2fes = new FiniteElementSpace(&mesh, &l2fec);
gf = new GridFunction(l2fes);
}
// If custom integration rule has not been set,
// then use the default integration rule
if (!irs)
{
int order_quad = 2*order + 3;
for (int i=0; i < Geometry::NumGeom; ++i)
{
ir_default[i] = &(IntRules.Get(i, order_quad));
}
irs = ir_default;
}
for (int i = 0; i < max_it; i++)
{
// Compute number of elements and L2-norm of f.
int NE = mesh.GetNE();
int globalNE = 0;
double norm_of_coeff = 0.0;
if (par)
{
#ifdef MFEM_USE_MPI
globalNE = pmesh->GetGlobalNE();
norm_of_coeff = ComputeGlobalLpNorm(2.0,*coeff,*pmesh,irs);
#endif
}
else
{
globalNE = NE;
norm_of_coeff = ComputeLpNorm(2.0,*coeff,mesh,irs);
}
// Compute average L2-norm of f
double av_norm_of_coeff = norm_of_coeff / sqrt(globalNE);
// Compute element-wise L2-norms of (I - Π) f
Vector element_norms_of_fine_scale(NE);
gf->SetSpace(l2fes);
gf->ProjectCoefficient(*coeff);
gf->ComputeElementL2Errors(*coeff,element_norms_of_fine_scale,irs);
// Define osc_K(f) := || h ⋅ (I - Π) f ||_K and select elements
// for refinement based on threshold. Also record relative osc(f).
global_osc = 0.0;
mesh_refinements.SetSize(0);
element_oscs.Destroy();
element_oscs.SetSize(NE);
element_oscs = 0.0;
for (int j = 0; j < NE; j++)
{
double h = mesh.GetElementSize(j);
double element_osc = h * element_norms_of_fine_scale(j);
if ( element_osc > threshold * av_norm_of_coeff )
{
mesh_refinements.Append(j);
}
element_oscs(j) = element_osc/(norm_of_coeff + 1e-10);
global_osc += element_osc*element_osc;
}
#ifdef MFEM_USE_MPI
if (par)
{
MPI_Comm comm = pmesh->GetComm();
MPI_Allreduce(MPI_IN_PLACE, &global_osc, 1, MPI_DOUBLE, MPI_SUM, comm);
MPI_Comm_rank(comm, &rank);
}
#endif
global_osc = sqrt(global_osc)/(norm_of_coeff + 1e-10);
// Exit if the global threshold or maximum number of elements is reached.
if (global_osc < threshold || globalNE > max_elements)
{
if (global_osc > threshold && globalNE > max_elements && rank == 0 &&
print_level)
{
MFEM_WARNING("Reached maximum number of elements "
"before resolving data to tolerance.");
}
delete l2fes;
delete gf;
return STOP;
}
// Refine elements.
mesh.GeneralRefinement(mesh_refinements, nonconforming, nc_limit);
l2fes->Update(false);
gf->Update();
}
delete l2fes;
delete gf;
return CONTINUE + REFINED;
}
void CoefficientRefiner::Reset()
{
element_oscs.Destroy();
global_osc = 0.0;
coeff = NULL;
irs = NULL;
}
int Rebalancer::ApplyImpl(Mesh &mesh)
{
#ifdef MFEM_USE_MPI

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