Compare commits

...
810 Commits
Author SHA1 Message Date
Stowell, Mark L e4a0506b57 Removing experimental example codes 2020-06-17 10:26:25 -07:00
Stowell, Mark L 4869e89f30 Removing redundant test code 2020-06-17 10:16:16 -07:00
Stowell, Mark L 002e17205f Removing duplicate macros 2020-06-17 10:07:23 -07:00
Stowell, Mark L 31c29096e8 make style 2020-06-17 10:05:11 -07:00
Stowell, Mark L aeac71bc1e Updating namespace name 2020-06-17 10:01:22 -07:00
Stowell, Mark L 1f390d6161 Merge remote-tracking branch 'origin/master' into hertz-dev
# Conflicts:
#	examples/ex21p.cpp
#	fem/complex_fem.cpp
#	miniapps/electromagnetics/makefile
2020-06-17 10:00:56 -07:00
Veselin Dobrev b8ab8fce47 Merge pull request #1414 from mfem/nurbs-face-dev
Adding NURBS face dofs [nurbs-face-dev]
2020-06-15 19:40:58 -07:00
Veselin Dobrev 35054e78b6 Merge branch 'master' into nurbs-face-dev
Resolved conflicts:
   CHANGELOG
2020-06-15 18:53:28 -07:00
Tzanio Kolev 646728dfac Merge pull request #1498 from mfem/tweaks-dev
Small bug fixes, accessor methods, and documentation tweaks [tweaks-dev]
2020-06-15 07:25:03 -07:00
Tzanio Kolev 864eeea4a3 Merge pull request #1482 from mfem/mesh-trimmer-dev
Adding simple mesh editing miniapp [mesh-trimmer-dev]
2020-06-15 07:21:46 -07:00
Tzanio b89f29c4b5 minor 2020-06-15 07:20:56 -07:00
Tzanio Kolev 6ba8d18e38 Merge pull request #1450 from mfem/gpu/artv3/batch-lu
Batch LU
2020-06-12 18:07:06 -07:00
Tzanio efd5b9f019 minor 2020-06-12 18:05:23 -07:00
Tzanio Kolev ae0c65082c Merge pull request #1528 from pghysels/master
Fix for superlu_dist 6.3.
2020-06-10 07:33:18 -07:00
Tzanio Kolev 357e2cdb51 Merge branch 'master' into mesh-trimmer-dev 2020-06-09 07:27:20 -07:00
Tzanio Kolev 84661e6385 Merge branch 'master' into gpu/artv3/batch-lu 2020-06-09 07:27:03 -07:00
Tzanio Kolev f795b0d728 Merge branch 'master' into master 2020-06-09 07:26:36 -07:00
Veselin Dobrev c9d97af717 Merge branch 'master' into nurbs-face-dev 2020-06-08 19:20:29 -07:00
Veselin Dobrev dc4715e03d Merge pull request #1510 from mfem/bugfix/hybridization-getedge
FiniteElementCollection::GetEdge bugfix
2020-06-08 17:01:55 -07:00
Veselin Dobrev 1435d64dfb Merge branch 'master' into bugfix/hybridization-getedge 2020-06-08 16:09:10 -07:00
Pieter Ghysels 8461df3d67 Fix for superlu_dist 6.3. 2020-06-08 13:05:43 -07:00
Tzanio Kolev 662b04ea8d Merge pull request #903 from mfem/dox-update1
Doxygen update [dox-update1]
2020-06-07 16:32:48 -07:00
Tzanio ca5a4dff6f Various documentation adjustments 2020-06-07 15:56:56 -07:00
Stowell, Mark L cfcf05b6f9 Adding mesh-trimmer to CodeDocumentation.dox 2020-06-07 14:58:39 -07:00
Stowell, Mark L 345f87f42e Adding mesh-trimmer to CHANGELOG 2020-06-07 14:55:58 -07:00
Stowell, Mark L ae3bdebcac Merge remote-tracking branch 'origin/master' into mesh-trimmer-dev 2020-06-07 14:51:07 -07:00
Tzanio 51a7703b48 minor editing 2020-06-07 13:02:31 -07:00
Tzanio Kolev a4f5921ae3 Merge branch 'master' into dox-update1 2020-06-07 12:26:07 -07:00
Tzanio Kolev 02d0bfe9c1 Merge pull request #1478 from mfem/gmsh-periodic-dev
Adding support for periodic Gmsh meshes [gmsh-periodic-dev]
2020-06-07 12:23:23 -07:00
Stowell, Mark L 43d20869d2 Modifying new mesh names in sample runs 2020-06-07 12:08:58 -07:00
Mark L. StowellandTzanio Kolev fbcd11dfef Update CHANGELOG
Co-authored-by: Tzanio Kolev <tzanio@llnl.gov>
2020-06-07 12:03:07 -07:00
Stowell, Mark L 0f86486c74 Merge remote-tracking branch 'origin/master' into gmsh-periodic-dev
# Conflicts:
#	CHANGELOG
2020-06-07 11:49:53 -07:00
Stowell, Mark L d00d9008e8 Updating CHANGELOG 2020-06-07 11:44:52 -07:00
Stowell, Mark L 762a258cf1 Renaming Gmsh files 2020-06-07 11:37:53 -07:00
Tzanio Kolev 657c64ac24 Merge pull request #1058 from mfem/feature/rwa/global-element-number-mapping
Add an interface to map between local and global element numberings
2020-06-07 10:56:33 -07:00
Tzanio Kolev 0be90bbb26 Merge pull request #1502 from mfem/zstream-exception-fix
Disable exceptions in zstr
2020-06-07 09:57:26 -07:00
Veselin Dobrev e89fb16c42 In class FiniteElementSpace:
* Add protected methods BuildBdrElementToDofTable() and
  BuildFaceToDofTable().
* Return 'const Table &' instead of 'const Table *' from the methods
  GetBdrElementToDofTable() and GetFaceToDofTable() -- these methods
  will now build their respective tables if they are not already built.
* Renamed GenerateFaceDofsFromBdr() to BuildNURBSFaceToDofTable() and
  made it a protected method. This method no longer needs to be called
  explicitly outside of the class to allow calling GetFaceDofs() and
  GetFaceElement() with NURBS spaces -- these two methods will
  automatically call BuildNURBSFaceToDofTable() when needed.
* The Table face_dof is no longer generated by the constructor for
  NURBS meshes -- it will be auto-generated when needed by other
  methods.
* Added a check in BuildNURBSFaceToDofTable() to see if a boundary
  element and its corresponding face element have the same orientation,
  i.e. their vertices are ordered the same. In some cases this
  assumption does not hold, so we may need to generalize the code
  to support such cases.
* Added documentation to several methods.

In class Mesh:
* Removed the method BdrInfoAvailable() -- it should always return true.
* Removed explicit calls to Nodes->FESpace()->GenerateFaceDofsFromBdr()
  in the case of NURBS meshes -- they are no longer required.
2020-06-05 20:29:09 -07:00
Ido Akkerman 1e1cb2d842 small corrections to makefile 2020-06-05 18:14:46 +02:00
Veselin Dobrev 56de3cc0b2 Merge branch 'master' into gpu/artv3/batch-lu 2020-06-03 22:39:09 -07:00
Veselin Dobrev f4eeb1d34e In cmake builds, the unit tests need the 'data' directory to be copied. 2020-06-03 22:27:39 -07:00
Ido Akkerman 4e199fd0b9 Merge branch 'nurbs-face-dev' of https://github.com/mfem/mfem into nurbs-face-dev 2020-06-03 16:53:48 +02:00
Ido Akkerman 68908783d8 Adding tests to GNU make file 2020-06-03 16:53:07 +02:00
Arturo 53a8346c95 fix dtensor header 2020-06-02 22:16:16 -07:00
Veselin Dobrev fb1de283a7 Remove extra empty line from CHANGELOG. 2020-06-02 15:53:47 -07:00
Veselin Dobrev 20849249cd Remove duplicate CHANGELOG entry. 2020-06-02 15:52:13 -07:00
Veselin Dobrev 679a0e6c15 Merge branch 'master' into nurbs-face-dev 2020-06-02 15:06:17 -07:00
Aaron Fisher 0a1e62b127 Merge branch 'master' into dox-update1 2020-06-02 13:19:31 -07:00
Tzanio Kolev 42207dbfed Merge pull request #1416 from mfem/adapt-lim
TMOP - adaptive limiting
2020-06-02 12:29:39 -07:00
Stowell, Mark L 6f9e370523 Adding Gmsh geo files, smaller Gmsh meshes, and sample runs in ex11p 2020-06-02 12:06:23 -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
Ido Akkerman 2ece39550c Avoid bdrElemdof table usage 2020-06-02 15:19:22 +02: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
Stowell, Mark L 774cc3bd68 Typo... oops 2020-06-01 09:28:46 -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
Veselin Dobrev bd14c65b69 In the top makefile, enforce building miniapps/meshing after
miniapps/common -- without this the build may fail.
2020-05-29 18:41:28 -07:00
Tomov 47ae39dbf1 Fixed an uninitialized variable. 2020-05-29 17:12:29 -07:00
Tomov 582d49116f Valgrind errors. 2020-05-29 15:46:24 -07:00
Veselin Dobrev 9258314ac6 Remove trailing whitespace. 2020-05-29 14:18:24 -07:00
Tomov 58a459ab66 Fixed an option string. 2020-05-29 13:53:42 -07:00
Tzanio ad0420e812 minor 2020-05-29 09:05:27 -07:00
Tomov 3c45d38250 Fixed the makefile. 2020-05-28 12:18:07 -07:00
Tomov 944dd26aa7 Fixed the sample runs. 2020-05-28 12:15:48 -07:00
Arturo Vargas 4f41f6bc4c Merge branch 'gpu/artv3/batch-lu' of github.com:mfem/mfem into gpu/artv3/batch-lu 2020-05-28 11:51:26 -07:00
Arturo Vargas 10dde95578 Merge branch 'master' into gpu/artv3/batch-lu 2020-05-28 11:51:09 -07:00
Vargas 71377db232 make style 2020-05-28 11:50:45 -07:00
Arturo Vargas da01fc0ed1 add docs 2020-05-28 11:49:30 -07:00
Vladimir Tomov 24e16c5af4 Update CHANGELOG 2020-05-27 15:04:37 -07:00
Tomov 41d508dacd Moved a common function to mesh_optimizer.hpp. 2020-05-27 12:29:25 -07:00
Tomov 437cd41773 Merge branch 'master' into adapt-lim 2020-05-27 12:24:14 -07:00
Tomov ff6e911139 Review comments. 2020-05-27 12:11:53 -07:00
Stowell, Mark L 101e5d948c Switching to TetMemory allocation in Cubit mesh reader 2020-05-27 10:42:23 -07:00
Stowell, Mark L 4571095d12 Switch to using TetMemory data structure in ReadGmshMesh 2020-05-27 08:50:45 -07:00
Stowell, Mark L 286888a85d Adding Gmsh example meshes and corresponding sample runs 2020-05-26 17:20:44 -07:00
Tomov faa5a79a16 Fixed wrong indexing in FiniteElementCollection::GetEdge(). 2020-05-26 17:19:30 -07:00
Stowell, Mark L 46e436b819 Correcting comments for clarity 2020-05-26 15:01:56 -07:00
Morteza HS a9bcd488cb Adds the new pumi version 2.2.3 2020-05-26 13:14:52 -04:00
Ido Akkerman efa34ab718 make style 2020-05-26 11:25:34 +02: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 4035ded04b Merge branch 'master' into tweaks-dev 2020-05-25 10:27:51 -07:00
Tzanio Kolev d05afa8974 Merge branch 'master' into zstream-exception-fix 2020-05-25 10:22:47 -07: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
Ido Akkerman 9e300dd159 Make GenerateFaceDofsFromBdr work for non-NURBS meshes 2020-05-25 12:13:33 +02: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
Tomov c6d74cda89 Fixed an include. 2020-05-21 19:38:53 -07:00
Tomov c072176287 cmake fix. 2020-05-21 17:29:01 -07:00
Julian Andrej 7d0ecbba20 disable exceptions in zstr 2020-05-21 17:23:14 -07:00
Tomov aae15033bc The common lib gets built for the meshing miniapps. 2020-05-21 17:05:31 -07:00
Arturo Vargas 0bbefe4e14 Merge branch 'gpu/artv3/batch-lu' of github.com:mfem/mfem into gpu/artv3/batch-lu 2020-05-21 13:46:30 -07:00
Arturo Vargas c6d5d3923a remove dead code 2020-05-21 13:46:01 -07:00
Vargas e37c2c7fb1 make style 2020-05-21 13:35:05 -07:00
Arturo Vargas 9bd653526e PR comments 2020-05-21 13:33:55 -07:00
Arturo Vargas 89abb3cd8c Merge branch 'master' into gpu/artv3/batch-lu 2020-05-21 13:04:06 -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
Stowell, Mark L 3f9ca7403a Adjusting comment on new const member functions 2020-05-21 11:16:45 -07:00
Stowell, Mark L f75aa06cd1 Adding accessor method to BlockVector for number of blocks 2020-05-21 11:15:31 -07:00
Stowell, Mark L 271e8ad822 Adding read-only access to BlockOperator member data 2020-05-21 11:12:30 -07:00
Stowell, Mark L 872e044a69 Avoiding memory leak in BlockDiagonalPreconditioner 2020-05-21 11:08:10 -07:00
Stowell, Mark L 93d9683931 Avoiding memory leak in BlockOperator 2020-05-21 11:03:22 -07:00
Stowell, Mark L e88a811861 Correcting a comment 2020-05-21 11:00:33 -07:00
Veselin Dobrev 6cb5a2abb1 Small tweak to avoid using a function before it is declared. 2020-05-21 10:56:52 -07:00
Stowell, Mark L dc31c57359 Adding DenseMatrixInverse::Mult(double*, double*) method similar to DenseMatrix 2020-05-21 10:55:43 -07:00
Stowell, Mark L db9c3c9142 Uninitialized pointer 2020-05-21 10:48:28 -07:00
Stowell, Mark L 7d4a7b2680 These macros have been moved to hypre_parcsr.hpp 2020-05-21 10:47:49 -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 1fc6280e9f Merge branch 'master' into dox-update1 2020-05-21 08:10:11 -07:00
Tzanio 89648f1c00 make style 2020-05-21 08:09:35 -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
Stowell, Mark L 9c5542a0de Merge remote-tracking branch 'origin/master' into mesh-trimmer-dev 2020-05-20 14:00:48 -07:00
Stowell, Mark L e73631f698 Merge remote-tracking branch 'origin/master' into gmsh-periodic-dev 2020-05-20 13:59:23 -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
Aaron Fisher dfddd53892 Merge branch 'master' into dox-update1 2020-05-19 16:38:16 -07:00
Aaron Fisher 08eb0f5bbb Updated the cmake documentation system. 2020-05-19 16:29:46 -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
Aaron Fisher e332188212 Merge branch 'chrome-doc-fix-dev' into dox-update1 2020-05-18 16:53:20 -07:00
Robert 763a8c6236 Addressing some of the concerns in relations to FieldInterpolant class 2020-05-18 16:52:50 -07:00
Aaron Fisher ce47cb4eb4 Merge branch 'master' into dox-update1 2020-05-18 16:40:52 -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
Ido Akkerman a78aef812c Changing access functions and adding NURBSext verify, both for safety 2020-05-18 22:11:50 +02: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
Tzanio Kolev afd31c8a7b Merge branch 'master' into dox-update1 2020-05-15 11:57:46 -07:00
Morteza HS f55a46e2e7 Adds notes about the location of pumi mesh/models 2020-05-15 01:37:21 -04:00
Arturo Vargas b0350a5999 pivot flag host read fix 2020-05-14 18:20:46 -07:00
Tzanio Kolev 5369835883 Merge branch 'master' into gmsh-periodic-dev 2020-05-14 17:56:46 -07:00
Tzanio Kolev 3c47d47456 Merge branch 'master' into mesh-trimmer-dev 2020-05-14 17:56:42 -07: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
Vargas 7a9b2bb98a make style 2020-05-14 16:40:55 -07:00
Arturo Vargas 860d2aca1c add suport for vector and dense tensor types 2020-05-14 16:32:22 -07:00
Stowell, Mark L 91916ada56 Merge remote-tracking branch 'origin/master' into gmsh-periodic-dev 2020-05-14 13:32:18 -07:00
Stowell, Mark L 3722c0b1a7 make style 2020-05-14 11:21:32 -07:00
Aaron Fisher 6983a71e63 Set up the doc make to be silent if it succeeds for testing purposes. 2020-05-14 10:07:11 -07:00
Ido Akkerman 79312eeb08 Clearify comments 2020-05-14 13:29:34 +02:00
Ido Akkerman 1f45834e42 Remove braces 2020-05-14 12:58:33 +02:00
Ido Akkerman 4f82fbda71 Correct penalty parameter input comment 2020-05-14 11:42:42 +02:00
Ido Akkerman 3e70d5da1c Removing whitespace/lines 2020-05-14 11:40:26 +02:00
Ido Akkerman 72e442ba45 Removing duplicate meshes 2020-05-14 11:34:07 +02:00
Morteza HS b0935c7f63 Updates MFEM_USE_PUMI instructions in INSTALL 2020-05-13 20:22:37 -04:00
Arturo Vargas a556dc8eba consider support for Vectors/DenseMatrices in lu batch 2020-05-13 17:07:38 -07: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
Arturo Vargas e10c38c636 Merge branch 'master' into gpu/artv3/batch-lu 2020-05-13 16:26:32 -07: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
Stowell, Mark L df62917d0c Adding trimmer to the build system 2020-05-13 15:45:11 -07:00
Stowell, Mark L e55e61a32c Adding documentation header, changing default, behavior, and adding visualization 2020-05-13 15:44:48 -07:00
Stowell, Mark L 109c53f13c Merge remote-tracking branch 'origin/master' into mesh-trimmer-dev 2020-05-13 14:58:58 -07: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
Bob Anderson 3ae7c0ae8a change convenience entry point for html docs from symbolic link to meta refresh. the symbolic link causes trouble with relative paths in chrome 2020-05-13 12:36:35 -07:00
Robert W. Anderson f330d4cb9e merge master 2020-05-13 11:20:28 -07:00
Robert W. Anderson 32c8c20f23 remove local/global methods from mesh, make non-virtual in pmesh. 2020-05-13 10:55:24 -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
Aaron Fisher 328dc13ba4 Added a small logo to the doxygen documentation. By resizing it I was able to make it look decent. 2020-05-12 14:06:58 -07:00
Stowell, Mark L 66939bdf8c Tweaks to comments 2020-05-12 13:52:59 -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
Stowell, Mark L 7aafd3c47f Merge remote-tracking branch 'origin/master' into gmsh-periodic-dev 2020-05-12 10:29:53 -07:00
Ido Akkerman 699d612513 Merge master 2020-05-12 12:54:23 +02:00
Ido Akkerman 1bf3e188fc Remove comment lines 2020-05-12 12:51:33 +02:00
Tomov 6dffbbfa0b Merge branch 'master' into adapt-lim 2020-05-11 19:51:21 -07:00
Tomov 239030b50a make style 2020-05-11 19:46:54 -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
Aaron Fisher 2852999324 Fixed a bug introduced by the merge. 2020-05-04 16:45:52 -07:00
Aaron Fisher 523db914fc make style 2020-05-04 16:32:15 -07:00
Aaron Fisher bb08084379 Merge branch 'master' into dox-update1 2020-05-04 16:30:35 -07:00
Tomov f64ad892d3 Minor. 2020-05-03 19:46:54 -07:00
Tomov f77273f92a Forgot a delete statement. 2020-05-03 19:33:51 -07:00
Tomov 2cc07be4aa Minor. 2020-05-03 19:05:25 -07:00
Tomov ab68fd9a78 Shows the final value of the limiting term. 2020-05-03 18:48:04 -07:00
Tomov d61ba83611 Doxygen improvements. 2020-05-03 16:40:51 -07:00
Tomov 53006001ce Added a testing mesh. 2020-05-03 15:44:16 -07:00
Tomov 00d182618f Improved the interface. 2020-05-03 15:42:18 -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
Tomov e1fc7d94b7 Corresponding changes in the serial miniapp. 2020-05-02 23:47:46 -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
Tomov 1fbad9f62d Avoids double counting of the adaptive limiting terms for FD. 2020-05-02 00:45:44 -07:00
Tomov 2856c64994 Fixed the normalization constant of the limiting term, for the case
when the target matrices don't contain volumetric information.
2020-05-02 00:21:24 -07:00
Tomov aa80429c54 Restructuring to avoid a segfault. 2020-05-01 23:33:14 -07: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
Tomov 6ec8be76f1 Return const reference in combo::getintegrators. 2020-05-01 15:13:00 -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
Stowell, Mark L 90a6df62c2 Adding mesh trimmer miniapp 2020-05-01 00:55:44 -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
Tomov 29f9e6cb90 Moved together all integration rule initializations. 2020-04-30 17:10:23 -07:00
Tomov ea1685e4cc Option to use gslib or advection. 2020-04-30 16:36:52 -07:00
Will Pazner 3d21c46a90 Add operator sizes to TrueTransferOperator, L2Prolongation, and L2Projection 2020-04-30 14:35:23 -07:00
Aaron Fisher 59e4409ea5 Merge branch 'master' into dox-update1 2020-04-30 13:18:48 -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
Aaron Fisher 8dda4f7441 Numerous changes suggested by Jakub in the review. 2020-04-30 10:59:22 -07: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
Tomov ecfb8c755d Merge branch 'master' into adapt-lim 2020-04-29 19:17:47 -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
Tomov 1000f0118c Option to use gslib for the interpolation. 2020-04-29 11:50:44 -07:00
Ido Akkerman b6aa995326 Merge branch 'nurbs-face-dev' of https://github.com/mfem/mfem into nurbs-face-dev 2020-04-29 11:31:20 +02:00
Ido Akkerman 0d4b1cb9ff Remove need for sort of face dofs 2020-04-29 11:30:54 +02:00
Arturo Vargas 4f430f0ee4 DenseTensor->Vector 2020-04-28 18:16:08 -07:00
Andrew T. Barker 8c253ad11c Fix style 2020-04-28 16:10:44 -07:00
Vargas 908f689ea5 makestyle 2020-04-28 14:40:36 -07:00
Arturo Vargas b8b5a21a7c clean up pass 2020-04-28 14:00:35 -07:00
Andrew T. Barker d9c6c1597f Make ex10p.cpp look just like master. 2020-04-28 13:53:09 -07:00
Vargas c1f7f42dcc make style 2020-04-28 13:36:05 -07:00
Andrew T. Barker 7cca547853 Move residual monitor demonstration from ex10 to ex19 2020-04-28 13:28:19 -07:00
Arturo Vargas 5925b7dfa8 init commit of batch lu decomp 2020-04-28 13:27:48 -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
Ido Akkerman e97a27d331 Merge branch 'master' into nurbs-face-dev 2020-04-28 14:08:10 +02: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
Ido Akkerman a5ef20ee9a Correct mesh file in test 2020-04-23 14:52:38 +02:00
Ido Akkerman e95687faaa Adding multi patch mesh in patch format to data 2020-04-23 14:18:48 +02:00
Ido Akkerman bd424d6a89 Debug init for Nmesh 2020-04-23 11:03:49 +02: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
Ido Akkerman f10f165b71 Fix mem leak 2020-04-22 13:52:36 +02: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
Aaron Fisher add2e8a3f2 Fixed the remainder of the issues that Mark caught. 2020-04-20 16:51:30 -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
Aaron Fisher 0119774c0f Changed the names of the basically typed member variables in the FiniteElement class to snake_case. 2020-04-20 15:10:28 -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
Aaron Fisher 84650f8381 Merge branch 'master' into dox-update1 2020-04-18 01:03:19 -07:00
Aaron Fisher 4114098c86 Fixed a bunch of typos and errors that Mark found. 2020-04-18 00:46:06 -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
Tomov a8abcac938 Adaptive limiting contributions in FD regime. 2020-04-15 15:51:27 -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
Ido Akkerman 05dd41530a Merge branch 'master' into nurbs-face-dev 2020-04-14 18:53:46 +02:00
Ido Akkerman da31bce595 Make empty partition check a while loop. 2020-04-14 18:03:00 +02:00
Ido Akkerman 8eff49047c Add 3d tests, no data copy. Moved meshes to data 2020-04-14 18:01:14 +02:00
Ido Akkerman 7e10b0a7ee Only pritn mehs info once 2020-04-14 17:59:49 +02:00
Ido Akkerman 52ccf07bdb Default mapping value to indicate failure -1 2020-04-14 17:11:33 +02:00
Ido Akkerman a9496f3c58 No strong BCs if switch is set. Increased penalty 2020-04-14 17:10:33 +02:00
Ido Akkerman c2a80e493c Rename and relocate face generation function 2020-04-14 12:37:01 +02: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
Tomov f8dd9bd06c More optimizations. 2020-04-10 19:28:02 -07:00
Tomov 3c404a6b27 Optimized using the symmetry of the Hessians. 2020-04-10 19:09:21 -07:00
Tomov e6ebf97a21 First and second (approximate) derivatives of the adaptive limiting term. 2020-04-10 18:28:38 -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
Tomov 9b0641f472 First derivative of the new limiting term. 2020-04-09 19:48:05 -07:00
Aaron Fisher 2dcae3ac05 make style 2020-04-09 14:06:34 -07:00
Aaron Fisher e262fcf988 Added Andrew's documentation for the templated code. 2020-04-09 13:33:24 -07:00
Ido Akkerman 8e9edf7c66 Merge master 2020-04-09 21:00:53 +02:00
Ido Akkerman c8b773712d make style 2020-04-09 18:35:01 +02:00
Ido Akkerman c88f75bbfc Symmetrice the pfespace code 2020-04-09 18:33:07 +02:00
Ido Akkerman d302141496 Adding face dofs 2020-04-09 18:29:42 +02:00
Ido Akkerman f8a9c558ff Small typo 2020-04-09 18:28:27 +02:00
Ido Akkerman af0fce3d73 Remove debug statements 2020-04-09 18:15:02 +02:00
Ketan Mittal 1c4155dc7b minor fix to findpts 2020-04-09 08:59:11 -07:00
Ido Akkerman 1759ccb2f1 Corrections to get parallel working: Generate call needs to move to correct location 2020-04-09 12:13:06 +02:00
Ido Akkerman 7a49e839db Modify parallel case to mirror serrial: adding weakbcs a.o. 2020-04-09 12:12:06 +02:00
Tomov 07f9bece01 Interpolation of the zeta function after mesh update. 2020-04-08 19:49:02 -07:00
Aaron Fisher 17d7a117c1 Added to the doc generated files to .gitignore. 2020-04-08 15:19:15 -07:00
Aaron Fisher bb2f464ca6 Merge branch 'master' into dox-update1 2020-04-08 15:15:52 -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
Ido Akkerman 40d9185c8b Updating changelog and comments 2020-04-08 17:53:17 +02:00
Ido Akkerman e089d8a4af make style 2020-04-08 17:46:33 +02:00
Ido Akkerman 0001d33b5b undo unnecessary changes 2020-04-08 17:24:58 +02:00
Ido Akkerman cea889054e Add test cases 2020-04-08 17:24:03 +02:00
Ido Akkerman b0d657e631 Merge branch 'master' into weakbc-nurbs-dev 2020-04-08 17:12:47 +02:00
Ido Akkerman f62a6eee75 Clean Face2Bdr and Bdr2Face mechanism 2020-04-08 17:05:18 +02:00
Ido Akkerman 9e0569c53a Add NURBS face integration capability 2020-04-08 14:55:15 +02:00
Ido Akkerman ea59ab0ce9 Add be2face and face2be mapping to mesh, needs cleaning 2020-04-08 14:47:37 +02:00
Ido Akkerman 224895adc2 Add mesh info output 2020-04-08 14:43:57 +02: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
Aaron Fisher c3be660074 Merge branch 'master' into dox-update1 2020-04-07 17:25:23 -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
Ido Akkerman ce4d12c8cb Correct penalty selection 2020-04-06 15:52:14 +02: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
Stowell, Mark L b32955bba7 Adding GridFunction coords to ReadGmshMesh 2020-03-30 21:16:00 -07:00
Stowell, Mark L 80d1533590 First draft of Gmsh periodic data parser 2020-03-30 19:42:08 -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
Tomov a7c2e91915 Initial tests for tangential limiting. 2020-03-20 11:27:09 -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
Ido Akkerman e673b80a9f Delete output statement 2020-03-06 12:20:39 +01:00
Ido Akkerman 8cd4c0049f Order and refinement bugfixes 2020-03-06 12:20:06 +01:00
Ido Akkerman 54d57691de Add weak bcs to NURBS miniapp, also improve refinement mechanism 2020-03-06 12:12:41 +01: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
Jakub Červený e24b839f22 Added 'virtual' to the ParMesh overrrides. 2019-11-07 15:57:18 +01:00
Jakub Červený 3e8acd547c Refactored, removed the "have_" flag. 2019-11-07 15:54:52 +01: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
Robert W. Anderson a953f6ee2a make translation functions const (even though they have mutable internal cached state) 2019-09-03 16:45:24 -07:00
Robert W. Anderson eef8f6ce8e add a facility to map between local and global element numberings 2019-09-03 16:28:36 -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
Andrew T. Barker eb216b91e3 A few updates to documentation. 2019-07-09 16:02:40 -07:00
Aaron Fisher 35d6b0a442 Merge branch 'master' into dox-update1 2019-07-03 14:20:36 -07:00
Aaron Fisher f04242da6e Added some documentation for fe and fe_coll, inculding a nice table. 2019-07-03 14:03:09 -07:00
Aaron Fisher eb9abd9cf6 Added a little bit of doxygen for all the element types and some minor documentation fixes elsewhere. 2019-06-10 11:05:43 -07:00
Tzanio 9fc570b1cc Merge branch 'master' into builddoftoarrays-dev 2019-05-25 22:23:58 -07:00
Aaron Fisher b57c90e4bb Fixed some documentation errors in coefficient. 2019-05-21 14:19:35 -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
Aaron Fisher 2e3d917e0c Improved the doxygen warning/error logging and fixed all of the errors in existing documentation. 2019-05-17 16:31:51 -07:00
Aaron Fisher 9c6efb61b2 Added doxygen for eltrans. Added some logging for the doxygen to help find errors and undocumented stuff. 2019-05-10 17:44:05 -07:00
Aaron Fisher c388a9dd7b Added doxygen for all of the coefficient code. 2019-05-09 16:24:38 -07:00
Aaron Fisher 9c838adca6 Added some doxygen to everything in general and started in fem. 2019-05-08 14:10:49 -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
Stowell, Mark L 1770b6c636 Merge remote-tracking branch 'origin/master' into hertz-dev 2019-04-12 14:39:21 -07:00
camierjs 19003df962 Merge branch 'master' into x86 2019-04-12 11:36:47 -07:00
Stowell, Mark L 82dbf56dae Adding a timer around the linear solve 2019-04-10 14:14:44 -07:00
Stowell, Mark L e85feaf8d7 Adding animation of final solution 2019-04-09 20:18:14 -07:00
Stowell, Mark L 7496438c70 Removing dead code 2019-04-09 17:54:19 -07:00
Stowell, Mark L 5c0dcb1723 Fixing visualization of current source AMR during update 2019-04-09 16:58:58 -07:00
Stowell, Mark L 5be61b645c make style 2019-04-09 16:57:48 -07:00
Stowell, Mark L 1877af796e Adding support for inhomogeneous Dirichlet BCs 2019-04-09 16:57:23 -07:00
Stowell, Mark L 1d108337fb Removing dead code 2019-04-09 16:56:33 -07:00
Stowell, Mark L 0095f8dd91 Fixing a missing "delete" 2019-04-09 16:55:51 -07:00
Stowell, Mark L 2bd39ac9e1 Cleaning out defunct code 2019-04-09 16:10:18 -07:00
Stowell, Mark L 957b35e1bd Removing debugging info 2019-04-09 16:08:16 -07:00
Stowell, Mark L 7ca8441841 Changing default solver/preconditioner pair to MINRES/AMS 2019-04-09 16:04:37 -07:00
Stowell, Mark L 0c28ed2960 Adding informational messages during solver construction 2019-04-09 16:01:18 -07:00
Stowell, Mark L af5634159e Fixing block preconditioner for imaginary block 2019-04-09 16:00:38 -07:00
Stowell, Mark L 1e27306734 Fixing block operator size during AMR update step 2019-04-09 15:59:24 -07:00
Stowell, Mark L cf20422b7d Adding sample run for hermitian operator 2019-04-09 15:56:38 -07:00
Stowell, Mark L 37463eb0c0 Adding ABC matrix to precond operator 2019-04-09 15:56:15 -07:00
Stowell, Mark L 6b38a62404 Adding solver/preconditioner options 2019-04-09 14:40:16 -07:00
Stowell, Mark L 967565f86b Merge remote-tracking branch 'origin/master' into hertz-dev
# Conflicts:
#	miniapps/common/fem_extras.cpp
#	miniapps/common/fem_extras.hpp
2019-04-09 14:17:30 -07:00
Stowell, Mark L 1c9bc33ab1 Merge remote-tracking branch 'origin/master' into hertz-dev
# Conflicts:
#	examples/ex11p.cpp
#	linalg/strumpack.cpp
#	linalg/strumpack.hpp
#	mesh/mesh.cpp
2019-04-01 11:09:30 -07:00
camierjs d53c004e19 Merge branch 'master' into x86 2019-02-27 18:15:28 -08:00
Stowell, Mark L 33d7447d62 Fixing a sign error in dielectric tensor 2019-01-28 10:22:42 -08:00
Stowell, Mark L 87bf55d75d small bugfixes 2019-01-25 13:05:37 -08:00
Stowell, Mark L 1404eeb2d9 Adding a specialized coefficient to compute the outward pointing normal vector for an arbitrary mesh 2019-01-14 17:25:46 -08:00
Stowell, Mark L 82d11a8d0b make style 2019-01-13 14:25:08 -08:00
Stowell, Mark L 72fdec591e Adding animation of the complex-valued solution 2019-01-13 14:24:57 -08:00
Stowell, Mark L ad2d860639 Commenting out debugging code 2019-01-12 21:17:30 -08:00
Stowell, Mark L 631d98f878 Improving readability and simplifying some expressions 2019-01-12 21:06:59 -08:00
Stowell, Mark L 0f7431569e Adding comments to some useful constants 2019-01-12 21:06:26 -08:00
Stowell, Mark L 1dafeeaa00 Using double rather than integer literals to be certain of arithmetic results 2019-01-12 21:05:55 -08:00
Stowell, Mark L 9e68069fe0 Returning scaled dielectric tensor rather than relative dielectric tensor 2019-01-12 21:04:10 -08:00
Stowell, Mark L 98beaf3178 Scaling the size of the current source with the size of the mesh 2019-01-12 21:01:23 -08:00
Stowell, Mark L 999b91e525 Fixing a bug in the initialization of the cold plasma dielectric tensor 2019-01-12 21:00:21 -08:00
Stowell, Mark L 38e533d79a Correcting the ion species charges in the plasma frequency definitions 2019-01-12 14:51:47 -08:00
Stowell, Mark L 3e55af1411 Fixed a sign error in the velocity advection term 2019-01-12 12:14:21 -08:00
Stowell, Mark L 895c62611f make style 2019-01-11 16:39:59 -08:00
Stowell, Mark L f4d98914d4 Implementing diffusion coefficients 2019-01-11 16:39:00 -08:00
Stowell, Mark L c4b85cd862 Adding visualiztion of both fields and fixed operator handle issue 2019-01-11 15:51:16 -08:00
Stowell, Mark L f63fe421fc Adding 1D advection diffusion test code 2019-01-11 14:44:33 -08:00
Stowell, Mark L 3b1ca33a56 Disabling num species option (for now) 2019-01-10 15:53:46 -08:00
Stowell, Mark L 02562975fa Small bugfix 2019-01-10 15:40:28 -08:00
Stowell, Mark L 344bf93689 Small bugfixes 2019-01-10 15:11:09 -08:00
Stowell, Mark L 358bac9b07 Adding tensor valued sigma 2019-01-09 14:26:18 -08:00
Stowell, Mark L d16404c8d0 Define and use the imaginary unit I 2019-01-09 13:36:16 -08:00
Stowell, Mark L e1e9c5d07c Fixing errors related to complex arithmetic 2019-01-09 10:52:22 -08:00
Stowell, Mark L 995e844f9a First draft of cold plasma dielectric tensor 2019-01-09 10:05:47 -08:00
Stowell, Mark L 2a2570089c Adding multiple species support 2019-01-08 11:07:11 -08:00
Stowell, Mark L 32afa97f0a Adding gridfunctions which dielectric tensor depends upon 2019-01-07 16:45:38 -08:00
Stowell, Mark L 6e69270827 Adding dummy implementations to link properly 2019-01-07 15:54:38 -08:00
Stowell, Mark L 2c20a79907 Updating coefficient transformation to matrix rather than scalar coefficients 2019-01-07 15:48:24 -08:00
Stowell, Mark L 8d621b6462 Replacing accidentally uploaded files 2019-01-07 15:35:11 -08:00
Stowell, Mark L ede361654f Adding test_hertz to make systems 2019-01-07 15:30:55 -08:00
Stowell, Mark L ac5636d933 adding temporary version of hertz for plasma physics developments 2019-01-07 15:19:26 -08:00
Stowell, Mark L c71eb4a83a Cleaning up compiler warnings 2018-12-17 11:14:54 -08:00
Stowell, Mark L a08340b702 Merge remote-tracking branch 'origin/complex-strumpack-dev' into hertz-dev
# Conflicts:
#	fem/linearform.hpp
#	fem/plinearform.hpp
#	miniapps/electromagnetics/hertz.cpp
#	miniapps/electromagnetics/hertz_solver.cpp
#	miniapps/electromagnetics/makefile
2018-12-17 11:09:22 -08:00
Stowell, Mark L b84a5c6c4d Merge remote-tracking branch 'origin/complex-mfem-dev' into complex-strumpack-dev 2018-12-17 10:58:56 -08:00
Stowell, Mark L b9c5cc8cf2 make style 2018-12-07 13:35:01 -08:00
Stowell, Mark L b03d30436f Switching to member data rather than argument 2018-12-06 16:12:22 -08:00
Stowell, Mark L 1c3e5a701e Accidentally deleting a pointer which we shouldn't 2018-12-06 16:11:50 -08:00
Stowell, Mark L 880e0e17d9 Correcting the frequency needed to successfully run the sample runs 2018-12-06 16:10:41 -08:00
Stowell, Mark L b2c817ee75 Disabling load balancing because it is crashing for some reason 2018-12-06 16:10:01 -08:00
Stowell, Mark L d649215136 Adding complex STRUMPACK support 2018-12-06 16:08:55 -08:00
Stowell, Mark L 37071f23ac commenting out older STRUMPACK method 2018-12-06 16:08:04 -08:00
Stowell, Mark L d9c3c340c2 Adding mfem_hypre_*Alloc macros to complex_operator source file 2018-12-06 16:07:26 -08:00
Stowell, Mark L bde242d51f Merge remote-tracking branch 'origin/master' into hertz-dev
# Conflicts:
#	fem/linearform.hpp
#	fem/plinearform.hpp
2018-11-26 15:05:04 -08:00
Stowell, Mark L 16403e1ba2 Merge remote-tracking branch 'origin/complex-mfem-dev' into complex-strumpack-dev 2018-11-26 14:11:15 -08:00
camierjs 965e5c85a0 Trying runtime compilation on miniapps/performance/ex1.cpp 2018-11-02 11:13:34 -07:00
Stowell, Mark L 7434c8e66c make style 2018-10-26 21:22:20 -07:00
Stowell, Mark L 08a9af35c5 Merge remote-tracking branch 'origin/complex-mfem-dev' into complex-strumpack-dev
# Conflicts:
#	examples/ex21p.cpp
2018-10-26 21:19:35 -07:00
Stowell, Mark L 443f97737e Fixing a typo in a comment 2018-10-23 11:02:30 -07:00
Dylan Copeland 4c746bd831 Added solver timer. 2018-10-17 09:08:30 -07:00
Dylan Copeland 98b26dba79 Adding strumpack version of ex3p. 2018-10-15 10:11:48 -07:00
Stowell, Mark L cf4ee34707 Fixing a typo 2018-10-13 10:01:16 -07:00
Stowell, Mark L 36210f27b1 Adding new files to CMakeLists.txt 2018-10-12 17:58:05 -07:00
Stowell, Mark L 377dbc2a56 Adding a serial version of "hertz" miniapp by request 2018-10-11 10:27:52 -07:00
Stowell, Mark L 9255eeb657 Adding convenience class for serial implementations 2018-10-11 10:25:08 -07:00
Stowell, Mark L 851d4b246e Merge remote-tracking branch 'origin/master' into hertz-dev 2018-10-10 21:59:19 -07:00
Stowell, Mark L 0d1ca9dc79 Merge remote-tracking branch 'origin/complex-mfem-dev' into complex-strumpack-dev 2018-10-10 21:09:42 -07:00
Stowell, Mark L d0a58f0b3d This functionality seems to have vanished from the latest STRUMPACK 2018-09-25 16:52:19 -07:00
Stowell, Mark L 82fdc3d4ce Merge remote-tracking branch 'origin/complex-mfem-dev' into complex-strumpack-dev 2018-09-25 13:19:27 -07:00
Stowell, Mark L 76f0d6a956 Merge remote-tracking branch 'origin/complex-mfem-dev' into complex-strumpack-dev 2018-09-08 14:56:47 -07:00
Mark L. Stowell 72bf549085 Small changes to assist debugging 2018-08-31 14:34:35 -07:00
Stowell, Mark L 63ee675bd4 Avoiding template instanitations each time strumpack header is included 2018-08-24 19:39:07 -07:00
Stowell, Mark L 42a509538d Adding STRUMPACK support to example 21 2018-08-23 15:04:09 -07:00
Stowell, Mark L ca7cb115b1 CSRMatrixMPI does not _borrow_ the data array, it copies it so this should avoid a large memory leak 2018-08-23 14:44:56 -07:00
Stowell, Mark L 0dfa567ce3 styling changes 2018-08-23 14:44:46 -07:00
Stowell, Mark L 837e2abed4 Adding wrappers for STRUMPACK's complex sparse matrix and solver 2018-08-23 14:44:08 -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
213 changed files with 24688 additions and 4279 deletions
+4
View File
@@ -29,6 +29,8 @@ config/sample-runs-build.log
doc/CodeDocumentation.conf
doc/CodeDocumentation.html
doc/CodeDocumentation
doc/undoc.log
doc/warnings.log
# Temporary files created by the tests.
*.stderr
@@ -167,6 +169,7 @@ miniapps/meshing/twist
miniapps/meshing/mesh-explorer
miniapps/meshing/shaper
miniapps/meshing/extruder
miniapps/meshing/trimmer
miniapps/meshing/mesh-optimizer
miniapps/meshing/pmesh-optimizer
miniapps/meshing/minimal-surface
@@ -180,6 +183,7 @@ miniapps/meshing/mesh-explorer.mesh
miniapps/meshing/partitioning.txt
miniapps/meshing/shaper.mesh
miniapps/meshing/extruder.mesh
miniapps/meshing/trimmer.mesh
miniapps/meshing/optimized*
miniapps/meshing/perturbed*
+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
+73 -8
View File
@@ -23,6 +23,27 @@ Meshing improvements
Hessian for r-adaptivity using discrete fields, and allows use of skewness
and orientation based metrics.
- 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.
- Added TMOP capability for approximate tangential mesh relaxation.
- Added support for reading periodic meshes in Gmsh format (version 2.2). See
for example the periodic-annulus-sector and periodic-torus-sector files in
the data directory.
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.
Improved GPU capabilities
-------------------------
- Added support for Chebyshev accelerated polynomial smoother on GPU.
@@ -35,6 +56,26 @@ 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.
- Added support face integrals on the boundaries of NURBS meshes.
Linear and nonlinear solvers
----------------------------
- Added power method to iteratively estimate the largest eigenvalue and the
@@ -43,6 +84,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
@@ -52,11 +104,10 @@ New and updated examples and miniapps
- Added a new Example 26/26p to demonstrate the construction of a matrix-free
geometric and p-multigrid preconditioner for the Laplace problem.
- Added a new example, Example 27/27p, to demonstrate the enforcement of
various boundary conditions with the Laplace operator. The example shows the
procedures for applying Dirichlet, Neumann (both homogeneous and
inhomogeneous), Robin, and periodic boundary conditions with either H1 or DG
discretizations.
- Added a new example, Example 27/27p, to demonstrate the enforcement of various
boundary conditions with the Laplace operator. The example shows the procedure
for applying Dirichlet, Neumann (both homogeneous and inhomogeneous), Robin,
and periodic boundary conditions with either H1 or DG discretizations.
- Added a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of
stitching together opposite surfaces of a mesh to create a topologically
@@ -65,6 +116,18 @@ 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.
- Added weak Dirichlet boundary conditions (Nitsche) to the NURBS miniapp.
- Added a simple mesh editing miniapp, Trimmer, which trims away portions of a
mesh based on element attributes. Any newly exposed boundary elements are
assigned attribute numbers related to the trimmed element attributes.
Improved testing
----------------
- Added a GitLab pipeline that automates PR testing on supercomputing systems
@@ -74,15 +137,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
{
+37
View File
@@ -0,0 +1,37 @@
SetFactory("OpenCASCADE");
R1 = 1.0;
R2 = 2.0;
Point(1) = {0.0, 0, 0, 1.0};
Point(2) = {R1, 0, 0, 1.0};
Point(3) = {R2, 0, 0, 1.0};
Point(4) = {R1*Cos(Pi/3), R1*Sin(Pi/3), 0, 1.0};
Point(5) = {R2*Cos(Pi/3), R2*Sin(Pi/3), 0, 1.0};
Line(1) = {2, 3};
Line(2) = {4, 5};
Circle(3) = {2, 1, 4};
Circle(4) = {3, 1, 5};
Curve Loop(5) = {1, 4, -2, -3};
Plane Surface(1) = {5};
Transfinite Curve{1} = 7;
Transfinite Curve{2} = 7;
Transfinite Curve{3} = 4;
Transfinite Curve{4} = 10;
// Set a rotation periodicity constraint:
Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Pi/3};
// Tag surfaces and volumes with positive integers
Physical Curve(1) = {3};
Physical Curve(2) = {4};
Physical Curve(3) = {1};
Physical Curve(4) = {2};
Physical Surface(1) = {1};
// Generate 2D mesh
Mesh 2;
Mesh.MshFileVersion = 2.2;
Save "periodic-annulus-sector.msh";
+185
View File
@@ -0,0 +1,185 @@
$MeshFormat
2.2 0 8
$EndMeshFormat
$Nodes
55
1 1 0 0
2 2 0 0
3 0.5000000000000001 0.8660254037844386 0
4 1 1.732050807568877 0
5 1.166666666666667 0 0
6 1.333333333333333 0 0
7 1.5 0 0
8 1.666666666666667 0 0
9 1.833333333333333 0 0
10 0.5833333333333335 1.010362971081845 0
11 0.6666666666666667 1.154700538379251 0
12 0.7500000000000002 1.299038105676658 0
13 0.8333333333333335 1.443375672974064 0
14 0.9166666666666669 1.587713240271471 0
15 0.9396926207859085 0.3420201433256683 0
16 0.7660444431189786 0.6427876096865386 0
17 1.986476715483886 0.2321858282504602 0
18 1.946089741159648 0.4612317414848793 0
19 1.879385241571817 0.6840402866513365 0
20 1.787265280646825 0.8975983604009234 0
21 1.670975622825874 1.09901795614161 0
22 1.532088886237958 1.285575219373077 0
23 1.372483275737469 1.454747283146095 0
24 1.194317183405575 1.604246385510085 0
25 1.425989114816062 0.1915326920916892 0
26 0.8788667344146573 1.13917645290495 0
27 1.630372059110754 0.7154531062316609 0
28 1.436395769298814 1.053728612482506 0
29 1.081023776188756 0.6241293681829633 0
30 1.168737372335971 1.428012728596308 0
31 1.821063986059922 0.298149890497067 0
32 1.234707097211386 0.3469796339295647 0
33 1.377747393186519 0.6200150626754309 0
34 1.457047681210906 0.3890895843559762 0
35 0.917846726184522 0.8957978954532204 0
36 1.218335619030348 0.9017812086952638 0
37 1.066623110765233 1.061857005744772 0
38 1.587029716281926 0.1355955181472859 0
39 1.744445799211916 0.1441515753740107 0
40 1.25 0.1443375672974065 0
41 1.453660070628011 0.8435769396609902 0
42 1.741367044061892 0.499612708014486 0
43 1.30550638526547 1.257610469847477 0
44 1.118213276932792 0.1666674689105279 0
45 0.9109440214958271 1.306610291787315 0
46 0.9970618258753989 1.438658589955562 0
47 0.7499999999999998 1.010362971081845 0
48 0.7034449005273667 0.8850673702175776 0
49 1.605449512513618 0.9269067082200894 0
50 1.561654019115059 0.5298592532912715 0
51 1.229782222487711 1.096820457143683 0
52 1.617066998712459 0.3090202662210922 0
53 1.079645953234324 1.246963713711438 0
54 1.877063966817811 0.1348974588243076 0
55 1.055356609656722 1.558136350380461 0
$EndNodes
$Elements
108
1 1 2 3 1 1 5
2 1 2 3 1 5 6
3 1 2 3 1 6 7
4 1 2 3 1 7 8
5 1 2 3 1 8 9
6 1 2 3 1 9 2
7 1 2 4 2 3 10
8 1 2 4 2 10 11
9 1 2 4 2 11 12
10 1 2 4 2 12 13
11 1 2 4 2 13 14
12 1 2 4 2 14 4
13 1 2 1 3 1 15
14 1 2 1 3 15 16
15 1 2 1 3 16 3
16 1 2 2 4 2 17
17 1 2 2 4 17 18
18 1 2 2 4 18 19
19 1 2 2 4 19 20
20 1 2 2 4 20 21
21 1 2 2 4 21 22
22 1 2 2 4 22 23
23 1 2 2 4 23 24
24 1 2 2 4 24 4
25 2 2 1 1 32 40 25
26 2 2 1 1 25 34 32
27 2 2 1 1 33 41 36
28 2 2 1 1 38 52 25
29 2 2 1 1 33 36 29
30 2 2 1 1 26 47 35
31 2 2 1 1 35 37 26
32 2 2 1 1 25 52 34
33 2 2 1 1 32 44 40
34 2 2 1 1 15 32 29
35 2 2 1 1 15 29 16
36 2 2 1 1 36 41 28
37 2 2 1 1 32 33 29
38 2 2 1 1 50 52 42
39 2 2 1 1 32 34 33
40 2 2 1 1 42 52 31
41 2 2 1 1 43 53 51
42 2 2 1 1 27 41 33
43 2 2 1 1 26 53 45
44 2 2 1 1 18 31 17
45 2 2 1 1 29 35 16
46 2 2 1 1 29 36 35
47 2 2 1 1 24 30 23
48 2 2 1 1 30 53 43
49 2 2 1 1 17 54 2
50 2 2 1 1 4 55 24
51 2 2 1 1 28 51 36
52 2 2 1 1 47 48 35
53 2 2 1 1 36 37 35
54 2 2 1 1 37 53 26
55 2 2 1 1 22 28 21
56 2 2 1 1 20 27 19
57 2 2 1 1 33 50 27
58 2 2 1 1 15 44 32
59 2 2 1 1 18 42 31
60 2 2 1 1 30 43 23
61 2 2 1 1 35 48 16
62 2 2 1 1 31 54 17
63 2 2 1 1 9 39 8
64 2 2 1 1 8 38 7
65 2 2 1 1 7 25 6
66 2 2 1 1 22 43 28
67 2 2 1 1 23 43 22
68 2 2 1 1 39 54 31
69 2 2 1 1 19 42 18
70 2 2 1 1 24 55 30
71 2 2 1 1 27 42 19
72 2 2 1 1 13 46 14
73 2 2 1 1 51 53 37
74 2 2 1 1 39 52 38
75 2 2 1 1 6 40 5
76 2 2 1 1 34 52 50
77 2 2 1 1 12 45 13
78 2 2 1 1 30 55 46
79 2 2 1 1 10 47 11
80 2 2 1 1 8 39 38
81 2 2 1 1 28 49 21
82 2 2 1 1 7 38 25
83 2 2 1 1 41 49 28
84 2 2 1 1 20 49 27
85 2 2 1 1 11 26 12
86 2 2 1 1 27 49 41
87 2 2 1 1 31 52 39
88 2 2 1 1 25 40 6
89 2 2 1 1 2 54 9
90 2 2 1 1 14 55 4
91 2 2 1 1 45 53 46
92 2 2 1 1 45 46 13
93 2 2 1 1 5 44 1
94 2 2 1 1 21 49 20
95 2 2 1 1 46 53 30
96 2 2 1 1 3 48 10
97 2 2 1 1 34 50 33
98 2 2 1 1 36 51 37
99 2 2 1 1 26 45 12
100 2 2 1 1 11 47 26
101 2 2 1 1 27 50 42
102 2 2 1 1 40 44 5
103 2 2 1 1 43 51 28
104 2 2 1 1 10 48 47
105 2 2 1 1 9 54 39
106 2 2 1 1 46 55 14
107 2 2 1 1 1 44 15
108 2 2 1 1 16 48 3
$EndElements
$Periodic
1
1 1 2
Affine 0.5000000000000001 0.8660254037844386 0 0 -0.8660254037844386 0.5000000000000001 0 0 0 0 1 0 0 0 0 1
7
9 14
6 11
8 13
5 10
7 12
2 4
1 3
$EndPeriodic
+25
View File
@@ -0,0 +1,25 @@
SetFactory("OpenCASCADE");
R = 1.5;
r = 0.5;
Torus(1) = {0,0,0, R, r, Pi/3};
pts() = PointsOf{ Volume{1}; };
Characteristic Length{ pts() } = 0.25;
// Set a rotation periodicity constraint:
Periodic Surface{3} = {2} Rotate{{0,0,1}, {0,0,0}, Pi/3};
// Tag surfaces and volumes with positive integers
Physical Surface(1) = {1};
Physical Surface(2) = {2};
Physical Surface(3) = {3};
Physical Volume(1) = {1};
// Generate 3D mesh
Mesh 3;
Mesh.MshFileVersion = 2.2;
Save "periodic-torus-sector.msh";
File diff suppressed because it is too large Load Diff
+155
View File
@@ -0,0 +1,155 @@
MFEM NURBS mesh v1.0
dimension
2
elements
5
1 3 0 3 7 4
1 3 3 2 6 7
1 3 2 1 5 6
1 3 1 0 4 5
1 3 2 8 9 1
boundary
10
1 1 0 3
2 1 3 2
2 1 1 0
2 1 2 8
2 1 9 1
3 1 7 4
3 1 6 7
3 1 5 6
3 1 4 5
4 1 8 9
edges
15
0 0 4
0 3 7
0 1 5
0 2 6
1 0 3
1 4 7
2 3 2
2 7 6
2 1 0
2 5 4
1 2 1
1 6 5
1 8 9
3 2 8
3 1 9
vertices
10
patches
knotvectors
2
2 3 0 0 0 1 1 1
2 4 0 0 0 0.5 1 1 1
dimension
2
controlpoints_cartesian
-5 5 1
-5 3.92523e-16 1
-5 -5 1
-2.47593 2.47593 1
-4.95187 6.06429e-16 0.707107
-2.47593 -2.47593 1
-0.424264 0.424264 1
-0.848528 1.03915e-16 0.707107
-0.424264 -0.424264 1
-0.353553 0.353553 1
-0.707107 8.65956e-17 0.707107
-0.353553 -0.353553 1
knotvectors
2
2 3 0 0 0 1 1 1
2 4 0 0 0 0.5 1 1 1
dimension
2
controlpoints_cartesian
-5 -5 1
-1.17757e-15 -5 1
5 -5 1
-2.47593 -2.47593 1
-9.09644e-16 -4.95187 0.707107
2.47593 -2.47593 1
-0.424264 -0.424264 1
-1.55872e-16 -0.848528 0.707107
0.424264 -0.424264 1
-0.353553 -0.353553 1
-1.29893e-16 -0.707107 0.707107
0.353553 -0.353553 1
knotvectors
2
2 3 0 0 0 1 1 1
2 4 0 0 0 0.5 1 1 1
dimension
2
controlpoints_cartesian
5 -5 1
5 -1.17757e-15 1
5 5 1
2.47593 -2.47593 1
4.95187 -1.21286e-15 0.707107
2.47593 2.47593 1
0.424264 -0.424264 1
0.848528 -2.07829e-16 0.707107
0.424264 0.424264 1
0.353553 -0.353553 1
0.707107 -1.73191e-16 0.707107
0.353553 0.353553 1
knotvectors
2
2 3 0 0 0 1 1 1
2 4 0 0 0 0.5 1 1 1
dimension
2
controlpoints_cartesian
5 5 1
3.92523e-16 5 1
-5 5 1
2.47593 2.47593 1
3.03215e-16 4.95187 0.707107
-2.47593 2.47593 1
0.424264 0.424264 1
5.19574e-17 0.848528 0.707107
-0.424264 0.424264 1
0.353553 0.353553 1
4.32978e-17 0.707107 0.707107
-0.353553 0.353553 1
knotvectors
2
2 3 0 0 0 1 1 1
2 3 0 0 0 1 1 1
dimension
2
controlpoints_cartesian
5 -5 1
10 -5 1
15 -5 1
5 0 1
10 0 1
15 0 1
5 5 1
10 5 1
15 5 1
+14 -29
View File
@@ -16,36 +16,21 @@ if (DOXYGEN_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CodeDocumentation.conf.in
${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf @ONLY)
if (UNIX)
# Only create symlinks if UNIX operating system
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen to CodeDocumentation.html"
VERBATIM)
add_custom_target(clean-doc
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
COMMENT "Removing API documentation"
VERBATIM)
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
COMMAND echo "<meta http-equiv=\"REFRESH\" content=\"0;URL=CodeDocumentation/html/index.html\">" > ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen to CodeDocumentation.html"
VERBATIM)
add_custom_target(clean-doc
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/warnings.log
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
COMMENT "Removing API documentation"
VERBATIM)
else (UNIX)
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen to CodeDocumentation/html/index.html"
VERBATIM)
add_custom_target(clean-doc
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
COMMENT "Removing API documentation"
VERBATIM)
endif (UNIX)
endif (DOXYGEN_FOUND)
+3 -3
View File
@@ -51,7 +51,7 @@ PROJECT_BRIEF = "Finite element discretization library"
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO =
PROJECT_LOGO = web/logo-small.png
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
@@ -746,7 +746,7 @@ WARN_FORMAT = "$file:$line: $text"
# messages should be written. If left blank the output is written to standard
# error (stderr).
WARN_LOGFILE =
WARN_LOGFILE = warnings.log
#---------------------------------------------------------------------------
# Configuration options related to the input files
@@ -1470,7 +1470,7 @@ MATHJAX_FORMAT = HTML-CSS
# The default value is: http://cdn.mathjax.org/mathjax/latest.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = https://cdn.llnl.gov/mathjax/2.7.2
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
+1
View File
@@ -149,6 +149,7 @@ namespace mfem {
* - <a class="el" href="extruder_8cpp_source.html">Extruder</a>: extrude a low-dimensional mesh into a higher dimension
* - <a class="el" href="mesh-explorer_8cpp_source.html">Mesh Explorer</a>: visualize and manipulate meshes
* - <a class="el" href="mesh-optimizer_8cpp_source.html">Mesh Optimizer</a>: optimize high-order meshes, <a class="el" href="mesh-optimizer_8cpp_source.html">serial</a> and <a class="el" href="pmesh-optimizer_8cpp_source.html">parallel</a> versions
* - <a class="el" href="trimmer_8cpp_source.html">Trimmer</a>: trim elements from existing meshes
* - <a class="el" href="display-basis_8cpp_source.html">Display Basis</a>: visualize finite element basis functions
* - <a class="el" href="get-values_8cpp_source.html">Get Values</a>: extract field values via DataCollection classes
* - <a class="el" href="load-dc_8cpp_source.html">Load DC</a>: visualize fields saved via DataCollection classes
+11 -4
View File
@@ -9,18 +9,25 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
SHELL = /bin/bash
MFEM_DIR ?= ..
DOXYGEN_CONF = CodeDocumentation.conf
# doxygen uses: graphviz, latex
html: $(DOXYGEN_CONF)
doxygen $(DOXYGEN_CONF)
rm -f CodeDocumentation.html
ln -s CodeDocumentation/html/index.html CodeDocumentation.html
@# Generate the html documentation
@doxygen $(DOXYGEN_CONF)
@echo "<meta http-equiv=\"REFRESH\" content=\"0;URL=CodeDocumentation/html/index.html\">" > CodeDocumentation.html
@cat warnings.log
@# Generate the log of undocumented methods
@( cat $(DOXYGEN_CONF) ; echo "GENERATE_HTML=NO" ; echo "EXTRACT_ALL=NO" ; echo "WARN_LOGFILE=undoc.log" ; echo "QUIET=YES" ) | doxygen - &> /dev/null
clean:
rm -rf $(DOXYGEN_CONF) CodeDocumentation CodeDocumentation.html *~
rm -rf undoc.log warnings.log
$(DOXYGEN_CONF): $(MFEM_DIR)/doc/$(DOXYGEN_CONF).in
sed -e 's%@MFEM_SOURCE_DIR@%$(MFEM_DIR)%g' $(<) \
@sed -e 's%@MFEM_SOURCE_DIR@%$(MFEM_DIR)%g' $(<) \
> $(DOXYGEN_CONF)
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+2
View File
@@ -9,6 +9,8 @@
// ex1 -m ../data/fichera.mesh
// ex1 -m ../data/fichera-mixed.mesh
// ex1 -m ../data/toroid-wedge.mesh
// ex1 -m ../data/periodic-annulus-sector.msh
// ex1 -m ../data/periodic-torus-sector.msh
// ex1 -m ../data/square-disc-p2.vtk -o 2
// ex1 -m ../data/square-disc-p3.mesh -o 3
// ex1 -m ../data/square-disc-nurbs.mesh -o -1
+2
View File
@@ -8,6 +8,8 @@
// mpirun -np 4 ex11p -m ../data/escher.mesh
// mpirun -np 4 ex11p -m ../data/fichera.mesh
// mpirun -np 4 ex11p -m ../data/fichera-mixed.mesh
// mpirun -np 4 ex11p -m ../data/periodic-annulus-sector.msh
// mpirun -np 4 ex11p -m ../data/periodic-torus-sector.msh -rs 1
// mpirun -np 4 ex11p -m ../data/toroid-wedge.mesh -o 2
// mpirun -np 4 ex11p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex11p -m ../data/square-disc-p3.mesh -o 3
+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);
+2
View File
@@ -9,6 +9,8 @@
// mpirun -np 4 ex1p -m ../data/fichera.mesh
// mpirun -np 4 ex1p -m ../data/fichera-mixed.mesh
// mpirun -np 4 ex1p -m ../data/toroid-wedge.mesh
// mpirun -np 4 ex1p -m ../data/periodic-annulus-sector.msh
// mpirun -np 4 ex1p -m ../data/periodic-torus-sector.msh
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3
// mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1
+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)
+97 -36
View File
@@ -25,8 +25,8 @@
namespace mfem
{
/// Enumeration defining the assembly level for bilinear and nonlinear form
/// classes derived from Operator.
/** @brief Enumeration defining the assembly level for bilinear and nonlinear
form classes derived from Operator. */
enum class AssemblyLevel
{
/// Fully assembled form, i.e. a global sparse matrix in MFEM, Hypre or PETSC
@@ -44,15 +44,19 @@ enum class AssemblyLevel
};
/** Class for bilinear form - "Matrix" with associated FE space and
BLFIntegrators. */
/** @brief A "square matrix" operator for the associated FE space and
BLFIntegrators The sum of all the BLFIntegrators can be used form the matrix
M. This class also supports other assembly levels specified via the
SetAssemblyLevel() function. */
class BilinearForm : public Matrix
{
protected:
/// Sparse matrix to be associated with the form. Owned.
/// Sparse matrix \f$ M \f$ to be associated with the form. Owned.
SparseMatrix *mat;
/// Matrix used to eliminate b.c. Owned.
/** @brief Sparse Matrix \f$ M_e \f$ used to store the eliminations
from the b.c. Owned.
\f$ M + M_e = M_{original} \f$ */
SparseMatrix *mat_e;
/// FE space on which the form lives. Not owned.
@@ -62,12 +66,12 @@ protected:
AssemblyLevel assembly;
/// Element batch size used in the form action (1, 8, num_elems, etc.)
int batch;
/** Extension for supporting Full Assembly (FA), Element Assembly (EA),
/** @brief Extension for supporting Full Assembly (FA), Element Assembly (EA),
Partial Assembly (PA), or Matrix Free assembly (MF). */
BilinearFormExtension *ext;
/// Indicates the Mesh::sequence corresponding to the current state of the
/// BilinearForm.
/** @brief Indicates the Mesh::sequence corresponding to the current state of
the BilinearForm. */
long sequence;
/** @brief Indicates the BilinearFormIntegrator%s stored in #dbfi, #bbfi,
@@ -147,35 +151,43 @@ public:
/// Get the size of the BilinearForm as a square matrix.
int Size() const { return height; }
/// Set the desired assembly level. The default is AssemblyLevel::FULL.
/** This method must be called before assembly. */
/// Set the desired assembly level.
/** Valid choices are:
- AssemblyLevel::FULL (default)
- AssemblyLevel::PARTIAL
- AssemblyLevel::ELEMENT
- AssemblyLevel::NONE
This method must be called before assembly. */
void SetAssemblyLevel(AssemblyLevel assembly_level);
/// Returns the assembly level
AssemblyLevel GetAssemblyLevel() const { return assembly; }
/** Enable the use of static condensation. For details see the description
for class StaticCondensation in fem/staticcond.hpp This method should be
called before assembly. If the number of unknowns after static
/** @brief Enable the use of static condensation. For details see the
description for class StaticCondensation in fem/staticcond.hpp This method
should be called before assembly. If the number of unknowns after static
condensation is not reduced, it is not enabled. */
void EnableStaticCondensation();
/** Check if static condensation was actually enabled by a previous call to
EnableStaticCondensation(). */
/** @brief Check if static condensation was actually enabled by a previous
call to EnableStaticCondensation(). */
bool StaticCondensationIsEnabled() const { return static_cond; }
/// Return the trace FE space associated with static condensation.
FiniteElementSpace *SCFESpace() const
{ return static_cond ? static_cond->GetTraceFESpace() : NULL; }
/** Enable hybridization; for details see the description for class
/// Enable hybridization.
/** For details see the description for class
Hybridization in fem/hybridization.hpp. This method should be called
before assembly. */
void EnableHybridization(FiniteElementSpace *constr_space,
BilinearFormIntegrator *constr_integ,
const Array<int> &ess_tdof_list);
/** For scalar FE spaces, precompute the sparsity pattern of the matrix
/** @brief For scalar FE spaces, precompute the sparsity pattern of the matrix
(assuming dense element matrices) based on the types of integrators
present in the bilinear form. */
void UsePrecomputedSparsity(int ps = 1) { precompute_sparsity = ps; }
@@ -194,15 +206,16 @@ public:
/// Use the sparsity of @a A to allocate the internal SparseMatrix.
void UseSparsity(SparseMatrix &A);
/** Pre-allocate the internal SparseMatrix before assembly. If the flag
'precompute sparsity' is set, the matrix is allocated in CSR format (i.e.
/// Pre-allocate the internal SparseMatrix before assembly.
/** If the flag 'precompute sparsity'
is set, the matrix is allocated in CSR format (i.e.
finalized) and the entries are initialized with zeros. */
void AllocateMatrix() { if (mat == NULL) { AllocMat(); } }
/// Access all integrators added with AddDomainIntegrator().
/// Access all the integrators added with AddDomainIntegrator().
Array<BilinearFormIntegrator*> *GetDBFI() { return &dbfi; }
/// Access all integrators added with AddBoundaryIntegrator().
/// Access all the integrators added with AddBoundaryIntegrator().
Array<BilinearFormIntegrator*> *GetBBFI() { return &bbfi; }
/** @brief Access all boundary markers added with AddBoundaryIntegrator().
If no marker was specified when the integrator was added, the
@@ -219,64 +232,85 @@ public:
corresponding pointer (to Array<int>) will be NULL. */
Array<Array<int>*> *GetBFBFI_Marker() { return &bfbfi_marker; }
/// Returns a reference to: \f$ M_{ij} \f$
const double &operator()(int i, int j) { return (*mat)(i,j); }
/// Returns reference to a_{ij}.
/// Returns a reference to: \f$ M_{ij} \f$
virtual double &Elem(int i, int j);
/// Returns constant reference to a_{ij}.
/// Returns constant reference to: \f$ M_{ij} \f$
virtual const double &Elem(int i, int j) const;
/// Matrix vector multiplication.
/// Matrix vector multiplication: \f$ y = M x \f$
virtual void Mult(const Vector &x, Vector &y) const;
/** @brief Matrix vector multiplication with the original uneliminated
matrix. The original matrix is \f$ M + M_e \f$ so we have:
\f$ y = M x + M_e x \f$ */
void FullMult(const Vector &x, Vector &y) const
{ mat->Mult(x, y); mat_e->AddMult(x, y); }
/// Add the matrix vector multiple to a vector: \f$ y += a M x \f$
virtual void AddMult(const Vector &x, Vector &y, const double a = 1.0) const
{ mat -> AddMult (x, y, a); }
/** @brief Add the original uneliminated matrix vector multiple to a vector.
The original matrix is \f$ M + Me \f$ so we have:
\f$ y += M x + M_e x \f$ */
void FullAddMult(const Vector &x, Vector &y) const
{ mat->AddMult(x, y); mat_e->AddMult(x, y); }
/// Add the matrix transpose vector multiplication: \f$ y += a M^T x \f$
virtual void AddMultTranspose(const Vector & x, Vector & y,
const double a = 1.0) const
{ mat->AddMultTranspose(x, y, a); }
/** @brief Add the original uneliminated matrix transpose vector
multiple to a vector. The original matrix is \f$ M + M_e \f$
so we have: \f$ y += M^T x + {M_e}^T x \f$ */
void FullAddMultTranspose(const Vector & x, Vector & y) const
{ mat->AddMultTranspose(x, y); mat_e->AddMultTranspose(x, y); }
/// Matrix transpose vector multiplication: \f$ y = M^T x \f$
virtual void MultTranspose(const Vector & x, Vector & y) const
{ y = 0.0; AddMultTranspose (x, y); }
/// Compute \f$ y^T M x \f$
double InnerProduct(const Vector &x, const Vector &y) const
{ return mat->InnerProduct (x, y); }
/// Returns a pointer to (approximation) of the matrix inverse.
/// Returns a pointer to (approximation) of the matrix inverse: \f$ M^{-1} \f$
virtual MatrixInverse *Inverse() const;
/// Finalizes the matrix initialization.
virtual void Finalize(int skip_zeros = 1);
/// Returns a reference to the sparse matrix
/// Returns a const reference to the sparse matrix.
const SparseMatrix &SpMat() const
{
MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced");
return *mat;
}
/// Returns a reference to the sparse matrix: \f$ M \f$
SparseMatrix &SpMat()
{
MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced");
return *mat;
}
/** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer
to it. Used for transfering ownership. */
SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; }
/// Returns a reference to the sparse matrix of eliminated b.c.
/// Returns a const reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$
const SparseMatrix &SpMatElim() const
{
MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced");
return *mat_e;
}
/// Returns a reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$
SparseMatrix &SpMatElim()
{
MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced");
@@ -311,6 +345,7 @@ public:
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi,
Array<int> &bdr_marker);
/// Sets all sparse values of \f$ M \f$ and \f$ M_e \f$ to 'a'.
void operator=(const double a)
{
if (mat != NULL) { *mat = a; }
@@ -328,10 +363,10 @@ public:
for an AMR mesh. */
void AssembleDiagonal(Vector &diag) const;
/// Get the finite element space prolongation matrix
/// Get the finite element space prolongation operator.
virtual const Operator *GetProlongation() const
{ return fes->GetConformingProlongation(); }
/// Get the finite element space restriction matrix
/// Get the finite element space restriction operator
virtual const Operator *GetRestriction() const
{ return fes->GetConformingRestriction(); }
/// Get the output finite element space prolongation matrix
@@ -491,10 +526,12 @@ public:
double value);
/// Eliminate the given @a vdofs. NOTE: here, @a vdofs is a list of DOFs.
/** In this case the eliminations are applied to the internal \f$ M \f$
and @a rhs without storing the elimination matrix \f$ M_e \f$. */
void EliminateVDofs(const Array<int> &vdofs, const Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy = DIAG_ONE);
/// Eliminate the given @a vdofs, storing the eliminated part internally.
/// Eliminate the given @a vdofs, storing the eliminated part internally in \f$ M_e \f$.
/** This method works in conjunction with EliminateVDofsInRHS() and allows
elimination of boundary conditions in multiple right-hand sides. In this
method, @a vdofs is a list of DOFs. */
@@ -523,9 +560,11 @@ public:
void EliminateVDofsInRHS(const Array<int> &vdofs, const Vector &x,
Vector &b);
/// Compute inner product for full uneliminated matrix \f$ y^T M x + y^T M_e x \f$
double FullInnerProduct(const Vector &x, const Vector &y) const
{ return mat->InnerProduct(x, y) + mat_e->InnerProduct(x, y); }
/// Update the @a FiniteElementSpace and delete all data associated with the old one.
virtual void Update(FiniteElementSpace *nfes = NULL);
/// (DEPRECATED) Return the FE space associated with the BilinearForm.
@@ -537,7 +576,13 @@ public:
/// Read-only access to the associated FiniteElementSpace.
const FiniteElementSpace *FESpace() const { return fes; }
/// Sets diagonal policy used upon construction of the linear system
/// Sets diagonal policy used upon construction of the linear system.
/** Policies include:
- DIAG_ZERO (Set the diagonal values to zero)
- DIAG_ONE (Set the diagonal values to one)
- DIAG_KEEP (Keep the diagonal values)
*/
void SetDiagonalPolicy(DiagonalPolicy policy);
/// Indicate that integrators are not owned by the BilinearForm
@@ -550,16 +595,16 @@ public:
/**
Class for assembling of bilinear forms `a(u,v)` defined on different
trial and test spaces. The assembled matrix `A` is such that
trial and test spaces. The assembled matrix `M` is such that
a(u,v) = V^t A U
a(u,v) = V^t M U
where `U` and `V` are the vectors representing the functions `u` and `v`,
respectively. The first argument, `u`, of `a(,)` is in the trial space
and the second argument, `v`, is in the test space. Thus,
# of rows of A = dimension of the test space and
# of cols of A = dimension of the trial space.
# of rows of M = dimension of the test space and
# of cols of M = dimension of the trial space.
Both trial and test spaces should be defined on the same mesh.
*/
@@ -628,11 +673,15 @@ public:
FiniteElementSpace *te_fes,
MixedBilinearForm *mbf);
/// Returns a reference to: \f$ M_{ij} \f$
virtual double &Elem(int i, int j);
/// Returns a reference to: \f$ M_{ij} \f$
virtual const double &Elem(int i, int j) const;
/// Matrix multiplication: \f$ y = M x \f$
virtual void Mult(const Vector & x, Vector & y) const;
virtual void AddMult(const Vector & x, Vector & y,
const double a = 1.0) const;
@@ -642,6 +691,7 @@ public:
virtual MatrixInverse *Inverse() const;
/// Finalizes the matrix initialization.
virtual void Finalize(int skip_zeros = 1);
/** Extract the associated matrix as SparseMatrix blocks. The number of
@@ -649,8 +699,14 @@ public:
test and trial spaces, respectively. */
void GetBlocks(Array2D<SparseMatrix *> &blocks) const;
/// Returns a const reference to the sparse matrix: \f$ M \f$
const SparseMatrix &SpMat() const { return *mat; }
/// Returns a reference to the sparse matrix: \f$ M \f$
SparseMatrix &SpMat() { return *mat; }
/** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer
to it. Used for transfering ownership. */
SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; }
/// Adds a domain integrator. Assumes ownership of @a bfi.
@@ -697,6 +753,7 @@ public:
corresponding pointer (to Array<int>) will be NULL. */
Array<Array<int>*> *GetBTFBFI_Marker() { return &btfbfi_marker; }
/// Sets all sparse values of \f$ M \f$ to @a a.
void operator=(const double a) { *mat = a; }
/// Set the desired assembly level. The default is AssemblyLevel::FULL.
@@ -705,6 +762,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
+42 -29
View File
@@ -22,9 +22,12 @@ namespace mfem
class BilinearForm;
class MixedBilinearForm;
/** @brief Class extending the BilinearForm class to support the different
AssemblyLevel%s. */
/// Class extending the BilinearForm class to support different AssemblyLevels.
/** FA - Full Assembly
PA - Partial Assembly
EA - Element Assembly
MF - Matrix Free
*/
class BilinearFormExtension : public Operator
{
protected:
@@ -42,6 +45,7 @@ public:
/// Get the finite element space restriction matrix
virtual const Operator *GetRestriction() const;
/// Assemble at the level given for the BilinearFormExtension subclass
virtual void Assemble() = 0;
virtual void AssembleDiagonal(Vector &diag) const
@@ -58,7 +62,8 @@ public:
virtual void Update() = 0;
};
/// Data and methods for fully-assembled bilinear forms
/** @brief Data and methods for fully-assembled bilinear forms.
Not yet implemented! Use the BilinearForm Class instead. */
class FABilinearFormExtension : public BilinearFormExtension
{
public:
@@ -78,26 +83,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 +98,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,14 +105,34 @@ 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;
/// Data and methods for matrix-free bilinear forms
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 NOT YET IMPLEMENTED.
class MFBilinearFormExtension : public BilinearFormExtension
{
public:
@@ -148,8 +152,12 @@ public:
~MFBilinearFormExtension() {}
};
/** @brief Class extending the MixedBilinearForm class to support the different
AssemblyLevel%s. */
/// Class extending the MixedBilinearForm class to support different AssemblyLevels.
/** FA - Full Assembly
PA - Partial Assembly
EA - Element Assembly
MF - Matrix Free
*/
class MixedBilinearFormExtension : public Operator
{
protected:
@@ -186,6 +194,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 +246,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++)
+74 -2
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,
@@ -180,6 +199,8 @@ public:
virtual ~BilinearFormIntegrator() { }
};
/** Wraps a given @a BilinearFormIntegrator and transposes the resulting element
matrices. See for example ex9, ex9p. */
class TransposeIntegrator : public BilinearFormIntegrator
{
private:
@@ -234,6 +255,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; } }
};
@@ -1535,7 +1565,7 @@ public:
};
/** Class for integrating the bilinear form a(u,v) := (-V u, Grad v) in 2D or 3D
and where V is a vector coefficient, u is in H1 and v is in H1. */
and where V is a vector coefficient, u is in H1 or L2 and v is in H1. */
class MixedScalarWeakDivergenceIntegrator : public MixedScalarVectorIntegrator
{
public:
@@ -1885,6 +1915,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 +1990,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;
@@ -1969,6 +2003,7 @@ public:
void SetupPA(const FiniteElementSpace &fes, const bool force = false);
};
/** Mass integrator (u, v) restricted to the boundary of a domain */
class BoundaryMassIntegrator : public MassIntegrator
{
public:
@@ -2011,6 +2046,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 +2147,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 +2176,8 @@ public:
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
virtual void AssembleDiagonalPA_ADAt(const Vector &D, Vector &diag);
};
@@ -2308,7 +2361,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 +2440,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 +2609,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
+82 -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;
}
@@ -302,6 +285,22 @@ void VectorRestrictedCoefficient::Eval(
}
}
void UnitNormalCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
V.SetSize(vdim);
V = 0.0;
const DenseMatrix & J = T.Jacobian();
if (J.Width() == J.Height() - 1)
{
CalcOrtho(J, V);
double norm = V.Norml2();
MFEM_ASSERT(norm > 0.0, "Length of normal vector is non-positive!");
V /= norm;
}
}
void MatrixFunctionCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
@@ -775,4 +774,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];
}
}
+346 -80
View File
File diff suppressed because it is too large Load Diff
+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);
}
}
+149 -19
View File
@@ -38,9 +38,12 @@ protected:
};
Geometry::Type geom;
// Evaluate the Jacobian of the transformation at the IntPoint and store it
// in dFdx.
/** @brief Evaluate the Jacobian of the transformation at the IntPoint and
store it in dFdx. */
virtual const DenseMatrix &EvalJacobian() = 0;
/** @brief Evaluate the Hessian of the transformation at the IntPoint and
store it in d2Fdx2. */
virtual const DenseMatrix &EvalHessian() = 0;
double EvalWeight();
@@ -48,18 +51,53 @@ 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();
/** @brief Set the integration point @a ip that weights and Jacobians will
be evaluated at. */
void SetIntPoint(const IntegrationPoint *ip)
{ IntPoint = ip; EvalState = 0; }
/** @brief Get a const reference to the currently set integration point. This
will return NULL if no integration point is set. */
const IntegrationPoint &GetIntPoint() { return *IntPoint; }
/** @brief Transform integration point from reference coordinates to
physical coordinates and store them in the vector. */
virtual void Transform(const IntegrationPoint &, Vector &) = 0;
/** @brief Transform all the integration points from the integration rule
from reference coordinates to physical
coordinates and store them as column vectors in the matrix. */
virtual void Transform(const IntegrationRule &, DenseMatrix &) = 0;
/// Transform columns of 'matrix', store result in 'result'.
/** @brief Transform all the integration points from the column vectors
of @a matrix from reference coordinates to physical
coordinates and store them as column vectors in @a result. */
virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result) = 0;
/** @brief Return the Jacobian matrix of the transformation at the currently
@@ -70,27 +108,44 @@ public:
const DenseMatrix &Jacobian()
{ return (EvalState & JACOBIAN_MASK) ? dFdx : EvalJacobian(); }
/** @brief Return the Hessian matrix of the transformation at the currently
set IntegrationPoint, using the method SetIntPoint(). */
const DenseMatrix &Hessian()
{ return (EvalState & HESSIAN_MASK) ? d2Fdx2 : EvalHessian(); }
/** @brief Return the weight of the Jacobian matrix of the transformation
at the currently set IntegrationPoint.
The Weight evaluates to \f$ \sqrt{\lvert J^T J \rvert} \f$. */
double Weight() { return (EvalState & WEIGHT_MASK) ? Wght : EvalWeight(); }
/** @brief Return the adjugate of the Jacobian matrix of the transformation
at the currently set IntegrationPoint. */
const DenseMatrix &AdjugateJacobian()
{ return (EvalState & ADJUGATE_MASK) ? adjJ : EvalAdjugateJ(); }
/** @brief Return the inverse of the Jacobian matrix of the transformation
at the currently set IntegrationPoint. */
const DenseMatrix &InverseJacobian()
{ return (EvalState & INVERSE_MASK) ? invJ : EvalInverseJ(); }
/// Return the order of the current element we are using for the transformation.
virtual int Order() const = 0;
/// Return the order of the elements of the Jacobian of the transformation.
virtual int OrderJ() const = 0;
/** @brief Return the order of the determinant of the Jacobian (weight)
of the transformation. */
virtual int OrderW() const = 0;
/// Order of adj(J)^t.grad(fi)
/// Return the order of \f$ adj(J)^T \nabla fi \f$
virtual int OrderGrad(const FiniteElement *fe) const = 0;
/// Return the Geometry::Type of the reference element.
Geometry::Type GetGeometryType() const { return geom; }
/// Return the dimension of the reference element.
/// Return the topological dimension of the reference element.
int GetDimension() const { return Geometry::Dimension[geom]; }
/// Get the dimension of the target (physical) space.
@@ -286,7 +341,7 @@ public:
virtual int Transform(const Vector &pt, IntegrationPoint &ip);
};
/// A standard isoparametric element transformation
class IsoparametricTransformation : public ElementTransformation
{
private:
@@ -296,26 +351,29 @@ private:
const FiniteElement *FElem;
DenseMatrix PointMat; // dim x dof
// Evaluate the Jacobian of the transformation at the IntPoint and store it
// in dFdx.
/** @brief Evaluate the Jacobian of the transformation at the IntPoint and
store it in dFdx. */
virtual const DenseMatrix &EvalJacobian();
// Evaluate the Hessian of the transformation at the IntPoint and store it
// in d2Fdx2.
virtual const DenseMatrix &EvalHessian();
public:
/// Set the element that will be used to compute the transformations
void SetFE(const FiniteElement *FE) { FElem = FE; geom = FE->GetGeomType(); }
/// Get the current element used to compute the transformations
const FiniteElement* GetFE() const { return FElem; }
/// @brief Set the underlying point matrix describing the transformation.
/** The dimensions of the matrix are space-dim x dof. The transformation is
defined as
\f$ x = F( \hat x ) = P \phi( \hat x ) \f$
x = F(xh) = P . phi(xh),
where xh (x hat) is the reference point, x is the corresponding physical
point, P is the point matrix, and phi(xh) is the column-vector of all
basis functions evaluated at xh. The columns of P represent the control
points in physical space defining the transformation. */
where \f$ \hat x \f$ is the reference point, @a x is the corresponding
physical point, @a P is the point matrix, and \f$ \phi( \hat x ) \f$ is
the column-vector of all basis functions evaluated at \f$ \hat x \f$ .
The columns of @a P represent the control points in physical space
defining the transformation. */
void SetPointMat(const DenseMatrix &pm) { PointMat = pm; }
/// Return the stored point matrix.
@@ -324,19 +382,44 @@ public:
/// Write access to the stored point matrix. Use with caution.
DenseMatrix &GetPointMat() { return PointMat; }
/// Set the FiniteElement Geometry for the reference elements being used.
void SetIdentityTransformation(Geometry::Type GeomType);
/** @brief Transform integration point from reference coordinates to
physical coordinates and store them in the vector. */
virtual void Transform(const IntegrationPoint &, Vector &);
/** @brief Transform all the integration points from the integration rule
from reference coordinates to physical
coordinates and store them as column vectors in the matrix. */
virtual void Transform(const IntegrationRule &, DenseMatrix &);
/** @brief Transform all the integration points from the column vectors
of @a matrix from reference coordinates to physical
coordinates and store them as column vectors in @a result. */
virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result);
/// Return the order of the current element we are using for the transformation.
virtual int Order() const { return FElem->GetOrder(); }
/// Return the order of the elements of the Jacobian of the transformation.
virtual int OrderJ() const;
/** @brief Return the order of the determinant of the Jacobian (weight)
of the transformation. */
virtual int OrderW() const;
/// Return the order of \f$ adj(J)^T \nabla fi \f$
virtual int OrderGrad(const FiniteElement *fe) const;
virtual int GetSpaceDim() const { return PointMat.Height(); }
/** @brief Transform a point @a pt from physical space to a point @a ip in
reference space. */
/** Attempt to find the IntegrationPoint that is transformed into the given
point in physical space. If the inversion fails a non-zero value is
returned. This method is not 100 percent reliable for non-linear
transformations. */
virtual int TransformBack(const Vector & v, IntegrationPoint & ip)
{
InverseElementTransformation inv_tr(this);
@@ -356,15 +439,62 @@ 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))
/** Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x))
Physical Space
+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
+92
View File
@@ -45,6 +45,7 @@ public:
/// Force recomputation of the estimates on the next call to GetLocalErrors.
virtual void Reset() = 0;
/// Destruct the error estimator
virtual ~ErrorEstimator() { }
};
@@ -66,6 +67,14 @@ public:
/** @brief The ZienkiewiczZhuEstimator class implements the Zienkiewicz-Zhu
error estimation procedure.
Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery
and a posteriori error estimates. Part 1: The recovery technique.
Int. J. Num. Meth. Engng. 33, 1331-1364 (1992).
Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery
and a posteriori error estimates. Part 2: Error estimates and adaptivity.
Int. J. Num. Meth. Engng. 33, 1365-1382 (1992).
The required BilinearFormIntegrator must implement the methods
ComputeElementFlux() and ComputeFluxEnergy().
*/
@@ -217,6 +226,7 @@ protected:
class when needed.*/
bool own_flux_fes; ///< Ownership flag for flux_space and smooth_flux_space.
/// Initialize with the integrator, solution, and flux finite element spaces.
void Init(BilinearFormIntegrator &integ,
ParGridFunction &sol,
ParFiniteElementSpace *flux_fes,
@@ -304,6 +314,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
+519 -510
View File
File diff suppressed because it is too large Load Diff
+437 -189
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -311,10 +311,10 @@ GetEdge(int &nv, v_t &v, int &ne, int &e, int &eo, const int edge_info)
eo = edge_info%64;
MFEM_ASSERT(0 <= e && e < g_consts::NumEdges, "");
MFEM_ASSERT(0 <= eo && eo < e_consts::NumOrient, "");
v[0] = g_consts::Edges[e][0];
v[1] = g_consts::Edges[e][1];
v[0] = e_consts::Orient[eo][v[0]];
v[1] = e_consts::Orient[eo][v[1]];
v[0] = e_consts::Orient[eo][0];
v[1] = e_consts::Orient[eo][1];
v[0] = g_consts::Edges[e][v[0]];
v[1] = g_consts::Edges[e][v[1]];
}
template <Geometry::Type geom, Geometry::Type f_geom,
+176 -47
View File
@@ -19,10 +19,10 @@
namespace mfem
{
/** Collection of finite elements from the same family in multiple dimensions.
This class is used to match the degrees of freedom of a FiniteElementSpace
between elements, and to provide the finite element restriction from an
element to its boundary. */
/** @brief Collection of finite elements from the same family in multiple
dimensions. This class is used to match the degrees of freedom of a
FiniteElementSpace between elements, and to provide the finite element
restriction from an element to its boundary. */
class FiniteElementCollection
{
protected:
@@ -40,6 +40,14 @@ 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 +60,8 @@ public:
virtual const char * Name() const { return "Undefined"; }
virtual int GetContType() const = 0;
int HasFaceDofs(Geometry::Type GeomType) const;
virtual const FiniteElement *TraceFiniteElementForGeometry(
@@ -66,15 +76,81 @@ public:
/** @brief Factory method: return a newly allocated FiniteElementCollection
according to the given name. */
/**
| FEC Name | Space | Order | BasisType | FiniteElement::MapT | Notes |
| :------: | :---: | :---: | :-------: | :-----: | :---: |
| H1_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements |
| H1@[BTYPE]_[DIM]_[ORDER] | H1 | * | * | VALUE | H1 nodal elements |
| H1Pos_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements |
| H1Pos_Trace_[DIM]_[ORDER] | H^{1/2} | * | 2 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) |
| H1_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) |
| H1_Trace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) |
| ND_[DIM]_[ORDER] | H(curl) | * | 1 / 0 | H_CURL | Nedelec vector elements |
| ND@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H(curl) | * | * / * | H_CURL | Nedelec vector elements |
| ND_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | H_CURL | H^{1/2}-conforming trace elements for H(curl) defined on the interface between mesh elements (faces) |
| ND_Trace@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | H_CURL | H^{1/2}-conforming trace elements for H(curl) defined on the interface between mesh elements (faces) |
| RT_[DIM]_[ORDER] | H(div) | * | 1 / 0 | H_DIV | Raviart-Thomas vector elements |
| RT@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H(div) | * | * / * | H_DIV | Raviart-Thomas vector elements |
| RT_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | INTEGRAL | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
| RT_ValTrace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | VALUE | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
| RT_Trace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | INTEGRAL | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
| RT_ValTrace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | VALUE | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
| L2_[DIM]_[ORDER] | L2 | * | 0 | VALUE | Discontinous L2 elements |
| L2_T[BTYPE]_[DIM]_[ORDER] | L2 | * | 0 | VALUE | Discontinous L2 elements |
| L2Int_[DIM]_[ORDER] | L2 | * | 0 | INTEGRAL | Discontinous L2 elements |
| L2Int_T[BTYPE]_[DIM]_[ORDER] | L2 | * | 0 | INTEGRAL | Discontinous L2 elements |
| DG_Iface_[DIM]_[ORDER] | - | * | 0 | VALUE | Discontinuous elements on the interface between mesh elements (faces) |
| DG_Iface@[BTYPE]_[DIM]_[ORDER] | - | * | 0 | VALUE | Discontinuous elements on the interface between mesh elements (faces) |
| DG_IntIface_[DIM]_[ORDER] | - | * | 0 | INTEGRAL | Discontinuous elements on the interface between mesh elements (faces) |
| DG_IntIface@[BTYPE]_[DIM]_[ORDER] | - | * | 0 | INTEGRAL | Discontinuous elements on the interface between mesh elements (faces) |
| NURBS[ORDER] | - | * | - | VALUE | Non-Uniform Rational B-Splines (NURBS) elements |
| LinearNonConf3D | - | 1 | 1 | VALUE | Piecewise-linear nonconforming finite elements in 3D |
| CrouzeixRaviart | - | - | - | - | Crouzeix-Raviart nonconforming elements in 2D |
| Local_[FENAME] | - | - | - | - | Special collection that builds a local version out of the FENAME collection |
|-|-|-|-|-|-|
| Linear | H1 | 1 | 1 | VALUE | Left in for backward compatibility, consider using H1_ |
| Quadratic | H1 | 2 | 1 | VALUE | Left in for backward compatibility, consider using H1_ |
| QuadraticPos | H1 | 2 | 2 | VALUE | Left in for backward compatibility, consider using H1_ |
| Cubic | H1 | 2 | 1 | VALUE | Left in for backward compatibility, consider using H1_ |
| Const2D | L2 | 0 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| Const3D | L2 | 0 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| LinearDiscont2D | L2 | 1 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| GaussLinearDiscont2D | L2 | 1 | 0 | VALUE | Left in for backward compatibility, consider using L2_ |
| P1OnQuad | H1 | 1 | 1 | VALUE | Linear P1 element with 3 nodes on a square |
| QuadraticDiscont2D | L2 | 2 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| QuadraticPosDiscont2D | L2 | 2 | 2 | VALUE | Left in for backward compatibility, consider using L2_ |
| GaussQuadraticDiscont2D | L2 | 2 | 0 | VALUE | Left in for backward compatibility, consider using L2_ |
| CubicDiscont2D | L2 | 3 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| LinearDiscont3D | L2 | 1 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| QuadraticDiscont3D | L2 | 2 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
| ND1_3D | H(Curl) | 1 | 1 / 0 | H_CURL | Left in for backward compatibility, consider using ND_ |
| RT0_2D | H(Div) | 1 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
| RT1_2D | H(Div) | 2 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
| RT2_2D | H(Div) | 3 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
| RT0_3D | H(Div) | 1 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
| RT1_3D | H(Div) | 2 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
| Tag | Description |
| :------: | :--------: |
| [DIM] | Dimension of the elements (1D, 2D, 3D) |
| [ORDER] | Approximation order of the elements (P0, P1, P2, ...) |
| [BTYPE] | BasisType of the element (0-GaussLegendre, 1 - GaussLobatto, 2-Bernstein, 3-OpenUniform, 4-CloseUniform, 5-OpenHalfUniform) |
| [OBTYPE] | Open BasisType of the element for elements which have both types |
| [CBTYPE] | Closed BasisType of the element for elements which have both types |
[FENAME] Is a special case for the Local FEC which generates a local version of a given
FEC. It is selected from one of (BiCubic2DFiniteElement, Quad_Q3, Nedelec1HexFiniteElement,
Hex_ND1, H1_[DIM]_[ORDER],H1Pos_[DIM]_[ORDER], L2_[DIM]_[ORDER] )
*/
static FiniteElementCollection *New(const char *name);
/** @brief Get the local dofs for a given sub-manifold.
Return the local dofs for a SDim-dimensional sub-manifold (0D - vertex,
1D - edge, 2D - face) including those on its boundary. The local index of
the sub-manifold (inside Geom) and its orientation are given by the
parameter Info = 64 * SubIndex + SubOrientation. Naturally, it is assumed
that 0 <= SDim <= Dim(Geom). */
Return the local dofs for a SDim-dimensional sub-manifold (0D - vertex, 1D
- edge, 2D - face) including those on its boundary. The local index of the
sub-manifold (inside Geom) and its orientation are given by the parameter
Info = 64 * SubIndex + SubOrientation. Naturally, it is assumed that 0 <=
SDim <= Dim(Geom). */
void SubDofOrder(Geometry::Type Geom, int SDim, int Info,
Array<int> &dofs) const;
};
@@ -102,6 +178,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; }
@@ -111,8 +188,8 @@ public:
virtual ~H1_FECollection();
};
/** Arbitrary order H1-conforming (continuous) finite elements with positive
basis functions. */
/** @brief Arbitrary order H1-conforming (continuous) finite elements with
positive basis functions. */
class H1Pos_FECollection : public H1_FECollection
{
public:
@@ -120,6 +197,7 @@ public:
: H1_FECollection(p, dim, BasisType::Positive) { }
};
/** Arbitrary order H1-conforming (continuous) serendipity finite elements;
Current implementation works in 2D only; 3D version is in development. */
class H1Ser_FECollection : public H1_FECollection
@@ -129,9 +207,9 @@ public:
: H1_FECollection(p, dim, BasisType::Serendipity) { };
};
/** Arbitrary order "H^{1/2}-conforming" trace finite elements defined on the
interface between mesh elements (faces,edges,vertices); these are the trace
FEs of the H1-conforming FEs. */
/** @brief Arbitrary order "H^{1/2}-conforming" trace finite elements defined on
the interface between mesh elements (faces,edges,vertices); these are the
trace FEs of the H1-conforming FEs. */
class H1_Trace_FECollection : public H1_FECollection
{
public:
@@ -174,6 +252,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,14 +301,15 @@ 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();
};
/** Arbitrary order "H^{-1/2}-conforming" face finite elements defined on the
interface between mesh elements (faces); these are the normal trace FEs of
the H(div)-conforming FEs. */
/** @brief Arbitrary order "H^{-1/2}-conforming" face finite elements defined on
the interface between mesh elements (faces); these are the normal trace FEs
of the H(div)-conforming FEs. */
class RT_Trace_FECollection : public RT_FECollection
{
public:
@@ -270,14 +351,15 @@ 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();
};
/** Arbitrary order H(curl)-trace finite elements defined on the interface
between mesh elements (faces,edges); these are the tangential trace FEs of
the H(curl)-conforming FEs. */
/** @brief Arbitrary order H(curl)-trace finite elements defined on the
interface between mesh elements (faces,edges); these are the tangential
trace FEs of the H(curl)-conforming FEs. */
class ND_Trace_FECollection : public ND_FECollection
{
public:
@@ -334,13 +416,15 @@ public:
virtual const char *Name() const { return name; }
virtual int GetContType() const { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const;
virtual ~NURBSFECollection();
};
/// Piecewise-(bi)linear continuous finite elements.
/// Piecewise-(bi/tri)linear continuous finite elements.
class LinearFECollection : public FiniteElementCollection
{
private:
@@ -363,6 +447,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 +475,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 +498,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 +527,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 +550,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,11 +575,13 @@ public:
int Or) const;
virtual const char * Name() const { return "LinearNonConf3D"; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
/** First order Raviart-Thomas finite elements in 2D. This class is kept only
for backward compatibility, consider using RT_FECollection instead. */
/** @brief First order Raviart-Thomas finite elements in 2D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
class RT0_2DFECollection : public FiniteElementCollection
{
private:
@@ -504,10 +600,12 @@ 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
for backward compatibility, consider using RT_FECollection instead. */
/** @brief Second order Raviart-Thomas finite elements in 2D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
class RT1_2DFECollection : public FiniteElementCollection
{
private:
@@ -526,10 +624,12 @@ 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
for backward compatibility, consider using RT_FECollection instead. */
/** @brief Third order Raviart-Thomas finite elements in 2D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
class RT2_2DFECollection : public FiniteElementCollection
{
private:
@@ -548,10 +648,13 @@ 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
only for backward compatibility, consider using L2_FECollection instead. */
/** @brief Piecewise-constant discontinuous finite elements in 2D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
class Const2DFECollection : public FiniteElementCollection
{
private:
@@ -569,10 +672,13 @@ 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
only for backward compatibility, consider using L2_FECollection instead. */
/** @brief Piecewise-linear discontinuous finite elements in 2D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
class LinearDiscont2DFECollection : public FiniteElementCollection
{
private:
@@ -591,6 +697,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 +721,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,10 +738,12 @@ 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
only for backward compatibility, consider using L2_FECollection instead. */
/** @brief Piecewise-quadratic discontinuous finite elements in 2D. This class
is kept only for backward compatibility, consider using L2_FECollection
instead. */
class QuadraticDiscont2DFECollection : public FiniteElementCollection
{
private:
@@ -650,6 +762,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 +780,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,10 +803,12 @@ 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
only for backward compatibility, consider using L2_FECollection instead. */
/** @brief Piecewise-cubic discontinuous finite elements in 2D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
class CubicDiscont2DFECollection : public FiniteElementCollection
{
private:
@@ -711,10 +827,12 @@ 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
only for backward compatibility, consider using L2_FECollection instead. */
/** @brief Piecewise-constant discontinuous finite elements in 3D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
class Const3DFECollection : public FiniteElementCollection
{
private:
@@ -734,10 +852,12 @@ 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
only for backward compatibility, consider using L2_FECollection instead. */
/** @brief Piecewise-linear discontinuous finite elements in 3D. This class is
kept only for backward compatibility, consider using L2_FECollection
instead. */
class LinearDiscont3DFECollection : public FiniteElementCollection
{
private:
@@ -756,10 +876,12 @@ 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
only for backward compatibility, consider using L2_FECollection instead. */
/** @brief Piecewise-quadratic discontinuous finite elements in 3D. This class
is kept only for backward compatibility, consider using L2_FECollection
instead. */
class QuadraticDiscont3DFECollection : public FiniteElementCollection
{
private:
@@ -778,6 +900,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,10 +926,12 @@ 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
backward compatibility, consider using the new ND_FECollection instead. */
/** @brief Lowest order Nedelec finite elements in 3D. This class is kept only
for backward compatibility, consider using the new ND_FECollection
instead. */
class ND1_3DFECollection : public FiniteElementCollection
{
private:
@@ -825,10 +950,11 @@ 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
for backward compatibility, consider using RT_FECollection instead. */
/** @brief First order Raviart-Thomas finite elements in 3D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
class RT0_3DFECollection : public FiniteElementCollection
{
private:
@@ -848,10 +974,11 @@ 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
for backward compatibility, consider using RT_FECollection instead. */
/** @brief Second order Raviart-Thomas finite elements in 3D. This class is kept
only for backward compatibility, consider using RT_FECollection instead. */
class RT1_3DFECollection : public FiniteElementCollection
{
private:
@@ -870,6 +997,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 +1022,7 @@ public:
virtual const char *Name() const { return d_name; }
virtual ~Local_FECollection() { delete Local_Element; }
virtual int GetContType() const { return DISCONTINUOUS; }
};
}
+173 -47
View File
@@ -60,7 +60,7 @@ FiniteElementSpace::FiniteElementSpace()
: mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
fdofs(NULL), bdofs(NULL),
elem_dof(NULL), bdrElem_dof(NULL),
elem_dof(NULL), bdrElem_dof(NULL), face_dof(NULL),
NURBSext(NULL), own_ext(false),
cP(NULL), cR(NULL), cP_is_set(false),
Th(Operator::ANY_TYPE),
@@ -233,6 +233,54 @@ void FiniteElementSpace::BuildElementToDofTable() const
elem_dof = el_dof;
}
void FiniteElementSpace::BuildBdrElementToDofTable() const
{
if (bdrElem_dof) { return; }
Table *bel_dof = new Table;
Array<int> dofs;
bel_dof->MakeI(mesh->GetNBE());
for (int i = 0; i < mesh->GetNBE(); i++)
{
GetBdrElementDofs(i, dofs);
bel_dof->AddColumnsInRow(i, dofs.Size());
}
bel_dof->MakeJ();
for (int i = 0; i < mesh->GetNBE(); i++)
{
GetBdrElementDofs(i, dofs);
bel_dof->AddConnections(i, (int *)dofs, dofs.Size());
}
bel_dof->ShiftUpI();
bdrElem_dof = bel_dof;
}
void FiniteElementSpace::BuildFaceToDofTable() const
{
// Here, "face" == (dim-1)-dimensional mesh entity.
if (face_dof) { return; }
if (NURBSext) { BuildNURBSFaceToDofTable(); return; }
Table *fc_dof = new Table;
Array<int> dofs;
fc_dof->MakeI(mesh->GetNumFaces());
for (int i = 0; i < fc_dof->Size(); i++)
{
GetFaceDofs(i, dofs);
fc_dof->AddColumnsInRow(i, dofs.Size());
}
fc_dof->MakeJ();
for (int i = 0; i < fc_dof->Size(); i++)
{
GetFaceDofs(i, dofs);
fc_dof->AddConnections(i, (int *)dofs, dofs.Size());
}
fc_dof->ShiftUpI();
face_dof = fc_dof;
}
void FiniteElementSpace::RebuildElementToDofTable()
{
delete elem_dof;
@@ -1456,6 +1504,7 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext,
this->ordering = (Ordering::Type) ordering;
elem_dof = NULL;
face_dof = NULL;
sequence = mesh->GetSequence();
Th.SetType(Operator::ANY_TYPE);
@@ -1505,6 +1554,8 @@ NURBSExtension *FiniteElementSpace::StealNURBSext()
void FiniteElementSpace::UpdateNURBS()
{
MFEM_VERIFY(NURBSext, "NURBSExt not defined.");
nvdofs = 0;
nedofs = 0;
nfdofs = 0;
@@ -1512,6 +1563,10 @@ void FiniteElementSpace::UpdateNURBS()
fdofs = NULL;
bdofs = NULL;
delete face_dof;
face_dof = NULL;
face_to_be.DeleteAll();
dynamic_cast<const NURBSFECollection *>(fec)->Reset();
ndofs = NURBSext->GetNDof();
@@ -1519,6 +1574,55 @@ void FiniteElementSpace::UpdateNURBS()
bdrElem_dof = NURBSext->GetBdrElementDofTable();
}
void FiniteElementSpace::BuildNURBSFaceToDofTable() const
{
if (face_dof) { return; }
const int dim = mesh->Dimension();
// Find bdr to face mapping
face_to_be.SetSize(GetNF());
face_to_be = -1;
for (int b = 0; b < GetNBE(); b++)
{
int f = mesh->GetBdrElementEdgeIndex(b);
face_to_be[f] = b;
}
// Loop over faces in correct order, to prevent a sort
// Sort will destroy orientation info in ordering of dofs
Array<Connection> face_dof_list;
Array<int> row;
for (int f = 0; f < GetNF(); f++)
{
int b = face_to_be[f];
if (b == -1) { continue; }
// FIXME: this assumes the boundary element and the face element have the
// same orientation.
if (dim > 1)
{
const Element *fe = mesh->GetFace(f);
const Element *be = mesh->GetBdrElement(b);
const int nv = be->GetNVertices();
const int *fv = fe->GetVertices();
const int *bv = be->GetVertices();
for (int i = 0; i < nv; i++)
{
MFEM_VERIFY(fv[i] == bv[i],
"non-matching face and boundary elements detected!");
}
}
GetBdrElementDofs(b, row);
Connection conn(f,0);
for (int i = 0; i < row.Size(); i++)
{
conn.to = row[i];
face_dof_list.Append(conn);
}
}
face_dof = new Table(GetNF(), face_dof_list);
}
void FiniteElementSpace::Construct()
{
// This method should be used only for non-NURBS spaces.
@@ -1526,6 +1630,7 @@ void FiniteElementSpace::Construct()
elem_dof = NULL;
bdrElem_dof = NULL;
face_dof = NULL;
ndofs = 0;
nedofs = nfdofs = nbdofs = 0;
@@ -1788,59 +1893,68 @@ void FiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
void FiniteElementSpace::GetFaceDofs(int i, Array<int> &dofs) const
{
int j, k, nv, ne, nf, nd, dim = mesh->Dimension();
Array<int> V, E, Eo;
const int *ind;
// If face_dof is already built, use it.
// If it is not and we have a NURBS space, build the face_dof and use it.
if (face_dof || (NURBSext && (BuildNURBSFaceToDofTable(), true)))
{
face_dof->GetRow(i, dofs);
}
else
{
int j, k, nv, ne, nf, nd, dim = mesh->Dimension();
Array<int> V, E, Eo;
const int *ind;
// for 1D, 2D and 3D faces
nv = fec->DofForGeometry(Geometry::POINT);
ne = (dim > 1) ? fec->DofForGeometry(Geometry::SEGMENT) : 0;
if (nv > 0)
{
mesh->GetFaceVertices(i, V);
}
if (ne > 0)
{
mesh->GetFaceEdges(i, E, Eo);
}
nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0);
nd = V.Size() * nv + E.Size() * ne + nf;
dofs.SetSize(nd);
if (nv > 0)
{
for (k = 0; k < V.Size(); k++)
// for 1D, 2D and 3D faces
nv = fec->DofForGeometry(Geometry::POINT);
ne = (dim > 1) ? fec->DofForGeometry(Geometry::SEGMENT) : 0;
if (nv > 0)
{
for (j = 0; j < nv; j++)
{
dofs[k*nv+j] = V[k]*nv+j;
}
mesh->GetFaceVertices(i, V);
}
}
nv *= V.Size();
if (ne > 0)
{
for (k = 0; k < E.Size(); k++)
if (ne > 0)
{
ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[k]);
for (j = 0; j < ne; j++)
mesh->GetFaceEdges(i, E, Eo);
}
nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0);
nd = V.Size() * nv + E.Size() * ne + nf;
dofs.SetSize(nd);
if (nv > 0)
{
for (k = 0; k < V.Size(); k++)
{
if (ind[j] < 0)
for (j = 0; j < nv; j++)
{
dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) );
}
else
{
dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j];
dofs[k*nv+j] = V[k]*nv+j;
}
}
}
}
ne = nv + ne * E.Size();
if (nf > 0)
{
for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++)
nv *= V.Size();
if (ne > 0)
{
dofs[ne+k] = j;
for (k = 0; k < E.Size(); k++)
{
ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[k]);
for (j = 0; j < ne; j++)
{
if (ind[j] < 0)
{
dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) );
}
else
{
dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j];
}
}
}
}
ne = nv + ne * E.Size();
if (nf > 0)
{
for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++)
{
dofs[ne+k] = j;
}
}
}
}
@@ -1969,14 +2083,21 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const
fe = fec->FiniteElementForGeometry(mesh->GetFaceBaseGeometry(i));
}
// if (NURBSext)
// NURBSext->LoadFaceElement(i, fe);
if (NURBSext)
{
// Ensure 'face_to_be' is built:
if (!face_dof) { BuildNURBSFaceToDofTable(); }
MFEM_ASSERT(face_to_be[i] >= 0,
"NURBS mesh: only boundary faces are supported!");
NURBSext->LoadBE(face_to_be[i], fe);
}
return fe;
}
const FiniteElement *FiniteElementSpace::GetEdgeElement(int i) const
{
MFEM_ASSERT(mesh->Dimension() > 1, "No edges with a mesh dimension < 2");
return fec->FiniteElementForGeometry(Geometry::SEGMENT);
}
@@ -2024,11 +2145,14 @@ void FiniteElementSpace::Destroy()
if (NURBSext)
{
if (own_ext) { delete NURBSext; }
delete face_dof;
face_to_be.DeleteAll();
}
else
{
delete elem_dof;
delete bdrElem_dof;
delete face_dof;
delete [] bdofs;
delete [] fdofs;
@@ -2615,7 +2739,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,
+75 -30
View File
@@ -111,7 +111,9 @@ protected:
int *fdofs, *bdofs;
mutable Table *elem_dof; // if NURBS FE space, not owned; otherwise, owned.
Table *bdrElem_dof; // used only with NURBS FE spaces; not owned.
mutable Table *bdrElem_dof; // not owned only if NURBS FE space.
mutable Table *face_dof; // owned
mutable Array<int> face_to_be; // used only with NURBS FE spaces; owned.
Array<int> dof_elem_array, dof_ldof_array;
@@ -158,6 +160,14 @@ protected:
void Destroy();
void BuildElementToDofTable() const;
void BuildBdrElementToDofTable() const;
void BuildFaceToDofTable() const;
/** @brief Generates partial face_dof table for a NURBS space.
The table is only defined for exterior faces that coincide with a
boundary. */
void BuildNURBSFaceToDofTable() const;
/// Helpers to remove encoded sign from a DOF
static inline int DecodeDof(int dof)
@@ -206,7 +216,7 @@ protected:
virtual ~RefinementOperator();
};
// Derefinement operator, used by the friend class InterpolationGridTransfer.
/// Derefinement operator, used by the friend class InterpolationGridTransfer.
class DerefinementOperator : public Operator
{
const FiniteElementSpace *fine_fes; // Not owned.
@@ -225,12 +235,12 @@ protected:
virtual ~DerefinementOperator();
};
// This method makes the same assumptions as the method:
// void GetLocalRefinementMatrices(
// const FiniteElementSpace &coarse_fes, Geometry::Type geom,
// DenseTensor &localP) const
// which is defined below. It also assumes that the coarse fes and this have
// the same vector dimension, vdim.
/** This method makes the same assumptions as the method:
void GetLocalRefinementMatrices(
const FiniteElementSpace &coarse_fes, Geometry::Type geom,
DenseTensor &localP) const
which is defined below. It also assumes that the coarse fes and this have
the same vector dimension, vdim. */
SparseMatrix *RefinementMatrix_main(const int coarse_ndofs,
const Table &coarse_elem_dof,
const DenseTensor localP[]) const;
@@ -248,11 +258,13 @@ protected:
/// Calculate GridFunction restriction matrix after mesh derefinement.
SparseMatrix* DerefinementMatrix(int old_ndofs, const Table* old_elem_dof);
// This method assumes that this->mesh is a refinement of coarse_fes->mesh
// and that the CoarseFineTransformations of this->mesh are set accordingly.
// Another assumption is that the FEs of this use the same MapType as the FEs
// of coarse_fes. Finally, it assumes that the spaces this and coarse_fes are
// NOT variable-order spaces.
/** @brief Return in @a localP the local refinement matrices that map
between fespaces after mesh refinement. */
/** This method assumes that this->mesh is a refinement of coarse_fes->mesh
and that the CoarseFineTransformations of this->mesh are set accordingly.
Another assumption is that the FEs of this use the same MapType as the FEs
of coarse_fes. Finally, it assumes that the spaces this and coarse_fes are
NOT variable-order spaces. */
void GetLocalRefinementMatrices(const FiniteElementSpace &coarse_fes,
Geometry::Type geom,
DenseTensor &localP) const;
@@ -467,11 +479,11 @@ public:
/// Returns indexes of degrees of freedom for i'th boundary element.
virtual void GetBdrElementDofs(int i, Array<int> &dofs) const;
/** Returns the indexes of the degrees of freedom for i'th face
/** @brief eturns the indexes of the degrees of freedom for i'th face
including the dofs for the edges and the vertices of the face. */
virtual void GetFaceDofs(int i, Array<int> &dofs) const;
/** Returns the indexes of the degrees of freedom for i'th edge
/** @brief Returns the indexes of the degrees of freedom for i'th edge
including the dofs for the vertices of the edge. */
void GetEdgeDofs(int i, Array<int> &dofs) const;
@@ -526,28 +538,59 @@ public:
is preserved. */
void ReorderElementToDofTable();
/** @brief Return a reference to the internal Table that stores the lists of
scalar dofs, for each mesh element, as returned by GetElementDofs(). */
const Table &GetElementToDofTable() const { return *elem_dof; }
/** @brief Return a reference to the internal Table that stores the lists of
scalar dofs, for each boundary mesh element, as returned by
GetBdrElementDofs(). */
const Table &GetBdrElementToDofTable() const
{ if (!bdrElem_dof) { BuildBdrElementToDofTable(); } return *bdrElem_dof; }
/** @brief Return a reference to the internal Table that stores the lists of
scalar dofs, for each face in the mesh, as returned by GetFaceDofs(). In
this context, "face" refers to a (dim-1)-dimensional mesh entity. */
/** @note In the case of a NURBS space, the rows corresponding to interior
faces will be empty. */
const Table &GetFaceToDofTable() const
{ if (!face_dof) { BuildFaceToDofTable(); } return *face_dof; }
/** @brief Initialize internal data that enables the use of the methods
GetElementForDof() and GetLocalDofForDof(). */
void BuildDofToArrays();
const Table &GetElementToDofTable() const { return *elem_dof; }
const Table &GetBdrElementToDofTable() const { return *bdrElem_dof; }
/// Return the index of the first element that contains dof @a i.
/** This method can be called only after setup is performed using the method
BuildDofToArrays(). */
int GetElementForDof(int i) const { return dof_elem_array[i]; }
/// Return the local dof index in the first element that contains dof @a i.
/** This method can be called only after setup is performed using the method
BuildDofToArrays(). */
int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; }
/// Returns pointer to the FiniteElement associated with i'th element.
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th element in the mesh object. */
const FiniteElement *GetFE(int i) const;
/// Returns pointer to the FiniteElement for the i'th boundary element.
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th boundary face in the mesh object. */
const FiniteElement *GetBE(int i) const;
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th face in the mesh object. Faces in this case refer
to the MESHDIM-1 primitive so in 2D they are segments and in 1D they are
points.*/
const FiniteElement *GetFaceElement(int i) const;
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
associated with i'th edge in the mesh object. */
const FiniteElement *GetEdgeElement(int i) const;
/// Return the trace element from element 'i' to the given 'geom_type'
const FiniteElement *GetTraceElement(int i, Geometry::Type geom_type) const;
/** Mark degrees of freedom associated with boundary elements with
/** @brief Mark degrees of freedom associated with boundary elements with
the specified boundary attributes (marked in 'bdr_attr_is_ess').
For spaces with 'vdim' > 1, the 'component' parameter can be used
to restricts the marked vDOFs to the specified component. */
@@ -555,7 +598,7 @@ public:
Array<int> &ess_vdofs,
int component = -1) const;
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
/** @brief Get a list of essential true dofs, ess_tdof_list, corresponding to the
boundary attributes marked in the array bdr_attr_is_ess.
For spaces with 'vdim' > 1, the 'component' parameter can be used
to restricts the marked tDOFs to the specified component. */
@@ -566,19 +609,19 @@ public:
/// Convert a Boolean marker array to a list containing all marked indices.
static void MarkerToList(const Array<int> &marker, Array<int> &list);
/** Convert an array of indices (list) to a Boolean marker array where all
/** @brief Convert an array of indices (list) to a Boolean marker array where all
indices in the list are marked with the given value and the rest are set
to zero. */
static void ListToMarker(const Array<int> &list, int marker_size,
Array<int> &marker, int mark_val = -1);
/** For a partially conforming FE space, convert a marker array (nonzero
/** @brief For a partially conforming FE space, convert a marker array (nonzero
entries are true) on the partially conforming dofs to a marker array on
the conforming dofs. A conforming dofs is marked iff at least one of its
dependent dofs is marked. */
void ConvertToConformingVDofs(const Array<int> &dofs, Array<int> &cdofs);
/** For a partially conforming FE space, convert a marker array (nonzero
/** @brief For a partially conforming FE space, convert a marker array (nonzero
entries are true) on the conforming dofs to a marker array on the
(partially conforming) dofs. A dof is marked iff it depends on a marked
conforming dofs, where dependency is defined by the ConformingRestriction
@@ -586,15 +629,15 @@ public:
conforming dof. */
void ConvertFromConformingVDofs(const Array<int> &cdofs, Array<int> &dofs);
/** Generate the global restriction matrix from a discontinuous
/** @brief Generate the global restriction matrix from a discontinuous
FE space to the continuous FE space of the same polynomial degree. */
SparseMatrix *D2C_GlobalRestrictionMatrix(FiniteElementSpace *cfes);
/** Generate the global restriction matrix from a discontinuous
/** @brief Generate the global restriction matrix from a discontinuous
FE space to the piecewise constant FE space. */
SparseMatrix *D2Const_GlobalRestrictionMatrix(FiniteElementSpace *cfes);
/** Construct the restriction matrix from the FE space given by
/** @brief Construct the restriction matrix from the FE space given by
(*this) to the lower degree FE space given by (*lfes) which
is defined on the same mesh. */
SparseMatrix *H2L_GlobalRestrictionMatrix(FiniteElementSpace *lfes);
@@ -631,7 +674,7 @@ public:
virtual void GetTrueTransferOperator(const FiniteElementSpace &coarse_fes,
OperatorHandle &T) const;
/** Reflect changes in the mesh: update number of DOFs, etc. Also, calculate
/** @brief Reflect changes in the mesh: update number of DOFs, etc. Also, calculate
GridFunction transformation operator (unless want_transform is false).
Safe to call multiple times, does nothing if space already up to date. */
virtual void Update(bool want_transform = true);
@@ -669,6 +712,7 @@ public:
return dynamic_cast<const L2_FECollection*>(fec) != NULL;
}
/// Save finite element space to output stream @a out.
void Save(std::ostream &out) const;
/** @brief Read a FiniteElementSpace from a stream. The returned
@@ -906,7 +950,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++)
{
+161 -28
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); }
@@ -496,11 +598,13 @@ public:
type = adios2stream::data_type::point_data) const;
#endif
/** Write the GridFunction in VTK format. Note that Mesh::PrintVTK must be
called first. The parameter ref > 0 must match the one used in
/** @brief Write the GridFunction in VTK format. Note that Mesh::PrintVTK
must be called first. The parameter ref > 0 must match the one used in
Mesh::PrintVTK. */
void SaveVTK(std::ostream &out, const std::string &field_name, int ref);
/** @brief Write the GridFunction in STL format. Note that the mesh dimension
must be 2 and that quad elements will be broken into two triangles.*/
void SaveSTL(std::ostream &out, int TimesToRefine = 1);
/// Destroys grid function.
@@ -633,6 +737,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 +851,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;
+1 -1
View File
@@ -19,7 +19,7 @@
namespace mfem
{
/// Class for linear form - Vector with associated FE space and LFIntegrators.
/// Vector with associated FE space and LinearFormIntegrators.
class LinearForm : public Vector
{
protected:
+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
+3 -4
View File
@@ -20,10 +20,9 @@
namespace mfem
{
/** The abstract base class NonlinearFormIntegrator is used to express the
local action of a general nonlinear finite element operator. In addition
it may provide the capability to assemble the local gradient operator
and to compute the local energy. */
/** @brief This class is used to express the local action of a general nonlinear
finite element operator. In addition it may provide the capability to
assemble the local gradient operator and to compute the local energy. */
class NonlinearFormIntegrator
{
protected:
+5
View File
@@ -487,6 +487,11 @@ void ParFiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
void ParFiniteElementSpace::GetFaceDofs(int i, Array<int> &dofs) const
{
if (face_dof)
{
face_dof->GetRow(i, dofs);
return;
}
FiniteElementSpace::GetFaceDofs(i, dofs);
if (Conforming())
{
+1 -1
View File
@@ -376,7 +376,7 @@ public:
void PrintPartitionStats();
// Obsolete, kept for backward compatibility
/// Obsolete, kept for backward compatibility
int TrueVSize() const { return ltdof_size; }
};
+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;
+239 -146
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"
@@ -23,16 +24,32 @@
namespace mfem
{
// Templated bilinear form class, cf. bilinearform.?pp
/** @brief Templated bilinear form class, cf. bilinearform.?pp
// complex_t - sol dof data type
@tparam meshType typically TMesh, which is templated on FE type
// real_t - mesh nodes, sol basis, mesh basis data type
@tparam solFESpace eg. H1_FiniteElementSpace
@tparam IR integration rule, typically TIntegrationRule, which is further
templated on element geometry
@tparam IntegratorType typically a TIntegrator, which is templated on a
kernel, eg. TDiffusionKernel or TMassKernel. This
describes what actual problem you solve.
@tparam solVecLayout_t describes how degrees of freedom are laid out,
scalar or vector, column/row major, etc.
@tparam complex_t data type for solution dofs
@tparam real_t data type for mesh nodes, solution basis, and mesh basis
*/
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 +65,47 @@ 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;
/// @name IntegratorType defines several internal types
///@{
typedef IntegratorType integ_t;
/// coeff_t might be TConstantCoefficient or TFunctionCoefficient, for example
typedef typename integ_t::coefficient_type coeff_t;
typedef typename integ_t::template kernel<sdim,dim,complex_t>::type kernel_t;
/// kernel_t may be TDiffusionKernel or TMassKernel
typedef typename integ_t::template kernel<sdim,dim,vcomplex_t>::type kernel_t;
/// p_assembled_t is something like a TTensor or TMatrix for partial assembly
typedef typename kernel_t::template p_asm_data<qpts>::type p_assembled_t;
/// f_assembled_t is something like a TTensor or TMatrix for full assembly
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
/** @brief Contains matrix sizes, type of kernel (ElementMatrix is templated
on a kernel, e.g. ElementMatrix::Compute may be AssembleGradGrad()). */
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 +124,7 @@ protected:
coeff_t coeff;
p_assembled_t *assembled_data;
Memory<p_assembled_t> assembled_data;
const FiniteElementSpace &in_fes;
@@ -101,13 +139,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 +161,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 +176,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,49 +186,49 @@ 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);
}
}
// Partial assembly of quadrature point data
/// 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 +236,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 +264,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 +279,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,98 +296,108 @@ 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;
}
}
// partial assembly from "serialized" nodes
/// Partial assembly from "serialized" nodes
// 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;
}
}
// serialized vector sx --> serialized vector 'sy'
/// serialized vector sx --> serialized vector 'sy'
// complex_t = double
void MultAssembledSerialized(const Vector &sx, Vector &sy) const
{
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
// Assemble the operator in a SparseMatrix.
/// Assemble the operator in a SparseMatrix.
// 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,79 +405,100 @@ 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);
}
}
}
}
// Assemble element matrices and store them as a DenseTensor object.
/// Assemble element matrices and store them as a DenseTensor object.
// 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];
}
}
}
}
}
}
// Assemble element matrices and add them to the bilinear form
/// Assemble element matrices and add them to the bilinear form
// 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,61 +509,93 @@ 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);
}
}
}
}
// Multiplication using assembled element matrices stored as a DenseTensor.
/// Multiplication using assembled element matrices stored as a DenseTensor.
// complex_t = double
void AddMult(DenseTensor &M, const Vector &x, Vector &y) const
{
@@ -513,7 +606,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);
+159 -140
View File
@@ -21,8 +21,7 @@ namespace mfem
// Templated local bilinear form integrator kernels, cf. bilininteg.?pp
// The Integrator class combines a kernel and a coefficient
/// The Integrator class combines a kernel and a coefficient
template <typename coeff_t, template<int,int,typename> class kernel_t>
class TIntegrator
{
@@ -38,46 +37,48 @@ public:
};
// Mass kernel
/// Mass kernel
template <int SDim, int Dim, typename complex_t>
struct TMassKernel
{
typedef complex_t complex_type;
// needed for the TElementTransformation::Result class
/// Needed for the TElementTransformation::Result class
static const bool uses_Jacobians = true;
// needed for the FieldEvaluator::Data class
/// @name Needed for the FieldEvaluator::Data class
///@{
static const bool in_values = true;
static const bool in_gradients = false;
static const bool out_values = true;
static const bool out_gradients = false;
///@}
// Partially assembled data type for one element with the given number of
// quadrature points. This type is used in partial assembly, and partially
// assembled action.
/** @brief Partially assembled data type for one element with the given number of
quadrature points. This type is used in partial assembly, and partially
assembled action. */
template <int qpts>
struct p_asm_data { typedef TVector<qpts,complex_t> type; };
// Partially assembled data type for one element with the given number of
// quadrature points. This type is used in full element matrix assembly.
/** @brief Partially assembled data type for one element with the given
number of quadrature points. This type is used in full element matrix
assembly. */
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.
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
// Q - CoefficientEval<>::Type
// q - CoefficientEval<>::Type::result_t
// val_qpts [M x NC x NE] - in/out data member in R
//
// val_qpts *= w det(J)
/** @brief Method used for un-assembled (matrix free) action.
@param k the element number
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
@param Q CoefficientEval<>::Type
@param q CoefficientEval<>::Type::result_t
@param R val_qpts [M x NC x NE] - in/out data member in R
val_qpts *= w det(J) */
template <typename T_result_t, typename Q_t, typename q_t,
typename S_data_t>
static inline MFEM_ALWAYS_INLINE
@@ -101,13 +102,16 @@ struct TMassKernel
}
}
// Method defining partial assembly.
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
// Q - CoefficientEval<>::Type
// q - CoefficientEval<>::Type::result_t
// A [M] - partially assembled scalars
//
// A = w det(J)
/** @brief Method defining partial assembly.
Result in A is the quadrature-point dependent part of element matrix
assembly (as opposed to part that is same for all elements),
A = w det(J)
@param k the element number
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
@param Q CoefficientEval<>::Type
@param q CoefficientEval<>::Type::result_t
@param A [M] - partially assembled scalars
*/
template <typename T_result_t, typename Q_t, typename q_t, int qpts>
static inline MFEM_ALWAYS_INLINE
void Assemble(const int k, const T_result_t &F,
@@ -124,11 +128,12 @@ struct TMassKernel
}
}
// Method for partially assembled action.
// A [M] - partially assembled scalars
// val_qpts [M x NC x NE] - in/out data member in R
//
// val_qpts *= A
/** @brief Method for partially assembled action.
@param k the element number
@param A [M] - partially assembled scalars
@param R val_qpts [M x NC x NE] - in/out data member in R
val_qpts *= A
*/
template <int qpts, typename S_data_t>
static inline MFEM_ALWAYS_INLINE
void MultAssembled(const int k, const TVector<qpts,complex_t> &A, S_data_t &R)
@@ -148,51 +153,54 @@ struct TMassKernel
};
// Diffusion kernel
// complex_t - type for the assembled data
/** @brief Diffusion kernel
@tparam complex_t - type for the assembled data
*/
template <int SDim, int Dim, typename complex_t>
struct TDiffusionKernel;
// Diffusion kernel in 1D
/// Diffusion kernel in 1D
template <typename complex_t>
struct TDiffusionKernel<1,1,complex_t>
{
typedef complex_t complex_type;
// needed for the TElementTransformation::Result class
/// Needed for the TElementTransformation::Result class
static const bool uses_Jacobians = true;
// needed for the FieldEvaluator::Data class
/// Needed for the FieldEvaluator::Data class
///@{
static const bool in_values = false;
static const bool in_gradients = true;
static const bool out_values = false;
static const bool out_gradients = true;
///@}
// Partially assembled data type for one element with the given number of
// quadrature points. This type is used in partial assembly, and partially
// assembled action.
/** @brief Partially assembled data type for one element with the given number of
quadrature points. This type is used in partial assembly, and partially
assembled action. */
template <int qpts>
struct p_asm_data { typedef TMatrix<qpts,1,complex_t> type; };
// Partially assembled data type for one element with the given number of
// quadrature points. This type is used in full element matrix assembly.
/** @brief Partially assembled data type for one element with the given number of
quadrature points. This type is used in full element matrix assembly. */
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.
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
// Q - CoefficientEval<>::Type
// q - CoefficientEval<>::Type::result_t
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
//
// grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
/** @brief Method used for un-assembled (matrix free) action.
@param k the element number
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
@param Q - CoefficientEval<>::Type
@param q - CoefficientEval<>::Type::result_t
@param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts */
template <typename T_result_t, typename Q_t, typename q_t,
typename S_data_t>
static inline MFEM_ALWAYS_INLINE
@@ -214,17 +222,20 @@ struct TDiffusionKernel<1,1,complex_t>
}
}
// Method defining partial assembly. The pointwise Dim x Dim matrices are
// stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2)
// or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3)
// matrices.
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
// Q - CoefficientEval<>::Type
// q - CoefficientEval<>::Type::result_t
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
// A [M x Dim x Dim] - partially assembled Dim x Dim matrices
//
// A = (w/det(J)) adj(J) adj(J)^t
/** @brief Method defining partial assembly.
The pointwise Dim x Dim matrices are stored as symmetric (when
asm_type == p_asm_data, i.e. A.layout.rank == 2) or
non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank
== 3) matrices.
@param k the element number
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
@param Q CoefficientEval<>::Type
@param q CoefficientEval<>::Type::result_t
@param A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
A [M x Dim x Dim] - partially assembled Dim x Dim matrices
A = (w/det(J)) adj(J) adj(J)^t
*/
template <typename T_result_t, typename Q_t, typename q_t, typename asm_type>
static inline MFEM_ALWAYS_INLINE
void Assemble(const int k, const T_result_t &F,
@@ -240,13 +251,13 @@ struct TDiffusionKernel<1,1,complex_t>
A[i] = Q.get(q,i,k) / F.Jt(i,0,0,k);
}
}
// Method for partially assembled action.
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
// matrices
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
//
// grad_qpts = A grad_qpts
/** @brief Method for partially assembled action.
@param k the element number
@param A [M x Dim*(Dim+1)/2] partially assembled Dim x Dim symmetric
matrices
@param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
grad_qpts = A grad_qpts
*/
template <int qpts, typename S_data_t>
static inline MFEM_ALWAYS_INLINE
void MultAssembled(const int k, const TMatrix<qpts,1,complex_t> &A,
@@ -266,46 +277,49 @@ struct TDiffusionKernel<1,1,complex_t>
}
};
// Diffusion kernel in 2D
/// Diffusion kernel in 2D
template <typename complex_t>
struct TDiffusionKernel<2,2,complex_t>
{
typedef complex_t complex_type;
// needed for the TElementTransformation::Result class
/// Needed for the TElementTransformation::Result class
static const bool uses_Jacobians = true;
// needed for the FieldEvaluator::Data class
/// Needed for the FieldEvaluator::Data class
///@{
static const bool in_values = false;
static const bool in_gradients = true;
static const bool out_values = false;
static const bool out_gradients = true;
///@}
// Partially assembled data type for one element with the given number of
// quadrature points. This type is used in partial assembly, and partially
// assembled action. Stores one symmetric 2 x 2 matrix per point.
/** @brief Partially assembled data type for one element with the given number of
quadrature points. This type is used in partial assembly, and partially
assembled action. Stores one symmetric 2 x 2 matrix per point. */
template <int qpts>
struct p_asm_data { typedef TMatrix<qpts,3,complex_t> type; };
// Partially assembled data type for one element with the given number of
// quadrature points. This type is used in full element matrix assembly.
// Stores one general (non-symmetric) 2 x 2 matrix per point.
/** @brief Partially assembled data type for one element with the given number of
quadrature points. This type is used in full element matrix assembly.
Stores one general (non-symmetric) 2 x 2 matrix per point. */
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.
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
// Q - CoefficientEval<>::Type
// q - CoefficientEval<>::Type::result_t
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
//
// grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
/** @brief Method used for un-assembled (matrix free) action.
@param k the element number
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
@param Q CoefficientEval<>::Type
@param q CoefficientEval<>::Type::result_t
@param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
*/
template <typename T_result_t, typename Q_t, typename q_t,
typename S_data_t>
static inline MFEM_ALWAYS_INLINE
@@ -338,17 +352,18 @@ struct TDiffusionKernel<2,2,complex_t>
}
}
// Method defining partial assembly. The pointwise Dim x Dim matrices are
// stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2)
// or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3)
// matrices.
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
// Q - CoefficientEval<>::Type
// q - CoefficientEval<>::Type::result_t
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
// A [M x Dim x Dim] - partially assembled Dim x Dim matrices
//
// A = (w/det(J)) adj(J) adj(J)^t
/** @brief Method defining partial assembly.
The pointwise Dim x Dim matrices are stored as symmetric (when
asm_type == p_asm_data, i.e. A.layout.rank == 2) or non-symmetric
(when asm_type == f_asm_data, i.e. A.layout.rank == 3) matrices.
A = (w/det(J)) adj(J) adj(J)^t
@param k the element number
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
@param Q CoefficientEval<>::Type
@param q CoefficientEval<>::Type::result_t
@param A [M x Dim*(Dim+1)/2] partially assembled Dim x Dim symm. matrices
@param A [M x Dim x Dim] partially assembled Dim x Dim matrices
*/
template <typename T_result_t, typename Q_t, typename q_t, typename asm_type>
static inline MFEM_ALWAYS_INLINE
void Assemble(const int k, const T_result_t &F,
@@ -376,12 +391,13 @@ struct TDiffusionKernel<2,2,complex_t>
}
}
// Method for partially assembled action.
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
// matrices
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
//
// grad_qpts = A grad_qpts
/** @brief Method for partially assembled action.
@param k the element number
@param A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
matrices
@param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
grad_qpts = A grad_qpts
*/
template <int qpts, typename S_data_t>
static inline MFEM_ALWAYS_INLINE
void MultAssembled(const int k, const TMatrix<qpts,3,complex_t> &A,
@@ -407,46 +423,48 @@ struct TDiffusionKernel<2,2,complex_t>
}
};
// Diffusion kernel in 3D
/// Diffusion kernel in 3D
template <typename complex_t>
struct TDiffusionKernel<3,3,complex_t>
{
typedef complex_t complex_type;
// needed for the TElementTransformation::Result class
/// Needed for the TElementTransformation::Result class
static const bool uses_Jacobians = true;
// needed for the FieldEvaluator::Data class
/// Needed for the FieldEvaluator::Data class
///@{
static const bool in_values = false;
static const bool in_gradients = true;
static const bool out_values = false;
static const bool out_gradients = true;
///@}
// Partially assembled data type for one element with the given number of
// quadrature points. This type is used in partial assembly, and partially
// assembled action. Stores one symmetric 3 x 3 matrix per point.
/** @brief Partially assembled data type for one element with the given number of
quadrature points. This type is used in partial assembly, and partially
assembled action. Stores one symmetric 3 x 3 matrix per point. */
template <int qpts>
struct p_asm_data { typedef TMatrix<qpts,6,complex_t> type; };
// Partially assembled data type for one element with the given number of
// quadrature points. This type is used in full element matrix assembly.
// Stores one general (non-symmetric) 3 x 3 matrix per point.
/** @brief Partially assembled data type for one element with the given number of
quadrature points. This type is used in full element matrix assembly.
Stores one general (non-symmetric) 3 x 3 matrix per point. */
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.
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
// Q - CoefficientEval<>::Type
// q - CoefficientEval<>::Type::result_t
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
//
// grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
/** @brief Method used for un-assembled (matrix free) action.
grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
Q - CoefficientEval<>::Type
q - CoefficientEval<>::Type::result_t
grad_qpts [M x SDim x NC x NE] - in/out data member in R
*/
template <typename T_result_t, typename Q_t, typename q_t,
typename S_data_t>
static inline MFEM_ALWAYS_INLINE
@@ -477,17 +495,18 @@ struct TDiffusionKernel<3,3,complex_t>
}
}
// Method defining partial assembly. The pointwise Dim x Dim matrices are
// stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2)
// or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3)
// matrices.
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
// Q - CoefficientEval<>::Type
// q - CoefficientEval<>::Type::result_t
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
// A [M x Dim x Dim] - partially assembled Dim x Dim matrices
//
// A = (w/det(J)) adj(J) adj(J)^t
/** @brief Method defining partial assembly.
The pointwise Dim x Dim matrices are stored as symmetric (when
asm_type == p_asm_data, i.e. A.layout.rank == 2) or
non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank
== 3) matrices.
A = (w/det(J)) adj(J) adj(J)^t
Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
Q - CoefficientEval<>::Type
q - CoefficientEval<>::Type::result_t
A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
A [M x Dim x Dim] - partially assembled Dim x Dim matrices
*/
template <typename T_result_t, typename Q_t, typename q_t, typename asm_type>
static inline MFEM_ALWAYS_INLINE
void Assemble(const int k, const T_result_t &F,
@@ -518,12 +537,12 @@ struct TDiffusionKernel<3,3,complex_t>
}
}
// Method for partially assembled action.
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
// matrices
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
//
// grad_qpts = A grad_qpts
/** @brief Method for partially assembled action.
A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
matrices
grad_qpts [M x SDim x NC x NE] - in/out data member in R
grad_qpts = A grad_qpts
*/
template <int qpts, typename S_data_t>
static inline MFEM_ALWAYS_INLINE
void MultAssembled(const int k, const TMatrix<qpts,6,complex_t> &A,
+40 -18
View File
@@ -21,7 +21,7 @@
namespace mfem
{
// Templated coefficient classes, cf. coefficient.?pp
/// Templated coefficient classes, cf. coefficient.?pp
class TCoefficient
{
@@ -56,12 +56,13 @@ public:
};
// Function coefficient. The template class 'Func' has to implement at least one
// of the following methods, depending on the dimension that will be used:
// complex_t Eval1D(real_t);
// complex_t Eval2D(real_t,real_t);
// complex_t Eval3D(real_t,real_t,real_t);
// Use MFEM_FLOPS_ADD() to count flops inside Eval*D.
/** @brief Function coefficient.
@tparam Func has to implement at least one of the following methods,
depending on the dimension that will be used:
complex_t Eval1D(real_t);
complex_t Eval2D(real_t,real_t);
complex_t Eval3D(real_t,real_t,real_t);
Use MFEM_FLOPS_ADD() to count flops inside Eval*D. */
template <typename Func, typename complex_t = double>
class TFunctionCoefficient : public TCoefficient
{
@@ -81,11 +82,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 +103,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,20 +124,25 @@ 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]);
}
}
}
}
};
public:
// Constructor for the case when Func has no data members.
/// Constructor for the case when Func has no data members.
TFunctionCoefficient() : F() { }
// Constructor for the case when Func has data members.
/// Constructor for the case when Func has data members.
TFunctionCoefficient(Func &F_) : F(F_) { }
// Default copy constructor, Func has to have copy constructor.
@@ -170,14 +184,21 @@ 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);
}
}
};
/// GridFunction coefficient class.
template <typename FieldEval>
class TGridFunctionCoefficient : public TCoefficient
{
@@ -243,12 +264,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 +299,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 +334,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);
}
+115 -74
View File
@@ -21,12 +21,14 @@ namespace mfem
// Templated element transformation classes, cf. eltrans.?pp
// Element transformation class, templated on a mesh type and an integration
// rule. It is constructed from a mesh (e.g. class TMesh) and shape evaluator
// (e.g. class ShapeEvaluator) objects. Allows computation of physical
// coordinates and Jacobian matrices corresponding to the reference integration
// points. The desired result is specified through the template subclass Result
// and stored in an object of the same type.
/** @brief Element transformation class, templated on a mesh type and an
integration rule.
It is constructed from a mesh (e.g. class TMesh) and shape evaluator
(e.g. class ShapeEvaluator) objects. Allows computation of physical
coordinates and Jacobian matrices corresponding to the reference integration
points. The desired result is specified through the template subclass Result
and stored in an object of the same type.
*/
template <typename Mesh_t, typename IR, typename real_t = double>
class TElementTransformation
{
@@ -39,9 +41,9 @@ public:
typedef TElementTransformation<Mesh_t,IR,real_t> T_type;
// Enumeration for the result type of the TElementTransformation::Eval()
// method. The types can obtained by summing constants from this enumeration
// and used as a template parameter in struct Result.
/// Enumeration for the result type of the TElementTransformation::Eval()
/// method. The types can obtained by summing constants from this enumeration
/// and used as a template parameter in struct Result.
enum EvalOperations
{
EvalNone = 0,
@@ -51,6 +53,8 @@ public:
LoadElementIdxs = 8
};
/// Determines at compile-time the operations needed for given coefficient
/// and kernel
template <typename coeff_t, typename kernel_t> struct Get
{
static const int EvalOps =
@@ -61,12 +65,14 @@ public:
(EvalJacobians * kernel_t::uses_Jacobians);
};
// 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;
/** @brief Templated struct Result, used to specify the type result that is
computed by the TElementTransformation::Eval() method and stored in this
structure.
@tparam EvalOps is a sum (bitwise or) of constants from the enum EvalOperations
@tparam NE is the number of elements to be processed in the Eval() method.
@tparam 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 +91,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();
}
}
}
@@ -105,26 +115,31 @@ public:
elements(mesh.m_mesh.GetElementsArray())
{ }
// Evaluate coordinates and/or Jacobian matrices at quadrature points.
template<int EvalOps, int NE>
/// Evaluate coordinates and/or Jacobian matrices at quadrature points.
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 +152,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 +177,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 +191,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 +223,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 +237,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 +271,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 +287,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 +339,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 +373,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 +388,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;
}
+210 -168
View File
@@ -23,12 +23,16 @@ namespace mfem
// Templated classes for transitioning between degrees of freedom and quadrature
// points values.
// Shape evaluators -- values of basis functions on the reference element
/** @brief Shape evaluators -- values of basis functions on the reference element
@tparam FE some form of TFiniteElement, probably got from TMesh::FE_type
@tparam IR some form of TIntegrationRule
@tparam TP tensor product or not
@tparam real_t data type for mesh nodes, solution basis, mesh basis
*/
template <class FE, class IR, bool TP, typename real_t>
class ShapeEvaluator_base;
// ShapeEvaluator without tensor-product structure
/// ShapeEvaluator without tensor-product structure
template <class FE, class IR, typename real_t>
class ShapeEvaluator_base<FE, IR, false, real_t>
{
@@ -54,11 +58,11 @@ public:
// default copy constructor
// Multi-component shape evaluation from DOFs to quadrature points.
// dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp).
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
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
{
@@ -76,12 +80,12 @@ public:
qpt_layout, qpt_data);
}
// Multi-component shape evaluation transpose from quadrature points to DOFs.
// qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp).
/** @brief Multi-component shape evaluation transpose from quadrature points to
DOFs. qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */
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
{
@@ -99,11 +103,11 @@ public:
dof_layout, dof_data);
}
// Multi-component gradient evaluation from DOFs to quadrature points.
// dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp).
/** @brief Multi-component gradient evaluation from DOFs to quadrature points.
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,
@@ -124,12 +128,12 @@ public:
grad_layout.merge_12(), grad_data);
}
// Multi-component gradient evaluation transpose from quadrature points to
// DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp).
/** @brief Multi-component gradient evaluation transpose from quadrature points to
DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp). */
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,
@@ -150,11 +154,12 @@ public:
dof_layout, dof_data);
}
// Multi-component assemble.
// qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp)
/** @brief Multi-component assemble.
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
{
@@ -173,19 +178,20 @@ public:
#endif
}
// Multi-component assemble of grad-grad element matrices.
// qpt_layout is (NIP x DIM x DIM x NumComp), and
// D_layout is (DOF x DOF x NumComp).
/** @brief Multi-component assemble of grad-grad element matrices.
qpt_layout is (NIP x DIM x DIM x NumComp), and
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
@@ -207,7 +213,7 @@ public:
template <int Dim, int DOF, int NIP, typename real_t>
class TProductShapeEvaluator;
// ShapeEvaluator with 1D tensor-product structure
/// ShapeEvaluator with 1D tensor-product structure
template <int DOF, int NIP, typename real_t>
class TProductShapeEvaluator<1, DOF, NIP, real_t>
{
@@ -220,11 +226,11 @@ protected:
public:
TProductShapeEvaluator() { }
// Multi-component shape evaluation from DOFs to quadrature points.
// dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp).
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
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
{
@@ -233,12 +239,12 @@ public:
qpt_layout, qpt_data);
}
// Multi-component shape evaluation transpose from quadrature points to DOFs.
// qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp).
/** @brief Multi-component shape evaluation transpose from quadrature points
to DOFs. qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */
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
{
@@ -247,11 +253,11 @@ public:
dof_layout, dof_data);
}
// Multi-component gradient evaluation from DOFs to quadrature points.
// dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp).
/** @brief Multi-component gradient evaluation from DOFs to quadrature points.
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,
@@ -263,12 +269,12 @@ public:
grad_layout.merge_12(), grad_data);
}
// Multi-component gradient evaluation transpose from quadrature points to
// DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp).
/** @brief Multi-component gradient evaluation transpose from quadrature points to
DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp). */
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,
@@ -281,11 +287,11 @@ public:
dof_layout, dof_data);
}
// Multi-component assemble.
// qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp)
/** @brief Multi-component assemble.
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
{
@@ -304,12 +310,12 @@ public:
#endif
}
// Multi-component assemble of grad-grad element matrices.
// qpt_layout is (NIP x DIM x DIM x NumComp), and
// D_layout is (DOF x DOF x NumComp).
/** @brief Multi-component assemble of grad-grad element matrices.
qpt_layout is (NIP x DIM x DIM x NumComp), and
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,
@@ -331,7 +337,7 @@ public:
}
};
// ShapeEvaluator with 2D tensor-product structure
/// ShapeEvaluator with 2D tensor-product structure
template <int DOF, int NIP, typename real_t>
class TProductShapeEvaluator<2, DOF, NIP, real_t>
{
@@ -348,13 +354,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,
@@ -366,11 +373,11 @@ public:
qpt_layout.template split_1<NIP,NIP>(), qpt_data);
}
// Multi-component shape evaluation from DOFs to quadrature points.
// dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp).
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
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 +387,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,
@@ -398,23 +406,23 @@ public:
dof_layout.template split_1<DOF,DOF>(), dof_data);
}
// Multi-component shape evaluation transpose from quadrature points to DOFs.
// qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp).
/** @brief Multi-component shape evaluation transpose from quadrature points to DOFs.
qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). */
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
{
CalcT<false,false,Add>(qpt_layout, qpt_data, dof_layout, dof_data);
}
// Multi-component gradient evaluation from DOFs to quadrature points.
// dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp).
/** @brief Multi-component gradient evaluation from DOFs to quadrature points.
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,
@@ -426,13 +434,13 @@ public:
grad_layout.ind2(1), grad_data);
}
// Multi-component gradient evaluation transpose from quadrature points to
// DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is
// (TDOF x NumComp).
/** @brief Multi-component gradient evaluation transpose from quadrature points to
DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is
(TDOF x NumComp). */
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,
@@ -444,15 +452,16 @@ public:
dof_layout, dof_data);
}
// Multi-component assemble.
// qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp)
/** @brief Multi-component assemble.
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 +478,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 +519,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,16 +541,16 @@ 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);
}
// Multi-component assemble of grad-grad element matrices.
// qpt_layout is (TNIP x DIM x DIM x NumComp), and
// D_layout is (TDOF x TDOF x NumComp).
/** @brief Multi-component assemble of grad-grad element matrices.
qpt_layout is (TNIP x DIM x DIM x NumComp), and
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,
@@ -607,7 +617,7 @@ public:
}
};
// ShapeEvaluator with 3D tensor-product structure
/// ShapeEvaluator with 3D tensor-product structure
template <int DOF, int NIP, typename real_t>
class TProductShapeEvaluator<3, DOF, NIP, real_t>
{
@@ -624,13 +634,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,
@@ -646,11 +657,11 @@ public:
qpt_layout.template split_1<NIP*NIP,NIP>(), qpt_data);
}
// Multi-component shape evaluation from DOFs to quadrature points.
// dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp).
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
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 +671,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,
@@ -682,23 +694,23 @@ public:
dof_layout.template split_1<DOF,DOF*DOF>(), dof_data);
}
// Multi-component shape evaluation transpose from quadrature points to DOFs.
// qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp).
/** @brief Multi-component shape evaluation transpose from quadrature points to DOFs.
qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). */
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
{
CalcT<false,false,false,Add>(qpt_layout, qpt_data, dof_layout, dof_data);
}
// Multi-component gradient evaluation from DOFs to quadrature points.
// dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp).
/** @brief Multi-component gradient evaluation from DOFs to quadrature points.
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,
@@ -714,13 +726,13 @@ public:
// y-derivatives and second time for the z-derivatives.
}
// Multi-component gradient evaluation transpose from quadrature points to
// DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is
// (TDOF x NumComp).
/** @brief Multi-component gradient evaluation transpose from quadrature points to
DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is
(TDOF x NumComp). */
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,
@@ -734,17 +746,18 @@ public:
dof_layout, dof_data);
}
// Multi-component assemble.
// qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp)
/** @brief Multi-component assemble.
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 +801,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 +838,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,
@@ -859,12 +873,12 @@ public:
}
#endif
// Multi-component assemble of grad-grad element matrices.
// qpt_layout is (TNIP x DIM x DIM x NumComp), and
// D_layout is (TDOF x TDOF x NumComp).
/** @brief Multi-component assemble of grad-grad element matrices.
qpt_layout is (TNIP x DIM x DIM x NumComp), and
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,
@@ -895,7 +909,7 @@ public:
}
};
// ShapeEvaluator with tensor-product structure in any dimension
/// ShapeEvaluator with tensor-product structure in any dimension
template <class FE, class IR, typename real_t>
class ShapeEvaluator_base<FE, IR, true, real_t>
: public TProductShapeEvaluator<FE::dim, FE::dofs_1d, IR::qpts_1d, real_t>
@@ -921,7 +935,7 @@ public:
// default copy constructor
};
// General ShapeEvaluator for any scalar FE type (L2 or H1)
/// General ShapeEvaluator for any scalar FE type (L2 or H1)
template <class FE, class IR, typename real_t>
class ShapeEvaluator
: public ShapeEvaluator_base<FE,IR,FE::tensor_prod && IR::tensor_prod,real_t>
@@ -946,8 +960,9 @@ public:
};
// Field evaluators -- values of a given global FE grid function
/** @brief Field evaluators -- values of a given global FE grid function
This is roughly speaking a templated version of GridFunction
*/
template <typename FESpace_t, typename VecLayout_t, typename IR,
typename complex_t, typename real_t>
class FieldEvaluator_base
@@ -960,7 +975,7 @@ protected:
ShapeEval_type shapeEval;
VecLayout_t vec_layout;
// With this constructor, fespace is a shallow copy.
/// With this constructor, fespace is a shallow copy.
inline MFEM_ALWAYS_INLINE
FieldEvaluator_base(const FESpace_t &tfes, const ShapeEval_type &shape_eval,
const VecLayout_t &vec_layout)
@@ -969,14 +984,14 @@ protected:
vec_layout(vec_layout)
{ }
// This constructor creates new fespace, not a shallow copy.
/// This constructor creates new fespace, not a shallow copy.
inline MFEM_ALWAYS_INLINE
FieldEvaluator_base(const FE_type &fe, const FiniteElementSpace &fes)
: fespace(fe, fes), shapeEval(fe), vec_layout(fes)
{ }
};
// complex_t - dof/qpt data type, real_t - ShapeEvaluator (FE basis) data type
/// complex_t - dof/qpt data type, real_t - ShapeEvaluator (FE basis) data type
template <typename FESpace_t, typename VecLayout_t, typename IR,
typename complex_t = double, typename real_t = double>
class FieldEvaluator
@@ -1009,7 +1024,7 @@ protected:
complex_t *data_out;
public:
// With this constructor, fespace is a shallow copy of tfes.
/// With this constructor, fespace is a shallow copy of tfes.
inline MFEM_ALWAYS_INLINE
FieldEvaluator(const FESpace_t &tfes, const ShapeEval_type &shape_eval,
const VecLayout_type &vec_layout,
@@ -1019,7 +1034,7 @@ public:
data_out(global_data_out)
{ }
// With this constructor, fespace is a shallow copy of f.fespace.
/// With this constructor, fespace is a shallow copy of f.fespace.
inline MFEM_ALWAYS_INLINE
FieldEvaluator(const FieldEvaluator &f,
const complex_t *global_data_in, complex_t *global_data_out)
@@ -1028,7 +1043,7 @@ public:
data_out(global_data_out)
{ }
// This constructor creates a new fespace, not a shallow copy.
/// This constructor creates a new fespace, not a shallow copy.
inline MFEM_ALWAYS_INLINE
FieldEvaluator(const FiniteElementSpace &fes,
const complex_t *global_data_in, complex_t *global_data_out)
@@ -1049,25 +1064,25 @@ public:
fespace.SetElement(el);
}
// val_layout_t is (qpts x vdim x NE)
/// val_layout_t is (qpts x vdim x NE)
template <typename val_layout_t, typename val_data_t>
inline MFEM_ALWAYS_INLINE
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);
}
// grad_layout_t is (qpts x dim x vdim x NE)
/// grad_layout_t is (qpts x dim x vdim x NE)
template <typename grad_layout_t, typename grad_data_t>
inline MFEM_ALWAYS_INLINE
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,23 +1127,25 @@ 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);
}
#endif
// Enumeration for the data type used by the Eval() and Assemble() methods.
// The types can obtained by summing constants from this enumeration and used
// as a template parameter in struct Data.
/** @brief Enumeration for the data type used by the Eval() and Assemble() methods.
The types can be obtained by summing constants from this enumeration and used
as a template parameter in struct Data. */
enum InOutData
{
None = 0,
@@ -1136,65 +1153,72 @@ public:
Gradients = 2
};
// 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;
/** @brief Auxiliary templated struct AData, used by the Eval() and Assemble()
methods.
template <int NE> struct AData<0,NE> // 0 = None
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, typename impl_traits_t> struct AData;
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>
/** @brief 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, 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;
};
// This struct implements the input (Eval, EvalSerialized) and output
// (Assemble, AssembleSerialized) operations for the given Ops.
// Ops is "bitwise or" of constants from the enum InOutData.
/** @brief This struct implements the input (Eval, EvalSerialized) and output
(Assemble, AssembleSerialized) operations for the given Ops.
Ops is "bitwise or" of constants from the enum InOutData. */
template <int Ops, bool dummy> struct Action;
template <bool dummy> struct Action<0,dummy> // 0 = None
@@ -1238,7 +1262,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 +1272,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 +1318,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 +1328,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 +1379,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 +1391,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,
@@ -1371,14 +1404,15 @@ public:
#endif
};
// 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;
/** @brief This struct implements element matrix computation for some combinations
of input (InOps) and output (OutOps) operations. */
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 +1424,18 @@ 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
/** @brief Assemble element mass matrix
@param a the layout for the quadrature point data
@param A given quadrature point data for element (incl. coefficient,
geometry)
@param m the layout for the resulting element mass matrix
@param M the resulting element mass matrix
@param ev the shape evaluator
qpt_layout_t is (nip), M_layout_t is (dof x dof)
NE = 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 +1447,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;
};
};
+29
View File
@@ -20,6 +20,18 @@ namespace mfem
// Templated finite element classes, cf. fe.?pp
/** @brief Store mass-like matrix B for each integration point on the reference
element.
For tensor product evaluation, this is only called on the 1D reference
element, and higher dimensions are put together from that.
The element mass matrix can be written \f$ M_E = B^T D_E B \f$ where the B
built here is the B, and is unchanging across the mesh. The diagonal matrix
\f$ D_E \f$ then contains all the element-specific geometry and physics data.
@param fe the element we are calculating on
@param ir the integration rule to calculate the shape matrix on
@param B must be (nip x dof) with column major storage
@param dof_map the inverse of dof_map is applied to reorder local dofs.
*/
template <typename real_t>
void CalcShapeMatrix(const FiniteElement &fe, const IntegrationRule &ir,
real_t *B, const Array<int> *dof_map = NULL)
@@ -41,6 +53,23 @@ void CalcShapeMatrix(const FiniteElement &fe, const IntegrationRule &ir,
}
}
/** @brief store gradient matrix G for each integration point on the reference
element.
For tensor product evaluation, this is only called on the 1D reference
element, and higher dimensions are put together from that.
The element stiffness matrix can be written
\f[
S_E = \sum_{k=1}^{nq} G_{k,i}^T (D_E^G)_{k,k} G_{k,j}
\f]
where \f$ nq \f$ is the number of quadrature points, \f$ D_E^G \f$ contains
all the information about the element geometry and coefficients (Jacobians
etc.), and \f$ G \f$ is the matrix built in this routine, which is the same
for all elements in a mesh.
@param fe the element we are calculating on
@param ir the integration rule to calculate the gradients on
@param[out] G must be (nip x dim x dof) with column major storage
@param[in] dof_map the inverse of dof_map is applied to reorder local dofs.
*/
template <typename real_t>
void CalcGradTensor(const FiniteElement &fe, const IntegrationRule &ir,
real_t *G, const Array<int> *dof_map = NULL)
+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();
}
}
};

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