Compare commits

...
Author SHA1 Message Date
Tom Stitt 0e8625cf89 add optional MemoryType to the SparseMatrix copy-ctor 2020-07-24 09:13:21 -07:00
Tom Stitt 3f7a432e74 Cherry-picking changes on top of our current hash.
There are things that hurt performance in laster mfem@master commits,
not sure what yet.

This includes:
- feature/artv3/cusparse-Spmv
- feature/tomstitt/temp-mem-type
- patches to tmop.cpp and tmop_tools.cpp to address memory issues
- patch to mem_manager/device to use mfem's default allcator instead of
the host umpire one
2020-07-22 15:51:04 -07:00
Tom Stitt a57fd02a4c Use flattened FORALL instead of FORALL_2D. 2020-06-23 12:11:33 -07:00
Tom Stitt 2ae97ff2da Converts PADiffusionSetup3D and QuadratureInterpolator::Eval3D
kernels from 1 element per thread to 1 qpt/dof per thread for
better performance when offloading (there are not enough units
of work with 1 element/thread)
2020-06-22 14:42:48 -07:00
Arturo Vargas 2b712207c6 fix merge conflicts 2020-06-22 14:29:28 -07:00
Tzanio Kolev 62e95fe7bc Merge pull request #1564 from mfem/nc-amr-hybridization-fix
Fix a bug with hybridization on 2D NC meshes
2020-06-22 12:47:31 -07:00
Veselin Dobrev c62681aaf8 Merge branch 'master' into nc-amr-hybridization-fix 2020-06-19 21:07:07 -07:00
Veselin Dobrev a25138e611 Add an optional output stream parameter to the new method
FaceElementTransformations::CheckConsistency and improved its
documentation.

Extended Mesh::GetFaceGeometryType to support ghost child faces
and use this to generalize ParFiniteElementSpace::GetFaceNbrFaceFE
to support all face types.

Cleanup some old and debug code.
2020-06-19 20:43:47 -07:00
Tzanio Kolev cc3a4475d2 Merge pull request #1460 from mfem/LF-grad-curl-div
Additional LF-integrators
2020-06-18 18:52:17 -07:00
Tzanio 8e00ae03e4 Removed convergence/bae.cpp, this will be handled in another PR. 2020-06-18 18:49:12 -07:00
Arturo Vargas 2930c1477f promove temp vector class member 2020-06-18 13:35:11 -07:00
Tzanio Kolev bf3423dcba Merge pull request #1497 from mfem/coef-dev
Adding accessor methods to compound coefficient classes [coef-dev]
2020-06-18 10:55:33 -07:00
Veselin Dobrev dd23ccddb3 In ex4p, added a sample run that tests hybridization in 2D when
there are ghost shared faces using amr-quad.mesh on 3 processors.

In ex9p, added a sample run on amr-hex.mesh on 3 processors so
have a test case with ghost shared faces in 3D.
2020-06-17 22:39:16 -07:00
Tzanio Kolev 3c5dc275a4 Merge pull request #1539 from mfem/navier-bookkeeping-fix
Navier miniapp bookkeeping fix
2020-06-17 16:37:23 -07:00
Veselin Dobrev 6604ba702c WIP: debugging and bugfix for the issue with hybridization on 2D
nonconforming meshes, see issue #1105 on github.
2020-06-16 21:09:48 -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
Julian Andrej 395e75f69a Merge branch 'master' into navier-bookkeeping-fix 2020-06-12 11:21:38 -07:00
Julian Andrej 1875c34055 Add move constructor to custom types 2020-06-12 11:20:07 -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
Stowell, Mark L f58decb421 Adding Doxygen comments for the new accessor methods 2020-06-09 13:51:46 -07:00
Stowell, Mark L 635ac55e77 Creating Doxygen group for compound coefficient 2020-06-09 09:41:44 -07:00
Stowell, Mark L 6beb0decd7 Merge remote-tracking branch 'origin/master' into coef-dev
# Conflicts:
#	fem/coefficient.hpp
2020-06-09 09:41:13 -07:00
Tzanio Kolev 253aebb734 Merge branch 'master' into LF-grad-curl-div 2020-06-09 07:28:20 -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
Stowell, Mark L 7de36b40bb Wrapping math formulae in \f$ 2020-06-08 12:27:59 -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
Stowell, Mark L bf54fc6b3f Expanding name of MatVecCoefficient to conform to standard set by other product coefficients 2020-06-07 13:59:16 -07:00
Stowell, Mark L fb3b943cf0 Adding/improving comments 2020-06-07 13:53:24 -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
psocratis df3d0b51c2 renamed example name 2020-06-02 15:54:36 -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
psocratis 4c4aeaeec3 renamed example 2020-06-02 15:51:28 -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
Ido Akkerman 2ece39550c Avoid bdrElemdof table usage 2020-06-02 15:19:22 +02:00
Stowell, Mark L 774cc3bd68 Typo... oops 2020-06-01 09:28:46 -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
psocratis cadb9778a4 Added the legal statement at the top. Corrected the mesh path 2020-05-28 15:14:43 -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
Socratis 32bdcb6ef2 make style 2020-05-27 19:01:16 -07:00
Socratis e74d501ac3 fixed comments in example 2020-05-27 19:00:11 -07:00
Socratis fcd2f0ceb2 Merge branch 'master' into LF-grad-curl-div 2020-05-27 18:44:36 -07:00
Socratis c0879aaf76 fixed valgrind leaks 2020-05-27 18:44:06 -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
Ido Akkerman efa34ab718 make style 2020-05-26 11:25:34 +02: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
Ido Akkerman 9e300dd159 Make GenerateFaceDofsFromBdr work for non-NURBS meshes 2020-05-25 12:13:33 +02: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
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
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 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
Stowell, Mark L e024ac0f9c Adding accessor methods to compound coefficient classes (and adding a couple new ones) 2020-05-20 15:43:17 -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
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
Aaron Fisher e332188212 Merge branch 'chrome-doc-fix-dev' into dox-update1 2020-05-18 16:53:20 -07:00
Aaron Fisher ce47cb4eb4 Merge branch 'master' into dox-update1 2020-05-18 16:40:52 -07:00
Ido Akkerman a78aef812c Changing access functions and adding NURBSext verify, both for safety 2020-05-18 22:11:50 +02:00
Tzanio Kolev afd31c8a7b Merge branch 'master' into dox-update1 2020-05-15 11:57:46 -07: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
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
Arturo Vargas b3ee631aa6 tmop_tools 2020-05-14 14:33:32 -07:00
Arturo Vargas daf2fdecec use tmop_tools from master 2020-05-14 14:24:52 -07:00
Arturo Vargas d3a0d0a181 Merge branch 'master' into feature/apps/mesh-helper-tmop-ea 2020-05-14 14:19:13 -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
Arturo Vargas a556dc8eba consider support for Vectors/DenseMatrices in lu batch 2020-05-13 17:07:38 -07:00
Arturo Vargas e10c38c636 Merge branch 'master' into gpu/artv3/batch-lu 2020-05-13 16:26:32 -07: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
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
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
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
Arturo Vargas 07853b9c62 add missing host reads to tmop 2020-05-09 21:41:26 -07:00
Socratis 20089dd62b valgrind checks passed 2020-05-05 15:36:16 -07:00
psocratis a8ebdf16bd Added convergence tests 2020-05-05 15:19:27 -07:00
psocratis 99372de933 Added parallel test 2020-05-04 20:35:27 -07:00
psocratis 70d84e441d make style 2020-05-04 19:56:38 -07:00
psocratis f6bc0f8988 Added test for the newly added LF integrators 2020-05-04 19:55:00 -07:00
psocratis ef54519a29 Added LF integrators (Q, grard V), (Q, curl V) and (Q, div V) 2020-05-04 19:54:24 -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
Tomov e1fc7d94b7 Corresponding changes in the serial miniapp. 2020-05-02 23:47:46 -07: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
Tomov 6ec8be76f1 Return const reference in combo::getintegrators. 2020-05-01 15:13:00 -07:00
Arturo Vargas 49a31c0cf7 Merge branch 'yohann/mass-emat' into feature/apps/mesh-helper-tmop-ea 2020-05-01 10:17:42 -07:00
Arturo Vargas ba9b251007 Merge branch 'master' into feature/apps/mesh-helper-tmop-ea 2020-05-01 10:13:46 -07:00
Stowell, Mark L 90a6df62c2 Adding mesh trimmer miniapp 2020-05-01 00:55:44 -07:00
Arturo Vargas 5ce2fa9ab9 fix free 2020-04-30 18:06:29 -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
Aaron Fisher 59e4409ea5 Merge branch 'master' into dox-update1 2020-04-30 13:18:48 -07:00
Arturo Vargas 78c93de6ce Merge branch 'gpu/artv3/batch-lu' into feature/apps/mesh-helper-tmop-ea 2020-04-30 13:09:53 -07:00
Aaron Fisher 8dda4f7441 Numerous changes suggested by Jakub in the review. 2020-04-30 10:59:22 -07:00
Tomov ecfb8c755d Merge branch 'master' into adapt-lim 2020-04-29 19:17:47 -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
Arturo Vargas 3d4aa157cb testing super code 2020-04-28 16:54:23 -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
Vargas c1f7f42dcc make style 2020-04-28 13:36:05 -07:00
Arturo Vargas 5925b7dfa8 init commit of batch lu decomp 2020-04-28 13:27:48 -07:00
Ido Akkerman e97a27d331 Merge branch 'master' into nurbs-face-dev 2020-04-28 14:08:10 +02: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
Ido Akkerman f10f165b71 Fix mem leak 2020-04-22 13:52:36 +02:00
Aaron Fisher add2e8a3f2 Fixed the remainder of the issues that Mark caught. 2020-04-20 16:51:30 -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
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
Tomov a8abcac938 Adaptive limiting contributions in FD regime. 2020-04-15 15:51:27 -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
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
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
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
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
Aaron Fisher c3be660074 Merge branch 'master' into dox-update1 2020-04-07 17:25:23 -07:00
Ido Akkerman ce4d12c8cb Correct penalty selection 2020-04-06 15:52:14 +02:00
Tomov a7f1c177c5 Fixed a parallel communication bug in tmop's AdvectorCG. 2020-03-30 22:29:51 -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
Arturo Vargas 2d4e3cf77e minor helper functions 2020-03-24 14:11:37 -07:00
Tomov a7c2e91915 Initial tests for tangential limiting. 2020-03-20 11:27:09 -07: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
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
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
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
Aaron Fisher b57c90e4bb Fixed some documentation errors in coefficient. 2019-05-21 14:19:35 -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
114 changed files with 7906 additions and 1832 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*
+22 -7
View File
@@ -24,8 +24,14 @@ Meshing improvements
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.
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
------------------------
@@ -38,6 +44,8 @@ Performance improvements
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.
Discretization improvements
@@ -66,6 +74,8 @@ Discretization improvements
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
@@ -94,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
@@ -113,6 +122,12 @@ New and updated examples and miniapps
- 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
+17 -2
View File
@@ -125,6 +125,7 @@ MFEM_USE_GINKGO = NO
MFEM_USE_GNUTLS = NO
MFEM_USE_NETCDF = NO
MFEM_USE_PETSC = NO
MFEM_USE_SLEPC = NO
MFEM_USE_MPFR = NO
MFEM_USE_SIDRE = NO
MFEM_USE_CONDUIT = NO
@@ -276,6 +277,20 @@ ifeq ($(PETSC_FOUND),YES)
-L$(abspath $(PETSC_DIR))/lib -lpetsc $(PETSC_LIB)
endif
SLEPC_DIR := $(MFEM_DIR)/../slepc
SLEPC_VARS := $(SLEPC_DIR)/lib/slepc/conf/slepc_variables
SLEPC_FOUND := $(if $(wildcard $(SLEPC_VARS)),YES,)
SLEPC_INC_VAR = SLEPC_INCLUDE
SLEPC_LIB_VAR = SLEPC_EXTERNAL_LIB
ifeq ($(SLEPC_FOUND),YES)
SLEPC_OPT := $(shell sed -n "s/$(SLEPC_INC_VAR) *= *//p" $(SLEPC_VARS))
# Some additional external libraries might be defined in this file
-include ${SLEPC_DIR}/${PETSC_ARCH}/lib/slepc/conf/slepcvariables
SLEPC_LIB := $(shell sed -n "s/$(SLEPC_LIB_VAR) *= *//p" $(SLEPC_VARS))
SLEPC_LIB := -Wl,-rpath,$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib\
-L$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib -lslepc $(SLEPC_LIB)
endif
# MPFR library configuration
MPFR_OPT =
MPFR_LIB = -lmpfr
@@ -324,9 +339,9 @@ GSLIB_DIR = @MFEM_DIR@/../gslib/build
GSLIB_OPT = -I$(GSLIB_DIR)/include
GSLIB_LIB = -L$(GSLIB_DIR)/lib -lgs
# CUDA library configuration (currently not needed)
# CUDA library configuration
CUDA_OPT =
CUDA_LIB =
CUDA_LIB = -lcusparse
# HIP library configuration (currently not needed)
HIP_OPT =
+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
+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
+1
View File
@@ -16,6 +16,7 @@
// mpirun -np 4 ex4p -m ../data/periodic-square.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/periodic-cube.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/amr-quad.mesh
// mpirun -np 3 ex4p -m ../data/amr-quad.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
+1
View File
@@ -16,6 +16,7 @@
// mpirun -np 4 ex9p -m ../data/disc-nurbs.mesh -p 2 -rp 1 -dt 0.005 -tf 9
// mpirun -np 4 ex9p -m ../data/periodic-square.mesh -p 3 -rp 2 -dt 0.0025 -tf 9 -vs 20
// mpirun -np 4 ex9p -m ../data/periodic-cube.mesh -p 0 -o 2 -rp 1 -dt 0.01 -tf 8
// mpirun -np 3 ex9p -m ../data/amr-hex.mesh -p 1 -rs 1 -rp 0 -dt 0.005 -tf 0.5
//
// Device sample runs:
// mpirun -np 4 ex9p -pa
+93 -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.
+16 -7
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:
@@ -127,7 +132,7 @@ public:
void MultTranspose(const Vector &x, Vector &y) const;
};
/// Data and methods for matrix-free bilinear forms
/// Data and methods for matrix-free bilinear forms NOT YET IMPLEMENTED.
class MFBilinearFormExtension : public BilinearFormExtension
{
public:
@@ -147,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:
+4 -1
View File
@@ -199,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:
@@ -1563,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:
@@ -2001,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:
+34 -35
View File
@@ -176,42 +176,41 @@ static void PADiffusionSetup3D(const int Q1D,
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
auto D = Reshape(d.Write(), NQ, 6, NE);
MFEM_FORALL(e, NE,
MFEM_FORALL(eq, NE*NQ,
{
for (int q = 0; q < NQ; ++q)
{
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J31 = J(q,2,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double J32 = J(q,2,1,e);
const double J13 = J(q,0,2,e);
const double J23 = J(q,1,2,e);
const double J33 = J(q,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double coeff = const_c ? C(0,0) : C(q,e);
const double c_detJ = W[q] * coeff / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
D(q,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
D(q,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
D(q,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
D(q,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
D(q,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
D(q,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
}
const int e = eq / NQ;
const int q = eq % NQ;
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J31 = J(q,2,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double J32 = J(q,2,1,e);
const double J13 = J(q,0,2,e);
const double J23 = J(q,1,2,e);
const double J33 = J(q,2,2,e);
const double detJ = J11 * (J22 * J33 - J32 * J23) -
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double coeff = const_c ? C(0,0) : C(q,e);
const double c_detJ = W[q] * coeff / detJ;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
const double A13 = (J12 * J23) - (J22 * J13);
const double A21 = (J31 * J23) - (J21 * J33);
const double A22 = (J11 * J33) - (J13 * J31);
const double A23 = (J21 * J13) - (J11 * J23);
const double A31 = (J21 * J32) - (J31 * J22);
const double A32 = (J31 * J12) - (J11 * J32);
const double A33 = (J11 * J22) - (J12 * J21);
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
D(q,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
D(q,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
D(q,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
D(q,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
D(q,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
D(q,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
});
}
+23 -11
View File
@@ -25,6 +25,7 @@ namespace mfem
void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
{
// Assuming the same element type
fespace = &fes;
Mesh *mesh = fes.GetMesh();
@@ -51,21 +52,30 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
dofs1D = maps->ndof;
quad1D = maps->nqpt;
pa_data.SetSize(ne*nq, Device::GetDeviceMemoryType());
Vector coeff;
Vector *coeff{nullptr};
bool own_coeff{true};
if (Q == nullptr)
{
coeff.SetSize(1);
coeff(0) = 1.0;
coeff = new Vector;
coeff->SetSize(1);
(*coeff)(0) = 1.0;
}
else if (ConstantCoefficient* cQ = dynamic_cast<ConstantCoefficient*>(Q))
{
coeff.SetSize(1);
coeff(0) = cQ->constant;
coeff = new Vector;
coeff->SetSize(1);
(*coeff)(0) = 1.0;
}
else if (QuadratureCoefficient* cQ = dynamic_cast<QuadratureCoefficient*>(Q))
{
coeff = cQ->Data();
own_coeff = false;
}
else
{
coeff.SetSize(nq * ne);
auto C = Reshape(coeff.HostWrite(), nq, ne);
coeff = new Vector;
coeff->SetSize(nq * ne);
auto C = Reshape(coeff->HostWrite(), nq, ne);
for (int e = 0; e < ne; ++e)
{
ElementTransformation& T = *fes.GetElementTransformation(e);
@@ -80,11 +90,11 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
{
const int NE = ne;
const int NQ = nq;
const bool const_c = coeff.Size() == 1;
const bool const_c = coeff->Size() == 1;
auto w = ir->GetWeights().Read();
auto J = Reshape(geom->J.Read(), NQ,2,2,NE);
auto C =
const_c ? Reshape(coeff.Read(), 1,1) : Reshape(coeff.Read(), NQ,NE);
const_c ? Reshape(coeff->Read(), 1,1) : Reshape(coeff->Read(), NQ,NE);
auto v = Reshape(pa_data.Write(), NQ, NE);
MFEM_FORALL(e, NE,
{
@@ -104,11 +114,11 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
{
const int NE = ne;
const int NQ = nq;
const bool const_c = coeff.Size() == 1;
const bool const_c = coeff->Size() == 1;
auto W = ir->GetWeights().Read();
auto J = Reshape(geom->J.Read(), NQ,3,3,NE);
auto C =
const_c ? Reshape(coeff.Read(), 1,1) : Reshape(coeff.Read(), NQ,NE);
const_c ? Reshape(coeff->Read(), 1,1) : Reshape(coeff->Read(), NQ,NE);
auto v = Reshape(pa_data.Write(), NQ,NE);
MFEM_FORALL(e, NE,
{
@@ -125,6 +135,8 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
}
});
}
if (own_coeff) { delete coeff; }
}
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
+109 -19
View File
@@ -12,6 +12,7 @@
// Implementation of Coefficient class
#include "fem.hpp"
#include "../linalg/dtensor.hpp"
#include <cmath>
#include <limits>
@@ -21,6 +22,13 @@ namespace mfem
using namespace std;
double QuadratureCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
auto coeff = mfem::Reshape(qData->HostRead(), nip, NE);
return coeff(ip.index, T.ElementNo);
}
double PWConstCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
@@ -416,13 +424,43 @@ double DeterminantCoefficient::Eval(ElementTransformation &T,
return ma.Det();
}
VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &A,
VectorCoefficient &B,
double _alpha, double _beta)
: VectorCoefficient(A.GetVDim()), a(&A), b(&B), alpha(_alpha), beta(_beta),
va(A.GetVDim())
VectorSumCoefficient::VectorSumCoefficient(int dim)
: VectorCoefficient(dim),
ACoef(NULL), BCoef(NULL),
A(dim), B(dim),
alphaCoef(NULL), betaCoef(NULL),
alpha(1.0), beta(1.0)
{
MFEM_ASSERT(A.GetVDim() == B.GetVDim(),
A = 0.0; B = 0.0;
}
VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &_A,
VectorCoefficient &_B,
double _alpha, double _beta)
: VectorCoefficient(_A.GetVDim()),
ACoef(&_A), BCoef(&_B),
A(_A.GetVDim()), B(_A.GetVDim()),
alphaCoef(NULL), betaCoef(NULL),
alpha(_alpha), beta(_beta)
{
MFEM_ASSERT(_A.GetVDim() == _B.GetVDim(),
"VectorSumCoefficient: "
"Arguments must have the same dimension.");
}
VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &_A,
VectorCoefficient &_B,
Coefficient &_alpha,
Coefficient &_beta)
: VectorCoefficient(_A.GetVDim()),
ACoef(&_A), BCoef(&_B),
A(_A.GetVDim()),
B(_A.GetVDim()),
alphaCoef(&_alpha),
betaCoef(&_beta),
alpha(0.0), beta(0.0)
{
MFEM_ASSERT(_A.GetVDim() == _B.GetVDim(),
"VectorSumCoefficient: "
"Arguments must have the same dimension.");
}
@@ -430,26 +468,47 @@ VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &A,
void VectorSumCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
b->Eval(V, T, ip);
if ( beta != 1.0 ) { V *= beta; }
a->Eval(va, T, ip);
V.Add(alpha, va);
V.SetSize(A.Size());
if ( ACoef) { ACoef->Eval(A, T, ip); }
if ( BCoef) { BCoef->Eval(B, T, ip); }
if (alphaCoef) { alpha = alphaCoef->Eval(T, ip); }
if ( betaCoef) { beta = betaCoef->Eval(T, ip); }
add(alpha, A, beta, B, V);
}
ScalarVectorProductCoefficient::ScalarVectorProductCoefficient(
double A,
VectorCoefficient &B)
: VectorCoefficient(B.GetVDim()), aConst(A), a(NULL), b(&B)
{}
ScalarVectorProductCoefficient::ScalarVectorProductCoefficient(
Coefficient &A,
VectorCoefficient &B)
: VectorCoefficient(B.GetVDim()), a(&A), b(&B)
: VectorCoefficient(B.GetVDim()), aConst(0.0), a(&A), b(&B)
{}
void ScalarVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
double sa = a->Eval(T, ip);
double sa = (a == NULL) ? aConst : a->Eval(T, ip);
b->Eval(V, T, ip);
V *= sa;
}
NormalizedVectorCoefficient::NormalizedVectorCoefficient(VectorCoefficient &A,
double _tol)
: VectorCoefficient(A.GetVDim()), a(&A), tol(_tol)
{}
void NormalizedVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
a->Eval(V, T, ip);
double nv = V.Norml2();
V *= (nv > tol) ? (1.0/nv) : 0.0;
}
VectorCrossProductCoefficient::VectorCrossProductCoefficient(
VectorCoefficient &A,
VectorCoefficient &B)
@@ -471,17 +530,18 @@ void VectorCrossProductCoefficient::Eval(Vector &V, ElementTransformation &T,
V[2] = va[0] * vb[1] - va[1] * vb[0];
}
MatVecCoefficient::MatVecCoefficient(MatrixCoefficient &A,
VectorCoefficient &B)
MatrixVectorProductCoefficient::MatrixVectorProductCoefficient(
MatrixCoefficient &A, VectorCoefficient &B)
: VectorCoefficient(A.GetHeight()), a(&A), b(&B),
ma(A.GetHeight(), A.GetWidth()), vb(B.GetVDim())
{
MFEM_ASSERT(A.GetWidth() == B.GetVDim(),
"MatVecCoefficient: Arguments have incompatible dimensions.");
"MatrixVectorProductCoefficient: "
"Arguments have incompatible dimensions.");
}
void MatVecCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
void MatrixVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
a->Eval(ma, T, ip);
b->Eval(vb, T, ip);
@@ -517,17 +577,23 @@ void MatrixSumCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
M.Add(alpha, ma);
}
ScalarMatrixProductCoefficient::ScalarMatrixProductCoefficient(
double A,
MatrixCoefficient &B)
: MatrixCoefficient(B.GetHeight(), B.GetWidth()), aConst(A), a(NULL), b(&B)
{}
ScalarMatrixProductCoefficient::ScalarMatrixProductCoefficient(
Coefficient &A,
MatrixCoefficient &B)
: MatrixCoefficient(B.GetHeight(), B.GetWidth()), a(&A), b(&B)
: MatrixCoefficient(B.GetHeight(), B.GetWidth()), aConst(0.0), a(&A), b(&B)
{}
void ScalarMatrixProductCoefficient::Eval(DenseMatrix &M,
ElementTransformation &T,
const IntegrationPoint &ip)
{
double sa = a->Eval(T, ip);
double sa = (a == NULL) ? aConst : a->Eval(T, ip);
b->Eval(M, T, ip);
M *= sa;
}
@@ -581,6 +647,30 @@ void OuterProductCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
}
}
CrossCrossCoefficient::CrossCrossCoefficient(Coefficient &A,
VectorCoefficient &K)
: MatrixCoefficient(K.GetVDim(), K.GetVDim()), aConst(0.0), a(&A), k(&K),
vk(K.GetVDim())
{}
void CrossCrossCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip)
{
k->Eval(vk, T, ip);
M.SetSize(vk.Size(), vk.Size());
M = 0.0;
double k2 = vk*vk;
for (int i=0; i<vk.Size(); i++)
{
M(i, i) = k2;
for (int j=0; j<vk.Size(); j++)
{
M(i, j) -= vk[i] * vk[j];
}
}
M *= ((a == NULL ) ? aConst : a->Eval(T, ip) );
}
double LpNormLoop(double p, Coefficient &coeff, Mesh &mesh,
const IntegrationRule *irs[])
{
+683 -78
View File
File diff suppressed because it is too large Load Diff
+73
View File
@@ -624,4 +624,77 @@ void FaceElementTransformations::Transform(const DenseMatrix &matrix,
IsoparametricTransformation::Transform(matrix, result);
}
double FaceElementTransformations::CheckConsistency(int print_level,
std::ostream &out)
{
// Check that the face vertices are mapped to the same physical location
// when using the following three transformations:
// - the face transformation, *this
// - Loc1 + Elem1
// - Loc2 + Elem2, if present.
const bool have_face = (mask & 16);
const bool have_el1 = (mask & 1) && (mask & 4);
const bool have_el2 = (mask & 2) && (mask & 8) && (Elem2No >= 0);
if (int(have_face) + int(have_el1) + int(have_el2) < 2)
{
// need at least two different transformations to perform a check
return 0.0;
}
const IntegrationRule &v_ir = *Geometries.GetVertices(GetGeometryType());
double max_dist = 0.0;
Vector dist(v_ir.GetNPoints());
DenseMatrix coords_base, coords_el;
IntegrationRule v_eir(v_ir.GetNPoints());
if (have_face)
{
Transform(v_ir, coords_base);
if (print_level > 0)
{
out << "\nface vertex coordinates (from face transform):\n"
<< "----------------------------------------------\n";
coords_base.PrintT(out, coords_base.Height());
}
}
if (have_el1)
{
Loc1.Transform(v_ir, v_eir);
Elem1->Transform(v_eir, coords_el);
if (print_level > 0)
{
out << "\nface vertex coordinates (from element 1 transform):\n"
<< "---------------------------------------------------\n";
coords_el.PrintT(out, coords_el.Height());
}
if (have_face)
{
coords_el -= coords_base;
coords_el.Norm2(dist);
max_dist = std::max(max_dist, dist.Normlinf());
}
else
{
coords_base = coords_el;
}
}
if (have_el2)
{
Loc2.Transform(v_ir, v_eir);
Elem2->Transform(v_eir, coords_el);
if (print_level > 0)
{
out << "\nface vertex coordinates (from element 2 transform):\n"
<< "---------------------------------------------------\n";
coords_el.PrintT(out, coords_el.Height());
}
coords_el -= coords_base;
coords_el.Norm2(dist);
max_dist = std::max(max_dist, dist.Normlinf());
}
return max_dist;
}
}
+97 -15
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();
@@ -74,14 +77,27 @@ public:
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
@@ -92,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.
@@ -308,7 +341,7 @@ public:
virtual int Transform(const Vector &pt, IntegrationPoint &ip);
};
/// A standard isoparametric element transformation
class IsoparametricTransformation : public ElementTransformation
{
private:
@@ -318,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.
@@ -346,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);
@@ -378,6 +439,7 @@ public:
void Transform (const IntegrationRule &, IntegrationRule &);
};
class FaceElementTransformations : public IsoparametricTransformation
{
private:
@@ -430,9 +492,29 @@ public:
ElementTransformation & GetElement2Transformation();
IntegrationPointTransformation & GetIntPoint1Transformation();
IntegrationPointTransformation & GetIntPoint2Transformation();
/** @brief Check for self-consistency: compares the result of mapping the
reference face vertices to physical coordinates using the three
transformations: face, element 1, and element 2.
@param[in] print_level If set to a positive number, print the physical
coordinates of the face vertices computed through
all available transformations: face, element 1,
and/or element 2.
@param[in,out] out The output stream to use for printing.
@returns A maximal distance between physical coordinates of face vertices
that should coincide. A successful check should return a small
number relative to the mesh extents. If less than 2 of the three
transformations are set, returns 0.
@warning This check will generally fail on periodic boundary faces.
*/
double CheckConsistency(int print_level = 0,
std::ostream &out = mfem::out);
};
/* Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x))
/** Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x))
Physical Space
+10
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,
+503 -503
View File
File diff suppressed because it is too large Load Diff
+431 -183
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,
+123 -49
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:
@@ -41,8 +41,7 @@ protected:
public:
/** @brief Enumeration for ContType: defines the continuity of the field
across element interfaces.
*/
across element interfaces. */
enum { CONTINUOUS, ///< Field is continuous across element interfaces
TANGENTIAL, ///< Tangential components of vector field
NORMAL, ///< Normal component of vector field
@@ -77,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;
};
@@ -123,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:
@@ -132,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
@@ -141,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:
@@ -241,9 +307,9 @@ public:
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:
@@ -291,9 +357,9 @@ public:
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:
@@ -358,7 +424,7 @@ public:
};
/// Piecewise-(bi)linear continuous finite elements.
/// Piecewise-(bi/tri)linear continuous finite elements.
class LinearFECollection : public FiniteElementCollection
{
private:
@@ -514,8 +580,8 @@ public:
};
/** 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:
@@ -538,8 +604,8 @@ public:
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:
@@ -562,8 +628,8 @@ public:
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:
@@ -586,8 +652,9 @@ public:
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:
@@ -609,8 +676,9 @@ public:
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:
@@ -673,8 +741,9 @@ public:
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:
@@ -737,8 +806,9 @@ public:
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:
@@ -760,8 +830,9 @@ public:
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:
@@ -784,8 +855,9 @@ public:
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:
@@ -807,8 +879,9 @@ public:
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:
@@ -856,8 +929,9 @@ public:
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:
@@ -879,8 +953,8 @@ public:
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:
@@ -903,8 +977,8 @@ public:
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:
+170 -46
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;
+73 -29
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
+2 -2
View File
@@ -1031,13 +1031,13 @@ int GridFunction::GetFaceVectorValues(
}
if (di == 0)
{
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 4);
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 5);
Transf->Loc1.Transform(ir, eir);
GetVectorValues(*Transf->Elem1, eir, vals, &tr);
}
else
{
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 8);
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 10);
Transf->Loc2.Transform(ir, eir);
GetVectorValues(*Transf->Elem2, eir, vals, &tr);
}
+4 -2
View File
@@ -598,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.
+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:
+166 -7
View File
@@ -63,6 +63,53 @@ void DomainLFIntegrator::AssembleDeltaElementVect(
elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
}
void DomainLFGradIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
int dof = el.GetDof();
int spaceDim = Tr.GetSpaceDim();
dshape.SetSize(dof, spaceDim);
elvect.SetSize(dof);
elvect = 0.0;
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
int intorder = 2 * el.GetOrder();
ir = &IntRules.Get(el.GetGeomType(), intorder);
}
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Tr.SetIntPoint(&ip);
el.CalcPhysDShape(Tr, dshape);
Q.Eval(Qvec, Tr, ip);
Qvec *= ip.weight * Tr.Weight();
dshape.AddMult(Qvec, elvect);
}
}
void DomainLFGradIntegrator::AssembleDeltaElementVect(
const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
{
MFEM_ASSERT(vec_delta != NULL,"coefficient must be VectorDeltaCoefficient");
int dof = fe.GetDof();
int spaceDim = Trans.GetSpaceDim();
dshape.SetSize(dof, spaceDim);
fe.CalcPhysDShape(Trans, dshape);
vec_delta->EvalDelta(Qvec, Trans, Trans.GetIntPoint());
elvect.SetSize(dof);
dshape.Mult(Qvec, elvect);
}
void BoundaryLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
@@ -255,7 +302,6 @@ void VectorDomainLFIntegrator::AssembleDeltaElementVect(
MultVWt(shape, Qvec, elvec_as_mat);
}
void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -332,7 +378,6 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
}
}
void VectorFEDomainLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -362,7 +407,6 @@ void VectorFEDomainLFIntegrator::AssembleRHSElementVect(
QF.Eval (vec, Tr, ip);
vec *= ip.weight * Tr.Weight();
vshape.AddMult (vec, elvect);
}
}
@@ -383,6 +427,125 @@ void VectorFEDomainLFIntegrator::AssembleDeltaElementVect(
vshape.Mult(vec, elvect);
}
void VectorFEDomainLFCurlIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
int dof = el.GetDof();
int spaceDim = Tr.GetSpaceDim();
int n=(spaceDim == 3)? spaceDim : 1;
curlshape.SetSize(dof,n);
vec.SetSize(n);
elvect.SetSize(dof);
elvect = 0.0;
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
int intorder = 2*el.GetOrder();
ir = &IntRules.Get(el.GetGeomType(), intorder);
}
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Tr.SetIntPoint (&ip);
el.CalcPhysCurlShape(Tr, curlshape);
switch (spaceDim)
{
case 3:
MFEM_VERIFY(QF, "VectorFunctionCoefficient not provided");
QF->Eval(vec, Tr, ip);
break;
case 2:
MFEM_VERIFY(Q, "FunctionCoefficient (Scalar) not provided");
vec[0] = Q->Eval(Tr, ip);
break;
default:
break; // This should be unreachable
}
vec *= ip.weight * Tr.Weight();
curlshape.AddMult (vec, elvect);
}
}
void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect(
const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
{
int spaceDim = Trans.GetSpaceDim();
switch (spaceDim)
{
case 3:
MFEM_ASSERT(vec_delta != NULL,
"coefficient must be VectorDeltaCoefficient");
break;
case 2:
MFEM_ASSERT(delta != NULL,
"coefficient must be DeltaCoefficient");
break;
default:
break; // This should be unreachable
}
int dof = fe.GetDof();
int n=(spaceDim == 3)? spaceDim : 1;
curlshape.SetSize(dof, n);
elvect.SetSize(dof);
fe.CalcPhysCurlShape(Trans, curlshape);
switch (spaceDim)
{
case 3:
vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint());
curlshape.Mult(vec, elvect);
break;
case 2:
curlshape.GetColumn(0,elvect);
elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
break;
default:
break; // This should be unreachable
}
}
void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
int dof = el.GetDof();
divshape.SetSize(dof); // vector of size dof
elvect.SetSize(dof);
elvect = 0.0;
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
int intorder = 2 * el.GetOrder();
ir = &IntRules.Get(el.GetGeomType(), intorder);
}
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Tr.SetIntPoint (&ip);
double val = Tr.Weight() * Q.Eval(Tr, ip);
el.CalcPhysDivShape(Tr, divshape);
add(elvect, ip.weight * val, divshape, elvect);
}
}
void VectorFEDomainLFDivIntegrator::AssembleDeltaElementVect(
const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
{
MFEM_ASSERT(delta != NULL, "coefficient must be DeltaCoefficient");
elvect.SetSize(fe.GetDof());
fe.CalcPhysDivShape(Trans, elvect);
elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
}
void VectorBoundaryFluxLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -448,7 +611,6 @@ void VectorFEBoundaryFluxLFIntegrator::AssembleRHSElementVect(
}
}
void VectorFEBoundaryTangentLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -483,7 +645,6 @@ void VectorFEBoundaryTangentLFIntegrator::AssembleRHSElementVect(
}
}
void BoundaryFlowIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -548,7 +709,6 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
}
}
void DGDirichletLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
@@ -637,7 +797,6 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect(
}
}
void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
+78 -1
View File
@@ -119,6 +119,33 @@ public:
using LinearFormIntegrator::AssembleRHSElementVect;
};
/// Class for domain integrator L(v) := (f, grad v)
class DomainLFGradIntegrator : public DeltaLFIntegrator
{
private:
Vector shape, Qvec;
VectorCoefficient &Q;
DenseMatrix dshape;
public:
/// Constructs the domain integrator (Q, grad v)
DomainLFGradIntegrator(VectorCoefficient &QF)
: DeltaLFIntegrator(QF), Q(QF) { }
/** Given a particular Finite Element and a transformation (Tr)
computes the element right hand side element vector, elvect. */
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect);
virtual void AssembleDeltaElementVect(const FiniteElement &fe,
ElementTransformation &Trans,
Vector &elvect);
using LinearFormIntegrator::AssembleRHSElementVect;
};
/// Class for boundary integration L(v) := (g, v)
class BoundaryLFIntegrator : public LinearFormIntegrator
{
@@ -252,6 +279,56 @@ public:
using LinearFormIntegrator::AssembleRHSElementVect;
};
/// \f$ (Q, curl v)_{\Omega} \f$ for Nedelec Elements)
class VectorFEDomainLFCurlIntegrator : public DeltaLFIntegrator
{
private:
VectorCoefficient *QF=nullptr;
Coefficient *Q=nullptr;
DenseMatrix curlshape;
Vector vec;
public:
/// Constructs the domain integrator (Q, curl v)
VectorFEDomainLFCurlIntegrator(VectorCoefficient &F)
: DeltaLFIntegrator(F), QF(&F) { }
VectorFEDomainLFCurlIntegrator(Coefficient &F)
: DeltaLFIntegrator(F), Q(&F) { }
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect);
virtual void AssembleDeltaElementVect(const FiniteElement &fe,
ElementTransformation &Trans,
Vector &elvect);
using LinearFormIntegrator::AssembleRHSElementVect;
};
/// \f$ (Q, div v)_{\Omega} \f$ for RT Elements)
class VectorFEDomainLFDivIntegrator : public DeltaLFIntegrator
{
private:
Vector divshape;
Coefficient &Q;
public:
/// Constructs the domain integrator (Q, div v)
VectorFEDomainLFDivIntegrator(Coefficient &QF)
: DeltaLFIntegrator(QF), Q(QF) { }
/** Given a particular Finite Element and a transformation (Tr)
computes the element right hand side element vector, elvect. */
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect);
virtual void AssembleDeltaElementVect(const FiniteElement &fe,
ElementTransformation &Trans,
Vector &elvect);
using LinearFormIntegrator::AssembleRHSElementVect;
};
/** \f$ (f, v \cdot n)_{\partial\Omega} \f$ for vector test function
v=(v1,...,vn) where all vi are in the same scalar FE space and f is a
@@ -283,7 +360,7 @@ class VectorFEBoundaryFluxLFIntegrator : public LinearFormIntegrator
private:
Coefficient *F;
Vector shape;
int oa, ob; // these contol the quadrature order, see DomainLFIntegrator
int oa, ob; // these control the quadrature order, see DomainLFIntegrator
public:
VectorFEBoundaryFluxLFIntegrator(int a = 1, int b = -1)
+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:
+12 -4
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())
{
@@ -1167,7 +1172,7 @@ void ParFiniteElementSpace::GetFaceNbrFaceVDofs(int i, Array<int> &vdofs) const
{
// Works for NC mesh where 'i' is an index returned by
// ParMesh::GetSharedFace() such that i >= Mesh::GetNumFaces(), i.e. 'i' is
// the index of a ghost.
// the index of a ghost face.
MFEM_ASSERT(Nonconforming() && i >= pmesh->GetNumFaces(), "");
int el1, el2, inf1, inf2;
pmesh->GetFaceElements(i, &el1, &el2);
@@ -1207,11 +1212,14 @@ const FiniteElement *ParFiniteElementSpace::GetFaceNbrFE(int i) const
const FiniteElement *ParFiniteElementSpace::GetFaceNbrFaceFE(int i) const
{
// Works for NC mesh where 'i' is an index returned by
// ParMesh::GetSharedFace() such that i >= Mesh::GetNumFaces(), i.e. 'i' is
// the index of a ghost face.
// Works in tandem with GetFaceNbrFaceVDofs() defined above.
MFEM_ASSERT(Nonconforming() && !NURBSext, "");
Geometry::Type geom = (pmesh->Dimension() == 2) ?
Geometry::SEGMENT : Geometry::SQUARE;
return fec->FiniteElementForGeometry(geom);
Geometry::Type face_geom = pmesh->GetFaceGeometryType(i);
return fec->FiniteElementForGeometry(face_geom);
}
void ParFiniteElementSpace::Lose_Dof_TrueDof_Matrix()
+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; }
};
+1 -1
View File
@@ -214,7 +214,7 @@ void ParGridFunction::ExchangeFaceNbrData()
ParMesh *pmesh = pfes->GetParMesh();
face_nbr_data.SetSize(pfes->GetFaceNbrVSize());
Vector send_data(pfes->send_face_nbr_ldof.Size_of_connections());
send_data.SetSize(pfes->send_face_nbr_ldof.Size_of_connections());
int *send_offset = pfes->send_face_nbr_ldof.GetI();
const int *d_send_ldof = mfem::Read(pfes->send_face_nbr_ldof.GetJMemory(),
+5
View File
@@ -38,6 +38,11 @@ protected:
initialized by ExchangeFaceNbrData(). */
Vector face_nbr_data;
/** @brief Vector used as an MPI buffer to send face-neighbor data
in ExchangeFaceNbrData() to neighboring processors. */
//TODO: Use temporary memory to avoid CUDA malloc allocation cost.
Vector send_data;
void ProjectBdrCoefficient(Coefficient *coeff[], VectorCoefficient *vcoeff,
Array<int> &attr);
+7 -4
View File
@@ -150,6 +150,7 @@ void QuadratureInterpolator::Eval3D(
const int nq = maps.nqpt;
const int ND = T_ND ? T_ND : nd;
const int NQ = T_NQ ? T_NQ : nq;
const int NMAX = NQ > ND ? NQ : ND;
const int VDIM = T_VDIM ? T_VDIM : vdim;
MFEM_VERIFY(ND <= MAX_ND3D, "");
MFEM_VERIFY(NQ <= MAX_NQ3D, "");
@@ -160,22 +161,24 @@ void QuadratureInterpolator::Eval3D(
auto val = Reshape(q_val.Write(), NQ, VDIM, NE);
auto der = Reshape(q_der.Write(), NQ, VDIM, 3, NE);
auto det = Reshape(q_det.Write(), NQ, NE);
MFEM_FORALL(e, NE,
MFEM_FORALL_2D(e, NE, NMAX, 1, 1,
{
const int ND = T_ND ? T_ND : nd;
const int NQ = T_NQ ? T_NQ : nq;
const int VDIM = T_VDIM ? T_VDIM : vdim;
constexpr int max_ND = T_ND ? T_ND : MAX_ND3D;
constexpr int max_VDIM = T_VDIM ? T_VDIM : MAX_VDIM3D;
double s_E[max_VDIM*max_ND];
for (int d = 0; d < ND; d++)
MFEM_SHARED double s_E[max_VDIM*max_ND];
MFEM_FOREACH_THREAD(d, x, ND)
{
for (int c = 0; c < VDIM; c++)
{
s_E[c+d*VDIM] = E(d,c,e);
}
}
for (int q = 0; q < NQ; ++q)
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(q, x, NQ)
{
if (eval_flags & VALUES)
{
+3 -2
View File
@@ -495,8 +495,9 @@ void FaceQuadratureInterpolator::Mult(
}
}
void FaceQuadratureInterpolator::Values(
const Vector &e_vec, Vector &q_val) const
void FaceQuadratureInterpolator::Values(const Vector &e_vec,
Vector &q_val) const
{
Vector q_der, q_det, q_nor;
Mult(e_vec, VALUES, q_val, q_der, q_det, q_nor);
+33 -10
View File
@@ -24,10 +24,22 @@
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,
@@ -61,11 +73,19 @@ protected:
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;
/// 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;
@@ -80,6 +100,9 @@ protected:
typedef FieldEvaluator<solFESpace,solVecLayout_t,IR,
complex_t,real_t> solFieldEval;
/** @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,impl_traits_t> Spec;
@@ -191,7 +214,7 @@ public:
}
}
// Partial assembly of quadrature point data
/// Partial assembly of quadrature point data
void Assemble()
{
Trans_t T(mesh, meshEval);
@@ -276,8 +299,8 @@ public:
typedef TTensor3<meshFE_type::dofs,sdim,BE,vreal_t> lnodes_t;
const int NE = mesh.GetNE();
// 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
// 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);
@@ -291,7 +314,7 @@ public:
}
}
// partial assembly from "serialized" nodes
/// Partial assembly from "serialized" nodes
// real_t = double
void AssembleFromSerializedNodes(const Vector &sNodes)
{
@@ -343,7 +366,7 @@ public:
}
}
// serialized vector sx --> serialized vector 'sy'
/// serialized vector sx --> serialized vector 'sy'
// complex_t = double
void MultAssembledSerialized(const Vector &sx, Vector &sy) const
{
@@ -371,7 +394,7 @@ public:
}
#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
{
@@ -419,7 +442,7 @@ public:
}
}
// 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
{
@@ -472,7 +495,7 @@ public:
}
}
// 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
{
@@ -572,7 +595,7 @@ public:
}
}
// 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
{
+151 -132
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,30 +37,32 @@ 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; };
@@ -71,13 +72,13 @@ struct TMassKernel
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,35 +153,38 @@ 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; };
@@ -186,13 +194,13 @@ struct TDiffusionKernel<1,1,complex_t>
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,30 +277,32 @@ 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; };
@@ -299,13 +312,14 @@ struct TDiffusionKernel<2,2,complex_t>
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,30 +423,32 @@ 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; };
@@ -440,13 +458,13 @@ struct TDiffusionKernel<3,3,complex_t>
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,
+11 -10
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
{
@@ -139,9 +140,9 @@ protected:
};
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.
@@ -197,7 +198,7 @@ public:
}
};
/// GridFunction coefficient class.
template <typename FieldEval>
class TGridFunctionCoefficient : public TCoefficient
{
+21 -15
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,11 +65,13 @@ 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 type impl_traits_t specifies additional
// parameters and types to be used by the Eval() method.
/** @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;
@@ -109,7 +115,7 @@ public:
elements(mesh.m_mesh.GetElementsArray())
{ }
// Evaluate coordinates and/or Jacobian matrices at quadrature points.
/// 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,impl_traits_t> &F)
+103 -88
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,8 +58,8 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -76,8 +80,8 @@ 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>
@@ -99,8 +103,8 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -124,8 +128,8 @@ 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>
@@ -150,8 +154,9 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -173,9 +178,9 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -208,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>
{
@@ -221,8 +226,8 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -234,8 +239,8 @@ 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>
@@ -248,8 +253,8 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -264,8 +269,8 @@ 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>
@@ -282,8 +287,8 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -305,9 +310,9 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -332,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>
{
@@ -368,8 +373,8 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -401,8 +406,8 @@ 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>
@@ -413,8 +418,8 @@ public:
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>
inline MFEM_ALWAYS_INLINE
@@ -429,9 +434,9 @@ 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>
@@ -447,8 +452,8 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -540,9 +545,9 @@ public:
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>
inline MFEM_ALWAYS_INLINE
@@ -612,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>
{
@@ -652,8 +657,8 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -689,8 +694,8 @@ 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>
@@ -701,8 +706,8 @@ public:
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>
inline MFEM_ALWAYS_INLINE
@@ -721,9 +726,9 @@ 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>
@@ -741,8 +746,8 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -868,9 +873,9 @@ 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>
inline MFEM_ALWAYS_INLINE
@@ -904,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>
@@ -930,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>
@@ -955,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
@@ -969,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)
@@ -978,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
@@ -1018,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,
@@ -1028,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)
@@ -1037,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)
@@ -1058,7 +1064,7 @@ 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)
@@ -1070,7 +1076,7 @@ public:
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)
@@ -1137,9 +1143,9 @@ public:
}
#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,
@@ -1147,10 +1153,12 @@ 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 type impl_traits_t specifies parameters and types
// to be used in the Eval() and Assemble() methods.
/** @brief 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, typename impl_traits_t> struct AData;
template <typename it_t> struct AData<0,it_t> // 0 = None
@@ -1198,8 +1206,8 @@ public:
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.
/** @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>
{
@@ -1208,9 +1216,9 @@ public:
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
@@ -1396,8 +1404,8 @@ public:
#endif
};
// This struct implements element matrix computation for some combinations
// of input (InOps) and output (OutOps) operations.
/** @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;
// Case 1,1 = Values,Values
@@ -1419,8 +1427,15 @@ public:
// 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)
// it_t::batch_size = 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
+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)
+311 -72
View File
@@ -843,7 +843,20 @@ void TargetConstructor::ComputeAvgVolume() const
#endif
}
// virtual method
bool TargetConstructor::ContainsVolumeInfo() const
{
switch (target_type)
{
case IDEAL_SHAPE_UNIT_SIZE: return false;
case IDEAL_SHAPE_EQUAL_SIZE:
case IDEAL_SHAPE_GIVEN_SIZE:
case GIVEN_SHAPE_AND_SIZE:
case GIVEN_FULL: return true;
default: MFEM_ABORT("TargetType not added to ContainsVolumeInfo.");
}
return false;
}
void TargetConstructor::ComputeElementTargets(int e_id, const FiniteElement &fe,
const IntegrationRule &ir,
const Vector &elfun,
@@ -1045,6 +1058,7 @@ void DiscreteAdaptTC::SetDiscreteTargetBase(const GridFunction &tspec_)
// make a copy of tspec->tspec_temp, increase its size, and
// copy data from tspec_temp -> tspec, then add new entries
Vector tspec_temp = tspec;
tspec.UseDevice(true);
tspec.SetSize(ncomp*dof_cnt);
for (int i = 0; i < tspec_temp.Size(); i++)
@@ -1196,11 +1210,12 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
ntspec_dofs = ndofs*ncomp;
Vector shape(ndofs), tspec_vals(ntspec_dofs), par_vals,
par_vals_c1(ndofs), par_vals_c2(ndofs), par_vals_c3(ndofs);
par_vals_c1, par_vals_c2, par_vals_c3;
Array<int> dofs;
DenseMatrix D_rho(dim), Q_phi(dim), R_theta(dim);
tspec_fesv->GetElementVDofs(e_id, dofs);
tspec.UseDevice(true);
tspec.GetSubVector(dofs, tspec_vals);
for (int i = 0; i < ir.GetNPoints(); i++)
@@ -1237,9 +1252,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
{
par_vals.SetDataAndSize(tspec_vals.GetData()+
aspectratioidx*ndofs, ndofs*3);
par_vals_c1.SetData(par_vals.GetData());
par_vals_c2.SetData(par_vals.GetData()+ndofs);
par_vals_c3.SetData(par_vals.GetData()+2*ndofs);
par_vals_c1.SetDataAndSize(par_vals.GetData(), ndofs);
par_vals_c2.SetDataAndSize(par_vals.GetData()+ndofs, ndofs);
par_vals_c3.SetDataAndSize(par_vals.GetData()+2*ndofs, ndofs);
const double rho1 = shape * par_vals_c1;
const double rho2 = shape * par_vals_c2;
@@ -1272,9 +1287,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
{
par_vals.SetDataAndSize(tspec_vals.GetData()+
skewidx*ndofs, ndofs*3);
par_vals_c1.SetData(par_vals.GetData());
par_vals_c2.SetData(par_vals.GetData()+ndofs);
par_vals_c3.SetData(par_vals.GetData()+2*ndofs);
par_vals_c1.SetDataAndSize(par_vals.GetData(), ndofs);
par_vals_c2.SetDataAndSize(par_vals.GetData()+ndofs, ndofs);
par_vals_c3.SetDataAndSize(par_vals.GetData()+2*ndofs, ndofs);
const double phi12 = shape * par_vals_c1;
const double phi13 = shape * par_vals_c2;
@@ -1312,9 +1327,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
{
par_vals.SetDataAndSize(tspec_vals.GetData()+
orientationidx*ndofs, ndofs*3);
par_vals_c1.SetData(par_vals.GetData());
par_vals_c2.SetData(par_vals.GetData()+ndofs);
par_vals_c3.SetData(par_vals.GetData()+2*ndofs);
par_vals_c1.SetDataAndSize(par_vals.GetData(), ndofs);
par_vals_c2.SetDataAndSize(par_vals.GetData()+ndofs, ndofs);
par_vals_c3.SetDataAndSize(par_vals.GetData()+2*ndofs, ndofs);
const double theta = shape * par_vals_c1;
const double psi = shape * par_vals_c2;
@@ -1471,6 +1486,17 @@ AdaptivityEvaluator::~AdaptivityEvaluator()
#endif
}
TMOP_Integrator::~TMOP_Integrator()
{
delete lim_func;
delete zeta;
for (int i = 0; i < ElemDer.Size(); i++)
{
delete ElemDer[i];
delete ElemPertEnergy[i];
}
}
void TMOP_Integrator::EnableLimiting(const GridFunction &n0,
const GridFunction &dist, Coefficient &w0,
TMOP_LimiterFunction *lfunc)
@@ -1496,24 +1522,57 @@ void TMOP_Integrator::EnableLimiting(const GridFunction &n0, Coefficient &w0,
}
}
void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &z0,
Coefficient &coeff,
AdaptivityEvaluator &ae)
{
zeta_0 = &z0;
delete zeta;
zeta = new GridFunction(z0);
coeff_zeta = &coeff;
adapt_eval = &ae;
adapt_eval->SetSerialMetaInfo(*zeta->FESpace()->GetMesh(),
*zeta->FESpace()->FEColl(), 1);
adapt_eval->SetInitialField
(*zeta->FESpace()->GetMesh()->GetNodes(), *zeta);
}
#ifdef MFEM_USE_MPI
void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &z0,
Coefficient &coeff,
AdaptivityEvaluator &ae)
{
zeta_0 = &z0;
delete zeta;
zeta = new GridFunction(z0);
coeff_zeta = &coeff;
adapt_eval = &ae;
adapt_eval->SetParMetaInfo(*z0.ParFESpace()->GetParMesh(),
*z0.ParFESpace()->FEColl(), 1);
adapt_eval->SetInitialField
(*zeta->FESpace()->GetMesh()->GetNodes(), *zeta);
}
#endif
double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun)
{
int dof = el.GetDof(), dim = el.GetDim();
const int dof = el.GetDof(), dim = el.GetDim();
double energy;
// No adaptive limiting terms if this is a FD computation.
const bool adaptive_limiting = (zeta && fd_call_flag == false);
DSh.SetSize(dof, dim);
Jrt.SetSize(dim);
Jpr.SetSize(dim);
Jpt.SetSize(dim);
PMatI.UseExternalData(elfun.GetData(), dof, dim);
const IntegrationRule *ir = IntRule;
if (!ir)
{
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
}
const IntegrationRule *ir = EnergyIntegrationRule(el);
energy = 0.0;
DenseTensor Jtr(dim, dim, ir->GetNPoints());
@@ -1544,7 +1603,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
// Define ref->physical transformation, when a Coefficient is specified.
IsoparametricTransformation *Tpr = NULL;
if (coeff1 || coeff0)
if (coeff1 || coeff0 || adaptive_limiting)
{
Tpr = new IsoparametricTransformation;
Tpr->SetFE(&el);
@@ -1561,6 +1620,13 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
// the physical coordinates (i.e. changes in 'elfun'), e.g. when the
// coefficient is a ConstantCoefficient or a GridFunctionCoefficient.
Vector zeta_q, zeta0_q;
if (adaptive_limiting)
{
zeta->GetValues(T.ElementNo, *ir, zeta_q);
zeta_0->GetValues(T.ElementNo, *ir, zeta0_q);
}
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
@@ -1584,6 +1650,13 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
val += lim_normal *
lim_func->Eval(p, p0, d_vals(i)) * coeff0->Eval(*Tpr, ip);
}
if (adaptive_limiting)
{
const double diff = zeta_q(i) - zeta0_q(i);
val += coeff_zeta->Eval(*Tpr, ip) * lim_normal * diff * diff;
}
energy += weight * val;
}
delete Tpr;
@@ -1621,9 +1694,10 @@ void TMOP_Integrator::AssembleElementGrad(const FiniteElement &el,
void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun, Vector &elvect)
const Vector &elfun,
Vector &elvect)
{
int dof = el.GetDof(), dim = el.GetDim();
const int dof = el.GetDof(), dim = el.GetDim();
DSh.SetSize(dof, dim);
DS.SetSize(dof, dim);
@@ -1634,14 +1708,12 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
elvect.SetSize(dof*dim);
PMatO.UseExternalData(elvect.GetData(), dof, dim);
const IntegrationRule *ir = IntRule;
if (!ir)
{
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
}
const IntegrationRule *ir = ActionIntegrationRule(el);
const int nqp = ir->GetNPoints();
elvect = 0.0;
DenseTensor Jtr(dim, dim, ir->GetNPoints());
Vector weights(nqp);
DenseTensor Jtr(dim, dim, nqp);
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
// Limited case.
@@ -1663,13 +1735,13 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
}
else
{
d_vals.SetSize(ir->GetNPoints()); d_vals = 1.0;
d_vals.SetSize(nqp); d_vals = 1.0;
}
}
// Define ref->physical transformation, when a Coefficient is specified.
IsoparametricTransformation *Tpr = NULL;
if (coeff1 || coeff0)
if (coeff1 || coeff0 || zeta)
{
Tpr = new IsoparametricTransformation;
Tpr->SetFE(&el);
@@ -1679,14 +1751,14 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
}
for (int i = 0; i < ir->GetNPoints(); i++)
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
const DenseMatrix &Jtr_i = Jtr(i);
metric->SetTargetJacobian(Jtr_i);
CalcInverse(Jtr_i, Jrt);
const double weight = ip.weight * Jtr_i.Det();
double weight_m = weight * metric_normal;
const IntegrationPoint &ip = ir->IntPoint(q);
const DenseMatrix &Jtr_q = Jtr(q);
metric->SetTargetJacobian(Jtr_q);
CalcInverse(Jtr_q, Jrt);
weights(q) = ip.weight * Jtr_q.Det();
double weight_m = weights(q) * metric_normal;
el.CalcDShape(ip, DSh);
Mult(DSh, Jrt, DS);
@@ -1706,11 +1778,14 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
el.CalcShape(ip, shape);
PMatI.MultTranspose(shape, p);
pos0.MultTranspose(shape, p0);
lim_func->Eval_d1(p, p0, d_vals(i), grad);
grad *= weight * lim_normal * coeff0->Eval(*Tpr, ip);
lim_func->Eval_d1(p, p0, d_vals(q), grad);
grad *= weights(q) * lim_normal * coeff0->Eval(*Tpr, ip);
AddMultVWt(shape, grad, PMatO);
}
}
if (zeta) { AssembleElemVecAdaptLim(el, weights, *Tpr, *ir, PMatO); }
delete Tpr;
}
@@ -1719,7 +1794,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
const Vector &elfun,
DenseMatrix &elmat)
{
int dof = el.GetDof(), dim = el.GetDim();
const int dof = el.GetDof(), dim = el.GetDim();
DSh.SetSize(dof, dim);
DS.SetSize(dof, dim);
@@ -1728,14 +1803,12 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
PMatI.UseExternalData(elfun.GetData(), dof, dim);
elmat.SetSize(dof*dim);
const IntegrationRule *ir = IntRule;
if (!ir)
{
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
}
const IntegrationRule *ir = GradientIntegrationRule(el);
const int nqp = ir->GetNPoints();
elmat = 0.0;
DenseTensor Jtr(dim, dim, ir->GetNPoints());
Vector weights(nqp);
DenseTensor Jtr(dim, dim, nqp);
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
// Limited case.
@@ -1757,13 +1830,13 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
}
else
{
d_vals.SetSize(ir->GetNPoints()); d_vals = 1.0;
d_vals.SetSize(nqp); d_vals = 1.0;
}
}
// Define ref->physical transformation, when a Coefficient is specified.
IsoparametricTransformation *Tpr = NULL;
if (coeff1 || coeff0)
if (coeff1 || coeff0 || zeta)
{
Tpr = new IsoparametricTransformation;
Tpr->SetFE(&el);
@@ -1773,14 +1846,14 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
Tpr->GetPointMat().Transpose(PMatI);
}
for (int i = 0; i < ir->GetNPoints(); i++)
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
const DenseMatrix &Jtr_i = Jtr(i);
metric->SetTargetJacobian(Jtr_i);
CalcInverse(Jtr_i, Jrt);
const double weight = ip.weight * Jtr_i.Det();
double weight_m = weight * metric_normal;
const IntegrationPoint &ip = ir->IntPoint(q);
const DenseMatrix &Jtr_q = Jtr(q);
metric->SetTargetJacobian(Jtr_q);
CalcInverse(Jtr_q, Jrt);
weights(q) = ip.weight * Jtr_q.Det();
double weight_m = weights(q) * metric_normal;
el.CalcDShape(ip, DSh);
Mult(DSh, Jrt, DS);
@@ -1792,13 +1865,14 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
// TODO: derivatives of adaptivity-based targets.
// TODO optimize by symmetry.
if (coeff0)
{
el.CalcShape(ip, shape);
PMatI.MultTranspose(shape, p);
pos0.MultTranspose(shape, p0);
weight_m = weight * lim_normal * coeff0->Eval(*Tpr, ip);
lim_func->Eval_d2(p, p0, d_vals(i), grad_grad);
weight_m = weights(q) * lim_normal * coeff0->Eval(*Tpr, ip);
lim_func->Eval_d2(p, p0, d_vals(q), grad_grad);
for (int i = 0; i < dof; i++)
{
const double w_shape_i = weight_m * shape(i);
@@ -1816,9 +1890,115 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
}
}
}
if (zeta) { AssembleElemGradAdaptLim(el, weights, *Tpr, *ir, elmat); }
delete Tpr;
}
void TMOP_Integrator::AssembleElemVecAdaptLim(const FiniteElement &el,
const Vector &weights,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir,
DenseMatrix &mat)
{
if (zeta == NULL) { return; }
const int dof = el.GetDof(), dim = el.GetDim();
Vector shape(dof), zeta_e, zeta_q, zeta0_q;
Array<int> dofs;
zeta->FESpace()->GetElementDofs(Tpr.ElementNo, dofs);
zeta->GetSubVector(dofs, zeta_e);
zeta->GetValues(Tpr.ElementNo, ir, zeta_q);
zeta_0->GetValues(Tpr.ElementNo, ir, zeta0_q);
// Project the gradient of zeta in the same space.
// The FE coefficients of the gradient go in zeta_grad_e.
DenseMatrix zeta_grad_e(dof, dim);
DenseMatrix grad_phys; // This will be (dof x dim, dof).
el.ProjectGrad(el, Tpr, grad_phys);
Vector grad_ptr(zeta_grad_e.GetData(), dof*dim);
grad_phys.Mult(zeta_e, grad_ptr);
Vector zeta_grad_q(dim);
const int nqp = weights.Size();
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir.IntPoint(q);
el.CalcShape(ip, shape);
zeta_grad_e.MultTranspose(shape, zeta_grad_q);
zeta_grad_q *= 2.0 * (zeta_q(q) - zeta0_q(q));
zeta_grad_q *= weights(q) * lim_normal * coeff_zeta->Eval(Tpr, ip);
AddMultVWt(shape, zeta_grad_q, mat);
}
}
void TMOP_Integrator::AssembleElemGradAdaptLim(const FiniteElement &el,
const Vector &weights,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir,
DenseMatrix &mat)
{
if (zeta == NULL) { return; }
const int dof = el.GetDof(), dim = el.GetDim();
Vector shape(dof), zeta_e, zeta_q, zeta0_q;
Array<int> dofs;
zeta->FESpace()->GetElementDofs(Tpr.ElementNo, dofs);
zeta->GetSubVector(dofs, zeta_e);
zeta->GetValues(Tpr.ElementNo, ir, zeta_q);
zeta_0->GetValues(Tpr.ElementNo, ir, zeta0_q);
// Project the gradient of zeta in the same space.
// The FE coefficients of the gradient go in zeta_grad_e.
DenseMatrix zeta_grad_e(dof, dim);
DenseMatrix grad_phys; // This will be (dof x dim, dof).
el.ProjectGrad(el, Tpr, grad_phys);
Vector grad_ptr(zeta_grad_e.GetData(), dof*dim);
grad_phys.Mult(zeta_e, grad_ptr);
// Project the gradient of each gradient of zeta in the same space.
// The FE coefficients of the second derivatives go in zeta_grad_grad_e.
DenseMatrix zeta_grad_grad_e(dof*dim, dim);
Mult(grad_phys, zeta_grad_e, zeta_grad_grad_e);
// Reshape to be more convenient later (no change in the data).
zeta_grad_grad_e.SetSize(dof, dim*dim);
Vector zeta_grad_q(dim);
DenseMatrix zeta_grad_grad_q(dim, dim);
const int nqp = weights.Size();
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir.IntPoint(q);
el.CalcShape(ip, shape);
zeta_grad_e.MultTranspose(shape, zeta_grad_q);
Vector gg_ptr(zeta_grad_grad_q.GetData(), dim*dim);
zeta_grad_grad_e.MultTranspose(shape, gg_ptr);
const double w = weights(q) * lim_normal * coeff_zeta->Eval(Tpr, ip);
for (int i = 0; i < dof * dim; i++)
{
const int idof = i % dof, idim = i / dof;
for (int j = 0; j <= i; j++)
{
const int jdof = j % dof, jdim = j / dof;
const double entry =
w * ( 2.0 * zeta_grad_q(idim) * shape(idof) *
/* */ zeta_grad_q(jdim) * shape(jdof) +
2.0 * (zeta_q(q) - zeta0_q(q)) *
zeta_grad_grad_q(idim, jdim) * shape(idof) * shape(jdof));
mat(i, j) += entry;
if (i != j) { mat(j, i) += entry; }
}
}
}
}
double TMOP_Integrator::GetFDDerivative(const FiniteElement &el,
ElementTransformation &T,
Vector &elfun, const int dofidx,
@@ -1858,8 +2038,11 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el,
elvect.SetSize(dof*dim);
Vector elfunmod(elfun);
// Energy for unperturbed configuration
double e_fx = GetElementEnergy(el, T, elfun);
// In GetElementEnergy(), skip terms that have exact derivative calculations.
fd_call_flag = true;
// Energy for unperturbed configuration.
const double e_fx = GetElementEnergy(el, T, elfun);
for (int j = 0; j < dim; j++)
{
@@ -1874,6 +2057,32 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el,
if (discr_tc) { discr_tc->RestoreTargetSpecificationAtNode(T, i); }
}
}
fd_call_flag = false;
// Contributions from adaptive limiting (exact derivatives).
if (zeta)
{
const IntegrationRule *ir = ActionIntegrationRule(el);
const int nqp = ir->GetNPoints();
DenseTensor Jtr(dim, dim, nqp);
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
IsoparametricTransformation Tpr;
Tpr.SetFE(&el);
Tpr.ElementNo = T.ElementNo;
Tpr.Attribute = T.Attribute;
PMatI.UseExternalData(elfun.GetData(), dof, dim);
Tpr.GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
Vector weights(nqp);
for (int q = 0; q < nqp; q++)
{
weights(q) = ir->IntPoint(q).weight * Jtr(q).Det();
}
PMatO.UseExternalData(elvect.GetData(), dof, dim);
AssembleElemVecAdaptLim(el, weights, Tpr, *ir, PMatO);
}
}
void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
@@ -1889,6 +2098,8 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
const Vector &ElemDerLoc = *(ElemDer[T.ElementNo]);
const Vector &ElemPertLoc = *(ElemPertEnergy[T.ElementNo]);
// In GetElementEnergy(), skip terms that have exact derivative calculations.
fd_call_flag = true;
for (int i = 0; i < dof; i++)
{
for (int j = 0; j < i+1; j++)
@@ -1942,6 +2153,31 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
}
}
}
fd_call_flag = false;
// Contributions from adaptive limiting.
if (zeta)
{
const IntegrationRule *ir = GradientIntegrationRule(el);
const int nqp = ir->GetNPoints();
DenseTensor Jtr(dim, dim, nqp);
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
IsoparametricTransformation Tpr;
Tpr.SetFE(&el);
Tpr.ElementNo = T.ElementNo;
Tpr.Attribute = T.Attribute;
PMatI.UseExternalData(elfun.GetData(), dof, dim);
Tpr.GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
Vector weights(nqp);
for (int q = 0; q < nqp; q++)
{
weights(q) = ir->IntPoint(q).weight * Jtr(q).Det();
}
AssembleElemGradAdaptLim(el, weights, Tpr, *ir, elmat);
}
}
void TMOP_Integrator::EnableNormalization(const GridFunction &x)
@@ -1958,7 +2194,8 @@ void TMOP_Integrator::ParEnableNormalization(const ParGridFunction &x)
ComputeNormalizationEnergies(x, loc[0], loc[1]);
double rdc[2];
MPI_Allreduce(loc, rdc, 2, MPI_DOUBLE, MPI_SUM, x.ParFESpace()->GetComm());
metric_normal = 1.0 / rdc[0]; lim_normal = 1.0 / rdc[1];
metric_normal = 1.0 / rdc[0];
lim_normal = 1.0 / rdc[1];
}
#endif
@@ -1978,12 +2215,7 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x,
Jpr.SetSize(dim);
Jpt.SetSize(dim);
const IntegrationRule *ir = IntRule;
if (!ir)
{
ir = &(IntRules.Get(fe->GetGeomType(), 2*fe->GetOrder() + 3)); // <---
}
const IntegrationRule *ir = EnergyIntegrationRule(*fe);
DenseTensor Jtr(dim, dim, ir->GetNPoints());
metric_energy = 0.0;
@@ -2012,19 +2244,20 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x,
lim_energy += weight;
}
}
if (targetC->ContainsVolumeInfo() == false)
{
// Special case when the targets don't contain volumetric information.
lim_energy = fes->GetNE();
}
}
void TMOP_Integrator::ComputeMinJac(const Vector &x,
const FiniteElementSpace &fes)
{
const IntegrationRule *ir = IntRule;
if (!ir)
{
ir = &(IntRules.Get(fes.GetFE(0)->GetGeomType(),
2*fes.GetFE(0)->GetOrder() + 3)); // <---
}
const int NE = fes.GetMesh()->GetNE(), dim = fes.GetFE(0)->GetDim(),
dof = fes.GetFE(0)->GetDof(), nsp = ir->GetNPoints();
const FiniteElement *fe = fes.GetFE(0);
const IntegrationRule *ir = EnergyIntegrationRule(*fe);
const int NE = fes.GetMesh()->GetNE(), dim = fe->GetDim(),
dof = fe->GetDof(), nsp = ir->GetNPoints();
Array<int> xdofs(dof * dim);
DenseMatrix Jpr(dim), dshape(dof, dim), pos(dof, dim);
@@ -2051,6 +2284,12 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x,
dx = detv_avg_min / dxscale;
}
void TMOP_Integrator::UpdateAfterMeshChange(const Vector &new_x)
{
// Update zeta if adaptive limiting is enabled.
if (zeta) { adapt_eval->ComputeAtNewPosition(new_x, *zeta); }
}
void TMOP_Integrator::ComputeFDh(const Vector &x, const FiniteElementSpace &fes)
{
if (!fdflag) { return; }
+73 -23
View File
@@ -598,7 +598,8 @@ public:
supports a set of algorithms chosen by the #TargetType enumeration.
New target-matrix construction algorithms can be defined by deriving new
classes and overriding the method ComputeElementTargets(). */
classes and overriding the methods ComputeElementTargets() and
ContainsVolumeInfo(). */
class TargetConstructor
{
public:
@@ -666,6 +667,9 @@ public:
/// Used by target type IDEAL_SHAPE_EQUAL_SIZE. The default volume scale is 1.
void SetVolumeScale(double vol_scale) { volume_scale = vol_scale; }
/// Checks if the target matrices contain non-trivial size specification.
virtual bool ContainsVolumeInfo() const;
/** @brief Given an element and quadrature rule, computes ref->target
transformation Jacobians for each quadrature point in the element.
The physical positions of the element's nodes are given by @a elfun. */
@@ -870,12 +874,21 @@ protected:
// Normalization factor for the limiting term.
double lim_normal;
// Adaptive limiting.
const GridFunction *zeta_0; // Not owned.
GridFunction *zeta; // Owned. Updated by adapt_eval.
Coefficient *coeff_zeta; // Not owned.
AdaptivityEvaluator *adapt_eval; // Not owned.
DiscreteAdaptTC *discr_tc;
// Parameters for FD-based Gradient & Hessian calculation.
bool fdflag;
bool fdflag;
double dx;
double dxscale;
// Specifies that ComputeElementTargets is being called by a FD function.
// It's used to skip terms that have exact derivative calculations.
bool fd_call_flag;
Array <Vector *> ElemDer; //f'(x)
Array <Vector *> ElemPertEnergy; //f(x+h)
@@ -908,11 +921,18 @@ protected:
ElementTransformation &T,
const Vector &elfun, Vector &elvect);
/** Assumes that AssembleElementVectorFD has been called. */
// Assumes that AssembleElementVectorFD has been called.
void AssembleElementGradFD(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun, DenseMatrix &elmat);
void AssembleElemVecAdaptLim(const FiniteElement &el, const Vector &weights,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir, DenseMatrix &m);
void AssembleElemGradAdaptLim(const FiniteElement &el, const Vector &weights,
IsoparametricTransformation &Tpr,
const IntegrationRule &ir, DenseMatrix &m);
double GetFDDerivative(const FiniteElement &el,
ElementTransformation &T,
Vector &elfun, const int nodenum,const int idir,
@@ -925,11 +945,29 @@ protected:
#endif
void ComputeMinJac(const Vector &x, const FiniteElementSpace &fes);
void UpdateAfterMeshChange(const Vector &new_x);
void DisableLimiting()
{
nodes0 = NULL; coeff0 = NULL; lim_dist = NULL; lim_func = NULL;
}
const IntegrationRule *EnergyIntegrationRule(const FiniteElement &el) const
{
return (IntRule) ? IntRule
/* */ : &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3));
}
const IntegrationRule *ActionIntegrationRule(const FiniteElement &el) const
{
// TODO the energy most likely needs less integration points.
return EnergyIntegrationRule(el);
}
const IntegrationRule *GradientIntegrationRule(const FiniteElement &el) const
{
// TODO the action and energy most likely need less integration points.
return EnergyIntegrationRule(el);
}
public:
/** @param[in] m TMOP_QualityMetric that will be integrated (not owned).
@param[in] tc Target-matrix construction algorithm to use (not owned). */
@@ -938,19 +976,12 @@ public:
coeff1(NULL), metric_normal(1.0),
nodes0(NULL), coeff0(NULL),
lim_dist(NULL), lim_func(NULL), lim_normal(1.0),
zeta_0(NULL), zeta(NULL), coeff_zeta(NULL), adapt_eval(NULL),
discr_tc(dynamic_cast<DiscreteAdaptTC *>(tc)),
fdflag(false), dxscale(1.0e3)
fdflag(false), dxscale(1.0e3), fd_call_flag(false)
{ }
~TMOP_Integrator()
{
delete lim_func;
for (int i = 0; i < ElemDer.Size(); i++)
{
delete ElemDer[i];
delete ElemPertEnergy[i];
}
}
~TMOP_Integrator();
/// Sets a scaling Coefficient for the quality metric term of the integrator.
/** With this addition, the integrator becomes
@@ -960,15 +991,15 @@ public:
not in the target configuration which may be undefined. */
void SetCoefficient(Coefficient &w1) { coeff1 = &w1; }
/// Adds a limiting term to the integrator (general version).
/** With this addition, the integrator becomes
@f$ \int w1 W(Jpt) + w0 f(x, x_0, d) dx @f$,
where the second term measures the change with respect to the original
physical positions, @a n0.
@param[in] n0 Original mesh node coordinates.
@param[in] dist Limiting physical distances.
@param[in] w0 Coefficient scaling the limiting term.
@param[in] lfunc TMOP_LimiterFunction defining the limiting term f. If
/** @brief Limiting of the mesh displacements (general version).
Adds the term @f$ \int w_0 f(x, x_0, d) dx @f$, where f is a measure of
the displacement between x and x_0, given the max allowed displacement d.
@param[in] n0 Original mesh node coordinates (x0 above).
@param[in] dist Allowed displacement in physical space (d above).
@param[in] w0 Coefficient scaling the limiting integral.
@param[in] lfunc TMOP_LimiterFunction defining the function f. If
NULL, a TMOP_QuadraticLimiter will be used. The
TMOP_Integrator assumes ownership of this pointer. */
void EnableLimiting(const GridFunction &n0, const GridFunction &dist,
@@ -979,6 +1010,25 @@ public:
void EnableLimiting(const GridFunction &n0, Coefficient &w0,
TMOP_LimiterFunction *lfunc = NULL);
/** @brief Restriction of the node positions to certain regions.
Adds the term @f$ \int c (z(x) - z_0(x_0))^2 @f$, where z0(x0) is a given
function on the starting mesh, and z(x) is its image on the new mesh.
Minimizing this, means that a node at x0 is allowed to move to a
position x(x0) only if z(x) ~ z0(x0).
Such term can be used for tangential mesh relaxation.
@param[in] z0 Function z0 that controls the adaptive limiting.
@param[in] coeff Coefficient c for the above integral.
@param[in] ae AdaptivityEvaluator to compute z(x) from z0(x0). */
void EnableAdaptiveLimiting(const GridFunction &z0, Coefficient &coeff,
AdaptivityEvaluator &ae);
#ifdef MFEM_USE_MPI
/// Parallel support for adaptive limiting.
void EnableAdaptiveLimiting(const ParGridFunction &z0, Coefficient &coeff,
AdaptivityEvaluator &ae);
#endif
/// Update the original/reference nodes used for limiting.
void SetLimitingNodes(const GridFunction &n0) { nodes0 = &n0; }
@@ -1035,7 +1085,7 @@ public:
/// Adds a new TMOP_Integrator to the combination.
void AddTMOPIntegrator(TMOP_Integrator *ti) { tmopi.Append(ti); }
Array<TMOP_Integrator *> GetTMOPIntegrators() const { return tmopi; }
const Array<TMOP_Integrator *> &GetTMOPIntegrators() const { return tmopi; }
/// Adds the limiting term to the first integrator. Disables it for the rest.
void EnableLimiting(const GridFunction &n0, const GridFunction &dist,
+7 -2
View File
@@ -33,10 +33,11 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes,
const int pnt_cnt = new_field.Size()/ncomp;
new_field = field0;
new_field.HostReadWrite();
Vector new_field_temp;
for (int i = 0; i < ncomp; i++)
{
Vector new_field_temp(new_field.GetData()+i*pnt_cnt, pnt_cnt);
new_field_temp.MakeRef(new_field, i*pnt_cnt, pnt_cnt);
ComputeAtNewPositionScalar(new_nodes, new_field_temp);
}
@@ -94,6 +95,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
double v_max = 0.0;
const int s = new_field.Size();
u.HostReadWrite();
for (int i = 0; i < s; i++)
{
double vel = 0.;
@@ -149,6 +151,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
#endif
// Trim the overshoots and undershoots.
new_field.HostReadWrite();
for (int i = 0; i < s; i++)
{
if (new_field(i) < glob_minv) { new_field(i) = glob_minv; }
@@ -499,6 +502,7 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
if (ti)
{
ti->UpdateAfterMeshChange(x_loc);
ti->ComputeFDh(x_loc, *pfesc);
UpdateDiscreteTC(*ti, x_loc);
}
@@ -534,6 +538,7 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
if (ti)
{
ti->UpdateAfterMeshChange(x_loc);
ti->ComputeFDh(x_loc, *fesc);
UpdateDiscreteTC(*ti, x_loc);
}
+51 -34
View File
@@ -60,31 +60,31 @@ public:
/// Creates an empty array with a given MemoryType
inline Array(MemoryType mt) : size(0) { data.Reset(mt); }
/// Creates array of asize elements
/// Creates array of @a asize elements
explicit inline Array(int asize)
: size(asize) { asize > 0 ? data.New(asize) : data.Reset(); }
/** Creates array using an existing c-array of asize elements;
/** @brief Creates array using an existing c-array of asize elements;
allocsize is set to -asize to indicate that the data will not
be deleted. */
inline Array(T *_data, int asize)
{ data.Wrap(_data, asize, false); size = asize; }
/// Copy constructor: deep copy
/// Copy constructor: deep copy from @a src
/** This method supports source arrays using any MemoryType. */
inline Array(const Array &src);
/// Copy constructor (deep copy) from an Array of convertable type
/// Copy constructor (deep copy) from 'src', an Array of convertible type.
template <typename CT>
inline Array(const Array<CT> &src);
/// Destructor
inline ~Array() { data.Delete(); }
/// Assignment operator: deep copy
/// Assignment operator: deep copy from 'src'.
Array<T> &operator=(const Array<T> &src) { src.Copy(*this); return *this; }
/// Assignment operator (deep copy) from an Array of convertable type
/// Assignment operator (deep copy) from @a src, an Array of convertible type.
template <typename CT>
inline Array &operator=(const Array<CT> &src);
@@ -120,13 +120,13 @@ public:
/// Make the Array own the data
void MakeDataOwner() const { data.SetHostPtrOwner(true); }
/// Logical size of the array
/// Return the logical size of the array.
inline int Size() const { return size; }
/// Change logical size of the array, keep existing entries
/// Change the logical size of the array, keep existing entries.
inline void SetSize(int nsize);
/// Same as SetSize(int) plus initialize new entries with 'initval'
/// Same as SetSize(int) plus initialize new entries with 'initval'.
inline void SetSize(int nsize, const T &initval);
/** @brief Resize the array to size @a nsize using MemoryType @a mt. Note
@@ -142,58 +142,63 @@ public:
inline void Reserve(int capacity)
{ if (capacity > Capacity()) { GrowSize(capacity); } }
/// Access element
/// Reference access to the ith element.
inline T & operator[](int i);
/// Access const element
/// Const reference access to the ith element.
inline const T &operator[](int i) const;
/// Append element to array, resize if necessary
/// Append element 'el' to array, resize if necessary.
inline int Append(const T & el);
/// Append another array to this array, resize if necessary
/// Append another array to this array, resize if necessary.
inline int Append(const T *els, int nels);
/// Append another array to this array, resize if necessary
/// Append another array to this array, resize if necessary.
inline int Append(const Array<T> &els) { return Append(els, els.Size()); }
/// Prepend an element to the array, resize if necessary
/// Prepend an 'el' to the array, resize if necessary.
inline int Prepend(const T &el);
/// Return the last element in the array
/// Return the last element in the array.
inline T &Last();
/// Return the last element in the array.
inline const T &Last() const;
/// Append element when it is not yet in the array, return index
/// Append element when it is not yet in the array, return index.
inline int Union(const T & el);
/// Return the first index where 'el' is found; return -1 if not found
/// Return the first index where 'el' is found; return -1 if not found.
inline int Find(const T &el) const;
/// Do bisection search for 'el' in a sorted array; return -1 if not found.
inline int FindSorted(const T &el) const;
/// Delete the last entry
/// Delete the last entry of the array.
inline void DeleteLast() { if (size > 0) { size--; } }
/// Delete the first 'el' entry
/// Delete the first entry with value == 'el'.
inline void DeleteFirst(const T &el);
/// Delete whole array
/// Delete the whole array.
inline void DeleteAll();
/// Create a copy of the current array
/// Create a copy of the internal array to the provided @a copy.
inline void Copy(Array &copy) const;
/// Make this Array a reference to a pointer
/// Make this Array a reference to a pointer.
inline void MakeRef(T *, int);
/// Make this Array a reference to 'master'
/// Make this Array a reference to 'master'.
inline void MakeRef(const Array &master);
/// Copy sub array starting from @a offset out to the provided @a sa.
inline void GetSubArray(int offset, int sa_size, Array<T> &sa) const;
/// Prints array to stream with width elements per row
/// Prints array to stream with width elements per row.
void Print(std::ostream &out = mfem::out, int width = 4) const;
/** @brief Save the Array to the stream @a out using the format @a fmt.
@@ -225,48 +230,60 @@ public:
operator `<` for class T. */
T Min() const;
/// Sorts the array. This requires operator< to be defined for T.
/// Sorts the array in ascending order. This requires operator< to be defined for T.
void Sort() { std::sort((T*)data, data + size); }
/// Sorts the array using the supplied comparison function object.
/// Sorts the array in ascending order using the supplied comparison function object.
template<class Compare>
void Sort(Compare cmp) { std::sort((T*)data, data + size, cmp); }
/** Removes duplicities from a sorted array. This requires operator== to be
defined for T. */
/** @brief Removes duplicities from a sorted array. This requires
operator== to be defined for T. */
void Unique()
{
T* end = std::unique((T*)data, data + size);
SetSize(end - data);
}
/// return true if the array is sorted.
/// Return 1 if the array is sorted from lowest to highest. Otherwise return 0.
int IsSorted();
/// Partial Sum
/// Fill the entries of the array with the cumulative sum of the entries.
void PartialSum();
/// Sum all entries
/// Return the sum of all the array entries using the '+'' operator for class 'T'.
T Sum();
/// Set all entries of the array to the provided constant.
inline void operator=(const T &a);
/// Copy data from a pointer. Size() elements are copied.
/// Copy data from a pointer. 'Size()' elements are copied.
inline void Assign(const T *);
/// STL-like copyTo @a dest from begin to end.
template <typename U>
inline void CopyTo(U *dest) { std::copy(begin(), end(), dest); }
/** @brief Copy from @a src into this array. Copies enough entries to
fill the Capacity size of this array. Careful this does not update
the Size to match this Capacity after this.*/
template <typename U>
inline void CopyFrom(const U *src)
{ std::memcpy(begin(), src, MemoryUsage()); }
// STL-like begin/end
/// STL-like begin. Returns pointer to the first element of the array.
inline T* begin() { return data; }
/// STL-like end. Returns pointer after the last element of the array.
inline T* end() { return data + size; }
/// STL-like begin. Returns const pointer to the first element of the array.
inline const T* begin() const { return data; }
/// STL-like end. Returns const pointer after the last element of the array.
inline const T* end() const { return data + size; }
/// Returns the number of bytes allocated for the array including any reserve.
long MemoryUsage() const { return Capacity() * sizeof(T); }
/// Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
+2
View File
@@ -25,12 +25,14 @@ namespace mfem
namespace bin_io
{
/// Write 'value' to stream.
template<typename T>
inline void write(std::ostream& os, T value)
{
os.write((char*) &value, sizeof(T));
}
/// Read a value from the stream and return it.
template<typename T>
inline T read(std::istream& is)
{
+61 -36
View File
@@ -47,69 +47,91 @@ public:
bool Root() const { return world_rank == 0; }
};
/** The shared entities (e.g. vertices, faces and edges) are split into groups,
each group determined by the set of participating processors. They are
numbered locally in lproc. Assumptions:
- group 0 is the 'local' group
- groupmaster_lproc[0] = 0
- lproc_proc[0] = MyRank */
class GroupTopology
{
private:
MPI_Comm MyComm;
/* The shared entities (e.g. vertices, faces and edges) are split into
groups, each group determined by the set of participating processors.
They are numbered locally in lproc. Assumptions:
- group 0 is the 'local' group
- groupmaster_lproc[0] = 0
- lproc_proc[0] = MyRank */
// Neighbor ids (lproc) in each group.
/// Neighbor ids (lproc) in each group.
Table group_lproc;
// Master neighbor id for each group.
/// Master neighbor id for each group.
Array<int> groupmaster_lproc;
// MPI rank of each neighbor.
/// MPI rank of each neighbor.
Array<int> lproc_proc;
// Group --> Group number in the master.
/// Group --> Group number in the master.
Array<int> group_mgroup;
void ProcToLProc();
public:
/// Constructor with the MPI communicator = 0.
GroupTopology() : MyComm(0) {}
/// Constructor given the MPI communicator 'comm'.
GroupTopology(MPI_Comm comm) { MyComm = comm; }
/// Copy constructor
GroupTopology(const GroupTopology &gt);
/// Set the MPI communicator to 'comm'.
void SetComm(MPI_Comm comm) { MyComm = comm; }
/// Return the MPI communicator.
MPI_Comm GetComm() const { return MyComm; }
/// Return the MPI rank within this object's communicator.
int MyRank() const { int r; MPI_Comm_rank(MyComm, &r); return r; }
/// Return the number of MPI ranks within this object's communicator.
int NRanks() const { int s; MPI_Comm_size(MyComm, &s); return s; }
/// Set up the group topology given the list of sets of shared entities.
void Create(ListOfIntegerSets &groups, int mpitag);
/// Return the number of groups.
int NGroups() const { return group_lproc.Size(); }
// return the number of neighbors including the local processor
/// Return the number of neighbors including the local processor.
int GetNumNeighbors() const { return lproc_proc.Size(); }
/// Return the MPI rank of neighbor 'i'.
int GetNeighborRank(int i) const { return lproc_proc[i]; }
// am I master for group 'g'?
/// Return true if I am master for group 'g'.
bool IAmMaster(int g) const { return (groupmaster_lproc[g] == 0); }
// return the neighbor index of the group master for a given group.
// neighbor 0 is the local processor
/** @brief Return the neighbor index of the group master for a given group.
Neighbor 0 is the local processor. */
int GetGroupMaster(int g) const { return groupmaster_lproc[g]; }
// return the rank of the group master for a given group
/// Return the rank of the group master for group 'g'.
int GetGroupMasterRank(int g) const
{ return lproc_proc[groupmaster_lproc[g]]; }
// for a given group return the group number in the master
/// Return the group number in the master for group 'g'.
int GetGroupMasterGroup(int g) const { return group_mgroup[g]; }
// get the number of processors in a group
/// Get the number of processors in a group
int GetGroupSize(int g) const { return group_lproc.RowSize(g); }
// return a pointer to a list of neighbors for a given group.
// neighbor 0 is the local processor
/** @brief Return a pointer to a list of neighbors for a given group.
Neighbor 0 is the local processor */
const int *GetGroup(int g) const { return group_lproc.GetRow(g); }
/// Save the data in a stream.
void Save(std::ostream &out) const;
/// Load the data from a stream.
void Load(std::istream &in);
/// Copy
/// Copy the internal data to the external 'copy'.
void Copy(GroupTopology & copy) const;
virtual ~GroupTopology() {}
@@ -186,9 +208,8 @@ public:
void GetNeighborLDofTable(Table &nbr_ldof) const;
/** @brief Data structure on which we define reduce operations.
The data is associated with (and the operation is performed on) one group
at a time. */
The data is associated with (and the operation is performed on) one
group at a time. */
template <class T> struct OpData
{
int nldofs, nb;
@@ -322,9 +343,10 @@ struct VarMessage
std::string data;
MPI_Request send_request;
/** Non-blocking send to processor 'rank'. Returns immediately. Completion
(as tested by MPI_Wait/Test) does not mean the message was received --
it may be on its way or just buffered locally. */
/** @brief Non-blocking send to processor 'rank'.
Returns immediately. Completion (as tested by MPI_Wait/Test) does not
mean the message was received -- it may be on its way or just buffered
locally. */
void Isend(int rank, MPI_Comm comm)
{
Encode(rank);
@@ -332,8 +354,9 @@ struct VarMessage
&send_request);
}
/** Non-blocking synchronous send to processor 'rank'. Returns immediately.
Completion (MPI_Wait/Test) means that the message was received. */
/** @brief Non-blocking synchronous send to processor 'rank'.
Returns immediately. Completion (MPI_Wait/Test) means that the message
was received. */
void Issend(int rank, MPI_Comm comm)
{
Encode(rank);
@@ -362,8 +385,8 @@ struct VarMessage
}
}
/** Return true if all messages in the map container were sent, otherwise
return false, without waiting. */
/** @brief Return true if all messages in the map container were sent,
otherwise return false, without waiting. */
template<typename MapT>
static bool TestAllSent(MapT& rank_msg)
{
@@ -381,7 +404,7 @@ struct VarMessage
return true;
}
/** Blocking probe for incoming message of this type from any rank.
/** @brief Blocking probe for incoming message of this type from any rank.
Returns the rank and message size. */
static void Probe(int &rank, int &size, MPI_Comm comm)
{
@@ -391,9 +414,9 @@ struct VarMessage
MPI_Get_count(&status, MPI_BYTE, &size);
}
/** Non-blocking probe for incoming message of this type from any rank.
If there is an incoming message, returns true and sets 'rank' and 'size'.
Otherwise returns false. */
/** @brief Non-blocking probe for incoming message of this type from any
rank. If there is an incoming message, returns true and sets 'rank' and
'size'. Otherwise returns false. */
static bool IProbe(int &rank, int &size, MPI_Comm comm)
{
int flag;
@@ -421,7 +444,7 @@ struct VarMessage
Decode(rank);
}
/// Like Recv(), but throw away the messsage.
/// Like Recv(), but throw away the message.
void RecvDrop(int rank, int size, MPI_Comm comm)
{
data.resize(size);
@@ -448,6 +471,8 @@ struct VarMessage
}
VarMessage() : send_request(MPI_REQUEST_NULL) {}
/// Clear the message and associated request.
void Clear() { data.clear(); send_request = MPI_REQUEST_NULL; }
virtual ~VarMessage()
+4 -4
View File
@@ -77,19 +77,19 @@ void mfem_cuda_error(cudaError_t err, const char *expr, const char *func,
const char *file, int line);
#endif
/// Allocates device memory
/// Allocates device memory and returns destination ptr.
void* CuMemAlloc(void **d_ptr, size_t bytes);
/// Allocates managed device memory
void* CuMallocManaged(void **d_ptr, size_t bytes);
/// Frees device memory
/// Frees device memory and returns destination ptr.
void* CuMemFree(void *d_ptr);
/// Copies memory from Host to Device
/// Copies memory from Host to Device and returns destination ptr.
void* CuMemcpyHtoD(void *d_dst, const void *h_src, size_t bytes);
/// Copies memory from Host to Device
/// Copies memory from Host to Device and returns destination ptr.
void* CuMemcpyHtoDAsync(void *d_dst, const void *h_src, size_t bytes);
/// Copies memory from Device to Device
+35 -15
View File
@@ -61,15 +61,11 @@ Device Device::device_singleton;
bool Device::device_env = false;
bool Device::mem_host_env = false;
bool Device::mem_device_env = false;
#ifdef MFEM_USE_UMPIRE
bool Device::use_umpire = true;
#endif
Device::Device() : mode(Device::SEQUENTIAL),
backends(Backend::CPU),
destroy_mm(false),
mpi_gpu_aware(false),
host_mem_type(MemoryType::HOST),
host_mem_class(MemoryClass::HOST),
device_mem_type(MemoryType::HOST),
device_mem_class(MemoryClass::HOST)
Device::Device()
{
if (getenv("MFEM_MEMORY") && !mem_host_env && !mem_device_env)
{
@@ -135,7 +131,7 @@ Device::Device() : mode(Device::SEQUENTIAL),
{
MFEM_ABORT("Unknown memory backend!");
}
mm.Configure(host_mem_type, device_mem_type);
mm.Configure(host_mem_type, device_mem_type, device_mem_type);
}
if (getenv("MFEM_DEVICE"))
@@ -165,6 +161,8 @@ Device::~Device()
Get().host_mem_class = MemoryClass::HOST;
Get().device_mem_type = MemoryType::HOST;
Get().device_mem_class = MemoryClass::HOST;
Get().device_temp_mem_type = MemoryType::HOST;
Get().device_temp_mem_class = MemoryClass::HOST;
}
void Device::Configure(const std::string &device, const int dev)
@@ -260,6 +258,10 @@ void Device::Print(std::ostream &out)
if (Device::Allows(Backend::DEVICE_MASK))
{
out << ',' << MemoryTypeName[static_cast<int>(device_mem_type)];
if (device_temp_mem_type != device_mem_type)
{
out << ',' << MemoryTypeName[static_cast<int>(device_temp_mem_type)];
}
}
out << std::endl;
}
@@ -272,7 +274,8 @@ void Device::UpdateMemoryTypeAndClass()
#ifdef MFEM_USE_UMPIRE
// If MFEM has been compiled with Umpire support, use it as the default
if (!mem_host_env) { host_mem_type = MemoryType::HOST_UMPIRE; }
// TODO TMS: temporary
//if (!mem_host_env && use_umpire) { host_mem_type = MemoryType::HOST_UMPIRE; }
#endif
// Enable the device memory type
@@ -296,11 +299,16 @@ void Device::UpdateMemoryTypeAndClass()
}
else
{
#ifndef MFEM_USE_UMPIRE
device_mem_type = MemoryType::DEVICE;
#else
device_mem_type = MemoryType::DEVICE_UMPIRE;
#ifdef MFEM_USE_UMPIRE
if (use_umpire)
{
device_mem_type = MemoryType::DEVICE_UMPIRE;
}
else
#endif
{
device_mem_type = MemoryType::DEVICE;
}
}
}
device_mem_class = MemoryClass::DEVICE;
@@ -320,8 +328,20 @@ void Device::UpdateMemoryTypeAndClass()
device_mem_type = MemoryType::DEVICE_DEBUG;
}
// Setup device_temp_mem_{type,class}
switch (device_mem_type)
{
case MemoryType::DEVICE_UMPIRE:
device_temp_mem_type = MemoryType::DEVICE_TEMP_UMPIRE;
break;
default:
device_temp_mem_type = device_mem_type;
break;
}
device_temp_mem_class = device_mem_class;
// Update the memory manager with the new settings
mm.Configure(host_mem_type, device_mem_type);
mm.Configure(host_mem_type, device_mem_type, device_temp_mem_type);
}
void Device::Enable()
+28 -16
View File
@@ -119,20 +119,26 @@ private:
static bool device_env, mem_host_env, mem_device_env;
static Device device_singleton;
#ifdef MFEM_USE_UMPIRE
static bool use_umpire;
#endif
MODES mode;
MODES mode{Device::SEQUENTIAL};
int dev = 0; ///< Device ID of the configured device.
int ngpu = -1; ///< Number of detected devices; -1: not initialized.
unsigned long backends; ///< Bitwise-OR of all configured backends.
unsigned long backends{Backend::CPU}; ///< Bitwise-OR of all configured backends.
/// Set to true during configuration, except in 'device_singleton'.
bool destroy_mm;
bool mpi_gpu_aware;
bool destroy_mm{false};
bool mpi_gpu_aware{false};
MemoryType host_mem_type; ///< Current Host MemoryType
MemoryClass host_mem_class; ///< Current Host MemoryClass
MemoryType host_mem_type{MemoryType::HOST}; ///< Current Host MemoryType
MemoryClass host_mem_class{MemoryClass::HOST}; ///< Current Host MemoryClass
MemoryType device_mem_type; ///< Current Device MemoryType
MemoryClass device_mem_class; ///< Current Device MemoryClass
MemoryType device_mem_type{MemoryType::HOST}; ///< Current Device MemoryType
MemoryClass device_mem_class{MemoryClass::HOST}; ///< Current Device MemoryClass
MemoryType device_temp_mem_type{MemoryType::HOST}; ///< Current Device MemoryType
MemoryClass device_temp_mem_class{MemoryClass::HOST}; ///< Current Device MemoryClass
char *device_option = NULL;
Device(Device const&);
@@ -173,14 +179,6 @@ public:
@note This object should be destroyed after all other MFEM objects that
use the Device are destroyed. */
Device(const std::string &device, const int dev = 0)
: mode(Device::SEQUENTIAL),
backends(Backend::CPU),
destroy_mm(false),
mpi_gpu_aware(false),
host_mem_type(MemoryType::HOST),
host_mem_class(MemoryClass::HOST),
device_mem_type(MemoryType::HOST),
device_mem_class(MemoryClass::HOST)
{ Configure(device, dev); }
/// Destructor.
@@ -260,10 +258,24 @@ public:
/** @deprecated Use GetDeviceMemoryClass() instead. */
static inline MemoryClass GetMemoryClass() { return Get().device_mem_class; }
/** @brief Get the current Device Temporary MemoryType. This is the MemoryType used by
MFEM classes when allocating temporary memory to be used with device kernels.
*/
static inline MemoryType GetDeviceTempMemoryType() { return Get().device_temp_mem_type; }
/** @brief Get the current Device Temporary MemoryClass. This is the MemoryClass used
by MFEM device kernels when they need to access temporary Memory objects. */
static inline MemoryClass GetDeviceTempMemoryClass() { return Get().device_temp_mem_class; }
static void SetGPUAwareMPI(const bool force = true)
{ Get().mpi_gpu_aware = force; }
static bool GetGPUAwareMPI() { return Get().mpi_gpu_aware; }
#ifdef MFEM_USE_UMPIRE
static bool UseUmpire() { return Get().use_umpire; }
static void UseUmpire(bool use) { Get().use_umpire = use; }
#endif
};
+2 -1
View File
@@ -77,7 +77,7 @@ public:
HashTable(const HashTable& other); // deep copy
~HashTable();
/// Get item whose parents are p1, p2... Create it if it doesn't exist.
/// Get item whose parents are 'p1', 'p2'... Create it if it doesn't exist.
T* Get(int p1, int p2);
T* Get(int p1, int p2, int p3, int p4 = -1 /* p4 optional */);
@@ -123,6 +123,7 @@ public:
/// Return total size of allocated memory (tables plus items), in bytes.
long MemoryUsage() const;
/// Write details of the memory usage to the mfem output stream.
void PrintMemoryDetail() const;
class iterator : public Base::iterator
+9
View File
@@ -33,12 +33,21 @@ private:
StackPart <Elem, Num> *TopPart, *TopFreePart;
int UsedInTop, SSize;
public:
/// Construct an empty stack.
Stack() { TopPart = TopFreePart = NULL; UsedInTop = Num; SSize = 0; }
/// Return the number of elements on the stack.
int Size() const { return SSize; }
/// Push element 'E' on the stack.
void Push (Elem E);
/// Pop an element off the stack and return it.
Elem Pop();
/// Clear the elements off the stack.
void Clear();
/// Swap the data in this stack with the data in @a other.
void Swap(Stack<Elem, Num> &other);
/// Return the number of bytes used by the stack.
size_t MemoryUsage() const;
~Stack() { Clear(); }
};
+118 -44
View File
@@ -67,15 +67,19 @@ MemoryType MemoryManager::GetDualMemoryType_(MemoryType mt)
{
switch (mt)
{
case MemoryType::HOST: return MemoryType::DEVICE;
// TODO TMS: temporary
case MemoryType::HOST: return MemoryType::DEVICE_UMPIRE;
case MemoryType::HOST_32: return MemoryType::DEVICE;
case MemoryType::HOST_64: return MemoryType::DEVICE;
case MemoryType::HOST_DEBUG: return MemoryType::DEVICE_DEBUG;
case MemoryType::HOST_UMPIRE: return MemoryType::DEVICE_UMPIRE;
//case MemoryType::HOST_UMPIRE: return MemoryType::DEVICE_UMPIRE;
case MemoryType::MANAGED: return MemoryType::MANAGED;
case MemoryType::DEVICE: return MemoryType::HOST;
case MemoryType::DEVICE_DEBUG: return MemoryType::HOST_DEBUG;
case MemoryType::DEVICE_UMPIRE: return MemoryType::HOST_UMPIRE;
//case MemoryType::DEVICE_UMPIRE: return MemoryType::HOST_UMPIRE;
case MemoryType::DEVICE_UMPIRE: return MemoryType::HOST;
//case MemoryType::DEVICE_TEMP_UMPIRE: return MemoryType::HOST_UMPIRE;
case MemoryType::DEVICE_TEMP_UMPIRE: return MemoryType::HOST;
default: mfem_error("Unknown memory type!");
}
MFEM_VERIFY(false,"");
@@ -88,6 +92,9 @@ static void MFEM_VERIFY_TYPES(const MemoryType h_mt, const MemoryType d_mt)
MFEM_ASSERT(IsDeviceMemory(d_mt),"");
const bool sync =
(h_mt == MemoryType::HOST_UMPIRE && d_mt == MemoryType::DEVICE_UMPIRE) ||
(h_mt == MemoryType::HOST_UMPIRE && d_mt == MemoryType::DEVICE_TEMP_UMPIRE) ||
(h_mt == MemoryType::HOST && d_mt == MemoryType::DEVICE_UMPIRE) ||
(h_mt == MemoryType::HOST && d_mt == MemoryType::DEVICE_TEMP_UMPIRE) ||
(h_mt == MemoryType::HOST_DEBUG && d_mt == MemoryType::DEVICE_DEBUG) ||
(h_mt == MemoryType::MANAGED && d_mt == MemoryType::MANAGED) ||
(h_mt == MemoryType::HOST_64 && d_mt == MemoryType::DEVICE) ||
@@ -461,48 +468,96 @@ public:
#ifndef MFEM_USE_UMPIRE
class UmpireHostMemorySpace : public NoHostMemorySpace { };
class UmpireDeviceMemorySpace : public NoDeviceMemorySpace { };
class UmpireDeviceTempMemorySpace : public NoDeviceMemorySpace { };
#else
// TODO TMS: replace with um.hasAllocatorId(int) when it exists
bool UmpireHasId(const umpire::ResourceManager & rm, int id)
{
const auto & ids = rm.getAllocatorIds();
return std::find(ids.begin(), ids.end(), id) != ids.end();
}
/// The Umpire host memory space
class UmpireHostMemorySpace : public HostMemorySpace
{
private:
const char *name;
umpire::ResourceManager &rm;
umpire::Allocator h_allocator;
umpire::strategy::AllocationStrategy *strat;
bool owns_allocator{false};
public:
~UmpireHostMemorySpace() { h_allocator.release(); }
UmpireHostMemorySpace():
HostMemorySpace(),
name(mm.GetUmpireAllocatorHostName()),
rm(umpire::ResourceManager::getInstance()),
h_allocator(rm.isAllocator(name)? rm.getAllocator(name):
rm.makeAllocator<umpire::strategy::DynamicPool>
(name, rm.getAllocator("HOST"))),
strat(h_allocator.getAllocationStrategy()) { }
// TODO: this only releases unused memory
~UmpireHostMemorySpace() { if (owns_allocator) { h_allocator.release(); } }
UmpireHostMemorySpace(): HostMemorySpace(),
rm(umpire::ResourceManager::getInstance())
{
const int id = MemoryManager::GetUmpireHostAllocatorId();
if (!UmpireHasId(rm, id))
{
h_allocator = rm.makeAllocator<umpire::strategy::DynamicPool>("MFEM_HOST",
rm.getAllocator("HOST"));
owns_allocator = true;
}
else
{
h_allocator = rm.getAllocator(id);
}
MemoryManager::SetUmpireHostAllocatorId(id);
}
void Alloc(void **ptr, size_t bytes) { *ptr = h_allocator.allocate(bytes); }
void Dealloc(void *ptr) { h_allocator.deallocate(ptr); }
void Insert(void *ptr, size_t bytes)
{ rm.registerAllocation(ptr, {ptr, bytes, strat}); }
{ mfem_error("UmpireHostMemorySpace::Insert is unsupported"); }
};
/// The Umpire device memory space
#ifdef MFEM_USE_CUDA
class UmpireDeviceMemorySpace : public DeviceMemorySpace
class UmpireDeviceMemorySpaceImpl : public DeviceMemorySpace
{
public:
enum class AllocatorType { TEMPORARY, PERMANENT };
private:
const char *name;
umpire::ResourceManager &rm;
umpire::Allocator d_allocator;
bool owns_allocator{false};
int SetupAllocator(int possible_id, const char * allocator_name)
{
if (!UmpireHasId(rm, possible_id))
{
d_allocator = rm.makeAllocator<umpire::strategy::DynamicPool>(allocator_name,
rm.getAllocator("DEVICE"));
owns_allocator = true;
}
else
{
d_allocator = rm.getAllocator(possible_id);
}
return d_allocator.getId();
}
public:
~UmpireDeviceMemorySpace() { d_allocator.release(); }
UmpireDeviceMemorySpace():
DeviceMemorySpace(),
name(mm.GetUmpireAllocatorDeviceName()),
rm(umpire::ResourceManager::getInstance()),
d_allocator(rm.isAllocator(name)? rm.getAllocator(name):
rm.makeAllocator<umpire::strategy::DynamicPool>
(name, rm.getAllocator("DEVICE"))) { }
// TODO: this only releases unused memory
~UmpireDeviceMemorySpaceImpl() { if (owns_allocator) { d_allocator.release(); } }
UmpireDeviceMemorySpaceImpl(AllocatorType t): DeviceMemorySpace(),
rm(umpire::ResourceManager::getInstance())
{
switch (t)
{
case AllocatorType::PERMANENT:
MemoryManager::SetUmpireDeviceAllocatorId(SetupAllocator(
MemoryManager::GetUmpireDeviceAllocatorId(),
"MFEM_DEVICE"));
break;
case AllocatorType::TEMPORARY:
MemoryManager::SetUmpireDeviceTempAllocatorId(SetupAllocator(
MemoryManager::GetUmpireDeviceTempAllocatorId(),
"MFEM_DEVICE_TEMPORARY"));
break;
default:
mfem_error("Unknown Umpire AllocatorType");
}
}
void Alloc(Memory &base) { base.d_ptr = d_allocator.allocate(base.bytes); }
void Dealloc(Memory &base) { d_allocator.deallocate(base.d_ptr); }
void *HtoD(void *dst, const void *src, size_t bytes)
@@ -536,8 +591,23 @@ public:
//rm.copy(dst, const_cast<void*>(src), bytes); return dst;
}
};
class UmpireDeviceMemorySpace : public UmpireDeviceMemorySpaceImpl
{
public:
UmpireDeviceMemorySpace() : UmpireDeviceMemorySpaceImpl(
AllocatorType::PERMANENT) {}
};
class UmpireDeviceTempMemorySpace : public UmpireDeviceMemorySpaceImpl
{
public:
UmpireDeviceTempMemorySpace() : UmpireDeviceMemorySpaceImpl(
AllocatorType::TEMPORARY) {}
};
#else
class UmpireDeviceMemorySpace : public NoDeviceMemorySpace { };
class UmpireDeviceTempMemorySpace : public NoDeviceMemorySpace { };
#endif // MFEM_USE_CUDA
#endif // MFEM_USE_UMPIRE
@@ -568,7 +638,7 @@ public:
host[static_cast<int>(MT::HOST_64)] = new Aligned64HostMemorySpace();
// HOST_DEBUG is delayed, as it reroutes signals
host[static_cast<int>(MT::HOST_DEBUG)] = nullptr;
host[static_cast<int>(MT::HOST_UMPIRE)] = new UmpireHostMemorySpace();
host[static_cast<int>(MT::HOST_UMPIRE)] = nullptr;
host[static_cast<int>(MT::MANAGED)] = new UvmHostMemorySpace();
// Filling the device memory backends, shifting with the device size
@@ -610,8 +680,12 @@ public:
private:
HostMemorySpace* NewHostCtrl(const MemoryType mt)
{
if (mt == MT::HOST_DEBUG) { return new MmuHostMemorySpace(); }
MFEM_ABORT("Unknown host memory controller!");
switch (mt)
{
case MT::HOST_DEBUG: return new MmuHostMemorySpace();
case MT::HOST_UMPIRE: return new UmpireHostMemorySpace();
default: MFEM_ABORT("Unknown host memory controller!");
}
return nullptr;
}
@@ -620,6 +694,7 @@ private:
switch (mt)
{
case MT::DEVICE_UMPIRE: return new UmpireDeviceMemorySpace();
case MT::DEVICE_TEMP_UMPIRE: return new UmpireDeviceTempMemorySpace();
case MT::DEVICE_DEBUG: return new MmuDeviceMemorySpace();
case MT::DEVICE:
{
@@ -760,7 +835,7 @@ bool MemoryManager::MemoryClassCheck_(MemoryClass mc, void *h_ptr,
const bool known = mm.IsKnown(h_ptr);
const bool alias = mm.IsAlias(h_ptr);
const bool check = known || ((flags & Mem::ALIAS) && alias);
MFEM_VERIFY(check,"");
MFEM_VERIFY(check,"Unknown host pointer: " << h_ptr);
const internal::Memory &mem =
(flags & Mem::ALIAS) ?
*maps->aliases.at(h_ptr).mem : maps->memories.at(h_ptr);
@@ -783,6 +858,7 @@ bool MemoryManager::MemoryClassCheck_(MemoryClass mc, void *h_ptr,
MFEM_VERIFY(d_mt == MemoryType::DEVICE ||
d_mt == MemoryType::DEVICE_DEBUG ||
d_mt == MemoryType::DEVICE_UMPIRE ||
d_mt == MemoryType::DEVICE_TEMP_UMPIRE ||
d_mt == MemoryType::MANAGED,"");
return true;
}
@@ -1262,22 +1338,15 @@ MemoryManager::MemoryManager() { Init(); }
MemoryManager::~MemoryManager() { if (exists) { Destroy(); } }
void MemoryManager::Configure(const MemoryType host_mt,
const MemoryType device_mt)
const MemoryType device_mt,
const MemoryType device_tmt)
{
Init();
host_mem_type = host_mt;
device_mem_type = device_mt;
device_temp_mem_type = device_tmt;
}
#ifdef MFEM_USE_UMPIRE
void MemoryManager::SetUmpireAllocatorNames(const char *h_name,
const char *d_name)
{
h_umpire_name = h_name;
d_umpire_name = d_name;
}
#endif
void MemoryManager::Destroy()
{
MFEM_VERIFY(exists, "MemoryManager has already been destroyed!");
@@ -1381,12 +1450,14 @@ MemoryManager mm;
bool MemoryManager::exists = false;
#ifdef MFEM_USE_UMPIRE
const char* MemoryManager::h_umpire_name = "HOST";
const char* MemoryManager::d_umpire_name = "DEVICE";
int MemoryManager::h_umpire_id = -1;
int MemoryManager::d_umpire_id = -1;
int MemoryManager::d_umpire_temp_id = -1;
#endif
MemoryType MemoryManager::host_mem_type = MemoryType::HOST;
MemoryType MemoryManager::device_mem_type = MemoryType::HOST;
MemoryType MemoryManager::device_temp_mem_type = MemoryType::HOST;
const char *MemoryTypeName[MemoryTypeSize] =
{
@@ -1403,11 +1474,14 @@ const char *MemoryTypeName[MemoryTypeSize] =
#endif
"device-debug",
#if defined(MFEM_USE_CUDA)
"cuda-umpire"
"cuda-umpire",
"cuda-umpire-temp"
#elif defined(MFEM_USE_HIP)
"hip-umpire"
"hip-umpire",
"hip-umpire-temp"
#else
"device-umpire"
"device-umpire",
"device-umpire-temp"
#endif
};
+42 -27
View File
@@ -27,18 +27,19 @@ namespace mfem
/// Memory types supported by MFEM.
enum class MemoryType
{
HOST, ///< Host memory; using new[] and delete[]
HOST_32, ///< Host memory; aligned at 32 bytes
HOST_64, ///< Host memory; aligned at 64 bytes
HOST_DEBUG, ///< Host memory; allocated from a "host-debug" pool
HOST_UMPIRE, ///< Host memory; using Umpire
MANAGED, /**< Managed memory; using CUDA or HIP *MallocManaged
and *Free */
DEVICE, ///< Device memory; using CUDA or HIP *Malloc and *Free
DEVICE_DEBUG, /**< Pseudo-device memory; allocated on host from a
"device-debug" pool */
DEVICE_UMPIRE, ///< Device memory; using Umpire
SIZE ///< Number of host and device memory types
HOST, ///< Host memory; using new[] and delete[]
HOST_32, ///< Host memory; aligned at 32 bytes
HOST_64, ///< Host memory; aligned at 64 bytes
HOST_DEBUG, ///< Host memory; allocated from a "host-debug" pool
HOST_UMPIRE, ///< Host memory; using Umpire
MANAGED, /**< Managed memory; using CUDA or HIP *MallocManaged
and *Free */
DEVICE, ///< Device memory; using CUDA or HIP *Malloc and *Free
DEVICE_DEBUG, /**< Pseudo-device memory; allocated on host from a
"device-debug" pool */
DEVICE_UMPIRE, ///< Device memory; using Umpire
DEVICE_TEMP_UMPIRE, ///< Temporary Device memory; using Umpire
SIZE ///< Number of host and device memory types
};
/// Static casts to 'int' and sizes of some useful memory types.
@@ -61,7 +62,7 @@ enum class MemoryClass
HOST_UMPIRE, MANAGED } */
HOST_32, ///< Memory types: { HOST_32, HOST_64, HOST_DEBUG }
HOST_64, ///< Memory types: { HOST_64, HOST_DEBUG }
DEVICE, ///< Memory types: { DEVICE, DEVICE_DEBUG, DEVICE_UMPIRE, MANAGED }
DEVICE, ///< Memory types: { DEVICE, DEVICE_DEBUG, DEVICE_UMPIRE, DEVICE_TEMP_UMPIRE, MANAGED }
MANAGED ///< Memory types: { MANAGED }
};
@@ -450,16 +451,16 @@ private:
template <std::size_t align_bytes, bool dummy = true> struct Alloc
{
#if __cplusplus < 201703L
static inline T *New(std::size_t)
{
#if __cplusplus < 201703L
// Generate an error in debug mode
MFEM_ASSERT(false, "overaligned type cannot use MemoryType::HOST");
return nullptr;
#else
return new T[size];
#endif
}
#else
static inline T *New(std::size_t size) { return new T[size]; }
#endif
};
#if __cplusplus < 201703L
@@ -471,7 +472,9 @@ private:
};
/// The memory manager class
/** The MFEM memory manager class. Host-side pointers are inserted into this
manager which keeps track of the associated device pointer, and where the
data currently resides. */
class MemoryManager
{
private:
@@ -487,6 +490,9 @@ private:
/// Device memory type set during the Setup.
static MemoryType device_mem_type;
/// Device temporary memory type set during the Setup.
static MemoryType device_temp_mem_type;
/// Allow to detect if a global memory manager instance exists.
static bool exists;
@@ -495,8 +501,9 @@ private:
/// Host and device allocator names for Umpire.
#ifdef MFEM_USE_UMPIRE
static const char *h_umpire_name;
static const char *d_umpire_name;
static int h_umpire_id;
static int d_umpire_id;
static int d_umpire_temp_id;
#endif
private: // Static methods used by the Memory<T> class
@@ -578,7 +585,8 @@ private: // Static methods used by the Memory<T> class
private:
/// Insert a host address in the memory map
/// Insert a host address @a h_ptr and size *a bytes in the memory map to be
/// managed.
void Insert(void *h_ptr, size_t bytes, MemoryType h_mt, MemoryType d_mt);
/// Insert a device and the host addresses in the memory map
@@ -618,15 +626,21 @@ public:
/// Initialize the memory manager.
void Init();
/// Configure the Memory manager with given default host and device types
/// Configure the Memory manager with given default host, device, and device temporary types
/// This method will be called when configuring a device.
void Configure(const MemoryType h_mt, const MemoryType d_mt);
void Configure(const MemoryType h_mt, const MemoryType d_mt,
const MemoryType d_tmt);
#ifdef MFEM_USE_UMPIRE
/// Set the host and device UMpire allocator names
void SetUmpireAllocatorNames(const char *h_name, const char *d_name);
const char *GetUmpireAllocatorHostName() { return h_umpire_name; }
const char *GetUmpireAllocatorDeviceName() { return d_umpire_name; }
/// Set the host and device Umpire allocator ids
static void SetUmpireHostAllocatorId(int h_id) { h_umpire_id = h_id; }
static void SetUmpireDeviceAllocatorId(int d_id) { d_umpire_id = d_id; }
static void SetUmpireDeviceTempAllocatorId(int d_id) { d_umpire_temp_id = d_id; }
/// Get the host and device Umpire allocator ids
static int GetUmpireHostAllocatorId() { return h_umpire_id; }
static int GetUmpireDeviceAllocatorId() { return d_umpire_id; }
static int GetUmpireDeviceTempAllocatorId() { return d_umpire_temp_id; }
#endif
/// Free all the device memories
@@ -651,6 +665,7 @@ public:
static MemoryType GetHostMemoryType() { return host_mem_type; }
static MemoryType GetDeviceMemoryType() { return device_mem_type; }
static MemoryType GetDeviceTempMemoryType() { return device_temp_mem_type; }
};
+34 -4
View File
@@ -68,11 +68,17 @@ private:
static void WriteValue(const Option &opt, std::ostream &out);
public:
/// Construct a command line option parser with '_argc' and '_argv'.
OptionsParser(int _argc, char *_argv[])
: argc(_argc), argv(_argv)
{
error_type = error_idx = 0;
}
/** @brief Add a boolean option and set 'var' to receive the value.
Enable/disable tags are used to set the bool to true/false
respectively. */
void AddOption(bool *var, const char *enable_short_name,
const char *enable_long_name, const char *disable_short_name,
const char *disable_long_name, const char *description,
@@ -83,18 +89,24 @@ public:
options.Append(Option(DISABLE, var, disable_short_name, disable_long_name,
description, required));
}
/// Add an integer option and set 'var' to receive the value.
void AddOption(int *var, const char *short_name, const char *long_name,
const char *description, bool required = false)
{
options.Append(Option(INT, var, short_name, long_name, description,
required));
}
/// Add a double option and set 'var' to receive the value.
void AddOption(double *var, const char *short_name, const char *long_name,
const char *description, bool required = false)
{
options.Append(Option(DOUBLE, var, short_name, long_name, description,
required));
}
/// Add a string (char*) option and set 'var' to receive the value.
void AddOption(const char **var, const char *short_name,
const char *long_name, const char *description,
bool required = false)
@@ -102,6 +114,9 @@ public:
options.Append(Option(STRING, var, short_name, long_name, description,
required));
}
/** Add an integer array (separated by spaces) option and set 'var' to
receive the values. */
void AddOption(Array<int> * var, const char *short_name,
const char *long_name, const char *description,
bool required = false)
@@ -109,6 +124,9 @@ public:
options.Append(Option(ARRAY, var, short_name, long_name, description,
required));
}
/** Add a vector (doubles separated by spaces) option and set 'var' to
receive the values. */
void AddOption(Vector * var, const char *short_name,
const char *long_name, const char *description,
bool required = false)
@@ -117,16 +135,28 @@ public:
required));
}
/** Parse the command-line options. Note that this function expects all the
options provided through the command line to have a corresponding
AddOption. In particular, this function cannot be used for partial
parsing. */
/** @brief Parse the command-line options.
Note that this function expects all the options provided through the
command line to have a corresponding AddOption. In particular, this
function cannot be used for partial parsing. */
void Parse();
/// Return true if the command line options were parsed successfully.
bool Good() const { return (error_type == 0); }
/// Return true if we are flagged to print the help message.
bool Help() const { return (error_type == 1); }
/// Print the options
void PrintOptions(std::ostream &out) const;
/// Print the error message
void PrintError(std::ostream &out) const;
/// Print the help message
void PrintHelp(std::ostream &out) const;
/// Print the usage message
void PrintUsage(std::ostream &out) const;
};
+19 -5
View File
@@ -26,27 +26,32 @@ private:
Array<int> me;
public:
/// Create an empty set.
IntegerSet() { }
/// Create a copy of set 's'.
IntegerSet(IntegerSet &s);
/// Create an integer set from a block of memory containing integer values
/// ( like an array ).
///
/// n - length ( number of integers )
/// p - pointer to block of memory containing the integer values
/// Create an integer set from C-array 'p' of 'n' integers.
IntegerSet(const int n, const int *p) { Recreate(n, p); }
/// Return the size of the set.
int Size() { return me.Size(); }
/// Return a reference to the sorted array of all the set entries.
operator Array<int>& () { return me; }
/// Return the value of the lowest element of the set.
int PickElement() { return me[0]; }
/// Return the value of a random element of the set.
int PickRandomElement();
/// Return 1 if the sets are equal and 0 otherwise.
int operator==(IntegerSet &s);
/** @brief Create an integer set from C-array 'p' of 'n' integers.
Overwrites any existing set data. */
void Recreate(const int n, const int *p);
};
@@ -58,16 +63,25 @@ private:
public:
/// Return the number of integer sets in the list.
int Size() { return TheList.Size(); }
/// Return the value of the first element of the ith set.
int PickElementInSet(int i) { return TheList[i]->PickElement(); }
/// Return a random value from the ith set in the list.
int PickRandomElementInSet(int i) { return TheList[i]->PickRandomElement(); }
/** @brief Check to see if set 's' is in the list. If not append it to the
end of the list. Returns the index of the list where set 's' can be
found. */
int Insert(IntegerSet &s);
/** Return the index of the list where set 's' can be found. Returns -1 if
not found. */
int Lookup(IntegerSet &s);
/// Write the list of sets into table 't'.
void AsTable(Table &t);
~ListOfIntegerSets();
+14 -4
View File
@@ -53,18 +53,25 @@ public:
open(hostname, port);
}
/** Attach a new socket descriptor to the socketbuf.
Returns the old socket descriptor which is NOT closed. */
/** @brief Attach a new socket descriptor to the socketbuf. Returns the old
socket descriptor which is NOT closed. */
virtual int attach(int sd);
/// Detach the current socket descriptor from the socketbuf.
int detach() { return attach(-1); }
/** @brief Open a socket on the 'port' at 'hostname' and store the socket
descriptor. Returns 0 if there is no error, otherwise returns -1. */
virtual int open(const char hostname[], int port);
/// Close the current socket descriptor.
virtual int close();
/// Returns the attached socket descriptor.
int getsocketdescriptor() { return socket_descriptor; }
/** @brief Returns true if the socket is open and has a valid socket
descriptor. Otherwise returns false. */
bool is_open() { return (socket_descriptor >= 0); }
virtual ~socketbuf() { close(); }
@@ -177,8 +184,8 @@ public:
bool gnutls_good() const { return status.good(); }
/** Attach a new socket descriptor to the socketbuf.
Returns the old socket descriptor which is NOT closed. */
/** Attach a new socket descriptor to the socketbuf. Returns the old socket
descriptor which is NOT closed. */
virtual int attach(int sd);
virtual int open(const char hostname[], int port);
@@ -255,10 +262,13 @@ public:
socketbuf *rdbuf() { return buf__; }
/// Open the socket stream on 'port' at 'hostname'.
int open(const char hostname[], int port);
/// Close the socketstream.
int close() { return buf__->close(); }
/// True if the socketstream is open, false otherwise.
bool is_open() { return buf__->is_open(); }
virtual ~socketstream();
+1 -1
View File
@@ -52,7 +52,7 @@ void SortPairs (Pair<A, B> *pairs, int size)
std::sort(pairs, pairs + size);
}
/// A triple of objects
template <class A, class B, class C>
class Triple
{
+20 -1
View File
@@ -25,7 +25,12 @@ public:
int Column, Floor, Number;
};
/// Symmetric 3D Table
/** @brief Symmetric 3D Table stored as an array of rows each of which has a
stack of column, floor, number nodes. The number of the node is assigned by
counting the nodes from zero as they are pushed into the table. Diagonals of
any kind are not allowed so the row, column and floor must all be different
for each node. Only one node is stored for all 6 symmetric entries that are
indexable by unique triplets of row, column, and floor. */
class STable3D
{
private:
@@ -37,20 +42,34 @@ private:
#endif
public:
/// Construct the table with a total of 'nr' rows.
explicit STable3D (int nr);
/** @brief Check to see if this entry is in the table and add it to the table
if it is not there. Returns the number assigned to the table entry. */
int Push (int r, int c, int f);
/// Return the number assigned to the table entry. Abort if it's not there.
int operator() (int r, int c, int f) const;
/** Return the number assigned to the table entry. Return -1 if it's not
there. */
int Index (int r, int c, int f) const;
/** @brief Check to see if this entry is in the table and add it to the table
if it is not there. The entry is addressed by the three smallest values
of (r,c,f,t). Returns the number assigned to the table entry. */
int Push4 (int r, int c, int f, int t);
/** @brief Return the number assigned to the table entry. The entry is
addressed by the three smallest values of (r,c,f,t). Return -1 if it is
not there. */
int operator() (int r, int c, int f, int t) const;
/// Return the number of elements added to the table.
int NumberOfElements() { return NElem; }
/// Print out all of the table elements.
void Print(std::ostream &out = mfem::out) const;
~STable3D ();
-1
View File
@@ -192,7 +192,6 @@ Table * Mult (const Table &A, const Table &B);
/** Data type STable. STable is similar to Table, but it's for symmetric
connectivity, i.e. TYPE I is equivalent to TYPE II. In the first
dimension we put the elements with smaller index. */
class STable : public Table
{
public:
+5 -4
View File
@@ -24,6 +24,7 @@ namespace mfem
// Utilities for text parsing
/// Check if the stream starts with @a comment_char. If so skip it.
inline void skip_comment_lines(std::istream &is, const char comment_char)
{
while (1)
@@ -37,7 +38,7 @@ inline void skip_comment_lines(std::istream &is, const char comment_char)
}
}
// Check for, and remove, a trailing '\r'.
/// Check for, and remove, a trailing '\\r' from and std::string.
inline void filter_dos(std::string &line)
{
if (!line.empty() && *line.rbegin() == '\r')
@@ -46,7 +47,7 @@ inline void filter_dos(std::string &line)
}
}
// Convert an integer to a string
/// Convert an integer to an std::string.
inline std::string to_string(int i)
{
std::stringstream ss;
@@ -58,7 +59,7 @@ inline std::string to_string(int i)
return out_str;
}
// Convert an integer to a 0-padded string with the given number of 'digits'
/// Convert an integer to a 0-padded string with the given number of @a digits
inline std::string to_padded_string(int i, int digits)
{
std::ostringstream oss;
@@ -66,7 +67,7 @@ inline std::string to_padded_string(int i, int digits)
return oss.str();
}
// Convert a string to an int
/// Convert a string to an int
inline int to_int(const std::string& str)
{
int i;
+19 -2
View File
@@ -38,12 +38,29 @@ private:
public:
StopWatch();
/// Clear the elapsed time on the stopwatch and restart it if it's running.
void Clear();
/// Clear the elapsed time and start the stopwatch.
void Start();
/// Stop the stopwatch.
void Stop();
/// Return the time resolution available to the stopwatch.
double Resolution();
/** Return the number of real seconds elapsed since the stopwatch was
started. */
double RealTime();
/** Return the number of user seconds elapsed since the stopwatch was
started. */
double UserTime();
/** Return the number of system seconds elapsed since the stopwatch was
started. */
double SystTime();
~StopWatch();
};
@@ -51,10 +68,10 @@ public:
extern StopWatch tic_toc;
/// Start timing
/// Start the tic_toc timer
extern void tic();
/// End timing
/// End timing and return the time from tic() to toc() in seconds.
extern double toc();
}
+12
View File
@@ -15,13 +15,25 @@
namespace mfem
{
/// Return the MFEM version number as a single integer.
int GetVersion();
/// Return the MFEM major version number as an integer.
int GetVersionMajor();
/// Return the MFEM minor version number as an integer.
int GetVersionMinor();
/// Return the MFEM version patch number as an integer.
int GetVersionPatch();
/// Return the MFEM version number as a string.
const char *GetVersionStr();
/// Return the MFEM Git hash as a string.
const char *GetGitStr();
/// Return the MFEM configuration as a string.
const char *GetConfigStr();
} // namespace mfem
+10 -8
View File
@@ -203,10 +203,10 @@ public:
{
mode |= std::ios_base::in;
exceptions(std::ios_base::badbit);
detail::static_method_holder::check_mode(filename, mode);
// detail::static_method_holder::check_mode(filename, mode);
std::ifstream::open(filename, mode);
detail::static_method_holder::check_open(this, filename, mode);
detail::static_method_holder::check_peek(this, filename, mode);
// detail::static_method_holder::check_open(this, filename, mode);
// detail::static_method_holder::check_peek(this, filename, mode);
}
}; // class ifstream
@@ -225,9 +225,9 @@ public:
{
mode |= std::ios_base::out;
exceptions(std::ios_base::badbit);
detail::static_method_holder::check_mode(filename, mode);
// detail::static_method_holder::check_mode(filename, mode);
std::ofstream::open(filename, mode);
detail::static_method_holder::check_open(this, filename, mode);
// detail::static_method_holder::check_open(this, filename, mode);
}
}; // class ofstream
@@ -246,10 +246,10 @@ public:
{
if (! (mode & std::ios_base::out)) { mode |= std::ios_base::in; }
exceptions(std::ios_base::badbit);
detail::static_method_holder::check_mode(filename, mode);
// detail::static_method_holder::check_mode(filename, mode);
std::fstream::open(filename, mode);
detail::static_method_holder::check_open(this, filename, mode);
detail::static_method_holder::check_peek(this, filename, mode);
// detail::static_method_holder::check_open(this, filename, mode);
// detail::static_method_holder::check_peek(this, filename, mode);
}
}; // class fstream
@@ -754,6 +754,7 @@ public:
{
rdbuf(_fs.rdbuf());
}
setstate(_fs.rdstate());
exceptions(std::ios_base::badbit);
}
@@ -781,6 +782,7 @@ public:
#else
rdbuf(_fs.rdbuf());
#endif
setstate(_fs.rdstate());
exceptions(std::ios_base::badbit);
}
+8
View File
@@ -56,6 +56,10 @@ void BlockOperator::SetDiagonalBlock(int iblock, Operator *op, double c)
void BlockOperator::SetBlock(int iRow, int iCol, Operator *opt, double c)
{
if (owns_blocks && op(iRow, iCol))
{
delete op(iRow, iCol);
}
op(iRow, iCol) = opt;
coef(iRow, iCol) = c;
@@ -148,6 +152,10 @@ void BlockDiagonalPreconditioner::SetDiagonalBlock(int iblock, Operator *opt)
offsets[iblock+1] - offsets[iblock] == opt->Width(),
"incompatible Operator dimensions");
if (owns_blocks && op[iblock])
{
delete op[iblock];
}
op[iblock] = opt;
}
+14
View File
@@ -76,6 +76,9 @@ public:
//! Return a reference to block i,j
Operator & GetBlock(int i, int j)
{ MFEM_VERIFY(op(i,j), ""); return *op(i,j); }
//! Return a reference to block i,j (const version)
const Operator & GetBlock(int i, int j) const
{ MFEM_VERIFY(op(i,j), ""); return *op(i,j); }
//! Return the coefficient for block i,j
double GetBlockCoef(int i, int j) const
{ MFEM_VERIFY(op(i,j), ""); return coef(i,j); }
@@ -85,8 +88,12 @@ public:
//! Return the row offsets for block starts
Array<int> & RowOffsets() { return row_offsets; }
//! Read only access to the row offsets for block starts
const Array<int> & RowOffsets() const { return row_offsets; }
//! Return the columns offsets for block starts
Array<int> & ColOffsets() { return col_offsets; }
//! Read only access to the columns offsets for block starts
const Array<int> & ColOffsets() const { return col_offsets; }
/// Operator application
virtual void Mult (const Vector & x, Vector & y) const;
@@ -153,9 +160,16 @@ public:
Operator & GetDiagonalBlock(int iblock)
{ MFEM_VERIFY(op[iblock], ""); return *op[iblock]; }
//! Return a reference to block i,i (const version).
const Operator & GetDiagonalBlock(int iblock) const
{ MFEM_VERIFY(op[iblock], ""); return *op[iblock]; }
//! Return the offsets for block starts
Array<int> & Offsets() { return offsets; }
//! Read only access to the offsets for block starts
const Array<int> & Offsets() const { return offsets; }
/// Operator application
virtual void Mult (const Vector & x, Vector & y) const;
+3
View File
@@ -72,6 +72,9 @@ public:
*/
BlockVector(double *data, const Array<int> & bOffsets);
//! Return the number of blocks
int NumBlocks() const { return numBlocks; }
//! Assignment operator. this and original must have the same block structure.
BlockVector & operator=(const BlockVector & original);
//! Set each entry of this equal to val
-20
View File
@@ -13,26 +13,6 @@
#include <set>
#include <map>
// Define macro wrappers for hypre_TAlloc, hypre_CTAlloc and hypre_TFree:
// mfem_hypre_TAlloc, mfem_hypre_CTAlloc, and mfem_hypre_TFree, respectively.
// Note: the same macros are defined in hypre.cpp and hypre_parser.cpp.
#if MFEM_HYPRE_VERSION < 21400
#define mfem_hypre_TAlloc(type, size) hypre_TAlloc(type, size)
#define mfem_hypre_CTAlloc(type, size) hypre_CTAlloc(type, size)
#define mfem_hypre_TFree(ptr) hypre_TFree(ptr)
#else // MFEM_HYPRE_VERSION >= 21400
// See the notes about hypre 2.14.0 in hypre.cpp
#define mfem_hypre_TAlloc(type, size) \
hypre_TAlloc(type, size, HYPRE_MEMORY_HOST)
#define mfem_hypre_CTAlloc(type, size) \
hypre_CTAlloc(type, size, HYPRE_MEMORY_HOST)
#define mfem_hypre_TFree(ptr) hypre_TFree(ptr, HYPRE_MEMORY_HOST)
#endif // #if MFEM_HYPRE_VERSION < 21400
namespace mfem
{
+205
View File
@@ -17,6 +17,8 @@
#include "vector.hpp"
#include "matrix.hpp"
#include "densemat.hpp"
#include "kernels.hpp"
#include "../general/forall.hpp"
#include "../general/table.hpp"
#include "../general/globals.hpp"
@@ -3272,6 +3274,15 @@ void DenseMatrixInverse::SetOperator(const Operator &op)
Factor(*p);
}
void DenseMatrixInverse::Mult(const double *x, double *y) const
{
for (int row = 0; row < height; row++)
{
y[row] = x[row];
}
lu.Solve(width, 1, y);
}
void DenseMatrixInverse::Mult(const Vector &x, Vector &y) const
{
y = x;
@@ -3500,4 +3511,198 @@ DenseTensor &DenseTensor::operator=(double c)
return *this;
}
void BatchLUFactor(DenseTensor &Mlu, Array<int> &P, const double TOL)
{
const int m = Mlu.SizeI();
const int NE = Mlu.SizeK();
P.SetSize(m*NE);
auto data_all = mfem::Reshape(Mlu.ReadWrite(), m, m, NE);
auto ipiv_all = mfem::Reshape(P.Write(), m, NE);
Array<bool> pivot_flag(1);
pivot_flag[0] = true;
bool *d_pivot_flag = pivot_flag.ReadWrite();
MFEM_FORALL(e, NE,
{
for (int i = 0; i < m; i++)
{
// pivoting
{
int piv = i;
double a = fabs(data_all(piv,i,e));
for (int j = i+1; j < m; j++)
{
const double b = fabs(data_all(j,i,e));
if (b > a)
{
a = b;
piv = j;
}
}
ipiv_all(i,e) = piv;
if (piv != i)
{
// swap rows i and piv in both L and U parts
for (int j = 0; j < m; j++)
{
mfem::kernels::internal::Swap<double>(data_all(i,j,e), data_all(piv,j,e));
}
}
} // pivot end
if (abs(data_all(i,i,e)) <= TOL)
{
d_pivot_flag[0] = false;
}
const double a_ii_inv = 1.0 / data_all(i,i,e);
for (int j = i+1; j < m; j++)
{
data_all(j,i,e) *= a_ii_inv;
}
for (int k = i+1; k < m; k++)
{
const double a_ik = data_all(i,k,e);
for (int j = i+1; j < m; j++)
{
data_all(j,k,e) -= a_ik * data_all(j,i,e);
}
}
} // m loop
});
MFEM_ASSERT(pivot_flag.HostRead()[0], "Batch LU factorization failed \n");
}
void BatchLUSolve(const DenseTensor &Mlu, const Array<int> &P, Vector &X)
{
const int m = Mlu.SizeI();
const int NE = Mlu.SizeK();
auto data_all = mfem::Reshape(Mlu.Read(), m, m, NE);
auto piv_all = mfem::Reshape(P.Read(), m, NE);
auto x_all = mfem::Reshape(X.ReadWrite(), m, NE);
MFEM_FORALL(e, NE,
{
kernels::LUSolve(&data_all(0, 0,e), m, &piv_all(0, e), &x_all(0,e));
});
}
void BatchLUFactor(Vector &Minv,const int m,const int NE, Array<int> &P)
{
P.SetSize(m*NE);
auto data_all = mfem::Reshape(Minv.ReadWrite(), m, m, NE);
auto piv_all = mfem::Reshape(P.Write(), m, NE);
MFEM_FORALL(e, NE,
{
double *data = &data_all(0,0,e);
int *ipiv = &piv_all(0,e);
for (int i = 0; i < m; i++)
{
// pivoting
{
int piv = i;
double a = fabs(data[piv+i*m]);
for (int j = i+1; j < m; j++)
{
const double b = fabs(data[j+i*m]);
if (b > a)
{
a = b;
piv = j;
}
}
ipiv[i] = piv;
if (piv != i)
{
// swap rows i and piv in both L and U parts
for (int j = 0; j < m; j++)
{
mfem::kernels::internal::Swap<double>(data[i+j*m], data[piv+j*m]);
}
}
}//pivot end
//Q: How to check for errors?
//if (abs(data[i + i*m]) <= TOL)
//{
//return false; // failed
//}
const double a_ii_inv = 1.0 / data[i+i*m];
for (int j = i+1; j < m; j++)
{
data[j+i*m] *= a_ii_inv;
}
for (int k = i+1; k < m; k++)
{
const double a_ik = data[i+k*m];
for (int j = i+1; j < m; j++)
{
data[j+k*m] -= a_ik * data[j+i*m];
}
}
}//m loop
});
}
void BatchLUSolve(Vector &Minv, int m, int NE,
Array<int> &P, Vector &X)
{
auto data_all = mfem::Reshape(Minv.Read(), m, m, NE);
auto piv_all = mfem::Reshape(P.Read(), m, NE);
auto x_all = mfem::Reshape(X.ReadWrite(), m, NE);
MFEM_FORALL(e, NE,
{
const double *data = &data_all(0,0,e);
const int *ipiv = &piv_all(0,e);
double *x = &x_all(0,e);
// X <- P X
for (int i = 0; i < m; i++)
{
mfem::kernels::internal::Swap<double>(x[i], x[ipiv[i]]);
}
// X <- L^{-1} X
for (int j = 0; j < m; j++)
{
const double x_j = x[j];
for (int i = j+1; i < m; i++)
{
x[i] -= data[i+j*m] * x_j;
}
}
// X <- U^{-1} X
for (int j = m-1; j >= 0; j--)
{
const double x_j = ( x[j] /= data[j+j*m] );
for (int i = 0; i < j; i++)
{
x[i] -= data[i+j*m] * x_j;
}
}
});
}
} // namespace mfem
+29
View File
@@ -643,6 +643,9 @@ public:
virtual void SetOperator(const Operator &op);
/// Matrix vector multiplication with the inverse of dense matrix.
void Mult(const double *x, double *y) const;
/// Matrix vector multiplication with the inverse of dense matrix.
virtual void Mult(const Vector &x, Vector &y) const;
@@ -859,6 +862,32 @@ public:
~DenseTensor() { tdata.Delete(); }
};
/** @brief Compute the LU factorization of a batch of matrices
Factorize n matrices of size (m x m) stored in a dense tensor overwriting it
with the LU factors. The factorization is such that L.U = Piv.A, where A is
the original matrix and Piv is a permutation matrix represented by P.
@param [in, out] Mlu batch of square matrices - dimension m x m x n.
@param [out] P array storing pivot information - dimension m x n.
@param [in] TOL optional fuzzy comparison tolerance. Defaults to 0.0. */
void BatchLUFactor(DenseTensor &Mlu, Array<int> &P, const double TOL = 0.0);
/** @brief Solve batch linear systems
Assuming L.U = P.A for n factored matrices (m x m), compute x <- A x, for n
companion vectors.
@param [in] Mlu batch of LU factors for matrix M - dimension m x m x n.
@param [in] P array storing pivot information - dimension m x n.
@param [in, out] X vector storing right-hand side and then solution -
dimension m x n. */
void BatchLUSolve(const DenseTensor &Mlu, const Array<int> &P, Vector &X);
void BatchLUFactor(Vector &Minv,int m,int NE, Array<int> &P);
void BatchLUSolve(Vector &Minv, int m, int NE,
Array<int> &P, Vector &X);
// Inline methods
+1 -1
View File
@@ -2719,7 +2719,7 @@ HypreGMRES::HypreGMRES(MPI_Comm comm) : precond(NULL)
SetDefaultOptions();
}
HypreGMRES::HypreGMRES(HypreParMatrix &_A) : HypreSolver(&_A)
HypreGMRES::HypreGMRES(HypreParMatrix &_A) : HypreSolver(&_A), precond(NULL)
{
MPI_Comm comm;
+2 -1
View File
@@ -593,7 +593,8 @@ protected:
if (dont(HAVE_I3b_p))
{
eval_state |= HAVE_I3b_p;
I3b_p = sign_detJ*scalar_ops::pow(Get_I3b(), -2, 3);
const scalar_t i3b = Get_I3b();
I3b_p = sign_detJ*scalar_ops::pow(i3b, -2, 3);
}
return I3b_p;
}
+39
View File
@@ -1376,6 +1376,45 @@ have_aa:
return sqrt(fabs(aa))*mult; // take abs before we sort?
}
/// Assuming L.U = P.A for a factored matrix (m x m),
// compute x <- A x
//
// @param [in] data LU factorization of A
// @param [in] m square matrix height
// @param [in] ipiv array storing pivot information
// @param [in, out] x vector storing right-hand side and then solution
MFEM_HOST_DEVICE
inline void LUSolve(const double *data, const int m, const int *ipiv,
double *x)
{
// X <- P X
for (int i = 0; i < m; i++)
{
internal::Swap<double>(x[i], x[ipiv[i]]);
}
// X <- L^{-1} X
for (int j = 0; j < m; j++)
{
const double x_j = x[j];
for (int i = j + 1; i < m; i++)
{
x[i] -= data[i + j * m] * x_j;
}
}
// X <- U^{-1} X
for (int j = m - 1; j >= 0; j--)
{
const double x_j = (x[j] /= data[j + j * m]);
for (int i = 0; i < j; i++)
{
x[i] -= data[i + j * m] * x_j;
}
}
}
} // namespace kernels
} // namespace mfem
+1 -1
View File
@@ -28,7 +28,7 @@ class Matrix : public Operator
{
friend class MatrixInverse;
public:
//// Defines matrix diagonal policy upon elimination of rows and/or columns.
/// Defines matrix diagonal policy upon elimination of rows and/or columns.
enum DiagonalPolicy
{
DIAG_ZERO, ///< Set the diagonal value to zero
+3 -3
View File
@@ -492,7 +492,7 @@ protected:
mutable Vector dq_;
};
// First Order Symplectic Integration Algorithm
/// First Order Symplectic Integration Algorithm
class SIA1Solver : public SIASolver
{
public:
@@ -500,7 +500,7 @@ public:
void Step(Vector &q, Vector &p, double &t, double &dt);
};
// Second Order Symplectic Integration Algorithm
/// Second Order Symplectic Integration Algorithm
class SIA2Solver : public SIASolver
{
public:
@@ -508,7 +508,7 @@ public:
void Step(Vector &q, Vector &p, double &t, double &dt);
};
// Variable order Symplectic Integration Algorithm (orders 1-4)
/// Variable order Symplectic Integration Algorithm (orders 1-4)
class SIAVSolver : public SIASolver
{
public:
+162 -31
View File
@@ -28,6 +28,25 @@ namespace mfem
using namespace std;
#ifdef MFEM_USE_CUDA
int SparseMatrix::SparseMatrixCount = 0;
cusparseHandle_t SparseMatrix::handle;
size_t SparseMatrix::bufferSize = 0;
void * SparseMatrix::dBuffer = nullptr;
#endif
void SparseMatrix::InitCuSparse()
{
/* Initialize CuSparse library */
#ifdef MFEM_USE_CUDA
SparseMatrixCount++;
if (SparseMatrixCount == 1 && Device::Allows(Backend::CUDA_MASK))
{
cusparseCreate(&handle);
}
#endif
}
SparseMatrix::SparseMatrix(int nrows, int ncols)
: AbstractSparseMatrix(nrows, (ncols >= 0) ? ncols : nrows),
Rows(new RowNode *[nrows]),
@@ -50,6 +69,8 @@ SparseMatrix::SparseMatrix(int nrows, int ncols)
#ifdef MFEM_USE_MEMALLOC
NodesMem = new RowNodeAlloc;
#endif
InitCuSparse();
}
SparseMatrix::SparseMatrix(int *i, int *j, double *data, int m, int n)
@@ -67,6 +88,8 @@ SparseMatrix::SparseMatrix(int *i, int *j, double *data, int m, int n)
#ifdef MFEM_USE_MEMALLOC
NodesMem = NULL;
#endif
InitCuSparse();
}
SparseMatrix::SparseMatrix(int *i, int *j, double *data, int m, int n,
@@ -98,6 +121,8 @@ SparseMatrix::SparseMatrix(int *i, int *j, double *data, int m, int n,
A[i] = 0.0;
}
}
InitCuSparse();
}
SparseMatrix::SparseMatrix(int nrows, int ncols, int rowsize)
@@ -119,9 +144,11 @@ SparseMatrix::SparseMatrix(int nrows, int ncols, int rowsize)
{
I[i] = i * rowsize;
}
InitCuSparse();
}
SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph)
SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph, MemoryType mt)
: AbstractSparseMatrix(mat.Height(), mat.Width())
{
if (mat.Finalized())
@@ -129,8 +156,8 @@ SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph)
const int nnz = mat.I[height];
if (copy_graph)
{
I.New(height+1, mat.I.GetMemoryType());
J.New(nnz, mat.J.GetMemoryType());
I.New(height+1, mt == MemoryType::SIZE ? mat.I.GetMemoryType() : mt);
J.New(nnz, mt == MemoryType::SIZE ? mat.J.GetMemoryType() : mt);
I.CopyFrom(mat.I, height+1);
J.CopyFrom(mat.J, nnz);
}
@@ -141,7 +168,7 @@ SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph)
I.ClearOwnerFlags();
J.ClearOwnerFlags();
}
A.New(nnz, mat.A.GetMemoryType());
A.New(nnz, mt == MemoryType::SIZE ? mat.A.GetMemoryType() : mt);
A.CopyFrom(mat.A, nnz);
Rows = NULL;
@@ -184,6 +211,8 @@ SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph)
ColPtrNode = NULL;
At = NULL;
isSorted = mat.isSorted;
InitCuSparse();
}
SparseMatrix::SparseMatrix(const Vector &v)
@@ -211,6 +240,8 @@ SparseMatrix::SparseMatrix(const Vector &v)
J[r] = r;
A[r] = v[r];
}
InitCuSparse();
}
SparseMatrix& SparseMatrix::operator=(const SparseMatrix &rhs)
@@ -250,6 +281,16 @@ void SparseMatrix::SetEmpty()
NodesMem = NULL;
#endif
isSorted = false;
#ifdef MFEM_USE_CUDA
if (initBuffers)
{
cusparseDestroySpMat(matA_descr);
cusparseDestroyDnVec(vecX_descr);
cusparseDestroyDnVec(vecY_descr);
initBuffers = false;
}
#endif
}
int SparseMatrix::RowSize(const int i) const
@@ -494,24 +535,29 @@ void SparseMatrix::GetDiag(Vector & d) const
d.SetSize(height);
int j, end;
for (int i = 0; i < height; i++)
{
auto I = this->ReadI();
auto J = this->ReadJ();
auto A = this->ReadData();
auto dd = d.Write();
end = I[i+1];
for (j = I[i]; j < end; j++)
MFEM_FORALL(i, height,
{
const int begin = I[i];
const int end = I[i+1];
int j;
for (j = begin; j < end; j++)
{
if (J[j] == i)
{
d[i] = A[j];
dd[i] = A[j];
break;
}
}
if (j == end)
{
d[i] = 0.;
dd[i] = 0.;
}
}
});
}
/// Produces a DenseMatrix from a SparseMatrix
@@ -587,16 +633,72 @@ void SparseMatrix::AddMult(const Vector &x, Vector &y, const double a) const
auto d_A = Read(A, nnz);
auto d_x = x.Read();
auto d_y = y.ReadWrite();
MFEM_FORALL(i, height,
//Skip if matrix has no non-zeros
if (nnz == 0) {return;}
if (Device::Allows(Backend::CUDA_MASK) && useCuSparse)
{
double d = 0.0;
const int end = d_I[i+1];
for (int j = d_I[i]; j < end; j++)
#ifdef MFEM_USE_CUDA
const double alpha = a;
const double beta = 1.0;
//Setup descriptors
if (!initBuffers)
{
d += d_A[j] * d_x[d_J[j]];
/* Setup matrix descriptor */
cusparseCreateCsr(&matA_descr,Height(), Width(), J.Capacity(),
const_cast<int *>(d_I),
const_cast<int *>(d_J), const_cast<double *>(d_A), CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_BASE_ZERO, CUDA_R_64F);
/*Create handles for input/output vectors */
cusparseCreateDnVec(&vecX_descr, x.Size(), const_cast<double *>(d_x),
CUDA_R_64F);
cusparseCreateDnVec(&vecY_descr, y.Size(), d_y, CUDA_R_64F);
initBuffers = true;
}
d_y[i] += a * d;
});
/*Allocate space for kernel. Buffer is shared between different sparsemats */
size_t newBufferSize = 0;
cusparseSpMV_bufferSize(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha,
matA_descr,
vecX_descr, &beta, vecY_descr, CUDA_R_64F,
CUSPARSE_CSRMV_ALG1, &newBufferSize);
//Check if need to resize
if (newBufferSize > bufferSize)
{
bufferSize = newBufferSize;
if (dBuffer != NULL) { CuMemFree(dBuffer); }
CuMemAlloc(&dBuffer, bufferSize);
}
//Update input/output vectors
cusparseDnVecSetValues(vecX_descr, const_cast<double *>(d_x));
cusparseDnVecSetValues(vecY_descr, d_y);
// Y = alpha A * X + beta * Y
cusparseSpMV(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matA_descr,
vecX_descr, &beta, vecY_descr, CUDA_R_64F, CUSPARSE_CSRMV_ALG1, dBuffer);
#endif
}
else
{
//Native version
MFEM_FORALL(i, height,
{
double d = 0.0;
const int end = d_I[i+1];
for (int j = d_I[i]; j < end; j++)
{
d += d_A[j] * d_x[d_J[j]];
}
d_y[i] += a * d;
});
}
#else
const double *Ap = A, *xp = x.GetData();
double *yp = y.GetData();
@@ -2145,31 +2247,46 @@ void SparseMatrix::DiagScale(const Vector &b, Vector &x, double sc) const
{
MFEM_VERIFY(Finalized(), "Matrix must be finalized.");
const int nnz = J.Capacity();
const bool use_dev = b.UseDevice() || x.UseDevice();
auto bp = b.Read(use_dev);
auto xp = x.Write(use_dev);
auto Ap = Read(A, nnz);
auto Ip = Read(I, height+1);
auto Jp = Read(J, nnz);
bool scale = (sc != 1.0);
for (int i = 0, j = 0; i < height; i++)
MFEM_FORALL(i, height,
{
int end = I[i+1];
for ( ; true; j++)
int end = Ip[i+1];
for (int j = Ip[i]; true; j++)
{
MFEM_VERIFY(j != end, "Couldn't find diagonal in row. i = " << i
<< ", j = " << j
<< ", I[i+1] = " << end );
if (J[j] == i)
if (j == end)
{
MFEM_VERIFY(std::abs(A[j]) > 0.0, "Diagonal " << j << " must be nonzero");
//MFEM_ABORT_KERNEL("Diagonal not found in SparseMatrix::DiagScale");
}
if (Jp[j] == i)
{
if (!(std::abs(Ap[j]) > 0.0))
{
//MFEM_ABORT_KERNEL("Zero diagonal in SparseMatrix::DiagScale");
}
if (scale)
{
x(i) = sc * b(i) / A[j];
xp[i] = sc * bp[i] / Ap[j];
}
else
{
x(i) = b(i) / A[j];
xp[i] = bp[i] / Ap[j];
}
break;
}
}
j = end;
}
});
return;
}
@@ -2749,6 +2866,10 @@ void SparseMatrix::Print(std::ostream & out, int _width) const
return;
}
// HostRead forces synchronization
HostReadI();
HostReadJ();
HostReadData();
for (i = 0; i < height; i++)
{
out << "[row " << i << "]\n";
@@ -2938,6 +3059,16 @@ void SparseMatrix::Destroy()
delete NodesMem;
#endif
delete At;
#ifdef MFEM_USE_CUDA
if (initBuffers)
{
cusparseDestroySpMat(matA_descr);
cusparseDestroyDnVec(vecX_descr);
cusparseDestroyDnVec(vecY_descr);
initBuffers = false;
}
#endif
}
int SparseMatrix::ActualWidth() const
+53 -3
View File
@@ -21,6 +21,12 @@
#include "../general/globals.hpp"
#include "densemat.hpp"
#ifdef MFEM_USE_CUDA
#include <cusparse.h>
#include <library_types.h>
#include "../general/cuda.hpp"
#endif
namespace mfem
{
@@ -80,9 +86,33 @@ protected:
void Destroy(); // Delete all owned data
void SetEmpty(); // Init all entries with empty values
bool useCuSparse{true}; //Use CuSparse if available
// Initialize CuSparse
void InitCuSparse();
#ifdef MFEM_USE_CUDA
cusparseStatus_t status;
static cusparseHandle_t handle;
cusparseMatDescr_t descr=0;
static size_t bufferSize;
static void *dBuffer;
mutable bool initBuffers{false};
static int SparseMatrixCount;
mutable cusparseSpMatDescr_t matA_descr;
mutable cusparseDnVecDescr_t vecX_descr;
mutable cusparseDnVecDescr_t vecY_descr;
#endif
public:
/// Create an empty SparseMatrix.
SparseMatrix() { SetEmpty(); }
SparseMatrix()
{
SetEmpty();
InitCuSparse();
}
/** @brief Create a sparse matrix with flexible sparsity structure using a
row-wise linked list (LIL) format. */
@@ -113,11 +143,14 @@ public:
/** If @a mat is finalized and @a copy_graph is false, the #I and #J arrays
will use a shallow copy (copy the pointers only) without transferring
ownership. */
SparseMatrix(const SparseMatrix &mat, bool copy_graph = true);
SparseMatrix(const SparseMatrix &mat, bool copy_graph = true, MemoryType mt = MemoryType::SIZE);
/// Create a SparseMatrix with diagonal @a v, i.e. A = Diag(v)
SparseMatrix(const Vector & v);
// Runtime option to use CuSparse
// Only valid when using a CUDA backend
void UseCuSparse(bool _useCuSparse = true) { useCuSparse = _useCuSparse;}
/// Assignment operator: deep copy
SparseMatrix& operator=(const SparseMatrix &rhs);
@@ -573,11 +606,28 @@ public:
void Swap(SparseMatrix &other);
/// Destroys sparse matrix.
virtual ~SparseMatrix() { Destroy(); }
virtual ~SparseMatrix()
{
Destroy();
#ifdef MFEM_USE_CUDA
if (handle && SparseMatrixCount==1 && Device::Allows(Backend::CUDA_MASK))
{
cusparseDestroy(handle);
CuMemFree(dBuffer);
}
SparseMatrixCount--;
#endif
}
Type GetType() const { return MFEM_SPARSEMAT; }
};
inline std::ostream& operator<<(std::ostream& os, SparseMatrix const& mat)
{
mat.Print(os);
return os;
}
/// Applies f() to each element of the matrix (after it is finalized).
void SparseMatrixFunction(SparseMatrix &S, double (*f)(double));
+12
View File
@@ -24,6 +24,18 @@
#error "SuperLUDist has been built with 64bit integers. This is not supported"
#endif
#if SUPERLU_DIST_MAJOR_VERSION > 6 || \
(SUPERLU_DIST_MAJOR_VERSION == 6 && SUPERLU_DIST_MINOR_VERSION > 2)
#define ScalePermstruct_t dScalePermstruct_t
#define LUstruct_t dLUstruct_t
#define SOLVEstruct_t dSOLVEstruct_t
#define ScalePermstructFree dScalePermstructFree
#define Destroy_LU dDestroy_LU
#define LUstructFree dLUstructFree
#define LUstructInit dLUstructInit
#endif
using namespace std;
namespace mfem
+30 -3
View File
@@ -281,21 +281,48 @@ public:
/// v = median(v,lo,hi) entrywise. Implementation assumes lo <= hi.
void median(const Vector &lo, const Vector &hi);
/// Extract entries listed in @a dofs to the output Vector @a elemvect.
/** Negative dof values cause the -dof-1 position in @a elemvect to receive
the -val in from this Vector. */
void GetSubVector(const Array<int> &dofs, Vector &elemvect) const;
/// Extract entries listed in @a dofs to the output array @a elem_data.
/** Negative dof values cause the -dof-1 position in @a elem_data to receive
the -val in from this Vector. */
void GetSubVector(const Array<int> &dofs, double *elem_data) const;
/// Set the entries listed in `dofs` to the given `value`.
/// Set the entries listed in @a dofs to the given @a value.
/** Negative dof values cause the -dof-1 position in this Vector to receive
the -value. */
void SetSubVector(const Array<int> &dofs, const double value);
/** @brief Set the entries listed in @a dofs to the values given in the @a
elemvect Vector. Negative dof values cause the -dof-1 position in this
Vector to receive the -val from @a elemvect. */
void SetSubVector(const Array<int> &dofs, const Vector &elemvect);
/** @brief Set the entries listed in @a dofs to the values given the @a ,
elem_data array. Negative dof values cause the -dof-1 position in this
Vector to receive the -val from @a elem_data. */
void SetSubVector(const Array<int> &dofs, double *elem_data);
/// Add (element) subvector to the vector.
/** @brief Add elements of the @a elemvect Vector to the entries listed in @a
dofs. Negative dof values cause the -dof-1 position in this Vector to add
the -val from @a elemvect. */
void AddElementVector(const Array<int> & dofs, const Vector & elemvect);
/** @brief Add elements of the @a elem_data array to the entries listed in @a
dofs. Negative dof values cause the -dof-1 position in this Vector to add
the -val from @a elem_data. */
void AddElementVector(const Array<int> & dofs, double *elem_data);
/** @brief Add @a times the elements of the @a elemvect Vector to the entries
listed in @a dofs. Negative dof values cause the -dof-1 position in this
Vector to add the -a*val from @a elemvect. */
void AddElementVector(const Array<int> & dofs, const double a,
const Vector & elemvect);
/// Set all vector entries NOT in the 'dofs' array to the given 'val'.
/// Set all vector entries NOT in the @a dofs Array to the given @a val.
void SetSubVectorComplement(const Array<int> &dofs, const double val);
/// Prints vector to stream out.
+1 -1
View File
@@ -120,7 +120,7 @@ EXAMPLE_TEST_DIRS := examples
MINIAPP_SUBDIRS = common electromagnetics meshing navier performance tools toys nurbs gslib
MINIAPP_DIRS := $(addprefix miniapps/,$(MINIAPP_SUBDIRS))
MINIAPP_TEST_DIRS := $(filter-out %/common,$(MINIAPP_DIRS))
MINIAPP_USE_COMMON := $(addprefix miniapps/,electromagnetics tools toys)
MINIAPP_USE_COMMON := $(addprefix miniapps/,electromagnetics meshing tools toys)
EM_DIRS = $(EXAMPLE_DIRS) $(MINIAPP_DIRS)
+91 -22
View File
@@ -911,20 +911,27 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo,
// NC meshes: prepend slave edge/face transformation to Loc2
if (Nonconforming() && IsSlaveFace(face_info))
{
ApplyLocalSlaveTransformation(FaceElemTr.Loc2.Transf, face_info);
if (face_type == Element::SEGMENT)
{
// flip Loc2 to match Loc1 and Face
DenseMatrix &pm = FaceElemTr.Loc2.Transf.GetPointMat();
std::swap(pm(0,0), pm(0,1));
std::swap(pm(1,0), pm(1,1));
}
ApplyLocalSlaveTransformation(FaceElemTr, face_info, false);
}
}
FaceElemTr.SetConfigurationMask(mask);
// This check can be useful for internal debugging, however it will fail on
// periodic boundary faces, so we keep it disabled in general.
#if 0
#ifdef MFEM_DEBUG
double dist = FaceElemTr.CheckConsistency();
if (dist >= 1e-12)
{
mfem::out << "\nInternal error: face id = " << FaceNo
<< ", dist = " << dist << '\n';
FaceElemTr.CheckConsistency(1); // print coordinates
MFEM_ABORT("internal error");
}
#endif
#endif
return &FaceElemTr;
}
@@ -933,8 +940,8 @@ bool Mesh::IsSlaveFace(const FaceInfo &fi) const
return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave;
}
void Mesh::ApplyLocalSlaveTransformation(IsoparametricTransformation &transf,
const FaceInfo &fi)
void Mesh::ApplyLocalSlaveTransformation(FaceElementTransformations &FT,
const FaceInfo &fi, bool is_ghost)
{
#ifdef MFEM_THREAD_SAFE
DenseMatrix composition;
@@ -942,8 +949,34 @@ void Mesh::ApplyLocalSlaveTransformation(IsoparametricTransformation &transf,
static DenseMatrix composition;
#endif
MFEM_ASSERT(fi.NCFace >= 0, "");
transf.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
transf.SetPointMat(composition);
MFEM_ASSERT(nc_faces_info[fi.NCFace].Slave, "internal error");
if (!is_ghost)
{
// side 1 -> child side, side 2 -> parent side
IsoparametricTransformation &LT = FT.Loc2.Transf;
LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
// In 2D, we need to flip the point matrix since it is aligned with the
// parent side.
if (Dim == 2)
{
// swap points (columns) 0 and 1
std::swap(composition(0,0), composition(0,1));
std::swap(composition(1,0), composition(1,1));
}
LT.SetPointMat(composition);
}
else // is_ghost == true
{
// side 1 -> parent side, side 2 -> child side
IsoparametricTransformation &LT = FT.Loc1.Transf;
LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
// In 2D, there is no need to flip the point matrix since it is already
// aligned with the parent side, see also ParNCMesh::GetFaceNeighbors.
// In 3D the point matrix was flipped during construction in
// ParNCMesh::GetFaceNeighbors and due to that it is already aligned with
// the parent side.
LT.SetPointMat(composition);
}
}
FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo)
@@ -988,7 +1021,21 @@ void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) const
Geometry::Type Mesh::GetFaceGeometryType(int Face) const
{
return (Dim == 1) ? Geometry::POINT : faces[Face]->GetGeometryType();
switch (Dim)
{
case 1: return Geometry::POINT;
case 2: return Geometry::SEGMENT;
case 3:
if (Face < NumOfFaces) // local (non-ghost) face
{
return faces[Face]->GetGeometryType();
}
// ghost face
const int nc_face_id = faces_info[Face].NCFace;
MFEM_ASSERT(nc_face_id >= 0, "parent ghost faces are not supported");
return faces[nc_faces_info[nc_face_id].MasterFace]->GetGeometryType();
}
return Geometry::INVALID;
}
Element::Type Mesh::GetFaceElementType(int Face) const
@@ -3286,7 +3333,7 @@ void Mesh::Loader(std::istream &input, int generate_edges,
}
else if (mesh_type == "$MeshFormat") // Gmsh
{
ReadGmshMesh(input);
ReadGmshMesh(input, curved, read_gf);
}
else if
((mesh_type.size() > 2 &&
@@ -5261,7 +5308,10 @@ void Mesh::GenerateNCFaceInfo()
slave_fi.Elem2No = master_fi.Elem1No;
slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above
// NOTE: orientation part of Elem2Inf is encoded in the point matrix
// NOTE: In 3D, the orientation part of Elem2Inf is encoded in the point
// matrix. In 2D, the point matrix has the orientation of the parent
// edge, so its columns need to be flipped when applying it, see
// ApplyLocalSlaveTransformation.
}
}
@@ -5768,6 +5818,7 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method)
// Check for empty partitionings (a "feature" in METIS)
{
Array< Pair<int,int> > psize(nparts);
int empty_parts;
for (i = 0; i < nparts; i++)
{
psize[i].one = 0;
@@ -5779,7 +5830,7 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method)
psize[partitioning[i]].one++;
}
int empty_parts = 0;
empty_parts = 0;
for (i = 0; i < nparts; i++)
{
if (psize[i].one == 0) { empty_parts++; }
@@ -5787,7 +5838,7 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method)
// This code just split the largest partitionings in two.
// Do we need to replace it with something better?
if (empty_parts)
while (empty_parts)
{
if (print_messages)
{
@@ -5818,6 +5869,24 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method)
}
}
}
// Check for empty partitionings again
for (i = 0; i < nparts; i++)
{
psize[i].one = 0;
}
for (i = 0; i < NumOfElements; i++)
{
psize[partitioning[i]].one++;
}
empty_parts = 0;
for (i = 0; i < nparts; i++)
{
if (psize[i].one == 0) { empty_parts++; }
}
}
}
@@ -10455,17 +10524,17 @@ GeometricFactors::GeometricFactors(const Mesh *mesh, const IntegrationRule &ir,
unsigned eval_flags = 0;
if (flags & GeometricFactors::COORDINATES)
{
X.SetSize(vdim*NQ*NE);
X.SetSize(vdim*NQ*NE, Device::GetDeviceTempMemoryType());
eval_flags |= QuadratureInterpolator::VALUES;
}
if (flags & GeometricFactors::JACOBIANS)
{
J.SetSize(dim*vdim*NQ*NE);
J.SetSize(dim*vdim*NQ*NE, Device::GetDeviceTempMemoryType());
eval_flags |= QuadratureInterpolator::DERIVATIVES;
}
if (flags & GeometricFactors::DETERMINANTS)
{
detJ.SetSize(NQ*NE);
detJ.SetSize(NQ*NE, Device::GetDeviceTempMemoryType());
eval_flags |= QuadratureInterpolator::DETERMINANTS;
}
@@ -10475,7 +10544,7 @@ GeometricFactors::GeometricFactors(const Mesh *mesh, const IntegrationRule &ir,
qi->SetOutputLayout(QVectorLayout::byNODES);
if (elem_restr)
{
Vector Enodes(vdim*ND*NE);
Vector Enodes(vdim*ND*NE, Device::GetDeviceTempMemoryType());
elem_restr->Mult(*nodes, Enodes);
qi->Mult(Enodes, eval_flags, X, J, detJ);
}
+9 -3
View File
@@ -131,11 +131,16 @@ protected:
// face. Elem2No is < 0 and -1-Elem2No is the index of the ghost
// face-neighbor element that generated this slave ghost face. In this
// case, Elem2Inf >= 0.
// Relevant methods: GenerateFaces(), GenerateNCFaceInfo(),
// ParNCMesh::GetFaceNeighbors(),
// ParMesh::ExchangeFaceNbrData()
struct NCFaceInfo
{
bool Slave; // true if this is a slave face, false if master face
int MasterFace; // if Slave, this is the index of the master face
// If not Slave, 'MasterFace' is the local face index of this master face
// as a face in the unique adjacent element.
const DenseMatrix* PointMatrix; // if Slave, position within master face
// (NOTE: PointMatrix points to a matrix owned by NCMesh.)
@@ -235,7 +240,7 @@ protected:
bool &finalize_topo);
void ReadNURBSMesh(std::istream &input, int &curved, int &read_gf);
void ReadInlineMesh(std::istream &input, bool generate_edges = false);
void ReadGmshMesh(std::istream &input);
void ReadGmshMesh(std::istream &input, int &curved, int &read_gf);
/* Note NetCDF (optional library) is used for reading cubit files */
#ifdef MFEM_USE_NETCDF
void ReadCubit(const char *filename, int &curved, int &read_gf);
@@ -363,8 +368,9 @@ protected:
/** Used in GetFaceElementTransformations to account for the fact that a
slave face occupies only a portion of its master face. */
void ApplyLocalSlaveTransformation(IsoparametricTransformation &transf,
const FaceInfo &fi);
void ApplyLocalSlaveTransformation(FaceElementTransformations &FT,
const FaceInfo &fi, bool is_ghost);
bool IsSlaveFace(const FaceInfo &fi) const;
/// Returns the orientation of "test" relative to "base"
+81 -2
View File
@@ -887,7 +887,7 @@ void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges)
}
}
void Mesh::ReadGmshMesh(std::istream &input)
void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
{
string buff;
double version;
@@ -1110,8 +1110,14 @@ void Mesh::ReadGmshMesh(std::istream &input)
}
case 4: // 4-node tetrahedron
{
#ifdef MFEM_USE_MEMALLOC
elements_3D.push_back(TetMemory.Alloc());
elements_3D.back()->SetVertices(&vert_indices[0]);
elements_3D.back()->SetAttribute(phys_domain);
#else
elements_3D.push_back(
new Tetrahedron(&vert_indices[0], phys_domain));
#endif
break;
}
case 5: // 8-node hexahedron
@@ -1195,8 +1201,14 @@ void Mesh::ReadGmshMesh(std::istream &input)
}
case 4: // 4-node tetrahedron
{
#ifdef MFEM_USE_MEMALLOC
elements_3D.push_back(TetMemory.Alloc());
elements_3D.back()->SetVertices(&vert_indices[0]);
elements_3D.back()->SetAttribute(phys_domain);
#else
elements_3D.push_back(
new Tetrahedron(&vert_indices[0], phys_domain));
#endif
break;
}
case 5: // 8-node hexahedron
@@ -1291,6 +1303,66 @@ void Mesh::ReadGmshMesh(std::istream &input)
MFEM_CONTRACT_VAR(elem_domain);
} // section '$Elements'
else if (buff == "$Periodic") // Reading master/slave node pairs
{
curved = 1;
read_gf = 0;
spaceDim = 3;
Array<int> v2v(NumOfVertices);
for (int i = 0; i < v2v.Size(); i++)
{
v2v[i] = i;
}
int num_per_ent;
int num_nodes;
int slave, master;
input >> num_per_ent;
getline(input, buff); // Read end-of-line
for (int i = 0; i < num_per_ent; i++)
{
getline(input, buff); // Read and ignore entity dimension and tags
getline(input, buff); // Read and ignore affine mapping
// Read master/slave vertex pairs
input >> num_nodes;
for (int j=0; j<num_nodes; j++)
{
input >> slave >> master;
v2v[slave - 1] = master - 1;
}
getline(input, buff); // Read end-of-line
}
// Convert nodes to discontinuous GridFunction
this->SetCurvature(1, true, Dim, Ordering::byVDIM);
// Replace "slave" vertex indices in the element connectivity
// with their corresponding "master" vertex indices.
for (int i = 0; i < this->GetNE(); i++)
{
Element *el = this->GetElement(i);
int *v = el->GetVertices();
int nv = el->GetNVertices();
for (int j = 0; j < nv; j++)
{
v[j] = v2v[v[j]];
}
}
// Replace "slave" vertex indices in the boundary element connectivity
// with their corresponding "master" vertex indices.
for (int i = 0; i < this->GetNBE(); i++)
{
Element *el = this->GetBdrElement(i);
int *v = el->GetVertices();
int nv = el->GetNVertices();
for (int j = 0; j < nv; j++)
{
v[j] = v2v[v[j]];
}
}
this->RemoveUnusedVertices();
this->RemoveInternalBoundaries();
}
} // we reach the end of the file
}
@@ -1878,7 +1950,14 @@ void Mesh::ReadCubit(const char *filename, int &curved, int &read_gf)
case (ELEMENT_TET4):
case (ELEMENT_TET10):
{
elements[elcount] = new Tetrahedron(renumberedVertID,ebprop[iblk]);
#ifdef MFEM_USE_MEMALLOC
elements[elcount] = TetMemory.Alloc();
elements[elcount]->SetVertices(renumberedVertID);
elements[elcount]->SetAttribute(ebprop[iblk]);
#else
elements[elcount] = new Tetrahedron(renumberedVertID,
ebprop[iblk]);
#endif
break;
}
case (ELEMENT_HEX8):
+72 -23
View File
@@ -34,6 +34,8 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes)
group_sedge(pmesh.group_sedge),
group_stria(pmesh.group_stria),
group_squad(pmesh.group_squad),
glob_elem_offset(-1),
glob_offset_sequence(-1),
gtopo(pmesh.gtopo)
{
MyComm = pmesh.MyComm;
@@ -92,7 +94,9 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes)
ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
int part_method)
: gtopo(comm)
: glob_elem_offset(-1)
, glob_offset_sequence(-1)
, gtopo(comm)
{
int *partitioning = NULL;
Array<bool> activeBdrElem;
@@ -833,6 +837,8 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh)
: MyComm(pncmesh.MyComm)
, NRanks(pncmesh.NRanks)
, MyRank(pncmesh.MyRank)
, glob_elem_offset(-1)
, glob_offset_sequence(-1)
, gtopo(MyComm)
, pncmesh(NULL)
{
@@ -841,6 +847,18 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh)
have_face_nbr_data = false;
}
void ParMesh::ComputeGlobalElementOffset() const
{
if (glob_offset_sequence != sequence) // mesh has changed
{
long local_elems = NumOfElements;
MPI_Scan(&local_elems, &glob_elem_offset, 1, MPI_LONG, MPI_SUM, MyComm);
glob_elem_offset -= local_elems;
glob_offset_sequence = sequence; // don't recalculate until refinement etc.
}
}
void ParMesh::ReduceMeshGen()
{
int loc_meshgen = meshgen;
@@ -885,7 +903,9 @@ void ParMesh::FinalizeParTopo()
}
ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine)
: gtopo(comm)
: glob_elem_offset(-1)
, glob_offset_sequence(-1)
, gtopo(comm)
{
MyComm = comm;
MPI_Comm_size(MyComm, &NRanks);
@@ -1062,6 +1082,8 @@ ParMesh::ParMesh(ParMesh *orig_mesh, int ref_factor, int ref_type)
MyComm(orig_mesh->GetComm()),
NRanks(orig_mesh->GetNRanks()),
MyRank(orig_mesh->GetMyRank()),
glob_elem_offset(-1),
glob_offset_sequence(-1),
gtopo(orig_mesh->gtopo),
have_face_nbr_data(false),
pncmesh(NULL)
@@ -1299,6 +1321,20 @@ void ParMesh::Finalize(bool refine, bool fix_orientation)
FinalizeParTopo();
}
int ParMesh::GetLocalElementNum(long global_element_num) const
{
ComputeGlobalElementOffset();
long local = global_element_num - glob_elem_offset;
if (local < 0 || local >= NumOfElements) { return -1; }
return local;
}
long ParMesh::GetGlobalElementNum(int local_element_num) const
{
ComputeGlobalElementOffset();
return glob_elem_offset + local_element_num;
}
void ParMesh::DistributeAttributes(Array<int> &attr)
{
// Determine the largest attribute number across all processors
@@ -2327,16 +2363,16 @@ Table *ParMesh::GetFaceToAllElementTable() const
return face_elem;
}
ElementTransformation* ParMesh::GetGhostFaceTransformation(
void ParMesh::GetGhostFaceTransformation(
FaceElementTransformations* FETr, Element::Type face_type,
Geometry::Type face_geom)
{
// calculate composition of FETr->Loc1 and FETr->Elem1
DenseMatrix &face_pm = FaceTransformation.GetPointMat();
DenseMatrix &face_pm = FETr->GetPointMat();
if (Nodes == NULL)
{
FETr->Elem1->Transform(FETr->Loc1.Transf.GetPointMat(), face_pm);
FaceTransformation.SetFE(GetTransformationFEforElementType(face_type));
FETr->SetFE(GetTransformationFEforElementType(face_type));
}
else
{
@@ -2352,15 +2388,23 @@ ElementTransformation* ParMesh::GetGhostFaceTransformation(
FETr->Loc1.Transform(face_el->GetNodes(), eir);
Nodes->GetVectorValues(*FETr->Elem1, eir, face_pm);
#endif
FaceTransformation.SetFE(face_el);
FETr->SetFE(face_el);
}
return &FaceTransformation;
}
FaceElementTransformations *ParMesh::
GetSharedFaceTransformations(int sf, bool fill2)
GetSharedFaceTransformations(int sf, bool fill2, bool direct)
{
int FaceNo = GetSharedFace(sf);
//int FaceNo = GetSharedFace(sf);
int FaceNo;
if (direct)
{
FaceNo = sf;
}
else
{
FaceNo = GetSharedFace(sf);
}
FaceInfo &face_info = faces_info[FaceNo];
@@ -2417,22 +2461,10 @@ GetSharedFaceTransformations(int sf, bool fill2)
// adjust Loc1 or Loc2 of the master face if this is a slave face
if (is_slave)
{
// is a ghost slave? -> master not a ghost -> choose Elem1 local transf
// not a ghost slave? -> master is a ghost -> choose Elem2 local transf
IsoparametricTransformation &loctr =
is_ghost ? FaceElemTr.Loc1.Transf : FaceElemTr.Loc2.Transf;
if (is_ghost || fill2)
{
ApplyLocalSlaveTransformation(loctr, face_info);
}
if (face_type == Element::SEGMENT && fill2)
{
// fix slave orientation in 2D: flip Loc2 to match Loc1 and Face
DenseMatrix &pm = FaceElemTr.Loc2.Transf.GetPointMat();
std::swap(pm(0,0), pm(0,1));
std::swap(pm(1,0), pm(1,1));
// is_ghost -> modify side 1, otherwise -> modify side 2:
ApplyLocalSlaveTransformation(FaceElemTr, face_info, is_ghost);
}
}
@@ -2442,6 +2474,23 @@ GetSharedFaceTransformations(int sf, bool fill2)
GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom);
}
FaceElemTr.SetConfigurationMask(fill2 ? 31 : 21);
// This check can be useful for internal debugging, however it will fail on
// periodic boundary faces, so we keep it disabled in general.
#if 0
#ifdef MFEM_DEBUG
double dist = FaceElemTr.CheckConsistency();
if (dist >= 1e-12)
{
mfem::out << "\nInternal error: face id = " << FaceNo
<< ", dist = " << dist << ", rank = " << MyRank << '\n';
FaceElemTr.CheckConsistency(1); // print coordinates
MFEM_ABORT("internal error");
}
#endif
#endif
return &FaceElemTr;
}
+14 -3
View File
@@ -78,6 +78,10 @@ protected:
// sface ids: all triangles first, then all quads
Array<int> sface_lface;
// glob_elem_offset + local element number defines a global element numbering
mutable long glob_elem_offset, glob_offset_sequence;
void ComputeGlobalElementOffset() const;
/// Create from a nonconforming mesh.
ParMesh(const ParNCMesh &pncmesh);
@@ -103,7 +107,7 @@ protected:
void GetFaceNbrElementTransformation(
int i, IsoparametricTransformation *ElTr);
ElementTransformation* GetGhostFaceTransformation(
void GetGhostFaceTransformation(
FaceElementTransformations* FETr, Element::Type face_type,
Geometry::Type face_geom);
@@ -231,6 +235,13 @@ public:
int GetNRanks() const { return NRanks; }
int GetMyRank() const { return MyRank; }
/** Map a global element number to a local element number. If the global
element is not on this processor, return -1. */
int GetLocalElementNum(long global_element_num) const;
/// Map a local element number to a global element number.
long GetGlobalElementNum(int local_element_num) const;
GroupTopology gtopo;
// Face-neighbor elements and vertices
@@ -280,9 +291,9 @@ public:
/** Get the FaceElementTransformations for the given shared face (edge 2D).
In the returned object, 1 and 2 refer to the local and the neighbor
elements, respectively. */
elements, respectively. Use direct if sf is the face number */
FaceElementTransformations *
GetSharedFaceTransformations(int sf, bool fill2 = true);
GetSharedFaceTransformations(int sf, bool fill2 = true, bool direct = false);
/// Return the number of shared faces (3D), edges (2D), vertices (1D)
int GetNSharedFaces() const;
+10
View File
@@ -1263,6 +1263,8 @@ void ParNCMesh::GetFaceNeighbors(ParMesh &pmesh)
const DenseMatrix* pm = &sf.point_matrix;
if (!sloc && Dim == 3)
{
// TODO: does this handle triangle faces correctly?
// ghost slave in 3D needs flipping orientation
DenseMatrix* pm2 = new DenseMatrix(*pm);
std::swap((*pm2)(0,1), (*pm2)(0,3));
@@ -1282,6 +1284,14 @@ void ParNCMesh::GetFaceNeighbors(ParMesh &pmesh)
// processor, but on the other it is the element containing the
// master face. In the latter case we need to flip the pm.
}
else if (!sloc && Dim == 2)
{
fi.Elem2Inf ^= 1; // set orientation to 1
// The point matrix (used to define "side 1" which is the same as
// "parent side" in this case) does not require a flip since it
// is aligned with the parent side, so NO flip is performed in
// Mesh::ApplyLocalSlaveTransformation.
}
MFEM_ASSERT(fi.NCFace < 0, "");
fi.NCFace = pmesh.nc_faces_info.Size();

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