Compare commits

...
Author SHA1 Message Date
Justin Crum bb7ecb5f26 Some comments to make it clear what some newer parts are doing. 2020-08-07 13:30:20 -07:00
Justin Crum 3f9dd93102 Edits to make the NoConverge.txt file clearer. 2020-07-15 09:35:03 -07:00
Justin Crum 6f4e1f3419 Adding a couple of lines to output a file called NoConverge.txt if the code doesn't finish by the final time. 2020-07-15 09:20:56 -07:00
Justin Crum ee39c4cc11 Allowing command line parameter -rt # to input a relative tolerance for stopping criterion. Defaults to a value of 1e-6. 2020-07-13 15:45:02 -07:00
Justin Crum 3c103ad217 Further testing with changing relative tolerance for stopping criterion to 1e-6. 2020-07-13 15:35:41 -07:00
Justin Crum db9775e18d Trialing different stopping conditions by varying relative error tolerances. 2020-07-13 12:58:43 -07:00
Justin Crum 7bde510930 Changing how the output file is saved. 2020-07-08 13:57:17 -07:00
Justin Crum f34ae6d9f4 Changing to save only the final time step of data. 2020-07-02 13:27:05 -07:00
Justin Crum 9356ce68e0 Added the ability to change the height at which the lid is implemented. 2020-06-29 13:47:51 -07:00
Justin Crum a7dea72193 Moving the lid speed to the context section. 2020-06-24 15:07:06 -07:00
Justin Crum d44b6d63fc Fixed an error with the lid speed not getting used properly. 2020-06-24 15:03:20 -07:00
Justin Crum bc96e63a99 Allowing both kinematic viscosity and lid speed to be changed via command line entries. 2020-06-24 14:37:43 -07:00
Justin Crum 4db2a2538a Switching outputs to ascii format. 2020-06-23 15:54:55 -07:00
Justin Robert Crum d8223e67a4 Fixing merge conflicts with unnecessary includes. 2020-06-16 13:19:30 -07:00
Justin Robert Crum dc2c634ba6 navier_ldc.cpp updated to allow for command line inputs for the mesh choice. 2020-06-16 13:16:45 -07:00
Andrew Gillette f38f8ba472 Navier_ldc edits from Justin Crum - waiting for his git access. 2020-06-15 16:30:21 -07:00
Justin Robert Crum bf02567aaa Updating navier_ldc to give paraview outputs. 2020-06-15 14:00:44 -07:00
Andrew Gillette 6039d96d4e Addded navier_ldc to makefile 2020-06-07 13:13:02 -07:00
Andrew Gillette ac2777f46c Starting branch for lid-driven cavity problem in navier miniapp 2020-06-05 14:09:39 -07:00
Tzanio Kolev b484581a08 Merge pull request #1473 from mfem/hypre-smoother-cg-iter-dev
Change number of CG iterations in HypreSmoother [hypre-smoother-cg-iter-dev]
2020-06-02 10:39:42 -07:00
Veselin Dobrev df18895428 Merge pull request #1281 from mfem/qfvc-dev
QuadratureFunction Coefficient and VectorCoefficient classes
2020-06-01 14:24:52 -07:00
Veselin Dobrev fcaeaeb96a Merge branch 'master' into qfvc-dev 2020-06-01 13:06:32 -07:00
Tzanio Kolev f8174fa8cd Merge pull request #1454 from mortezah/pumi2mfem_field_transfer
Pumi2mfem field transfer updates [pumi2mfem_field_transfer]
2020-05-31 16:20:48 -07:00
Morteza HS a9bcd488cb Adds the new pumi version 2.2.3 2020-05-26 13:14:52 -04:00
Veselin Dobrev 21401db8fa Merge pull request #1352 from mfem/tmop-multidiscrete-dev
Using multiple discrete functions with TMOP for adaptivity
2020-05-25 13:26:28 -07:00
Veselin Dobrev 50de57707d Merge branch 'master' into tmop-multidiscrete-dev 2020-05-25 12:18:19 -07:00
Veselin Dobrev 884563c027 Merge branch 'master' into qfvc-dev 2020-05-25 11:55:19 -07:00
Morteza HS 8d458616a7 Updates PUMI version 2020-05-25 14:03:08 -04:00
Tzanio Kolev 63b73b21a8 Merge pull request #1047 from mfem/x86
Intrinsic for the high-performance templated operator [x86]
2020-05-25 10:06:33 -07:00
Robert db90d96e3b CHANGELOG additions 2020-05-22 19:51:10 -07:00
Robert a68ed06b7e address last few comments 2020-05-22 19:50:45 -07:00
Tomov ecaf79cb0b Compilation warnings. 2020-05-22 16:30:10 -07:00
Tomov 1d43d15b5c Alignments. 2020-05-22 16:05:46 -07:00
Robert Carson a2a6e38ce9 Merge branch 'master' into qfvc-dev 2020-05-22 13:42:06 -07:00
Robert 695e98a6c8 Make LinearFormIntegrator::SetIntRule virtual 2020-05-22 12:42:08 -07:00
Morteza H. Siboni 40fb147676 Fixes problem with overloaded virt. function Load 2020-05-21 15:19:20 -04:00
Morteza H. Siboni 78a8c79755 Removes unused static functions 2020-05-21 15:01:56 -04:00
Robert c663cc3925 make style 2020-05-21 11:34:35 -07:00
Robert 21c73b4076 Addressing comments made in tech talk 2020-05-21 11:33:24 -07:00
Veselin Dobrev 6cb5a2abb1 Small tweak to avoid using a function before it is declared. 2020-05-21 10:56:52 -07:00
Tzanio 51dfbfeb6e Fix fo unary minus with AVX512 when AVX512DQ is not available. 2020-05-21 10:38:00 -07:00
Tzanio Kolev 261fd7adcd Merge pull request #919 from mfem/builddoftoarrays-dev
Automatically call BuildDofToArrays() in certain ProjectCoefficient() signatures [builddoftoarrays-dev]
2020-05-21 08:01:06 -07:00
Tzanio Kolev 29748560ed Merge pull request #1456 from mfem/trueaddmult-pa-dev
Adding PA support to ParBilinearForm::TrueAddMult [trueaddmult-pa-dev]
2020-05-21 08:00:00 -07:00
Veselin Dobrev 13a2b369c2 In the miniapps/performance makefile, run compiler auto-detection
only when needed.
2020-05-20 12:23:32 -07:00
Morteza H. Siboni 6f6e134d45 Uses (( )) inside while loop condition 2020-05-20 15:01:04 -04:00
Veselin Dobrev 7206a673ee Alternative definition for unary minus with AVX512 when AVX512DQ is
not available.
2020-05-20 10:20:57 -07:00
Veselin Dobrev d8c1556dec Merge branch 'master' into tmop-multidiscrete-dev 2020-05-19 21:06:40 -07:00
Veselin Dobrev 44837bbb66 Restore a CHANGELOG entry. 2020-05-19 20:41:44 -07:00
Veselin Dobrev b28b5370d1 Remove the MFEM_HOST_DEVICE specifiers from the operator[] methods
in class TVector -- this was causing compilation errors when CUDA is
enabled.
2020-05-19 20:32:50 -07:00
Veselin Dobrev 5f0ff9d5ca Remove repeated CHANGELOG entry. 2020-05-19 20:31:24 -07:00
Veselin Dobrev 5a37ae4b85 Merge branch 'master' into x86
Resolved conflicts:
   CHANGELOG
2020-05-19 20:27:09 -07:00
Tzanio Kolev 4fc13517f5 Merge pull request #1194 from mfem/gf-getvalue-dev
Generalizing GridFunction::GetValue methods [gf-getvalue-dev]
2020-05-19 10:34:28 -07:00
Tzanio Kolev cc49757166 Merge branch 'master' into gf-getvalue-dev 2020-05-19 10:34:14 -07:00
Tzanio 100cae1158 minor 2020-05-19 10:30:47 -07:00
Tzanio Kolev c04de102c3 Merge branch 'master' into hypre-smoother-cg-iter-dev 2020-05-19 09:32:35 -07:00
Ketan Mittal a87dd49930 Merge branch 'master' of https://github.com/mfem/mfem into tmop-multidiscrete-dev 2020-05-19 08:24:15 -07:00
Ketan Mittal 6d101ca8bd merge with master and update changelog 2020-05-19 08:23:16 -07:00
Robert 03ed06bd7a make style 2020-05-18 20:13:16 -07:00
Robert c915cc791f Improve on verification checks related to making sure integration rules are the same 2020-05-18 20:12:22 -07:00
Robert 17580ca044 make style and a few small edits to address some other concerns 2020-05-18 18:56:35 -07:00
Tzanio Kolev 53278144c3 Merge pull request #879 from mfem/lp-error-est-dev
Error estimator based on Lp errors [lp-error-est-dev]
2020-05-18 17:08:11 -07:00
Tzanio Kolev 95712c91a8 Merge branch 'master' into lp-error-est-dev 2020-05-18 17:07:29 -07:00
Tzanio 0f5c506955 Mention integration order change in CHANGELOG 2020-05-18 17:07:04 -07:00
Tzanio Kolev a5b7fba3d4 Merge pull request #1400 from mfem/ext-dh-wrap
Memory wraps for pair of h_ptr/d_ptr [ext-dh-wrap]
2020-05-18 16:57:35 -07:00
Tzanio 069ad59143 minor 2020-05-18 16:54:29 -07:00
Robert 763a8c6236 Addressing some of the concerns in relations to FieldInterpolant class 2020-05-18 16:52:50 -07:00
Robert e9e145b01b Change VQFC and QFC from holding pointers for QF to it being a reference 2020-05-18 16:09:28 -07:00
camierjs 0a1019669f Merge branch 'master' into x86 2020-05-18 15:46:22 -07:00
Veselin Dobrev b86a6ab0e1 Merge pull request #1485 from mfem/x86-updates
Some updates to the SIMD intrinsics branch
2020-05-18 15:44:09 -07:00
Robert 728777c5be Address comments regarding VQFC, QFC, QF classes 2020-05-18 13:34:54 -07:00
Veselin Dobrev 1be972b036 In the performance miniapps, print the SIMD width in terms of "doubles". 2020-05-18 10:56:06 -07:00
Tzanio 2274d411f7 New COPYRIGHT banner, minor edits 2020-05-17 11:30:15 -07:00
Tomov 9294603134 Minor - comments, alignments, etc. 2020-05-16 22:39:25 -07:00
Veselin Dobrev ed96b27547 Minor consistency fix. 2020-05-16 17:40:27 -07:00
Veselin Dobrev fbb60d2ae1 Fix .travis.yml
[skip appveyor]
2020-05-16 16:56:18 -07:00
Veselin Dobrev 41e5c9b205 A few small fixes and tweaks. 2020-05-16 15:28:04 -07:00
Veselin Dobrev b68643cbec In the performance miniapps, print the MFEM SIMD width.
In the miniapps/performance makefile, print the auto-detected compiler
and if that fails, the print the output used for auto-dection.
2020-05-16 14:04:54 -07:00
Veselin Dobrev 74a892bb78 Add support for x86/x64 intrinsics with MSVC. 2020-05-16 13:21:13 -07:00
Veselin Dobrev d0221b980c Move the SIMD headers from 'config' to 'linalg'. 2020-05-16 08:14:38 -07:00
Veselin Dobrev b60159377c In class Memory, guard against allocating over-aligned types with
'new' if not using c++17 or newer.
2020-05-15 17:27:31 -07:00
Tzanio Kolev d14a31483d Merge pull request #1340 from mfem/yohann/mass-emat
Implement Element Assembly
2020-05-15 16:16:53 -07:00
Tzanio 773d266093 Edited CHANGELOG 2020-05-15 16:14:42 -07:00
Tzanio 2b8eb900f6 Merge branch 'yohann/mass-emat' of github.com:mfem/mfem into yohann/mass-emat 2020-05-15 16:01:17 -07:00
Tzanio 10c0a9c92b Minor styling 2020-05-15 16:01:12 -07:00
Yohann 4ff9fa3c28 Merge branch 'master' into yohann/mass-emat 2020-05-15 15:58:37 -07:00
Yohann Dudouit e9ec68befe Edit CHANGELOG. 2020-05-15 15:55:07 -07:00
Yohann Dudouit 29f9f11652 Edit documentation. 2020-05-15 15:54:57 -07:00
Veselin Dobrev c9d9d0f8ff Various tweaks in the template + SIMD code. Make sure the SIMD
interinsics can be used when CUDA is enabled.

A few tweaks related to adios2 when building with GNU make.
2020-05-15 12:33:07 -07:00
Morteza HS f55a46e2e7 Adds notes about the location of pumi mesh/models 2020-05-15 01:37:21 -04:00
Tzanio Kolev 88ae0ca089 Merge pull request #1451 from mfem/gf-exchange-face-nbr-data-fix
Add support for vector FE in ParGridFunction::ExchangeFaceNbrData [gf-exchange-face-nbr-data-fix]
2020-05-14 17:52:09 -07:00
Tzanio Kolev 83f1ad62d2 Merge pull request #1447 from mfem/minor-bugfixes
Minor bugfixes [minor-bugfixes]
2020-05-14 17:51:48 -07:00
Tzanio Kolev e3458aabfc Merge branch 'master' into minor-bugfixes 2020-05-14 17:51:36 -07:00
Tzanio Kolev 85333e2ce0 Merge branch 'master' into gf-exchange-face-nbr-data-fix 2020-05-14 17:50:45 -07:00
Tzanio Kolev 346df05aa7 Merge branch 'master' into trueaddmult-pa-dev 2020-05-14 17:23:30 -07:00
Morteza HS b0935c7f63 Updates MFEM_USE_PUMI instructions in INSTALL 2020-05-13 20:22:37 -04:00
Morteza HS a23760dd80 Fixes variable length arrays 2020-05-13 19:54:16 -04:00
Morteza HS 5667a72b24 Fixes styles 2020-05-13 19:46:21 -04:00
Morteza HS 76b3f742c5 Removes commented code 2020-05-13 19:12:15 -04:00
Morteza HS 9ce518a722 Cleans up pumi to mfem field transfer routine
Now the same routine should work for both vector and scalar field
2020-05-13 19:10:53 -04:00
Veselin Dobrev 90f2ddf058 Merge pull request #1172 from mfem/hypre-mem-macro-dev
Moving HYPRE memory allocation macros to a common location [hypre-mem-macro-dev]
2020-05-13 14:47:05 -07:00
Veselin Dobrev 444b939834 Merge branch 'master' into hypre-mem-macro-dev 2020-05-13 13:49:14 -07:00
Stowell, Mark L 55ff02fe20 Adding CHANGELOG entry 2020-05-13 10:53:06 -07:00
Veselin Dobrev 41394b6fd3 Merge pull request #1448 from mfem/barker29/doftoquad-bugfix
[barker29/doftoquad-bugfix] minor bug in VectorTensorFiniteElement::GetTensorDofToQuadm
2020-05-13 10:06:36 -07:00
Veselin Dobrev 369d7cc96e Merge branch 'master' into barker29/doftoquad-bugfix 2020-05-13 09:29:11 -07:00
Tzanio Kolev 39db486ab9 Merge branch 'master' into lp-error-est-dev 2020-05-12 12:38:29 -07:00
Stowell, Mark L 6b7c8bf33b Changing to CeedGridCoef::coeff to const to conform to GridFunctionCoefficient class 2020-05-12 12:08:48 -07:00
Stowell, Mark L 0bd112160c Removing reference to documentation that no longer exists 2020-05-12 12:07:25 -07:00
Robert Carson 2123041a6a Merge branch 'master' into qfvc-dev 2020-05-12 11:20:28 -07:00
Tzanio e340b7b800 minor 2020-05-11 19:19:19 -07:00
Tzanio Kolev 3ea7061c98 Merge branch 'master' into ext-dh-wrap 2020-05-11 19:02:49 -07:00
Stowell, Mark L 493e8b7862 Merge remote-tracking branch 'origin/master' into gf-getvalue-dev 2020-05-11 16:01:59 -07:00
Tzanio 39e97357db Merge branch 'master' into minor-bugfixes 2020-05-11 12:18:38 -07:00
Andreas Schafelner 2245027aec make style 2020-05-11 14:36:06 +02:00
Andreas Schafelner fb73228fdb Added a brief description. 2020-05-11 10:48:41 +02:00
Tzanio Kolev 0edf8ffe4a Merge pull request #1422 from mfem/hypreblocks
Create a HypreParMatrix from blocks
2020-05-10 17:14:18 -07:00
Tzanio 9ce103df4b Updated CHANGELOG 2020-05-10 17:13:43 -07:00
Tzanio Kolev 8829b5ef03 Merge pull request #1415 from mfem/findpts-serialpatch
Additional interface for FindPointsGSLIB methods and bug fix
2020-05-10 17:03:04 -07:00
Tzanio 0f250b73a5 minor 2020-05-10 17:02:30 -07:00
Tzanio Kolev 2e175905d8 Merge pull request #1455 from mfem/miniapps-nurbs-fix
Minor bugfix in NURBS miniapps [miniapps-nurbs-fix]
2020-05-10 16:51:24 -07:00
Stowell, Mark L ada4fcca83 Moving field continuity enum to FiniteElementCollection 2020-05-06 14:52:48 -07:00
Tzanio Kolev e559d93b5f Merge pull request #1337 from mfem/matrix-coef-mass-bug-fix
VectorFEMassIntegrator bug fix [matrix-coef-mass-bug-fix]
2020-05-06 14:25:17 -07:00
Stowell, Mark L f8bd593d5f Adding unit tests for EDGE and FACE cases of GetValue and GetVectorValue 2020-05-06 14:21:43 -07:00
Stowell, Mark L a090b75f26 Replacing explicit 2's and 3's with dim in get value unit tests 2020-05-06 14:21:10 -07:00
Stowell, Mark L 0a6113d497 Adding EDGE and FACE cases to GetValue and GetVectorValue for continuous fields 2020-05-06 13:44:46 -07:00
Stowell, Mark L af3cdb67ea Clarifying the FaceElementTransformation::SetGeometryType documentation 2020-05-05 11:09:11 -07:00
Stowell, Mark L 15e0e4d1aa Setting default value for ElementTransformation::geom 2020-05-05 10:48:28 -07:00
Tzanio Kolev 0f067d4139 Merge pull request #1390 from mfem/feature/monitor
Add IterativeSolverMonitor [feature/monitor]
2020-05-03 14:07:36 -07:00
Veselin Dobrev a95474b1e5 Proposed updates for the 'x86' branch. 2020-05-03 01:19:08 -07:00
Morteza H. Siboni e4afb9dc70 fixes style 2020-05-02 11:47:17 -04:00
Morteza H. Siboni d6a4827869 Updates pumi ex6p for changes made to pumi code 2020-05-02 11:43:18 -04:00
Morteza H. Siboni 458c1f45ff Changes ~ParPumiMesh() to default.
v_num_loc must persist throughout. It will need to be updated each time
the underlying pumi_mesh is changed, and should never be destroyed
manually during an adaptive solve (in the application code).
2020-05-02 11:41:23 -04:00
Morteza H. Siboni 18f90a2bce Updates declarations in pumi.hpp to match w/ .cpp 2020-05-02 11:01:51 -04:00
Dylan Copeland 409f3ad65f Reverting ex5p to the master version. 2020-05-01 17:17:30 -07:00
Dylan Copeland a238a820ee Merge branch 'master' of github.com:mfem/mfem into hypreblocks 2020-05-01 16:28:28 -07:00
Dylan Copeland 0ded2725e8 Adding some comments and fixing a memory leak in ex5p. 2020-05-01 11:53:08 -07:00
Stowell, Mark L b86570dd2f Merge remote-tracking branch 'origin/master' into matrix-coef-mass-bug-fix 2020-05-01 10:32:02 -07:00
Stowell, Mark L 9381b21a69 Expanding the description of LpErrorEstimator 2020-05-01 10:26:29 -07:00
Ketan Mittal 46752b3620 minor fix to CMakeLists for gslib miniapp in parallel 2020-05-01 08:08:33 -07:00
Veselin Dobrev d07a98fff2 Fix typos in the MFEM_THREAD_SAFE sections of nurbs_ex1/1p.
Add '-no-vis' option to the 'minimal-surface' tests in CMake.

Thread-safe issue reported by: @makeclean (#1452)
2020-04-30 23:27:23 -07:00
Morteza HS 62bf39a011 Fixes style 2020-05-01 02:13:22 -04:00
Veselin Dobrev 11f3414929 Merge pull request #1353 from mfem/rtpa
Partial assembly for H(div)
2020-04-30 22:48:31 -07:00
Will Pazner 3d21c46a90 Add operator sizes to TrueTransferOperator, L2Prolongation, and L2Projection 2020-04-30 14:35:23 -07:00
Morteza H. Siboni 2b1355a83a Merge branch 'master' of github.com:mfem/mfem into pumi2mfem_field_transfer 2020-04-30 15:04:22 -04:00
Morteza H. Siboni 37f64ec487 Cleans the field transfer routines + bug fix
This clean up is achieved by using getElementXis to get all the nodes
associated with a given tet, as opposed to computing those using loops.

Bug fix note:
The previous code would ignore the fact that the
tet-to-vertex connectivities could change when a PUMI mesh is converted
to an MFEM mesh. This means that for some of tets a given parent xi
coordinate would not be the same in the PUMI and MFEM meshes. Ignoring
this can cause incorrect field transfers. This is fixed now, by
explicitly checking the tet rotations and adjusting the xi coordinates
accordingly.
2020-04-30 14:56:58 -04:00
Stowell, Mark L 83c406a0a8 Removing redundant unit tests 2020-04-30 11:26:52 -07:00
Morteza H. Siboni 39d89aa961 Adds RotationPUMItoMFEM to ParPumiMesh
Also makes the default last argument in ParentXisPUMItoMFEM to be true.
This is because there is always rotated tets (due to orientation fix at
the boundary).
2020-04-30 14:19:51 -04:00
camierjs 6173cb7e4c MFEM_USE_SIMD defaulted to YES 2020-04-30 10:14:08 -07:00
camierjs 90f1552b94 Merge branch 'master' into x86 2020-04-30 09:52:08 -07:00
Stowell, Mark L a6afae3fc3 Improving the wording of a comment 2020-04-30 09:37:18 -07:00
camierjs 5c991972c7 External wrap documentation (h_mt,d_mt) 2020-04-30 09:25:22 -07:00
camierjs be28ce8812 Merge branch 'master' into ext-dh-wrap 2020-04-30 09:12:22 -07:00
Veselin Dobrev 8fa9a24e20 Add support for vector FE in ParGridFunction::ExchangeFaceNbrData()
Issue reported by: @hongbo-yao (#1440)
2020-04-30 02:26:25 -07:00
Morteza H. Siboni 049b447ec7 Uses apf::getElementXis instead of a loop
Previously this was done in a loop inside each of the field transfer
member functions (a lot of code repetition!). Now it is a single
function call that can be called by any of the field transfer members.
On this commit it is only used for the Nedelec field transfer routine.
2020-04-30 00:06:17 -04:00
Stowell, Mark L 3f15660960 Merge remote-tracking branch 'origin/master' into hypre-mem-macro-dev 2020-04-29 20:34:27 -07:00
Morteza H. Siboni 219c4fa736 Some clean up the Nedelec Field transfer routine
a) now used v_num_loc directly
b) added a new routine to get the rotated xi values
2020-04-29 20:47:15 -04:00
Stowell, Mark L 0f0e38283e Updating GetValue unit tests and adding 1D and 2D variants. Also adding GetVectorValue tests in 2D and 3D. 2020-04-29 16:59:10 -07:00
Stowell, Mark L 8511c709e3 Removing active side unit tests 2020-04-29 16:58:09 -07:00
Stowell, Mark L 408d5e411b T->Elem[12]->SetIntPoint is now handled internally by FaceElementTransformations::SetIntPoint 2020-04-29 16:57:51 -07:00
Stowell, Mark L 5394b3f8e5 Removing SetActiveSide from integrators 2020-04-29 16:56:41 -07:00
Stowell, Mark L 4619cf228d Using new field continuity information to simplify the logic in the GetValue and GetVectorValue methods 2020-04-29 16:55:57 -07:00
Stowell, Mark L c7f3b4049b Adding BDR_FACE element type for BdrFaceElementTransformations 2020-04-29 16:55:06 -07:00
Stowell, Mark L 8592a79c3d Removing ActiveSide concept from FaceElementTransformations 2020-04-29 16:54:19 -07:00
Stowell, Mark L 70acff2a18 Adding enumeration and methods to help distinguish continuous fields from limited continuity fields. 2020-04-29 16:53:39 -07:00
Andrew T. Barker 8c253ad11c Fix style 2020-04-28 16:10:44 -07:00
Andrew T. Barker d9c6c1597f Make ex10p.cpp look just like master. 2020-04-28 13:53:09 -07:00
Andrew T. Barker 7cca547853 Move residual monitor demonstration from ex10 to ex19 2020-04-28 13:28:19 -07:00
Will Pazner ee31c5d6d2 Update ILU unit test according to new ordering 2020-04-28 12:54:31 -07:00
Dylan Copeland 1d0e05b5fd Added the option to specify the number of serial mesh refinements in ex5p, and changed the star.mesh -pa sample run to use a coarser mesh. 2020-04-28 11:50:34 -07:00
Robert 3d10820417 Accidentally left FES in here when playing around with things 2020-04-28 11:20:07 -07:00
Andrew T. Barker 698241867e bugfix: fix minor bug in VectorTensorFiniteElement::GetTensorDofToQuad
The loop condition was incorrect.
2020-04-28 10:50:48 -07:00
Robert ddddb3dab8 fix ambiguous default parameter issue for the parallel builds
Since MPI_Comm is an int type the compiler was getting confused when trying to compile the parallel unit tests. So, I just moved the double parameters before the int CGSolver parameters.
2020-04-28 10:50:06 -07:00
Will Pazner 15125e4cc0 Merge remote-tracking branch 'origin/master' into minor-bugfixes 2020-04-28 10:36:47 -07:00
Ketan Mittal 52ce77da81 reviewer comments 2020-04-28 10:31:38 -07:00
Robert ad4b4c902e Update CGSolver with user options and default values 2020-04-28 09:51:46 -07:00
Dylan Copeland 49bb10823a Fixed memory leaks. 2020-04-27 22:32:07 -07:00
Stowell, Mark L 744c7aafb1 Adding VectorFEMassIntegerator tests with diagonal matrix coefficients 2020-04-27 20:08:17 -07:00
Yohann Dudouit 7226241e1e Remove ea from ex1/ex1p device sample runs. 2020-04-27 18:49:29 -07:00
Yohann Dudouit 4fa7c20419 Use public inheritance between PA and EA to avoid code ducplication. 2020-04-27 18:17:36 -07:00
Yohann Dudouit 72c69a9b0e Remove ElementAssembly from ex1 and ex1p. 2020-04-27 17:03:29 -07:00
Yohann Dudouit bc01b6079c Minor 2020-04-27 17:00:40 -07:00
Yohann Dudouit 43fe97f5f9 Revert "Use a string option to select the Assembly Level."
This reverts commit bd3f1bc431.
2020-04-27 16:56:31 -07:00
Samiullah Malik b03da60c17 Implements NedelecFieldMFEMtoPUMI 2020-04-27 19:41:49 -04:00
Stowell, Mark L 427453a1ff Merge remote-tracking branch 'origin/master' into gf-getvalue-dev 2020-04-27 11:56:43 -07:00
camierjs cd0c6e6a0c Revert auto.hpp and cleanup 2020-04-27 11:44:07 -07:00
camierjs 3e98c0b552 Address reviewer's comments 2020-04-27 11:03:04 -07:00
Veselin Dobrev 51a0cf05df Merge branch 'master' into feature/monitor 2020-04-24 22:42:45 -07:00
Robert 68a58b2188 Fixing ProjectQuadratureDiscCoefficient methods and unit tests based on GitHub comments related to L2
My understanding of where L2 FiniteElementSpace values was off. I thought they were at the element nodes, but it turns out they are just at the quadrature points instead.
2020-04-24 20:27:04 -07:00
Stowell, Mark L adf2ca72e9 Merge remote-tracking branch 'origin/master' into gf-getvalue-dev
# Conflicts:
#	fem/coefficient.cpp
2020-04-24 15:30:49 -07:00
Stowell, Mark L 9900068b7a Adding error checking to FaceElementTransformations 2020-04-24 15:16:33 -07:00
Andrew T. Barker 917f0ee3e5 Monitor: Fix parallel output in ex10p.cpp 2020-04-24 13:41:31 -07:00
Tomov e3d0907234 Valgrind. 2020-04-24 00:26:56 -07:00
Tomov dc18fc27a0 Valgrind errors. 2020-04-24 00:19:42 -07:00
Tomov 33b9f04412 Modified some of the sample runs to use GSLIB as they
don't work well with the advection.
Fixed some debug build warnings.
2020-04-23 23:59:14 -07:00
Tomov ad483c2d21 Merge branch 'master' into tmop-multidiscrete-dev 2020-04-23 22:35:18 -07:00
Tomov ca10dca105 Minor edits in mesh-optimizer. 2020-04-23 22:33:30 -07:00
Robert 7bea8ddf8b Update unit tests to have vector coefficients be based on the projection of the mesh nodes to quadrature points and back to nodes 2020-04-23 20:21:36 -07:00
Ketan Mittal d9566397fd additional interface 2020-04-23 15:01:29 -07:00
Robert e87905396d Left out a set of ifdef to guard against parallel portions of the header file... 2020-04-23 13:36:42 -07:00
Robert 4252b22632 Refactor class FieldInterpolant to seperate out parallel implementation and not require the formation of bilinearform and cg objects to be repeatedly created each time a function is called. 2020-04-23 13:01:07 -07:00
Ketan Mittal 7102e5f53e ading cube.mesh 2020-04-23 12:13:08 -07:00
Tomov 08bff51ce8 Updated comments. 2020-04-23 11:30:11 -07:00
Robert e38ae35ceb Add tests for FiniteElementSpace Ordering::ByVDIM and bug fixes to have it work correctly 2020-04-22 17:45:47 -07:00
Robert 18b488d14d Get rid of reorder warning 2020-04-22 16:50:20 -07:00
Robert 75dab15fc8 Fixed bracket in wrong place for ifdef 2020-04-22 16:49:41 -07:00
Robert 57fbb7e7ab Bug fix and parallel implementation is now added along with relevant bug fixes 2020-04-22 15:34:57 -07:00
Ketan Mittal aea7ed6069 changes to discrete adaptivity 2020-04-22 14:00:29 -07:00
Robert b1bacf9b3f fix uninitialized value 2020-04-22 11:33:25 -07:00
Tomov c658d4ead0 Added some comments, const qualifiers. 2020-04-21 16:49:08 -07:00
Julian Andrej 90bbd93330 add to CHANGELOG 2020-04-21 16:41:55 -07:00
Stowell, Mark L 41e0872d79 Removing uses of deprecated FaceElementTransformations features 2020-04-21 15:01:23 -07:00
Stowell, Mark L fdae3b1f19 Adding a "Set" method to replace the deprecated public FaceGeom member data 2020-04-21 15:00:21 -07:00
camierjs b262dbc40d Merge branch 'master' into ext-dh-wrap 2020-04-21 13:59:40 -07:00
camierjs ab57721a3d Merge branch 'master' into x86 2020-04-21 13:55:28 -07:00
Dylan Copeland a90e329043 More VS errors. 2020-04-21 13:28:33 -07:00
Dylan Copeland 4bdbcb30b6 Fixing another VS error. 2020-04-21 12:40:41 -07:00
Ketan Mittal 408fe9270d merge with master and resolve conflicts 2020-04-21 12:32:50 -07:00
Yohann Dudouit 9c32615e8c Merge branch 'master' into yohann/mass-emat 2020-04-21 12:09:44 -07:00
Dylan Copeland 71ecff776a Merge branch 'master' of https://github.com/mfem/mfem into rtpa
Conflicts:
	CHANGELOG
	linalg/operator.cpp
2020-04-21 11:48:59 -07:00
Ketan Mittal 662ffefdb8 reviewer comments 2020-04-21 11:26:19 -07:00
Dylan Copeland f91341e59d Fixing a constant expression for VS. 2020-04-20 19:51:27 -07:00
Yohann Dudouit 5aef8f8c8c Revert CMakeLists 2020-04-20 18:55:03 -07:00
Yohann Dudouit 79ec5c24ae make style 2020-04-20 18:53:31 -07:00
Yohann Dudouit 1f6b56447a make style 2020-04-20 18:47:48 -07:00
Yohann 014697673e Merge branch 'master' into yohann/mass-emat 2020-04-20 18:45:25 -07:00
Yohann Dudouit bd3f1bc431 Use a string option to select the Assembly Level. 2020-04-20 18:43:38 -07:00
Yohann Dudouit f989040c0d Add a unit test for Element Assembly. 2020-04-20 17:22:48 -07:00
Yohann Dudouit f25963eb41 Fix a bug in EA::Mult. 2020-04-20 17:16:46 -07:00
Yohann Dudouit f9d66a6839 Remove includes of ElementMatrix. 2020-04-20 15:58:09 -07:00
Yohann Dudouit 18e1762286 Remove commented code. 2020-04-20 15:16:40 -07:00
Yohann Dudouit 29150be9ae Remove the ElementMatrix classes. 2020-04-20 15:11:39 -07:00
Robert 881539dfb5 make style 2020-04-20 15:03:46 -07:00
Robert 02caf2cdf0 All L2 projection methods now work but still missing parallel implementations 2020-04-20 15:01:29 -07:00
Will Pazner 2073fcfb70 Improve minimum discarded fill ordering for ILU 2020-04-20 13:51:26 -07:00
Will Pazner d22a1a8a77 Fix parallel file I/O bug for ParaView output 2020-04-20 13:50:35 -07:00
Will Pazner 78744e4438 Remove unneeded function in ParaViewDataCollection 2020-04-20 13:50:17 -07:00
Will Pazner b5078e593b Merge branch 'master' of github.com:mfem/mfem into minor-bugfixes 2020-04-20 13:47:00 -07:00
Robert 1e8f50bcd6 make style 2020-04-20 11:16:44 -07:00
Robert 1478efc4b0 Fixes to FieldInterpolant class and update tests 2020-04-20 11:15:16 -07:00
Robert bfb9d3e705 WIP: Initial shot at L2 projection for VQFC and QFC
This compiles but no idea if it actually runs like it should yet...
2020-04-19 18:17:09 -07:00
Andrew T. Barker ec246395ce Merge branch 'feature/monitor' of github.com:mfem/mfem into feature/monitor 2020-04-17 14:40:23 -07:00
Andrew T. Barker bf6dc2e6de Fix style. 2020-04-17 14:40:12 -07:00
Stowell, Mark L 7ade67276d Merge remote-tracking branch 'origin/master' into hypre-mem-macro-dev 2020-04-17 14:21:21 -07:00
Stowell, Mark L 4f2caaacc1 Merge remote-tracking branch 'origin/master' into lp-error-est-dev
# Conflicts:
#	tests/unit/fem/test_3d_bilininteg.cpp
2020-04-17 13:57:16 -07:00
Ketan Mittal 671923f041 addressing reviewer comments 2020-04-17 11:06:32 -07:00
Tomov 4cf82c950e Comments / alignments / unused variables. 2020-04-16 19:18:34 -07:00
camierjs 249cbb3274 Merge branch 'master' into x86 2020-04-16 15:45:09 -07:00
camierjs 1b3e32e27a Merge branch 'master' into ext-dh-wrap 2020-04-16 15:44:18 -07:00
Ketan Mittal da531c4460 minor 2020-04-16 13:06:21 -07:00
Ketan Mittal 64da10077d Merge branch 'master' of https://github.com/mfem/mfem into tmop-multidiscrete-dev 2020-04-16 12:46:38 -07:00
Dylan Copeland f79e69daef Rearranging vector FE PA code in different files. 2020-04-16 12:14:29 -07:00
Andrew T. Barker 5971f8ce10 Merge branch 'master' into feature/monitor 2020-04-16 09:54:47 -07:00
Andrew T. Barker b68838f7a1 Add final argument to Monitor, and demonstrate a custom monitor in ex14p 2020-04-16 09:51:17 -07:00
Andrew T. Barker 5b75d014f6 Add Monitor() call to NewtonSolver 2020-04-16 09:16:53 -07:00
Andrew T. Barker 0fd9e5218f Add Monitor() calls to MINRESSolver
I am about 80 percent confident I am passing the "right" residual vector
to the monitor routine.
2020-04-16 09:11:30 -07:00
Andrew T. Barker d8cd06ea39 Add Monitor() calls to FGMRES and BiCGSTAB
BiCGSTAB has two residuals, r and s. I have chosen to only monitor r, ignoring
s, but this is an arguable choice.
2020-04-16 08:57:17 -07:00
Dylan Copeland 2f0b2599c7 CHANGELOG 2020-04-15 21:28:34 -07:00
Dylan Copeland b252ea0bb1 Removing device support from example 5. 2020-04-15 18:51:05 -07:00
Dylan Copeland af278650d3 Fixed a bug in the rectangular case. Added the option to provide block coefficients. Added a rectangular parallel unit test. 2020-04-15 16:44:58 -07:00
Stowell, Mark L a6b908f23e Removing unneeded tests 2020-04-15 15:18:43 -07:00
Stowell, Mark L 650a61b093 Fix variable names 2020-04-15 15:07:17 -07:00
Stowell, Mark L f8e50b4aa4 make style 2020-04-15 15:04:04 -07:00
Stowell, Mark L 00edaa1089 Merge remote-tracking branch 'origin/master' into matrix-coef-mass-bug-fix
# Conflicts:
#	tests/unit/fem/test_3d_bilininteg.cpp
2020-04-15 15:03:45 -07:00
Dylan Copeland 3c36cc62a4 Trying to fix some cuda issues for ex5. 2020-04-15 12:35:53 -07:00
Robert 03b50176d9 Should fix issues with eval passing back the underlying quadrature data 2020-04-15 09:13:50 -07:00
Andreas Schafelner 59901ecddc Default value in default constructor. 2020-04-15 17:09:23 +02:00
Andreas Schafelner eefde7fc9d Added variable eig_est_cg_iter to HypreSmoother.
Behaves as before if eig_est_cg_iter != 0, and uses hypre_ParCSRMaxEigEstimate to estimate the maximum eigenvalue otherwise.
2020-04-15 15:08:06 +02:00
Robert 9ab36ea057 Small updates to VQFC and QFC classes to address some of the comments 2020-04-14 11:14:49 -07:00
Stowell, Mark L a39c7cb753 Fixing return type on ParMesh::GetGhostFaceTransformation 2020-04-14 10:33:53 -07:00
Stowell, Mark L 0be1846a73 Merge remote-tracking branch 'origin/master' into gf-getvalue-dev
# Conflicts:
#	mesh/pmesh.cpp
2020-04-14 10:29:23 -07:00
Stowell, Mark L c20a680439 Revert u coefficient to use volume element transformation 2020-04-14 10:24:08 -07:00
Stowell, Mark L a407734872 Reverting lambda and mu evaluations to use volume element transformations 2020-04-14 10:11:50 -07:00
Dylan Copeland 2fdb4ad455 Added the new function HypreParMatrixFromBlocks and an example of its use in ex5p. 2020-04-12 20:45:41 -07:00
Ketan Mittal 0cfea84cba add a leaner FindPoints interface 2020-04-10 12:56:51 -07:00
Ketan Mittal b402c45a06 fix use in serial with parallel build 2020-04-10 10:30:25 -07:00
Ketan Mittal 1c4155dc7b minor fix to findpts 2020-04-09 08:59:11 -07:00
Yohann Dudouit 0dfbf2c784 Update CMakeLists 2020-04-08 15:00:14 -07:00
Yohann Dudouit df384d8bf9 Split elementmatrix into .hpp and .cpp. 2020-04-08 14:37:05 -07:00
Yohann Dudouit 3821482466 make style 2020-04-08 12:57:56 -07:00
Yohann Dudouit 6dbfaafa30 Replace Print() with overlaod of operator<<. 2020-04-08 12:33:06 -07:00
Stowell, Mark L b0ddd613fd Adding doxygen warnings to GetValue(int i,...) methods 2020-04-08 11:24:17 -07:00
Stowell, Mark L 5fc741c731 make style 2020-04-08 10:57:40 -07:00
Stowell, Mark L 5f090c9542 Adding const GridFunction* from PR #716 to GridFunctionCoefficient classes 2020-04-08 10:57:22 -07:00
Stowell, Mark L 8436ce39bd Reproducing the effect of the mask when setting up the FaceElementTransformation 2020-04-08 10:46:27 -07:00
camierjs 72baf3e54c Update external wrap documentation 2020-04-08 10:23:04 -07:00
Stowell, Mark L a8d146622e FaceGeom is a reference so we don't need to set it this way. 2020-04-08 09:58:33 -07:00
Stowell, Mark L bb25ac674c Move a call to GetBdrElementDofs to avoid unneeded function call in DG context 2020-04-08 09:58:01 -07:00
Stowell, Mark L 52405412db Make FaceGeom a reference and add @deprecated comments. 2020-04-08 09:56:50 -07:00
Yohann Dudouit 996f27c48b Add device sample runs. 2020-04-07 17:54:16 -07:00
camierjs 7df19938c4 Use _aligned_free 2020-04-07 17:44:57 -07:00
Yohann Dudouit bfdc26c37a make style (last?) 2020-04-07 17:36:42 -07:00
Yohann Dudouit f439503647 make style (forever) 2020-04-07 17:34:40 -07:00
Yohann Dudouit 732ff75492 make style (again) 2020-04-07 17:25:07 -07:00
Yohann Dudouit 2c28c92a4a make style 2020-04-07 16:59:26 -07:00
camierjs d058f79591 Reset assembled_data 2020-04-07 16:47:19 -07:00
Dylan Copeland 386e02f0f8 Adding unit tests for H(curl) and H(div) diagonal partial assembly. 2020-04-07 16:24:04 -07:00
Yohann Dudouit f17748510c Change for BSD-3 license. 2020-04-07 16:10:51 -07:00
Yohann Dudouit 2fd8ad493c Merge branch 'master' into yohann/mass-emat 2020-04-07 16:07:21 -07:00
Yohann Dudouit 90d1e910ab Remove unused code in mass_ea. 2020-04-07 16:05:01 -07:00
Yohann Dudouit f19ac3dd6f Remove unused code in diffusion_ea. 2020-04-07 16:03:38 -07:00
Yohann Dudouit 61aadcf103 Remove unused code in dgtrace_ea. 2020-04-07 16:02:25 -07:00
Yohann Dudouit ae9cae0dec Remove unused code in convection_ea. 2020-04-07 16:01:35 -07:00
camierjs 6c63638300 Fix zstr.hpp(178): warning C4101: 'e': unreferenced local variable and try HOST_32 2020-04-07 15:39:12 -07:00
Dylan Copeland 5341e36ab2 Bug fix. 2020-04-07 15:33:25 -07:00
Stowell, Mark L e6fd16e6a5 Rearranging the comments to produce more effective doxygen output 2020-04-07 14:54:17 -07:00
Dylan Copeland 906bc734e4 Incorporating some of Yohann's suggestions. 2020-04-07 14:17:22 -07:00
camierjs b1e7bbaa11 Simplify assembled_data allocation 2020-04-07 14:07:31 -07:00
camierjs 4ec1f7782a Update CHANGELOG, remove MFEM_POSIX_MEMALIGN to use aligned Memory. 2020-04-07 13:53:48 -07:00
Dylan CopelandandYohann b771ad3f16 Apply suggestions from code review
Co-Authored-By: Yohann <dudouit1@llnl.gov>
2020-04-07 12:09:32 -07:00
Stowell, Mark L 8f76ce56fb Backward compatibility changes in FaceElementTransformations 2020-04-07 12:03:39 -07:00
camierjs a08e2b2b5e Meld toward master 2020-04-07 11:33:44 -07:00
camierjs 80ab2f4671 SIMD headers cleanup 2020-04-07 11:13:42 -07:00
Robert b75b24ddfa QuadratureFunctionCoeff tests now have a nonuniform project test 2020-04-07 10:58:06 -07:00
camierjs 75173ce65c Cleanup config/tconfig 2020-04-07 10:48:40 -07:00
Dylan Copeland 278d557fb4 Adding some comments. 2020-04-07 09:54:34 -07:00
Tomov 8d627d84c1 Minor. 2020-04-07 00:15:07 -07:00
Yohann Dudouit a3ce056626 Fix the need for ExchangeFaceNbrData in ex9p. 2020-04-06 16:51:10 -07:00
Yohann Dudouit b043ab52b3 Small style edit. 2020-04-06 15:58:10 -07:00
camierjs 9e679c9e90 Merge branch 'master' into x86 2020-04-06 15:21:57 -07:00
camierjs 094b89f70d Typo 2020-04-06 15:13:00 -07:00
camierjs afb934a92f Memory wraps for pair of h_ptr/d_ptr 2020-04-06 15:10:17 -07:00
Yohann Dudouit 70c2e9479d Add Element Assembly to ex1p. 2020-04-06 14:03:24 -07:00
Robert b776d12f1d Remove comment that's not needed 2020-04-06 14:00:32 -07:00
Robert 40c628f50b Merge branch 'qfvc-dev' of github.com:mfem/mfem into qfvc-dev 2020-04-06 13:46:45 -07:00
Robert fbdb989776 Fix slow QuadratureFunction::GetElementValues when provided int pt 2020-04-06 13:44:59 -07:00
Robert 7c23c922ec Address coefficient comments 2020-04-06 13:15:19 -07:00
Dylan Copeland 05c6b7290f Removing unused variables. 2020-04-06 12:54:06 -07:00
Andrew T. Barker a0a978b208 [PR into feature/monitor branch] simplify monitor interface (#1393)
* Simplify the IterativeSolverMonitor interface.

* Fix style.
2020-04-06 09:43:22 -07:00
Dylan Copeland 1b513bf32f Changed MultUnsigned to use gatherMap in ElementRestriction. Fixed ex4 in case SUITESPARSE is used. Added more checks for Q1D and D1D sizes. Shortened some long lines. 2020-04-02 19:10:42 -07:00
Dylan Copeland d90e017601 Removed some commented code. 2020-04-01 17:34:35 -07:00
Yohann Dudouit 9040fffa7a Replace std::cout with mfem::out 2020-04-01 15:45:11 -07:00
Morteza H. Siboni 9dae5eec55 Cleans the pumi related codes
1- Code repetition for ReadElement was fixed
2- getting nodes associated with an entity is repeated for MFEMToPUMI
field transfer routines (one of the is fixed in this commit but not yet
tested. Others need to be cleaned up as well.
3- TODO: It's probably possible to have one general field transfer
routine as opposed to multiples ones for different fields types.
2020-04-01 16:19:44 -04:00
rcarson3 efb8627383 Fix bugs for when vector coeff length isn't equal to quadfunc length for projections 2020-04-01 12:46:47 -07:00
Julian Andrej 04eec9733a Add IterativeSolverMonitor 2020-04-01 11:27:50 -07:00
Ketan Mittal ab2bc2aa50 make style 2020-03-31 14:36:08 -07:00
Ketan Mittal f7db02aa1b resolve conflicts and add sample runs to example 2020-03-31 14:30:35 -07:00
camierjs 2567c2bf75 Merge branch 'master' into x86 2020-03-30 10:18:16 -07:00
camierjs b9b27fc180 Merge branch 'x86' of github.com:mfem/mfem into x86 2020-03-30 10:16:59 -07:00
Dylan Copeland d7b0a8ce64 Merge branch 'master' of https://github.com/mfem/mfem into rtpa
Conflicts:
	examples/ex24.cpp
	examples/ex24p.cpp
	examples/ex5p.cpp
	fem/CMakeLists.txt
	tests/unit/fem/test_pa_coeff.cpp
2020-03-29 19:54:52 -07:00
Will Pazner 39647f4ffd Fix bug in RightSolve 2020-03-27 20:49:04 -07:00
Yohann Dudouit f58e57e870 Add AddMultTranspose to ElementAssembly. 2020-03-27 12:23:41 -07:00
Ketan Mittal 8b166f918b misc changes 2020-03-27 11:09:59 -07:00
Morteza H. Siboni bf53235250 Calls Finalize at the end of ParPumiMesh ctor
This is to fix the orientation for 2D meshes.
2020-03-27 02:05:11 -04:00
Yohann Dudouit dea6191644 Remove prints 2020-03-26 15:38:55 -07:00
Yohann Dudouit 1c9421a36f Clean ElementMatrix 2020-03-26 12:18:08 -07:00
Ketan Mittal 3ba59c3f12 merge with master and resolve conflicts 2020-03-25 14:39:59 -07:00
Robert d4d2c96646 unit test fixes 2020-03-24 13:20:19 -07:00
Robert b608ffafd6 Rename QuadratureVectorFunctionCoefficient to VectorQuadratureFunctionCoefficient 2020-03-24 13:09:00 -07:00
Ketan Mittal 5d7811a854 minor 2020-03-24 07:53:09 -07:00
Yohann Dudouit 524a44e0f6 make style 2020-03-23 17:12:22 -07:00
Yohann Dudouit 721ce79dc0 Fix a few bugs. 2020-03-23 17:06:17 -07:00
Yohann Dudouit aca9a1a07b Add Element Assembly to Transpose Integrator. 2020-03-23 15:57:40 -07:00
Ketan Mittal a8043e4f58 Merge branch 'master' of https://github.com/mfem/mfem into tmop-multidiscrete-dev 2020-03-23 10:08:13 -07:00
Yohann Dudouit 050003daab Fix a bug when allocating space for FaceMatrices 2020-03-20 18:50:37 -07:00
Yohann Dudouit 60c3324faf Fix bugs in DGTrace Integrator. 2020-03-20 18:49:33 -07:00
Yohann Dudouit 174d5f9c12 Treat SingleValued case in MultTranspose. 2020-03-20 18:49:03 -07:00
Yohann Dudouit c07851f849 Add Print() method to FaceMatrix 2020-03-20 18:48:35 -07:00
Robert b6dddeb01e make style 2020-03-20 13:59:31 -07:00
camierjs 445037c954 Merge branch 'master' into x86 2020-03-20 13:55:23 -07:00
Robert e237208800 Add unit tests for QuadVecFuncCoeff an QuadFuncCoeff 2020-03-20 13:51:40 -07:00
Yohann Dudouit b2530c6173 Fix a bug in FaceMatrixInt 2020-03-20 13:35:34 -07:00
Ketan Mittal 9c9e02f427 clean up 2020-03-20 10:14:57 -07:00
Robert 0c7796c40c Merge branch 'master' into qfvc-dev 2020-03-20 09:19:27 -07:00
Yohann Dudouit a86b5fda53 Separate Interior and Boundary faces kernels. 2020-03-19 18:59:31 -07:00
Yohann Dudouit 25a5bbbfa2 Add FaceMatrixBdr 2020-03-19 18:21:41 -07:00
Yohann Dudouit 72ef682f23 Add to ex9 an Element Assembly option: -ea. 2020-03-19 16:52:44 -07:00
Yohann Dudouit 7aa8f14dcd Fix a bug in SetupEA in DGTraceIntegrator 2020-03-19 16:51:10 -07:00
Yohann Dudouit 14f3ed6986 Modify ex1 to work Element Assembly. 2020-03-19 16:28:14 -07:00
Yohann Dudouit 3fe6414610 Fix a bug in dgtrace_ea. 2020-03-19 16:27:35 -07:00
Yohann Dudouit 495fe483f3 Integrate change for boundary vs interior faces. 2020-03-18 18:44:51 -07:00
Yohann Dudouit 8e9ff181d2 Skeleton for AddMult on faces. 2020-03-18 16:32:20 -07:00
Ketan Mittal c616458da6 minor 2020-03-18 14:30:01 -07:00
Ketan Mittal 911e383c69 unused variables 2020-03-18 14:26:06 -07:00
Ketan Mittal 6943d175ba minor 2020-03-18 12:11:05 -07:00
Yohann Dudouit 0f26cf2400 Skeleton for DGTrace assemble EA. 2020-03-17 17:37:10 -07:00
Ketan Mittal 45f4209fd2 minor 2020-03-17 16:28:55 -07:00
Ketan Mittal 637a941b06 Merge branch 'master' of https://github.com/mfem/mfem into tmop-multidiscrete-dev 2020-03-17 15:37:07 -07:00
Ketan Mittal aa8987cc10 make style 2020-03-17 15:36:37 -07:00
Ketan Mittal 3dc292f9f2 adding some 3D functionality 2020-03-17 15:35:29 -07:00
Yohann Dudouit 78e521fed7 Skeleton for FaceMatrix 2020-03-17 14:41:23 -07:00
Stowell, Mark L 0bf973d760 Removing temporary example 2020-03-16 21:32:40 -07:00
Stowell, Mark L 0472eca7d3 make style 2020-03-16 12:02:19 -07:00
Stowell, Mark L 59f037d46c Adding unit test for new GridFunction::GetValue variants 2020-03-16 11:15:40 -07:00
Stowell, Mark L 5a031461f7 Adding unit test for FaceElementTransformations 2020-03-15 17:15:51 -07:00
camierjs 1ed8afdf93 Merge leftovers fix 2020-03-15 16:03:11 -07:00
camierjs 333e5a8701 Merge branch 'master' into x86 2020-03-15 14:55:03 -07:00
Stowell, Mark L 535ab5f5dc Merge remote-tracking branch 'origin/master' into gf-getvalue-dev 2020-03-15 10:32:21 -07:00
Dylan Copeland 447a73cdac Implemented PA for ex5(p), with a new MixedBilinearForm function to assemble the diagonal of ADA^T for a diagonal D. 2020-03-13 13:59:54 -07:00
Ketan Mittal 7193e18aad merging with tmop-fd-dev 2020-03-13 13:14:59 -07:00
Ketan Mittal 1420be0a42 changes to tmop_tools 2020-03-13 09:57:43 -07:00
Ketan Mittal 1f6982cca6 merging with tmop-fd-dev 2020-03-13 09:57:02 -07:00
Stowell, Mark L 5d8aac53d1 Documenting the enumeration used in ElementTransformation 2020-03-13 00:08:37 -07:00
Stowell, Mark L c3f42bff3b make style 2020-03-12 23:04:10 -07:00
Stowell, Mark L 15d84fc9c4 Merge remote-tracking branch 'origin/master' into gf-getvalue-dev 2020-03-12 21:22:37 -07:00
Stowell, Mark L b6e1430a46 Fixing implementation that was overwritten by merge with master 2020-03-12 21:20:44 -07:00
Stowell, Mark L 8b81c29b2b Merge remote-tracking branch 'origin/master' into gf-getvalue-dev
# Conflicts:
#	fem/datacollection.cpp
#	fem/gridfunc.hpp
2020-03-12 20:56:28 -07:00
Stowell, Mark L b33654bfa4 make style 2020-03-12 18:00:42 -07:00
Stowell, Mark L 2da035cbdc Rearranging and documenting the various GridFunction::GetValue methods 2020-03-12 18:00:28 -07:00
Stowell, Mark L 18c9103305 Removing dead code 2020-03-12 15:36:55 -07:00
Stowell, Mark L 540e4deb5f Removing unnecessary recursive method call 2020-03-12 15:36:24 -07:00
Stowell, Mark L 80158f14b6 Removing unnecessary temporary variable 2020-03-12 15:35:44 -07:00
Stowell, Mark L d4697dd692 Adding comment block describing "active side" concept for FaceElementTransformations objects 2020-03-12 15:34:53 -07:00
Dylan Copeland 3e4f6a575c Debugged PA for the transpose of mixed H(div)-L2 bilinear form VectorFEDivergenceIntegrator. Added unit test for this mixed form, including its transpose. Added a test for this mixed bilinear form to ex24p. 2020-03-12 12:39:24 -07:00
Dylan Copeland 09f1e0fc48 Debugged PA for mixed H(div)-L2 bilinear form VectorFEDivergenceIntegrator. Added a test for this mixed bilinear form to ex24. 2020-03-11 16:14:52 -07:00
Yohann Dudouit ec3ac06ed5 minor 2020-03-10 16:45:57 -07:00
Dylan Copeland acec17cc3d Adding H(div) PA unit tests. 2020-03-10 15:41:47 -07:00
Yohann Dudouit 70cf00ebb2 Comment Smem usage to work on GPU for any order. 2020-03-10 15:35:28 -07:00
Dylan Copeland 84cac245c0 PA is working now in ex4 and ex4p. 2020-03-10 15:03:46 -07:00
Yohann Dudouit 341ba2d9ec Add Element Assembly for Diffusion Integrator. 2020-03-10 14:28:30 -07:00
Yohann Dudouit 80c4278a3e Add EA for Convection Integrator. 2020-03-10 10:31:10 -07:00
Dylan Copeland 0e496bbf96 Adding PA for RT spaces in H(div). 2020-03-09 10:43:09 -07:00
Yohann Dudouit 8a9dea2a0f Element Assembly working for mass on CPU and GPU. 2020-03-06 09:30:00 -08:00
Stowell, Mark L c05d5c2fb6 Expanding unit tests to catch incorrect DenseMatrix size in VectorFEMassIntegrator 2020-03-06 10:19:35 -05:00
Stowell, Mark L c9f366e0b0 Fixed size of temporary DenseMatrix 2020-03-06 10:18:51 -05:00
Yohann Dudouit 756f1354be Skeleton for EA 2020-03-04 17:04:44 -08:00
Yohann Dudouit aee9ec0e4d Initial commit for Mass Element Matrix. 2020-03-04 11:33:50 -08:00
Ketan Mittal 542239dcb2 merging with changes to tmop-fd-dev 2020-02-28 17:08:21 -08:00
Ketan Mittal 54764ae988 working version for multiple discrete fields 2020-02-28 16:34:23 -08:00
Ketan Mittal 360814df67 Merge branch 'tmop-fd-dev' of https://github.com/mfem/mfem into tmop-multidiscrete-dev 2020-02-27 08:52:07 -08:00
camierjs 52df77a770 Merge branch 'master' into x86 2020-02-25 17:15:58 -08:00
camierjs 9dbc2278b0 Merge branch 'master' into x86 2020-02-23 17:26:59 -08:00
camierjs 6ac509a5ed Merge branch 'master' into x86 2020-02-11 08:28:19 -08:00
camierjs 68f5a585b5 Merge branch 'master' into x86 2020-02-07 16:35:11 -08:00
rcarson3 364c3fe055 Additional run-time checks and nicer class construction 2020-02-05 09:20:20 -08:00
rcarson3 f8b0ecdba8 make style 2020-02-04 11:50:21 -08:00
rcarson3 b7ca7c3ca0 Initial QuadratureFunction Coefficient and VectorCoefficient implementations 2020-02-04 09:17:14 -08:00
Stowell, Mark L 8fb34a4cad Bug fixes in GetValues methods (thanks to unit testing) 2020-01-23 17:03:06 -08:00
Stowell, Mark L d8c11bb42d Setting index type in TMOP classes 2020-01-23 16:03:02 -08:00
Stowell, Mark L 57bd13e29e Setting index type in a couple missed locations 2020-01-23 15:59:00 -08:00
Stowell, Mark L 69f6e413f1 Simplifying GetValues methods by using GetValue methods 2020-01-23 14:52:05 -08:00
Stowell, Mark L 08c6d61928 Adding implementation of GetValues method so that examples will compile 2020-01-23 14:29:32 -08:00
Stowell, Mark L f3888a5a73 make style 2020-01-23 13:50:10 -08:00
Stowell, Mark L e801b87fda Fixing getVectorValues usage 2020-01-23 11:55:56 -08:00
Stowell, Mark L 79457f1c71 Merge remote-tracking branch 'origin/master' into gf-getvalue-dev 2020-01-23 11:44:01 -08:00
Stowell, Mark L be1f96fd0c Set/reset coefficient after object construction 2020-01-13 10:06:55 -08:00
Stowell, Mark L 0486231ce9 Merge remote-tracking branch 'origin/master' into lp-error-est-dev 2020-01-08 14:04:16 -08:00
camierjs cec012321b VSX tconfig logic 2020-01-07 17:12:19 -08:00
camierjs af10111e35 Remove unsupported mtune option 2020-01-07 16:37:13 -08:00
camierjs 25961fd099 Use vsx header 2020-01-07 16:36:06 -08:00
camierjs cafe87ba34 xlc makefile 2020-01-07 16:34:44 -08:00
camierjs 4b894a089a Add vsx header file and logic for Lassen 2020-01-07 16:15:13 -08:00
camierjs 40e68f7f21 tconfig MFEM_USE_SIMD definitions fix 2020-01-07 15:49:01 -08:00
camierjs b625f628d4 ABI of passing aggregates with 32-byte alignment warning fix 2020-01-07 15:36:09 -08:00
camierjs 696950f296 Move MFEM_POSIX_MEMALIGN to tconfig.hpp 2020-01-07 15:12:58 -08:00
camierjs 6147b72ec1 Cleanup and Style 2020-01-07 12:04:28 -08:00
camierjs 2a3dc3c0b1 Global default SIMD and BLOCK sizes 2020-01-07 11:20:40 -08:00
camierjs 532e5371bd Default MFEM_SIMD_SIZE and MFEM_TEMPLATE_BLOCK_SIZE for _WIN32 2020-01-07 11:14:39 -08:00
camierjs 592757bfa3 AutoImplTraits simd & valign size set to 1 2020-01-07 10:46:10 -08:00
camierjs b10e9a9b4a Revert MSVC inline option 2020-01-06 19:39:12 -08:00
camierjs 76f36cb1ee appveyor config Release 2020-01-06 18:14:31 -08:00
camierjs 02febb1445 Incompatible '/O2' and '/RTC1' command-line options 2020-01-06 18:06:59 -08:00
camierjs 941f5b85ba Try CMAKE_CXX_COMPILER_ID MATCHES "MSVC" 2020-01-06 17:43:14 -08:00
camierjs 9be3aad19d Debug CMAKE_CXX_COMPILER_ID and PERFORMANCE_CXX_OPTIONS 2020-01-06 16:37:41 -08:00
camierjs 3c7f9d7f87 CMAKE_CXX_COMPILER_ID for MSVC: O2 & Ob2 2020-01-06 14:37:06 -08:00
camierjs b1a3126b68 Merge branch 'master' into x86 2020-01-06 11:03:39 -08:00
Stowell, Mark L f683d75c8b Updating ex18 to use the new FaceElementTransformation object 2019-12-16 22:09:27 -08:00
Stowell, Mark L e3e768ec53 Updating test program to also test scalar fields using INTEGRAL map type 2019-12-16 21:54:41 -08:00
Stowell, Mark L c7f00662e8 Modifying integrator classes to use FaceElementTransformations rather than its Face data member when appropriate 2019-12-16 21:53:59 -08:00
Stowell, Mark L 254feae591 Modifying mesh classes to produce new FaceElementTransformations object 2019-12-16 21:53:05 -08:00
Stowell, Mark L c0a4a3b0d5 Adding more general GetValue and GetVectorValue methods to GridFunction 2019-12-16 21:52:17 -08:00
Stowell, Mark L e14011fcbb Removing FaceElementTransformation specializations from coefficient classes 2019-12-16 21:50:59 -08:00
Stowell, Mark L 11cde1acdd Promoting FaceElementTransformation to a subclass of IsoparametricTransformation 2019-12-16 21:50:15 -08:00
Stowell, Mark L 41764a6c64 Adding draft of test program for new GridFunctionCoefficient::Eval methods 2019-12-15 23:38:00 -08:00
Stowell, Mark L 35f82a4c9d Adding GridFunctionCoefficient::Eval method using FaceElementTransformations object 2019-12-15 23:37:05 -08:00
Stowell, Mark L d8ed4d4cd2 Adding GridFunction::GetValue methods that take transformation objects rather than simple indices 2019-12-15 23:35:58 -08:00
Stowell, Mark L 37408efcae Adding convenience methods to FaceElementTransformations class 2019-12-15 23:34:49 -08:00
Stowell, Mark L 52a7ea01da Adding and populating an ElementType data member in ElementTransformation class 2019-12-15 23:33:52 -08:00
camierjs c9c75d8529 Merge branch 'master' into x86 2019-12-12 11:45:31 -08:00
Stowell, Mark L cf0023edbc Merge remote-tracking branch 'origin/master' into lp-error-est-dev 2019-12-11 11:21:45 -08:00
Stowell, Mark L 1621f5516f Moving HYPRE memory allocation macros to a common location 2019-11-26 13:47:22 -08:00
camierjs 6895d39bf7 Merge branch 'master' into x86 2019-10-25 10:37:20 -07:00
camierjs 244a59d7ad _WIN32 posix_memalign _aligned_malloc macro 2019-09-24 09:21:40 -07:00
camierjs 1642001d2d Win32 posix_memalign logic 2019-09-23 18:51:56 -07:00
camierjs 94a91e2f5e Typo fix 2019-09-23 14:56:00 -07:00
camierjs d48c1c8cf4 Merge branch 'master' into x86 2019-09-23 10:24:18 -07:00
camierjs 31cc6f47f2 WIN32: posix_memalign => _aligned_malloc 2019-09-23 10:07:38 -07:00
camierjs 2def41540d X86 => SIMD 2019-08-28 10:47:17 -07:00
camierjs b4f1ef6ca9 Merge branch 'master' into x86 2019-08-28 10:17:32 -07:00
Stowell, Mark L 7e61ddc5f8 Increasing integration order in element-wise Lp error computations 2019-08-22 14:46:58 -07:00
Stowell, Mark L eb7ae55c7c Increasing order of test field 2019-08-22 14:43:11 -07:00
Stowell, Mark L 484609f57a Merge remote-tracking branch 'origin/master' into lp-error-est-dev 2019-08-22 10:47:55 -07:00
Tzanio 9fc570b1cc Merge branch 'master' into builddoftoarrays-dev 2019-05-25 22:23:58 -07:00
Robert W. Anderson bb468f8e8a remove comment about calling preqreq function - moved into body of fns 2019-05-21 12:49:44 -07:00
Robert W. Anderson ba5904e66a automatically build dof_to arrays in functions where they are needed 2019-05-21 12:38:26 -07:00
Stowell, Mark L 7979d55651 Merge remote-tracking branch 'origin/master' into lp-error-est-dev 2019-05-01 09:59:52 -07:00
Stowell, Mark L 6410f4e814 make style 2019-04-22 13:55:26 -07:00
Stowell, Mark L 8b9efac481 Adding error estimator based on comparison to a Coefficent 2019-04-22 13:55:13 -07:00
Stowell, Mark L 0a9acf4ac4 Increasing integration order in ComputeLpError methods so they work with DG spaces 2019-04-22 13:40:30 -07:00
Stowell, Mark L 7cbc593816 Adding size check on result vector 2019-04-22 13:39:34 -07:00
Stowell, Mark L 2b7569c900 Generalizing ComputeElementError methods to accept Vectors 2019-04-22 13:36:40 -07:00
camierjs 19003df962 Merge branch 'master' into x86 2019-04-12 11:36:47 -07:00
camierjs d53c004e19 Merge branch 'master' into x86 2019-02-27 18:15:28 -08:00
camierjs 965e5c85a0 Trying runtime compilation on miniapps/performance/ex1.cpp 2018-11-02 11:13:34 -07:00
camierjs a9935c77db ex1rtc defines tweaks 2018-08-15 18:02:46 -07:00
camierjs 091cedfbcb okrtc + ex1 2018-08-15 16:39:09 -07:00
camierjs 4fc053f0a9 qpx64 size fix 2018-08-14 18:14:47 -07:00
camierjs 02e9929fae qpx, qpx64 & ex1 SIMD vs scalar test 2018-08-14 17:34:30 -07:00
camierjs 127a60e8b9 Merge branch 'master' into x86 2018-08-14 15:35:42 -07:00
camierjs c0ba409a06 [qpx] changed / to vec_swdiv and remove #warnings 2018-06-27 13:54:04 -07:00
camierjs 0042234bb1 [BG/Q] QPX vectorization 2018-06-25 18:40:48 -07:00
camierjs ec9a490cd2 [vsx] (2x) double vector for __VSX__ Power8 architecture 2018-06-25 14:52:13 -07:00
camierjs d565111732 [x86] makefile cleanup 2018-06-25 11:07:21 -07:00
camierjs 798168325b [x86] perf vs master 2018-06-22 20:47:14 -07:00
camierjs 65778b5757 [x86] add inline MFEM_ALWAYS_INLINE in each simd header files 2018-06-22 14:43:10 -07:00
camierjs 5d7177f044 [x86] miss miniapps/performance/ex1.cpp 2018-06-21 17:27:34 -07:00
camierjs 0f9a7feefb [x86] - MFEM_USE_X86INTRIN makefile if for GCC's param max-completely-peel-times option
- Brought bp1p from github.com/CEED/benchmarks/blob/master/tests/mfem_bps to test the kernels
2018-06-21 17:11:05 -07:00
camierjs 299e555cf7 [x86] INSTALL and force inline for the auto class 2018-06-19 15:16:24 -07:00
camierjs bccbe14a1e [x86] cleanup 2018-06-18 18:55:37 -07:00
camierjs 8af1fe9d20 [simd] ex1 w/ & w/o x86 2018-06-18 12:07:42 -07:00
camierjs eff37321d9 [simd] auto working with posix_memalign 2018-06-15 19:26:33 -07:00
camierjs 89db8f121a [batch] applied 2018-06-15 18:21:31 -07:00
camierjs e192295133 [x86] before SIMD/BATCH patch 2018-06-15 17:46:38 -07:00
camierjs 4a234bc418 [x86] merge addon to get tensor alignment, not yet matrix-free 2018-06-15 15:16:57 -07:00
camierjs 8bb71658ee Merge branch 'master' into x86 2018-06-15 11:57:07 -07:00
camierjs af53d47cb7 Cleanup & MFEM_USE_X86INTRIN ifdefs 2017-09-28 17:36:24 -07:00
camierjs bf8ac9629b GCC, ICC & Clang alignment sanitization for TBilinearForm root class 2017-09-28 11:21:43 -07:00
camierjs 6709f15f7f Merge branch 'master' of https://github.com/mfem/mfem into okina 2017-09-28 11:18:42 -07:00
camierjs fffcf07169 Merge branch 'master' of https://github.com/mfem/mfem into okina 2017-09-22 10:18:00 -07:00
camierjs 8c1041979f x86 scalar/sse/avx/avx2/avx512 header files 2017-09-21 17:47:22 -07:00
camierjs 1fed67455a x86 intrinsic for the high-performance templated operator 2017-09-19 15:39:46 -07:00
147 changed files with 15180 additions and 2768 deletions
+3 -6
View File
@@ -11,8 +11,6 @@
language: cpp
sudo: false
stages:
- checks
- tests
@@ -370,8 +368,10 @@ script:
# Compiler
- if [ $MPI == "YES" ]; then
export MYCXX=mpic++;
export MAKE_CXX_FLAG=MPICXX=$MYCXX;
else
export MYCXX="$CXX";
export MAKE_CXX_FLAG=CXX=$MYCXX;
fi
# Print the compiler version
@@ -384,12 +384,9 @@ script:
if [ "$CODECOV" == "YES" ]; then
CPPFLAGS="--coverage -g";
fi;
if [ "$CXX" == "clang++" ]; then
export MFEM_PERF_SW=clang;
fi
# Configure the library
- make config MFEM_USE_MPI=$MPI MFEM_DEBUG=$DEBUG MFEM_CXX="$MYCXX"
- make config MFEM_USE_MPI=$MPI MFEM_DEBUG=$DEBUG $MAKE_CXX_FLAG
MFEM_MPI_NP=$NPROCS CPPFLAGS="$CPPFLAGS"
# Show the configuration
- make info
+55 -5
View File
@@ -23,8 +23,21 @@ Meshing improvements
Hessian for r-adaptivity using discrete fields, and allows use of skewness
and orientation based metrics.
Improved GPU capabilities
-------------------------
- Added support for r-adaptivity with more than one discrete field. This allows
the user to specify different discrete functions for controlling the
size, aspect-ratio, orientation, and skew of elements in the mesh.
Performance improvements
------------------------
- Added support for explicit vectorization in the high-performance templated
code, which can now take advantage of specific intrinsics classes on the
following architectures:
- x86 (SSE/AVX/AVX2/AVX512),
- Power8 & Power9 (VSX),
- BG/Q (QPX).
These are now enabled by default, and can be disabled with MFEM_USE_SIMD=NO.
See the new file linalg/simd.hpp and the new directory linalg/simd.
- Added support for Chebyshev accelerated polynomial smoother on GPU.
Discretization improvements
@@ -35,6 +48,24 @@ Discretization improvements
- Added support for simplices in GSLIB-FindPoints.
- Added support for H1 and L2 element matrix assembly in the mass, convection,
diffusion, transpose, and the face DG trace integrators. This is compatible
with GPU device execution and is illustrated in Example 9/9p, see the option
'-ea'. When enabled, this level of assembly stores independent dense matrices
for the elements, and independent dense matrices for the faces in the DG case.
- Added new partial assembly kernels for H(div) bilinear forms, as well as
VectorFEDivergenceIntegrator.
- Improved the documentation of the GridFunction GetValue and GetVectorValue
methods. Expanded the GetValue and GetVectorValue methods which accept an
ElementTransformation argument to support evaluation on boundary elements
and, in the continuous field case, arbitrary mesh edges and faces.
- Added new coefficient and vector coefficient classes for QuadratureFunctions.
Additionaly, new LinearForm integrators were also added which make use of
these new QuadratureFunction coefficient classes.
Linear and nonlinear solvers
----------------------------
- Added power method to iteratively estimate the largest eigenvalue and the
@@ -43,6 +74,17 @@ Linear and nonlinear solvers
- Added initial support for h- and p-multigrid solvers and preconditioners for
matrix-based and matrix-free discretizations with basic GPU capability.
- Added a new IterativeSolverMonitor class that allows to monitor the residual
and solution during the solving process of an IterativeSolver after every
iteration.
- Block arrays of parallel matrices can now be merged into a single parallel
matrix with the function HypreParMatrixFromBlocks. This could be useful for
solving block systems with parallel direct solvers such as STRUMPACK.
- In SLISolver, changed the residual inner product from (Br,r) to (Br,Br) so the
solver can work with non-SPD preconditioner B.
New and updated examples and miniapps
-------------------------------------
- Added a new example, Example 25/25p, to demonstrate the use of a Perfectly
@@ -65,6 +107,12 @@ New and updated examples and miniapps
- Added a new meshing miniapp, Minimal Surface, which solves Plateau's problem:
the Dirichlet problem for the minimal surface equation.
- Added partial assembly support to examples 4/4p and 5/5p, with diagonal
preconditioning.
- Added a new test problem in example 24/24p, demonstrating a mixed bilinear
form for H(div) and L_2, with partial assembly support.
Improved testing
----------------
- Added a GitLab pipeline that automates PR testing on supercomputing systems
@@ -74,15 +122,17 @@ Improved testing
Miscellaneous
-------------
- In SLISolver, changed the residual inner product from (Br,r) to (Br,Br) so the
solver can work with non-SPD preconditioner B.
- Added support for ADIOS2 for parallel I/O with ParaView visualization. The
classes adios2stream and ADIOS2DataCollection are introduced in mfem as the
interfaces to generate ADIOS2 Binary Pack (BP4) directory datasets for the
entire spatial and temporal data. In addition, ADIOS2 allows for setting a
user-defined number of data substreams/subfiles. See examples 5, 9, 12, 16.
- The integration order used in the ComputeLpError and ComputeElementLpError
methods of class GridFunction has been increased.
- Various other simplifications, extensions, and bugfixes in the code.
Version 4.1, released on March 10, 2020
=======================================
+10 -1
View File
@@ -396,6 +396,12 @@ MFEM_USE_SIDRE = YES/NO
blueprint specification. When enabled, this option requires installation of
HDF5 (see also MFEM_USE_NETCDF), Conduit and LLNL's axom project.
MFEM_USE_SIMD = YES/NO
Enables the high performance templated classes to use architecture dependent
SIMD intrinsics instead of the generic implementation of class AutoSIMD in
linalg/simd/auto.hpp. This option should be combined with suitable
compiler options, such as -march=native, to enable optimal vectorization.
MFEM_USE_CONDUIT = YES/NO
Enables support for converting MFEM Mesh and Grid Function objects to and
from Conduit Mesh Blueprint Descriptions (https://github.com/LLNL/conduit/)
@@ -426,6 +432,8 @@ MFEM_USE_PUMI = YES/NO
data management system that is capable of handling general non-manifold
models and effectively supports automated adaptive analysis. PUMI enables
support for parallel unstructured mesh modifications in MFEM.
The develop branch of PUMI repository (https://github.com/SCOREC/core)
should be used for most updated features.
MFEM_USE_UMPIRE = YES/NO
Enables support for Umpire, a resource management library that allows the
@@ -609,8 +617,9 @@ The specific libraries and their options are:
- PUMI (optional), used when MFEM_USE_PUMI = YES.
URL: https://scorec.rpi.edu/pumi
https://github.com/SCOREC/core
Options: PUMI_OPT, PUMI_LIB.
Versions: PUMI >= 2.2.0.
Versions: PUMI >= 2.2.3.
- HiOp (optional), used when MFEM_USE_HIOP = YES.
URL: https://github.com/LLNL/hiop
+1
View File
@@ -47,6 +47,7 @@ set(MFEM_USE_OCCA @MFEM_USE_OCCA@)
set(MFEM_USE_RAJA @MFEM_USE_RAJA@)
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_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
+3
View File
@@ -107,6 +107,9 @@
// Enable MFEM functionality based on the Sidre library
#cmakedefine MFEM_USE_SIDRE
// Enable the use of SIMD in the high performance templated classes
#cmakedefine MFEM_USE_SIMD
// Enable MFEM functionality based on Conduit
#cmakedefine MFEM_USE_CONDUIT
@@ -733,7 +733,7 @@ function(mfem_export_mk_files)
MFEM_USE_SUPERLU MFEM_USE_STRUMPACK MFEM_USE_GNUTLS
MFEM_USE_GSLIB MFEM_USE_NETCDF MFEM_USE_PETSC MFEM_USE_MPFR MFEM_USE_SIDRE
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_CUDA MFEM_USE_OCCA MFEM_USE_RAJA
MFEM_USE_UMPIRE)
MFEM_USE_UMPIRE MFEM_USE_SIMD MFEM_USE_ADIOS2)
foreach(var ${CONFIG_MK_BOOL_VARS})
if (${var})
set(${var} YES)
@@ -743,6 +743,7 @@ function(mfem_export_mk_files)
endforeach()
# TODO: Add support for MFEM_USE_CUDA=YES
set(MFEM_CXX ${CMAKE_CXX_COMPILER})
set(MFEM_HOST_CXX ${MFEM_CXX})
set(MFEM_CPPFLAGS "")
string(STRIP "${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}"
MFEM_CXXFLAGS)
+3
View File
@@ -106,6 +106,9 @@
// Enable Sidre support
// #define MFEM_USE_SIDRE
// Enable the use of SIMD in the high performance templated classes
// #define MFEM_USE_SIMD
// Enable Conduit support
// #define MFEM_USE_CONDUIT
+2
View File
@@ -49,10 +49,12 @@ MFEM_USE_RAJA = @MFEM_USE_RAJA@
MFEM_USE_OCCA = @MFEM_USE_OCCA@
MFEM_USE_CEED = @MFEM_USE_CEED@
MFEM_USE_UMPIRE = @MFEM_USE_UMPIRE@
MFEM_USE_SIMD = @MFEM_USE_SIMD@
MFEM_USE_ADIOS2 = @MFEM_USE_ADIOS2@
# Compiler, compile options, and link options
MFEM_CXX = @MFEM_CXX@
MFEM_HOST_CXX = @MFEM_HOST_CXX@
MFEM_CPPFLAGS = @MFEM_CPPFLAGS@
MFEM_CXXFLAGS = @MFEM_CXXFLAGS@
MFEM_TPLFLAGS = @MFEM_TPLFLAGS@
+1
View File
@@ -49,6 +49,7 @@ option(MFEM_USE_OCCA "Enable OCCA" OFF)
option(MFEM_USE_RAJA "Enable RAJA" OFF)
option(MFEM_USE_CEED "Enable CEED" OFF)
option(MFEM_USE_UMPIRE "Enable Umpire" OFF)
option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" ON)
option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
+1
View File
@@ -137,6 +137,7 @@ MFEM_USE_RAJA = NO
MFEM_USE_OCCA = NO
MFEM_USE_CEED = NO
MFEM_USE_UMPIRE = NO
MFEM_USE_SIMD = YES
MFEM_USE_ADIOS2 = NO
# Compile and link options for zlib.
+13 -6
View File
@@ -29,8 +29,20 @@
#define MFEM_ALWAYS_INLINE
#endif
// --- MFEM_VECTORIZE_LOOP (disabled)
#if (__cplusplus >= 201103L) && !defined(MFEM_DEBUG) && defined(__GNUC__)
//#define MFEM_VECTORIZE_LOOP _Pragma("GCC ivdep")
#define MFEM_VECTORIZE_LOOP
#else
#define MFEM_VECTORIZE_LOOP
#endif
// MFEM_TEMPLATE_BLOCK_SIZE is the block size used by the template matrix-matrix
// multiply, Mult_AB, defined in tmatrix.hpp. This parameter will generally
// require tuning to determine good value. It is probably highly influenced by
// the SIMD width when Mult_AB is used with a SIMD type like AutoSIMD.
#define MFEM_TEMPLATE_BLOCK_SIZE 4
#define MFEM_SIMD_SIZE 32
#define MFEM_TEMPLATE_ENABLE_SERIALIZE
// #define MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
@@ -38,11 +50,6 @@
// #define MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS
#define MFEM_TEMPLATE_INTRULE_COEFF_PRECOMP
// derived macros
#define MFEM_ROUNDUP(val,base) ((((val)+(base)-1)/(base))*(base))
#define MFEM_ALIGN_SIZE(size,type) \
MFEM_ROUNDUP(size,(MFEM_SIMD_SIZE)/sizeof(type))
#ifdef MFEM_COUNT_FLOPS
namespace mfem
{
+34
View File
@@ -35,6 +35,38 @@
using namespace std;
using namespace mfem;
class CustomSolverMonitor : public IterativeSolverMonitor
{
public:
CustomSolverMonitor(const ParMesh *m,
ParGridFunction *f) :
pmesh(m),
pgf(f) {}
void MonitorSolution(int i, double norm, const Vector &x, bool final)
{
char vishost[] = "localhost";
int visport = 19916;
int num_procs, myid;
MPI_Comm_size(pmesh->GetComm(),&num_procs);
MPI_Comm_rank(pmesh->GetComm(),&myid);
pgf->SetFromTrueDofs(x);
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << *pgf
<< "window_title 'Iteration no " << i << "'"
<< "keys rRjlc\n" << flush;
}
private:
const ParMesh *pmesh;
ParGridFunction *pgf;
};
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
@@ -188,6 +220,7 @@ int main(int argc, char *argv[])
}
else
{
CustomSolverMonitor monitor(pmesh, &x);
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetAbsTol(0.0);
gmres.SetRelTol(1e-12);
@@ -196,6 +229,7 @@ int main(int argc, char *argv[])
gmres.SetPrintLevel(1);
gmres.SetOperator(*A);
gmres.SetPreconditioner(*amg);
gmres.SetMonitor(monitor);
gmres.Mult(*B, *X);
}
delete amg;
+3 -3
View File
@@ -418,7 +418,7 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
{
intorder++;
}
const IntegrationRule *ir = &IntRules.Get(Tr.FaceGeom, intorder);
const IntegrationRule *ir = &IntRules.Get(Tr.GetGeometryType(), intorder);
for (int i = 0; i < ir->GetNPoints(); i++)
{
@@ -435,10 +435,10 @@ void FaceIntegrator::AssembleFaceVector(const FiniteElement &el1,
elfun1_mat.MultTranspose(shape1, funval1);
elfun2_mat.MultTranspose(shape2, funval2);
Tr.Face->SetIntPoint(&ip);
Tr.SetIntPoint(&ip);
// Get the normal vector and the flux on the face
CalcOrtho(Tr.Face->Jacobian(), nor);
CalcOrtho(Tr.Jacobian(), nor);
const double mcs = rsolver.Eval(funval1, funval2, nor, fluxN);
// Update max char speed
+44 -3
View File
@@ -38,6 +38,42 @@
using namespace std;
using namespace mfem;
class GeneralResidualMonitor : public IterativeSolverMonitor
{
public:
GeneralResidualMonitor(const std::string& prefix_, int print_lvl)
: prefix(prefix_)
{
print_level = print_lvl;
}
virtual void MonitorResidual(int it, double norm, const Vector &r, bool final);
private:
const std::string prefix;
int print_level;
mutable double norm0;
};
void GeneralResidualMonitor::MonitorResidual(int it, double norm,
const Vector &r, bool final)
{
if (print_level == 1 || (print_level == 3 && (final || it == 0)))
{
mfem::out << prefix << " iteration " << setw(2) << it
<< " : ||r|| = " << norm;
if (it > 0)
{
mfem::out << ", ||r||/||r_0|| = " << norm/norm0;
}
else
{
norm0 = norm;
}
mfem::out << '\n';
}
}
// Custom block preconditioner for the Jacobian of the incompressible nonlinear
// elasticity operator. It has the form
//
@@ -103,9 +139,11 @@ protected:
// Newton solver for the hyperelastic operator
NewtonSolver newton_solver;
GeneralResidualMonitor newton_monitor;
// Solver for the Jacobian solve in the Newton method
Solver *j_solver;
GeneralResidualMonitor j_monitor;
// Preconditioner for the Jacobian
Solver *j_prec;
@@ -410,7 +448,8 @@ RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
int iter,
Coefficient &c_mu)
: Operator(fes[0]->GetVSize() + fes[1]->GetVSize()),
newton_solver(), mu(c_mu), block_offsets(offsets)
newton_solver(), newton_monitor("Newton", 1),
j_monitor(" GMRES", 3), mu(c_mu), block_offsets(offsets)
{
Array<Vector *> rhs(2);
rhs = NULL; // Set all entries in the array
@@ -446,7 +485,8 @@ RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
j_gmres->SetRelTol(1e-12);
j_gmres->SetAbsTol(1e-12);
j_gmres->SetMaxIter(300);
j_gmres->SetPrintLevel(0);
j_gmres->SetPrintLevel(-1);
j_gmres->SetMonitor(j_monitor);
j_gmres->SetPreconditioner(*j_prec);
j_solver = j_gmres;
@@ -454,7 +494,8 @@ RubberOperator::RubberOperator(Array<FiniteElementSpace *> &fes,
newton_solver.iterative_mode = true;
newton_solver.SetSolver(*j_solver);
newton_solver.SetOperator(*this);
newton_solver.SetPrintLevel(1);
newton_solver.SetPrintLevel(-1);
newton_solver.SetMonitor(newton_monitor);
newton_solver.SetRelTol(rel_tol);
newton_solver.SetAbsTol(abs_tol);
newton_solver.SetMaxIter(iter);
+60 -3
View File
@@ -38,6 +38,56 @@
using namespace std;
using namespace mfem;
class GeneralResidualMonitor : public IterativeSolverMonitor
{
public:
GeneralResidualMonitor(MPI_Comm comm, const std::string& prefix_,
int print_lvl)
: prefix(prefix_)
{
#ifndef MFEM_USE_MPI
print_level = print_lvl;
#else
int rank;
MPI_Comm_rank(comm, &rank);
if (rank == 0)
{
print_level = print_lvl;
}
else
{
print_level = -1;
}
#endif
}
virtual void MonitorResidual(int it, double norm, const Vector &r, bool final);
private:
const std::string prefix;
int print_level;
mutable double norm0;
};
void GeneralResidualMonitor::MonitorResidual(int it, double norm,
const Vector &r, bool final)
{
if (print_level == 1 || (print_level == 3 && (final || it == 0)))
{
mfem::out << prefix << " iteration " << setw(2) << it
<< " : ||r|| = " << norm;
if (it > 0)
{
mfem::out << ", ||r||/||r_0|| = " << norm/norm0;
}
else
{
norm0 = norm;
}
mfem::out << '\n';
}
}
// Custom block preconditioner for the Jacobian of the incompressible nonlinear
// elasticity operator. It has the form
//
@@ -103,9 +153,11 @@ protected:
// Newton solver for the hyperelastic operator
NewtonSolver newton_solver;
GeneralResidualMonitor newton_monitor;
// Solver for the Jacobian solve in the Newton method
Solver *j_solver;
GeneralResidualMonitor j_monitor;
// Preconditioner for the Jacobian
Solver *j_prec;
@@ -459,7 +511,10 @@ RubberOperator::RubberOperator(Array<ParFiniteElementSpace *> &fes,
int iter,
Coefficient &c_mu)
: Operator(fes[0]->TrueVSize() + fes[1]->TrueVSize()),
newton_solver(fes[0]->GetComm()), mu(c_mu), block_trueOffsets(trueOffsets)
newton_solver(fes[0]->GetComm()),
newton_monitor(fes[0]->GetComm(), "Newton", 1),
j_monitor(fes[0]->GetComm(), " GMRES", 3),
mu(c_mu), block_trueOffsets(trueOffsets)
{
Array<Vector *> rhs(2);
rhs = NULL; // Set all entries in the array
@@ -499,7 +554,8 @@ RubberOperator::RubberOperator(Array<ParFiniteElementSpace *> &fes,
j_gmres->SetRelTol(1e-12);
j_gmres->SetAbsTol(1e-12);
j_gmres->SetMaxIter(300);
j_gmres->SetPrintLevel(0);
j_gmres->SetPrintLevel(-1);
j_gmres->SetMonitor(j_monitor);
j_gmres->SetPreconditioner(*j_prec);
j_solver = j_gmres;
@@ -507,7 +563,8 @@ RubberOperator::RubberOperator(Array<ParFiniteElementSpace *> &fes,
newton_solver.iterative_mode = true;
newton_solver.SetSolver(*j_solver);
newton_solver.SetOperator(*this);
newton_solver.SetPrintLevel(1);
newton_solver.SetPrintLevel(-1);
newton_solver.SetMonitor(newton_monitor);
newton_solver.SetRelTol(rel_tol);
newton_solver.SetAbsTol(abs_tol);
newton_solver.SetMaxIter(iter);
+177 -90
View File
@@ -6,6 +6,7 @@
// ex24 -m ../data/square-disc.mesh -o 2
// ex24 -m ../data/beam-tet.mesh
// ex24 -m ../data/beam-hex.mesh -o 2 -pa
// ex24 -m ../data/beam-hex.mesh -o 2 -pa -p 1
// ex24 -m ../data/escher.mesh
// ex24 -m ../data/escher.mesh -o 2
// ex24 -m ../data/fichera.mesh
@@ -23,11 +24,15 @@
// ex24 -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code illustrates usage of mixed finite element
// spaces. Using two different approaches, we project a gradient
// of a function in H^1 to H(curl). Other spaces and example
// computations are to be added in the future.
// spaces, with two variants:
//
// We recommend viewing examples 1 and 3 before viewing this
// 1) (grad p, u) for p in H^1 tested against u in H(curl)
// 2) (div v, q) for v in H(div) tested against q in L_2
//
// Using different approaches, we project the gradient or
// divergence to the appropriate space.
//
// We recommend viewing examples 1, 3, and 5 before viewing this
// example.
#include "mfem.hpp"
@@ -39,6 +44,7 @@ using namespace mfem;
double p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
double div_gradp_exact(const Vector &x);
int dim;
@@ -47,6 +53,7 @@ int main(int argc, char *argv[])
// 1. Parse command-line options.
const char *mesh_file = "../data/beam-hex.mesh";
int order = 1;
int prob = 0;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
@@ -57,6 +64,8 @@ int main(int argc, char *argv[])
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: H(Curl) or 1: H(Div)");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
@@ -100,72 +109,107 @@ int main(int argc, char *argv[])
}
mesh->ReorientTetMesh();
// 5. 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);
FiniteElementCollection *H1fec = new H1_FECollection(order, dim);
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
FiniteElementSpace *H1fespace = new FiniteElementSpace(mesh, H1fec);
// 5. Define a finite element space on the mesh. Here we use Nedelec or
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *trial_fec = NULL;
FiniteElementCollection *test_fec = NULL;
int size = fespace->GetTrueVSize();
int H1size = H1fespace->GetTrueVSize();
cout << "Number of Nedelec finite element unknowns: " << size << endl;
cout << "Number of H1 finite element unknowns: " << H1size << endl;
// 6. 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.
GridFunction x(fespace);
FunctionCoefficient p_coef(p_exact);
GridFunction p(H1fespace);
p.ProjectCoefficient(p_coef);
p.SetTrueVector();
p.SetFromTrueVector();
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
// 7. Set up the bilinear forms.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
BilinearForm *a = new BilinearForm(fespace);
MixedBilinearForm *a_NDH1 = new MixedBilinearForm(H1fespace, fespace);
if (pa)
if (prob == 0)
{
a->SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_NDH1->SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
// First approach: L2 projection
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
a_NDH1->AddDomainIntegrator(new MixedVectorGradientIntegrator(*muinv));
// 8. 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();
if (!pa) { a->Finalize(); }
a_NDH1->Assemble();
if (!pa) { a_NDH1->Finalize(); }
if (pa)
{
a_NDH1->Mult(p, x);
trial_fec = new H1_FECollection(order, dim);
test_fec = new ND_FECollection(order, dim);
}
else
{
SparseMatrix& NDH1 = a_NDH1->SpMat();
NDH1.Mult(p, x);
trial_fec = new RT_FECollection(order - 1, dim);
test_fec = new L2_FECollection(order - 1, dim);
}
FiniteElementSpace trial_fes(mesh, trial_fec);
FiniteElementSpace test_fes(mesh, test_fec);
int trial_size = trial_fes.GetTrueVSize();
int test_size = test_fes.GetTrueVSize();
if (prob == 0)
{
cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
cout << "Number of H1 finite element unknowns: " << trial_size << endl;
}
else
{
cout << "Number of Raviart-Thomas finite element unknowns: "
<< trial_size << endl;
cout << "Number of L2 finite element unknowns: " << test_size << endl;
}
// 6. Define the solution vector as a finite element grid function
// corresponding to the trial fespace.
GridFunction gftest(&test_fes);
GridFunction gftrial(&trial_fes);
GridFunction x(&test_fes);
FunctionCoefficient p_coef(p_exact);
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
FunctionCoefficient divgradp_coef(div_gradp_exact);
if (prob == 0)
{
gftrial.ProjectCoefficient(p_coef);
}
else
{
gftrial.ProjectCoefficient(gradp_coef);
}
gftrial.SetTrueVector();
gftrial.SetFromTrueVector();
// 7. Set up the bilinear forms for L2 projection.
ConstantCoefficient one(1.0);
BilinearForm a(&test_fes);
MixedBilinearForm a_mixed(&trial_fes, &test_fes);
if (pa)
{
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_mixed.SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
if (prob == 0)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorGradientIntegrator(one));
}
else
{
a.AddDomainIntegrator(new MassIntegrator(one));
a_mixed.AddDomainIntegrator(new VectorFEDivergenceIntegrator(one));
}
// 8. 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();
if (!pa) { a.Finalize(); }
a_mixed.Assemble();
if (!pa) { a_mixed.Finalize(); }
if (pa)
{
a_mixed.Mult(gftrial, x);
}
else
{
SparseMatrix& mixed = a_mixed.SpMat();
mixed.Mult(gftrial, x);
}
// 9. Define and apply a PCG solver for Ax = b with Jacobi preconditioner.
{
GridFunction rhs(fespace);
GridFunction rhs(&test_fes);
rhs = x;
x = 0.0;
@@ -176,15 +220,15 @@ int main(int argc, char *argv[])
if (pa)
{
Array<int> ess_tdof_list; // empty
OperatorJacobiSmoother Jacobi(*a, ess_tdof_list);
OperatorJacobiSmoother Jacobi(a, ess_tdof_list);
cg.SetOperator(*a);
cg.SetOperator(a);
cg.SetPreconditioner(Jacobi);
cg.Mult(rhs, x);
}
else
{
SparseMatrix& Amat = a->SpMat();
SparseMatrix& Amat = a.SpMat();
DSmoother Jacobi(Amat);
cg.SetOperator(Amat);
@@ -193,33 +237,68 @@ int main(int argc, char *argv[])
}
}
// 10. Second approach: compute the same solution by applying
// GradientInterpolator in H(curl).
DiscreteLinearOperator grad(H1fespace, fespace);
grad.AddDomainInterpolator(new GradientInterpolator());
grad.Assemble();
// 10. Compute the same field by applying a DiscreteInterpolator.
GridFunction discreteInterpolant(&test_fes);
DiscreteLinearOperator dlo(&trial_fes, &test_fes);
if (prob == 0)
{
dlo.AddDomainInterpolator(new GradientInterpolator());
}
else
{
dlo.AddDomainInterpolator(new DivergenceInterpolator());
}
GridFunction gradp(fespace);
grad.Mult(p, gradp);
dlo.Assemble();
dlo.Mult(gftrial, discreteInterpolant);
// 11. Compute the projection of the exact grad p.
GridFunction exact_gradp(fespace);
exact_gradp.ProjectCoefficient(gradp_coef);
exact_gradp.SetTrueVector();
exact_gradp.SetFromTrueVector();
// 11. Compute the projection of the exact field.
GridFunction exact_proj(&test_fes);
if (prob == 0)
{
exact_proj.ProjectCoefficient(gradp_coef);
}
else
{
exact_proj.ProjectCoefficient(divgradp_coef);
}
// 12. Compute and print the L^2 norm of the error.
exact_proj.SetTrueVector();
exact_proj.SetFromTrueVector();
// 12. Compute and print the L_2 norm of the error.
if (prob == 0)
{
double errSol = x.ComputeL2Error(gradp_coef);
double errInterp = gradp.ComputeL2Error(gradp_coef);
double errProj = exact_gradp.ComputeL2Error(gradp_coef);
double errInterp = discreteInterpolant.ComputeL2Error(gradp_coef);
double errProj = exact_proj.ComputeL2Error(gradp_coef);
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in H(curl): "
"|| E_h - grad p ||_{L^2} = " << errSol << '\n' << endl;
"|| E_h - grad p ||_{L_2} = " << errSol << '\n' << endl;
cout << " Gradient interpolant E_h = grad p_h in H(curl): || E_h - grad p"
"||_{L^2} = " << errInterp << '\n' << endl;
"||_{L_2} = " << errInterp << '\n' << endl;
cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
"||_{L^2} = " << errProj << '\n' << endl;
"||_{L_2} = " << errProj << '\n' << endl;
}
else
{
int order_quad = max(2, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
double errSol = x.ComputeL2Error(divgradp_coef, irs);
double errInterp = discreteInterpolant.ComputeL2Error(divgradp_coef, irs);
double errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
cout << "\n Solution of (f_h,q) = (div v_h,q) for f_h and q in L_2: "
"|| f_h - div v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Divergence interpolant f_h = div v_h in L_2: || f_h - div v"
"||_{L_2} = " << errInterp << '\n' << endl;
cout << " Projection f_h of exact div v in L_2: || f_h - div v "
"||_{L_2} = " << errProj << '\n' << endl;
}
// 13. Save the refined mesh and the solution. This output can be viewed
@@ -242,14 +321,8 @@ int main(int argc, char *argv[])
}
// 15. Free the used memory.
delete a;
delete a_NDH1;
delete sigma;
delete muinv;
delete fespace;
delete H1fespace;
delete fec;
delete H1fec;
delete trial_fec;
delete test_fec;
delete mesh;
return 0;
@@ -284,3 +357,17 @@ void gradp_exact(const Vector &x, Vector &f)
if (x.Size() == 3) { f(2) = 0.0; }
}
}
double div_gradp_exact(const Vector &x)
{
if (dim == 3)
{
return -3.0 * sin(x(0)) * sin(x(1)) * sin(x(2));
}
else if (dim == 2)
{
return -2.0 * sin(x(0)) * sin(x(1));
}
return 0.0;
}
+171 -81
View File
@@ -6,6 +6,7 @@
// mpirun -np 4 ex24p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex24p -m ../data/beam-tet.mesh
// mpirun -np 4 ex24p -m ../data/beam-hex.mesh -o 2 -pa
// mpirun -np 4 ex24p -m ../data/beam-hex.mesh -o 2 -p 1 -pa
// mpirun -np 4 ex24p -m ../data/escher.mesh
// mpirun -np 4 ex24p -m ../data/escher.mesh -o 2
// mpirun -np 4 ex24p -m ../data/fichera.mesh
@@ -23,11 +24,15 @@
// mpirun -np 4 ex24p -m ../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code illustrates usage of mixed finite element
// spaces. Using two different approaches, we project a gradient
// of a function in H^1 to H(curl). Other spaces and example
// computations are to be added in the future.
// spaces, with two variants:
//
// We recommend viewing examples 1 and 3 before viewing this
// 1) (grad p, u) for p in H^1 tested against u in H(curl)
// 2) (div v, q) for v in H(div) tested against q in L_2
//
// Using different approaches, we project the gradient or
// divergence to the appropriate space.
//
// We recommend viewing examples 1, 3, and 5 before viewing this
// example.
#include "mfem.hpp"
@@ -39,6 +44,7 @@ using namespace mfem;
double p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
double div_gradp_exact(const Vector &x);
int dim;
@@ -53,6 +59,7 @@ int main(int argc, char *argv[])
// 2. Parse command-line options.
const char *mesh_file = "../data/beam-hex.mesh";
int order = 1;
int prob = 0;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
@@ -63,6 +70,8 @@ int main(int argc, char *argv[])
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: H(Curl) or 1: H(Div)");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
@@ -129,80 +138,115 @@ int main(int argc, char *argv[])
pmesh->ReorientTetMesh();
// 7. 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);
FiniteElementCollection *H1fec = new H1_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
ParFiniteElementSpace *H1fespace = new ParFiniteElementSpace(pmesh, H1fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
HYPRE_Int H1size = H1fespace->GlobalTrueVSize();
// use Nedelec or Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *trial_fec = NULL;
FiniteElementCollection *test_fec = NULL;
if (prob == 0)
{
trial_fec = new H1_FECollection(order, dim);
test_fec = new ND_FECollection(order, dim);
}
else
{
trial_fec = new RT_FECollection(order - 1, dim);
test_fec = new L2_FECollection(order - 1, dim);
}
ParFiniteElementSpace trial_fes(pmesh, trial_fec);
ParFiniteElementSpace test_fes(pmesh, test_fec);
HYPRE_Int trial_size = trial_fes.GlobalTrueVSize();
HYPRE_Int test_size = test_fes.GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of Nedelec finite element unknowns: " << size << endl;
cout << "Number of H1 finite element unknowns: " << H1size << endl;
if (prob == 0)
{
cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
cout << "Number of H1 finite element unknowns: " << trial_size << endl;
}
else
{
cout << "Number of Raviart-Thomas finite element unknowns: "
<< trial_size << endl;
cout << "Number of L2 finite element unknowns: " << test_size << endl;
}
}
// 8. 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);
// 8. Define the solution vector as a parallel finite element grid function
// corresponding to the trial fespace.
ParGridFunction gftest(&test_fes);
ParGridFunction gftrial(&trial_fes);
ParGridFunction x(&test_fes);
FunctionCoefficient p_coef(p_exact);
ParGridFunction p(H1fespace);
p.ProjectCoefficient(p_coef);
p.SetTrueVector();
p.SetFromTrueVector();
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
FunctionCoefficient divgradp_coef(div_gradp_exact);
// 9. Set up the parallel bilinear forms.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
ParMixedBilinearForm *a_NDH1 = new ParMixedBilinearForm(H1fespace, fespace);
if (prob == 0)
{
gftrial.ProjectCoefficient(p_coef);
}
else
{
gftrial.ProjectCoefficient(gradp_coef);
}
gftrial.SetTrueVector();
gftrial.SetFromTrueVector();
// 9. Set up the parallel bilinear forms for L2 projection.
ConstantCoefficient one(1.0);
ParBilinearForm a(&test_fes);
ParMixedBilinearForm a_mixed(&trial_fes, &test_fes);
if (pa)
{
a->SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_NDH1->SetAssemblyLevel(AssemblyLevel::PARTIAL);
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_mixed.SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
// First approach: L2 projection
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
a_NDH1->AddDomainIntegrator(new MixedVectorGradientIntegrator(*muinv));
if (prob == 0)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorGradientIntegrator(one));
}
else
{
a.AddDomainIntegrator(new MassIntegrator(one));
a_mixed.AddDomainIntegrator(new VectorFEDivergenceIntegrator(one));
}
// 10. 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(); }
if (static_cond) { a.EnableStaticCondensation(); }
a->Assemble();
if (!pa) { a->Finalize(); }
a.Assemble();
if (!pa) { a.Finalize(); }
a_NDH1->Assemble();
if (!pa) { a_NDH1->Finalize(); }
a_mixed.Assemble();
if (!pa) { a_mixed.Finalize(); }
Vector B(fespace->GetTrueVSize());
Vector X(fespace->GetTrueVSize());
Vector B(test_fes.GetTrueVSize());
Vector X(test_fes.GetTrueVSize());
if (pa)
{
ParLinearForm *b = new ParLinearForm(fespace); // used as a vector
a_NDH1->Mult(p, *b); // process-local multiplication
b->ParallelAssemble(B);
delete b;
ParLinearForm b(&test_fes); // used as a vector
a_mixed.Mult(gftrial, b); // process-local multiplication
b.ParallelAssemble(B);
}
else
{
HypreParMatrix *NDH1 = a_NDH1->ParallelAssemble();
HypreParMatrix *mixed = a_mixed.ParallelAssemble();
Vector P(H1fespace->GetTrueVSize());
p.GetTrueDofs(P);
Vector P(trial_fes.GetTrueVSize());
gftrial.GetTrueDofs(P);
NDH1->Mult(P,B);
mixed->Mult(P,B);
delete NDH1;
delete mixed;
}
// 11. Define and apply a parallel PCG solver for AX=B with Jacobi
@@ -212,9 +256,9 @@ int main(int argc, char *argv[])
Array<int> ess_tdof_list; // empty
OperatorPtr A;
a->FormSystemMatrix(ess_tdof_list, A);
a.FormSystemMatrix(ess_tdof_list, A);
OperatorJacobiSmoother Jacobi(*a, ess_tdof_list);
OperatorJacobiSmoother Jacobi(a, ess_tdof_list);
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
@@ -227,7 +271,7 @@ int main(int argc, char *argv[])
}
else
{
HypreParMatrix *Amat = a->ParallelAssemble();
HypreParMatrix *Amat = a.ParallelAssemble();
HypreDiagScale Jacobi(*Amat);
HyprePCG pcg(*Amat);
pcg.SetTol(1e-12);
@@ -242,35 +286,73 @@ int main(int argc, char *argv[])
x.SetFromTrueDofs(X);
// 12. Second approach: compute the same solution by applying
// GradientInterpolator in H(curl).
ParDiscreteLinearOperator grad(H1fespace, fespace);
grad.AddDomainInterpolator(new GradientInterpolator());
grad.Assemble();
// 12. Compute the same field by applying a DiscreteInterpolator.
ParGridFunction discreteInterpolant(&test_fes);
ParDiscreteLinearOperator dlo(&trial_fes, &test_fes);
if (prob == 0)
{
dlo.AddDomainInterpolator(new GradientInterpolator());
}
else
{
dlo.AddDomainInterpolator(new DivergenceInterpolator());
}
ParGridFunction gradp(fespace);
grad.Mult(p, gradp);
dlo.Assemble();
dlo.Mult(gftrial, discreteInterpolant);
// 13. Compute the projection of the exact grad p.
ParGridFunction exact_gradp(fespace);
exact_gradp.ProjectCoefficient(gradp_coef);
exact_gradp.SetTrueVector();
exact_gradp.SetFromTrueVector();
// 13. Compute the projection of the exact field.
ParGridFunction exact_proj(&test_fes);
if (prob == 0)
{
exact_proj.ProjectCoefficient(gradp_coef);
}
else
{
exact_proj.ProjectCoefficient(divgradp_coef);
}
// 14. Compute and print the L^2 norm of the error.
exact_proj.SetTrueVector();
exact_proj.SetFromTrueVector();
// 14. Compute and print the L_2 norm of the error.
if (prob == 0)
{
double errSol = x.ComputeL2Error(gradp_coef);
double errInterp = gradp.ComputeL2Error(gradp_coef);
double errProj = exact_gradp.ComputeL2Error(gradp_coef);
double errInterp = discreteInterpolant.ComputeL2Error(gradp_coef);
double errProj = exact_proj.ComputeL2Error(gradp_coef);
if (myid == 0)
{
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in "
"H(curl): || E_h - grad p ||_{L^2} = " << errSol << '\n' << endl;
cout << " Gradient interpolant E_h = grad p_h in H(curl): || E_h - "
"grad p ||_{L^2} = " << errInterp << '\n' << endl;
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in H(curl): "
"|| E_h - grad p ||_{L_2} = " << errSol << '\n' << endl;
cout << " Gradient interpolant E_h = grad p_h in H(curl): || E_h - grad p"
"||_{L_2} = " << errInterp << '\n' << endl;
cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
"||_{L^2} = " << errProj << '\n' << endl;
"||_{L_2} = " << errProj << '\n' << endl;
}
}
else
{
int order_quad = max(2, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
double errSol = x.ComputeL2Error(divgradp_coef, irs);
double errInterp = discreteInterpolant.ComputeL2Error(divgradp_coef, irs);
double errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
if (myid == 0)
{
cout << "\n Solution of (f_h,q) = (div v_h,q) for f_h and q in L_2: "
"|| f_h - div v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Divergence interpolant f_h = div v_h in L_2: || f_h - div v"
"||_{L_2} = " << errInterp << '\n' << endl;
cout << " Projection f_h of exact div v in L_2: || f_h - div v "
"||_{L_2} = " << errProj << '\n' << endl;
}
}
@@ -302,14 +384,8 @@ int main(int argc, char *argv[])
}
// 17. Free the used memory.
delete a;
delete a_NDH1;
delete sigma;
delete muinv;
delete fespace;
delete H1fespace;
delete fec;
delete H1fec;
delete trial_fec;
delete test_fec;
delete pmesh;
MPI_Finalize();
@@ -346,3 +422,17 @@ void gradp_exact(const Vector &x, Vector &f)
if (x.Size() == 3) { f(2) = 0.0; }
}
}
double div_gradp_exact(const Vector &x)
{
if (dim == 3)
{
return -3.0 * sin(x(0)) * sin(x(1)) * sin(x(2));
}
else if (dim == 2)
{
return -2.0 * sin(x(0)) * sin(x(1));
}
return 0.0;
}
+60 -26
View File
@@ -6,6 +6,7 @@
// ex4 -m ../data/star.mesh
// ex4 -m ../data/beam-tet.mesh
// ex4 -m ../data/beam-hex.mesh
// ex4 -m ../data/beam-hex.mesh -o 2 -pa
// ex4 -m ../data/escher.mesh
// ex4 -m ../data/fichera.mesh -o 2 -hb
// ex4 -m ../data/fichera-q2.vtk
@@ -20,6 +21,12 @@
// ex4 -m ../data/fichera-amr.mesh -o 2 -sc
// ex4 -m ../data/star-surf.mesh -o 1
//
// Device sample runs:
// ex4 -m ../data/star.mesh -pa -d cuda
// ex4 -m ../data/star.mesh -pa -d raja-cuda
// ex4 -m ../data/star.mesh -pa -d raja-omp
// ex4 -m ../data/beam-hex.mesh -pa -d cuda
//
// 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
@@ -55,6 +62,8 @@ int main(int argc, char *argv[])
bool set_bc = true;
bool static_cond = false;
bool hybridization = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -70,6 +79,10 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
"--no-hybridization", "Enable hybridization.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -82,14 +95,19 @@ int main(int argc, char *argv[])
args.PrintOptions(cout);
kappa = freq * M_PI;
// 2. Read the mesh from the given mesh file. We can handle triangular,
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. 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);
int dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 3. Refine the mesh to increase the resolution. In this example we do
// 4. 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 25,000
// elements.
@@ -102,14 +120,14 @@ int main(int argc, char *argv[])
}
}
// 4. Define a finite element space on the mesh. Here we use the
// 5. Define a finite element space on the mesh. Here we use the
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *fec = new RT_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.
// 6. 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.
@@ -121,7 +139,7 @@ int main(int argc, char *argv[])
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 6. Set up the linear form b(.) which corresponds to the right-hand side
// 7. Set up the 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.
@@ -130,7 +148,7 @@ int main(int argc, char *argv[])
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 7. Define the solution vector x as a finite element grid function
// 8. Define the solution vector x as a 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
@@ -139,16 +157,17 @@ int main(int argc, char *argv[])
VectorFunctionCoefficient F(sdim, F_exact);
x.ProjectCoefficient(F);
// 8. Set up the bilinear form corresponding to the H(div) diffusion operator
// 9. Set up the 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);
BilinearForm *a = new BilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
// 9. Assemble the bilinear form and the corresponding linear system,
// 10. 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, hybridization, etc.
@@ -167,32 +186,47 @@ int main(int argc, char *argv[])
}
a->Assemble();
SparseMatrix A;
OperatorPtr A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A.Height() << endl;
cout << "Size of linear system: " << A->Height() << endl;
// 11. Solve the linear system A X = B.
if (!pa)
{
#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, 10000, 1e-20, 0.0);
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 1, 10000, 1e-20, 0.0);
#else
// 10. If compiled with SuiteSparse support, 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);
// If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(*A);
umf_solver.Mult(B, X);
#endif
}
else // Jacobi preconditioning in partial assembly mode
{
if (UsesTensorBasis(*fespace))
{
OperatorJacobiSmoother M(*a, ess_tdof_list);
PCG(*A, M, B, X, 1, 10000, 1e-20, 0.0);
}
else
{
CG(*A, B, X, 1, 10000, 1e-20, 0.0);
}
}
// 11. Recover the solution as a finite element grid function.
// 12. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 12. Compute and print the L^2 norm of the error.
// 13. Compute and print the L^2 norm of the error.
cout << "\n|| F_h - F ||_{L^2} = " << x.ComputeL2Error(F) << '\n' << endl;
// 13. Save the refined mesh and the solution. This output can be viewed
// 14. 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");
@@ -203,7 +237,7 @@ int main(int argc, char *argv[])
x.Save(sol_ofs);
}
// 14. Send the solution by socket to a GLVis server.
// 15. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
@@ -213,7 +247,7 @@ int main(int argc, char *argv[])
sol_sock << "solution\n" << *mesh << x << flush;
}
// 15. Free the used memory.
// 16. Free the used memory.
delete hfes;
delete hfec;
delete a;
@@ -235,7 +269,7 @@ void F_exact(const Vector &p, Vector &F)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if F is changed to depend on z
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
@@ -252,7 +286,7 @@ void f_exact(const Vector &p, Vector &f)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if f is changed to depend on z
double temp = 1 + 2*kappa*kappa;
+50 -29
View File
@@ -6,6 +6,7 @@
// 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/beam-hex.mesh -o 2 -pa
// 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
@@ -19,6 +20,12 @@
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
//
// Device sample runs:
// mpirun -np 4 ex4p -m ../data/star.mesh -pa -d cuda
// mpirun -np 4 ex4p -m ../data/star.mesh -pa -d raja-cuda
// mpirun -np 4 ex4p -m ../data/star.mesh -pa -d raja-omp
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh -pa -d cuda
//
// 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
@@ -60,6 +67,8 @@ int main(int argc, char *argv[])
bool set_bc = true;
bool static_cond = false;
bool hybridization = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -75,6 +84,10 @@ int main(int argc, char *argv[])
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
"--no-hybridization", "Enable hybridization.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -94,14 +107,19 @@ int main(int argc, char *argv[])
}
kappa = freq * M_PI;
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// 3. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
if (myid == 0) { device.Print(); }
// 4. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume, as well as periodic 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. In
// 5. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
@@ -114,7 +132,7 @@ int main(int argc, char *argv[])
}
}
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
@@ -130,7 +148,7 @@ int main(int argc, char *argv[])
}
pmesh->ReorientTetMesh();
// 6. Define a parallel finite element space on the parallel mesh. Here we
// 7. 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);
@@ -140,7 +158,7 @@ int main(int argc, char *argv[])
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// 8. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
@@ -152,7 +170,7 @@ int main(int argc, char *argv[])
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// 9. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
@@ -161,7 +179,7 @@ int main(int argc, char *argv[])
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// 10. 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
@@ -170,16 +188,17 @@ int main(int argc, char *argv[])
VectorFunctionCoefficient F(sdim, F_exact);
x.ProjectCoefficient(F);
// 10. Set up the parallel bilinear form corresponding to the H(div)
// 11. 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);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
// 11. Assemble the parallel bilinear form and the corresponding linear
// 12. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation,
@@ -199,41 +218,43 @@ int main(int argc, char *argv[])
}
a->Assemble();
HypreParMatrix A;
OperatorPtr A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
HYPRE_Int glob_size = A.GetGlobalNumRows();
if (myid == 0)
if (myid == 0 && !pa)
{
cout << "Size of linear system: " << glob_size << endl;
cout << "Size of linear system: "
<< A.As<HypreParMatrix>()->GetGlobalNumRows() << endl;
}
// 12. Define and apply a parallel PCG solver for A X = B with the 2D AMS or
// 13. 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);
// system is preconditioned with hypre's BoomerAMG. In the partial
// assembly case, use Jacobi preconditioning.
Solver *prec = NULL;
CGSolver *pcg = new CGSolver(MPI_COMM_WORLD);
pcg->SetOperator(*A);
pcg->SetRelTol(1e-12);
pcg->SetMaxIter(500);
pcg->SetMaxIter(2000);
pcg->SetPrintLevel(1);
if (hybridization) { prec = new HypreBoomerAMG(A); }
if (hybridization) { prec = new HypreBoomerAMG(*A.As<HypreParMatrix>()); }
else if (pa) { prec = new OperatorJacobiSmoother(*a, ess_tdof_list); }
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); }
if (dim == 2) { prec = new HypreAMS(*A.As<HypreParMatrix>(), prec_fespace); }
else { prec = new HypreADS(*A.As<HypreParMatrix>(), prec_fespace); }
}
pcg->SetPreconditioner(*prec);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// 14. 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.
// 15. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(F);
if (myid == 0)
@@ -242,7 +263,7 @@ int main(int argc, char *argv[])
}
}
// 15. Save the refined mesh and the solution in parallel. This output can
// 16. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
@@ -258,7 +279,7 @@ int main(int argc, char *argv[])
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
@@ -269,7 +290,7 @@ int main(int argc, char *argv[])
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
// 18. Free the used memory.
delete pcg;
delete prec;
delete hfes;
@@ -295,7 +316,7 @@ void F_exact(const Vector &p, Vector &F)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if F is changed to depend on z
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
@@ -312,7 +333,7 @@ void f_exact(const Vector &p, Vector &f)
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
// double z = (dim == 3) ? p(2) : 0.0; // Uncomment if f is changed to depend on z
double temp = 1 + 2*kappa*kappa;
+76 -24
View File
@@ -4,8 +4,10 @@
//
// Sample runs: ex5 -m ../data/square-disc.mesh
// ex5 -m ../data/star.mesh
// ex5 -m ../data/star.mesh -pa
// ex5 -m ../data/beam-tet.mesh
// ex5 -m ../data/beam-hex.mesh
// ex5 -m ../data/beam-hex.mesh -pa
// ex5 -m ../data/escher.mesh
// ex5 -m ../data/fichera.mesh
//
@@ -47,6 +49,7 @@ int main(int argc, char *argv[])
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
bool pa = false;
bool visualization = 1;
OptionsParser args(argc, argv);
@@ -54,6 +57,8 @@ int main(int argc, char *argv[])
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -146,22 +151,39 @@ int main(int argc, char *argv[])
BilinearForm *mVarf(new BilinearForm(R_space));
MixedBilinearForm *bVarf(new MixedBilinearForm(R_space, W_space));
if (pa) { mVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(k));
mVarf->Assemble();
mVarf->Finalize();
SparseMatrix &M(mVarf->SpMat());
if (!pa) { mVarf->Finalize(); }
if (pa) { bVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
bVarf->Assemble();
bVarf->Finalize();
SparseMatrix & B(bVarf->SpMat());
B *= -1.;
SparseMatrix *BT = Transpose(B);
if (!pa) { bVarf->Finalize(); }
BlockMatrix darcyMatrix(block_offsets);
darcyMatrix.SetBlock(0,0, &M);
darcyMatrix.SetBlock(0,1, BT);
darcyMatrix.SetBlock(1,0, &B);
BlockOperator darcyOp(block_offsets);
TransposeOperator *Bt = NULL;
if (pa)
{
Bt = new TransposeOperator(bVarf);
darcyOp.SetBlock(0,0, mVarf);
darcyOp.SetBlock(0,1, Bt, -1.0);
darcyOp.SetBlock(1,0, bVarf, -1.0);
}
else
{
SparseMatrix &M(mVarf->SpMat());
SparseMatrix &B(bVarf->SpMat());
B *= -1.;
Bt = new TransposeOperator(&B);
darcyOp.SetBlock(0,0, &M);
darcyOp.SetBlock(0,1, Bt);
darcyOp.SetBlock(1,0, &B);
}
// 9. Construct the operators for preconditioner
//
@@ -170,27 +192,57 @@ int main(int argc, char *argv[])
//
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
// pressure Schur Complement
SparseMatrix *MinvBt = Transpose(B);
Vector Md(M.Height());
M.GetDiag(Md);
for (int i = 0; i < Md.Size(); i++)
{
MinvBt->ScaleRow(i, 1./Md(i));
}
SparseMatrix *S = Mult(B, *MinvBt);
SparseMatrix *MinvBt = NULL;
Vector Md(mVarf->Height());
BlockDiagonalPreconditioner darcyPrec(block_offsets);
Solver *invM, *invS;
invM = new DSmoother(M);
SparseMatrix *S = NULL;
if (pa)
{
mVarf->AssembleDiagonal(Md);
Vector invMd(mVarf->Height());
for (int i=0; i<mVarf->Height(); ++i)
{
invMd(i) = 1.0 / Md(i);
}
Vector BMBt_diag(bVarf->Height());
bVarf->AssembleDiagonal_ADAt(invMd, BMBt_diag);
Array<int> ess_tdof_list; // empty
invM = new OperatorJacobiSmoother(Md, ess_tdof_list);
invS = new OperatorJacobiSmoother(BMBt_diag, ess_tdof_list);
}
else
{
SparseMatrix &M(mVarf->SpMat());
M.GetDiag(Md);
SparseMatrix &B(bVarf->SpMat());
MinvBt = Transpose(B);
for (int i = 0; i < Md.Size(); i++)
{
MinvBt->ScaleRow(i, 1./Md(i));
}
S = Mult(B, *MinvBt);
invM = new DSmoother(M);
#ifndef MFEM_USE_SUITESPARSE
invS = new GSSmoother(*S);
invS = new GSSmoother(*S);
#else
invS = new UMFPackSolver(*S);
invS = new UMFPackSolver(*S);
#endif
}
invM->iterative_mode = false;
invS->iterative_mode = false;
BlockDiagonalPreconditioner darcyPrec(block_offsets);
darcyPrec.SetDiagonalBlock(0, invM);
darcyPrec.SetDiagonalBlock(1, invS);
@@ -206,7 +258,7 @@ int main(int argc, char *argv[])
solver.SetAbsTol(atol);
solver.SetRelTol(rtol);
solver.SetMaxIter(maxIter);
solver.SetOperator(darcyMatrix);
solver.SetOperator(darcyOp);
solver.SetPreconditioner(darcyPrec);
solver.SetPrintLevel(1);
x = 0.0;
@@ -295,8 +347,8 @@ int main(int argc, char *argv[])
delete invM;
delete invS;
delete S;
delete Bt;
delete MinvBt;
delete BT;
delete mVarf;
delete bVarf;
delete W_space;
+84 -25
View File
@@ -4,8 +4,10 @@
//
// Sample runs: mpirun -np 4 ex5p -m ../data/square-disc.mesh
// mpirun -np 4 ex5p -m ../data/star.mesh
// mpirun -np 4 ex5p -m ../data/star.mesh -r 2 -pa
// mpirun -np 4 ex5p -m ../data/beam-tet.mesh
// mpirun -np 4 ex5p -m ../data/beam-hex.mesh
// mpirun -np 4 ex5p -m ../data/beam-hex.mesh -pa
// mpirun -np 4 ex5p -m ../data/escher.mesh
// mpirun -np 4 ex5p -m ../data/fichera.mesh
//
@@ -54,19 +56,25 @@ int main(int argc, char *argv[])
// 2. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int ref_levels = -1;
int order = 1;
bool par_format = false;
bool pa = false;
bool visualization = 1;
bool adios2 = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&par_format, "-pf", "--parallel-format", "-sf",
"--serial-format",
"Format to use when saving the results for VisIt.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
@@ -97,10 +105,13 @@ int main(int argc, char *argv[])
// 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.
// more than 10,000 elements, unless the user specifies it as input.
{
int ref_levels =
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
if (ref_levels == -1)
{
ref_levels = (int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
@@ -196,25 +207,47 @@ int main(int argc, char *argv[])
ParBilinearForm *mVarf(new ParBilinearForm(R_space));
ParMixedBilinearForm *bVarf(new ParMixedBilinearForm(R_space, W_space));
HypreParMatrix *M, *B;
HypreParMatrix *M = NULL;
HypreParMatrix *B = NULL;
if (pa) { mVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(k));
mVarf->Assemble();
mVarf->Finalize();
M = mVarf->ParallelAssemble();
if (!pa) { mVarf->Finalize(); }
if (pa) { bVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
bVarf->Assemble();
bVarf->Finalize();
B = bVarf->ParallelAssemble();
(*B) *= -1;
HypreParMatrix *BT = B->Transpose();
if (!pa) { bVarf->Finalize(); }
BlockOperator *darcyOp = new BlockOperator(block_trueOffsets);
darcyOp->SetBlock(0,0, M);
darcyOp->SetBlock(0,1, BT);
darcyOp->SetBlock(1,0, B);
Array<int> empty_tdof_list; // empty
OperatorPtr opM, opB;
TransposeOperator *Bt = NULL;
if (pa)
{
mVarf->FormSystemMatrix(empty_tdof_list, opM);
bVarf->FormRectangularSystemMatrix(empty_tdof_list, empty_tdof_list, opB);
Bt = new TransposeOperator(opB.Ptr());
darcyOp->SetBlock(0,0, opM.Ptr());
darcyOp->SetBlock(0,1, Bt, -1.0);
darcyOp->SetBlock(1,0, opB.Ptr(), -1.0);
}
else
{
M = mVarf->ParallelAssemble();
B = bVarf->ParallelAssemble();
(*B) *= -1;
Bt = new TransposeOperator(B);
darcyOp->SetBlock(0,0, M);
darcyOp->SetBlock(0,1, Bt);
darcyOp->SetBlock(1,0, B);
}
// 11. Construct the operators for preconditioner
//
@@ -223,17 +256,43 @@ int main(int argc, char *argv[])
//
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
// pressure Schur Complement.
HypreParMatrix *MinvBt = B->Transpose();
HypreParVector *Md = new HypreParVector(MPI_COMM_WORLD, M->GetGlobalNumRows(),
M->GetRowStarts());
M->GetDiag(*Md);
HypreParMatrix *MinvBt = NULL;
HypreParVector *Md = NULL;
HypreParMatrix *S = NULL;
Vector Md_PA;
Solver *invM, *invS;
MinvBt->InvScaleRows(*Md);
HypreParMatrix *S = ParMult(B, MinvBt);
if (pa)
{
Md_PA.SetSize(R_space->GetTrueVSize());
mVarf->AssembleDiagonal(Md_PA);
Vector invMd(Md_PA.Size());
for (int i=0; i<Md_PA.Size(); ++i)
{
invMd(i) = 1.0 / Md_PA(i);
}
HypreSolver *invM, *invS;
invM = new HypreDiagScale(*M);
invS = new HypreBoomerAMG(*S);
Vector BMBt_diag(W_space->GetTrueVSize());
bVarf->AssembleDiagonal_ADAt(invMd, BMBt_diag);
Array<int> ess_tdof_list; // empty
invM = new OperatorJacobiSmoother(Md_PA, ess_tdof_list);
invS = new OperatorJacobiSmoother(BMBt_diag, ess_tdof_list);
}
else
{
Md = new HypreParVector(MPI_COMM_WORLD, M->GetGlobalNumRows(),
M->GetRowStarts());
M->GetDiag(*Md);
MinvBt = B->Transpose();
MinvBt->InvScaleRows(*Md);
S = ParMult(B, MinvBt);
invM = new HypreDiagScale(*M);
invS = new HypreBoomerAMG(*S);
}
invM->iterative_mode = false;
invS->iterative_mode = false;
@@ -245,7 +304,7 @@ int main(int argc, char *argv[])
// 12. Solve the linear system with MINRES.
// Check the norm of the unpreconditioned residual.
int maxIter(500);
int maxIter(pa ? 1000 : 500);
double rtol(1.e-6);
double atol(1.e-10);
@@ -395,7 +454,7 @@ int main(int argc, char *argv[])
delete S;
delete Md;
delete MinvBt;
delete BT;
delete Bt;
delete B;
delete M;
delete mVarf;
+11 -1
View File
@@ -19,6 +19,7 @@
//
// Device sample runs:
// ex9 -pa
// ex9 -ea
// ex9 -pa -m ../data/periodic-cube.mesh
// ex9 -pa -m ../data/periodic-cube.mesh -d cuda
//
@@ -142,6 +143,7 @@ int main(int argc, char *argv[])
int ref_levels = 2;
int order = 3;
bool pa = false;
bool ea = false;
const char *device_config = "cpu";
int ode_solver_type = 4;
double t_final = 10.0;
@@ -166,6 +168,8 @@ int main(int argc, char *argv[])
"Order (degree) of the finite elements.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
@@ -269,6 +273,11 @@ int main(int argc, char *argv[])
m.SetAssemblyLevel(AssemblyLevel::PARTIAL);
k.SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
else if (ea)
{
m.SetAssemblyLevel(AssemblyLevel::ELEMENT);
k.SetAssemblyLevel(AssemblyLevel::ELEMENT);
}
m.AddDomainIntegrator(new MassIntegrator);
k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
k.AddInteriorFaceIntegrator(
@@ -429,8 +438,9 @@ FE_Evolution::FE_Evolution(BilinearForm &_M, BilinearForm &_K, const Vector &_b)
: TimeDependentOperator(_M.Height()), M(_M), K(_K), b(_b), z(_M.Height())
{
bool pa = M.GetAssemblyLevel() == AssemblyLevel::PARTIAL;
bool ea = M.GetAssemblyLevel() == AssemblyLevel::ELEMENT;
Array<int> ess_tdof_list;
if (pa)
if (pa || ea)
{
M_prec = new OperatorJacobiSmoother(M, ess_tdof_list);
M_solver.SetOperator(M);
+12 -2
View File
@@ -19,6 +19,7 @@
//
// Device sample runs:
// mpirun -np 4 ex9p -pa
// mpirun -np 4 ex9p -ea
// mpirun -np 4 ex9p -pa -m ../data/periodic-cube.mesh
// mpirun -np 4 ex9p -pa -m ../data/periodic-cube.mesh -d cuda
//
@@ -161,6 +162,7 @@ int main(int argc, char *argv[])
int par_ref_levels = 0;
int order = 3;
bool pa = false;
bool ea = false;
const char *device_config = "cpu";
int ode_solver_type = 4;
double t_final = 10.0;
@@ -188,6 +190,8 @@ int main(int argc, char *argv[])
"Order (degree) of the finite elements.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
@@ -319,6 +323,11 @@ int main(int argc, char *argv[])
m->SetAssemblyLevel(AssemblyLevel::PARTIAL);
k->SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
else if (ea)
{
m->SetAssemblyLevel(AssemblyLevel::ELEMENT);
k->SetAssemblyLevel(AssemblyLevel::ELEMENT);
}
m->AddDomainIntegrator(new MassIntegrator);
k->AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
k->AddInteriorFaceIntegrator(
@@ -556,8 +565,9 @@ FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K,
z(_M.Height())
{
bool pa = _M.GetAssemblyLevel()==AssemblyLevel::PARTIAL;
bool ea = _M.GetAssemblyLevel()==AssemblyLevel::ELEMENT;
if (pa)
if (pa || ea)
{
M.Reset(&_M, false);
K.Reset(&_K, false);
@@ -571,7 +581,7 @@ FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K,
M_solver.SetOperator(*M);
Array<int> ess_tdof_list;
if (pa)
if (pa || ea)
{
M_prec = new OperatorJacobiSmoother(_M, ess_tdof_list);
dg_solver = NULL;
+7
View File
@@ -32,6 +32,13 @@
// is used for the Finite Element order and "-go" is used for the
// geometry order. Note that they can be used independently, i.e.
// "-o 8 -go 3" solves for 8th order FE on a third order geometry.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
+8
View File
@@ -36,6 +36,14 @@
// option "-o" is used for the Finite Element order and "-go" for
// the geometry order. Note that they can be used independently:
// "-o 8 -go 3" solves for 8th order FE on third order geometry.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
+8
View File
@@ -43,6 +43,14 @@
// also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
+8 -2
View File
@@ -1,7 +1,7 @@
// MFEM Example 6 - Parallel Version
// PUMI Modification
//
// Compile with: make ex1p
// Compile with: make ex6p
//
// Sample runs: mpirun -np 8 ex6p
//
@@ -18,6 +18,13 @@
// is added to modify the "adapt_ratio" which is the fraction of
// allowable error that scales the output size field of the error
// estimator.
//
// NOTE: Model/Mesh files for this example are in the (large) data file
// repository of MFEM here https://github.com/mfem/data under the
// folder named "pumi", which consists of the following sub-folders:
// a) geom --> model files
// b) parallel --> parallel pumi mesh files
// c) serial --> serial pumi mesh files
#include "mfem.hpp"
#include <fstream>
@@ -332,7 +339,6 @@ int main(int argc, char *argv[])
apf::destroyField(Tmag_field);
apf::destroyField(ipfield);
apf::destroyNumbering(pumi_mesh->findNumbering("LocalVertexNumbering"));
// 18. Perform MesAdapt.
ma::Input* erinput = ma::configure(pumi_mesh, sizefield);
+11 -4
View File
@@ -13,13 +13,20 @@ set(SRCS
bilinearform.cpp
bilinearform_ext.cpp
bilininteg.cpp
bilininteg_convection.cpp
bilininteg_dgtrace.cpp
bilininteg_diffusion.cpp
bilininteg_convection_pa.cpp
bilininteg_convection_ea.cpp
bilininteg_dgtrace_pa.cpp
bilininteg_dgtrace_ea.cpp
bilininteg_diffusion_pa.cpp
bilininteg_diffusion_ea.cpp
bilininteg_divergence.cpp
bilininteg_hcurl.cpp
bilininteg_hdiv.cpp
bilininteg_vectorfe.cpp
bilininteg_gradient.cpp
bilininteg_mass.cpp
bilininteg_mass_pa.cpp
bilininteg_mass_ea.cpp
bilininteg_transpose_ea.cpp
bilininteg_vecdiffusion.cpp
bilininteg_vecmass.cpp
coefficient.cpp
+3 -1
View File
@@ -15,6 +15,8 @@
#include "adios2datacollection.hpp"
#ifdef MFEM_USE_ADIOS2
namespace mfem
{
@@ -87,4 +89,4 @@ noexcept
} //end namespace mfem
#endif // MFEM_USE_ADIOS2
+5
View File
@@ -17,6 +17,9 @@
#define MFEM_ADIOS2DATACOLLECTION
#include "../config/config.hpp"
#ifdef MFEM_USE_ADIOS2
#include "../general/adios2stream.hpp"
#include "datacollection.hpp"
@@ -85,4 +88,6 @@ private:
} // namespace mfem
#endif // MFEM_USE_ADIOS2
#endif /* MFEM_ADIOS2DATACOLLECTION */
+49 -2
View File
@@ -126,8 +126,7 @@ void BilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
// Use the original BilinearForm implementation for now
break;
case AssemblyLevel::ELEMENT:
mfem_error("Element assembly not supported yet... stay tuned!");
// ext = new EABilinearFormExtension(this);
ext = new EABilinearFormExtension(this);
break;
case AssemblyLevel::PARTIAL:
ext = new PABilinearFormExtension(this);
@@ -1432,6 +1431,54 @@ void MixedBilinearForm::Assemble (int skip_zeros)
}
}
void MixedBilinearForm::AssembleDiagonal_ADAt(const Vector &D,
Vector &diag) const
{
if (ext)
{
MFEM_ASSERT(diag.Size() == test_fes->GetTrueVSize(),
"Vector for holding diagonal has wrong size!");
MFEM_ASSERT(D.Size() == trial_fes->GetTrueVSize(),
"Vector for holding diagonal has wrong size!");
const Operator *P_trial = trial_fes->GetProlongationMatrix();
const Operator *P_test = test_fes->GetProlongationMatrix();
if (!IsIdentityProlongation(P_trial))
{
Vector local_D(P_trial->Height());
P_trial->Mult(D, local_D);
if (!IsIdentityProlongation(P_test))
{
Vector local_diag(P_test->Height());
ext->AssembleDiagonal_ADAt(local_D, local_diag);
P_test->MultTranspose(local_diag, diag);
}
else
{
ext->AssembleDiagonal_ADAt(local_D, diag);
}
}
else
{
if (!IsIdentityProlongation(P_test))
{
Vector local_diag(P_test->Height());
ext->AssembleDiagonal_ADAt(D, local_diag);
P_test->MultTranspose(local_diag, diag);
}
else
{
ext->AssembleDiagonal_ADAt(D, diag);
}
}
}
else
{
MFEM_ABORT("Not implemented. Maybe assemble your bilinear form into a "
"matrix and use SparseMatrix functions?");
}
}
void MixedBilinearForm::ConformingAssemble()
{
if (assembly != AssemblyLevel::FULL)
+4
View File
@@ -705,6 +705,10 @@ public:
void Assemble(int skip_zeros = 1);
/** @brief Assemble the diagonal of ADA^T into diag, where A is this mixed
bilinear form and D is a diagonal. */
void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const;
/// Get the input finite element space prolongation matrix
virtual const Operator *GetProlongation() const
{ return trial_fes->GetProlongationMatrix(); }
+376 -4
View File
@@ -47,7 +47,7 @@ PABilinearFormExtension::PABilinearFormExtension(BilinearForm *form)
bdr_face_restrict_lex = NULL;
}
void PABilinearFormExtension::SetupRestrictionOperators()
void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
{
ElementDofOrdering ordering = UsesTensorBasis(*a->FESpace())?
ElementDofOrdering::LEXICOGRAPHIC:
@@ -65,7 +65,8 @@ void PABilinearFormExtension::SetupRestrictionOperators()
if (int_face_restrict_lex == NULL && a->GetFBFI()->Size() > 0)
{
int_face_restrict_lex = trialFes->GetFaceRestriction(
ElementDofOrdering::LEXICOGRAPHIC, FaceType::Interior);
ElementDofOrdering::LEXICOGRAPHIC,
FaceType::Interior);
faceIntX.SetSize(int_face_restrict_lex->Height(), Device::GetMemoryType());
faceIntY.SetSize(int_face_restrict_lex->Height(), Device::GetMemoryType());
faceIntY.UseDevice(true); // ensure 'faceIntY = 0.0' is done on device
@@ -74,7 +75,9 @@ void PABilinearFormExtension::SetupRestrictionOperators()
if (bdr_face_restrict_lex == NULL && a->GetBFBFI()->Size() > 0)
{
bdr_face_restrict_lex = trialFes->GetFaceRestriction(
ElementDofOrdering::LEXICOGRAPHIC, FaceType::Boundary);
ElementDofOrdering::LEXICOGRAPHIC,
FaceType::Boundary,
m);
faceBdrX.SetSize(bdr_face_restrict_lex->Height(), Device::GetMemoryType());
faceBdrY.SetSize(bdr_face_restrict_lex->Height(), Device::GetMemoryType());
faceBdrY.UseDevice(true); // ensure 'faceBoundY = 0.0' is done on device
@@ -83,7 +86,7 @@ void PABilinearFormExtension::SetupRestrictionOperators()
void PABilinearFormExtension::Assemble()
{
SetupRestrictionOperators();
SetupRestrictionOperators(L2FaceValues::DoubleValued);
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int integratorCount = integrators.Size();
@@ -287,6 +290,311 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
}
}
// Data and methods for element-assembled bilinear forms
EABilinearFormExtension::EABilinearFormExtension(BilinearForm *form)
: PABilinearFormExtension(form)
{
}
void EABilinearFormExtension::Assemble()
{
SetupRestrictionOperators(L2FaceValues::SingleValued);
ne = trialFes->GetMesh()->GetNE();
elemDofs = trialFes->GetFE(0)->GetDof();
ea_data.SetSize(ne*elemDofs*elemDofs, Device::GetMemoryType());
ea_data.UseDevice(true);
ea_data = 0.0;
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int integratorCount = integrators.Size();
for (int i = 0; i < integratorCount; ++i)
{
integrators[i]->AssembleEA(*a->FESpace(), ea_data);
}
faceDofs = trialFes ->
GetTraceElement(0, trialFes->GetMesh()->GetFaceBaseGeometry(0)) ->
GetDof();
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int intFaceIntegratorCount = intFaceIntegrators.Size();
if (intFaceIntegratorCount>0)
{
nf_int = trialFes->GetNFbyType(FaceType::Interior);
ea_data_int.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_ext.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_int = 0.0;
ea_data_ext = 0.0;
}
for (int i = 0; i < intFaceIntegratorCount; ++i)
{
intFaceIntegrators[i]->AssembleEAInteriorFaces(*a->FESpace(),
ea_data_int,
ea_data_ext);
}
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int boundFaceIntegratorCount = bdrFaceIntegrators.Size();
if (boundFaceIntegratorCount>0)
{
nf_bdr = trialFes->GetNFbyType(FaceType::Boundary);
ea_data_bdr.SetSize(nf_bdr*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_bdr = 0.0;
}
for (int i = 0; i < boundFaceIntegratorCount; ++i)
{
bdrFaceIntegrators[i]->AssembleEABoundaryFaces(*a->FESpace(),ea_data_bdr);
}
}
void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
{
// Apply the Element Restriction
const bool useRestrict = !DeviceCanUseCeed() && elem_restrict;
if (!useRestrict)
{
y.UseDevice(true); // typically this is a large vector, so store on device
y = 0.0;
}
else
{
elem_restrict->Mult(x, localX);
localY = 0.0;
}
// Apply the Element Matrices
const int NDOFS = elemDofs;
auto X = Reshape(useRestrict?localX.Read():x.Read(), NDOFS, ne);
auto Y = Reshape(useRestrict?localY.ReadWrite():y.ReadWrite(), NDOFS, ne);
auto A = Reshape(ea_data.Read(), NDOFS, NDOFS, ne);
MFEM_FORALL(glob_j, ne*NDOFS,
{
const int e = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(i, j, e)*X(i, e);
}
Y(j, e) += res;
});
// Apply the Element Restriction transposed
if (useRestrict)
{
elem_restrict->MultTranspose(localY, y);
}
// Treatment of interior faces
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int iFISz = intFaceIntegrators.Size();
if (int_face_restrict_lex && iFISz>0)
{
// Apply the Interior Face Restriction
int_face_restrict_lex->Mult(x, faceIntX);
if (faceIntX.Size()>0)
{
faceIntY = 0.0;
// Apply the interior face matrices
const int NDOFS = faceDofs;
auto X = Reshape(faceIntX.Read(), NDOFS, 2, nf_int);
auto Y = Reshape(faceIntY.ReadWrite(), NDOFS, 2, nf_int);
auto A_int = Reshape(ea_data_int.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(i, j, 0, f)*X(i, 0, f);
}
Y(j, 0, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(i, j, 1, f)*X(i, 1, f);
}
Y(j, 1, f) += res;
});
auto A_ext = Reshape(ea_data_ext.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(i, j, 0, f)*X(i, 0, f);
}
Y(j, 1, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(i, j, 1, f)*X(i, 1, f);
}
Y(j, 0, f) += res;
});
// Apply the Interior Face Restriction transposed
int_face_restrict_lex->MultTranspose(faceIntY, y);
}
}
// Treatment of boundary faces
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (bdr_face_restrict_lex && bFISz>0)
{
// Apply the Boundary Face Restriction
bdr_face_restrict_lex->Mult(x, faceBdrX);
if (faceBdrX.Size()>0)
{
faceBdrY = 0.0;
// Apply the boundary face matrices
const int NDOFS = faceDofs;
auto X = Reshape(faceBdrX.Read(), NDOFS, nf_bdr);
auto Y = Reshape(faceBdrY.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
MFEM_FORALL(glob_j, nf_bdr*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(i, j, f)*X(i, f);
}
Y(j, f) += res;
});
// Apply the Boundary Face Restriction transposed
bdr_face_restrict_lex->MultTranspose(faceBdrY, y);
}
}
}
void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
{
// Apply the Element Restriction
const bool useRestrict = DeviceCanUseCeed() || !elem_restrict;
if (!useRestrict)
{
y.UseDevice(true); // typically this is a large vector, so store on device
y = 0.0;
}
else
{
elem_restrict->Mult(x, localX);
localY = 0.0;
}
// Apply the Element Matrices transposed
const int NDOFS = elemDofs;
auto X = Reshape(useRestrict?localX.Read():x.Read(), NDOFS, ne);
auto Y = Reshape(useRestrict?localY.ReadWrite():y.ReadWrite(), NDOFS, ne);
auto A = Reshape(ea_data.Read(), NDOFS, NDOFS, ne);
MFEM_FORALL(glob_j, ne*NDOFS,
{
const int e = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(j, i, e)*X(i, e);
}
Y(j, e) += res;
});
// Apply the Element Restriction transposed
if (useRestrict)
{
elem_restrict->MultTranspose(localY, y);
}
// Treatment of interior faces
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int iFISz = intFaceIntegrators.Size();
if (int_face_restrict_lex && iFISz>0)
{
// Apply the Interior Face Restriction
int_face_restrict_lex->Mult(x, faceIntX);
if (faceIntX.Size()>0)
{
faceIntY = 0.0;
// Apply the interior face matrices transposed
const int NDOFS = faceDofs;
auto X = Reshape(faceIntX.Read(), NDOFS, 2, nf_int);
auto Y = Reshape(faceIntY.ReadWrite(), NDOFS, 2, nf_int);
auto A_int = Reshape(ea_data_int.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(j, i, 0, f)*X(i, 0, f);
}
Y(j, 0, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_int(j, i, 1, f)*X(i, 1, f);
}
Y(j, 1, f) += res;
});
auto A_ext = Reshape(ea_data_ext.Read(), NDOFS, NDOFS, 2, nf_int);
MFEM_FORALL(glob_j, nf_int*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(j, i, 0, f)*X(i, 0, f);
}
Y(j, 1, f) += res;
res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A_ext(j, i, 1, f)*X(i, 1, f);
}
Y(j, 0, f) += res;
});
// Apply the Interior Face Restriction transposed
int_face_restrict_lex->MultTranspose(faceIntY, y);
}
}
// Treatment of boundary faces
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (bdr_face_restrict_lex && bFISz>0)
{
// Apply the Boundary Face Restriction
bdr_face_restrict_lex->Mult(x, faceBdrX);
if (faceBdrX.Size()>0)
{
faceBdrY = 0.0;
// Apply the boundary face matrices transposed
const int NDOFS = faceDofs;
auto X = Reshape(faceBdrX.Read(), NDOFS, nf_bdr);
auto Y = Reshape(faceBdrY.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
MFEM_FORALL(glob_j, nf_bdr*NDOFS,
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
double res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(j, i, f)*X(i, f);
}
Y(j, f) += res;
});
// Apply the Boundary Face Restriction transposed
bdr_face_restrict_lex->MultTranspose(faceBdrY, y);
}
}
}
MixedBilinearFormExtension::MixedBilinearFormExtension(MixedBilinearForm *form)
: Operator(form->Height(), form->Width()), a(form)
{
@@ -487,4 +795,68 @@ void PAMixedBilinearFormExtension::AddMultTranspose(const Vector &x, Vector &y,
}
}
void PAMixedBilinearFormExtension::AssembleDiagonal_ADAt(const Vector &D,
Vector &diag) const
{
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int iSz = integrators.Size();
if (elem_restrict_trial)
{
const ElementRestriction* H1elem_restrict_trial =
dynamic_cast<const ElementRestriction*>(elem_restrict_trial);
if (H1elem_restrict_trial)
{
H1elem_restrict_trial->MultUnsigned(D, localTrial);
}
else
{
elem_restrict_trial->Mult(D, localTrial);
}
}
if (elem_restrict_test)
{
localTest = 0.0;
for (int i = 0; i < iSz; ++i)
{
if (elem_restrict_trial)
{
integrators[i]->AssembleDiagonalPA_ADAt(localTrial, localTest);
}
else
{
integrators[i]->AssembleDiagonalPA_ADAt(D, localTest);
}
}
const ElementRestriction* H1elem_restrict_test =
dynamic_cast<const ElementRestriction*>(elem_restrict_test);
if (H1elem_restrict_test)
{
H1elem_restrict_test->MultTransposeUnsigned(localTest, diag);
}
else
{
elem_restrict_test->MultTranspose(localTest, diag);
}
}
else
{
diag.UseDevice(true); // typically this is a large vector, so store on device
diag = 0.0;
for (int i = 0; i < iSz; ++i)
{
if (elem_restrict_trial)
{
integrators[i]->AssembleDiagonalPA_ADAt(localTrial, diag);
}
else
{
integrators[i]->AssembleDiagonalPA_ADAt(D, diag);
}
}
}
}
} // namespace mfem
+26 -22
View File
@@ -78,26 +78,6 @@ public:
~FABilinearFormExtension() {}
};
/// Data and methods for element-assembled bilinear forms
class EABilinearFormExtension : public BilinearFormExtension
{
public:
EABilinearFormExtension(BilinearForm *form)
: BilinearFormExtension(form) { }
/// TODO
void Assemble() {}
void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A) {}
void FormLinearSystem(const Array<int> &ess_tdof_list,
Vector &x, Vector &b,
OperatorHandle &A, Vector &X, Vector &B,
int copy_interior = 0) {}
void Mult(const Vector &x, Vector &y) const {}
void MultTranspose(const Vector &x, Vector &y) const {}
void Update() {}
~EABilinearFormExtension() {}
};
/// Data and methods for partially-assembled bilinear forms
class PABilinearFormExtension : public BilinearFormExtension
{
@@ -113,7 +93,6 @@ protected:
public:
PABilinearFormExtension(BilinearForm*);
void SetupRestrictionOperators();
void Assemble();
void AssembleDiagonal(Vector &diag) const;
void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A);
@@ -121,12 +100,32 @@ public:
Vector &x, Vector &b,
OperatorHandle &A, Vector &X, Vector &B,
int copy_interior = 0);
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const;
void Update();
protected:
void SetupRestrictionOperators(const L2FaceValues m);
};
/// Data and methods for element-assembled bilinear forms
class EABilinearFormExtension : public PABilinearFormExtension
{
protected:
int ne;
int elemDofs;
Vector ea_data;
int nf_int, nf_bdr;
int faceDofs;
Vector ea_data_int, ea_data_ext, ea_data_bdr;
public:
EABilinearFormExtension(BilinearForm *form);
void Assemble();
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const;
};
/// Data and methods for matrix-free bilinear forms
class MFBilinearFormExtension : public BilinearFormExtension
@@ -186,6 +185,8 @@ public:
virtual void AddMultTranspose(const Vector &x, Vector &y,
const double c=1.0) const = 0;
virtual void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const = 0;
virtual void Update() = 0;
};
@@ -236,6 +237,9 @@ public:
void MultTranspose(const Vector &x, Vector &y) const;
/// y += c*A^T*x
void AddMultTranspose(const Vector &x, Vector &y, const double c=1.0) const;
/// Assemble the diagonal of ADA^T for a diagonal vector D.
void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const;
/// Update internals for when a new MixedBilinearForm is given to this class
void Update();
};
+50 -28
View File
@@ -47,7 +47,37 @@ void BilinearFormIntegrator::AssemblePABoundaryFaces(const FiniteElementSpace&)
void BilinearFormIntegrator::AssembleDiagonalPA(Vector &)
{
MFEM_ABORT("BilinearFormIntegrator::AssembleDiagonalPA(...)\n"
mfem_error ("BilinearFormIntegrator::AssembleDiagonalPA(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &emat)
{
mfem_error ("BilinearFormIntegrator::AssembleEA(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
&fes,
Vector &ea_data_int,
Vector &ea_data_ext)
{
mfem_error ("BilinearFormIntegrator::AssembleEAInteriorFaces(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace
&fes,
Vector &ea_data_bdr)
{
mfem_error ("BilinearFormIntegrator::AssembleEABoundaryFaces(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleDiagonalPA_ADAt(const Vector &, Vector &)
{
MFEM_ABORT("BilinearFormIntegrator::AssembleDiagonalPA_ADAt(...)\n"
" is not implemented for this class.");
}
@@ -889,7 +919,7 @@ void BoundaryMassIntegrator::AssembleFaceMatrix(
{
int order = 2 * el1.GetOrder();
ir = &IntRules.Get(Trans.FaceGeom, order);
ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
elmat = 0.0;
@@ -900,11 +930,11 @@ void BoundaryMassIntegrator::AssembleFaceMatrix(
Trans.Loc1.Transform(ip, eip);
el1.CalcShape(eip, shape);
Trans.Face->SetIntPoint(&ip);
w = Trans.Face->Weight() * ip.weight;
Trans.SetIntPoint(&ip);
w = Trans.Weight() * ip.weight;
if (Q)
{
w *= Q -> Eval(*Trans.Face, ip);
w *= Q -> Eval(Trans, ip);
}
AddMult_a_VVt(w, shape, elmat);
@@ -1974,7 +2004,7 @@ void VectorFEMassIntegrator::AssembleElementMatrix2(
D.SetSize(VQ ? VQ->GetVDim() : 0);
K.SetSize(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0);
#endif
DenseMatrix tmp(trial_vshape.Height(), K.Width());
DenseMatrix tmp(test_vshape.Height(), K.Width());
elmat.SetSize (test_dof, trial_dof);
@@ -2535,7 +2565,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
{
order++;
}
ir = &IntRules.Get(Trans.FaceGeom, order);
ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
@@ -2549,8 +2579,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
}
el1.CalcShape(eip1, shape1);
Trans.Face->SetIntPoint(&ip);
Trans.Elem1->SetIntPoint(&eip1);
Trans.SetIntPoint(&ip);
u->Eval(vu, *Trans.Elem1, eip1);
@@ -2560,7 +2589,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
}
else
{
CalcOrtho(Trans.Face->Jacobian(), nor);
CalcOrtho(Trans.Jacobian(), nor);
}
un = vu * nor;
@@ -2575,7 +2604,6 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
double rho_p;
if (un >= 0.0 && ndof2)
{
Trans.Elem2->SetIntPoint(&eip2);
rho_p = rho->Eval(*Trans.Elem2, eip2);
}
else
@@ -2691,7 +2719,7 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
{
order = 2*el1.GetOrder();
}
ir = &IntRules.Get(Trans.FaceGeom, order);
ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
// assemble: < {(Q \nabla u).n},[v] > --> elmat
@@ -2702,19 +2730,18 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
IntegrationPoint eip1, eip2;
Trans.Loc1.Transform(ip, eip1);
Trans.Face->SetIntPoint(&ip);
Trans.SetIntPoint(&ip);
if (dim == 1)
{
nor(0) = 2*eip1.x - 1.0;
}
else
{
CalcOrtho(Trans.Face->Jacobian(), nor);
CalcOrtho(Trans.Jacobian(), nor);
}
el1.CalcShape(eip1, shape1);
el1.CalcDShape(eip1, dshape1);
Trans.Elem1->SetIntPoint(&eip1);
w = ip.weight/Trans.Elem1->Weight();
if (ndof2)
{
@@ -2763,7 +2790,6 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
Trans.Loc2.Transform(ip, eip2);
el2.CalcShape(eip2, shape2);
el2.CalcDShape(eip2, dshape2);
Trans.Elem2->SetIntPoint(&eip2);
w = ip.weight/2/Trans.Elem2->Weight();
if (!MQ)
{
@@ -2973,7 +2999,7 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
{
// a simple choice for the integration order; is this OK?
const int order = 2 * max(el1.GetOrder(), ndofs2 ? el2.GetOrder() : 0);
ir = &IntRules.Get(Trans.FaceGeom, order);
ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
for (int pind = 0; pind < ir->GetNPoints(); ++pind)
@@ -2981,8 +3007,7 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
const IntegrationPoint &ip = ir->IntPoint(pind);
IntegrationPoint eip1, eip2; // integration point in the reference space
Trans.Loc1.Transform(ip, eip1);
Trans.Face->SetIntPoint(&ip);
Trans.Elem1->SetIntPoint(&eip1);
Trans.SetIntPoint(&ip);
el1.CalcShape(eip1, shape1);
el1.CalcDShape(eip1, dshape1);
@@ -2996,14 +3021,13 @@ void DGElasticityIntegrator::AssembleFaceMatrix(
}
else
{
CalcOrtho(Trans.Face->Jacobian(), nor);
CalcOrtho(Trans.Jacobian(), nor);
}
double w, wLM;
if (ndofs2)
{
Trans.Loc2.Transform(ip, eip2);
Trans.Elem2->SetIntPoint(&eip2);
el2.CalcShape(eip2, shape2);
el2.CalcDShape(eip2, dshape2);
CalcAdjugate(Trans.Elem2->Jacobian(), adjJ);
@@ -3133,9 +3157,9 @@ void TraceJumpIntegrator::AssembleFaceMatrix(
order += trial_face_fe.GetOrder();
if (trial_face_fe.GetMapType() == FiniteElement::VALUE)
{
order += Trans.Face->OrderW();
order += Trans.OrderW();
}
ir = &IntRules.Get(Trans.FaceGeom, order);
ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
@@ -3143,23 +3167,21 @@ void TraceJumpIntegrator::AssembleFaceMatrix(
const IntegrationPoint &ip = ir->IntPoint(p);
IntegrationPoint eip1, eip2;
// Trace finite element shape function
Trans.Face->SetIntPoint(&ip);
Trans.SetIntPoint(&ip);
trial_face_fe.CalcShape(ip, face_shape);
// Side 1 finite element shape function
Trans.Loc1.Transform(ip, eip1);
test_fe1.CalcShape(eip1, shape1);
Trans.Elem1->SetIntPoint(&eip1);
if (ndof2)
{
// Side 2 finite element shape function
Trans.Loc2.Transform(ip, eip2);
test_fe2.CalcShape(eip2, shape2);
Trans.Elem2->SetIntPoint(&eip2);
}
w = ip.weight;
if (trial_face_fe.GetMapType() == FiniteElement::VALUE)
{
w *= Trans.Face->Weight();
w *= Trans.Weight();
}
face_shape *= w;
for (i = 0; i < ndof1; i++)
@@ -3224,7 +3246,7 @@ void NormalTraceJumpIntegrator::AssembleFaceMatrix(
order = test_fe1.GetOrder() - 1;
}
order += trial_face_fe.GetOrder();
ir = &IntRules.Get(Trans.FaceGeom, order);
ir = &IntRules.Get(Trans.GetGeometryType(), order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
+70 -1
View File
@@ -57,6 +57,9 @@ public:
/// Assemble diagonal and add it to Vector @a diag.
virtual void AssembleDiagonalPA(Vector &diag);
/// Assemble diagonal of ADA^T (A is this integrator) and add it to @a diag.
virtual void AssembleDiagonalPA_ADAt(const Vector &D, Vector &diag);
/// Method for partially assembled action.
/** Perform the action of integrator on the input @a x and add the result to
the output @a y. Both @a x and @a y are E-vectors, i.e. they represent
@@ -75,6 +78,22 @@ public:
called. */
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
/// Method defining element assembly.
/** The result of the element assembly is added and stored in the @a emat
Vector. */
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
/** Used with BilinearFormIntegrators that have different spaces. */
// virtual void AssembleEA(const FiniteElementSpace &trial_fes,
// const FiniteElementSpace &test_fes,
// Vector &emat);
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
Vector &ea_data_bdr);
/// Given a particular Finite Element computes the element matrix elmat.
virtual void AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
@@ -234,6 +253,15 @@ public:
bfi->AddMultTransposePA(x, y);
}
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
Vector &ea_data_bdr);
virtual ~TransposeIntegrator() { if (own_bfi) { delete bfi; } }
};
@@ -1885,6 +1913,8 @@ public:
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleDiagonalPA(Vector &diag);
virtual void AddMultPA(const Vector&, Vector&) const;
@@ -1958,6 +1988,8 @@ public:
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AssembleDiagonalPA(Vector &diag);
virtual void AddMultPA(const Vector&, Vector&) const;
@@ -2011,6 +2043,8 @@ public:
virtual void AssemblePA(const FiniteElementSpace&);
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
virtual void AddMultPA(const Vector&, Vector&) const;
static const IntegrationRule &GetRule(const FiniteElement &el,
@@ -2110,11 +2144,25 @@ class VectorFEDivergenceIntegrator : public BilinearFormIntegrator
protected:
Coefficient *Q;
using BilinearFormIntegrator::AssemblePA;
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes);
virtual void AddMultPA(const Vector&, Vector&) const;
virtual void AddMultTransposePA(const Vector&, Vector&) const;
private:
#ifndef MFEM_THREAD_SAFE
Vector divshape, shape;
#endif
// PA extension
Vector pa_data;
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *L2mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
int dim, ne, dofs1D, L2dofs1D, quad1D;
public:
VectorFEDivergenceIntegrator() { Q = NULL; }
VectorFEDivergenceIntegrator(Coefficient &q) { Q = &q; }
@@ -2125,6 +2173,8 @@ public:
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
virtual void AssembleDiagonalPA_ADAt(const Vector &D, Vector &diag);
};
@@ -2308,7 +2358,7 @@ protected:
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
const GeometricFactors *geom; ///< Not owned
int dim, ne, nq, dofs1D, quad1D;
int dim, ne, nq, dofs1D, quad1D, fetype;
public:
VectorFEMassIntegrator() { Init(NULL, NULL, NULL); }
@@ -2387,11 +2437,23 @@ class DivDivIntegrator: public BilinearFormIntegrator
protected:
Coefficient *Q;
using BilinearFormIntegrator::AssemblePA;
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AddMultPA(const Vector &x, Vector &y) const;
virtual void AssembleDiagonalPA(Vector& diag);
private:
#ifndef MFEM_THREAD_SAFE
Vector divshape;
#endif
// PA extension
Vector pa_data;
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
const GeometricFactors *geom; ///< Not owned
int dim, ne, dofs1D, quad1D;
public:
DivDivIntegrator() { Q = NULL; }
DivDivIntegrator(Coefficient &q) : Q(&q) { }
@@ -2544,6 +2606,13 @@ public:
virtual void AddMultPA(const Vector&, Vector&) const;
virtual void AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr);
static const IntegrationRule &GetRule(Geometry::Type geom, int order,
FaceElementTransformations &T);
+258
View File
@@ -0,0 +1,258 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
template<int T_D1D = 0, int T_Q1D = 0>
static void EAConvectionAssemble1D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_Gi[MQ1];
double r_Bj[MQ1];
for (int q = 0; q < Q1D; q++)
{
r_Gi[q] = G(q,MFEM_THREAD_ID(x));
r_Bj[q] = B(q,MFEM_THREAD_ID(y));
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val += r_Bj[k1] * D(k1, e) * r_Gi[k1];
}
A(i1, j1, e) = val;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAConvectionAssemble2D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][2];
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2][0] = D(k1,k2,0,e);
s_D[k1][k2][1] = D(k1,k2,1,e);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val += (r_G[k1][i1] * r_B[k2][i2] * s_D[k1][k2][0]
+ r_B[k1][i1] * r_G[k2][i2] * s_D[k1][k2][1])
* r_B[k1][j1]* r_B[k2][j2];
}
}
A(i1, i2, j1, j2, e) = val;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAConvectionAssemble3D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 3, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
MFEM_FOREACH_THREAD(i3,z,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
for (int j3 = 0; j3 < D1D; ++j3)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
for (int k3 = 0; k3 < Q1D; ++k3)
{
double D0 = D(k1,k2,k3,0,e);
double D1 = D(k1,k2,k3,1,e);
double D2 = D(k1,k2,k3,2,e);
val += (r_G[k1][i1] * r_B[k2][i2] * r_B[k3][i3] * D0
+ r_B[k1][i1] * r_G[k2][i2] * r_B[k3][i3] * D1
+ r_B[k1][i1] * r_B[k2][i2] * r_G[k3][i3] * D2)
* r_B[k1][j1] * r_B[k2][j2] * r_B[k3][j3];
}
}
}
A(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
}
}
}
});
}
void ConvectionIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
const Array<double> &B = maps->B;
const Array<double> &G = maps->G;
if (dim == 1)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAConvectionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EAConvectionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EAConvectionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EAConvectionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EAConvectionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EAConvectionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EAConvectionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EAConvectionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAConvectionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EAConvectionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EAConvectionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EAConvectionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EAConvectionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EAConvectionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EAConvectionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EAConvectionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EAConvectionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
case 0x34: return EAConvectionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
case 0x45: return EAConvectionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
case 0x56: return EAConvectionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
case 0x67: return EAConvectionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
case 0x78: return EAConvectionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
case 0x89: return EAConvectionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
default: return EAConvectionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
+414
View File
@@ -0,0 +1,414 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
static void EADGTraceAssemble1DInt(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext)
{
auto D = Reshape(padata.Read(), 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), 2, NF);
MFEM_FORALL(f, NF,
{
double val_int0, val_int1, val_ext01, val_ext10;
val_int0 = D(0, 0, f);
val_ext10 = D(1, 0, f);
val_ext01 = D(0, 1, f);
val_int1 = D(1, 1, f);
A_int(0, f) += val_int0;
A_int(1, f) += val_int1;
A_ext(0, f) += val_ext01;
A_ext(1, f) += val_ext10;
});
}
static void EADGTraceAssemble1DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr)
{
auto D = Reshape(padata.Read(), 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), NF);
MFEM_FORALL(f, NF,
{
A_bdr(f) += D(0, 0, f);
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble2DInt(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), D1D, D1D, 2, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val_int0 = 0.0;
double val_int1 = 0.0;
double val_ext01 = 0.0;
double val_ext10 = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val_int0 += B(k1,i1) * B(k1,j1) * D(k1, 0, 0, f);
val_ext01 += B(k1,i1) * B(k1,j1) * D(k1, 0, 1, f);
val_ext10 += B(k1,i1) * B(k1,j1) * D(k1, 1, 0, f);
val_int1 += B(k1,i1) * B(k1,j1) * D(k1, 1, 1, f);
}
A_int(i1, j1, 0, f) += val_int0;
A_int(i1, j1, 1, f) += val_int1;
A_ext(i1, j1, 0, f) += val_ext01;
A_ext(i1, j1, 1, f) += val_ext10;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble2DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), D1D, D1D, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val_bdr = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val_bdr += B(k1,i1) * B(k1,j1) * D(k1, 0, 0, f);
}
A_bdr(i1, j1, f) += val_bdr;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble3DInt(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_int,
Vector &eadata_ext,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, 2, NF);
auto A_int = Reshape(eadata_int.ReadWrite(), D1D, D1D, D1D, D1D, 2, NF);
auto A_ext = Reshape(eadata_ext.ReadWrite(), D1D, D1D, D1D, D1D, 2, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][2][2];
for (int i=0; i < 2; i++)
{
for (int j=0; j < 2; j++)
{
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2][i][j] = D(k1,k2,i,j,f);
}
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val_int0 = 0.0;
double val_int1 = 0.0;
double val_ext01 = 0.0;
double val_ext10 = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val_int0 += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][0][0];
val_int1 += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][1][1];
val_ext01+= r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][0][1];
val_ext10+= r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][1][0];
}
}
A_int(i1, i2, j1, j2, 0, f) += val_int0;
A_int(i1, i2, j1, j2, 1, f) += val_int1;
A_ext(i1, i2, j1, j2, 0, f) += val_ext01;
A_ext(i1, i2, j1, j2, 1, f) += val_ext10;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADGTraceAssemble3DBdr(const int NF,
const Array<double> &basis,
const Vector &padata,
Vector &eadata_bdr,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 2, 2, NF);
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), D1D, D1D, D1D, D1D, NF);
MFEM_FORALL_3D(f, NF, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][2][2];
for (int i=0; i < 2; i++)
{
for (int j=0; j < 2; j++)
{
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2][i][j] = D(k1,k2,i,j,f);
}
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val_bdr = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val_bdr += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2][0][0];
}
}
A_bdr(i1, i2, j1, j2, f) += val_bdr;
}
}
}
}
});
}
void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext)
{
SetupPA(fes, FaceType::Interior);
nf = fes.GetNFbyType(FaceType::Interior);
if (nf==0) { return; }
const Array<double> &B = maps->B;
if (dim == 1)
{
return EADGTraceAssemble1DInt(nf,B,pa_data,ea_data_int,ea_data_ext);
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22:
return EADGTraceAssemble2DInt<2,2>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x33:
return EADGTraceAssemble2DInt<3,3>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x44:
return EADGTraceAssemble2DInt<4,4>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x55:
return EADGTraceAssemble2DInt<5,5>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x66:
return EADGTraceAssemble2DInt<6,6>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x77:
return EADGTraceAssemble2DInt<7,7>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x88:
return EADGTraceAssemble2DInt<8,8>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x99:
return EADGTraceAssemble2DInt<9,9>(nf,B,pa_data,ea_data_int,
ea_data_ext);
default:
return EADGTraceAssemble2DInt(nf,B,pa_data,ea_data_int,
ea_data_ext,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23:
return EADGTraceAssemble3DInt<2,3>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x34:
return EADGTraceAssemble3DInt<3,4>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x45:
return EADGTraceAssemble3DInt<4,5>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x56:
return EADGTraceAssemble3DInt<5,6>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x67:
return EADGTraceAssemble3DInt<6,7>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x78:
return EADGTraceAssemble3DInt<7,8>(nf,B,pa_data,ea_data_int,
ea_data_ext);
case 0x89:
return EADGTraceAssemble3DInt<8,9>(nf,B,pa_data,ea_data_int,
ea_data_ext);
default:
return EADGTraceAssemble3DInt(nf,B,pa_data,ea_data_int,
ea_data_ext,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
void DGTraceIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr)
{
SetupPA(fes, FaceType::Boundary);
nf = fes.GetNFbyType(FaceType::Boundary);
if (nf==0) { return; }
const Array<double> &B = maps->B;
if (dim == 1)
{
return EADGTraceAssemble1DBdr(nf,B,pa_data,ea_data_bdr);
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADGTraceAssemble2DBdr<2,2>(nf,B,pa_data,ea_data_bdr);
case 0x33: return EADGTraceAssemble2DBdr<3,3>(nf,B,pa_data,ea_data_bdr);
case 0x44: return EADGTraceAssemble2DBdr<4,4>(nf,B,pa_data,ea_data_bdr);
case 0x55: return EADGTraceAssemble2DBdr<5,5>(nf,B,pa_data,ea_data_bdr);
case 0x66: return EADGTraceAssemble2DBdr<6,6>(nf,B,pa_data,ea_data_bdr);
case 0x77: return EADGTraceAssemble2DBdr<7,7>(nf,B,pa_data,ea_data_bdr);
case 0x88: return EADGTraceAssemble2DBdr<8,8>(nf,B,pa_data,ea_data_bdr);
case 0x99: return EADGTraceAssemble2DBdr<9,9>(nf,B,pa_data,ea_data_bdr);
default:
return EADGTraceAssemble2DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EADGTraceAssemble3DBdr<2,3>(nf,B,pa_data,ea_data_bdr);
case 0x34: return EADGTraceAssemble3DBdr<3,4>(nf,B,pa_data,ea_data_bdr);
case 0x45: return EADGTraceAssemble3DBdr<4,5>(nf,B,pa_data,ea_data_bdr);
case 0x56: return EADGTraceAssemble3DBdr<5,6>(nf,B,pa_data,ea_data_bdr);
case 0x67: return EADGTraceAssemble3DBdr<6,7>(nf,B,pa_data,ea_data_bdr);
case 0x78: return EADGTraceAssemble3DBdr<7,8>(nf,B,pa_data,ea_data_bdr);
case 0x89: return EADGTraceAssemble3DBdr<8,9>(nf,B,pa_data,ea_data_bdr);
default:
return EADGTraceAssemble3DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
+275
View File
@@ -0,0 +1,275 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
template<int T_D1D = 0, int T_Q1D = 0>
static void EADiffusionAssemble1D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_Gi[MQ1];
double r_Gj[MQ1];
for (int q = 0; q < Q1D; q++)
{
r_Gi[q] = G(q,MFEM_THREAD_ID(x));
r_Gj[q] = G(q,MFEM_THREAD_ID(y));
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val += r_Gj[k1] * D(k1, e) * r_Gi[k1];
}
A(i1, j1, e) = val;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADiffusionAssemble2D(const int NE,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, 3, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
double bgi = r_G[k1][i1] * r_B[k2][i2];
double gbi = r_B[k1][i1] * r_G[k2][i2];
double bgj = r_G[k1][j1] * r_B[k2][j2];
double gbj = r_B[k1][j1] * r_G[k2][j2];
double D00 = D(k1,k2,0,e);
double D10 = D(k1,k2,1,e);
double D01 = D10;
double D11 = D(k1,k2,2,e);
val += bgi * D00 * bgj
+ gbi * D01 * bgj
+ bgi * D10 * gbj
+ gbi * D11 * gbj;
}
}
A(i1, i2, j1, j2, e) = val;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EADiffusionAssemble3D(const int NE,
const Array<double> &g,
const Array<double> &b,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, 6, NE);
auto A = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
double r_G[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
r_G[q][d] = G(q,d);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
MFEM_FOREACH_THREAD(i3,z,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
for (int j3 = 0; j3 < D1D; ++j3)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
for (int k3 = 0; k3 < Q1D; ++k3)
{
double bbgi = r_G[k1][i1] * r_B[k2][i2] * r_B[k3][i3];
double bgbi = r_B[k1][i1] * r_G[k2][i2] * r_B[k3][i3];
double gbbi = r_B[k1][i1] * r_B[k2][i2] * r_G[k3][i3];
double bbgj = r_G[k1][j1] * r_B[k2][j2] * r_B[k3][j3];
double bgbj = r_B[k1][j1] * r_G[k2][j2] * r_B[k3][j3];
double gbbj = r_B[k1][j1] * r_B[k2][j2] * r_G[k3][j3];
double D00 = D(k1,k2,k3,0,e);
double D10 = D(k1,k2,k3,1,e);
double D20 = D(k1,k2,k3,2,e);
double D01 = D10;
double D11 = D(k1,k2,k3,3,e);
double D21 = D(k1,k2,k3,4,e);
double D02 = D20;
double D12 = D21;
double D22 = D(k1,k2,k3,5,e);
val += bbgi * D00 * bbgj
+ bgbi * D10 * bbgj
+ gbbi * D20 * bbgj
+ bbgi * D01 * bgbj
+ bgbi * D11 * bgbj
+ gbbi * D21 * bgbj
+ bbgi * D02 * gbbj
+ bgbi * D12 * gbbj
+ gbbi * D22 * gbbj;
}
}
}
A(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
}
}
}
});
}
void DiffusionIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
const Array<double> &B = maps->B;
const Array<double> &G = maps->G;
if (dim == 1)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADiffusionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EADiffusionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EADiffusionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EADiffusionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EADiffusionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EADiffusionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EADiffusionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EADiffusionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EADiffusionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
case 0x33: return EADiffusionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
case 0x44: return EADiffusionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
case 0x55: return EADiffusionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
case 0x66: return EADiffusionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
case 0x77: return EADiffusionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
case 0x88: return EADiffusionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
case 0x99: return EADiffusionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EADiffusionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
case 0x34: return EADiffusionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
case 0x45: return EADiffusionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
case 0x56: return EADiffusionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
case 0x67: return EADiffusionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
case 0x78: return EADiffusionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
case 0x89: return EADiffusionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
default: return EADiffusionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
+77 -240
View File
@@ -24,12 +24,12 @@ constexpr int HCURL_MAX_D1D = 5;
constexpr int HCURL_MAX_Q1D = 6;
// PA H(curl) Mass Assemble 2D kernel
static void PAHcurlSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op)
void PAHcurlSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op)
{
const int NQ = Q1D*Q1D;
auto W = w.Read();
@@ -55,12 +55,12 @@ static void PAHcurlSetup2D(const int Q1D,
}
// PA H(curl) Mass Assemble 3D kernel
static void PAHcurlSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op)
void PAHcurlSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op)
{
const int NQ = Q1D*Q1D*Q1D;
auto W = w.Read();
@@ -106,78 +106,16 @@ static void PAHcurlSetup3D(const int Q1D,
});
}
void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement *fel = fes.GetFE(0);
const VectorTensorFiniteElement *el =
dynamic_cast<const VectorTensorFiniteElement*>(fel);
MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*el, *el,
*mesh->GetElementTransformation(0));
const int dims = el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
Vector coeff(ne * nq);
coeff = 1.0;
if (Q)
{
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
static void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
{
constexpr static int VDIM = 2;
@@ -294,13 +232,13 @@ static void PAHcurlMassApply2D(const int D1D,
}); // end of element loop
}
static void PAHcurlMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag)
void PAHcurlMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag)
{
constexpr static int VDIM = 2;
@@ -348,15 +286,17 @@ static void PAHcurlMassAssembleDiagonal2D(const int D1D,
}); // end of element loop
}
template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
static void PAHcurlMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag)
void PAHcurlMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag)
{
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
@@ -416,28 +356,20 @@ static void PAHcurlMassAssembleDiagonal3D(const int D1D,
}); // end of element loop
}
void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
{
if (dim == 3)
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
else
PAHcurlMassAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
static void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
{
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
@@ -615,20 +547,6 @@ static void PAHcurlMassApply3D(const int D1D,
}); // end of element loop
}
void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
{
PAHcurlMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else
{
PAHcurlMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
}
// PA H(curl) curl-curl assemble 2D kernel
static void PACurlCurlSetup2D(const int Q1D,
const int NE,
@@ -1678,92 +1596,25 @@ void CurlCurlIntegrator::AssembleDiagonalPA(Vector& diag)
}
}
void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
&trial_fes,
const FiniteElementSpace &test_fes)
{
// Assumes tensor-product elements, with a vector test space and H^1 trial space.
Mesh *mesh = trial_fes.GetMesh();
const FiniteElement *trial_fel = trial_fes.GetFE(0);
const FiniteElement *test_fel = test_fes.GetFE(0);
const NodalTensorFiniteElement *trial_el =
dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
MFEM_VERIFY(trial_el != NULL, "Only NodalTensorFiniteElement is supported!");
const VectorTensorFiniteElement *test_el =
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
*mesh->GetElementTransformation(0));
const int dims = trial_el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
ne = trial_fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
Vector coeff(ne * nq);
coeff = 1.0;
if (Q)
{
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
// Use the same setup functions as VectorFEMassIntegrator.
if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
// Apply to x corresponding to DOF's in H^1 (trial), whose gradients are integrated
// against H(curl) test functions corresponding to y.
template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
static void PAHcurlH1Apply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
void PAHcurlH1Apply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
{
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
@@ -1937,16 +1788,16 @@ static void PAHcurlH1Apply3D(const int D1D,
// Apply to x corresponding to DOF's in H^1 (trial), whose gradients are integrated
// against H(curl) test functions corresponding to y.
static void PAHcurlH1Apply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
void PAHcurlH1Apply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
{
constexpr static int VDIM = 2;
@@ -2057,18 +1908,4 @@ static void PAHcurlH1Apply2D(const int D1D,
}); // end of element loop
}
void MixedVectorGradientIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
PAHcurlH1Apply3D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
else if (dim == 2)
PAHcurlH1Apply2D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
} // namespace mfem
File diff suppressed because it is too large Load Diff
+255
View File
@@ -0,0 +1,255 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
#include "gridfunc.hpp"
namespace mfem
{
template<int T_D1D = 0, int T_Q1D = 0>
static void EAMassAssemble1D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, NE);
auto M = Reshape(eadata.Write(), D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_Bi[MQ1];
double r_Bj[MQ1];
for (int q = 0; q < Q1D; q++)
{
r_Bi[q] = B(q,MFEM_THREAD_ID(x));
r_Bj[q] = B(q,MFEM_THREAD_ID(y));
}
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(j1,y,D1D)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
val += r_Bi[k1] * r_Bj[k1] * D(k1, e);
}
M(i1, j1, e) = val;
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAMassAssemble2D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, NE);
auto M = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, 1,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1];
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
s_D[k1][k2] = D(k1,k2,e);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
val += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* s_D[k1][k2];
}
}
M(i1, i2, j1, j2, e) = val;
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void EAMassAssemble3D(const int NE,
const Array<double> &basis,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= MAX_D1D, "");
MFEM_VERIFY(Q1D <= MAX_Q1D, "");
auto B = Reshape(basis.Read(), Q1D, D1D);
auto D = Reshape(padata.Read(), Q1D, Q1D, Q1D, NE);
auto M = Reshape(eadata.Write(), D1D, D1D, D1D, D1D, D1D, D1D, NE);
MFEM_FORALL_3D(e, NE, D1D, D1D, D1D,
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
double r_B[MQ1][MD1];
for (int d = 0; d < D1D; d++)
{
for (int q = 0; q < Q1D; q++)
{
r_B[q][d] = B(q,d);
}
}
MFEM_SHARED double s_D[MQ1][MQ1][MQ1];
MFEM_FOREACH_THREAD(k1,x,Q1D)
{
MFEM_FOREACH_THREAD(k2,y,Q1D)
{
MFEM_FOREACH_THREAD(k3,z,Q1D)
{
s_D[k1][k2][k3] = D(k1,k2,k3,e);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(i1,x,D1D)
{
MFEM_FOREACH_THREAD(i2,y,D1D)
{
MFEM_FOREACH_THREAD(i3,z,D1D)
{
for (int j1 = 0; j1 < D1D; ++j1)
{
for (int j2 = 0; j2 < D1D; ++j2)
{
for (int j3 = 0; j3 < D1D; ++j3)
{
double val = 0.0;
for (int k1 = 0; k1 < Q1D; ++k1)
{
for (int k2 = 0; k2 < Q1D; ++k2)
{
for (int k3 = 0; k3 < Q1D; ++k3)
{
val += r_B[k1][i1] * r_B[k1][j1]
* r_B[k2][i2] * r_B[k2][j2]
* r_B[k3][i3] * r_B[k3][j3]
* s_D[k1][k2][k3];
}
}
}
M(i1, i2, i3, j1, j2, j3, e) = val;
}
}
}
}
}
}
});
}
void MassIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
AssemblePA(fes);
const int ne = fes.GetMesh()->GetNE();
const Array<double> &B = maps->B;
if (dim == 1)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAMassAssemble1D<2,2>(ne,B,pa_data,ea_data);
case 0x33: return EAMassAssemble1D<3,3>(ne,B,pa_data,ea_data);
case 0x44: return EAMassAssemble1D<4,4>(ne,B,pa_data,ea_data);
case 0x55: return EAMassAssemble1D<5,5>(ne,B,pa_data,ea_data);
case 0x66: return EAMassAssemble1D<6,6>(ne,B,pa_data,ea_data);
case 0x77: return EAMassAssemble1D<7,7>(ne,B,pa_data,ea_data);
case 0x88: return EAMassAssemble1D<8,8>(ne,B,pa_data,ea_data);
case 0x99: return EAMassAssemble1D<9,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble1D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 2)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return EAMassAssemble2D<2,2>(ne,B,pa_data,ea_data);
case 0x33: return EAMassAssemble2D<3,3>(ne,B,pa_data,ea_data);
case 0x44: return EAMassAssemble2D<4,4>(ne,B,pa_data,ea_data);
case 0x55: return EAMassAssemble2D<5,5>(ne,B,pa_data,ea_data);
case 0x66: return EAMassAssemble2D<6,6>(ne,B,pa_data,ea_data);
case 0x77: return EAMassAssemble2D<7,7>(ne,B,pa_data,ea_data);
case 0x88: return EAMassAssemble2D<8,8>(ne,B,pa_data,ea_data);
case 0x99: return EAMassAssemble2D<9,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble2D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
else if (dim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x23: return EAMassAssemble3D<2,3>(ne,B,pa_data,ea_data);
case 0x34: return EAMassAssemble3D<3,4>(ne,B,pa_data,ea_data);
case 0x45: return EAMassAssemble3D<4,5>(ne,B,pa_data,ea_data);
case 0x56: return EAMassAssemble3D<5,6>(ne,B,pa_data,ea_data);
case 0x67: return EAMassAssemble3D<6,7>(ne,B,pa_data,ea_data);
case 0x78: return EAMassAssemble3D<7,8>(ne,B,pa_data,ea_data);
case 0x89: return EAMassAssemble3D<8,9>(ne,B,pa_data,ea_data);
default: return EAMassAssemble3D(ne,B,pa_data,ea_data,dofs1D,quad1D);
}
}
MFEM_ABORT("Unknown kernel.");
}
}
+103
View File
@@ -0,0 +1,103 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../general/forall.hpp"
#include "bilininteg.hpp"
namespace mfem
{
void TransposeIntegrator::AssembleEA(const FiniteElementSpace &fes,
Vector &ea_data)
{
Vector ea_data_tmp(ea_data.Size());
ea_data_tmp = 0.0;
bfi->AssembleEA(fes, ea_data_tmp);
const int ne = fes.GetNE();
if (ne == 0) { return; }
const int dofs = fes.GetFE(0)->GetDof();
auto A = Reshape(ea_data_tmp.Write(), dofs, dofs, ne);
auto AT = Reshape(ea_data.Write(), dofs, dofs, ne);
MFEM_FORALL(e, ne,
{
for (int i = 0; i < dofs; i++)
{
for (int j = 0; j < dofs; j++)
{
const double a = A(i, j, e);
AT(j, i, e) += a;
}
}
});
}
void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext)
{
const int nf = fes.GetNFbyType(FaceType::Interior);
if (nf == 0) { return; }
Vector ea_data_int_tmp(ea_data_int.Size());
Vector ea_data_ext_tmp(ea_data_ext.Size());
ea_data_int_tmp = 0.0;
ea_data_ext_tmp = 0.0;
bfi->AssembleEAInteriorFaces(fes, ea_data_int_tmp, ea_data_ext_tmp);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_int = Reshape(ea_data_int_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
auto AT_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
MFEM_FORALL(f, nf,
{
for (int i = 0; i < faceDofs; i++)
{
for (int j = 0; j < faceDofs; j++)
{
const double a_int0 = A_int(i, j, 0, f);
const double a_int1 = A_int(i, j, 1, f);
const double a_ext0 = A_ext(i, j, 0, f);
const double a_ext1 = A_ext(i, j, 1, f);
AT_int(j, i, 0, f) += a_int0;
AT_int(j, i, 1, f) += a_int1;
AT_ext(j, i, 0, f) += a_ext1;
AT_ext(j, i, 1, f) += a_ext0;
}
}
});
}
void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
Vector &ea_data_bdr)
{
const int nf = fes.GetNFbyType(FaceType::Boundary);
if (nf == 0) { return; }
Vector ea_data_bdr_tmp(ea_data_bdr.Size());
ea_data_bdr_tmp = 0.0;
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr_tmp);
const int faceDofs = fes.GetTraceElement(0,
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
MFEM_FORALL(f, nf,
{
for (int i = 0; i < faceDofs; i++)
{
for (int j = 0; j < faceDofs; j++)
{
const double a_bdr = A_bdr(i, j, f);
AT_bdr(j, i, f) += a_bdr;
}
}
});
}
}
+379
View File
@@ -0,0 +1,379 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "bilininteg.hpp"
namespace mfem
{
void PAHcurlSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHcurlSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHcurlMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHcurlMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHdivSetup2D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHdivSetup3D(const int Q1D,
const int NE,
const Array<double> &w,
const Vector &j,
Vector &_coeff,
Vector &op);
void PAHcurlH1Apply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHcurlH1Apply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bc,
const Array<double> &_Gc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHdivMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHdivMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
Vector &_diag);
void PAHdivMassApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void PAHdivMassApply3D(const int D1D,
const int Q1D,
const int NE,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y);
void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement *fel = fes.GetFE(0);
const VectorTensorFiniteElement *el =
dynamic_cast<const VectorTensorFiniteElement*>(fel);
MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*el, *el,
*mesh->GetElementTransformation(0));
const int dims = el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
ne = fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
Vector coeff(ne * nq);
coeff = 1.0;
if (Q)
{
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
fetype = el->GetDerivType();
if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 3)
{
PAHdivSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 2)
{
PAHdivSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
{
if (dim == 3)
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassAssembleDiagonal3D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
else
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
}
void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
else
{
if (fetype == mfem::FiniteElement::CURL)
{
PAHcurlMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if (fetype == mfem::FiniteElement::DIV)
{
PAHdivMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
}
void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
&trial_fes,
const FiniteElementSpace &test_fes)
{
// Assumes tensor-product elements, with a vector test space and H^1 trial space.
Mesh *mesh = trial_fes.GetMesh();
const FiniteElement *trial_fel = trial_fes.GetFE(0);
const FiniteElement *test_fel = test_fes.GetFE(0);
const NodalTensorFiniteElement *trial_el =
dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
MFEM_VERIFY(trial_el != NULL, "Only NodalTensorFiniteElement is supported!");
const VectorTensorFiniteElement *test_el =
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
*mesh->GetElementTransformation(0));
const int dims = trial_el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
const int nq = ir->GetNPoints();
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
ne = trial_fes.GetNE();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
Vector coeff(ne * nq);
coeff = 1.0;
if (Q)
{
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
coeff[p + (e * nq)] = Q->Eval(*tr, ir->IntPoint(p));
}
}
}
// Use the same setup functions as VectorFEMassIntegrator.
if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (test_el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
{
PAHcurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
void MixedVectorGradientIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
PAHcurlH1Apply3D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
else if (dim == 2)
PAHcurlH1Apply2D(dofs1D, quad1D, ne, mapsC->B, mapsC->G,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
else
{
MFEM_ABORT("Unsupported dimension!");
}
}
} // namespace mfem
+66 -26
View File
@@ -49,7 +49,7 @@ double FunctionCoefficient::Eval(ElementTransformation & T,
double GridFunctionCoefficient::Eval (ElementTransformation &T,
const IntegrationPoint &ip)
{
return GridF -> GetValue (T.ElementNo, ip, Component);
return GridF -> GetValue (T, ip, Component);
}
double TransformedCoefficient::Eval(ElementTransformation &T,
@@ -160,13 +160,13 @@ void VectorArrayCoefficient::Eval(Vector &V, ElementTransformation &T,
}
VectorGridFunctionCoefficient::VectorGridFunctionCoefficient (
GridFunction *gf)
const GridFunction *gf)
: VectorCoefficient ((gf) ? gf -> VectorDim() : 0)
{
GridFunc = gf;
}
void VectorGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
void VectorGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
{
GridFunc = gf; vdim = (gf) ? gf -> VectorDim() : 0;
}
@@ -174,24 +174,7 @@ void VectorGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
void VectorGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
Mesh *mesh = GridFunc->FESpace()->GetMesh();
if (mesh->Dimension() == T.GetDimension())
{
GridFunc->GetVectorValue(T.ElementNo, ip, V);
}
else // Assuming T is a boundary element transformation
{
int el_id, el_info;
mesh->GetBdrElementAdjacentElement(T.ElementNo, el_id, el_info);
IntegrationPointTransformation loc_T;
mesh->GetLocalFaceTransformation(mesh->GetBdrElementType(T.ElementNo),
mesh->GetElementType(el_id),
loc_T.Transf,
el_info);
IntegrationPoint eip;
loc_T.Transform(ip, eip);
GridFunc->GetVectorValue(el_id, eip, V);
}
GridFunc->GetVectorValue(T, ip, V);
}
void VectorGridFunctionCoefficient::Eval(
@@ -201,14 +184,14 @@ void VectorGridFunctionCoefficient::Eval(
}
GradientGridFunctionCoefficient::GradientGridFunctionCoefficient (
GridFunction *gf)
const GridFunction *gf)
: VectorCoefficient((gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0)
{
GridFunc = gf;
}
void GradientGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
void GradientGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
{
GridFunc = gf; vdim = (gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0;
@@ -227,14 +210,14 @@ void GradientGridFunctionCoefficient::Eval(
}
CurlGridFunctionCoefficient::CurlGridFunctionCoefficient (
GridFunction *gf)
const GridFunction *gf)
: VectorCoefficient ((gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0)
{
GridFunc = gf;
}
void CurlGridFunctionCoefficient::SetGridFunction(GridFunction *gf)
void CurlGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
{
GridFunc = gf; vdim = (gf) ?
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0;
@@ -247,7 +230,7 @@ void CurlGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
}
DivergenceGridFunctionCoefficient::DivergenceGridFunctionCoefficient (
GridFunction *gf) : Coefficient()
const GridFunction *gf) : Coefficient()
{
GridFunc = gf;
}
@@ -775,4 +758,61 @@ double ComputeGlobalLpNorm(double p, VectorCoefficient &coeff, ParMesh &pmesh,
}
#endif
VectorQuadratureFunctionCoefficient::VectorQuadratureFunctionCoefficient(
QuadratureFunction &qf)
: VectorCoefficient(qf.GetVDim()), QuadF(qf), index(0) { }
void VectorQuadratureFunctionCoefficient::SetComponent(int _index, int _length)
{
MFEM_VERIFY(_index >= 0, "Index must be >= 0");
MFEM_VERIFY(_index < QuadF.GetVDim(),
"Index must be < QuadratureFunction length");
index = _index;
MFEM_VERIFY(_length > 0, "Length must be > 0");
MFEM_VERIFY(_length <= QuadF.GetVDim() - index,
"Length must be <= (QuadratureFunction length - index)");
vdim = _length;
}
void VectorQuadratureFunctionCoefficient::Eval(Vector &V,
ElementTransformation &T,
const IntegrationPoint &ip)
{
QuadF.HostRead();
if (index == 0 && vdim == QuadF.GetVDim())
{
QuadF.GetElementValues(T.ElementNo, ip.index, V);
}
else
{
Vector temp;
QuadF.GetElementValues(T.ElementNo, ip.index, temp);
V.SetSize(vdim);
for (int i = 0; i < vdim; i++)
{
V(i) = temp(index + i);
}
}
return;
}
QuadratureFunctionCoefficient::QuadratureFunctionCoefficient(
QuadratureFunction &qf) : QuadF(qf)
{
MFEM_VERIFY(qf.GetVDim() == 1, "QuadratureFunction's vdim must be 1");
}
double QuadratureFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
QuadF.HostRead();
Vector temp(1);
QuadF.GetElementValues(T.ElementNo, ip.index, temp);
return temp[0];
}
}
+68 -20
View File
@@ -164,18 +164,18 @@ class GridFunction;
class GridFunctionCoefficient : public Coefficient
{
private:
GridFunction *GridF;
const GridFunction *GridF;
int Component;
public:
GridFunctionCoefficient() : GridF(NULL), Component(1) { }
/** Construct GridFunctionCoefficient from a given GridFunction, and
optionally specify a component to use if it is a vector GridFunction. */
GridFunctionCoefficient (GridFunction *gf, int comp = 1)
GridFunctionCoefficient (const GridFunction *gf, int comp = 1)
{ GridF = gf; Component = comp; }
void SetGridFunction(GridFunction *gf) { GridF = gf; }
GridFunction * GetGridFunction() const { return GridF; }
void SetGridFunction(const GridFunction *gf) { GridF = gf; }
const GridFunction * GetGridFunction() const { return GridF; }
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
@@ -400,14 +400,14 @@ public:
class VectorGridFunctionCoefficient : public VectorCoefficient
{
protected:
GridFunction *GridFunc;
const GridFunction *GridFunc;
public:
VectorGridFunctionCoefficient() : VectorCoefficient(0), GridFunc(NULL) { }
VectorGridFunctionCoefficient(GridFunction *gf);
VectorGridFunctionCoefficient(const GridFunction *gf);
void SetGridFunction(GridFunction *gf);
GridFunction * GetGridFunction() const { return GridFunc; }
void SetGridFunction(const GridFunction *gf);
const GridFunction * GetGridFunction() const { return GridFunc; }
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
@@ -422,13 +422,13 @@ public:
class GradientGridFunctionCoefficient : public VectorCoefficient
{
protected:
GridFunction *GridFunc;
const GridFunction *GridFunc;
public:
GradientGridFunctionCoefficient(GridFunction *gf);
GradientGridFunctionCoefficient(const GridFunction *gf);
void SetGridFunction(GridFunction *gf);
GridFunction * GetGridFunction() const { return GridFunc; }
void SetGridFunction(const GridFunction *gf);
const GridFunction * GetGridFunction() const { return GridFunc; }
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
@@ -443,13 +443,13 @@ public:
class CurlGridFunctionCoefficient : public VectorCoefficient
{
protected:
GridFunction *GridFunc;
const GridFunction *GridFunc;
public:
CurlGridFunctionCoefficient(GridFunction *gf);
CurlGridFunctionCoefficient(const GridFunction *gf);
void SetGridFunction(GridFunction *gf);
GridFunction * GetGridFunction() const { return GridFunc; }
void SetGridFunction(const GridFunction *gf);
const GridFunction * GetGridFunction() const { return GridFunc; }
using VectorCoefficient::Eval;
virtual void Eval(Vector &V, ElementTransformation &T,
@@ -462,13 +462,13 @@ public:
class DivergenceGridFunctionCoefficient : public Coefficient
{
protected:
GridFunction *GridFunc;
const GridFunction *GridFunc;
public:
DivergenceGridFunctionCoefficient(GridFunction *gf);
DivergenceGridFunctionCoefficient(const GridFunction *gf);
void SetGridFunction(GridFunction *gf) { GridFunc = gf; }
GridFunction * GetGridFunction() const { return GridFunc; }
void SetGridFunction(const GridFunction *gf) { GridFunc = gf; }
const GridFunction * GetGridFunction() const { return GridFunc; }
virtual double Eval(ElementTransformation &T,
const IntegrationPoint &ip);
@@ -946,6 +946,54 @@ public:
const IntegrationPoint &ip);
};
class QuadratureFunction;
/** @brief Vector quadrature function coefficient which requires that the
quadrature rules used for this vector coefficient be the same as those that
live within the supplied QuadratureFunction. */
class VectorQuadratureFunctionCoefficient : public VectorCoefficient
{
private:
const QuadratureFunction &QuadF; //do not own
int index;
public:
/// Constructor with a quadrature function as input
VectorQuadratureFunctionCoefficient(QuadratureFunction &qf);
/** Set the starting index within the QuadFunc that'll be used to
project outwards as well as the corresponding length. The projected length
should have the bounds of 1 <= length <= (length QuadFunc - index). */
void SetComponent(int _index, int _length);
const QuadratureFunction& GetQuadFunction() const { return QuadF; }
using VectorCoefficient::Eval;
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
virtual ~VectorQuadratureFunctionCoefficient() { }
};
/** @brief Quadrature function coefficient which requires that the quadrature
rules used for this coefficient be the same as those that live within the
supplied QuadratureFunction. */
class QuadratureFunctionCoefficient : public Coefficient
{
private:
const QuadratureFunction &QuadF;
public:
/// Constructor with a quadrature function as input
QuadratureFunctionCoefficient(QuadratureFunction &qf);
const QuadratureFunction& GetQuadFunction() const { return QuadF; }
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
virtual ~QuadratureFunctionCoefficient() { }
};
/** Compute the Lp norm of a function f.
\f$ \| f \|_{Lp} = ( \int_\Omega | f |^p d\Omega)^{1/p} \f$ */
double ComputeLpNorm(double p, Coefficient &coeff, Mesh &mesh,
+1 -7
View File
@@ -739,12 +739,6 @@ ParaViewDataCollection::ParaViewDataCollection(const std::string&
#endif
}
void ParaViewDataCollection::RegisterField(const std::string& field_name,
mfem::GridFunction *gf)
{
DataCollection::RegisterField(field_name,gf);
}
void ParaViewDataCollection::SetLevelsOfDetail(int levels_of_detail_)
{
levels_of_detail = levels_of_detail_;
@@ -815,7 +809,7 @@ void ParaViewDataCollection::Save()
// the directory is created
// create pvd file if needed
if (!pvd_stream.is_open())
if (myid == 0 && !pvd_stream.is_open())
{
std::string dpath=GenerateCollectionPath();
std::string pvdname=dpath+"/"+GeneratePVDFileName();
-4
View File
@@ -501,10 +501,6 @@ public:
ParaViewDataCollection(const std::string& collection_name,
mfem::Mesh *mesh_ = NULL);
/// Add a grid function to the collection
virtual void RegisterField(const std::string& field_name,
mfem::GridFunction *gf) override;
/// Set refinement levels - every element is uniformly split based on
/// levels_of_detail_
void SetLevelsOfDetail(int levels_of_detail_);
+73
View File
@@ -19,6 +19,7 @@ namespace mfem
ElementTransformation::ElementTransformation()
: IntPoint(static_cast<IntegrationPoint *>(NULL)),
EvalState(0),
geom(Geometry::INVALID),
Attribute(-1),
ElementNo(-1)
{ }
@@ -551,4 +552,76 @@ void IntegrationPointTransformation::Transform (const IntegrationRule &ir1,
}
}
void FaceElementTransformations::SetIntPoint(const IntegrationPoint *ip)
{
IsoparametricTransformation::SetIntPoint(ip);
if (Elem1)
{
Loc1.Transform(*ip, eip1);
Elem1->SetIntPoint(&eip1);
}
if (Elem2)
{
Loc2.Transform(*ip, eip2);
Elem2->SetIntPoint(&eip2);
}
}
ElementTransformation &
FaceElementTransformations::GetElement1Transformation()
{
MFEM_VERIFY(mask & 1 && Elem1 != NULL, "The ElementTransformation "
"for the element has not been configured for side 1.");
return *Elem1;
}
ElementTransformation &
FaceElementTransformations::GetElement2Transformation()
{
MFEM_VERIFY(mask & 2 && Elem2 != NULL, "The ElementTransformation "
"for the element has not been configured for side 2.");
return *Elem2;
}
IntegrationPointTransformation &
FaceElementTransformations::GetIntPoint1Transformation()
{
MFEM_VERIFY(mask & 4, "The IntegrationPointTransformation "
"for the element has not been configured for side 1.");
return Loc1;
}
IntegrationPointTransformation &
FaceElementTransformations::GetIntPoint2Transformation()
{
MFEM_VERIFY(mask & 8, "The IntegrationPointTransformation "
"for the element has not been configured for side 2.");
return Loc2;
}
void FaceElementTransformations::Transform(const IntegrationPoint &ip,
Vector &trans)
{
MFEM_VERIFY(mask & 16, "The ElementTransformation "
"for the face has not been configured.");
IsoparametricTransformation::Transform(ip, trans);
}
void FaceElementTransformations::Transform(const IntegrationRule &ir,
DenseMatrix &tr)
{
MFEM_VERIFY(mask & 16, "The ElementTransformation "
"for the face has not been configured.");
IsoparametricTransformation::Transform(ir, tr);
}
void FaceElementTransformations::Transform(const DenseMatrix &matrix,
DenseMatrix &result)
{
MFEM_VERIFY(mask & 16, "The ElementTransformation "
"for the face has not been configured.");
IsoparametricTransformation::Transform(matrix, result);
}
}
+72 -4
View File
@@ -48,7 +48,29 @@ protected:
const DenseMatrix &EvalInverseJ();
public:
int Attribute, ElementNo;
/** This enumeration declares the values stored in
ElementTransformation::ElementType and indicates which group of objects
the index stored in ElementTransformation::ElementNo refers:
| ElementType | Range of ElementNo
+-------------+-------------------------
| ELEMENT | [0, Mesh::GetNE() )
| BDR_ELEMENT | [0, Mesh::GetNBE() )
| EDGE | [0, Mesh::GetNEdges() )
| FACE | [0, Mesh::GetNFaces() )
| BDR_FACE | [0, Mesh::GetNBE() )
*/
enum
{
ELEMENT = 1,
BDR_ELEMENT = 2,
EDGE = 3,
FACE = 4,
BDR_FACE = 5
};
int Attribute, ElementNo, ElementType;
ElementTransformation();
@@ -356,12 +378,58 @@ public:
void Transform (const IntegrationRule &, IntegrationRule &);
};
class FaceElementTransformations
class FaceElementTransformations : public IsoparametricTransformation
{
private:
int mask;
IntegrationPoint eip1, eip2;
public:
int Elem1No, Elem2No, FaceGeom;
ElementTransformation *Elem1, *Elem2, *Face;
int Elem1No, Elem2No;
Geometry::Type &FaceGeom; ///< @deprecated Use GetGeometryType instead
ElementTransformation *Elem1, *Elem2;
ElementTransformation *Face; ///< @deprecated No longer necessary
IntegrationPointTransformation Loc1, Loc2;
FaceElementTransformations() : FaceGeom(geom), Face(this) {}
/** @brief Method to set the geometry type of the face.
@note This method is designed to be used when
[Par]Mesh::GetFaceTransformation will not be called i.e. when the face
transformation will not be needed but the neighboring element
transformations will be. Using this method to override the GeometryType
should only be done with great care.
*/
void SetGeometryType(Geometry::Type g) { geom = g; }
/// Set the mask indicating which portions of the object have been setup
/** The argument @a m is a bitmask used in
Mesh::GetFaceElementTransformations to indicate which portions of the
FaceElement Transformations object have been configured.
mask & 1: Elem1 is configured
mask & 2: Elem2 is configured
mask & 4: Loc1 is configured
mask & 8: Loc2 is configured
mask & 16: The Face transformation itself is configured
*/
void SetConfigurationMask(int m) { mask = m; }
int GetConfigurationMask() const { return mask; }
/** @brief Set the integration point in the Face and the two neighboring
elements, if present. */
void SetIntPoint(const IntegrationPoint *ip);
virtual void Transform(const IntegrationPoint &, Vector &);
virtual void Transform(const IntegrationRule &, DenseMatrix &);
virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result);
ElementTransformation & GetElement1Transformation();
ElementTransformation & GetElement2Transformation();
IntegrationPointTransformation & GetIntPoint1Transformation();
IntegrationPointTransformation & GetIntPoint2Transformation();
};
/* Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x))
+17
View File
@@ -50,4 +50,21 @@ void L2ZienkiewiczZhuEstimator::ComputeEstimates()
#endif // MFEM_USE_MPI
void LpErrorEstimator::ComputeEstimates()
{
MFEM_VERIFY(coef != NULL || vcoef != NULL,
"LpErrorEstimator has no coefficient! Call SetCoef first.");
error_estimates.SetSize(sol->FESpace()->GetMesh()->GetNE());
if (coef)
{
sol->ComputeElementLpErrors(local_norm_p, *coef, error_estimates);
}
else
{
sol->ComputeElementLpErrors(local_norm_p, *vcoef, error_estimates);
}
current_sequence = sol->FESpace()->GetMesh()->GetSequence();
}
} // namespace mfem
+82
View File
@@ -304,6 +304,88 @@ public:
#endif // MFEM_USE_MPI
/** @brief The LpErrorEstimator class compares the solution to a known
coefficient.
This class can be used, for example, to adapt a mesh to a non-trivial
initial condition in a time-dependent simulation. It can also be used to
force refinement in the neighborhood of small features before switching to a
more traditional error estimator.
The LpErrorEstimator supports either scalar or vector coefficients and works
both in serial and in parallel.
*/
class LpErrorEstimator : public ErrorEstimator
{
protected:
long current_sequence;
int local_norm_p;
Vector error_estimates;
Coefficient * coef;
VectorCoefficient * vcoef;
GridFunction * sol;
/// Check if the mesh of the solution was modified.
bool MeshIsModified()
{
long mesh_sequence = sol->FESpace()->GetMesh()->GetSequence();
MFEM_ASSERT(mesh_sequence >= current_sequence, "");
return (mesh_sequence > current_sequence);
}
/// Compute the element error estimates.
void ComputeEstimates();
public:
/** @brief Construct a new LpErrorEstimator object for a scalar field.
@param p Integer which selects which Lp norm to use.
@param sol The GridFunction representation of the scalar field.
Note: the coefficient must be set before use with the SetCoef method.
*/
LpErrorEstimator(int p, GridFunction &sol)
: current_sequence(-1), local_norm_p(p),
error_estimates(0), coef(NULL), vcoef(NULL), sol(&sol) { }
/** @brief Construct a new LpErrorEstimator object for a scalar field.
@param p Integer which selects which Lp norm to use.
@param coef The scalar Coefficient to compare to the solution.
@param sol The GridFunction representation of the scalar field.
*/
LpErrorEstimator(int p, Coefficient &coef, GridFunction &sol)
: current_sequence(-1), local_norm_p(p),
error_estimates(0), coef(&coef), vcoef(NULL), sol(&sol) { }
/** @brief Construct a new LpErrorEstimator object for a vector field.
@param p Integer which selects which Lp norm to use.
@param coef The vector VectorCoefficient to compare to the solution.
@param sol The GridFunction representation of the vector field.
*/
LpErrorEstimator(int p, VectorCoefficient &coef, GridFunction &sol)
: current_sequence(-1), local_norm_p(p),
error_estimates(0), coef(NULL), vcoef(&coef), sol(&sol) { }
/** @brief Set the exponent, p, of the Lp norm used for computing the local
element errors. */
void SetLocalErrorNormP(int p) { local_norm_p = p; }
void SetCoef(Coefficient &A) { coef = &A; }
void SetCoef(VectorCoefficient &A) { vcoef = &A; }
/// Reset the error estimator.
virtual void Reset() { current_sequence = -1; }
/// Get a Vector with all element errors.
virtual const Vector &GetLocalErrors()
{
if (MeshIsModified()) { ComputeEstimates(); }
return error_estimates;
}
/// Destructor
virtual ~LpErrorEstimator() {}
};
} // namespace mfem
#endif // MFEM_ERROR_ESTIMATORS
+20 -11
View File
@@ -10287,12 +10287,12 @@ const double RT_QuadrilateralElement::nk[8] =
RT_QuadrilateralElement::RT_QuadrilateralElement(const int p,
const int cb_type,
const int ob_type)
: VectorFiniteElement(2, Geometry::SQUARE, 2*(p + 1)*(p + 2), p + 1,
H_DIV, FunctionSpace::Qk),
cbasis1d(poly1d.GetBasis(p + 1, VerifyClosed(cb_type))),
obasis1d(poly1d.GetBasis(p, VerifyOpen(ob_type))),
dof_map(Dof), dof2nk(Dof)
: VectorTensorFiniteElement(2, 2*(p + 1)*(p + 2), p + 1, cb_type, ob_type,
H_DIV, DofMapType::L2_DOF_MAP),
dof2nk(Dof)
{
dof_map.SetSize(Dof);
const double *cp = poly1d.ClosedPoints(p + 1, cb_type);
const double *op = poly1d.OpenPoints(p, ob_type);
const int dof2 = Dof/2;
@@ -10498,12 +10498,12 @@ const double RT_HexahedronElement::nk[18] =
RT_HexahedronElement::RT_HexahedronElement(const int p,
const int cb_type,
const int ob_type)
: VectorFiniteElement(3, Geometry::CUBE, 3*(p + 1)*(p + 1)*(p + 2), p + 1,
H_DIV, FunctionSpace::Qk),
cbasis1d(poly1d.GetBasis(p + 1, VerifyClosed(cb_type))),
obasis1d(poly1d.GetBasis(p, VerifyOpen(ob_type))),
dof_map(Dof), dof2nk(Dof)
: VectorTensorFiniteElement(3, 3*(p + 1)*(p + 1)*(p + 2), p + 1, cb_type,
ob_type, H_DIV, DofMapType::L2_DOF_MAP),
dof2nk(Dof)
{
dof_map.SetSize(Dof);
const double *cp = poly1d.ClosedPoints(p + 1, cb_type);
const double *op = poly1d.OpenPoints(p, ob_type);
const int dof3 = Dof/3;
@@ -11537,7 +11537,8 @@ const DofToQuad &VectorTensorFiniteElement::GetTensorDofToQuad(
{
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
for (int i = 0; i < closed ? dof2quad_array.Size() : dof2quad_array_open.Size();
for (int i = 0;
i < (closed ? dof2quad_array.Size() : dof2quad_array_open.Size());
i++)
{
const DofToQuad &d2q = closed ? *dof2quad_array[i] : *dof2quad_array_open[i];
@@ -11590,6 +11591,14 @@ const DofToQuad &VectorTensorFiniteElement::GetTensorDofToQuad(
return *d2q;
}
VectorTensorFiniteElement::~VectorTensorFiniteElement()
{
for (int i = 0; i < dof2quad_array_open.Size(); i++)
{
delete dof2quad_array_open[i];
}
}
const double ND_QuadrilateralElement::tk[8] =
{ 1.,0., 0.,1., -1.,0., 0.,-1. };
+6 -6
View File
@@ -1930,6 +1930,8 @@ public:
const DofToQuad &GetTensorDofToQuad(const IntegrationRule &ir,
DofToQuad::Mode mode,
const bool closed) const;
~VectorTensorFiniteElement();
};
class H1_SegmentElement : public NodalTensorFiniteElement
@@ -2430,17 +2432,16 @@ public:
};
class RT_QuadrilateralElement : public VectorFiniteElement
class RT_QuadrilateralElement : public VectorTensorFiniteElement
{
private:
static const double nk[8];
Poly_1D::Basis &cbasis1d, &obasis1d;
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_cx, shape_ox, shape_cy, shape_oy;
mutable Vector dshape_cx, dshape_cy;
#endif
Array<int> dof_map, dof2nk;
Array<int> dof2nk;
public:
RT_QuadrilateralElement(const int p,
@@ -2486,16 +2487,15 @@ public:
};
class RT_HexahedronElement : public VectorFiniteElement
class RT_HexahedronElement : public VectorTensorFiniteElement
{
static const double nk[18];
Poly_1D::Basis &cbasis1d, &obasis1d;
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_cx, shape_ox, shape_cy, shape_oy, shape_cz, shape_oz;
mutable Vector dshape_cx, dshape_cy, dshape_cz;
#endif
Array<int> dof_map, dof2nk;
Array<int> dof2nk;
public:
RT_HexahedronElement(const int p,
+55
View File
@@ -40,6 +40,15 @@ protected:
const int face_info);
public:
/** @brief Enumeration for ContType: defines the continuity of the field
across element interfaces.
*/
enum { CONTINUOUS, ///< Field is continuous across element interfaces
TANGENTIAL, ///< Tangential components of vector field
NORMAL, ///< Normal component of vector field
DISCONTINUOUS ///< Field is discontinuous across element interfaces
};
virtual const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const = 0;
@@ -52,6 +61,8 @@ public:
virtual const char * Name() const { return "Undefined"; }
virtual int GetContType() const = 0;
int HasFaceDofs(Geometry::Type GeomType) const;
virtual const FiniteElement *TraceFiniteElementForGeometry(
@@ -102,6 +113,7 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char *Name() const { return h1_name; }
virtual int GetContType() const { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const;
int GetBasisType() const { return b_type; }
@@ -174,6 +186,8 @@ public:
int Or) const;
virtual const char *Name() const { return d_name; }
virtual int GetContType() const { return DISCONTINUOUS; }
virtual const FiniteElement *TraceFiniteElementForGeometry(
Geometry::Type GeomType) const
{
@@ -221,6 +235,7 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char *Name() const { return rt_name; }
virtual int GetContType() const { return NORMAL; }
FiniteElementCollection *GetTraceCollection() const;
virtual ~RT_FECollection();
@@ -270,6 +285,7 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char *Name() const { return nd_name; }
virtual int GetContType() const { return TANGENTIAL; }
FiniteElementCollection *GetTraceCollection() const;
virtual ~ND_FECollection();
@@ -334,6 +350,8 @@ public:
virtual const char *Name() const { return name; }
virtual int GetContType() const { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const;
virtual ~NURBSFECollection();
@@ -363,6 +381,8 @@ public:
int Or) const;
virtual const char * Name() const { return "Linear"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Piecewise-(bi)quadratic continuous finite elements.
@@ -389,6 +409,8 @@ public:
int Or) const;
virtual const char * Name() const { return "Quadratic"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Version of QuadraticFECollection with positive basis functions.
@@ -410,6 +432,8 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticPos"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Piecewise-(bi)cubic continuous finite elements.
@@ -437,6 +461,8 @@ public:
int Or) const;
virtual const char * Name() const { return "Cubic"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/// Crouzeix-Raviart nonconforming elements in 2D.
@@ -458,6 +484,8 @@ public:
int Or) const;
virtual const char * Name() const { return "CrouzeixRaviart"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Piecewise-linear nonconforming finite elements in 3D.
@@ -481,6 +509,8 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearNonConf3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
@@ -504,6 +534,8 @@ public:
int Or) const;
virtual const char * Name() const { return "RT0_2D"; }
virtual int GetContType() const { return NORMAL; }
};
/** Second order Raviart-Thomas finite elements in 2D. This class is kept only
@@ -526,6 +558,8 @@ public:
int Or) const;
virtual const char * Name() const { return "RT1_2D"; }
virtual int GetContType() const { return NORMAL; }
};
/** Third order Raviart-Thomas finite elements in 2D. This class is kept only
@@ -548,6 +582,8 @@ public:
int Or) const;
virtual const char * Name() const { return "RT2_2D"; }
virtual int GetContType() const { return NORMAL; }
};
/** Piecewise-constant discontinuous finite elements in 2D. This class is kept
@@ -569,6 +605,8 @@ public:
int Or) const;
virtual const char * Name() const { return "Const2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** Piecewise-linear discontinuous finite elements in 2D. This class is kept
@@ -591,6 +629,8 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Version of LinearDiscont2DFECollection with dofs in the Gaussian points.
@@ -613,6 +653,8 @@ public:
int Or) const;
virtual const char * Name() const { return "GaussLinearDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Linear (P1) finite elements on quadrilaterals.
@@ -628,6 +670,7 @@ public:
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const;
virtual const char * Name() const { return "P1OnQuad"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** Piecewise-quadratic discontinuous finite elements in 2D. This class is kept
@@ -650,6 +693,7 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Version of QuadraticDiscont2DFECollection with positive basis functions.
@@ -667,6 +711,7 @@ public:
int Or) const
{ return NULL; }
virtual const char * Name() const { return "QuadraticPosDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Version of QuadraticDiscont2DFECollection with dofs in the Gaussian points.
@@ -689,6 +734,7 @@ public:
int Or) const;
virtual const char * Name() const { return "GaussQuadraticDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** Piecewise-cubic discontinuous finite elements in 2D. This class is kept
@@ -711,6 +757,7 @@ public:
int Or) const;
virtual const char * Name() const { return "CubicDiscont2D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** Piecewise-constant discontinuous finite elements in 3D. This class is kept
@@ -734,6 +781,7 @@ public:
int Or) const;
virtual const char * Name() const { return "Const3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** Piecewise-linear discontinuous finite elements in 3D. This class is kept
@@ -756,6 +804,7 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearDiscont3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** Piecewise-quadratic discontinuous finite elements in 3D. This class is kept
@@ -778,6 +827,7 @@ public:
int Or) const;
virtual const char * Name() const { return "QuadraticDiscont3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/// Finite element collection on a macro-element.
@@ -803,6 +853,7 @@ public:
int Or) const;
virtual const char * Name() const { return "RefinedLinear"; }
virtual int GetContType() const { return CONTINUOUS; }
};
/** Lowest order Nedelec finite elements in 3D. This class is kept only for
@@ -825,6 +876,7 @@ public:
int Or) const;
virtual const char * Name() const { return "ND1_3D"; }
virtual int GetContType() const { return TANGENTIAL; }
};
/** First order Raviart-Thomas finite elements in 3D. This class is kept only
@@ -848,6 +900,7 @@ public:
int Or) const;
virtual const char * Name() const { return "RT0_3D"; }
virtual int GetContType() const { return NORMAL; }
};
/** Second order Raviart-Thomas finite elements in 3D. This class is kept only
@@ -870,6 +923,7 @@ public:
int Or) const;
virtual const char * Name() const { return "RT1_3D"; }
virtual int GetContType() const { return NORMAL; }
};
/// Discontinuous collection defined locally by a given finite element.
@@ -894,6 +948,7 @@ public:
virtual const char *Name() const { return d_name; }
virtual ~Local_FECollection() { delete Local_Element; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
}
+3 -1
View File
@@ -2615,7 +2615,9 @@ const Operator &InterpolationGridTransfer::BackwardOperator()
L2ProjectionGridTransfer::L2Projection::L2Projection(
const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_)
: fes_ho(fes_ho_), fes_lor(fes_lor_)
: Operator(fes_lor_.GetVSize(), fes_ho_.GetVSize()),
fes_ho(fes_ho_),
fes_lor(fes_lor_)
{
Mesh *mesh_ho = fes_ho.GetMesh();
MFEM_VERIFY(mesh_ho->GetNumGeometries(mesh_ho->Dimension()) <= 1,
+2 -1
View File
@@ -906,7 +906,8 @@ protected:
const L2Projection &l2proj;
public:
L2Prolongation(const L2Projection &l2proj_) : l2proj(l2proj_) { }
L2Prolongation(const L2Projection &l2proj_)
: Operator(l2proj_.Width(), l2proj_.Height()), l2proj(l2proj_) { }
void Mult(const Vector &x, Vector &y) const
{
l2proj.Prolongate(x, y);
+372 -29
View File
@@ -236,7 +236,6 @@ void GridFunction::MakeTRef(FiniteElementSpace *f, Vector &tv, int tv_offset)
}
}
void GridFunction::SumFluxAndCount(BilinearFormIntegrator &blfi,
GridFunction &flux,
Array<int>& count,
@@ -617,17 +616,354 @@ int GridFunction::GetFaceValues(int i, int side, const IntegrationRule &ir,
return dir;
}
void GridFunction::GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
Tr->Transform(ir, tr);
GetVectorValues(*Tr, ir, vals);
}
void be_to_bfe(Geometry::Type geom, int o, const IntegrationPoint &ip,
IntegrationPoint &fip)
{
if (geom == Geometry::TRIANGLE)
{
if (o == 2)
{
fip.x = 1.0 - ip.x - ip.y;
fip.y = ip.x;
}
else if (o == 4)
{
fip.x = ip.y;
fip.y = 1.0 - ip.x - ip.y;
}
else
{
fip.x = ip.x;
fip.y = ip.y;
}
fip.z = ip.z;
}
else
{
if (o == 2)
{
fip.x = ip.y;
fip.y = 1.0 - ip.x;
}
else if (o == 4)
{
fip.x = 1.0 - ip.x;
fip.y = 1.0 - ip.y;
}
else if (o == 6)
{
fip.x = 1.0 - ip.y;
fip.y = ip.x;
}
else
{
fip.x = ip.x;
fip.y = ip.y;
}
fip.z = ip.z;
}
fip.weight = ip.weight;
fip.index = ip.index;
}
double GridFunction::GetValue(ElementTransformation &T,
const IntegrationPoint &ip,
int comp, Vector *tr) const
{
if (tr)
{
T.SetIntPoint(&ip);
T.Transform(ip, *tr);
}
const FiniteElement * fe = NULL;
Array<int> dofs;
switch (T.ElementType)
{
case ElementTransformation::ELEMENT:
fe = fes->GetFE(T.ElementNo);
fes->GetElementDofs(T.ElementNo, dofs);
break;
case ElementTransformation::EDGE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetEdgeElement(T.ElementNo);
fes->GetEdgeDofs(T.ElementNo, dofs);
}
else
{
MFEM_ABORT("GridFunction::GetValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh edges.");
return NAN;
}
break;
case ElementTransformation::FACE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetFaceElement(T.ElementNo);
fes->GetFaceDofs(T.ElementNo, dofs);
}
else
{
MFEM_ABORT("GridFunction::GetValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh faces.");
return NAN;
}
break;
case ElementTransformation::BDR_ELEMENT:
{
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
// This is a continuous field so we can evaluate it on the boundary.
fe = fes->GetBE(T.ElementNo);
fes->GetBdrElementDofs(T.ElementNo, dofs);
}
else
{
// This is a discontinuous field which cannot be evaluated on the
// boundary so we'll evaluate it in the neighboring element.
FaceElementTransformations * FET =
fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo);
// Boundary elements and Boundary Faces may have different
// orientations so adjust the integration point if necessary.
int o = 0;
if (fes->GetMesh()->Dimension() == 3)
{
int f;
fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
}
IntegrationPoint fip;
be_to_bfe(FET->GetGeometryType(), o, ip, fip);
FET->SetIntPoint(&fip);
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetValue(T1, T1.GetIntPoint(), comp);
}
break;
}
case ElementTransformation::BDR_FACE:
{
FaceElementTransformations * FET =
dynamic_cast<FaceElementTransformations *>(&T);
// Evaluate in neighboring element for both continuous and
// discontinuous fields.
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetValue(T1, T1.GetIntPoint(), comp);
}
default:
{
MFEM_ABORT("GridFunction::GetValue: Unsupported element type \""
<< T.ElementType << "\"");
return NAN;
}
}
fes->DofsToVDofs(comp-1, dofs);
Vector DofVal(dofs.Size()), LocVec;
if (fe->GetMapType() == FiniteElement::VALUE)
{
fe->CalcShape(ip, DofVal);
}
else
{
fe->CalcPhysShape(T, DofVal);
}
GetSubVector(dofs, LocVec);
return (DofVal * LocVec);
}
void GridFunction::GetValues(ElementTransformation &T,
const IntegrationRule &ir,
Vector &vals, int comp,
DenseMatrix *tr) const
{
if (tr)
{
T.Transform(ir, *tr);
}
int nip = ir.GetNPoints();
vals.SetSize(nip);
for (int j = 0; j < nip; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
T.SetIntPoint(&ip);
vals[j] = GetValue(T, ip, comp);
}
}
void GridFunction::GetVectorValue(ElementTransformation &T,
const IntegrationPoint &ip,
Vector &val, Vector *tr) const
{
if (tr)
{
T.SetIntPoint(&ip);
T.Transform(ip, *tr);
}
Array<int> vdofs;
const FiniteElement *fe = NULL;
switch (T.ElementType)
{
case ElementTransformation::ELEMENT:
fes->GetElementVDofs(T.ElementNo, vdofs);
fe = fes->GetFE(T.ElementNo);
break;
case ElementTransformation::EDGE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetEdgeElement(T.ElementNo);
fes->GetEdgeVDofs(T.ElementNo, vdofs);
}
else
{
MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh edges.");
return;
}
break;
case ElementTransformation::FACE:
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
fe = fes->GetFaceElement(T.ElementNo);
fes->GetFaceVDofs(T.ElementNo, vdofs);
}
else
{
MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \""
<< fes->FEColl()->GetContType() << "\" not supported "
<< "on mesh faces.");
return;
}
break;
case ElementTransformation::BDR_ELEMENT:
{
if (fes->FEColl()->GetContType() ==
FiniteElementCollection::CONTINUOUS)
{
// This is a continuous field so we can evaluate it on the boundary.
fes->GetBdrElementVDofs(T.ElementNo, vdofs);
fe = fes->GetBE(T.ElementNo);
}
else
{
// This is a discontinuous vector field which cannot be evaluated on
// the boundary so we'll evaluate it in the neighboring element.
FaceElementTransformations * FET =
fes->GetMesh()->GetBdrFaceTransformations(T.ElementNo);
// Boundary elements and Boundary Faces may have different
// orientations so adjust the integration point if necessary.
int o = 0;
if (fes->GetMesh()->Dimension() == 3)
{
int f;
fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
}
IntegrationPoint fip;
be_to_bfe(FET->GetGeometryType(), o, ip, fip);
FET->SetIntPoint(&fip);
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetVectorValue(T1, T1.GetIntPoint(), val);
}
break;
}
case ElementTransformation::BDR_FACE:
{
FaceElementTransformations * FET =
dynamic_cast<FaceElementTransformations *>(&T);
// Evaluate in neighboring element for both continuous and
// discontinuous fields.
ElementTransformation & T1 = FET->GetElement1Transformation();
return GetVectorValue(T1, T1.GetIntPoint(), val);
}
default:
{
MFEM_ABORT("GridFunction::GetVectorValue: Unsupported element type \""
<< T.ElementType << "\"");
if (val.Size() > 0) { val = NAN; }
return;
}
}
int dof = fe->GetDof();
Vector loc_data;
GetSubVector(vdofs, loc_data);
if (fe->GetRangeType() == FiniteElement::SCALAR)
{
Vector shape(dof);
if (fe->GetMapType() == FiniteElement::VALUE)
{
fe->CalcShape(ip, shape);
}
else
{
fe->CalcPhysShape(T, shape);
}
int vdim = fes->GetVDim();
val.SetSize(vdim);
for (int k = 0; k < vdim; k++)
{
val(k) = shape * ((const double *)loc_data + dof * k);
}
}
else
{
int spaceDim = fes->GetMesh()->SpaceDimension();
DenseMatrix vshape(dof, spaceDim);
fe->CalcVShape(T, vshape);
val.SetSize(spaceDim);
vshape.MultTranspose(loc_data, val);
}
}
void GridFunction::GetVectorValues(ElementTransformation &T,
const IntegrationRule &ir,
DenseMatrix &vals) const
DenseMatrix &vals,
DenseMatrix *tr) const
{
if (tr)
{
T.Transform(ir, *tr);
}
const FiniteElement *FElem = fes->GetFE(T.ElementNo);
int dof = FElem->GetDof();
Array<int> vdofs;
fes->GetElementVDofs(T.ElementNo, vdofs);
Vector loc_data;
GetSubVector(vdofs, loc_data);
int nip = ir.GetNPoints();
if (FElem->GetRangeType() == FiniteElement::SCALAR)
{
MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
@@ -639,6 +975,7 @@ void GridFunction::GetVectorValues(ElementTransformation &T,
{
const IntegrationPoint &ip = ir.IntPoint(j);
FElem->CalcShape(ip, shape);
for (int k = 0; k < vdim; k++)
{
vals(k,j) = shape * ((const double *)loc_data + dof * k);
@@ -649,28 +986,22 @@ void GridFunction::GetVectorValues(ElementTransformation &T,
{
int spaceDim = fes->GetMesh()->SpaceDimension();
DenseMatrix vshape(dof, spaceDim);
vals.SetSize(spaceDim, nip);
Vector val_j;
for (int j = 0; j < nip; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
T.SetIntPoint(&ip);
FElem->CalcVShape(T, vshape);
vals.GetColumnReference(j, val_j);
vshape.MultTranspose(loc_data, val_j);
}
}
}
void GridFunction::GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
Tr->Transform(ir, tr);
GetVectorValues(*Tr, ir, vals);
}
int GridFunction::GetFaceVectorValues(
int i, int side, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const
@@ -702,13 +1033,13 @@ int GridFunction::GetFaceVectorValues(
{
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 4);
Transf->Loc1.Transform(ir, eir);
GetVectorValues(Transf->Elem1No, eir, vals, tr);
GetVectorValues(*Transf->Elem1, eir, vals, &tr);
}
else
{
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 8);
Transf->Loc2.Transform(ir, eir);
GetVectorValues(Transf->Elem2No, eir, vals, tr);
GetVectorValues(*Transf->Elem2, eir, vals, &tr);
}
return di;
@@ -1716,6 +2047,8 @@ void GridFunction::ProjectCoefficient(
ElementTransformation *T = NULL;
const FiniteElement *fe = NULL;
fes->BuildDofToArrays(); // ensures GetElementForDof(), GetLocalDofForDof() initialized.
for (int i = 0; i < dofs.Size(); i++)
{
int dof = dofs[i], j = fes->GetElementForDof(dof);
@@ -1757,6 +2090,8 @@ void GridFunction::ProjectCoefficient(
Vector val;
fes->BuildDofToArrays(); // ensures GetElementForDof(), GetLocalDofForDof() initialized.
for (int i = 0; i < dofs.Size(); i++)
{
int dof = dofs[i], j = fes->GetElementForDof(dof);
@@ -2009,7 +2344,7 @@ double GridFunction::ComputeL2Error(
fdof = fe->GetDof();
transf = fes->GetElementTransformation(i);
shape.SetSize(fdof);
intorder = 2*fe->GetOrder() + 1; // <----------
intorder = 2*fe->GetOrder() + 3; // <----------
const IntegrationRule *ir;
if (irs)
{
@@ -2064,7 +2399,7 @@ double GridFunction::ComputeL2Error(
{
if (elems != NULL && (*elems)[i] == 0) { continue; }
fe = fes->GetFE(i);
int intorder = 2*fe->GetOrder() + 1; // <----------
int intorder = 2*fe->GetOrder() + 3; // <----------
const IntegrationRule *ir;
if (irs)
{
@@ -2168,7 +2503,7 @@ double GridFunction::ComputeH1Error(
}
intorder = 2 * intorder; // <-------------
const IntegrationRule &ir =
IntRules.Get(face_elem_transf->FaceGeom, intorder);
IntRules.Get(face_elem_transf->GetGeometryType(), intorder);
err_val.SetSize(ir.GetNPoints());
ell_coeff_val.SetSize(ir.GetNPoints());
// side 1
@@ -2225,7 +2560,7 @@ double GridFunction::ComputeH1Error(
}
}
face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
transf = face_elem_transf->Face;
transf = face_elem_transf;
for (j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
@@ -2259,7 +2594,7 @@ double GridFunction::ComputeMaxError(
fdof = fe->GetDof();
transf = fes->GetElementTransformation(i);
shape.SetSize(fdof);
intorder = 2*fe->GetOrder() + 1; // <----------
intorder = 2*fe->GetOrder() + 3; // <----------
const IntegrationRule *ir;
if (irs)
{
@@ -2425,7 +2760,7 @@ double GridFunction::ComputeLpError(const double p, Coefficient &exsol,
}
else
{
int intorder = 2*fe->GetOrder() + 1; // <----------
int intorder = 2*fe->GetOrder() + 3; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
GetValues(i, *ir, vals);
@@ -2472,10 +2807,13 @@ double GridFunction::ComputeLpError(const double p, Coefficient &exsol,
}
void GridFunction::ComputeElementLpErrors(const double p, Coefficient &exsol,
GridFunction &error,
Vector &error,
Coefficient *weight,
const IntegrationRule *irs[]) const
{
MFEM_ASSERT(error.Size() == fes->GetNE(),
"Incorrect size for result vector");
error = 0.0;
const FiniteElement *fe;
ElementTransformation *T;
@@ -2491,7 +2829,7 @@ void GridFunction::ComputeElementLpErrors(const double p, Coefficient &exsol,
}
else
{
int intorder = 2*fe->GetOrder() + 1; // <----------
int intorder = 2*fe->GetOrder() + 3; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
GetValues(i, *ir, vals);
@@ -2555,7 +2893,7 @@ double GridFunction::ComputeLpError(const double p, VectorCoefficient &exsol,
}
else
{
int intorder = 2*fe->GetOrder() + 1; // <----------
int intorder = 2*fe->GetOrder() + 3; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
T = fes->GetElementTransformation(i);
@@ -2627,11 +2965,14 @@ double GridFunction::ComputeLpError(const double p, VectorCoefficient &exsol,
void GridFunction::ComputeElementLpErrors(const double p,
VectorCoefficient &exsol,
GridFunction &error,
Vector &error,
Coefficient *weight,
VectorCoefficient *v_weight,
const IntegrationRule *irs[]) const
{
MFEM_ASSERT(error.Size() == fes->GetNE(),
"Incorrect size for result vector");
error = 0.0;
const FiniteElement *fe;
ElementTransformation *T;
@@ -2648,7 +2989,7 @@ void GridFunction::ComputeElementLpErrors(const double p,
}
else
{
int intorder = 2*fe->GetOrder() + 1; // <----------
int intorder = 2*fe->GetOrder() + 3; // <----------
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
T = fes->GetElementTransformation(i);
@@ -2658,15 +2999,15 @@ void GridFunction::ComputeElementLpErrors(const double p,
loc_errs.SetSize(vals.Width());
if (!v_weight)
{
// compute the lengths of the errors at the integration points
// thus the vector norm is rotationally invariant
// compute the lengths of the errors at the integration points thus the
// vector norm is rotationally invariant
vals.Norm2(loc_errs);
}
else
{
v_weight->Eval(exact_vals, *T, *ir);
// column-wise dot product of the vector error (in vals) and the
// vector weight (in exact_vals)
// column-wise dot product of the vector error (in vals) and the vector
// weight (in exact_vals)
for (int j = 0; j < vals.Width(); j++)
{
double err = 0.0;
@@ -2798,7 +3139,9 @@ void GridFunction::SaveVTK(std::ostream &out, const std::string &field_name,
RefG = GlobGeometryRefiner.Refine(
mesh->GetElementBaseGeometry(i), ref, 1);
GetVectorValues(i, RefG->RefPts, vval, pmat);
// GetVectorValues(i, RefG->RefPts, vval, pmat);
ElementTransformation * T = mesh->GetElementTransformation(i);
GetVectorValues(*T, RefG->RefPts, vval, &pmat);
for (int j = 0; j < vval.Width(); j++)
{
+157 -26
View File
@@ -144,17 +144,133 @@ public:
/// Returns the values in the vertices of i'th element for dimension vdim.
void GetNodalValues(int i, Array<double> &nval, int vdim = 1) const;
/** @name Element index Get Value Methods
These methods take an element index and return the interpolated value of
the field at a given reference point within the element.
@warning These methods retrieve and use the ElementTransformation object
from the mfem::Mesh. This can alter the state of the element
transformation object and can also lead to unexpected results when the
ElementTransformation object is already in use such as when these methods
are called from within an integration loop. Consider using
GetValue(ElementTransformation &T, ...) instead.
*/
///@{
/** Return a scalar value from within the given element. */
virtual double GetValue(int i, const IntegrationPoint &ip,
int vdim = 1) const;
/** Return a vector value from within the given element. */
void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const;
///@}
/** @name Element Index Get Values Methods
These are convenience methods for repeatedly calling GetValue for
multiple points within a given element. The GetValues methods are
optimized and should perform better than repeatedly calling GetValue. The
GetVectorValues method simply calls GetVectorValue repeatedly.
@warning These methods retrieve and use the ElementTransformation object
from the mfem::Mesh. This can alter the state of the element
transformation object and can also lead to unexpected results when the
ElementTransformation object is already in use such as when these methods
are called from within an integration loop. Consider using
GetValues(ElementTransformation &T, ...) instead.
*/
///@{
/** Compute a collection of scalar values from within the element indicated
by the index i. */
void GetValues(int i, const IntegrationRule &ir, Vector &vals,
int vdim = 1) const;
/** Compute a collection of vector values from within the element indicated
by the index i. */
void GetValues(int i, const IntegrationRule &ir, Vector &vals,
DenseMatrix &tr, int vdim = 1) const;
void GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
///@}
/** @name ElementTransformation Get Value Methods
These member functions are designed for use within
GridFunctionCoefficient objects. These can be used with
ElementTransformation objects coming from either
Mesh::GetElementTransformation() or Mesh::GetBdrElementTransformation().
@note These methods do not reset the ElementTransformation object so they
should be safe to use within integration loops or other contexts where
the ElementTransformation is already in use.
*/
///@{
/** Return a scalar value from within the element indicated by the
ElementTransformation Object. */
double GetValue(ElementTransformation &T, const IntegrationPoint &ip,
int comp = 0, Vector *tr = NULL) const;
/** Return a vector value from within the element indicated by the
ElementTransformation Object. */
void GetVectorValue(ElementTransformation &T, const IntegrationPoint &ip,
Vector &val, Vector *tr = NULL) const;
///@}
/** @name ElementTransformation Get Values Methods
These are convenience methods for repeatedly calling GetValue for
multiple points within a given element. They work by calling either the
ElementTransformation or FaceElementTransformations versions described
above. Consequently, these methods should not be expected to run faster
than calling the above methods in an external loop.
@note These methods do not reset the ElementTransformation object so they
should be safe to use within integration loops or other contexts where
the ElementTransformation is already in use.
@note These methods can also be used with FaceElementTransformations
objects.
*/
///@{
/** Compute a collection of scalar values from within the element indicated
by the ElementTransformation object. */
void GetValues(ElementTransformation &T, const IntegrationRule &ir,
Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const;
/** Compute a collection of vector values from within the element indicated
by the ElementTransformation object. */
void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix *tr = NULL) const;
///@}
/** @name Face Index Get Values Methods
These methods are designed to work with Discontinuous Galerkin basis
functions. They compute field values on the interface between elements,
or on boundary elements, by interpolating the field in a neighboring
element. The \a side argument indices which neighboring element should be
used: 0, 1, or 2 (automatically chosen).
@warning These methods retrieve and use the FaceElementTransformations
object from the mfem::Mesh. This can alter the state of the face element
transformations object and can also lead to unexpected results when the
FaceElementTransformations object is already in use such as when these
methods are called from within an integration loop. Consider using
GetValues(ElementTransformation &T, ...) instead.
*/
///@{
/** Compute a collection of scalar values from within the face
indicated by the index i. */
int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals,
DenseMatrix &tr, int vdim = 1) const;
/** Compute a collection of vector values from within the face
indicated by the index i. */
int GetFaceVectorValues(int i, int side, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
///@}
void GetLaplacians(int i, const IntegrationRule &ir, Vector &laps,
int vdim = 1) const;
@@ -167,18 +283,6 @@ public:
void GetHessians(int i, const IntegrationRule &ir, DenseMatrix &hess,
DenseMatrix &tr, int vdim = 1) const;
int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals,
DenseMatrix &tr, int vdim = 1) const;
void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir,
DenseMatrix &vals) const;
void GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
int GetFaceVectorValues(int i, int side, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const;
void GetValuesFrom(const GridFunction &orig_func);
void GetBdrValuesFrom(const GridFunction &orig_func);
@@ -236,12 +340,10 @@ public:
virtual void ProjectCoefficient(Coefficient &coeff);
// call fes -> BuildDofToArrays() before using this projection
void ProjectCoefficient(Coefficient &coeff, Array<int> &dofs, int vd = 0);
void ProjectCoefficient(VectorCoefficient &vcoeff);
// call fes -> BuildDofToArrays() before using this projection
void ProjectCoefficient(VectorCoefficient &vcoeff, Array<int> &dofs);
void ProjectCoefficient(Coefficient *coeff[]);
@@ -365,28 +467,28 @@ public:
const IntegrationRule *irs[] = NULL) const;
/** Compute the Lp error in each element of the mesh and store the results in
the GridFunction @a error. The result should be an L2 GridFunction of
order zero using map type VALUE. */
the Vector @a error. The result should be of length number of elements,
for example an L2 GridFunction of order zero using map type VALUE. */
virtual void ComputeElementLpErrors(const double p, Coefficient &exsol,
GridFunction &error,
Vector &error,
Coefficient *weight = NULL,
const IntegrationRule *irs[] = NULL
) const;
virtual void ComputeElementL1Errors(Coefficient &exsol,
GridFunction &error,
Vector &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(1.0, exsol, error, NULL, irs); }
virtual void ComputeElementL2Errors(Coefficient &exsol,
GridFunction &error,
Vector &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(2.0, exsol, error, NULL, irs); }
virtual void ComputeElementMaxErrors(Coefficient &exsol,
GridFunction &error,
Vector &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(infinity(), exsol, error, NULL, irs); }
@@ -400,29 +502,29 @@ public:
const IntegrationRule *irs[] = NULL) const;
/** Compute the Lp error in each element of the mesh and store the results in
the GridFunction @ error. The result should be an L2 GridFunction of
order zero using map type VALUE. */
the Vector @ error. The result should be of length number of elements,
for example an L2 GridFunction of order zero using map type VALUE. */
virtual void ComputeElementLpErrors(const double p, VectorCoefficient &exsol,
GridFunction &error,
Vector &error,
Coefficient *weight = NULL,
VectorCoefficient *v_weight = NULL,
const IntegrationRule *irs[] = NULL
) const;
virtual void ComputeElementL1Errors(VectorCoefficient &exsol,
GridFunction &error,
Vector &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(1.0, exsol, error, NULL, NULL, irs); }
virtual void ComputeElementL2Errors(VectorCoefficient &exsol,
GridFunction &error,
Vector &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(2.0, exsol, error, NULL, NULL, irs); }
virtual void ComputeElementMaxErrors(VectorCoefficient &exsol,
GridFunction &error,
Vector &error,
const IntegrationRule *irs[] = NULL
) const
{ ComputeElementLpErrors(infinity(), exsol, error, NULL, NULL, irs); }
@@ -633,6 +735,16 @@ public:
*/
inline void GetElementValues(int idx, Vector &values) const;
/// Return the quadrature function values at an integration point.
/** The result is stored in the Vector @a values as a reference to the
global values. */
inline void GetElementValues(int idx, const int ip_num, Vector &values);
/// Return the quadrature function values at an integration point.
/** The result is stored in the Vector @a values as a copy to the
global values. */
inline void GetElementValues(int idx, const int ip_num, Vector &values) const;
/// Return all values associated with mesh element @a idx in a DenseMatrix.
/** The result is stored in the DenseMatrix @a values as a reference to the
global values.
@@ -737,6 +849,25 @@ inline void QuadratureFunction::GetElementValues(int idx, Vector &values) const
}
}
inline void QuadratureFunction::GetElementValues(int idx, const int ip_num,
Vector &values)
{
const int s_offset = qspace->element_offsets[idx] * vdim + ip_num * vdim;
values.NewDataAndSize(data + s_offset, vdim);
}
inline void QuadratureFunction::GetElementValues(int idx, const int ip_num,
Vector &values) const
{
const int s_offset = qspace->element_offsets[idx] * vdim + ip_num * vdim;
values.SetSize(vdim);
const double *q = data + s_offset;
for (int i = 0; i < values.Size(); i++)
{
values(i) = *(q++);
}
}
inline void QuadratureFunction::GetElementValues(int idx, DenseMatrix &values)
{
const int s_offset = qspace->element_offsets[idx];
+100 -32
View File
@@ -29,12 +29,14 @@ namespace mfem
{
FindPointsGSLIB::FindPointsGSLIB()
: mesh(NULL), ir_simplex(NULL), gsl_mesh(), fdata2D(NULL), fdata3D(NULL),
dim(-1)
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
{
gsl_comm = new comm;
#ifdef MFEM_USE_MPI
MPI_Init(NULL, NULL);
int initialized;
MPI_Initialized(&initialized);
if (!initialized) { MPI_Init(NULL, NULL); }
MPI_Comm comm = MPI_COMM_WORLD;;
comm_init(gsl_comm, comm);
#else
@@ -50,28 +52,29 @@ FindPointsGSLIB::~FindPointsGSLIB()
#ifdef MFEM_USE_MPI
FindPointsGSLIB::FindPointsGSLIB(MPI_Comm _comm)
: mesh(NULL), ir_simplex(NULL), gsl_mesh(), fdata2D(NULL), fdata3D(NULL),
dim(-1)
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
{
gsl_comm = new comm;
comm_init(gsl_comm, _comm);
}
#endif
void FindPointsGSLIB::Setup(Mesh &m, double bb_t, double newt_tol, int npt_max)
void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
const int npt_max)
{
MFEM_VERIFY(m.GetNodes() != NULL, "Mesh nodes are required.");
MFEM_VERIFY(m.GetNumGeometries(m.Dimension()) == 1,
"Mixed meshes are not currently supported in FindPointsGSLIB.");
// call FreeData if FindPointsGSLIB::Setup has been called already
if (setupflag) { FreeData(); }
mesh = &m;
dim = mesh->Dimension();
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
unsigned dof1D = fe->GetOrder() + 1;
int NE = mesh->GetNE(),
dof_cnt = fe->GetDof(),
pts_cnt = NE * dof_cnt,
gt = fe->GetGeomType();
const int gt = fe->GetGeomType();
if (gt == Geometry::TRIANGLE || gt == Geometry::TETRAHEDRON ||
gt == Geometry::PRISM)
@@ -87,8 +90,8 @@ void FindPointsGSLIB::Setup(Mesh &m, double bb_t, double newt_tol, int npt_max)
MFEM_ABORT("Element type not currently supported in FindPointsGSLIB.");
}
pts_cnt = gsl_mesh.Size()/dim;
int NEtot = pts_cnt/(int)pow(dof1D, dim);
const int pts_cnt = gsl_mesh.Size()/dim,
NEtot = pts_cnt/(int)pow(dof1D, dim);
if (dim == 2)
{
@@ -107,6 +110,7 @@ void FindPointsGSLIB::Setup(Mesh &m, double bb_t, double newt_tol, int npt_max)
fdata3D = findpts_setup_3(gsl_comm, elx, nr, NEtot, mr, bb_t,
pts_cnt, pts_cnt, npt_max, newt_tol);
}
setupflag = true;
}
void FindPointsGSLIB::FindPoints(const Vector &point_pos,
@@ -115,6 +119,7 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos,
Array<unsigned int> &elem_ids,
Vector &ref_pos, Vector &dist)
{
MFEM_VERIFY(setupflag, "Use FindPointsGSLIB::Setup before finding points.");
const int points_cnt = point_pos.Size() / dim;
if (dim == 2)
{
@@ -150,36 +155,92 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos,
}
}
void FindPointsGSLIB::FindPoints(const Vector &point_pos)
{
const int points_cnt = point_pos.Size() / dim;
gsl_code.SetSize(points_cnt);
gsl_proc.SetSize(points_cnt);
gsl_elem.SetSize(points_cnt);
gsl_ref.SetSize(points_cnt * dim);
gsl_dist.SetSize(points_cnt);
FindPoints(point_pos, gsl_code, gsl_proc, gsl_elem, gsl_ref, gsl_dist);
}
void FindPointsGSLIB::FindPoints(Mesh &m, const Vector &point_pos,
const double bb_t, const double newt_tol,
const int npt_max)
{
if (!setupflag || (mesh != &m) )
{
Setup(m, bb_t, newt_tol, npt_max);
}
FindPoints(point_pos);
}
void FindPointsGSLIB::Interpolate(Array<unsigned int> &codes,
Array<unsigned int> &proc_ids,
Array<unsigned int> &elem_ids,
Vector &ref_pos, const GridFunction &field_in,
Vector &field_out)
{
Vector node_vals;
GetNodeValues(field_in, node_vals);
const int points_cnt = ref_pos.Size() / dim;
if (dim==2)
FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
GridFunction field_in_scalar(&ind_fes);
Vector node_vals;
const int ncomp = field_in.FESpace()->GetVDim(),
points_fld = field_in.Size() / ncomp,
points_cnt = codes.Size();
for (int i = 0; i < ncomp; i++)
{
findpts_eval_2(field_out.GetData(), sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata2D);
}
else
{
findpts_eval_3(field_out.GetData(), sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata3D);
const int dataptrin = i*points_fld,
dataptrout = i*points_cnt;
field_in_scalar.NewDataAndSize(field_in.GetData()+dataptrin, points_fld);
GetNodeValues(field_in_scalar, node_vals);
if (dim==2)
{
findpts_eval_2(field_out.GetData()+dataptrout, sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata2D);
}
else
{
findpts_eval_3(field_out.GetData()+dataptrout, sizeof(double),
codes.GetData(), sizeof(unsigned int),
proc_ids.GetData(), sizeof(unsigned int),
elem_ids.GetData(), sizeof(unsigned int),
ref_pos.GetData(), sizeof(double) * dim,
points_cnt, node_vals.GetData(), fdata3D);
}
}
}
void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
Vector &field_out)
{
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::Interpolate(const Vector &point_pos,
const GridFunction &field_in, Vector &field_out)
{
FindPoints(point_pos);
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::Interpolate(Mesh &m, const Vector &point_pos,
const GridFunction &field_in, Vector &field_out)
{
FindPoints(m, point_pos);
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
}
void FindPointsGSLIB::FreeData()
{
if (dim == 2)
@@ -190,7 +251,13 @@ void FindPointsGSLIB::FreeData()
{
findpts_free_3(fdata3D);
}
setupflag = false;
gsl_code.DeleteAll();
gsl_proc.DeleteAll();
gsl_elem.DeleteAll();
gsl_mesh.Destroy();
gsl_ref.Destroy();
gsl_dist.Destroy();
}
void FindPointsGSLIB::GetNodeValues(const GridFunction &gf_in,
@@ -292,7 +359,7 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
const GridFunction *nodes = mesh->GetNodes();
Mesh *meshsplit = NULL;
const int NE = mesh->GetNE();
int NEsplit;
int NEsplit = -1;
// Split the reference element into a reference submesh of quads or hexes.
if (gt == Geometry::TRIANGLE)
@@ -386,6 +453,7 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
}
meshsplit->FinalizeHexMesh(1, 1, true);
}
else { MFEM_ABORT("Unsupported geometry type."); }
// Curve the reference submesh.
H1_FECollection fec(fe->GetOrder(), dim);
+30 -3
View File
@@ -29,10 +29,12 @@ class FindPointsGSLIB
protected:
Mesh *mesh;
IntegrationRule *ir_simplex;
Vector gsl_mesh;
struct findpts_data_2 *fdata2D;
struct findpts_data_3 *fdata3D;
int dim;
Array<unsigned int> gsl_code, gsl_proc, gsl_elem;
Vector gsl_mesh, gsl_ref, gsl_dist;
bool setupflag;
struct comm *gsl_comm;
@@ -59,7 +61,8 @@ public:
@param[in] newt_tol Newton tolerance for the gslib search methods.
@param[in] npt_max Number of points for simultaneous iteration. This
alters performance and memory footprint. */
void Setup(Mesh &m, double bb_t, double newt_tol, int npt_max);
void Setup(Mesh &m, const double bb_t = 0.1, const double newt_tol = 1.0e-12,
const int npt_max = 256);
/** Searches positions given in physical space by @a point_pos. All output
Arrays and Vectors are expected to have the correct size.
@@ -73,11 +76,15 @@ public:
@param[out] ref_pos Reference coordinates of the found point. Ordered
by vdim (XYZ,XYZ,XYZ...).
Note: the gslib reference frame is [-1,1].
@param[out] dist Distance between the seeked and the found point
@param[out] dist Distance between the sought and the found point
in physical space. */
void FindPoints(const Vector &point_pos, Array<unsigned int> &codes,
Array<unsigned int> &proc_ids, Array<unsigned int> &elem_ids,
Vector &ref_pos, Vector &dist);
void FindPoints(const Vector &point_pos);
/// Setup FindPoints and search positions
void FindPoints(Mesh &m, const Vector &point_pos, const double bb_t = 0.1,
const double newt_tol = 1.0e-12, const int npt_max = 256);
/** Interpolation of field values at prescribed reference space positions.
@@ -96,11 +103,31 @@ public:
void Interpolate(Array<unsigned int> &codes, Array<unsigned int> &proc_ids,
Array<unsigned int> &elem_ids, Vector &ref_pos,
const GridFunction &field_in, Vector &field_out);
void Interpolate(const GridFunction &field_in, Vector &field_out);
/** Search positions and interpolate */
void Interpolate(const Vector &point_pos, const GridFunction &field_in,
Vector &field_out);
/** Setup FindPoints, search positions and interpolate */
void Interpolate(Mesh &m, const Vector &point_pos,
const GridFunction &field_in, Vector &field_out);
/** Cleans up memory allocated internally by gslib.
Note that in parallel, this must be called before MPI_Finalize(), as
it calls MPI_Comm_free() for internal gslib communicators. */
void FreeData();
/// Return code for each point searched by FindPoints: inside element (0), on
/// element boundary (1), or not found (2).
const Array<unsigned int> &GetCode() const { return gsl_code; }
/// Return element number for each point found by FindPoints.
const Array<unsigned int> &GetElem() const { return gsl_elem; }
/// Return MPI rank on which each point was found by FindPoints.
const Array<unsigned int> &GetProc() const { return gsl_proc; }
/// Return reference coordinates for each point found by FindPoints.
const Vector &GetReferencePosition() const { return gsl_ref; }
/// Return distance Distance between the sought and the found point
/// in physical space, for each point found by FindPoints.
const Vector &GetDist() const { return gsl_dist; }
};
} // namespace mfem
+1 -1
View File
@@ -40,7 +40,7 @@ struct CeedConstCoeff
struct CeedGridCoeff
{
GridFunction* coeff;
const GridFunction* coeff;
CeedBasis basis;
CeedElemRestriction restr;
CeedVector coeffVector;
+77 -20
View File
@@ -307,7 +307,7 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
if (ir == NULL)
{
int intorder = 2*el.GetOrder();
ir = &IntRules.Get(Tr.FaceGeom, intorder);
ir = &IntRules.Get(Tr.GetGeometryType(), intorder);
}
for (int i = 0; i < ir->GetNPoints(); i++)
@@ -316,9 +316,11 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
IntegrationPoint eip;
Tr.Loc1.Transform(ip, eip);
Tr.Face->SetIntPoint(&ip);
Q.Eval(vec, *Tr.Face, ip);
vec *= Tr.Face->Weight() * ip.weight;
Tr.SetIntPoint(&ip);
// Use Tr transformation in case Q depends on boundary attribute
Q.Eval(vec, Tr, ip);
vec *= Tr.Weight() * ip.weight;
el.CalcShape(eip, shape);
for (int k = 0; k < vdim; k++)
{
@@ -510,7 +512,7 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
{
order++;
}
ir = &IntRules.Get(Tr.FaceGeom, order);
ir = &IntRules.Get(Tr.GetGeometryType(), order);
}
shape.SetSize(ndof);
@@ -524,8 +526,10 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
Tr.Loc1.Transform(ip, eip);
el.CalcShape(eip, shape);
Tr.Face->SetIntPoint(&ip);
Tr.SetIntPoint(&ip);
// Use Tr.Elem1 transformation for u so that it matches the coefficient
// used with the ConvectionIntegrator and/or the DGTraceIntegrator.
u->Eval(vu, *Tr.Elem1, eip);
if (dim == 1)
@@ -534,12 +538,12 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
}
else
{
CalcOrtho(Tr.Face->Jacobian(), nor);
CalcOrtho(Tr.Jacobian(), nor);
}
un = vu * nor;
w = 0.5*alpha*un - beta*fabs(un);
w *= ip.weight*f->Eval(*Tr.Elem1, eip);
w *= ip.weight*f->Eval(Tr, ip);
elvect.Add(w, shape);
}
}
@@ -582,7 +586,7 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect(
{
// a simple choice for the integration order; is this OK?
int order = 2*el.GetOrder();
ir = &IntRules.Get(Tr.FaceGeom, order);
ir = &IntRules.Get(Tr.GetGeometryType(), order);
}
for (int p = 0; p < ir->GetNPoints(); p++)
@@ -591,33 +595,33 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect(
IntegrationPoint eip;
Tr.Loc1.Transform(ip, eip);
Tr.Face->SetIntPoint(&ip);
Tr.SetIntPoint(&ip);
if (dim == 1)
{
nor(0) = 2*eip.x - 1.0;
}
else
{
CalcOrtho(Tr.Face->Jacobian(), nor);
CalcOrtho(Tr.Jacobian(), nor);
}
el.CalcShape(eip, shape);
el.CalcDShape(eip, dshape);
Tr.Elem1->SetIntPoint(&eip);
// compute uD through the face transformation
w = ip.weight * uD->Eval(*Tr.Face, ip) / Tr.Elem1->Weight();
w = ip.weight * uD->Eval(Tr, ip) / Tr.Elem1->Weight();
if (!MQ)
{
if (Q)
{
w *= Q->Eval(*Tr.Elem1, eip);
w *= Q->Eval(Tr, ip);
}
ni.Set(w, nor);
}
else
{
nh.Set(w, nor);
MQ->Eval(mq, *Tr.Elem1, eip);
MQ->Eval(mq, Tr, ip);
mq.MultTranspose(nh, ni);
}
CalcAdjugate(Tr.Elem1->Jacobian(), adjJ);
@@ -676,7 +680,7 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
if (ir == NULL)
{
const int order = 2*el.GetOrder(); // <-----
ir = &IntRules.Get(Tr.FaceGeom, order);
ir = &IntRules.Get(Tr.GetGeometryType(), order);
}
for (int pi = 0; pi < ir->GetNPoints(); ++pi)
@@ -684,11 +688,10 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
const IntegrationPoint &ip = ir->IntPoint(pi);
IntegrationPoint eip;
Tr.Loc1.Transform(ip, eip);
Tr.Face->SetIntPoint(&ip);
Tr.Elem1->SetIntPoint(&eip);
Tr.SetIntPoint(&ip);
// Evaluate the Dirichlet b.c. using the face transformation.
uD.Eval(u_dir, *Tr.Face, ip);
uD.Eval(u_dir, Tr, ip);
el.CalcShape(eip, shape);
el.CalcDShape(eip, dshape);
@@ -702,7 +705,7 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
}
else
{
CalcOrtho(Tr.Face->Jacobian(), nor);
CalcOrtho(Tr.Jacobian(), nor);
}
double wL, wM, jcoef;
@@ -768,4 +771,58 @@ void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
}
}
void VectorQuadratureLFIntegrator::AssembleRHSElementVect(
const FiniteElement &fe, ElementTransformation &Tr, Vector &elvect)
{
const IntegrationRule *ir =
&vqfc.GetQuadFunction().GetSpace()->GetElementIntRule(Tr.ElementNo);
const int nqp = ir->GetNPoints();
const int vdim = vqfc.GetVDim();
const int ndofs = fe.GetDof();
Vector shape(ndofs);
Vector temp(vdim);
elvect.SetSize(vdim * ndofs);
elvect = 0.0;
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir->IntPoint(q);
Tr.SetIntPoint(&ip);
const double w = Tr.Weight() * ip.weight;
vqfc.Eval(temp, Tr, ip);
fe.CalcShape(ip, shape);
for (int ind = 0; ind < vdim; ind++)
{
for (int nd = 0; nd < ndofs; nd++)
{
elvect(nd + ind * ndofs) += w * shape(nd) * temp(ind);
}
}
}
}
void QuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe,
ElementTransformation &Tr,
Vector &elvect)
{
const IntegrationRule *ir =
&qfc.GetQuadFunction().GetSpace()->GetElementIntRule(Tr.ElementNo);
const int nqp = ir->GetNPoints();
const int ndofs = fe.GetDof();
Vector shape(ndofs);
elvect.SetSize(ndofs);
elvect = 0.0;
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir->IntPoint(q);
Tr.SetIntPoint (&ip);
const double w = Tr.Weight() * ip.weight;
double temp = qfc.Eval(Tr, ip);
fe.CalcShape(ip, shape);
shape *= (w * temp);
elvect += shape;
}
}
}
+64 -1
View File
@@ -36,7 +36,7 @@ public:
FaceElementTransformations &Tr,
Vector &elvect);
void SetIntRule(const IntegrationRule *ir) { IntRule = ir; }
virtual void SetIntRule(const IntegrationRule *ir) { IntRule = ir; }
const IntegrationRule* GetIntRule() { return IntRule; }
virtual ~LinearFormIntegrator() { }
@@ -426,6 +426,69 @@ public:
Vector &elvect);
};
/** Class for domain integration of L(v) := (f, v), where
f=(f1,...,fn) and v=(v1,...,vn). that makes use of
VectorQuadratureFunctionCoefficient*/
class VectorQuadratureLFIntegrator : public LinearFormIntegrator
{
private:
VectorQuadratureFunctionCoefficient &vqfc;
public:
VectorQuadratureLFIntegrator(VectorQuadratureFunctionCoefficient &vqfc,
const IntegrationRule *ir)
: LinearFormIntegrator(ir), vqfc(vqfc)
{
if (ir)
{
MFEM_WARNING("Integration rule not used in this class. "
"The QuadratureFunction integration rules are used instead");
}
}
using LinearFormIntegrator::AssembleRHSElementVect;
virtual void AssembleRHSElementVect(const FiniteElement &fe,
ElementTransformation &Tr,
Vector &elvect);
virtual void SetIntRule(const IntegrationRule *ir)
{
MFEM_WARNING("Integration rule not used in this class. "
"The QuadratureFunction integration rules are used instead");
}
};
/** Class for domain integration L(v) := (f, v) that makes use
of QuadratureFunctionCoefficient. */
class QuadratureLFIntegrator : public LinearFormIntegrator
{
private:
QuadratureFunctionCoefficient &qfc;
public:
QuadratureLFIntegrator(QuadratureFunctionCoefficient &qfc,
const IntegrationRule *ir)
: LinearFormIntegrator(ir), qfc(qfc)
{
if (ir)
{
MFEM_WARNING("Integration rule not used in this class. "
"The QuadratureFunction integration rules are used instead");
}
}
using LinearFormIntegrator::AssembleRHSElementVect;
virtual void AssembleRHSElementVect(const FiniteElement &fe,
ElementTransformation &Tr,
Vector &elvect);
virtual void SetIntRule(const IntegrationRule *ir)
{
MFEM_WARNING("Integration rule not used in this class. "
"The QuadratureFunction integration rules are used instead");
}
};
}
#endif
+2 -1
View File
@@ -232,7 +232,8 @@ void ParGridFunction::ExchangeFaceNbrData()
auto d_send_data = send_data.Write();
MFEM_FORALL(i, send_data.Size(),
{
d_send_data[i] = d_data[d_send_ldof[i]];
const int ldof = d_send_ldof[i];
d_send_data[i] = d_data[ldof >= 0 ? ldof : -1-ldof];
});
bool mpi_gpu_aware = Device::GetGPUAwareMPI();
+62 -17
View File
@@ -168,6 +168,27 @@ void ElementRestriction::Mult(const Vector& x, Vector& y) const
});
}
void ElementRestriction::MultUnsigned(const Vector& x, Vector& y) const
{
// Assumes all elements have the same number of dofs
const int nd = dof;
const int vd = vdim;
const bool t = byvdim;
auto d_x = Reshape(x.Read(), t?vd:ndofs, t?ndofs:vd);
auto d_y = Reshape(y.Write(), nd, vd, ne);
auto d_gatherMap = gatherMap.Read();
MFEM_FORALL(i, dof*ne,
{
const int gid = d_gatherMap[i];
const int j = gid >= 0 ? gid : -1-gid;
for (int c = 0; c < vd; ++c)
{
d_y(i % nd, c, i / nd) = d_x(t?c:j, t?j:c);
}
});
}
void ElementRestriction::MultTranspose(const Vector& x, Vector& y) const
{
// Assumes all elements have the same number of dofs
@@ -966,27 +987,51 @@ void L2FaceRestriction::MultTranspose(const Vector& x, Vector& y) const
const int dofs = nfdofs;
auto d_offsets = offsets.Read();
auto d_indices = gather_indices.Read();
auto d_x = Reshape(x.Read(), nd, vd, 2, nf);
auto d_y = Reshape(y.Write(), t?vd:ndofs, t?ndofs:vd);
MFEM_FORALL(i, ndofs,
if (m == L2FaceValues::DoubleValued)
{
const int offset = d_offsets[i];
const int nextOffset = d_offsets[i + 1];
for (int c = 0; c < vd; ++c)
auto d_x = Reshape(x.Read(), nd, vd, 2, nf);
auto d_y = Reshape(y.Write(), t?vd:ndofs, t?ndofs:vd);
MFEM_FORALL(i, ndofs,
{
double dofValue = 0;
for (int j = offset; j < nextOffset; ++j)
const int offset = d_offsets[i];
const int nextOffset = d_offsets[i + 1];
for (int c = 0; c < vd; ++c)
{
int idx_j = d_indices[j];
bool isE1 = idx_j < dofs;
idx_j = isE1 ? idx_j : idx_j - dofs;
dofValue += isE1 ?
d_x(idx_j % nd, c, 0, idx_j / nd)
:d_x(idx_j % nd, c, 1, idx_j / nd);
double dofValue = 0;
for (int j = offset; j < nextOffset; ++j)
{
int idx_j = d_indices[j];
bool isE1 = idx_j < dofs;
idx_j = isE1 ? idx_j : idx_j - dofs;
dofValue += isE1 ?
d_x(idx_j % nd, c, 0, idx_j / nd)
:d_x(idx_j % nd, c, 1, idx_j / nd);
}
d_y(t?c:i,t?i:c) += dofValue;
}
d_y(t?c:i,t?i:c) += dofValue;
}
});
});
}
else
{
auto d_x = Reshape(x.Read(), nd, vd, nf);
auto d_y = Reshape(y.Write(), t?vd:ndofs, t?ndofs:vd);
MFEM_FORALL(i, ndofs,
{
const int offset = d_offsets[i];
const int nextOffset = d_offsets[i + 1];
for (int c = 0; c < vd; ++c)
{
double dofValue = 0;
for (int j = offset; j < nextOffset; ++j)
{
int idx_j = d_indices[j];
dofValue += d_x(idx_j % nd, c, idx_j / nd);
}
d_y(t?c:i,t?i:c) += dofValue;
}
});
}
}
int ToLexOrdering(const int dim, const int face_id, const int size1d,
+2
View File
@@ -47,6 +47,8 @@ public:
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const;
/// Compute Mult without applying signs based on DOF orientations.
void MultUnsigned(const Vector &x, Vector &y) const;
/// Compute MultTranspose without applying signs based on DOF orientations.
void MultTransposeUnsigned(const Vector &x, Vector &y) const;
+208 -138
View File
@@ -13,6 +13,7 @@
#define MFEM_TEMPLATE_BILINEAR_FORM
#include "../config/tconfig.hpp"
#include "../linalg/simd.hpp"
#include "../linalg/ttensor.hpp"
#include "bilinearform.hpp"
#include "tevaluator.hpp"
@@ -30,9 +31,13 @@ namespace mfem
template <typename meshType, typename solFESpace,
typename IR, typename IntegratorType,
typename solVecLayout_t = ScalarLayout,
typename complex_t = double, typename real_t = double>
typename complex_t = double, typename real_t = double,
typename impl_traits_t = AutoSIMDTraits<complex_t,real_t> >
class TBilinearForm : public Operator
{
public:
typedef impl_traits_t impl_traits_type;
protected:
typedef complex_t complex_type;
typedef real_t real_type;
@@ -48,26 +53,36 @@ protected:
static const int dofs = solFE_type::dofs;
static const int vdim = solVecLayout_t::vec_dim;
static const int qpts = IR::qpts;
static const int AB = impl_traits_t::align_bytes;
static const int SS = impl_traits_t::simd_size;
static const int BE = impl_traits_t::batch_size;
static const int TE = SS*BE;
typedef typename impl_traits_t::vcomplex_t vcomplex_t;
typedef typename impl_traits_t::vreal_t vreal_t;
typedef IntegratorType integ_t;
typedef typename integ_t::coefficient_type coeff_t;
typedef typename integ_t::template kernel<sdim,dim,complex_t>::type kernel_t;
typedef typename integ_t::template kernel<sdim,dim,vcomplex_t>::type kernel_t;
typedef typename kernel_t::template p_asm_data<qpts>::type p_assembled_t;
typedef typename kernel_t::template f_asm_data<qpts>::type f_assembled_t;
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,impl_traits_t>::Type coeff_eval_t;
typedef TElementTransformation<meshType,IR,real_t> Trans_t;
template <int NE> struct T_result
struct T_result
{
static const int EvalOps =
Trans_t::template Get<coeff_t,kernel_t>::EvalOps;
typedef typename Trans_t::template Result<EvalOps,NE> Type;
typedef typename Trans_t::template Result<EvalOps,impl_traits_t> Type;
};
typedef FieldEvaluator<solFESpace,solVecLayout_t,IR,
complex_t,real_t> solFieldEval;
template <int BE> struct S_spec
struct S_spec
{
typedef typename solFieldEval::template Spec<kernel_t,BE> Spec;
typedef typename solFieldEval::template Spec<kernel_t,impl_traits_t> Spec;
typedef typename Spec::DataType DataType;
typedef typename Spec::ElementMatrix ElementMatrix;
};
@@ -86,7 +101,7 @@ protected:
coeff_t coeff;
p_assembled_t *assembled_data;
Memory<p_assembled_t> assembled_data;
const FiniteElementSpace &in_fes;
@@ -101,13 +116,17 @@ public:
solVecLayout(sol_fes),
int_rule(),
coeff(integ.coeff),
assembled_data(NULL),
assembled_data(),
in_fes(sol_fes)
{ }
{
assembled_data.Reset(AB == 64 ? MemoryType::HOST_64 :
AB == 32 ? MemoryType::HOST_32 :
MemoryType::HOST);
}
virtual ~TBilinearForm()
{
delete [] assembled_data;
assembled_data.Delete();
}
/// Get the input finite element space prolongation matrix
@@ -119,10 +138,9 @@ public:
virtual void Mult(const Vector &x, Vector &y) const
{
if (assembled_data)
if (!assembled_data.Empty())
{
const int num_elem = 1;
MultAssembled<num_elem>(x, y);
MultAssembled(x, y);
}
else
{
@@ -135,10 +153,6 @@ public:
{
y = 0.0;
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
// For better performance, create stack copies of solFES, and solEval
// inside 'solFEval'. The element-transformation 'T' also copies the
// meshFES, meshEval, etc internally.
@@ -149,26 +163,29 @@ public:
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el++)
for (int el = 0; el < NE; el += TE)
{
#if 0
typename S_spec<BE>::DataType R;
typename S_spec::DataType R;
solFEval.Eval(el, R);
typename T_result<BE>::Type F;
typename T_result::Type F;
T.Eval(el, F);
#else
typename T_result<BE>::Type F;
typename T_result::Type F;
T.Eval(el, F);
typename S_spec<BE>::DataType R;
typename S_spec::DataType R;
solFEval.Eval(el, R);
#endif
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
kernel_t::Action(0, F, wQ, res, R);
for (int k = 0; k < BE; k++)
{
kernel_t::Action(k, F, wQ, res, R);
}
solFEval.template Assemble<true>(R);
}
@@ -177,21 +194,18 @@ public:
// Partial assembly of quadrature point data
void Assemble()
{
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
Trans_t T(mesh, meshEval);
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
if (!assembled_data)
if (assembled_data.Empty())
{
assembled_data = new p_assembled_t[NE];
const int size = ((NE+TE-1)/TE)*BE;
assembled_data.New(size, assembled_data.GetMemoryType());
}
for (int el = 0; el < NE; el++) // BE == 1
for (int el = 0; el < NE; el += TE)
{
typename T_result<BE>::Type F;
typename T_result::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
@@ -199,28 +213,26 @@ public:
for (int k = 0; k < BE; k++)
{
kernel_t::Assemble(k, F, wQ, res, assembled_data[el+k]);
kernel_t::Assemble(k, F, wQ, res, assembled_data[el/SS+k]);
}
}
}
template <int num_elem>
inline MFEM_ALWAYS_INLINE
void ElementAddMultAssembled(int el, solFieldEval &solFEval) const
{
typename S_spec<num_elem>::DataType R;
typename S_spec::DataType R;
solFEval.Eval(el, R);
for (int k = 0; k < num_elem; k++)
for (int k = 0; k < BE; k++)
{
kernel_t::MultAssembled(k, assembled_data[el+k], R);
kernel_t::MultAssembled(k, assembled_data[el/SS+k], R);
}
solFEval.template Assemble<true>(R);
}
// complex_t = double
template <int num_elem>
void MultAssembled(const Vector &x, Vector &y) const
{
y = 0.0;
@@ -229,14 +241,9 @@ public:
x.GetData(), y.GetData());
const int NE = mesh.GetNE();
const int bNE = NE-NE%num_elem;
for (int el = 0; el < bNE; el += num_elem)
for (int el = 0; el < NE; el += TE)
{
ElementAddMultAssembled<num_elem>(el, solFEval);
}
for (int el = bNE; el < NE; el++)
{
ElementAddMultAssembled<1>(el, solFEval);
ElementAddMultAssembled(el, solFEval);
}
}
@@ -249,10 +256,10 @@ public:
solVecLayout_type solVecLayout(this->solVecLayout);
solFESpace solFES(this->solFES);
TTensor3<dofs,vdim,1,complex_t> xy_dof;
TTensor3<dofs,vdim,BE,vcomplex_t> xy_dof;
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el++)
for (int el = 0; el < NE; el += TE)
{
solFES.SetElement(el);
@@ -266,17 +273,21 @@ public:
{
typedef typename meshType::FESpace_type meshFESpace;
meshFESpace meshFES(mesh.t_fes);
typedef TTensor3<meshFE_type::dofs,sdim,1,real_t> lnodes_t;
typedef TTensor3<meshFE_type::dofs,sdim,BE,vreal_t> lnodes_t;
const int NE = mesh.GetNE();
sNodes.SetSize(lnodes_t::size*NE);
real_t *lNodes = sNodes.GetData();
for (int el = 0; el < NE; el++)
// TODO: How do we make sure that this array is aligned properly, AND
// the compiler knows that it is aligned? => ALIGN_32|ALIGN_64 when ready
const int NVE = (NE+TE-1)/TE;
vreal_t *vsNodes = new vreal_t[lnodes_t::size*NVE];
sNodes.NewDataAndSize(vsNodes[0].vec, (lnodes_t::size*SS)*NVE);
sNodes.MakeDataOwner();
for (int el = 0; el < NE; el += TE)
{
meshFES.SetElement(el);
meshFES.VectorExtract(mesh.node_layout, mesh.Nodes,
lnodes_t::layout, lNodes);
lNodes += lnodes_t::size;
lnodes_t::layout, vsNodes);
vsNodes += lnodes_t::size;
}
}
@@ -284,45 +295,51 @@ public:
// real_t = double
void AssembleFromSerializedNodes(const Vector &sNodes)
{
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
Trans_t T(this->mesh, this->meshEval);
Trans_t T(mesh, meshEval);
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
if (!assembled_data)
if (assembled_data.Empty())
{
assembled_data = new p_assembled_t[NE];
const int size = ((NE+TE-1)/TE)*BE;
assembled_data.New(size, assembled_data.GetMemoryType());
}
for (int el = 0; el < NE; el++)
const vreal_t *vsNodes = (const vreal_t*)(sNodes.GetData());
for (int el = 0; el < NE; el += TE)
{
typename T_result<BE>::Type F;
T.EvalSerialized(el, sNodes.GetData(), F);
typename T_result::Type F;
T.EvalSerialized(el, vsNodes, F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
kernel_t::Assemble(0, F, wQ, res, assembled_data[el]);
for (int k = 0; k < BE; k++)
{
kernel_t::Assemble(k, F, wQ, res, assembled_data[el/SS+k]);
}
}
}
// complex_t = double
void Serialize(const Vector &x, Vector &sx) const
{
typedef TTensor3<dofs,vdim,BE,vcomplex_t> vdof_data_t;
solVecLayout_t solVecLayout(this->solVecLayout);
typedef TTensor3<dofs,vdim,1,complex_t> vdof_data_t;
solFESpace solFES(this->solFES);
const int NE = mesh.GetNE();
sx.SetSize(vdim*dofs*NE);
complex_t *loc_sx = sx.GetData();
for (int el = 0; el < NE; el++)
// TODO: How do we make sure that this array is aligned properly, AND
// the compiler knows that it is aligned? => ALIGN_32|ALIGN_64 when ready
const int NVE = (NE+TE-1)/TE;
vreal_t *vsx = new vreal_t[vdof_data_t::size*NVE];
sx.NewDataAndSize(vsx[0].vec, (vdof_data_t::size*SS)*NVE);
sx.MakeDataOwner();
for (int el = 0; el < NE; el += TE)
{
solFES.SetElement(el);
solFES.VectorExtract(solVecLayout, x, vdof_data_t::layout, loc_sx);
loc_sx += vdim*dofs;
solFES.VectorExtract(solVecLayout, x, vdof_data_t::layout, vsx);
vsx += vdof_data_t::size;
}
}
@@ -333,19 +350,23 @@ public:
solFieldEval solFEval(solFES, solEval, solVecLayout, NULL, NULL);
const int NE = mesh.GetNE();
const complex_t *loc_sx = sx.GetData();
complex_t *loc_sy = sy.GetData();
for (int el = 0; el < NE; el++)
const vreal_t *vsx = (const vreal_t*)(sx.GetData());
vreal_t *vsy = (vreal_t*)(sy.GetData());
for (int el = 0; el < NE; el += TE)
{
typename S_spec<1>::DataType R;
solFEval.EvalSerialized(loc_sx, R);
typename S_spec::DataType R;
solFEval.EvalSerialized(vsx, R);
kernel_t::MultAssembled(0, assembled_data[el], R);
for (int k = 0; k < BE; k++)
{
kernel_t::MultAssembled(k, assembled_data[el/SS+k], R);
}
solFEval.template AssembleSerialized<false>(R, loc_sy);
solFEval.template AssembleSerialized<false>(R, vsy);
loc_sx += vdim*dofs;
loc_sy += vdim*dofs;
vsx += vdim*dofs*BE;
vsy += vdim*dofs*BE;
}
}
#endif // MFEM_TEMPLATE_ENABLE_SERIALIZE
@@ -354,10 +375,6 @@ public:
// complex_t = double
void AssembleMatrix(SparseMatrix &M) const
{
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
Trans_t T(mesh, meshEval);
solFESpace solFES(this->solFES);
solShapeEval solEval(this->solEval);
@@ -365,29 +382,39 @@ public:
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el++)
for (int el = 0; el < NE; el += TE)
{
f_assembled_t asm_qpt_data;
f_assembled_t asm_qpt_data[BE];
{
typename T_result<BE>::Type F;
typename T_result::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
kernel_t::Assemble(0, F, wQ, res, asm_qpt_data);
for (int k = 0; k < BE; k++)
{
kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]);
}
}
// For now, when vdim > 1, assume block-diagonal matrix with the same
// diagonal block for all components.
TMatrix<dofs,dofs> M_loc;
S_spec<BE>::ElementMatrix::Compute(
asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval);
solFES.SetElement(el);
for (int bi = 0; bi < vdim; bi++)
for (int k = 0; k < BE; k++)
{
solFES.AssembleBlock(bi, bi, solVecLayout, M_loc, M);
const int el_k = el+SS*k;
if (el_k >= NE) { break; }
TMatrix<dofs,dofs,vcomplex_t> M_loc;
S_spec::ElementMatrix::Compute(
asm_qpt_data[k].layout, asm_qpt_data[k], M_loc.layout, M_loc,
solEval);
solFES.SetElement(el_k);
for (int bi = 0; bi < vdim; bi++)
{
solFES.AssembleBlock(bi, bi, solVecLayout, M_loc, M);
}
}
}
}
@@ -396,37 +423,52 @@ public:
// complex_t = double
void AssembleMatrix(DenseTensor &M) const
{
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
Trans_t T(mesh, meshEval);
solShapeEval solEval(this->solEval);
coeff_eval_t wQ(int_rule, coeff);
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el++)
for (int el = 0; el < NE; el += TE)
{
f_assembled_t asm_qpt_data;
f_assembled_t asm_qpt_data[BE];
{
typename T_result<BE>::Type F;
typename T_result::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
kernel_t::Assemble(0, F, wQ, res, asm_qpt_data);
for (int k = 0; k < BE; k++)
{
kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]);
}
}
// For now, when vdim > 1, assume block-diagonal matrix with the same
// diagonal block for all components.
// M is assumed to be (dof x dof x NE).
TMatrix<dofs,dofs> M_loc;
S_spec<BE>::ElementMatrix::Compute(
asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval);
for (int k = 0; k < BE; k++)
{
const int el_k = el+SS*k;
if (el_k >= NE) { break; }
complex_t *M_data = M.GetData(el);
M_loc.template AssignTo<AssignOp::Set>(M_data);
TMatrix<dofs,dofs,vcomplex_t> M_loc;
S_spec::ElementMatrix::Compute(
asm_qpt_data[k].layout, asm_qpt_data[k], M_loc.layout, M_loc,
solEval);
for (int s = 0; s < SS && el_k+s < NE; s++)
{
complex_t *M_data = M.GetData(el_k+s);
for (int j = 0; j < dofs; j++)
{
for (int i = 0; i < dofs; i++)
{
M_data[j+dofs*i] = M_loc(i,j)[s];
}
}
}
}
}
}
@@ -434,10 +476,6 @@ public:
// complex_t = double
void AssembleBilinearForm(BilinearForm &a) const
{
const int BE = 1; // batch-size of elements
typedef typename kernel_t::template
CoefficientEval<IR,coeff_t,BE>::Type coeff_eval_t;
Trans_t T(mesh, meshEval);
solShapeEval solEval(this->solEval);
coeff_eval_t wQ(int_rule, coeff);
@@ -448,55 +486,87 @@ public:
DenseMatrix M_loc_perm(dofs*vdim,dofs*vdim); // initialized with zeros
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el++)
for (int el = 0; el < NE; el += TE)
{
f_assembled_t asm_qpt_data;
f_assembled_t asm_qpt_data[BE];
{
typename T_result<BE>::Type F;
typename T_result::Type F;
T.Eval(el, F);
typename coeff_eval_t::result_t res;
wQ.Eval(F, res);
kernel_t::Assemble(0, F, wQ, res, asm_qpt_data);
for (int k = 0; k < BE; k++)
{
kernel_t::Assemble(k, F, wQ, res, asm_qpt_data[k]);
}
}
// For now, when vdim > 1, assume block-diagonal matrix with the same
// diagonal block for all components.
TMatrix<dofs,dofs> M_loc;
S_spec<BE>::ElementMatrix::Compute(
asm_qpt_data.layout, asm_qpt_data, M_loc.layout, M_loc, solEval);
if (dof_map) // switch from tensor-product ordering
for (int k = 0; k < BE; k++)
{
for (int i = 0; i < dofs; i++)
const int el_k = el+SS*k;
if (el_k >= NE) { break; }
TMatrix<dofs,dofs,vcomplex_t> M_loc;
S_spec::ElementMatrix::Compute(
asm_qpt_data[k].layout, asm_qpt_data[k], M_loc.layout, M_loc,
solEval);
if (dof_map) // switch from tensor-product ordering
{
for (int j = 0; j < dofs; j++)
for (int s = 0; s < SS && el_k+s < NE; s++)
{
M_loc_perm(dof_map_[i],dof_map_[j]) = M_loc(i,j);
for (int i = 0; i < dofs; i++)
{
for (int j = 0; j < dofs; j++)
{
M_loc_perm(dof_map_[i],dof_map_[j]) = M_loc(i,j)[s];
}
}
for (int bi = 1; bi < vdim; bi++)
{
M_loc_perm.CopyMN(M_loc_perm, dofs, dofs, 0, 0,
bi*dofs, bi*dofs);
}
a.AssembleElementMatrix(el_k+s, M_loc_perm, vdofs);
}
}
for (int bi = 1; bi < vdim; bi++)
else if (SS == 1)
{
M_loc_perm.CopyMN(M_loc_perm, dofs, dofs, 0, 0,
bi*dofs, bi*dofs);
}
a.AssembleElementMatrix(el, M_loc_perm, vdofs);
}
else
{
DenseMatrix DM(M_loc.data, dofs, dofs);
if (vdim == 1)
{
a.AssembleElementMatrix(el, DM, vdofs);
DenseMatrix DM(M_loc.data[0].vec, dofs, dofs);
if (vdim == 1)
{
a.AssembleElementMatrix(el_k, DM, vdofs);
}
else
{
for (int bi = 0; bi < vdim; bi++)
{
M_loc_perm.CopyMN(DM, dofs, dofs, 0, 0, bi*dofs, bi*dofs);
}
a.AssembleElementMatrix(el_k, M_loc_perm, vdofs);
}
}
else
{
for (int bi = 0; bi < vdim; bi++)
for (int s = 0; s < SS && el_k+s < NE; s++)
{
M_loc_perm.CopyMN(DM, dofs, dofs, 0, 0, bi*dofs, bi*dofs);
for (int i = 0; i < dofs; i++)
{
for (int j = 0; j < dofs; j++)
{
M_loc_perm(i,j) = M_loc(i,j)[s];
}
}
for (int bi = 1; bi < vdim; bi++)
{
M_loc_perm.CopyMN(M_loc_perm, dofs, dofs, 0, 0,
bi*dofs, bi*dofs);
}
a.AssembleElementMatrix(el_k+s, M_loc_perm, vdofs);
}
a.AssembleElementMatrix(el, M_loc_perm, vdofs);
}
}
}
@@ -513,7 +583,7 @@ public:
const int NE = mesh.GetNE();
for (int el = 0; el < NE; el++)
{
TTensor3<dofs,vdim,1,complex_t> x_dof, y_dof;
TTensor3<dofs,vdim,1,AutoSIMD<complex_t,1,1> > x_dof, y_dof;
solFES.SetElement(el);
solFES.VectorExtract(solVecLayout, x, x_dof.layout, x_dof);
+8 -8
View File
@@ -65,10 +65,10 @@ struct TMassKernel
template <int qpts>
struct f_asm_data { typedef TVector<qpts,complex_t> type; };
template <typename IR, typename coeff_t, int NE>
template <typename IR, typename coeff_t, typename impl_traits_t>
struct CoefficientEval
{
typedef typename IntRuleCoefficient<IR,coeff_t,NE>::Type Type;
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
};
// Method used for un-assembled (matrix free) action.
@@ -180,10 +180,10 @@ struct TDiffusionKernel<1,1,complex_t>
template <int qpts>
struct f_asm_data { typedef TTensor3<qpts,1,1,complex_t> type; };
template <typename IR, typename coeff_t, int NE>
template <typename IR, typename coeff_t, typename impl_traits_t>
struct CoefficientEval
{
typedef typename IntRuleCoefficient<IR,coeff_t,NE>::Type Type;
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
};
// Method used for un-assembled (matrix free) action.
@@ -293,10 +293,10 @@ struct TDiffusionKernel<2,2,complex_t>
template <int qpts>
struct f_asm_data { typedef TTensor3<qpts,2,2,complex_t> type; };
template <typename IR, typename coeff_t, int NE>
template <typename IR, typename coeff_t, typename impl_traits_t>
struct CoefficientEval
{
typedef typename IntRuleCoefficient<IR,coeff_t,NE>::Type Type;
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
};
// Method used for un-assembled (matrix free) action.
@@ -434,10 +434,10 @@ struct TDiffusionKernel<3,3,complex_t>
template <int qpts>
struct f_asm_data { typedef TTensor3<qpts,3,3,complex_t> type; };
template <typename IR, typename coeff_t, int NE>
template <typename IR, typename coeff_t, typename impl_traits_t>
struct CoefficientEval
{
typedef typename IntRuleCoefficient<IR,coeff_t,NE>::Type Type;
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
};
// Method used for un-assembled (matrix free) action.
+29 -8
View File
@@ -81,11 +81,15 @@ protected:
{
const int qpts = T_result_t::x_type::layout_type::dim_1;
const int ne = T_result_t::x_type::layout_type::dim_3;
const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]);
for (int k = 0; k < ne; k++)
{
for (int i = 0; i < qpts; i++)
{
c[l.ind(i,k)] = F.Eval1D(T.x(i,0,k));
for (int s = 0; s < vs; s++)
{
c[l.ind(i,k)][s] = F.Eval1D(T.x(i,0,k)[s]);
}
}
}
}
@@ -98,11 +102,15 @@ protected:
{
const int qpts = T_result_t::x_type::layout_type::dim_1;
const int ne = T_result_t::x_type::layout_type::dim_3;
const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]);
for (int k = 0; k < ne; k++)
{
for (int i = 0; i < qpts; i++)
{
c[l.ind(i,k)] = F.Eval2D(T.x(i,0,k), T.x(i,1,k));
for (int s = 0; s < vs; s++)
{
c[l.ind(i,k)][s] = F.Eval2D(T.x(i,0,k)[s], T.x(i,1,k)[s]);
}
}
}
}
@@ -115,11 +123,16 @@ protected:
{
const int qpts = T_result_t::x_type::layout_type::dim_1;
const int ne = T_result_t::x_type::layout_type::dim_3;
const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]);
for (int k = 0; k < ne; k++)
{
for (int i = 0; i < qpts; i++)
{
c[l.ind(i,k)] = F.Eval3D(T.x(i,0,k), T.x(i,1,k), T.x(i,2,k));
for (int s = 0; s < vs; s++)
{
c[l.ind(i,k)][s] =
F.Eval3D(T.x(i,0,k)[s], T.x(i,1,k)[s], T.x(i,2,k)[s]);
}
}
}
}
@@ -170,9 +183,16 @@ public:
void Eval(const T_result_t &T, const c_layout_t &l, c_data_t &c)
{
const int ne = T_result_t::ne;
const int vs = sizeof(T.attrib[0])/sizeof(T.attrib[0][0]);
MFEM_STATIC_ASSERT(vs == sizeof(c[0])/sizeof(c[0][0]), "");
for (int i = 0; i < ne; i++)
{
TAssign<AssignOp::Set>(l.ind2(i), c, constants(T.attrib[i]-1));
typename c_data_t::data_type ci;
for (int s = 0; s < vs; s++)
{
ci[s] = constants(T.attrib[i][s]-1);
}
TAssign<AssignOp::Set>(l.ind2(i), c, ci);
}
}
};
@@ -243,12 +263,13 @@ public:
/// Auxiliary class that is used to simplify the evaluation of a coefficient and
/// scaling it by the weights of a quadrature rule.
template <typename IR, typename coeff_t, int NE>
template <typename IR, typename coeff_t, typename impl_traits_t>
struct IntRuleCoefficient
{
static const int qpts = IR::qpts;
static const int ne = NE;
static const int ne = impl_traits_t::batch_size;
typedef typename coeff_t::complex_type complex_type;
typedef typename impl_traits_t::vcomplex_t vcomplex_t;
template <bool is_const, bool dummy> struct Aux;
@@ -277,7 +298,7 @@ struct IntRuleCoefficient
// non-constant coefficient
template <bool dummy> struct Aux<false,dummy>
{
typedef TMatrix<qpts,ne,complex_type> result_t;
typedef TMatrix<qpts,ne,vcomplex_t> result_t;
#ifdef MFEM_TEMPLATE_INTRULE_COEFF_PRECOMP
TMatrix<qpts,1,typename IR::real_type> w;
#else
@@ -312,7 +333,7 @@ struct IntRuleCoefficient
}
inline MFEM_ALWAYS_INLINE
const complex_type &get(const result_t &res, int i, int k) const
const vcomplex_t &get(const result_t &res, int i, int k) const
{
return res(i,k);
}
+96 -61
View File
@@ -64,9 +64,9 @@ public:
// Templated struct Result, used to specify the type result that is computed
// by the TElementTransformation::Eval() method and stored in this structure.
// The template parameter EvalOps is a sum (bitwise or) of constants from
// the enum EvalOperations. The parameter NE is the number of elements to be
// processed in the Eval() method.
template<int EvalOps, int NE> struct Result;
// the enum EvalOperations. The type impl_traits_t specifies additional
// parameters and types to be used by the Eval() method.
template<int EvalOps, typename impl_traits_t> struct Result;
static const int dim = Mesh_t::dim;
static const int sdim = Mesh_t::space_dim;
@@ -85,13 +85,17 @@ protected:
const Element* const *elements;
template <int NE>
template <typename vint_t, int NE>
inline MFEM_ALWAYS_INLINE
void SetAttributes(int el, int (&attrib)[NE]) const
void SetAttributes(int el, vint_t (&attrib)[NE]) const
{
const int vsize = sizeof(vint_t)/sizeof(attrib[0][0]);
for (int i = 0; i < NE; i++)
{
attrib[i] = elements[el+i]->GetAttribute();
for (int j = 0; j < vsize; i++)
{
attrib[i][j] = elements[el+j+i*vsize]->GetAttribute();
}
}
}
@@ -106,25 +110,30 @@ public:
{ }
// Evaluate coordinates and/or Jacobian matrices at quadrature points.
template<int EvalOps, int NE>
template<int EvalOps, typename impl_traits_t>
inline MFEM_ALWAYS_INLINE
void Eval(int el, Result<EvalOps,NE> &F)
void Eval(int el, Result<EvalOps,impl_traits_t> &F)
{
F.Eval(el, *this);
}
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
template<int EvalOps, int NE>
template<int EvalOps, typename impl_traits_t>
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, const real_t *nodeData, Result<EvalOps,NE> &F)
void EvalSerialized(int el, const typename impl_traits_t::vreal_t *nodeData,
Result<EvalOps,impl_traits_t> &F)
{
F.EvalSerialized(el, *this, nodeData);
}
#endif
template <int NE> struct Result<0,NE> // 0 = EvalNone
// Specialization of the Result<> class
// Case EvalOps = 0 = EvalNone
template <typename it_t> struct Result<0,it_t>
{
static const int ne = NE;
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
// x_type x;
// Jt_type Jt;
// int attrib[NE];
@@ -137,20 +146,23 @@ public:
}
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const real_t *nodeData) { }
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData) { }
#endif
};
template <int NE> struct Result<1,NE> // 1 = EvalCoordinates
// Case EvalOps = 1 = EvalCoordinates
template <typename it_t> struct Result<1,it_t>
{
static const int ne = NE;
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
typedef TTensor3<qpts,sdim,NE,real_t,true> x_type;
typedef TTensor3<qpts,sdim,NE,vreal_t,true> x_type;
#else
typedef TTensor3<qpts,sdim,NE,real_t/*,true*/> x_type;
typedef TTensor3<qpts,sdim,ne,vreal_t/*,true*/> x_type;
#endif
x_type x;
typedef TTensor3<dofs,sdim,NE,real_t> nodes_dof_t;
typedef TTensor3<dofs,sdim,ne,vreal_t> nodes_dof_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
nodes_dof_t nodes_dof;
#endif
@@ -159,8 +171,8 @@ public:
void Eval(int el, T_type &T)
{
#ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported");
TTensor3<dofs,sdim,1,real_t> &nodes_dof = T.nodes_dof;
MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported");
TTensor3<dofs,sdim,1,vreal_t> &nodes_dof = T.nodes_dof;
#elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES)
nodes_dof_t nodes_dof;
#endif
@@ -173,25 +185,30 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const real_t *nodeData)
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData)
{
const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]);
MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el);
T.evaluator.Calc(nodes_dof_t::layout.merge_23(),
&nodeData[el*nodes_dof_t::size],
&nodeData[el/SS*nodes_dof_t::size],
x.layout.merge_23(), x);
}
#endif
};
template <int NE> struct Result<2,NE> // 2 = EvalJacobians
// Case EvalOps = 2 = EvalJacobians
template <typename it_t> struct Result<2,it_t>
{
static const int ne = NE;
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
typedef TTensor4<qpts,dim,sdim,NE,real_t,true> Jt_type;
typedef TTensor4<qpts,dim,sdim,ne,vreal_t,true> Jt_type;
#else
typedef TTensor4<qpts,dim,sdim,NE,real_t/*,true*/> Jt_type;
typedef TTensor4<qpts,dim,sdim,ne,vreal_t/*,true*/> Jt_type;
#endif
Jt_type Jt;
typedef TTensor3<dofs,sdim,NE,real_t> nodes_dof_t;
typedef TTensor3<dofs,sdim,ne,vreal_t> nodes_dof_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
nodes_dof_t nodes_dof;
#endif
@@ -200,8 +217,8 @@ public:
void Eval(int el, T_type &T)
{
#ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported");
TTensor3<dofs,sdim,1,real_t> &nodes_dof = T.nodes_dof;
MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported");
TTensor3<dofs,sdim,1,vreal_t> &nodes_dof = T.nodes_dof;
#elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES)
nodes_dof_t nodes_dof;
#endif
@@ -214,27 +231,32 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const real_t *nodeData)
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData)
{
const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]);
MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el);
T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(),
&nodeData[el*nodes_dof_t::size],
&nodeData[el/SS*nodes_dof_t::size],
Jt.layout.merge_34(), Jt);
}
#endif
};
template <int NE> struct Result<3,NE> // 3 = EvalCoordinates|EvalJacobians
// Case EvalOps = 3 = EvalCoordinates|EvalJacobians
template <typename it_t> struct Result<3,it_t>
{
static const int ne = NE;
typedef TTensor3<qpts,sdim,NE,real_t,true> x_type;
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
typedef TTensor3<qpts,sdim,ne,vreal_t,true> x_type;
x_type x;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
typedef TTensor4<qpts,dim,sdim,NE,real_t,true> Jt_type;
typedef TTensor4<qpts,dim,sdim,ne,vreal_t,true> Jt_type;
#else
typedef TTensor4<qpts,dim,sdim,NE,real_t/*,true*/> Jt_type;
typedef TTensor4<qpts,dim,sdim,ne,vreal_t/*,true*/> Jt_type;
#endif
Jt_type Jt;
typedef TTensor3<dofs,sdim,NE,real_t> nodes_dof_t;
typedef TTensor3<dofs,sdim,ne,vreal_t> nodes_dof_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
nodes_dof_t nodes_dof;
#endif
@@ -243,8 +265,8 @@ public:
void Eval(int el, T_type &T)
{
#ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported");
TTensor3<dofs,sdim,1,real_t> &nodes_dof = T.nodes_dof;
MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported");
TTensor3<dofs,sdim,1,vreal_t> &nodes_dof = T.nodes_dof;
#elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES)
nodes_dof_t nodes_dof;
#endif
@@ -259,39 +281,45 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const real_t *nodeData)
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData)
{
const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]);
MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el);
T.evaluator.Calc(nodes_dof_t::layout.merge_23(),
&nodeData[el*nodes_dof_t::size],
&nodeData[el/SS*nodes_dof_t::size],
x.layout.merge_23(), x);
T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(),
&nodeData[el*nodes_dof_t::size],
&nodeData[el/SS*nodes_dof_t::size],
Jt.layout.merge_34(), Jt);
}
#endif
};
template <int NE> struct Result<6,NE> // 6 = EvalJacobians|LoadAttributes
// Case EvalOps = 6 = EvalJacobians|LoadAttributes
template <typename it_t> struct Result<6,it_t>
{
static const int ne = NE;
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
typedef typename it_t::vint_t vint_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
typedef TTensor4<qpts,dim,sdim,NE,real_t,true> Jt_type;
typedef TTensor4<qpts,dim,sdim,ne,vreal_t,true> Jt_type;
#else
typedef TTensor4<qpts,dim,sdim,NE,real_t/*,true*/> Jt_type;
typedef TTensor4<qpts,dim,sdim,ne,vreal_t/*,true*/> Jt_type;
#endif
Jt_type Jt;
typedef TTensor3<dofs,sdim,NE,real_t> nodes_dof_t;
typedef TTensor3<dofs,sdim,ne,vreal_t> nodes_dof_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
nodes_dof_t nodes_dof;
#endif
int attrib[NE];
vint_t attrib[ne];
inline MFEM_ALWAYS_INLINE
void Eval(int el, T_type &T)
{
#ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported");
TTensor3<dofs,sdim,1,real_t> &nodes_dof = T.nodes_dof;
MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported");
TTensor3<dofs,sdim,1,vreal_t> &nodes_dof = T.nodes_dof;
#elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES)
nodes_dof_t nodes_dof;
#endif
@@ -305,26 +333,31 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const real_t *nodeData)
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData)
{
const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]);
MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el);
T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(),
&nodeData[el*nodes_dof_t::size],
&nodeData[el/SS*nodes_dof_t::size],
Jt.layout.merge_34(), Jt);
T.SetAttributes(el, attrib);
}
#endif
};
template <int NE> struct Result<10,NE> // 10 = EvalJacobians|LoadElementIdxs
// Case EvalOps = 10 = EvalJacobians|LoadElementIdxs
template <typename it_t> struct Result<10,it_t>
{
static const int ne = NE;
static const int ne = it_t::batch_size;
typedef typename it_t::vreal_t vreal_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
typedef TTensor4<qpts,dim,sdim,NE,real_t,true> Jt_type;
typedef TTensor4<qpts,dim,sdim,ne,vreal_t,true> Jt_type;
#else
typedef TTensor4<qpts,dim,sdim,NE,real_t/*,true*/> Jt_type;
typedef TTensor4<qpts,dim,sdim,ne,vreal_t/*,true*/> Jt_type;
#endif
Jt_type Jt;
typedef TTensor3<dofs,sdim,NE,real_t> nodes_dof_t;
typedef TTensor3<dofs,sdim,ne,vreal_t> nodes_dof_t;
#ifdef MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES
nodes_dof_t nodes_dof;
#endif
@@ -334,8 +367,8 @@ public:
void Eval(int el, T_type &T)
{
#ifdef MFEM_TEMPLATE_ELTRANS_HAS_NODE_DOFS
MFEM_STATIC_ASSERT(NE == 1, "only NE == 1 is supported");
TTensor3<dofs,sdim,1,real_t> &nodes_dof = T.nodes_dof;
MFEM_STATIC_ASSERT(ne == 1, "only ne == 1 is supported");
TTensor3<dofs,sdim,1,vreal_t> &nodes_dof = T.nodes_dof;
#elif !defined(MFEM_TEMPLATE_ELTRANS_RESULT_HAS_NODES)
nodes_dof_t nodes_dof;
#endif
@@ -349,10 +382,12 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
inline MFEM_ALWAYS_INLINE
void EvalSerialized(int el, T_type &T, const real_t *nodeData)
void EvalSerialized(int el, T_type &T, const vreal_t *nodeData)
{
const int SS = sizeof(nodeData[0])/sizeof(nodeData[0][0]);
MFEM_ASSERT(el % (SS*ne) == 0, "invalid element index: " << el);
T.evaluator.CalcGrad(nodes_dof_t::layout.merge_23(),
&nodeData[el*nodes_dof_t::size],
&nodeData[el/SS*nodes_dof_t::size],
Jt.layout.merge_34(), Jt);
first_elem_idx = el;
}
+110 -83
View File
@@ -58,7 +58,7 @@ public:
// dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp).
template <typename dof_layout_t, typename dof_data_t,
typename qpt_layout_t, typename qpt_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
@@ -81,7 +81,7 @@ public:
template <bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename dof_layout_t, typename dof_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
@@ -103,7 +103,7 @@ public:
// dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp).
template <typename dof_layout_t, typename dof_data_t,
typename grad_layout_t, typename grad_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcGrad(const dof_layout_t &dof_layout,
const dof_data_t &dof_data,
const grad_layout_t &grad_layout,
@@ -129,7 +129,7 @@ public:
template <bool Add,
typename grad_layout_t, typename grad_data_t,
typename dof_layout_t, typename dof_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcGradT(const grad_layout_t &grad_layout,
const grad_data_t &grad_data,
const dof_layout_t &dof_layout,
@@ -154,7 +154,7 @@ public:
// qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp)
template <typename qpt_layout_t, typename qpt_data_t,
typename M_layout_t, typename M_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const M_layout_t &M_layout, M_data_t &M_data) const
{
@@ -178,14 +178,15 @@ public:
// D_layout is (DOF x DOF x NumComp).
template <typename qpt_layout_t, typename qpt_data_t,
typename D_layout_t, typename D_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void AssembleGradGrad(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
D_data_t &D_data) const
{
const int NC = qpt_layout_t::dim_4;
TTensor4<NIP,DIM,DOF,NC> F;
typedef typename qpt_data_t::data_type entry_type;
TTensor4<NIP,DIM,DOF,NC,entry_type> F;
for (int k = 0; k < NC; k++)
{
// Next loop performs a batch of matrix-matrix products of size
@@ -224,7 +225,7 @@ public:
// dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp).
template <typename dof_layout_t, typename dof_data_t,
typename qpt_layout_t, typename qpt_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
@@ -238,7 +239,7 @@ public:
template <bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename dof_layout_t, typename dof_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
@@ -251,7 +252,7 @@ public:
// dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp).
template <typename dof_layout_t, typename dof_data_t,
typename grad_layout_t, typename grad_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcGrad(const dof_layout_t &dof_layout,
const dof_data_t &dof_data,
const grad_layout_t &grad_layout,
@@ -268,7 +269,7 @@ public:
template <bool Add,
typename grad_layout_t, typename grad_data_t,
typename dof_layout_t, typename dof_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcGradT(const grad_layout_t &grad_layout,
const grad_data_t &grad_data,
const dof_layout_t &dof_layout,
@@ -285,7 +286,7 @@ public:
// qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp)
template <typename qpt_layout_t, typename qpt_data_t,
typename M_layout_t, typename M_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const M_layout_t &M_layout, M_data_t &M_data) const
{
@@ -309,7 +310,7 @@ public:
// D_layout is (DOF x DOF x NumComp).
template <typename qpt_layout_t, typename qpt_data_t,
typename D_layout_t, typename D_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void AssembleGradGrad(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
@@ -348,13 +349,14 @@ public:
template <bool Dx, bool Dy,
typename dof_layout_t, typename dof_data_t,
typename qpt_layout_t, typename qpt_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
const int NC = dof_layout_t::dim_2;
typedef typename qpt_data_t::data_type entry_type;
// DOF x DOF x NC --> NIP x DOF x NC --> NIP x NIP x NC
TTensor3<NIP,DOF,NC> A;
TTensor3<NIP,DOF,NC,entry_type> A;
// (1) A_{i,j,k} = \sum_s B_1d_{i,s} dof_data_{s,j,k}
Mult_2_1<false>(B_1d.layout, Dx ? G_1d : B_1d,
@@ -370,7 +372,7 @@ public:
// dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp).
template <typename dof_layout_t, typename dof_data_t,
typename qpt_layout_t, typename qpt_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
@@ -380,13 +382,14 @@ public:
template <bool Dx, bool Dy, bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename dof_layout_t, typename dof_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
const int NC = dof_layout_t::dim_2;
typedef typename qpt_data_t::data_type entry_type;
// NIP x NIP X NC --> NIP x DOF x NC --> DOF x DOF x NC
TTensor3<NIP,DOF,NC> A;
TTensor3<NIP,DOF,NC,entry_type> A;
// (1) A_{i,j,k} = \sum_s B_1d_{s,j} qpt_data_{i,s,k}
Mult_1_2<false>(B_1d.layout, Dy ? G_1d : B_1d,
@@ -403,7 +406,7 @@ public:
template <bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename dof_layout_t, typename dof_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
@@ -414,7 +417,7 @@ public:
// dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp).
template <typename dof_layout_t, typename dof_data_t,
typename grad_layout_t, typename grad_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcGrad(const dof_layout_t &dof_layout,
const dof_data_t &dof_data,
const grad_layout_t &grad_layout,
@@ -432,7 +435,7 @@ public:
template <bool Add,
typename grad_layout_t, typename grad_data_t,
typename dof_layout_t, typename dof_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcGradT(const grad_layout_t &grad_layout,
const grad_data_t &grad_data,
const dof_layout_t &dof_layout,
@@ -448,11 +451,12 @@ public:
// qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp)
template <typename qpt_layout_t, typename qpt_data_t,
typename M_layout_t, typename M_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const M_layout_t &M_layout, M_data_t &M_data) const
{
const int NC = qpt_layout_t::dim_2;
typedef typename qpt_data_t::data_type entry_type;
// Using TensorAssemble: <I,NIP,J> --> <DOF,I,DOF,J>
@@ -469,7 +473,7 @@ public:
TTensor3<DOF,NIP,DOF*NC>::layout, A,
M_layout.merge_23().template split_12<DOF,DOF,DOF,DOF*NC>(), M_data);
#elif 1
TTensor4<DOF,NIP,DOF,NC> A;
TTensor4<DOF,NIP,DOF,NC,entry_type> A;
// qpt_data<NIP1,NIP2,NC> --> A<DOF2,NIP1,DOF2,NC>
TensorAssemble<false>(
Bt_1d.layout, Bt_1d, B_1d.layout, B_1d,
@@ -510,14 +514,15 @@ public:
template <int D1, int D2, bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename D_layout_t, typename D_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
D_data_t &D_data) const
{
const int NC = qpt_layout_t::dim_2;
TTensor4<DOF,NIP,DOF,NC> A;
typedef typename qpt_data_t::data_type entry_type;
TTensor4<DOF,NIP,DOF,NC,entry_type> A;
// Using TensorAssemble: <I,NIP,J> --> <DOF,I,DOF,J>
@@ -531,7 +536,7 @@ public:
TensorAssemble<Add>(
Bt_1d.layout, D1 == 1 ? Bt_1d : Gt_1d,
B_1d.layout, D2 == 1 ? B_1d : G_1d,
TTensor3<DOF,NIP,DOF*NC>::layout, A,
A.layout.merge_34(), A,
D_layout.merge_23().template split_12<DOF,DOF,DOF,DOF*NC>(), D_data);
}
@@ -540,7 +545,7 @@ public:
// D_layout is (TDOF x TDOF x NumComp).
template <typename qpt_layout_t, typename qpt_data_t,
typename D_layout_t, typename D_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void AssembleGradGrad(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
@@ -624,13 +629,14 @@ public:
template <bool Dx, bool Dy, bool Dz,
typename dof_layout_t, typename dof_data_t,
typename qpt_layout_t, typename qpt_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
const int NC = dof_layout_t::dim_2;
TVector<NIP*DOF*DOF*NC> QDD;
TVector<NIP*NIP*DOF*NC> QQD;
typedef typename qpt_data_t::data_type entry_type;
TVector<NIP*DOF*DOF*NC,entry_type> QDD;
TVector<NIP*NIP*DOF*NC,entry_type> QQD;
// QDD_{i,jj,k} = \sum_s B_1d_{i,s} dof_data_{s,jj,k}
Mult_2_1<false>(B_1d.layout, Dx ? G_1d : B_1d,
@@ -650,7 +656,7 @@ public:
// dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp).
template <typename dof_layout_t, typename dof_data_t,
typename qpt_layout_t, typename qpt_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Calc(const dof_layout_t &dof_layout, const dof_data_t &dof_data,
const qpt_layout_t &qpt_layout, qpt_data_t &qpt_data) const
{
@@ -660,13 +666,14 @@ public:
template <bool Dx, bool Dy, bool Dz, bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename dof_layout_t, typename dof_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
const int NC = dof_layout_t::dim_2;
TVector<NIP*DOF*DOF*NC> QDD;
TVector<NIP*NIP*DOF*NC> QQD;
typedef typename qpt_data_t::data_type entry_type;
TVector<NIP*DOF*DOF*NC,entry_type> QDD;
TVector<NIP*NIP*DOF*NC,entry_type> QQD;
// QQD_{ii,j,k} = \sum_s B_1d_{s,j} qpt_data_{ii,s,k}
Mult_1_2<false>(B_1d.layout, Dz ? G_1d : B_1d,
@@ -687,7 +694,7 @@ public:
template <bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename dof_layout_t, typename dof_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcT(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const dof_layout_t &dof_layout, dof_data_t &dof_data) const
{
@@ -698,7 +705,7 @@ public:
// dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp).
template <typename dof_layout_t, typename dof_data_t,
typename grad_layout_t, typename grad_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcGrad(const dof_layout_t &dof_layout,
const dof_data_t &dof_data,
const grad_layout_t &grad_layout,
@@ -720,7 +727,7 @@ public:
template <bool Add,
typename grad_layout_t, typename grad_data_t,
typename dof_layout_t, typename dof_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void CalcGradT(const grad_layout_t &grad_layout,
const grad_data_t &grad_data,
const dof_layout_t &dof_layout,
@@ -738,13 +745,14 @@ public:
// qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp)
template <typename qpt_layout_t, typename qpt_data_t,
typename M_layout_t, typename M_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout, const qpt_data_t &qpt_data,
const M_layout_t &M_layout, M_data_t &M_data) const
{
const int NC = qpt_layout_t::dim_2;
TTensor4<DOF,NIP*NIP,DOF,NC> A1;
TTensor4<DOF,DOF*NIP,DOF,DOF*NC> A2;
typedef typename qpt_data_t::data_type entry_type;
TTensor4<DOF,NIP*NIP,DOF,NC,entry_type> A1;
TTensor4<DOF,DOF*NIP,DOF,DOF*NC,entry_type> A2;
// Using TensorAssemble: <I,NIP,J> --> <DOF,I,DOF,J>
@@ -788,15 +796,16 @@ public:
template <int D1, int D2, bool Add,
typename qpt_layout_t, typename qpt_data_t,
typename D_layout_t, typename D_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Assemble(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
D_data_t &D_data) const
{
const int NC = qpt_layout_t::dim_2;
TTensor4<DOF,NIP*NIP,DOF,NC> A1;
TTensor4<DOF,DOF*NIP,DOF,DOF*NC> A2;
typedef typename qpt_data_t::data_type entry_type;
TTensor4<DOF,NIP*NIP,DOF,NC,entry_type> A1;
TTensor4<DOF,DOF*NIP,DOF,DOF*NC,entry_type> A2;
// Using TensorAssemble: <I,NIP,J> --> <DOF,I,DOF,J>
@@ -824,7 +833,7 @@ public:
#if 0
template <typename qpt_layout_t, typename qpt_data_t,
typename D_layout_t, typename D_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void Assemble(int D1, int D2,
const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
@@ -864,7 +873,7 @@ public:
// D_layout is (TDOF x TDOF x NumComp).
template <typename qpt_layout_t, typename qpt_data_t,
typename D_layout_t, typename D_data_t>
MFEM_ALWAYS_INLINE
inline MFEM_ALWAYS_INLINE
void AssembleGradGrad(const qpt_layout_t &qpt_layout,
const qpt_data_t &qpt_data,
const D_layout_t &D_layout,
@@ -1055,7 +1064,7 @@ public:
void GetValues(int el, const val_layout_t &l, val_data_t &vals)
{
const int ne = val_layout_t::dim_3;
TTensor3<dofs,vdim,ne,complex_type> val_dofs;
TTensor3<dofs,vdim,ne,typename val_data_t::data_type> val_dofs;
SetElement(el);
fespace.VectorExtract(vec_layout, data_in, val_dofs.layout, val_dofs);
shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, l.merge_23(), vals);
@@ -1067,7 +1076,7 @@ public:
void GetGradients(int el, const grad_layout_t &l, grad_data_t &grad)
{
const int ne = grad_layout_t::dim_4;
TTensor3<dofs,vdim,ne,complex_type> val_dofs;
TTensor3<dofs,vdim,ne,typename grad_data_t::data_type> val_dofs;
SetElement(el);
fespace.VectorExtract(vec_layout, data_in, val_dofs.layout, val_dofs);
shapeEval.CalcGrad(val_dofs.layout.merge_23(), val_dofs,
@@ -1112,14 +1121,16 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
template <typename DataType>
inline MFEM_ALWAYS_INLINE
void EvalSerialized(const complex_t *loc_dofs, DataType &F)
void EvalSerialized(const typename DataType::vcomplex_t *loc_dofs,
DataType &F)
{
Action<DataType::InData,true>::EvalSerialized(*this, loc_dofs, F);
}
template <bool Add, typename DataType>
inline MFEM_ALWAYS_INLINE
void AssembleSerialized(const DataType &F, complex_t *loc_dofs)
void AssembleSerialized(const DataType &F,
typename DataType::vcomplex_t *loc_dofs)
{
Action<DataType::OutData,true>::
template AssembleSerialized<Add>(*this, F, loc_dofs);
@@ -1138,56 +1149,61 @@ public:
// Auxiliary templated struct AData, used by the Eval() and Assemble()
// methods. The template parameter IOData is "bitwise or" of constants from
// the enum InOutData. The parameter NE is the number of elements to be
// processed in the Eval() and Assemble() methods.
template<int IOData, int NE> struct AData;
// the enum InOutData. The type impl_traits_t specifies parameters and types
// to be used in the Eval() and Assemble() methods.
template<int IOData, typename impl_traits_t> struct AData;
template <int NE> struct AData<0,NE> // 0 = None
template <typename it_t> struct AData<0,it_t> // 0 = None
{
// Do we need this?
};
template <int NE> struct AData<1,NE> // 1 = Values
template <typename it_t> struct AData<1,it_t> // 1 = Values
{
static const int ne = it_t::batch_size;
typedef typename it_t::vcomplex_t vcomplex_t;
#ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS
typedef TTensor3<dofs,vdim,NE,complex_t,true> val_dofs_t;
typedef TTensor3<dofs,vdim,ne,vcomplex_t,true> val_dofs_t;
val_dofs_t val_dofs;
#else
typedef TTensor3<dofs,vdim,NE,complex_t> val_dofs_t;
typedef TTensor3<dofs,vdim,ne,vcomplex_t> val_dofs_t;
#endif
TTensor3<qpts,vdim,NE,complex_t> val_qpts;
TTensor3<qpts,vdim,ne,vcomplex_t> val_qpts;
};
template <int NE> struct AData<2,NE> // 2 = Gradients
template <typename it_t> struct AData<2,it_t> // 2 = Gradients
{
static const int ne = it_t::batch_size;
typedef typename it_t::vcomplex_t vcomplex_t;
#ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS
typedef TTensor3<dofs,vdim,NE,complex_t,true> val_dofs_t;
typedef TTensor3<dofs,vdim,ne,vcomplex_t,true> val_dofs_t;
val_dofs_t val_dofs;
#else
typedef TTensor3<dofs,vdim,NE,complex_t> val_dofs_t;
typedef TTensor3<dofs,vdim,ne,vcomplex_t> val_dofs_t;
#endif
TTensor4<qpts,dim,vdim,NE,complex_t> grad_qpts;
TTensor4<qpts,dim,vdim,ne,vcomplex_t> grad_qpts;
};
template <int NE> struct AData<3,NE> // 3 = Values+Gradients
template <typename it_t> struct AData<3,it_t> // 3 = Values+Gradients
{
static const int ne = it_t::batch_size;
typedef typename it_t::vcomplex_t vcomplex_t;
#ifdef MFEM_TEMPLATE_FIELD_EVAL_DATA_HAS_DOFS
typedef TTensor3<dofs,vdim,NE,complex_t,true> val_dofs_t;
typedef TTensor3<dofs,vdim,ne,vcomplex_t,true> val_dofs_t;
val_dofs_t val_dofs;
#else
typedef TTensor3<dofs,vdim,NE,complex_t> val_dofs_t;
typedef TTensor3<dofs,vdim,ne,vcomplex_t> val_dofs_t;
#endif
TTensor3<qpts, vdim,NE,complex_t,true> val_qpts;
TTensor4<qpts,dim,vdim,NE,complex_t> grad_qpts;
TTensor3<qpts, vdim,ne,vcomplex_t,true> val_qpts;
TTensor4<qpts,dim,vdim,ne,vcomplex_t> grad_qpts;
};
// This struct is similar to struct AData, adding separate static data
// members for the input (InData) and output (OutData) data types.
template <int IData, int OData, int NE>
struct BData : public AData<IData|OData,NE>
template <int IData, int OData, typename it_t>
struct BData : public AData<IData|OData,it_t>
{
typedef T_type eval_type;
static const int ne = NE;
static const int InData = IData;
static const int OutData = OData;
};
@@ -1238,7 +1254,9 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
template <typename AData_t>
static inline MFEM_ALWAYS_INLINE
void EvalSerialized(T_type &T, const complex_t *loc_dofs, AData_t &D)
void EvalSerialized(T_type &T,
const typename AData_t::vcomplex_t *loc_dofs,
AData_t &D)
{
T.shapeEval.Calc(AData_t::val_dofs_t::layout.merge_23(), loc_dofs,
D.val_qpts.layout.merge_23(), D.val_qpts);
@@ -1246,7 +1264,8 @@ public:
template <bool Add, typename AData_t>
static inline MFEM_ALWAYS_INLINE
void AssembleSerialized(T_type &T, const AData_t &D, complex_t *loc_dofs)
void AssembleSerialized(T_type &T, const AData_t &D,
typename AData_t::vcomplex_t *loc_dofs)
{
T.shapeEval.template CalcT<Add>(
D.val_qpts.layout.merge_23(), D.val_qpts,
@@ -1291,7 +1310,9 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
template <typename AData_t>
static inline MFEM_ALWAYS_INLINE
void EvalSerialized(T_type &T, const complex_t *loc_dofs, AData_t &D)
void EvalSerialized(T_type &T,
const typename AData_t::vcomplex_t *loc_dofs,
AData_t &D)
{
T.shapeEval.CalcGrad(AData_t::val_dofs_t::layout.merge_23(), loc_dofs,
D.grad_qpts.layout.merge_34(), D.grad_qpts);
@@ -1299,7 +1320,8 @@ public:
template <bool Add, typename AData_t>
static inline MFEM_ALWAYS_INLINE
void AssembleSerialized(T_type &T, const AData_t &D, complex_t *loc_dofs)
void AssembleSerialized(T_type &T, const AData_t &D,
typename AData_t::vcomplex_t *loc_dofs)
{
T.shapeEval.template CalcGradT<Add>(
D.grad_qpts.layout.merge_34(), D.grad_qpts,
@@ -1349,7 +1371,9 @@ public:
#ifdef MFEM_TEMPLATE_ENABLE_SERIALIZE
template <typename AData_t>
static inline MFEM_ALWAYS_INLINE
void EvalSerialized(T_type &T, const complex_t *loc_dofs, AData_t &D)
void EvalSerialized(T_type &T,
const typename AData_t::vcomplex_t *loc_dofs,
AData_t &D)
{
T.shapeEval.Calc(AData_t::val_dofs_t::layout.merge_23(), loc_dofs,
D.val_qpts.layout.merge_23(), D.val_qpts);
@@ -1359,7 +1383,8 @@ public:
template <bool Add, typename AData_t>
static inline MFEM_ALWAYS_INLINE
void AssembleSerialized(T_type &T, const AData_t &D, complex_t *loc_dofs)
void AssembleSerialized(T_type &T, const AData_t &D,
typename AData_t::vcomplex_t *loc_dofs)
{
T.shapeEval.template CalcT<Add>(
D.val_qpts.layout.merge_23(), D.val_qpts,
@@ -1373,12 +1398,13 @@ public:
// This struct implements element matrix computation for some combinations
// of input (InOps) and output (OutOps) operations.
template <int InOps, int OutOps, int NE> struct TElementMatrix;
template <int InOps, int OutOps, typename it_t> struct TElementMatrix;
template <int NE> struct TElementMatrix<1,1,NE> // 1,1 = Values,Values
// Case 1,1 = Values,Values
template <typename it_t> struct TElementMatrix<1,1,it_t>
{
// qpt_layout_t is (nip), M_layout_t is (dof x dof)
// NE = 1 is assumed
// it_t::batch_size = 1 is assumed
template <typename qpt_layout_t, typename qpt_data_t,
typename M_layout_t, typename M_data_t>
static inline MFEM_ALWAYS_INLINE
@@ -1390,10 +1416,11 @@ public:
}
};
template <int NE> struct TElementMatrix<2,2,NE> // 2,2 = Gradients,Gradients
// Case 2,2 = Gradients,Gradients
template <typename it_t> struct TElementMatrix<2,2,it_t>
{
// qpt_layout_t is (nip x dim x dim), M_layout_t is (dof x dof)
// NE = 1 is assumed
// it_t::batch_size = 1 is assumed
template <typename qpt_layout_t, typename qpt_data_t,
typename M_layout_t, typename M_data_t>
static inline MFEM_ALWAYS_INLINE
@@ -1405,15 +1432,15 @@ public:
}
};
template <typename kernel_t, int NE> struct Spec
template <typename kernel_t, typename impl_traits_t> struct Spec
{
static const int InData =
Values*kernel_t::in_values + Gradients*kernel_t::in_gradients;
static const int OutData =
Values*kernel_t::out_values + Gradients*kernel_t::out_gradients;
typedef BData<InData,OutData,NE> DataType;
typedef TElementMatrix<InData,OutData,NE> ElementMatrix;
typedef BData<InData,OutData,impl_traits_t> DataType;
typedef TElementMatrix<InData,OutData,impl_traits_t> ElementMatrix;
};
};
+96 -29
View File
@@ -114,18 +114,23 @@ class TFiniteElementSpace_simple
public:
typedef FE FE_type;
typedef IndexType index_type;
static const int dofs = FE::dofs;
protected:
index_type ind;
int num_elems, remain_elems;
public:
TFiniteElementSpace_simple(const FE &fe, const FiniteElementSpace &fes)
: ind(fe, fes) { }
: ind(fe, fes), num_elems(fes.GetNE()), remain_elems(num_elems) { }
// default copy constructor
void SetElement(int el) { ind.SetElement(el); }
int GetNE() const { return num_elems; }
void SetElement(int el) { ind.SetElement(el); remain_elems = num_elems-el; }
#if 0
// Multi-element Extract:
// Extract dofs for multiple elements starting with the current element.
// The number of elements to extract is given by the second dimension of
@@ -137,6 +142,7 @@ public:
const dof_layout_t &dof_layout,
dof_data_t &dof_data) const
{
const int SS = sizeof(dof_data[0])/sizeof(dof_data[0][0]);
const int NE = dof_layout_t::dim_2;
MFEM_STATIC_ASSERT(FE::dofs == dof_layout_t::dim_1,
"invalid number of dofs");
@@ -144,8 +150,11 @@ public:
{
for (int i = 0; i < FE::dofs; i++)
{
Assign<Op>(dof_data[dof_layout.ind(i,j)],
glob_dof_data[ind.map(i,j)]);
for (int s = 0; s < SS; s++)
{
Assign<Op>(dof_data[dof_layout.ind(i,j)][s],
glob_dof_data[ind.map(i,s+SS*j)]);
}
}
}
}
@@ -169,6 +178,7 @@ public:
const dof_data_t &dof_data,
glob_dof_data_t &glob_dof_data) const
{
const int SS = sizeof(dof_data[0])/sizeof(dof_data[0][0]);
const int NE = dof_layout_t::dim_2;
MFEM_STATIC_ASSERT(FE::dofs == dof_layout_t::dim_1,
"invalid number of dofs");
@@ -176,8 +186,11 @@ public:
{
for (int i = 0; i < FE::dofs; i++)
{
Assign<Op>(glob_dof_data[ind.map(i,j)],
dof_data[dof_layout.ind(i,j)]);
for (int s = 0; s < SS; s++)
{
Assign<Op>(glob_dof_data[ind.map(i,s+SS*j)],
dof_data[dof_layout.ind(i,j)][s]);
}
}
}
}
@@ -191,6 +204,7 @@ public:
{
Assemble<AssignOp::Add>(dof_layout, dof_data, glob_dof_data);
}
#endif
// Multi-element VectorExtract: vdof_layout is (DOFS x NumComp x NumElems).
template <AssignOp::Type Op,
@@ -202,21 +216,39 @@ public:
const vdof_layout_t &vdof_layout,
vdof_data_t &vdof_data) const
{
const int SS = sizeof(vdof_data[0])/sizeof(vdof_data[0][0]);
const int NC = vdof_layout_t::dim_2;
const int NE = vdof_layout_t::dim_3;
MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1,
"invalid number of dofs");
MFEM_ASSERT(NC == vl.NumComponents(), "invalid number of components");
const int TE = std::min(SS*NE, remain_elems);
// const int TE = SS*NE;
for (int k = 0; k < NC; k++)
{
#if 0
for (int j = 0; j < NE; j++)
{
for (int i = 0; i < FE::dofs; i++)
{
Assign<Op>(vdof_data[vdof_layout.ind(i,k,j)],
glob_vdof_data[vl.ind(ind.map(i,j), k)]);
for (int s = 0; s < SS; s++)
{
Assign<Op>(vdof_data[vdof_layout.ind(i,k,j)][s],
glob_vdof_data[vl.ind(ind.map(i,s+SS*j), k)]);
}
}
}
#else
for (int js = 0; js < TE; js++)
{
for (int i = 0; i < FE::dofs; i++)
{
const int s = js % SS, j = js / SS;
Assign<Op>(vdof_data[vdof_layout.ind(i,k,j)][s],
glob_vdof_data[vl.ind(ind.map(i,js), k)]);
}
}
#endif
}
}
@@ -241,21 +273,39 @@ public:
const vec_layout_t &vl,
glob_vdof_data_t &glob_vdof_data) const
{
const int SS = sizeof(vdof_data[0])/sizeof(vdof_data[0][0]);
const int NC = vdof_layout_t::dim_2;
const int NE = vdof_layout_t::dim_3;
MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1,
"invalid number of dofs");
MFEM_ASSERT(NC == vl.NumComponents(), "invalid number of components");
const int TE = std::min(SS*NE, remain_elems);
// const int TE = SS*NE;
for (int k = 0; k < NC; k++)
{
#if 0
for (int j = 0; j < NE; j++)
{
for (int i = 0; i < FE::dofs; i++)
{
Assign<Op>(glob_vdof_data[vl.ind(ind.map(i,j), k)],
vdof_data[vdof_layout.ind(i,k,j)]);
for (int s = 0; s < SS; s++)
{
Assign<Op>(glob_vdof_data[vl.ind(ind.map(i,s+SS*j), k)],
vdof_data[vdof_layout.ind(i,k,j)][s]);
}
}
}
#else
for (int js = 0; js < TE; js++)
{
for (int i = 0; i < FE::dofs; i++)
{
const int s = js % SS, j = js / SS;
Assign<Op>(glob_vdof_data[vl.ind(ind.map(i,js), k)],
vdof_data[vdof_layout.ind(i,k,j)][s]);
}
}
#endif
}
}
@@ -282,21 +332,24 @@ public:
const vdof_layout_t &vdof_layout,
vdof_data_t &vdof_data) const
{
const int SS = sizeof(vdof_data[0])/sizeof(vdof_data[0][0]);
const int NC = vdof_layout_t::dim_2;
const int NE = vdof_layout_t::dim_3;
const int TE = std::min(SS*NE, remain_elems);
MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1,
"invalid number of dofs");
MFEM_ASSERT(first_comp + NC <= vl.NumComponents(),
"invalid number of components");
for (int k = 0; k < NC; k++)
{
for (int j = 0; j < NE; j++)
for (int js = 0; js < TE; js++)
{
for (int i = 0; i < FE::dofs; i++)
{
const int s = js % SS, j = js / SS;
Assign<AssignOp::Set>(
vdof_data[vdof_layout.ind(i,k,j)],
glob_vdof_data[vl.ind(ind.map(i,j), first_comp+k)]);
vdof_data[vdof_layout.ind(i,k,j)][s],
glob_vdof_data[vl.ind(ind.map(i,js), first_comp+k)]);
}
}
}
@@ -314,55 +367,69 @@ public:
const vec_layout_t &vl,
glob_vdof_data_t &glob_vdof_data) const
{
const int SS = sizeof(vdof_data[0])/sizeof(vdof_data[0][0]);
const int NC = vdof_layout_t::dim_2;
const int NE = vdof_layout_t::dim_3;
const int TE = std::min(SS*NE, remain_elems);
MFEM_STATIC_ASSERT(FE::dofs == vdof_layout_t::dim_1,
"invalid number of dofs");
MFEM_ASSERT(first_comp + NC <= vl.NumComponents(),
"invalid number of components");
for (int k = 0; k < NC; k++)
{
for (int j = 0; j < NE; j++)
for (int js = 0; js < TE; js++)
{
for (int i = 0; i < FE::dofs; i++)
{
const int s = js % SS, j = js / SS;
Assign<AssignOp::Add>(
glob_vdof_data[vl.ind(ind.map(i,j), first_comp+k)],
vdof_data[vdof_layout.ind(i,k,j)]);
glob_vdof_data[vl.ind(ind.map(i,js), first_comp+k)],
vdof_data[vdof_layout.ind(i,k,j)][s]);
}
}
}
}
void Assemble(const TMatrix<FE::dofs,FE::dofs,double> &m,
template <typename vcomplex_t>
void Assemble(const TMatrix<FE::dofs,FE::dofs,vcomplex_t> &m,
SparseMatrix &M) const
{
const int SS = sizeof(m[0])/sizeof(m[0][0]);
const int TE = std::min(SS, remain_elems);
MFEM_FLOPS_ADD(FE::dofs*FE::dofs);
for (int i = 0; i < FE::dofs; i++)
for (int s = 0; s < TE; s++)
{
M.SetColPtr(ind.map(i,0));
for (int j = 0; j < FE::dofs; j++)
for (int i = 0; i < FE::dofs; i++)
{
M._Add_(ind.map(j,0), m(i,j));
M.SetColPtr(ind.map(i,s));
for (int j = 0; j < FE::dofs; j++)
{
M._Add_(ind.map(j,s), m(i,j)[s]);
}
M.ClearColPtr();
}
M.ClearColPtr();
}
}
template <typename vec_layout_t>
template <typename vec_layout_t, typename vcomplex_t>
void AssembleBlock(int block_i, int block_j, const vec_layout_t &vl,
const TMatrix<FE::dofs,FE::dofs,double> &m,
const TMatrix<FE::dofs,FE::dofs,vcomplex_t> &m,
SparseMatrix &M) const
{
const int SS = sizeof(m[0])/sizeof(m[0][0]);
const int TE = std::min(SS, remain_elems);
MFEM_FLOPS_ADD(FE::dofs*FE::dofs);
for (int i = 0; i < FE::dofs; i++)
for (int s = 0; s < TE; s++)
{
M.SetColPtr(vl.ind(ind.map(i,0), block_i));
for (int j = 0; j < FE::dofs; j++)
for (int i = 0; i < FE::dofs; i++)
{
M._Add_(vl.ind(ind.map(j,0), block_j), m(i,j));
M.SetColPtr(vl.ind(ind.map(i,s), block_i));
for (int j = 0; j < FE::dofs; j++)
{
M._Add_(vl.ind(ind.map(j,s), block_j), m(i,j)[s]);
}
M.ClearColPtr();
}
M.ClearColPtr();
}
}
};
+338 -53
View File
@@ -941,6 +941,7 @@ void AnalyticAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
IsoparametricTransformation Tpr;
Tpr.SetFE(&fe);
Tpr.ElementNo = e_id;
Tpr.ElementType = ElementTransformation::ELEMENT;
Tpr.GetPointMat().Transpose(point_mat);
for (int i = 0; i < ir.GetNPoints(); i++)
@@ -957,42 +958,176 @@ void AnalyticAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
}
#ifdef MFEM_USE_MPI
void DiscreteAdaptTC::SetParDiscreteTargetSpec(ParGridFunction &tspec_)
void DiscreteAdaptTC::FinalizeParDiscreteTargetSpec(const ParGridFunction
&tspec_)
{
tspec.SetSize(tspec_.Size());
tspec = tspec_;
tspec_fes = tspec_.FESpace();
MFEM_VERIFY(adapt_eval, "SetAdaptivityEvaluator() has not been called!")
MFEM_VERIFY(ncomp > 0, "No target specifications have been set!");
if (!adapt_eval) { MFEM_ABORT("Set adaptivity evaluator\n"); }
ParFiniteElementSpace *ptspec_fes = tspec_.ParFESpace();
adapt_eval->SetParMetaInfo(*tspec_.ParFESpace()->GetParMesh(),
*tspec_.FESpace()->FEColl(),
tspec_.FESpace()->GetVDim());
adapt_eval->SetInitialField
(*tspec_.FESpace()->GetMesh()->GetNodes(), tspec);
adapt_eval->SetParMetaInfo(*ptspec_fes->GetParMesh(),
*ptspec_fes->FEColl(), ncomp);
adapt_eval->SetInitialField(*tspec_fes->GetMesh()->GetNodes(), tspec);
tspec_sav = tspec;
delete tspec_fesv;
tspec_fesv = new FiniteElementSpace(tspec_fes->GetMesh(),
tspec_fes->FEColl(), ncomp);
}
void DiscreteAdaptTC::SetTspecAtIndex(int idx, const ParGridFunction &tspec_)
{
const int vdim = tspec_.FESpace()->GetVDim(),
dof_cnt = tspec_.Size()/vdim;
for (int i = 0; i < dof_cnt*vdim; i++)
{
tspec(i+idx*dof_cnt) = tspec_(i);
}
FinalizeParDiscreteTargetSpec(tspec_);
}
void DiscreteAdaptTC::SetParDiscreteTargetSize(const ParGridFunction &tspec_)
{
if (sizeidx > -1) { SetTspecAtIndex(sizeidx, tspec_); return; }
sizeidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeParDiscreteTargetSpec(tspec_);
}
void DiscreteAdaptTC::SetParDiscreteTargetSkew(const ParGridFunction &tspec_)
{
if (skewidx > -1) { SetTspecAtIndex(skewidx, tspec_); return; }
skewidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeParDiscreteTargetSpec(tspec_);
}
void DiscreteAdaptTC::SetParDiscreteTargetAspectRatio(const ParGridFunction
&tspec_)
{
if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, tspec_); return; }
aspectratioidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeParDiscreteTargetSpec(tspec_);
}
void DiscreteAdaptTC::SetParDiscreteTargetOrientation(const ParGridFunction
&tspec_)
{
if (orientationidx > -1) { SetTspecAtIndex(orientationidx, tspec_); return; }
orientationidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeParDiscreteTargetSpec(tspec_);
}
void DiscreteAdaptTC::SetParDiscreteTargetSpec(const ParGridFunction &tspec_)
{
SetParDiscreteTargetSize(tspec_);
FinalizeParDiscreteTargetSpec(tspec_);
}
#endif
void DiscreteAdaptTC::SetSerialDiscreteTargetSpec(GridFunction &tspec_)
void DiscreteAdaptTC::SetDiscreteTargetBase(const GridFunction &tspec_)
{
tspec.SetSize(tspec_.Size());
tspec = tspec_;
tspec_fes = tspec_.FESpace();
const int vdim = tspec_.FESpace()->GetVDim(),
dof_cnt = tspec_.Size()/vdim;
if (!adapt_eval) { MFEM_ABORT("Set adaptivity evaluator\n"); }
ncomp += vdim;
adapt_eval->SetSerialMetaInfo(*tspec_.FESpace()->GetMesh(),
*tspec_.FESpace()->FEColl(),
tspec_.FESpace()->GetVDim());
adapt_eval->SetInitialField
(*tspec_.FESpace()->GetMesh()->GetNodes(), tspec);
delete tspec_fes;
tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(),
tspec_.FESpace()->FEColl(), 1);
// need to append data to tspec
// make a copy of tspec->tspec_temp, increase its size, and
// copy data from tspec_temp -> tspec, then add new entries
Vector tspec_temp = tspec;
tspec.SetSize(ncomp*dof_cnt);
for (int i = 0; i < tspec_temp.Size(); i++)
{
tspec(i) = tspec_temp(i);
}
for (int i = 0; i < dof_cnt*vdim; i++)
{
tspec(i+(ncomp-vdim)*dof_cnt) = tspec_(i);
}
}
void DiscreteAdaptTC::SetTspecAtIndex(int idx, const GridFunction &tspec_)
{
const int vdim = tspec_.FESpace()->GetVDim(),
dof_cnt = tspec_.Size()/vdim;
for (int i = 0; i < dof_cnt*vdim; i++)
{
tspec(i+idx*dof_cnt) = tspec_(i);
}
FinalizeSerialDiscreteTargetSpec();
}
void DiscreteAdaptTC::SetSerialDiscreteTargetSize(const GridFunction &tspec_)
{
if (sizeidx > -1) { SetTspecAtIndex(sizeidx, tspec_); return; }
sizeidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeSerialDiscreteTargetSpec();
}
void DiscreteAdaptTC::SetSerialDiscreteTargetSkew(const GridFunction &tspec_)
{
if (skewidx > -1) { SetTspecAtIndex(skewidx, tspec_); return; }
skewidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeSerialDiscreteTargetSpec();
}
void DiscreteAdaptTC::SetSerialDiscreteTargetAspectRatio(
const GridFunction &tspec_)
{
if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, tspec_); return; }
aspectratioidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeSerialDiscreteTargetSpec();
}
void DiscreteAdaptTC::SetSerialDiscreteTargetOrientation(
const GridFunction &tspec_)
{
if (orientationidx > -1) { SetTspecAtIndex(orientationidx, tspec_); return; }
orientationidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeSerialDiscreteTargetSpec();
}
void DiscreteAdaptTC::FinalizeSerialDiscreteTargetSpec()
{
MFEM_VERIFY(adapt_eval, "SetAdaptivityEvaluator() has not been called!")
MFEM_VERIFY(ncomp > 0, "No target specifications have been set!");
adapt_eval->SetSerialMetaInfo(*tspec_fes->GetMesh(),
*tspec_fes->FEColl(), ncomp);
adapt_eval->SetInitialField(*tspec_fes->GetMesh()->GetNodes(), tspec);
tspec_sav = tspec;
delete tspec_fesv;
tspec_fesv = new FiniteElementSpace(tspec_fes->GetMesh(),
tspec_fes->FEColl(), ncomp);
}
void DiscreteAdaptTC::SetSerialDiscreteTargetSpec(const GridFunction &tspec_)
{
SetSerialDiscreteTargetSize(tspec_);
FinalizeSerialDiscreteTargetSpec();
}
void DiscreteAdaptTC::UpdateTargetSpecification(const Vector &new_x,
bool use_flag)
{
@@ -1020,8 +1155,12 @@ void DiscreteAdaptTC::UpdateTargetSpecificationAtNode(const FiniteElement &el,
Array<int> dofs;
tspec_fes->GetElementDofs(T.ElementNo, dofs);
int cnt = tspec.Size();
tspec(dofs[dofidx]) = IntData(dofs[dofidx]+dir*cnt);
const int cnt = tspec.Size()/ncomp; //dofs per scalar-field
for (int i = 0; i < ncomp; i++)
{
tspec(dofs[dofidx]+i*cnt) = IntData(dofs[dofidx] + i*cnt + dir*cnt*ncomp);
}
}
void DiscreteAdaptTC::RestoreTargetSpecificationAtNode(ElementTransformation &T,
@@ -1031,7 +1170,11 @@ void DiscreteAdaptTC::RestoreTargetSpecificationAtNode(ElementTransformation &T,
Array<int> dofs;
tspec_fes->GetElementDofs(T.ElementNo, dofs);
tspec(dofs[dofidx]) = tspec_sav(dofs[dofidx]);
const int cnt = tspec.Size()/ncomp;
for (int i = 0; i < ncomp; i++)
{
tspec(dofs[dofidx] + i*cnt) = tspec_sav(dofs[dofidx] + i*cnt);
}
}
void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
@@ -1039,37 +1182,176 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
const Vector &elfun,
DenseTensor &Jtr) const
{
MFEM_VERIFY(tspec_fes, "A call to SetDiscreteTargerSpec() is needed.");
MFEM_VERIFY(tspec_fesv, "No target specifications have been set.");
switch (target_type)
{
case IDEAL_SHAPE_GIVEN_SIZE:
case GIVEN_SHAPE_AND_SIZE:
{
const DenseMatrix &Wideal =
Geometries.GetGeomToPerfGeomJac(fe.GetGeomType());
const int dim = Wideal.Height(),
ntspec_dofs = tspec_fes->GetFE(0)->GetDof();
ndofs = tspec_fes->GetFE(0)->GetDof(),
ntspec_dofs = ndofs*ncomp;
Vector shape(ndofs), tspec_vals(ntspec_dofs), par_vals,
par_vals_c1(ndofs), par_vals_c2(ndofs), par_vals_c3(ndofs);
Vector shape(ntspec_dofs), tspec_vals(ntspec_dofs);
Array<int> dofs;
tspec_fes->GetElementDofs(e_id, dofs);
DenseMatrix D_rho(dim), Q_phi(dim), R_theta(dim);
tspec_fesv->GetElementVDofs(e_id, dofs);
tspec.GetSubVector(dofs, tspec_vals);
const double min_size = tspec_vals.Min();
MFEM_ASSERT(min_size > 0.0,
"Non-positive size propagated in the target definition.");
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
tspec_fes->GetFE(e_id)->CalcShape(ip, shape);
const double size = std::max(shape * tspec_vals, min_size);
Jtr(i).Set(std::pow(size / Wideal.Det(), 1.0/dim), Wideal);
Jtr(i) = Wideal; //Initialize to identity
if (sizeidx != -1) //Set size
{
par_vals.SetDataAndSize(tspec_vals.GetData()+sizeidx*ndofs, ndofs);
const double min_size = par_vals.Min();
MFEM_VERIFY(min_size > 0.0,
"Non-positive size propagated in the target definition.");
const double size = std::max(shape * par_vals, min_size);
Jtr(i).Set(std::pow(size, 1.0/dim), Jtr(i));
} //Done size
if (target_type == IDEAL_SHAPE_GIVEN_SIZE) { continue; }
if (aspectratioidx != -1) //Set aspect ratio
{
if (dim == 2)
{
par_vals.SetDataAndSize(tspec_vals.GetData()+
aspectratioidx*ndofs, ndofs);
const double aspectratio = shape * par_vals;
D_rho = 0.;
D_rho(0,0) = 1./pow(aspectratio,0.5);
D_rho(1,1) = pow(aspectratio,0.5);
}
else
{
par_vals.SetDataAndSize(tspec_vals.GetData()+
aspectratioidx*ndofs, ndofs*3);
par_vals_c1.SetData(par_vals.GetData());
par_vals_c2.SetData(par_vals.GetData()+ndofs);
par_vals_c3.SetData(par_vals.GetData()+2*ndofs);
const double rho1 = shape * par_vals_c1;
const double rho2 = shape * par_vals_c2;
const double rho3 = shape * par_vals_c3;
D_rho = 0.;
D_rho(0,0) = pow(rho1,2./3.);
D_rho(1,1) = pow(rho2,2./3.);
D_rho(2,2) = pow(rho3,2./3.);
}
DenseMatrix Temp = Jtr(i);
Mult(D_rho, Temp, Jtr(i));
} //Done aspect ratio
if (skewidx != -1) //Set skew
{
if (dim == 2)
{
par_vals.SetDataAndSize(tspec_vals.GetData()+
skewidx*ndofs, ndofs);
const double skew = shape * par_vals;
Q_phi = 0.;
Q_phi(0,0) = 1.;
Q_phi(0,1) = cos(skew);
Q_phi(1,1) = sin(skew);
}
else
{
par_vals.SetDataAndSize(tspec_vals.GetData()+
skewidx*ndofs, ndofs*3);
par_vals_c1.SetData(par_vals.GetData());
par_vals_c2.SetData(par_vals.GetData()+ndofs);
par_vals_c3.SetData(par_vals.GetData()+2*ndofs);
const double phi12 = shape * par_vals_c1;
const double phi13 = shape * par_vals_c2;
const double chi = shape * par_vals_c3;
Q_phi = 0.;
Q_phi(0,0) = 1.;
Q_phi(0,1) = cos(phi12);
Q_phi(0,2) = cos(phi13);
Q_phi(1,1) = sin(phi12);
Q_phi(1,2) = sin(phi13)*cos(chi);
Q_phi(2,2) = sin(phi13)*sin(chi);
}
DenseMatrix Temp = Jtr(i);
Mult(Q_phi, Temp, Jtr(i));
} // done skew
if (orientationidx != -1) //Set orientation
{
if (dim == 2)
{
par_vals.SetDataAndSize(tspec_vals.GetData()+
orientationidx*ndofs, ndofs);
const double theta = shape * par_vals;
R_theta(0,0) = cos(theta);
R_theta(0,1) = -sin(theta);
R_theta(1,0) = sin(theta);
R_theta(1,1) = cos(theta);
}
else
{
par_vals.SetDataAndSize(tspec_vals.GetData()+
orientationidx*ndofs, ndofs*3);
par_vals_c1.SetData(par_vals.GetData());
par_vals_c2.SetData(par_vals.GetData()+ndofs);
par_vals_c3.SetData(par_vals.GetData()+2*ndofs);
const double theta = shape * par_vals_c1;
const double psi = shape * par_vals_c2;
const double beta = shape * par_vals_c3;
DenseMatrix R_tp(dim), R_beta(dim), R_theta(dim);
double ct = cos(theta), st = sin(theta),
cp = cos(psi), sp = sin(psi);
R_tp(0,0) = ct*sp;
R_tp(1,0) = st*sp;
R_tp(2,0) = cp;
R_tp(0,1) = -(ct*st*sp*sp)/(1+cp);
R_tp(1,1) = cp+(pow(ct,2.)*pow(sp,2.))/(1+cp);
R_tp(2,1) = -st*sp;
R_tp(0,2) = -cp-(pow(st,2.)*pow(sp,2.))/(1+cp);
R_tp(1,2) = -R_tp(0,1);
R_tp(2,2) = ct*sp;
R_beta = 0.;
R_beta(0,0) = 1.;
R_beta(1,1) = cos(beta);
R_beta(1,2) = -sin(beta);
R_beta(2,1) = sin(beta);
R_beta(2,2) = cos(beta);
Mult(R_tp, R_beta, R_theta);
}
DenseMatrix Temp = Jtr(i);
Mult(R_theta, Temp, Jtr(i));
} // done orientation
}
break;
}
default:
MFEM_ABORT("Incompatible target type for analytic adaptation!");
MFEM_ABORT("Incompatible target type for discrete adaptation!");
}
}
@@ -1079,13 +1361,10 @@ void DiscreteAdaptTC::UpdateGradientTargetSpecification(const Vector &x,
{
if (use_flag && good_tspec_grad) { return; }
const int dim = tspec_fes->GetFE(0)->GetDim();
const int cnt = x.Size()/dim;
const int dim = tspec_fes->GetFE(0)->GetDim(),
cnt = x.Size()/dim;
if (tspec_pert1h.Size() != x.Size())
{
tspec_pert1h.SetSize(x.Size());
}
tspec_pert1h.SetSize(x.Size()*ncomp);
Vector TSpecTemp;
Vector xtemp = x;
@@ -1093,7 +1372,7 @@ void DiscreteAdaptTC::UpdateGradientTargetSpecification(const Vector &x,
{
for (int i = 0; i < cnt; i++) { xtemp(j*cnt+i) += dx; }
TSpecTemp.SetDataAndSize(tspec_pert1h.GetData() + j*cnt, cnt);
TSpecTemp.NewDataAndSize(tspec_pert1h.GetData() + j*cnt*ncomp, cnt*ncomp);
UpdateTargetSpecification(xtemp, TSpecTemp);
for (int i = 0; i < cnt; i++) { xtemp(j*cnt+i) -= dx; }
@@ -1105,16 +1384,15 @@ void DiscreteAdaptTC::UpdateGradientTargetSpecification(const Vector &x,
void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x,
double dx, bool use_flag)
{
if (use_flag && good_tspec_hess) { return; }
const int dim = tspec_fes->GetFE(0)->GetDim();
const int cnt = x.Size()/dim;
const int dim = tspec_fes->GetFE(0)->GetDim(),
cnt = x.Size()/dim,
totmix = 1+2*(dim-2);
if (tspec_pert2h.Size() != x.Size())
{
tspec_pert2h.SetSize(x.Size());
tspec_pertmix.SetSize(cnt*(1+2*(dim-2)));
}
tspec_pert2h.SetSize(cnt*dim*ncomp);
tspec_pertmix.SetSize(cnt*totmix*ncomp);
Vector TSpecTemp;
Vector xtemp = x;
@@ -1124,14 +1402,14 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x,
{
for (int i = 0; i < cnt; i++) { xtemp(j*cnt+i) += 2*dx; }
TSpecTemp.SetDataAndSize(tspec_pert2h.GetData() + j*cnt, cnt);
TSpecTemp.NewDataAndSize(tspec_pert2h.GetData() + j*cnt*ncomp, cnt*ncomp);
UpdateTargetSpecification(xtemp, TSpecTemp);
for (int i = 0; i < cnt; i++) { xtemp(j*cnt+i) -= 2*dx; }
}
// T(x+h,y+h)
int idx = 0;
int j = 0;
for (int k1 = 0; k1 < dim; k1++)
{
for (int k2 = 0; (k1 != k2) && (k2 < dim); k2++)
@@ -1142,7 +1420,7 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x,
xtemp(k2*cnt+i) += dx;
}
TSpecTemp.SetDataAndSize(tspec_pertmix.GetData() + idx*cnt, cnt);
TSpecTemp.NewDataAndSize(tspec_pertmix.GetData() + j*cnt*ncomp, cnt*ncomp);
UpdateTargetSpecification(xtemp, TSpecTemp);
for (int i = 0; i < cnt; i++)
@@ -1150,7 +1428,7 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x,
xtemp(k1*cnt+i) -= dx;
xtemp(k2*cnt+i) -= dx;
}
idx++;
j++;
}
}
@@ -1165,6 +1443,8 @@ void AdaptivityEvaluator::SetSerialMetaInfo(const Mesh &m,
delete mesh;
mesh = new Mesh(m, true);
fes = new FiniteElementSpace(mesh, &fec, num_comp);
dim = fes->GetFE(0)->GetDim();
ncomp = num_comp;
}
#ifdef MFEM_USE_MPI
@@ -1176,6 +1456,8 @@ void AdaptivityEvaluator::SetParMetaInfo(const ParMesh &m,
delete pmesh;
pmesh = new ParMesh(m, true);
pfes = new ParFiniteElementSpace(pmesh, &fec, num_comp);
dim = pfes->GetFE(0)->GetDim();
ncomp = num_comp;
}
#endif
@@ -1267,6 +1549,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
Tpr = new IsoparametricTransformation;
Tpr->SetFE(&el);
Tpr->ElementNo = T.ElementNo;
Tpr->ElementType = ElementTransformation::ELEMENT;
Tpr->Attribute = T.Attribute;
Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
}
@@ -1391,6 +1674,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
Tpr = new IsoparametricTransformation;
Tpr->SetFE(&el);
Tpr->ElementNo = T.ElementNo;
Tpr->ElementType = ElementTransformation::ELEMENT;
Tpr->Attribute = T.Attribute;
Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
}
@@ -1484,6 +1768,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
Tpr = new IsoparametricTransformation;
Tpr->SetFE(&el);
Tpr->ElementNo = T.ElementNo;
Tpr->ElementType = ElementTransformation::ELEMENT;
Tpr->Attribute = T.Attribute;
Tpr->GetPointMat().Transpose(PMatI);
}
+47 -4
View File
@@ -560,6 +560,8 @@ protected:
ParFiniteElementSpace *pfes;
#endif
int dim, ncomp;
public:
AdaptivityEvaluator() : mesh(NULL), fes(NULL)
{
@@ -708,15 +710,20 @@ class DiscreteAdaptTC : public TargetConstructor
protected:
// Discrete target specification.
// Data is owned, updated by UpdateTargetSpecification.
int ncomp, sizeidx, skewidx, aspectratioidx, orientationidx;
Vector tspec; //eta(x)
Vector tspec_sav;
Vector tspec_pert1h; //eta(x+h)
Vector tspec_pert2h; //eta(x+2*h)
Vector tspec_pertmix; //eta(x+h,y+h)
// The order inside these perturbation vectors (e.g. in 2D) is
// eta1(x+h,y), eta2(x+h,y) ... etan(x+h,y), eta1(x,y+h), eta2(x,y+h) ...
// same for tspec_pert2h and tspec_pertmix.
// Note: do not use the Nodes of this space as they may not be on the
// positions corresponding to the values of tspec.
const FiniteElementSpace *tspec_fes;
const FiniteElementSpace *tspec_fesv;
// These flags can be used by outside functions to avoid recomputing
// the tspec and tspec_perth fields again on the same mesh.
@@ -726,20 +733,55 @@ protected:
// Owned.
AdaptivityEvaluator *adapt_eval;
void SetDiscreteTargetBase(const GridFunction &tspec_);
void SetTspecAtIndex(int idx, const GridFunction &tspec_);
void FinalizeSerialDiscreteTargetSpec();
#ifdef MFEM_USE_MPI
void SetTspecAtIndex(int idx, const ParGridFunction &tspec_);
void FinalizeParDiscreteTargetSpec(const ParGridFunction &tspec_);
#endif
public:
DiscreteAdaptTC(TargetType ttype)
: TargetConstructor(ttype),
ncomp(0),
sizeidx(-1), skewidx(-1), aspectratioidx(-1), orientationidx(-1),
tspec(), tspec_sav(), tspec_pert1h(), tspec_pert2h(), tspec_pertmix(),
tspec_fes(NULL),
tspec_fes(NULL), tspec_fesv(NULL),
good_tspec(false), good_tspec_grad(false), good_tspec_hess(false),
adapt_eval(NULL) { }
virtual ~DiscreteAdaptTC() { delete adapt_eval; }
virtual ~DiscreteAdaptTC()
{
delete adapt_eval;
delete tspec_fes;
delete tspec_fesv;
}
virtual void SetSerialDiscreteTargetSpec(GridFunction &tspec_);
/** @name Target specification methods.
The following methods are used to specify geometric parameters of the
targets when these parameters are given by discrete FE functions.
Note that every GridFunction given to the Set methods must use a
H1_FECollection of the same order. The number of components must
correspond to the type of geometric parameter and dimension.
@param[in] tspec_ Input values of a geometric parameter. Note that
the methods in this class support only functions that
use H1_FECollection collection of the same order. */
///@{
virtual void SetSerialDiscreteTargetSpec(const GridFunction &tspec_);
virtual void SetSerialDiscreteTargetSize(const GridFunction &tspec_);
virtual void SetSerialDiscreteTargetSkew(const GridFunction &tspec_);
virtual void SetSerialDiscreteTargetAspectRatio(const GridFunction &tspec_);
virtual void SetSerialDiscreteTargetOrientation(const GridFunction &tspec_);
#ifdef MFEM_USE_MPI
virtual void SetParDiscreteTargetSpec(ParGridFunction &tspec_);
virtual void SetParDiscreteTargetSpec(const ParGridFunction &tspec_);
virtual void SetParDiscreteTargetSize(const ParGridFunction &tspec_);
virtual void SetParDiscreteTargetSkew(const ParGridFunction &tspec_);
virtual void SetParDiscreteTargetAspectRatio(const ParGridFunction &tspec_);
virtual void SetParDiscreteTargetOrientation(const ParGridFunction &tspec_);
#endif
///@}
/// Used in combination with the Update methods to avoid extra computations.
void ResetUpdateFlags()
@@ -756,6 +798,7 @@ public:
ElementTransformation &T,
int nodenum, int idir,
const Vector &IntData);
void RestoreTargetSpecificationAtNode(ElementTransformation &T, int nodenum);
/** Used for finite-difference based computations. Computes the target
+73 -27
View File
@@ -29,13 +29,26 @@ void AdvectorCG::SetInitialField(const Vector &init_nodes,
void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes,
Vector &new_field)
{
#if defined(MFEM_DEBUG) || defined(MFEM_USE_MPI)
int myid = 0;
#endif
Mesh *m = mesh;
// TODO: Implement for AMR meshes.
const int pnt_cnt = new_field.Size()/ncomp;
new_field = field0;
for (int i = 0; i < ncomp; i++)
{
Vector new_field_temp(new_field.GetData()+i*pnt_cnt, pnt_cnt);
ComputeAtNewPositionScalar(new_nodes, new_field_temp);
}
field0 = new_field;
nodes0 = new_nodes;
}
void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
Vector &new_field)
{
Mesh *m = mesh;
#ifdef MFEM_USE_MPI
if (pfes) { MPI_Comm_rank(pfes->GetComm(), &myid); }
if (pmesh) { m = pmesh; }
#endif
@@ -44,17 +57,29 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes,
// This will be used to move the positions.
GridFunction *mesh_nodes = m->GetNodes();
*mesh_nodes = nodes0;
new_field = field0;
double minv = new_field.Min(), maxv = new_field.Max();
// Velocity of the positions.
GridFunction u(mesh_nodes->FESpace());
subtract(new_nodes, nodes0, u);
// Define a scalar FE space for the solution, and the advection operator.
TimeDependentOperator *oper = NULL;
// This must be the fes of the ind, associated with the object's mesh.
if (fes) { oper = new SerialAdvectorCGOper(nodes0, u, *fes); }
FiniteElementSpace *fess = NULL;
#ifdef MFEM_USE_MPI
else if (pfes) { oper = new ParAdvectorCGOper(nodes0, u, *pfes); }
ParFiniteElementSpace *pfess = NULL;
#endif
if (fes)
{
fess = new FiniteElementSpace(fes->GetMesh(), fes->FEColl(), 1);
oper = new SerialAdvectorCGOper(nodes0, u, *fess);
}
#ifdef MFEM_USE_MPI
else if (pfes)
{
pfess = new ParFiniteElementSpace(pfes->GetParMesh(), pfes->FEColl(), 1);
oper = new ParAdvectorCGOper(nodes0, u, *pfess);
}
#endif
MFEM_VERIFY(oper != NULL,
"No FE space has been given to the AdaptivityEvaluator.");
@@ -67,12 +92,18 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes,
h_min = std::min(h_min, m->GetElementSize(i));
}
double v_max = 0.0;
const int s = u.FESpace()->GetVSize() / 2;
const int s = new_field.Size();
for (int i = 0; i < s; i++)
{
const double vel = u(i) * u(i) + u(i+s) * u(i+s);
double vel = 0.;
for (int j = 0; j < dim; j++)
{
vel += u(i+j*s)*u(i+j*s);
}
v_max = std::max(v_max, vel);
}
#ifdef MFEM_USE_MPI
if (pfes)
{
@@ -81,12 +112,17 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes,
MPI_Allreduce(&h_loc, &h_min, 1, MPI_DOUBLE, MPI_MIN, pfes->GetComm());
}
#endif
if (v_max == 0.0)
if (v_max == 0.0) // No need to change the field.
{
// No mesh motion --> no need to change the field.
delete oper;
delete fess;
#ifdef MFEM_USE_MPI
delete pfess;
#endif
return;
}
v_max = std::sqrt(v_max);
double dt = dt_scale * h_min / v_max;
@@ -96,30 +132,34 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes,
{
if (t + dt >= 1.0)
{
#ifdef MFEM_DEBUG
if (myid == 0)
{
mfem::out << "Remap took " << ti << " steps." << std::endl;
}
#endif
dt = 1.0 - t;
last_step = true;
}
ode_solver.Step(new_field, t, dt);
}
// Trim the overshoots and undershoots.
const double minv = field0.Min(), maxv = field0.Max();
for (int i = 0; i < new_field.Size(); i++)
double glob_minv = minv,
glob_maxv = maxv;
#ifdef MFEM_USE_MPI
if (pfes)
{
if (new_field(i) < minv) { new_field(i) = minv; }
if (new_field(i) > maxv) { new_field(i) = maxv; }
MPI_Allreduce(&minv, &glob_minv, 1, MPI_DOUBLE, MPI_MIN, pfes->GetComm());
MPI_Allreduce(&maxv, &glob_maxv, 1, MPI_DOUBLE, MPI_MAX, pfes->GetComm());
}
#endif
// Trim the overshoots and undershoots.
for (int i = 0; i < s; i++)
{
if (new_field(i) < glob_minv) { new_field(i) = glob_minv; }
if (new_field(i) > glob_maxv) { new_field(i) = glob_maxv; }
}
nodes0 = new_nodes;
field0 = new_field;
delete oper;
delete fess;
#ifdef MFEM_USE_MPI
delete pfess;
#endif
}
SerialAdvectorCGOper::SerialAdvectorCGOper(const Vector &x_start,
@@ -235,6 +275,12 @@ void InterpolatorFP::SetInitialField(const Vector &init_nodes,
const double newton_tol = 1.0e-12;
const int npts_at_once = 256;
if (finder)
{
finder->FreeData();
delete finder;
}
FiniteElementSpace *f = fes;
#ifdef MFEM_USE_MPI
if (pfes)
+3 -1
View File
@@ -27,9 +27,9 @@ private:
RK4Solver ode_solver;
Vector nodes0;
Vector field0;
const double dt_scale;
void ComputeAtNewPositionScalar(const Vector &new_nodes, Vector &new_field);
public:
AdvectorCG(double timestep_scale = 0.5)
: AdaptivityEvaluator(),
@@ -53,6 +53,8 @@ private:
Vector pos_r_out, dist_p_out;
int dim;
public:
InterpolatorFP() : finder(NULL) { }
virtual void SetInitialField(const Vector &init_nodes,
const Vector &init_field);
+3 -1
View File
@@ -520,7 +520,9 @@ void TensorProductPRefinementTransferOperator::MultTranspose(const Vector& x,
TrueTransferOperator::TrueTransferOperator(const
ParFiniteElementSpace& lFESpace_,
const ParFiniteElementSpace& hFESpace_)
: lFESpace(lFESpace_), hFESpace(hFESpace_)
: Operator(hFESpace_.GetTrueVSize(), lFESpace_.GetTrueVSize()),
lFESpace(lFESpace_),
hFESpace(hFESpace_)
{
localTransferOperator = new TransferOperator(lFESpace_, hFESpace_);
+4
View File
@@ -15,6 +15,8 @@
#include "adios2stream.hpp"
#ifdef MFEM_USE_ADIOS2
#include "../fem/geom.hpp"
#include "../general/array.hpp"
#include "../mesh/element.hpp"
@@ -750,3 +752,5 @@ noexcept
}
} // end namespace mfem
#endif // MFEM_USE_ADIOS2
+4
View File
@@ -18,6 +18,8 @@
#include "../config/config.hpp"
#ifdef MFEM_USE_ADIOS2
#include <map>
#include <memory> // std::unique_ptr
#include <string>
@@ -230,4 +232,6 @@ private:
} // end namespace mfem
#endif // MFEM_USE_ADIOS2
#endif /* MFEM_ADIOS2STREAM */
+10 -7
View File
@@ -26,8 +26,10 @@
#include <signal.h>
#include <sys/mman.h>
#define mfem_memalign(p,a,s) posix_memalign(p,a,s)
#define mfem_aligned_free free
#else
#define mfem_memalign(p,a,s) (((*(p))=_aligned_malloc((s),(a))),*(p)?0:errno)
#define mfem_aligned_free _aligned_free
#endif
#ifdef MFEM_USE_UMPIRE
@@ -212,7 +214,7 @@ public:
Aligned32HostMemorySpace(): HostMemorySpace() { }
void Alloc(void **ptr, size_t bytes)
{ if (mfem_memalign(ptr, 32, bytes) != 0) { throw ::std::bad_alloc(); } }
void Dealloc(void *ptr) { std::free(ptr); }
void Dealloc(void *ptr) { mfem_aligned_free(ptr); }
};
/// The aligned 64 host memory space
@@ -222,6 +224,7 @@ public:
Aligned64HostMemorySpace(): HostMemorySpace() { }
void Alloc(void **ptr, size_t bytes)
{ if (mfem_memalign(ptr, 64, bytes) != 0) { throw ::std::bad_alloc(); } }
void Dealloc(void *ptr) { mfem_aligned_free(ptr); }
};
#ifndef _WIN32
@@ -666,12 +669,11 @@ void *MemoryManager::Register_(void *ptr, void *h_tmp, size_t bytes,
{
MFEM_CONTRACT_VAR(alias);
MFEM_ASSERT(exists, "Internal error!");
MFEM_ASSERT(IsHostMemory(mt), "Internal error!");
MFEM_ASSERT(!alias, "Cannot register an alias!");
const bool is_host_mem = IsHostMemory(mt);
const MemType dual_mt = GetDualMemoryType_(mt);
const MemType h_mt = mt;
const MemType d_mt = dual_mt;
const MemType h_mt = is_host_mem ? mt : dual_mt;
const MemType d_mt = is_host_mem ? dual_mt : mt;
MFEM_VERIFY_TYPES(h_mt, d_mt);
if (ptr == nullptr && h_tmp == nullptr)
@@ -693,10 +695,11 @@ void *MemoryManager::Register_(void *ptr, void *h_tmp, size_t bytes,
else // DEVICE TYPES
{
h_ptr = h_tmp;
if (h_tmp == nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
if (own && h_tmp == nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
mm.InsertDevice(ptr, h_ptr, bytes, h_mt, d_mt);
flags = (own ? flags | Mem::OWNS_DEVICE : flags & ~Mem::OWNS_DEVICE) |
Mem::OWNS_HOST | Mem::VALID_DEVICE;
flags = own ? flags | Mem::OWNS_DEVICE : flags & ~Mem::OWNS_DEVICE;
flags = own ? flags | Mem::OWNS_HOST : flags & ~Mem::OWNS_HOST;
flags |= Mem::VALID_DEVICE;
}
CheckHostMemoryType_(h_mt, h_ptr);
return h_ptr;
+72 -3
View File
@@ -16,6 +16,7 @@
#include "error.hpp"
#include <cstring> // std::memcpy
#include <type_traits> // std::is_const
#include <cstddef> // std::max_align_t
namespace mfem
{
@@ -283,6 +284,28 @@ public:
@note The current memory is NOT deleted by this method. */
inline void Wrap(T *ptr, int size, MemoryType mt, bool own);
/** Wrap an externally pair of allocated pointers, @a h_ptr and @ d_ptr,
of the given host MemoryType @a h_mt. */
/** The new memory object will have the device MemoryType set as valid.
The given @a h_ptr and @a d_ptr must be allocated appropriately for the
given host MemoryType and its associated device MemoryType:
- MANAGED => MANAGED,
- HOST_DEBUG => DEVICE_DEBUG,
- HOST_UMPIRE => DEVICE_UMPIRE,
- HOST, HOST_32, HOST_64 => DEVICE.
The parameter @a own determines whether both @a h_ptr and @a d_ptr will
be deleted when the method Delete() is called.
@note Ownership can also be controled by using the folowing methods:
- ClearOwnerFlags,
- SetHostPtrOwner,
- SetDevicePtrOwner.
@note The current memory is NOT deleted by this method. */
inline void Wrap(T *h_ptr, T *d_ptr, int size, MemoryType h_mt, bool own);
/// Create a memory object that points inside the memory object @a base.
/** The new Memory object uses the same MemoryType(s) as @a base.
@@ -413,6 +436,38 @@ public:
/** This method can be useful for debugging. It is explicitly instantiated
for Memory<T> with T = int and T = double. */
inline int CompareHostAndDevice(int size) const;
private:
// GCC 4.8 workaround: max_align_t is not in std.
static constexpr std::size_t def_align_bytes_()
{
using namespace std;
return alignof(max_align_t);
}
static constexpr std::size_t def_align_bytes = def_align_bytes_();
static constexpr std::size_t new_align_bytes =
alignof(T) > def_align_bytes ? alignof(T) : def_align_bytes;
template <std::size_t align_bytes, bool dummy = true> struct Alloc
{
static inline T *New(std::size_t)
{
#if __cplusplus < 201703L
// Generate an error in debug mode
MFEM_ASSERT(false, "overaligned type cannot use MemoryType::HOST");
return nullptr;
#else
return new T[size];
#endif
}
};
#if __cplusplus < 201703L
template<bool dummy> struct Alloc<def_align_bytes,dummy>
{
static inline T *New(std::size_t size) { return new T[size]; }
};
#endif
};
@@ -625,7 +680,7 @@ inline void Memory<T>::New(int size)
capacity = size;
flags = OWNS_HOST | VALID_HOST;
h_mt = MemoryManager::host_mem_type;
h_ptr = (h_mt == MemoryType::HOST) ? new T[size] :
h_ptr = (h_mt == MemoryType::HOST) ? Alloc<new_align_bytes>::New(size) :
(T*)MemoryManager::New_(nullptr, size*sizeof(T), h_mt, flags);
}
@@ -637,8 +692,9 @@ inline void Memory<T>::New(int size, MemoryType mt)
const bool mt_host = mt == MemoryType::HOST;
if (mt_host) { flags = OWNS_HOST | VALID_HOST; }
h_mt = IsHostMemory(mt) ? mt : MemoryManager::GetDualMemoryType_(mt);
T *h_tmp = (h_mt == MemoryType::HOST) ? new T[size] : nullptr;
h_ptr = (mt_host) ? h_tmp: (T*)MemoryManager::New_(h_tmp, bytes, mt, flags);
T *h_tmp = (h_mt == MemoryType::HOST) ?
Alloc<new_align_bytes>::New(size) : nullptr;
h_ptr = (mt_host) ? h_tmp : (T*)MemoryManager::New_(h_tmp, bytes, mt, flags);
}
template <typename T>
@@ -682,6 +738,19 @@ inline void Memory<T>::Wrap(T *ptr, int size, MemoryType mt, bool own)
own, false, flags);
}
template <typename T>
inline void Memory<T>::Wrap(T *ptr, T *d_ptr, int size, MemoryType mt, bool own)
{
h_mt = mt;
flags = 0;
h_ptr = ptr;
capacity = size;
MFEM_ASSERT(IsHostMemory(h_mt),"");
const size_t bytes = size*sizeof(T);
const MemoryType d_mt = MemoryManager::GetDualMemoryType_(h_mt);
MemoryManager::Register_(d_ptr, h_ptr, bytes, d_mt, own, false, flags);
}
template <typename T>
inline void Memory<T>::MakeAlias(const Memory &base, int offset, int size)
{
+46 -6
View File
@@ -43,70 +43,110 @@ template <>
struct AssignOp_Impl<AssignOp::Set>
{
template <typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
static inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b)
{
return (a = b);
}
template <typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
static inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b)
{
return (a = b);
}
};
template <>
struct AssignOp_Impl<AssignOp::Add>
{
template <typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
static inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b)
{
MFEM_FLOPS_ADD(1);
return (a += b);
}
template <typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
static inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b)
{
MFEM_FLOPS_ADD(1);
return (a += b);
}
};
template <>
struct AssignOp_Impl<AssignOp::Mult>
{
template <typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
static inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b)
{
MFEM_FLOPS_ADD(1);
return (a *= b);
}
template <typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
static inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b)
{
MFEM_FLOPS_ADD(1);
return (a *= b);
}
};
template <>
struct AssignOp_Impl<AssignOp::Div>
{
template <typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
static inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b)
{
MFEM_FLOPS_ADD(1);
return (a /= b);
}
template <typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
static inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b)
{
MFEM_FLOPS_ADD(1);
return (a /= b);
}
};
template <>
struct AssignOp_Impl<AssignOp::rDiv>
{
template <typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
static inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b)
{
MFEM_FLOPS_ADD(1);
return (a = b/a);
}
template <typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
static inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b)
{
MFEM_FLOPS_ADD(1);
return (a = b/a);
}
};
} // namespace mfem::internal
template <AssignOp::Type Op, typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
inline lvalue_t &Assign(lvalue_t &a, const rvalue_t &b)
{
return internal::AssignOp_Impl<Op>::Assign(a, b);
}
template <AssignOp::Type Op, typename lvalue_t, typename rvalue_t>
MFEM_HOST_DEVICE
inline lvalue_t &AssignHD(lvalue_t &a, const rvalue_t &b)
{
return internal::AssignOp_Impl<Op>::AssignHD(a, b);
}
} // namespace mfem
#endif // MFEM_TEMPLATE_ASSIGN
+3
View File
@@ -148,6 +148,9 @@ const char *GetConfigStr()
#ifdef MFEM_USE_OCCA
"MFEM_USE_OCCA\n"
#endif
#ifdef MFEM_USE_SIMD
"MFEM_USE_SIMD\n"
#endif
#ifdef MFEM_USE_ADIOS2
"MFEM_USE_ADIOS2\n"
#endif
+1 -1
View File
@@ -175,7 +175,7 @@ struct static_method_holder
is_p->peek();
peek_failed = is_p->fail();
}
catch (std::ios_base::failure &e) {}
catch (std::ios_base::failure&) {}
if (peek_failed)
{
throw Exception(std::string("strict_fstream: open('")
+1 -4
View File
@@ -3043,9 +3043,6 @@ void LUFactors::RightSolve(int m, int n, double *X) const
}
#else
// compiling without LAPACK
const double *data = this->data;
const int *ipiv = this->ipiv;
// X <- X U^{-1}
x = X;
for (int k = 0; k < n; k++)
@@ -3080,7 +3077,7 @@ void LUFactors::RightSolve(int m, int n, double *X) const
x = X;
for (int k = 0; k < n; k++)
{
for (int i = 0; i < m; i++)
for (int i = m-1; i >= 0; --i)
{
Swap<double>(x[i*n], x[(ipiv[i]-ipiv_base)*n]);
}
+313 -55
View File
@@ -21,55 +21,6 @@
#include <cmath>
#include <cstdlib>
// Define macro wrappers for hypre_TAlloc, hypre_CTAlloc and hypre_TFree:
// mfem_hypre_TAlloc, mfem_hypre_CTAlloc, and mfem_hypre_TFree, respectively.
// Note: the same macros are defined in hypre_parcsr.cpp.
#if MFEM_HYPRE_VERSION < 21400
#define mfem_hypre_TAlloc(type, size) hypre_TAlloc(type, size)
#define mfem_hypre_CTAlloc(type, size) hypre_CTAlloc(type, size)
#define mfem_hypre_TFree(ptr) hypre_TFree(ptr)
#else // MFEM_HYPRE_VERSION >= 21400
#define mfem_hypre_TAlloc(type, size) \
hypre_TAlloc(type, size, HYPRE_MEMORY_HOST)
#define mfem_hypre_CTAlloc(type, size) \
hypre_CTAlloc(type, size, HYPRE_MEMORY_HOST)
#define mfem_hypre_TFree(ptr) hypre_TFree(ptr, HYPRE_MEMORY_HOST)
// Notes regarding allocation and deallocation of hypre objects in 2.14.0
//-----------------------------------------------------------------------
//
// 1. hypre_CSRMatrix: i, j, data, and rownnz use HYPRE_MEMORY_SHARED while the
// hypre_CSRMatrix structure uses HYPRE_MEMORY_HOST.
//
// Note: the function HYPRE_CSRMatrixCreate creates the i array using
// HYPRE_MEMORY_HOST!
// Note: the functions hypre_CSRMatrixAdd and hypre_CSRMatrixMultiply create
// C_i using HYPRE_MEMORY_HOST!
//
// 2. hypre_Vector: data uses HYPRE_MEMORY_SHARED while the hypre_Vector
// structure uses HYPRE_MEMORY_HOST.
//
// 3. hypre_ParVector: the structure hypre_ParVector uses HYPRE_MEMORY_HOST;
// partitioning uses HYPRE_MEMORY_HOST.
//
// 4. hypre_ParCSRMatrix: the structure hypre_ParCSRMatrix uses
// HYPRE_MEMORY_HOST; col_map_offd, row_starts, col_starts, rowindices,
// rowvalues also use HYPRE_MEMORY_HOST.
//
// Note: the function hypre_ParCSRMatrixToCSRMatrixAll allocates matrix_i
// using HYPRE_MEMORY_HOST!
//
// 5. The goal for the MFEM wrappers of hypre objects is to support only the
// standard hypre build case, i.e. when hypre is build without device support
// and all memory types correspond to host memory. In this case memory
// allocated with operator new can be used by hypre but (as usual) it must
// not be owned by hypre.
#endif // #if MFEM_HYPRE_VERSION < 21400
using namespace std;
namespace mfem
@@ -1713,6 +1664,293 @@ HypreParMatrix * RAP(const HypreParMatrix * Rt, const HypreParMatrix *A,
return new HypreParMatrix(rap);
}
// Helper function for HypreParMatrixFromBlocks. Note that scalability to
// extremely large processor counts is limited by the use of MPI_Allgather.
void GatherBlockOffsetData(MPI_Comm comm, const int rank, const int nprocs,
const int num_loc, Array<int> &offsets,
std::vector<int> &all_num_loc, const int numBlocks,
std::vector<std::vector<int>> &blockProcOffsets,
std::vector<int> &procOffsets,
std::vector<std::vector<int>> &procBlockOffsets,
int &firstLocal, int &globalNum)
{
std::vector<std::vector<int>> all_block_num_loc(numBlocks);
MPI_Allgather(&num_loc, 1, MPI_INT, all_num_loc.data(), 1, MPI_INT, comm);
for (int j = 0; j < numBlocks; ++j)
{
all_block_num_loc[j].resize(nprocs);
blockProcOffsets[j].resize(nprocs);
const int blockNumRows = offsets[j + 1] - offsets[j];
MPI_Allgather(&blockNumRows, 1, MPI_INT, all_block_num_loc[j].data(), 1,
MPI_INT, comm);
blockProcOffsets[j][0] = 0;
for (int i = 0; i < nprocs - 1; ++i)
{
blockProcOffsets[j][i + 1] = blockProcOffsets[j][i]
+ all_block_num_loc[j][i];
}
}
firstLocal = 0;
globalNum = 0;
procOffsets[0] = 0;
for (int i = 0; i < nprocs; ++i)
{
globalNum += all_num_loc[i];
if (i < rank)
{
firstLocal += all_num_loc[i];
}
if (i < nprocs - 1)
{
procOffsets[i + 1] = procOffsets[i] + all_num_loc[i];
}
procBlockOffsets[i].resize(numBlocks);
procBlockOffsets[i][0] = 0;
for (int j = 1; j < numBlocks; ++j)
{
procBlockOffsets[i][j] = procBlockOffsets[i][j - 1]
+ all_block_num_loc[j - 1][i];
}
}
}
HypreParMatrix * HypreParMatrixFromBlocks(Array2D<HypreParMatrix*> &blocks,
Array2D<double> *blockCoeff)
{
const int numBlockRows = blocks.NumRows();
const int numBlockCols = blocks.NumCols();
MFEM_VERIFY(numBlockRows > 0 &&
numBlockCols > 0, "Invalid input to HypreParMatrixFromBlocks");
if (blockCoeff != NULL)
{
MFEM_VERIFY(numBlockRows == blockCoeff->NumRows() &&
numBlockCols == blockCoeff->NumCols(),
"Invalid input to HypreParMatrixFromBlocks");
}
Array<int> rowOffsets(numBlockRows+1);
Array<int> colOffsets(numBlockCols+1);
int nonNullBlockRow0 = -1;
for (int j=0; j<numBlockCols; ++j)
{
if (blocks(0,j) != NULL)
{
nonNullBlockRow0 = j;
break;
}
}
MFEM_VERIFY(nonNullBlockRow0 >= 0, "Null row of blocks");
MPI_Comm comm = blocks(0,nonNullBlockRow0)->GetComm();
// Set offsets based on the number of rows or columns in each block.
rowOffsets = 0;
colOffsets = 0;
for (int i=0; i<numBlockRows; ++i)
{
for (int j=0; j<numBlockCols; ++j)
{
if (blocks(i,j) != NULL)
{
const int nrows = blocks(i,j)->NumRows();
const int ncols = blocks(i,j)->NumCols();
MFEM_VERIFY(nrows > 0 &&
ncols > 0, "Invalid block in HypreParMatrixFromBlocks");
if (rowOffsets[i+1] == 0)
{
rowOffsets[i+1] = nrows;
}
else
{
MFEM_VERIFY(rowOffsets[i+1] == nrows,
"Inconsistent blocks in HypreParMatrixFromBlocks");
}
if (colOffsets[j+1] == 0)
{
colOffsets[j+1] = ncols;
}
else
{
MFEM_VERIFY(colOffsets[j+1] == ncols,
"Inconsistent blocks in HypreParMatrixFromBlocks");
}
}
}
MFEM_VERIFY(rowOffsets[i+1] > 0, "Invalid input blocks");
rowOffsets[i+1] += rowOffsets[i];
}
for (int j=0; j<numBlockCols; ++j)
{
MFEM_VERIFY(colOffsets[j+1] > 0, "Invalid input blocks");
colOffsets[j+1] += colOffsets[j];
}
const int num_loc_rows = rowOffsets[numBlockRows];
const int num_loc_cols = colOffsets[numBlockCols];
int nprocs, rank;
MPI_Comm_rank(comm, &rank);
MPI_Comm_size(comm, &nprocs);
std::vector<int> all_num_loc_rows(nprocs);
std::vector<int> all_num_loc_cols(nprocs);
std::vector<int> procRowOffsets(nprocs);
std::vector<int> procColOffsets(nprocs);
std::vector<std::vector<int>> blockRowProcOffsets(numBlockRows);
std::vector<std::vector<int>> blockColProcOffsets(numBlockCols);
std::vector<std::vector<int>> procBlockRowOffsets(nprocs);
std::vector<std::vector<int>> procBlockColOffsets(nprocs);
int first_loc_row, glob_nrows, first_loc_col, glob_ncols;
GatherBlockOffsetData(comm, rank, nprocs, num_loc_rows, rowOffsets,
all_num_loc_rows, numBlockRows, blockRowProcOffsets,
procRowOffsets, procBlockRowOffsets, first_loc_row,
glob_nrows);
GatherBlockOffsetData(comm, rank, nprocs, num_loc_cols, colOffsets,
all_num_loc_cols, numBlockCols, blockColProcOffsets,
procColOffsets, procBlockColOffsets, first_loc_col,
glob_ncols);
std::vector<int> opI(num_loc_rows + 1);
std::vector<int> cnt(num_loc_rows);
for (int i = 0; i < num_loc_rows; ++i)
{
opI[i] = 0;
cnt[i] = 0;
}
opI[num_loc_rows] = 0;
Array2D<hypre_CSRMatrix *> csr_blocks(numBlockRows, numBlockCols);
// Loop over all blocks, to determine nnz for each row.
for (int i = 0; i < numBlockRows; ++i)
{
for (int j = 0; j < numBlockCols; ++j)
{
if (blocks(i, j) == NULL)
{
csr_blocks(i, j) = NULL;
}
else
{
{
hypre_ParCSRMatrix *parcsr_op = (hypre_ParCSRMatrix*)
const_cast<HypreParMatrix&>
(*(blocks(i, j)));
MFEM_ASSERT(parcsr_op != NULL, "const_cast failed");
csr_blocks(i, j) = hypre_MergeDiagAndOffd(parcsr_op);
}
for (int k = 0; k < csr_blocks(i, j)->num_rows; ++k)
{
opI[rowOffsets[i] + k + 1] +=
csr_blocks(i, j)->i[k + 1] - csr_blocks(i, j)->i[k];
}
}
}
}
// Now opI[i] is nnz for row i-1. Do a partial sum to get offsets.
for (int i = 0; i < num_loc_rows; ++i)
{
opI[i + 1] += opI[i];
}
const int nnz = opI[num_loc_rows];
std::vector<HYPRE_Int> opJ(nnz);
std::vector<double> data(nnz);
// Loop over all blocks, to set matrix data.
for (int i = 0; i < numBlockRows; ++i)
{
for (int j = 0; j < numBlockCols; ++j)
{
if (csr_blocks(i, j) != NULL)
{
const int nrows = csr_blocks(i, j)->num_rows;
const double cij = blockCoeff ? (*blockCoeff)(i, j) : 1.0;
for (int k = 0; k < nrows; ++k)
{
const int rowg = rowOffsets[i] + k; // process-local row
const int nnz_k = csr_blocks(i,j)->i[k+1]-csr_blocks(i,j)->i[k];
const int osk = csr_blocks(i, j)->i[k];
for (int l = 0; l < nnz_k; ++l)
{
// Find the column process offset for the block.
const int bcol = csr_blocks(i, j)->j[osk + l];
int bcolproc = 0;
for (int p = 1; p < nprocs; ++p)
{
if (blockColProcOffsets[j][p] > bcol)
{
bcolproc = p - 1;
break;
}
}
if (blockColProcOffsets[j][nprocs - 1] <= bcol)
{
bcolproc = nprocs - 1;
}
opJ[opI[rowg] + cnt[rowg]] = procColOffsets[bcolproc] +
procBlockColOffsets[bcolproc][j]
+ bcol
- blockColProcOffsets[j][bcolproc];
data[opI[rowg] + cnt[rowg]] = cij * csr_blocks(i, j)->data[osk + l];
cnt[rowg]++;
}
}
}
}
}
for (int i = 0; i < numBlockRows; ++i)
{
for (int j = 0; j < numBlockCols; ++j)
{
if (csr_blocks(i, j) != NULL)
{
hypre_CSRMatrixDestroy(csr_blocks(i, j));
}
}
}
std::vector<HYPRE_Int> rowStarts2(2);
rowStarts2[0] = first_loc_row;
rowStarts2[1] = first_loc_row + all_num_loc_rows[rank];
std::vector<HYPRE_Int> colStarts2(2);
colStarts2[0] = first_loc_col;
colStarts2[1] = first_loc_col + all_num_loc_cols[rank];
return new HypreParMatrix(comm, num_loc_rows, glob_nrows, glob_ncols,
(int *)opI.data(), (HYPRE_Int *)opJ.data(),
(double *)data.data(),
(HYPRE_Int *)rowStarts2.data(),
(HYPRE_Int *)colStarts2.data());
}
void EliminateBC(HypreParMatrix &A, HypreParMatrix &Ae,
const Array<int> &ess_dof_list,
const Vector &X, Vector &B)
@@ -1892,6 +2130,7 @@ HypreSmoother::HypreSmoother() : Solver()
l1_norms = NULL;
pos_l1_norms = false;
eig_est_cg_iter = 10;
B = X = V = Z = NULL;
X0 = X1 = NULL;
fir_coeffs = NULL;
@@ -1899,7 +2138,7 @@ HypreSmoother::HypreSmoother() : Solver()
HypreSmoother::HypreSmoother(HypreParMatrix &_A, int _type,
int _relax_times, double _relax_weight, double _omega,
int _poly_order, double _poly_fraction)
int _poly_order, double _poly_fraction, int _eig_est_cg_iter)
{
type = _type;
relax_times = _relax_times;
@@ -1907,6 +2146,7 @@ HypreSmoother::HypreSmoother(HypreParMatrix &_A, int _type,
omega = _omega;
poly_order = _poly_order;
poly_fraction = _poly_fraction;
eig_est_cg_iter = _eig_est_cg_iter;
l1_norms = NULL;
pos_l1_norms = false;
@@ -1929,10 +2169,12 @@ void HypreSmoother::SetSOROptions(double _relax_weight, double _omega)
omega = _omega;
}
void HypreSmoother::SetPolyOptions(int _poly_order, double _poly_fraction)
void HypreSmoother::SetPolyOptions(int _poly_order, double _poly_fraction,
int _eig_est_cg_iter)
{
poly_order = _poly_order;
poly_fraction = _poly_fraction;
eig_est_cg_iter = _eig_est_cg_iter;
}
void HypreSmoother::SetTaubinOptions(double _lambda, double _mu,
@@ -2016,15 +2258,31 @@ void HypreSmoother::SetOperator(const Operator &op)
if (type == 16)
{
poly_scale = 1;
hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, 10,
&max_eig_est, &min_eig_est);
if (eig_est_cg_iter > 0)
{
hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, eig_est_cg_iter,
&max_eig_est, &min_eig_est);
}
else
{
min_eig_est = 0;
hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est);
}
Z = new HypreParVector(*A);
}
else if (type == 1001 || type == 1002)
{
poly_scale = 0;
hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, 10,
&max_eig_est, &min_eig_est);
if (eig_est_cg_iter > 0)
{
hypre_ParCSRMaxEigEstimateCG(*A, poly_scale, eig_est_cg_iter,
&max_eig_est, &min_eig_est);
}
else
{
min_eig_est = 0;
hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est);
}
// The Taubin and FIR polynomials are defined on [0, 2]
max_eig_est /= 2;
+18 -2
View File
@@ -570,6 +570,17 @@ HypreParMatrix * RAP(const HypreParMatrix *A, const HypreParMatrix *P);
HypreParMatrix * RAP(const HypreParMatrix * Rt, const HypreParMatrix *A,
const HypreParMatrix *P);
/// Returns a merged hypre matrix constructed from hypre matrix blocks.
/** It is assumed that all block matrices use the same communicator, and the
block sizes are consistent in rows and columns. Rows and columns are
renumbered but not redistributed in parallel, e.g. the block rows owned by
each process remain on that process in the resulting matrix. Some blocks can
be NULL. Each block and the entire system can be rectangular. Scalability to
extremely large processor counts is limited by global MPI communication, see
GatherBlockOffsetData in hypre.cpp. */
HypreParMatrix * HypreParMatrixFromBlocks(Array2D<HypreParMatrix*> &blocks,
Array2D<double> *blockCoeff=NULL);
/** Eliminate essential BC specified by 'ess_dof_list' from the solution X to
the r.h.s. B. Here A is a matrix with eliminated BC, while Ae is such that
(A+Ae) is the original (Neumann) matrix before elimination. */
@@ -615,6 +626,8 @@ protected:
double *l1_norms;
/// If set, take absolute values of the computed l1_norms
bool pos_l1_norms;
/// Number of CG iterations to determine eigenvalue estimates
int eig_est_cg_iter;
/// Maximal eigenvalue estimate for polynomial smoothing
double max_eig_est;
/// Minimal eigenvalue estimate for polynomial smoothing
@@ -645,14 +658,17 @@ public:
HypreSmoother(HypreParMatrix &_A, int type = l1GS,
int relax_times = 1, double relax_weight = 1.0,
double omega = 1.0, int poly_order = 2,
double poly_fraction = .3);
double poly_fraction = .3, int eig_est_cg_iter = 10);
/// Set the relaxation type and number of sweeps
void SetType(HypreSmoother::Type type, int relax_times = 1);
/// Set SOR-related parameters
void SetSOROptions(double relax_weight, double omega);
/// Set parameters for polynomial smoothing
void SetPolyOptions(int poly_order, double poly_fraction);
/** By default, 10 iterations of CG are used to estimate the eigenvalues.
Setting eig_est_cg_iter = 0 uses hypre's hypre_ParCSRMaxEigEstimate() instead. */
void SetPolyOptions(int poly_order, double poly_fraction,
int eig_est_cg_iter = 10);
/// Set parameters for Taubin's lambda-mu method
void SetTaubinOptions(double lambda, double mu, int iter);
-20
View File
@@ -17,26 +17,6 @@
#include "hypre_parcsr.hpp"
#include <limits>
// Define macro wrappers for hypre_TAlloc, hypre_CTAlloc and hypre_TFree:
// mfem_hypre_TAlloc, mfem_hypre_CTAlloc, and mfem_hypre_TFree, respectively.
// Note: the same macros are defined in hypre.cpp.
#if MFEM_HYPRE_VERSION < 21400
#define mfem_hypre_TAlloc(type, size) hypre_TAlloc(type, size)
#define mfem_hypre_CTAlloc(type, size) hypre_CTAlloc(type, size)
#define mfem_hypre_TFree(ptr) hypre_TFree(ptr)
#else // MFEM_HYPRE_VERSION >= 21400
// See the notes about hypre 2.14.0 in hypre.cpp
#define mfem_hypre_TAlloc(type, size) \
hypre_TAlloc(type, size, HYPRE_MEMORY_HOST)
#define mfem_hypre_CTAlloc(type, size) \
hypre_CTAlloc(type, size, HYPRE_MEMORY_HOST)
#define mfem_hypre_TFree(ptr) hypre_TFree(ptr, HYPRE_MEMORY_HOST)
#endif // #if MFEM_HYPRE_VERSION < 21400
namespace mfem
{
namespace internal
+50
View File
@@ -21,6 +21,56 @@
#include "_hypre_parcsr_mv.h"
// Define macro wrappers for hypre_TAlloc, hypre_CTAlloc and hypre_TFree:
// mfem_hypre_TAlloc, mfem_hypre_CTAlloc, and mfem_hypre_TFree, respectively.
// Note: these macros are used in hypre.cpp, hypre_parcsr.cpp, and perhaps
// other locations in the future.
#if MFEM_HYPRE_VERSION < 21400
#define mfem_hypre_TAlloc(type, size) hypre_TAlloc(type, size)
#define mfem_hypre_CTAlloc(type, size) hypre_CTAlloc(type, size)
#define mfem_hypre_TFree(ptr) hypre_TFree(ptr)
#else // MFEM_HYPRE_VERSION >= 21400
#define mfem_hypre_TAlloc(type, size) \
hypre_TAlloc(type, size, HYPRE_MEMORY_HOST)
#define mfem_hypre_CTAlloc(type, size) \
hypre_CTAlloc(type, size, HYPRE_MEMORY_HOST)
#define mfem_hypre_TFree(ptr) hypre_TFree(ptr, HYPRE_MEMORY_HOST)
// Notes regarding allocation and deallocation of hypre objects in 2.14.0
//-----------------------------------------------------------------------
//
// 1. hypre_CSRMatrix: i, j, data, and rownnz use HYPRE_MEMORY_SHARED while the
// hypre_CSRMatrix structure uses HYPRE_MEMORY_HOST.
//
// Note: the function HYPRE_CSRMatrixCreate creates the i array using
// HYPRE_MEMORY_HOST!
// Note: the functions hypre_CSRMatrixAdd and hypre_CSRMatrixMultiply create
// C_i using HYPRE_MEMORY_HOST!
//
// 2. hypre_Vector: data uses HYPRE_MEMORY_SHARED while the hypre_Vector
// structure uses HYPRE_MEMORY_HOST.
//
// 3. hypre_ParVector: the structure hypre_ParVector uses HYPRE_MEMORY_HOST;
// partitioning uses HYPRE_MEMORY_HOST.
//
// 4. hypre_ParCSRMatrix: the structure hypre_ParCSRMatrix uses
// HYPRE_MEMORY_HOST; col_map_offd, row_starts, col_starts, rowindices,
// rowvalues also use HYPRE_MEMORY_HOST.
//
// Note: the function hypre_ParCSRMatrixToCSRMatrixAll allocates matrix_i
// using HYPRE_MEMORY_HOST!
//
// 5. The goal for the MFEM wrappers of hypre objects is to support only the
// standard hypre build case, i.e. when hypre is build without device support
// and all memory types correspond to host memory. In this case memory
// allocated with operator new can be used by hypre but (as usual) it must
// not be owned by hypre.
#endif // #if MFEM_HYPRE_VERSION < 21400
namespace mfem
{
+3 -3
View File
@@ -120,7 +120,7 @@ void Symmetrize(const int size, T *data)
template<int dim, typename T>
MFEM_HOST_DEVICE inline T Det(const T *data)
{
return TDet<T>(ColumnMajorLayout2D<dim,dim>(), data);
return TDetHD<T>(ColumnMajorLayout2D<dim,dim>(), data);
}
/** @brief Return the inverse a matrix with given @a size and @a data into the
@@ -130,8 +130,8 @@ MFEM_HOST_DEVICE inline
void CalcInverse(const T *data, T *inv_data)
{
typedef ColumnMajorLayout2D<dim,dim> layout_t;
const T det = TAdjDet<T>(layout_t(), data, layout_t(), inv_data);
TAssign<AssignOp::Mult>(layout_t(), inv_data, static_cast<T>(1.0)/det);
const T det = TAdjDetHD<T>(layout_t(), data, layout_t(), inv_data);
TAssignHD<AssignOp::Mult>(layout_t(), inv_data, static_cast<T>(1.0)/det);
}
/** @brief Compute C = A + alpha*B, where the matrices A, B and C are of size @a
+29
View File
@@ -543,6 +543,35 @@ void RectangularConstrainedOperator::Mult(const Vector &x, Vector &y) const
}
}
void RectangularConstrainedOperator::MultTranspose(const Vector &x,
Vector &y) const
{
const int trial_csz = trial_constraints.Size();
const int test_csz = test_constraints.Size();
if (test_csz == 0)
{
A->MultTranspose(x, y);
}
else
{
z = x;
auto idx = test_constraints.Read();
// Use read+write access - we are modifying sub-vector of z
auto d_z = z.ReadWrite();
MFEM_FORALL(i, test_csz, d_z[idx[i]] = 0.0;);
A->MultTranspose(z, y);
}
if (trial_csz != 0)
{
auto idx = trial_constraints.Read();
auto d_y = y.ReadWrite();
MFEM_FORALL(i, trial_csz, d_y[idx[i]] = 0.0;);
}
}
double PowerMethod::EstimateLargestEigenvalue(Operator& opr, Vector& v0,
int numSteps, double tolerance, int seed)
{
+1
View File
@@ -759,6 +759,7 @@ public:
where the "_i" subscripts denote all the nonessential (boundary) trial
indices and the "_j" subscript denotes the essential test indices */
virtual void Mult(const Vector &x, Vector &y) const;
virtual void MultTranspose(const Vector &x, Vector &y) const;
virtual ~RectangularConstrainedOperator() { if (own_A) { delete A; } }
};
+100
View File
@@ -0,0 +1,100 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_SIMD_HPP
#define MFEM_SIMD_HPP
#include "../config/tconfig.hpp"
// --- AutoSIMD + specializations with intrinsics
#include "simd/auto.hpp"
#ifdef MFEM_USE_SIMD
#if defined(__VSX__)
#include "simd/vsx.hpp"
#elif defined (__bgq__)
#include "simd/qpx.hpp"
#elif defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86)
#include "simd/x86.hpp"
#elif !defined(_MSC_VER)
#warning Unknown SIMD architecture
#else
#pragma message("warning: Unknown SIMD architecture")
#endif
#endif
// MFEM_SIMD_BYTES is the default SIMD size used by MFEM, see e.g. class
// TBilinearForm and the default traits class AutoSIMDTraits.
// MFEM_ALIGN_BYTES determines the padding used in TVector when its 'align'
// template parameter is set to true -- it ensues that the size of such TVector
// types is a multiple of MFEM_ALIGN_BYTES. MFEM_ALIGN_BYTES must be a multiple
// of MFEM_SIMD_BYTES.
#if !defined(MFEM_USE_SIMD)
#define MFEM_SIMD_BYTES 8
#define MFEM_ALIGN_BYTES 32
#elif defined(__AVX512F__)
#define MFEM_SIMD_BYTES 64
#define MFEM_ALIGN_BYTES 64
#elif defined(__AVX__) || defined(__VECTOR4DOUBLE__)
#define MFEM_SIMD_BYTES 32
#define MFEM_ALIGN_BYTES 32
#elif defined(__SSE2__) || defined(__VSX__)
#define MFEM_SIMD_BYTES 16
#define MFEM_ALIGN_BYTES 32
#else
#define MFEM_SIMD_BYTES 8
#define MFEM_ALIGN_BYTES 32
#endif
// derived macros
#define MFEM_ROUNDUP(val,base) ((((val)+(base)-1)/(base))*(base))
#define MFEM_ALIGN_SIZE(size,type) \
MFEM_ROUNDUP(size,(MFEM_ALIGN_BYTES)/sizeof(type))
namespace mfem
{
template<typename complex_t, typename real_t>
struct AutoSIMDTraits
{
static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE;
// Alignment for arrays of vcomplex_t and vreal_t
static const int align_bytes = MFEM_SIMD_BYTES;
static const int batch_size = 1;
static const int simd_size = MFEM_SIMD_BYTES/sizeof(real_t);
typedef AutoSIMD<complex_t, simd_size, MFEM_SIMD_BYTES> vcomplex_t;
typedef AutoSIMD<real_t, simd_size, MFEM_SIMD_BYTES> vreal_t;
typedef AutoSIMD<int, simd_size, simd_size*sizeof(int)> vint_t;
};
template<typename complex_t, typename real_t>
struct NoSIMDTraits
{
static const int block_size = MFEM_TEMPLATE_BLOCK_SIZE;
// Alignment for arrays of vcomplex_t and vreal_t
static const int align_bytes = sizeof(real_t);
static const int batch_size = 1;
static const int simd_size = 1;
typedef AutoSIMD<complex_t, simd_size, align_bytes> vcomplex_t;
typedef AutoSIMD<real_t, simd_size, align_bytes> vreal_t;
typedef AutoSIMD<int, simd_size, simd_size*sizeof(int)> vint_t;
};
} // mfem namespace
#endif // MFEM_SIMD_HPP
+273
View File
@@ -0,0 +1,273 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_SIMD_AUTO_HPP
#define MFEM_SIMD_AUTO_HPP
#include "../../config/tconfig.hpp"
namespace mfem
{
// Use this macro as a workaround for astyle formatting issue with 'alignas'
#define MFEM_AUTOSIMD_ALIGN__ alignas(align_bytes_)
template <typename scalar_t, int S, int align_bytes_>
struct MFEM_AUTOSIMD_ALIGN__ AutoSIMD
{
typedef scalar_t scalar_type;
static const int size = S;
static const int align_bytes = align_bytes_;
scalar_t vec[size];
inline MFEM_ALWAYS_INLINE scalar_t &operator[](int i)
{
return vec[i];
}
inline MFEM_ALWAYS_INLINE const scalar_t &operator[](int i) const
{
return vec[i];
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] = v[i]; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const scalar_t &e)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] = e; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] += v[i]; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const scalar_t &e)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] += e; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] -= v[i]; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const scalar_t &e)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] -= e; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] *= v[i]; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const scalar_t &e)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] *= e; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] /= v[i]; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const scalar_t &e)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] /= e; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const
{
AutoSIMD r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { r[i] = -vec[i]; }
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const
{
AutoSIMD r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { r[i] = vec[i] + v[i]; }
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const scalar_t &e) const
{
AutoSIMD r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { r[i] = vec[i] + e; }
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const
{
AutoSIMD r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { r[i] = vec[i] - v[i]; }
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const scalar_t &e) const
{
AutoSIMD r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { r[i] = vec[i] - e; }
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const
{
AutoSIMD r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { r[i] = vec[i] * v[i]; }
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const scalar_t &e) const
{
AutoSIMD r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { r[i] = vec[i] * e; }
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const
{
AutoSIMD r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { r[i] = vec[i] / v[i]; }
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const scalar_t &e) const
{
AutoSIMD r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { r[i] = vec[i] / e; }
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] += v[i] * w[i]; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const scalar_t &e)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] += v[i] * e; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const scalar_t &e, const AutoSIMD &v)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] += e * v[i]; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] = v[i] * w[i]; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const scalar_t &e)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] = v[i] * e; }
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const scalar_t &e, const AutoSIMD &v)
{
MFEM_VECTORIZE_LOOP
for (int i = 0; i < size; i++) { vec[i] = e * v[i]; }
return *this;
}
};
template <typename scalar_t, int S, int A>
inline MFEM_ALWAYS_INLINE
AutoSIMD<scalar_t,S,A> operator+(const scalar_t &e,
const AutoSIMD<scalar_t,S,A> &v)
{
AutoSIMD<scalar_t,S,A> r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < S; i++) { r[i] = e + v[i]; }
return r;
}
template <typename scalar_t, int S, int A>
inline MFEM_ALWAYS_INLINE
AutoSIMD<scalar_t,S,A> operator-(const scalar_t &e,
const AutoSIMD<scalar_t,S,A> &v)
{
AutoSIMD<scalar_t,S,A> r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < S; i++) { r[i] = e - v[i]; }
return r;
}
template <typename scalar_t, int S, int A>
inline MFEM_ALWAYS_INLINE
AutoSIMD<scalar_t,S,A> operator*(const scalar_t &e,
const AutoSIMD<scalar_t,S,A> &v)
{
AutoSIMD<scalar_t,S,A> r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < S; i++) { r[i] = e * v[i]; }
return r;
}
template <typename scalar_t, int S, int A>
inline MFEM_ALWAYS_INLINE
AutoSIMD<scalar_t,S,A> operator/(const scalar_t &e,
const AutoSIMD<scalar_t,S,A> &v)
{
AutoSIMD<scalar_t,S,A> r;
MFEM_VECTORIZE_LOOP
for (int i = 0; i < S; i++) { r[i] = e / v[i]; }
return r;
}
} // namespace mfem
#endif // MFEM_SIMD_AUTO_HPP
+254
View File
@@ -0,0 +1,254 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_SIMD_M128_HPP
#define MFEM_SIMD_M128_HPP
#ifdef __SSE2__
#include "../../config/tconfig.hpp"
#if defined(__x86_64__)
#include <x86intrin.h>
#else // assuming MSVC with _M_X64 or _M_IX86
#include <intrin.h>
#endif
namespace mfem
{
template <typename, int, int> struct AutoSIMD;
template <> struct AutoSIMD<double,2,16>
{
typedef double scalar_type;
static constexpr int size = 2;
static constexpr int align_bytes = 16;
union
{
__m128d m128d;
double vec[size];
};
inline MFEM_ALWAYS_INLINE double &operator[](int i)
{
return vec[i];
}
inline MFEM_ALWAYS_INLINE const double &operator[](int i) const
{
return vec[i];
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const AutoSIMD &v)
{
m128d = v.m128d;
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator=(const double &e)
{
m128d = _mm_set1_pd(e);
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const AutoSIMD &v)
{
m128d = _mm_add_pd(m128d,v.m128d);
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator+=(const double &e)
{
m128d = _mm_add_pd(m128d,_mm_set1_pd(e));
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const AutoSIMD &v)
{
m128d = _mm_sub_pd(m128d,v.m128d);
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator-=(const double &e)
{
m128d = _mm_sub_pd(m128d,_mm_set1_pd(e));
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const AutoSIMD &v)
{
m128d = _mm_mul_pd(m128d,v.m128d);
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator*=(const double &e)
{
m128d = _mm_mul_pd(m128d,_mm_set1_pd(e));
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const AutoSIMD &v)
{
m128d = _mm_div_pd(m128d,v.m128d);
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &operator/=(const double &e)
{
m128d = _mm_div_pd(m128d,_mm_set1_pd(e));
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator-() const
{
AutoSIMD r;
r.m128d = _mm_xor_pd(_mm_set1_pd(-0.0), m128d);
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const AutoSIMD &v) const
{
AutoSIMD r;
r.m128d = _mm_add_pd(m128d,v.m128d);
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator+(const double &e) const
{
AutoSIMD r;
r.m128d = _mm_add_pd(m128d, _mm_set1_pd(e));
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const AutoSIMD &v) const
{
AutoSIMD r;
r.m128d = _mm_sub_pd(m128d,v.m128d);
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator-(const double &e) const
{
AutoSIMD r;
r.m128d = _mm_sub_pd(m128d, _mm_set1_pd(e));
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const AutoSIMD &v) const
{
AutoSIMD r;
r.m128d = _mm_mul_pd(m128d,v.m128d);
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator*(const double &e) const
{
AutoSIMD r;
r.m128d = _mm_mul_pd(m128d, _mm_set1_pd(e));
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const AutoSIMD &v) const
{
AutoSIMD r;
r.m128d = _mm_div_pd(m128d,v.m128d);
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD operator/(const double &e) const
{
AutoSIMD r;
r.m128d = _mm_div_pd(m128d, _mm_set1_pd(e));
return r;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const AutoSIMD &w)
{
m128d = _mm_add_pd(_mm_mul_pd(w.m128d,v.m128d),m128d);
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const AutoSIMD &v, const double &e)
{
m128d = _mm_add_pd(_mm_mul_pd(_mm_set1_pd(e),v.m128d),m128d);
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &fma(const double &e, const AutoSIMD &v)
{
m128d = _mm_add_pd(_mm_mul_pd(v.m128d,_mm_set1_pd(e)),m128d);
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const AutoSIMD &w)
{
m128d = _mm_mul_pd(v.m128d,w.m128d);
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const AutoSIMD &v, const double &e)
{
m128d = _mm_mul_pd(v.m128d,_mm_set1_pd(e));
return *this;
}
inline MFEM_ALWAYS_INLINE AutoSIMD &mul(const double &e, const AutoSIMD &v)
{
m128d = _mm_mul_pd(_mm_set1_pd(e),v.m128d);
return *this;
}
};
inline MFEM_ALWAYS_INLINE
AutoSIMD<double,2,16> operator+(const double &e,
const AutoSIMD<double,2,16> &v)
{
AutoSIMD<double,2,16> r;
r.m128d = _mm_add_pd(_mm_set1_pd(e),v.m128d);
return r;
}
inline MFEM_ALWAYS_INLINE
AutoSIMD<double,2,16> operator-(const double &e,
const AutoSIMD<double,2,16> &v)
{
AutoSIMD<double,2,16> r;
r.m128d = _mm_sub_pd(_mm_set1_pd(e),v.m128d);
return r;
}
inline MFEM_ALWAYS_INLINE
AutoSIMD<double,2,16> operator*(const double &e,
const AutoSIMD<double,2,16> &v)
{
AutoSIMD<double,2,16> r;
r.m128d = _mm_mul_pd(_mm_set1_pd(e),v.m128d);
return r;
}
inline MFEM_ALWAYS_INLINE
AutoSIMD<double,2,16> operator/(const double &e,
const AutoSIMD<double,2,16> &v)
{
AutoSIMD<double,2,16> r;
r.m128d = _mm_div_pd(_mm_set1_pd(e),v.m128d);
return r;
}
} // namespace mfem
#endif // __SSE2__
#endif // MFEM_SIMD_M128_HPP

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