Compare commits

...
Author SHA1 Message Date
Dylan Copeland 432df01647 Adding cusparse ILU and incomplete Cholesky solvers on GPU. 2020-08-20 18:55:01 -07:00
Tzanio Kolev b3beafe905 Merge pull request #1638 from mfem/tmop-el-type
Mixed meshes in TMOP
2020-08-20 06:24:33 -07:00
Tzanio Kolev 9c936e24bb Merge pull request #1474 from mfem/h1-hessian-dev
Add CalcHessian for H1-conforming tensor finite elements [h1-hessian-dev]
2020-08-20 06:23:43 -07:00
Tzanio Kolev 3005dee1af Merge pull request #1622 from mfem/feature/stitt4/more-work-units
Expose more parallelism in some kernels [feature/stitt4/more-work-units]
2020-08-19 14:40:13 -07:00
Tzanio Kolev 7ef5575ab4 Merge pull request #1694 from mfem/boundary-integ-fix
Assert that added bilinear form integrators are supported by PA/EA
2020-08-19 14:38:48 -07:00
camierjs 3f2c2acf23 Merge master in feature/stitt4/more-work-units 2020-08-19 08:12:42 -07:00
Tzanio Kolev 04b5626fd4 Merge pull request #1571 from mfem/ho-gmsh-dev
Adding high order Gmsh support [ho-gmsh-dev]
2020-08-18 17:33:40 -07:00
Veselin Dobrev 8162d3047e Merge pull request #1641 from mfem/eval-state-dev
Reset ElementTransformation::EvalState in new situations [eval-state-dev]
2020-08-18 17:23:03 -07:00
Tzanio Kolev 00550ef4f7 Merge pull request #1489 from mfem/feature/artv3/cusparse-Spmv
SpMV with CuSPARSE
2020-08-16 15:16:10 -07:00
Tzanio a16b216c91 Final editorial changes 2020-08-16 15:14:03 -07:00
Tzanio 4b0d543114 Merge branch 'master' into ho-gmsh-dev
Conflicts:
	CHANGELOG
2020-08-16 14:50:28 -07:00
Tzanio 940ec885ef Clarify that 'l' in Mesh Explorer can be used for any function 2020-08-16 14:48:33 -07:00
camierjs a72fa476c5 Merge master in feature/stitt4/more-work-units 2020-08-14 11:23:42 -07:00
Tzanio Kolev 3a06bc39df Merge pull request #1618 from mfem/abs-mult-dev
AbsMult and AbsMultTranspose
2020-08-14 10:48:53 -07:00
Tzanio a3e9ac8e8d minor 2020-08-14 10:48:17 -07:00
stefanhenneking 353fd60e42 Adding comment to explain usage of AbsMult. 2020-08-14 11:40:09 -05:00
camierjs da8624fd45 Merge branch 'master' into feature/stitt4/more-work-units 2020-08-14 08:28:52 -07:00
Tzanio Kolev 064eeb6591 Merge pull request #1620 from mfem/matcoefpa
Matrix coefficient support for H(curl) PA.
2020-08-13 18:39:42 -07:00
Tzanio Kolev 690807d631 Merge pull request #1633 from mfem/residual-bc-monitor
Add residual monitor for checking for correct handling of essential boundary conditions
2020-08-13 18:35:31 -07:00
camierjs 69bfdbe248 Merge branch 'master' into feature/stitt4/more-work-units 2020-08-13 14:54:59 -07:00
Tzanio Kolev df22d9da86 Merge pull request #1674 from mfem/branch-history-update
Update the script branch-history [branch-history-update]
2020-08-13 12:24:20 -07:00
Tzanio Kolev 40045b01e2 Merge pull request #1660 from mfem/yohann/fix-diff3D-EA
Fix a bug in Diffusion Element Assembly in 3D.
2020-08-13 12:23:28 -07:00
Tzanio Kolev 91fc72b021 Merge pull request #1686 from mfem/jeremy/libceed-version
Update libCEED install git hash
2020-08-13 12:21:19 -07:00
Stowell, Mark L 66be99b4f5 Adding an assert to SetFE 2020-08-10 17:00:29 -07:00
Stowell, Mark L 8b69106bef Adding a constructor to IsoparametricTransformation so that its internal data can be initialized 2020-08-10 16:53:51 -07:00
Veselin Dobrev bfdfec0a2c Minor formatting edits. 2020-08-07 16:58:35 -07:00
stefanhenneking 6edd9b07ad Using MFEM_VERIFY instead of MFEM_ASSERT. 2020-08-07 11:50:32 -05:00
Veselin DobrevandAndrew T. Barker d767b6f541 Update linalg/solvers.cpp
Applying change suggested on github.

Co-authored-by: Andrew T. Barker <barker29@llnl.gov>
2020-08-07 03:28:56 -07:00
stefanhenneking 6ab34c27c1 Minor 2020-08-07 00:59:20 -05:00
stefanhenneking d565ad7d84 Adding additional assertions for MixedBilinearForm. 2020-08-06 16:47:08 -05:00
stefanhenneking 32df373a82 Adding assertions inform the user about missing support for BoundaryIntegrator. 2020-08-06 16:37:36 -05:00
jeremylt 0d1f3028f4 Update libCEED install git hash 2020-08-05 08:47:08 -06:00
camierjs 7afce5a62c Use inner threads for mass and diffusion setup 2020-08-04 14:19:43 -07:00
camierjs 1e6cd92ad7 Merge branch 'master' into feature/stitt4/more-work-units 2020-08-04 11:57:58 -07:00
Yohann Dudouit efa35e4a79 Modify test_pa_kernels.cpp to run all tests. 2020-08-03 17:53:14 -07:00
Yohann Dudouit 5feb9c21db Add Diffusion test for DG. 2020-08-03 15:56:52 -07:00
Yohann Dudouit 9b049b134a make style 2020-08-03 15:32:57 -07:00
Yohann Dudouit 28a4a8cc24 Remove unnecessary SetCurvature. 2020-08-03 14:26:19 -07:00
Yohann Dudouit bbcadbcc3b Fix testing of assembly levels.
- WARNING: catch SECTION inside for loops result in only the first iteration of the loop being executed.
2020-08-03 14:21:38 -07:00
Stowell, Mark L dc64a38a86 Reworked the torus-sector mesh using a butterfly configuration 2020-08-03 11:09:58 -07:00
Veselin Dobrev 088db70ad2 Fix doxygen warning. 2020-08-02 16:59:20 -07:00
Veselin Dobrev 2162829989 Fix reporting of warnings by './runtest documentation'. 2020-08-02 15:33:37 -07:00
Veselin Dobrev 4c1a849631 Small addition to the 'mesh-explorer' miniapp to support viewing
(the projection of) an analytic 'level_function' defined in the
source file. In particular, this allows us to view how much a mesh
boundary deviates from any level set of the 'level_function'.
2020-08-02 13:10:34 -07:00
Veselin Dobrev 898a33125c In 'branch-history', handle a couple of less common mode strings
when parsing merge commits. Also, when the checks for a branch fail,
print the name of the failed branch.
2020-08-01 14:38:01 -07:00
Veselin Dobrev a058e2ce63 Update the script 'branch-history':
* Allow setting the branch on the command line. This allows for
  testing branches that do not have the script or its latest version
  merged-in, or simply testing branches without checkout.
* When inspecting the branch commits, also consider merge- and root-
  commits -- these can also introduce new or modify existing files.
2020-07-31 22:34:16 -07:00
Ketan Mittal a73a473055 fix for Tpr->ElementType due to another PR 2020-07-31 12:01:54 -07:00
Veselin Dobrev 50d720c4d7 Tweak the CUDA support in the CMake build system, including
support for cuSPARSE and more CMake versions.
2020-07-29 21:42:11 -07:00
Tzanio 2ecf10cfe5 minor 2020-07-29 19:40:51 -07:00
Stowell, Mark L a1b3fedde3 Switching to finer torus mesh 2020-07-29 19:30:26 -07:00
Tzanio 747e871e80 Smaller periodic-torus-sector.msh with mesh optimization 2020-07-29 17:25:51 -07:00
Ketan Mittal 9d83a0d23c minor 2020-07-29 15:59:36 -07:00
Stowell, Mark L 04904936f7 Swapping a larger example mesh to avoid badly shaped hexahedra. 2020-07-29 13:38:30 -07:00
stefanhenneking 0db7b843f5 Using std::abs 2020-07-29 15:23:11 -05:00
Veselin Dobrev 06ec0d019f Merge branch 'master' into feature/artv3/cusparse-Spmv
Resolved conflicts:
   CHANGELOG
2020-07-29 12:55:06 -07:00
Stowell, Mark L 2e2d42a8a9 Cleanup compiler warnings 2020-07-29 10:45:08 -07:00
Tomov 0080f2898d Changelog. 2020-07-28 16:09:36 -07:00
Tzanio fd0d5927f6 Final updates 2020-07-28 14:30:42 -07:00
Stowell, Mark L a30eb78a6b Calculating spaceDim by inspecting the bounding box of the mesh 2020-07-28 13:37:10 -07:00
Ketan Mittal 167cda84c9 minor 2020-07-28 09:00:58 -07:00
Yohann Dudouit 5a3f58bdf7 Fix a bug in Diffusion EA 3D. 2020-07-27 16:57:27 -07:00
Dylan Copeland 2d464874e1 Merge branch 'master' of https://github.com/mfem/mfem into matcoefpa 2020-07-27 14:39:40 -07:00
Tzanio e938ec6d95 Small updates to *.geo files 2020-07-27 11:25:06 -07:00
Dylan Copeland 9258085c3d Further improving readability. 2020-07-27 11:18:19 -07:00
stefanhenneking db1d1f3aa5 Minor change in comment. 2020-07-27 12:21:16 -05:00
Tzanio d4b06b41cc Editing 2020-07-27 10:14:55 -07:00
Dylan Copeland 534d74a281 Improving readability with some boolean variables. 2020-07-27 09:50:10 -07:00
stefanhenneking 1520991750 Adding NCMesh unit test for PA diagonal assembly. 2020-07-25 18:07:53 -05:00
stefanhenneking a16de090e4 Minor fix. 2020-07-25 17:50:40 -05:00
Tomov 857ddd0c24 Merge branch 'master' into tmop-el-type 2020-07-24 16:06:58 -07:00
Tomov 30acc283d6 Reverted the change in the limiting; make style. 2020-07-24 15:36:52 -07:00
Dylan Copeland e00be4f28e Adding 2D versions of H(curl)-H(div) mixed mass PA operators with support for all coefficient types. 2020-07-23 11:13:01 -07:00
Arturo Vargas ad208cadfa update changelog 2020-07-23 09:28:44 -07:00
Stowell, Mark L 33e4d56213 Updating CHANGELOG and improving comments as suggested by reviewers 2020-07-22 17:24:11 -07:00
Tzanio cb1fd6fccb Merge branch 'master' into feature/artv3/cusparse-Spmv 2020-07-22 16:39:38 -07:00
Dylan Copeland eb6a7afb9c Adding PA for 3D mass operator with H(div) trial and H(curl) test functions, supporting all coefficient types, and with unit tests. 2020-07-22 13:54:30 -07:00
Dylan Copeland 95985e9c83 Adding PA for H(curl)-H(div) mass operator with scalar, diagonal vector, or matrix (symmetric or asymmetric) coefficients. Unit tests cover the new features. Fixed a bug in PAHcurlHdivApply3D which had no effect so far. 2020-07-21 22:16:28 -07:00
Tzanio a7f182e47c minor 2020-07-21 17:14:19 -07:00
Tzanio 10ebf2c2a2 Merge branch 'master' into ho-gmsh-dev 2020-07-21 16:39:41 -07:00
Arturo Vargas a59817b8a7 Merge branch 'feature/artv3/cusparse-Spmv' of https://github.com/mfem/mfem into feature/artv3/cusparse-Spmv 2020-07-21 16:24:23 -07:00
Arturo Vargas 4e8a531bb1 add guards for cpu with cuda codes 2020-07-21 16:23:43 -07:00
stefanhenneking 8f7db4d393 Merge branch 'master' of github.com:mfem/mfem into abs-mult-dev 2020-07-21 17:35:01 -05:00
Veselin Dobrev 51397513f1 Merge branch 'master' into residual-bc-monitor 2020-07-21 15:23:14 -07:00
Arturo Vargas 11964610e1 move cuda header to guards 2020-07-21 15:10:21 -07:00
Stowell, Mark L 8591f4eb0a Adding calls to Reset in locations where GetPointMat is used to update the point matrix 2020-07-21 12:07:51 -07:00
Stowell, Mark L 94c241c368 Adding comment to remind users of GetPointMat to call the new Reset member function 2020-07-21 12:07:04 -07:00
Stowell, Mark L c35a943aba Resetting EvalState when new FiniteElement or a new point matrix is set 2020-07-21 12:03:36 -07:00
Stowell, Mark L bc20049cd9 Adding ElementTransformation::Reset method to set EvalState to zero. 2020-07-21 12:02:49 -07:00
Arturo Vargas 9937009eab clean up pass, guard for resizing 2020-07-21 11:59:42 -07:00
Arturo Vargas 9bd06e360e temp_buffer->new_buffer 2020-07-21 11:13:33 -07:00
Arturo Vargas 2bea6d11f1 Merge branch 'feature/artv3/cusparse-Spmv' of github.com:mfem/mfem into feature/artv3/cusparse-Spmv 2020-07-21 11:11:49 -07:00
Arturo Vargas 264886c511 PR comments 2020-07-21 11:11:38 -07:00
Tzanio 7ec3c5a30c Merge branch 'master' into feature/artv3/cusparse-Spmv 2020-07-21 10:42:19 -07:00
Dylan Copeland 8412926d1f Documentation 2020-07-21 10:27:53 -07:00
Dylan CopelandandStefan Henneking e6a0818041 Minor change.
Co-authored-by: Stefan Henneking <stefan.henneking@gmail.com>
2020-07-21 10:08:16 -07:00
Dylan CopelandandStefan Henneking 1bb517c695 Minor change.
Co-authored-by: Stefan Henneking <stefan.henneking@gmail.com>
2020-07-21 10:02:49 -07:00
Tomov 8327c249de Old TODO comment. 2020-07-20 18:07:30 -07:00
Tomov 8208a13de4 Corresponding changes in the serial miniapp. 2020-07-20 17:35:53 -07:00
Tomov a000402216 Minor. 2020-07-20 17:18:01 -07:00
Tomov 85d171e7cb Sample runs for mixed meshes in pmesh-optimizer. 2020-07-20 17:10:29 -07:00
Tomov 8e631732e1 Merge branch 'master' into tmop-el-type 2020-07-20 16:13:27 -07:00
Arturo Vargas 15b50a277e move InitCuSparse to protected 2020-07-18 22:10:47 -07:00
Arturo Vargas 2a85ec5f97 Merge branch 'master' into feature/artv3/cusparse-Spmv 2020-07-18 22:05:07 -07:00
Ketan Mittal 320f491661 fix for discrete adaptivity 2020-07-17 15:58:21 -07:00
Veselin Dobrev fd45ae843a Extend the class IterativeSolverMonitor to store a pointer to
the last IterativeSolver that uses it.

Add a simple ResidualBCMonitor that can be used to check if
essential b.c. are properly imposed on the initial guess, rhs,
operator, and preconditioner.
2020-07-17 12:57:34 -07:00
Stowell, Mark L bfad6c9903 Removing unneeded Gmsh files 2020-07-16 15:19:41 -07:00
Stowell, Mark L 3d94969a8b Replacing sample Gmsh meshes with high order meshes 2020-07-16 12:43:00 -07:00
Stowell, Mark L 973e0486ff Switching to periodic annulus by default 2020-07-16 12:31:38 -07:00
Stowell, Mark L 655536e919 Adding element type improvements to periodic torus geo file (thanks to @bslazarov) 2020-07-16 12:26:22 -07:00
Stowell, Mark L 5d5e0a5320 Adjusting comments and user options in periodic annulus geo file 2020-07-16 12:24:57 -07:00
Dylan Copeland 77b6729309 Updating description of input parameters omitted from a previous PR. 2020-07-16 10:11:18 -07:00
lazarov ff03595251 Merge branch 'ho-gmsh-dev' of https://github.com/mfem/mfem into ho-gmsh-dev 2020-07-15 22:59:12 -07:00
lazarov f84f1c9416 periodic sector and 3rd order generated mesh 2020-07-15 22:57:50 -07:00
Tzanio Kolev 0da14b3875 Merge branch 'master' into ho-gmsh-dev 2020-07-15 14:52:44 -07:00
Veselin Dobrev c1a15aa858 Merge branch 'master' into h1-hessian-dev 2020-07-15 14:33:29 -07:00
stefanhenneking f2c7e4f166 Adding required preprocessor directives. 2020-07-15 14:55:40 -05:00
Tom Stitt 4877a6d350 Updates PADiffusionSetup{2,3}D and QuadratureInterpolator::Eval{2,3}D to
expose more units of work, there wasn't enough work with 1
thread/element.

The PADiffusionSetup kernels are now over NE*NQ instead of just NE
and the Eval{2,3}D kernels are now shared-memory kernels of size max(NQ,
ND) instead being over NE.
2020-07-15 12:47:02 -07:00
Dylan Copeland ea4d8c365c Restoring another unit test. 2020-07-15 11:29:00 -07:00
psocratis 7de90075e1 Merge branch 'abs-mult-dev' of https://github.com/mfem/mfem into abs-mult-dev 2020-07-15 11:19:25 -07:00
psocratis dba8b05843 cleanup 2020-07-15 11:18:29 -07:00
stefanhenneking 8fc24ace79 Adding AssembleDiagonal for NCMesh using AbsMultTranspose. 2020-07-15 11:39:35 -05:00
Stefan Henneking 79aa92e217 Merge branch 'master' into abs-mult-dev 2020-07-15 10:51:00 -05:00
Dylan Copeland 96dd27f68f Restoring changes. 2020-07-14 22:30:10 -07:00
Dylan Copeland ab51c0ad38 Merge branch 'master' of https://github.com/mfem/mfem into matcoefpa 2020-07-14 21:33:08 -07:00
psocratis 5ef9a11e9f unit test for rectangular HyprePar and Sparse Matrices 2020-07-14 18:25:10 -07:00
psocratis ae6b431161 Added unit test for SparseMatrix::AbsMultTranspose 2020-07-14 16:44:07 -07:00
psocratis e3a9948ab6 Added unit test for HypreParMatrix::AbsMultTranspose 2020-07-14 16:43:43 -07:00
psocratis b3e18e733b Added implementation for hypre_CSRMatrixAbsMatvecT and hypre_ParCSRMatrixAbsMatvecT 2020-07-14 16:43:10 -07:00
psocratis 6fc3b74033 Added unit tests for HypreParMatrix::AbsMult and SparseMatrix::AbsMult 2020-07-14 15:34:59 -07:00
psocratis b20b819e0e Added implementation for hypre_ParCSRMatrixAbsMatvec 2020-07-14 14:55:23 -07:00
psocratis 3b016624ca minor 2020-07-14 11:02:47 -07:00
psocratis 0b538f5cd1 Added implementation of hypre_CSRMatrixAbsMatvec 2020-07-13 20:19:27 -07:00
stefanhenneking a97509648a Adding signatures for hypre AbsMult and AbsMultTranpose. 2020-07-13 17:39:36 -05:00
stefanhenneking 6fc40b1ee5 Adding AbsMult and AbsMultTranspose to SparseMatrix. 2020-07-13 14:55:57 -05:00
Arturo Vargas ce2b02624d Merge branch 'master' into feature/artv3/cusparse-Spmv 2020-07-08 13:09:30 -07:00
Tomov dcf2e20f86 Added limiting to the mixed mesh sample runs, switched to references
instead of pointer for the local integration rules.
2020-07-08 10:59:21 -07:00
Tzanio Kolev c8990d45db Merge branch 'master' into h1-hessian-dev 2020-07-08 09:24:49 -07:00
Tomov 5e71900292 Sample runs with mixed 2D and 3D meshes. Fix in the normalization code. 2020-07-07 19:00:58 -07:00
Andreas Schafelner 4a17f07edf Fixed variable names. 2020-07-07 11:27:37 +02:00
Andreas Schafelner 1b5e10bd25 Fix a typo in CalCHessian documentation. 2020-07-07 10:41:22 +02:00
Andreas Schafelner 2f77370746 Merge branch 'master' into h1-hessian-dev 2020-07-07 10:40:55 +02:00
Andreas Schafelner 5e436c109e make style 2020-07-06 09:23:23 +02:00
Stowell, Mark L 346af0560f Gmsh pyramid mappings 2020-07-03 14:56:33 -07:00
Stowell, Mark L 5cdbec35ff Use predefined mappings for orders 2 and 3 2020-07-02 14:26:24 -07:00
Stowell, Mark L f917dfb3c1 Gmsh wedge mappings 2020-07-02 14:01:52 -07:00
Stowell, Mark L 89ae6ad31c Adding new gmsh.[ch]pp files to cmake 2020-07-02 10:33:17 -07:00
Stowell, Mark L a7ba2b2dad Gmsh tetrahedron mapping 2020-07-01 17:51:01 -07:00
Tomov 69ea9d3dc4 Support for mixed meshes in TMOPNewtonSolver. 2020-07-01 15:39:53 -07:00
Stowell, Mark L bf24259fda Gmsh hexahedron mapping 2020-07-01 15:21:02 -07:00
Stowell, Mark L a0ac13f0ef Gmsh quadrilateral mapping (thanks @pazner!) 2020-07-01 15:20:42 -07:00
Stowell, Mark L fc430a2732 Gmsh triangle mapping (thanks @pazner) 2020-07-01 15:18:38 -07:00
Stowell, Mark L ce12d60a57 Adding Gmsh specific high-order vertex mapping functions 2020-07-01 11:54:53 -07:00
Stowell, Mark L 25804821c9 Adding recognition of higher order element types (as well as Wedges and Pyramids). Still need mappings... 2020-07-01 00:51:32 -07:00
Stowell, Mark L 275ef2d826 Starting modifications to support orders up to 9 or 10 2020-06-30 22:16:05 -07:00
Dylan Copeland e77e7f592b Adding support for matrix coefficients in H(curl) mass diagonal assembly, with unit tests. 2020-06-30 15:10:55 -07:00
Tzanio f2c1441949 Merge branch 'master' into ho-gmsh-dev 2020-06-27 18:23:47 -07:00
Tzanio 4bae761338 make style 2020-06-27 18:23:43 -07:00
Stowell, Mark L 9a6954b957 Tweaks after double-checking high order hexahedron support 2020-06-26 09:42:56 -07:00
Arturo Vargas 1d35d74e85 fix logic for using cusparse 2020-06-25 11:40:28 -07:00
Arturo Vargas dceaf60897 Merge branch 'master' into feature/artv3/cusparse-Spmv 2020-06-25 11:37:20 -07:00
Arturo Vargas f761e4d033 add runtime option to use cusparse - on by default 2020-06-25 10:41:19 -07:00
Tomov dd9643cabd WIP mixed meshes. 2020-06-24 15:03:51 -07:00
Stowell, Mark L 9d21df44c9 Adding option to shutoff the periodicity 2020-06-24 13:32:09 -07:00
Tomov cfdd39a066 Merge branch 'master' into tmop-el-type 2020-06-24 10:40:02 -07:00
Stowell, Mark L a0e9c74b9d Generalizing 2D .geo script for different orders and element types 2020-06-24 09:36:19 -07:00
Stowell, Mark L 634ae97901 Adding "order" parameter to .geo files 2020-06-24 09:04:31 -07:00
Stowell, Mark L 484dadbe4f Removing finalize calls 2020-06-24 09:04:05 -07:00
Stowell, Mark L 411ee11ffd Adding finalize topology 2020-06-23 22:54:46 -07:00
Stowell, Mark L 37d153a393 Adding 20 node tetrahedron support 2020-06-23 22:54:09 -07:00
Stowell, Mark L 13f1441e6c Adding 64 nodes hexahedron support 2020-06-23 22:19:39 -07:00
Stowell, Mark L 331b940373 Adding support for 27 node hexahedral elements 2020-06-23 20:55:57 -07:00
Stowell, Mark L 67c70dc827 Adding support for 10 node tetrahedra 2020-06-23 18:58:21 -07:00
Stowell, Mark L 93a7b6ae86 High order Gmsh support in 1D and 2D 2020-06-23 16:50:17 -07:00
Arturo Vargas 684785eb64 clean up pass 2020-06-23 15:55:46 -07:00
Arturo Vargas bddf1110b4 PR review updates 2020-06-23 15:48:25 -07:00
Tomov a7cc1e74c3 wip on tmop with mixed meshes. 2020-06-16 16:41:59 -07:00
Arturo Vargas 88b98c8fb4 small fixes for applications 2020-06-13 22:01:12 -07:00
Arturo Vargas 6c1ee0c854 skip computation if matrix is zero 2020-06-11 20:33:43 -07:00
Arturo Vargas e7674ba0e7 free data if init 2020-06-11 09:44:28 -07:00
Vargas 9b83346ed3 make style 2020-06-01 10:42:45 -07:00
Arturo Vargas 26d3646c1b add guards for non cuda 2020-06-01 10:42:04 -07:00
Vargas f7724b30d9 make style 2020-06-01 10:15:09 -07:00
Arturo Vargas c28cfb92ac clean up pass, add diffusion benchmark 2020-06-01 10:13:55 -07:00
Arturo Vargas 2a5a1fc73b Merge branch 'master' into feature/artv3/cusparse-Spmv 2020-06-01 08:55:03 -07:00
Arturo Vargas c61af0cce9 comment out debugging code 2020-05-29 10:28:24 -07:00
Arturo Vargas e1bd6275d1 Merge branch 'master' into feature/artv3/cusparse-Spmv 2020-05-29 09:19:58 -07:00
Tzanio Kolev 0f54e013aa Merge branch 'master' into h1-hessian-dev 2020-05-19 09:31:42 -07:00
Arturo Vargas 8b9b0f7a0d uncomment inportant code 2020-05-18 17:58:43 -07:00
Arturo Vargas fd0ac87506 added driver for testing performance 2020-05-18 17:46:39 -07:00
Arturo Vargas 83d753c036 proof of concept 2020-05-18 15:53:26 -07:00
Arturo Vargas fb249c5775 fixed configuration for sparse matvec 2020-05-18 14:32:32 -07:00
Arturo Vargas a3e73ee1a3 init commit of cuSparse Spmv 2020-05-18 13:32:15 -07:00
Andreas Schafelner 9b47fcf5cf Fixed a typo in the documentation of CalcHessian. 2020-05-11 10:31:14 +02:00
Andreas Schafelner 247fa3fa11 Added CalcHessian for H1-conforming tensor f.e.
Also added Poly_1D::Basis::Eval that computes the second derivative.
2020-05-11 10:30:31 +02:00
62 changed files with 7055 additions and 1920 deletions
+12 -6
View File
@@ -16,7 +16,12 @@ Meshing improvements
- The graph linear ordering library Gecko, previously an external dependency, is
now included directly in MFEM. As a result, Mesh::GetGeckoElementOrdering is
always available. The interface has also been improved, see for example the
mesh-explorer miniapp.
Mesh Explorer miniapp.
- Improved Gmsh reader (version 2.2), which now supports both high-order and
periodic meshes. Segments, triangles, quadrilaterals, and tetrahedra are
supported up to order 10. Wedges and hexahedra are supported up to order 9.
For sample periodic meshes, see the periodic*.msh files in the data directory.
- Added support for finite difference-based gradient and Hessian approximation
in the TMOP mesh optimization algorithms. This improves the accuracy of the
@@ -27,11 +32,8 @@ Meshing improvements
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.
- Added TMOP capability for approximate tangential mesh relaxation. Added
support and examples for using TMOP on mixed meshes.
- Added complete action of the TMOP Integrator to account for the spatial
derivatives of discrete and analytic targets.
@@ -58,6 +60,8 @@ Improved GPU capabilities
compute a global sparse matrix. All integrators supported by element assembly
are also supported by full assembly. See the '-fa' option in Example 9.
- Added CUDA support for sparse matrix-vector multiplication with cuSPARSE.
- Added support for BlockOperator on GPU. See the updated Example 5.
Discretization improvements
@@ -165,6 +169,8 @@ New and updated examples and miniapps
- Added device support in Example 5/5p.
- Added the option to plot a function in Mesh Explorer.
Improved testing
----------------
- Added a GitLab pipeline that automates PR testing on supercomputing systems
+32 -17
View File
@@ -89,8 +89,38 @@ enable_language(CXX)
if (MFEM_USE_CUDA)
# MFEM_USE_CUDA requires CMake 3.8 or newer (for direct CUDA support)
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
# Use ${CMAKE_CXX_COMPILER} as the cuda host compiler.
if (NOT CMAKE_CUDA_HOST_COMPILER)
set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER})
endif()
enable_language(CUDA)
set(CMAKE_CUDA_STANDARD 11)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_EXTENSIONS OFF)
set(CUDA_FLAGS "--expt-extended-lambda")
if (CMAKE_VERSION VERSION_LESS 3.18.0)
set(CUDA_FLAGS "-arch=${CUDA_ARCH} ${CUDA_FLAGS}")
elseif (NOT CMAKE_CUDA_ARCHITECTURES)
string(REGEX REPLACE "^sm_" "" ARCH_NUMBER "${CUDA_ARCH}")
if ("${CUDA_ARCH}" STREQUAL "sm_${ARCH_NUMBER}")
set(CMAKE_CUDA_ARCHITECTURES "${ARCH_NUMBER}")
else()
message(FATAL_ERROR "Unknown CUDA_ARCH: ${CUDA_ARCH}")
endif()
else()
set(CUDA_ARCH "CMAKE_CUDA_ARCHITECTURES: ${CMAKE_CUDA_ARCHITECTURES}")
endif()
message(STATUS "Using CUDA architecture: ${CUDA_ARCH}")
if (CMAKE_VERSION VERSION_LESS 3.12.0)
# CMake versions 3.8 and 3.9 require this to work; 3.10 and 3.11 are not
# tested and may not actually need this (but should be ok to keep).
set(CUDA_FLAGS "-ccbin=${CMAKE_CXX_COMPILER} ${CUDA_FLAGS}")
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CMAKE_CXX_COMPILER})
endif()
set(CMAKE_CUDA_FLAGS "${CUDA_FLAGS}" CACHE STRING
"CUDA flags set for MFEM" FORCE)
set(CUSPARSE_FOUND TRUE)
set(CUSPARSE_LIBRARIES "cusparse")
endif()
if (XSDK_ENABLE_C)
@@ -296,22 +326,6 @@ if (MFEM_USE_HIOP)
# find_package updates HIOP_FOUND, HIOP_INCLUDE_DIRS, HIOP_LIBRARIES
endif()
# CUDA
if (MFEM_USE_CUDA)
set(CMAKE_CUDA_STANDARD 11)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_EXTENSIONS OFF)
set(CMAKE_CUDA_FLAGS "-arch=${CUDA_ARCH} --expt-extended-lambda"
CACHE STRING "CUDA flags set for MFEM" FORCE)
if (MFEM_USE_MPI)
set(CUDA_CCBIN_COMPILER ${MPI_CXX_COMPILER})
else()
set(CUDA_CCBIN_COMPILER ${CMAKE_CXX_COMPILER})
endif()
string(APPEND CMAKE_CUDA_FLAGS " -ccbin ${CUDA_CCBIN_COMPILER}")
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CUDA_CCBIN_COMPILER})
endif()
# OCCA
if (MFEM_USE_OCCA)
find_package(OCCA REQUIRED)
@@ -357,7 +371,8 @@ endif()
# be before SuiteSparse.
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
SLEPC MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2)
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2
CUSPARSE)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
set(TPL_LIBRARIES "")
set(TPL_INCLUDE_DIRS "")
+1 -1
View File
@@ -663,7 +663,7 @@ The specific libraries and their options are:
URL: https://github.com/CEED/libCEED
https://ceed.exascaleproject.org/libceed
Options: CEED_DIR, CEED_OPT, CEED_LIB.
Versions: libCEED >= 0.6, git-hash a970f63.
Versions: libCEED > 0.6, git-hash fe5822c.
- RAJA (optional), used when MFEM_USE_RAJA = YES.
Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported.
@@ -128,7 +128,15 @@ function(add_mfem_miniapp MFEM_EXE_NAME)
if (MFEM_USE_CUDA)
set_property(SOURCE ${MAIN_LIST} ${EXTRA_SOURCES_LIST}
PROPERTY LANGUAGE CUDA)
list(TRANSFORM EXTRA_OPTIONS_LIST PREPEND "-Xcompiler=")
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
list(TRANSFORM EXTRA_OPTIONS_LIST PREPEND "-Xcompiler=")
else()
set(LIST_)
foreach(item IN LISTS EXTRA_OPTIONS_LIST)
list(APPEND LIST_ "-Xcompiler=${item}")
endforeach()
set(EXTRA_OPTIONS_LIST ${LIST_})
endif()
endif()
# Actually add the executable
+2 -2
View File
@@ -341,9 +341,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 =
+57 -8
View File
@@ -1,13 +1,38 @@
SetFactory("OpenCASCADE");
// Select periodic mesh by setting this to either 0 - standard, 1 - periodic
periodic = 1;
// Set the geometry order (1, 2, ..., 9)
order = 3;
// Set the element type (3 - triangles, 4 - quadrilaterals)
type = 3;
// Number of radial elements
nrad = 2;
// Number of azimuthal elements on inner arc
nazm1 = 3;
// Number of azimuthal elements on outer arc
nazm2 = 5;
// Note: Using type = 4 with nazm1 != nazm2 can lead to mixed meshes
// containing both triangles and quadrilaterals.
// Inner and outer radii
R1 = 1.0;
R2 = 2.0;
// Angular size of the sector
Phi = Pi/3.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};
Point(4) = {R1*Cos(Phi), R1*Sin(Phi), 0, 1.0};
Point(5) = {R2*Cos(Phi), R2*Sin(Phi), 0, 1.0};
Line(1) = {2, 3};
Line(2) = {4, 5};
Circle(3) = {2, 1, 4};
@@ -15,13 +40,23 @@ 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;
Transfinite Curve{1} = nrad+1;
Transfinite Curve{2} = nrad+1;
Transfinite Curve{3} = nazm1+1;
Transfinite Curve{4} = nazm2+1;
If (nazm1 == nazm2)
Transfinite Surface{1};
EndIf
If (type == 4)
Recombine Surface {1};
EndIf
// Set a rotation periodicity constraint:
Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Pi/3};
If (periodic)
Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Phi};
EndIf
// Tag surfaces and volumes with positive integers
Physical Curve(1) = {3};
@@ -30,8 +65,22 @@ Physical Curve(3) = {1};
Physical Curve(4) = {2};
Physical Surface(1) = {1};
// Optimize the high-order mesh
// See https://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eHighOrderOptimize
// Mesh.ElementOrder = order;
// Mesh.HighOrderOptimize = 1;
// Generate 2D mesh
Mesh 2;
SetOrder order;
Mesh.MshFileVersion = 2.2;
Save "periodic-annulus-sector.msh";
// Check the element quality (the Plugin may be called AnalyseCurvedMesh)
// Plugin(AnalyseMeshQuality).JacobianDeterminant = 1;
// Plugin(AnalyseMeshQuality).Run;
If (periodic)
Save Sprintf("periodic-annulus-sector-t%01g-o%01g.msh", type, order);
Else
Save Sprintf("annulus-sector-t%01g-o%01g.msh", type, order);
EndIf
+168 -161
View File
@@ -2,184 +2,191 @@ $MeshFormat
2.2 0 8
$EndMeshFormat
$Nodes
55
136
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
5 1.5 0 0
6 1.166666666666667 0 0
7 1.333333333333333 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
10 0.7500000000000002 1.299038105676658 0
11 0.5833333333333335 1.010362971081845 0
12 0.6666666666666667 1.154700538379251 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
17 0.993238357741943 0.1160929141252301 0
18 0.9730448705798238 0.2306158707424401 0
19 0.8936326403234125 0.4487991802004617 0
20 0.8354878114129367 0.5495089780708056 0
21 0.6862416378687343 0.7273736415730481 0
22 0.597158591702787 0.8021231927550432 0
23 1.956295201467611 0.4158233816355181 0
24 1.827090915285202 0.8134732861515996 0
25 1.618033988749896 1.175570504584944 0
26 1.338261212717719 1.486289650954786 0
27 1.995128100519648 0.1395129474882505 0
28 1.980536137483141 0.278346201920131 0
29 1.922523391876638 0.551274711633998 0
30 1.879385241571817 0.6840402866513373 0
31 1.765895185717855 0.9389431255717802 0
32 1.696096192312853 1.059838528466408 0
33 1.532088886237958 1.285575219373077 0
34 1.438679600677305 1.389316740917992 0
35 1.231322950651319 1.576021507213442 0
36 1.118385806941496 1.658075145110082 0
37 1.162276263405681 0.6710405135499813 0
38 1.248615852873337 1.079531485311822 0
39 1.559209616901855 0.5415673055003691 0
40 1.478306597054007 0.8535007117539289 0
41 0.9210953433941653 0.9653302893212266 0
42 1.296548225291847 0.3150268220262836 0
43 1.055002035226811 1.358510675893086 0
44 1.704005774249187 0.2344032256041583 0
45 0.6403651144647218 0.8991270322967013 0
46 0.7807302289294435 0.9322286608089638 0
47 0.864063562262777 1.07656622810637 0
48 0.8070317811313885 1.187802166891514 0
49 0.7236984477980553 1.043464599594108 0
50 1.432182741763949 0.1050089406754279 0
51 1.364365483527898 0.2100178813508558 0
52 1.197698816861231 0.2100178813508558 0
53 1.098849408430616 0.1050089406754279 0
54 1.265516075097282 0.1050089406754278 0
55 0.8177280765440409 0.7503018362314346 0
56 0.869411709969103 0.8578160627763305 0
57 0.7348318576552288 0.8316090412164392 0
58 1.177596357123201 0.3240245957927452 0
59 1.058644488954555 0.3330223695592067 0
60 1.087610484537871 0.2205785356313179 0
61 1.267619707955123 0.7318605796179638 0
62 1.372963152504565 0.7926806456859463 0
63 1.40174301566045 0.9288443029398934 0
64 1.325179434266893 1.004187894125858 0
65 1.219835989717452 0.9433678280578752 0
66 1.191056126561566 0.8072041708039283 0
67 1.296399571111008 0.8680242368719107 0
68 1.532241943619239 0.645545107584889 0
69 1.505274270336623 0.7495229096694089 0
70 1.294587381237739 0.6278827775334439 0
71 1.426898499069797 0.5847250415169065 0
72 1.399930825787181 0.6887028436014264 0
73 1.139442349713613 1.041464419981624 0
74 1.030268846553889 1.003397354651425 0
75 1.001488983398004 0.8672336973974781 0
76 1.081882623401843 0.7691371054737297 0
77 1.110662486557728 0.9053007627276766 0
78 1.207033584034403 0.5523692830420821 0
79 1.251790904663125 0.4336980525341829 0
80 1.384102022495183 0.3905403165176455 0
81 1.471655819698519 0.4660538110090073 0
82 1.339344701866461 0.5092115470255447 0
83 1.73779714915742 0.7228379592678562 0
84 1.648503383029637 0.6322026323841127 0
85 1.691571478423774 0.4996526642120855 0
86 1.823933339945692 0.4577380229238018 0
87 1.787039416783436 0.5922941012619014 0
88 1.308379426102925 1.350703595740465 0
89 1.278497639488131 1.215117540526144 0
90 1.371755231498856 1.111544491736196 0
91 1.494894610124376 1.14355749816057 0
92 1.4064614465962 1.25147448186763 0
93 1.013887168325833 0.451693600067106 0
94 1.088081715865757 0.5613670568085436 0
95 1.03019898997678 0.6616228789288338 0
96 0.8981217165478794 0.6522052443076862 0
97 0.9637989050473432 0.5564495572737495 0
98 1.432367408277627 0.2881522898855752 0
99 1.568186591263407 0.2612777577448668 0
100 1.655740388466743 0.3367912522362286 0
101 1.607475002684299 0.4391792788682989 0
102 1.519921205480963 0.3636657843769371 0
103 1.184077913657828 1.17252454883891 0
104 1.119539974442319 1.265517612365998 0
105 1.010366471282595 1.2274505470358 0
106 0.9657309073383804 1.096390418178513 0
107 1.074904410498104 1.134457483508712 0
108 1.901335258083062 0.07813440853471942 0
109 1.802670516166124 0.1562688170694388 0
110 1.636003849499458 0.156268817069439 0
111 1.568001924749729 0.07813440853471942 0
112 1.734668591416396 0.07813440853471944 0
113 0.8516673450756037 1.318862295748801 0
114 0.9533346901512071 1.338686485820944 0
115 1.03666802348454 1.48302405311835 0
116 1.01833401174227 1.607537430343614 0
117 0.9350006784089369 1.463199863046207 0
118 1.710829475874804 0.8268157613523761 0
119 1.594568036464405 0.8401582365531526 0
120 1.621535709747021 0.7361804344686326 0
121 1.52488239428597 0.9608573093642675 0
122 1.571458191517933 1.068213906974606 0
123 1.448318812892413 1.036200900550232 0
124 0.908699126206992 1.207626356963657 0
125 1.500184666513678 0.1831433492101474 0
126 1.646765991694905 0.9507607885973723 0
127 0.9498053499729417 0.7597194708525821 0
128 1.132839036494479 0.4426958263006443 0
129 1.149421761057113 1.40110366758032 0
130 1.243841486887416 1.443696659267553 0
131 1.134903597606542 1.530869109405537 0
132 1.872198725728137 0.3553499962917315 0
133 1.788102249988661 0.2948766109479449 0
134 1.893223337417325 0.2174207916708467 0
135 1.213959700272622 1.308110604053232 0
136 1.739836864206217 0.3972646375800152 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
38
1 26 2 3 1 1 5 6 7
2 26 2 3 1 5 2 8 9
3 26 2 4 2 3 10 11 12
4 26 2 4 2 10 4 13 14
5 26 2 1 3 1 15 17 18
6 26 2 1 3 15 16 19 20
7 26 2 1 3 16 3 21 22
8 26 2 2 4 2 23 27 28
9 26 2 2 4 23 24 29 30
10 26 2 2 4 24 25 31 32
11 26 2 2 4 25 26 33 34
12 26 2 2 4 26 4 35 36
13 21 2 1 1 3 41 10 45 46 47 48 12 11 49
14 21 2 1 1 5 42 1 50 51 52 53 6 7 54
15 21 2 1 1 16 41 3 55 56 46 45 22 21 57
16 21 2 1 1 1 42 15 53 52 58 59 18 17 60
17 21 2 1 1 37 40 38 61 62 63 64 65 66 67
18 21 2 1 1 39 40 37 68 69 62 61 70 71 72
19 21 2 1 1 38 41 37 73 74 75 76 66 65 77
20 21 2 1 1 37 42 39 78 79 80 81 71 70 82
21 21 2 1 1 24 39 23 83 84 85 86 29 30 87
22 21 2 1 1 26 38 25 88 89 90 91 33 34 92
23 21 2 1 1 15 37 16 93 94 95 96 20 19 97
24 21 2 1 1 42 44 39 98 99 100 101 81 80 102
25 21 2 1 1 38 43 41 103 104 105 106 74 73 107
26 21 2 1 1 2 44 5 108 109 110 111 8 9 112
27 21 2 1 1 10 43 4 113 114 115 116 14 13 117
28 21 2 1 1 24 40 39 118 119 69 68 84 83 120
29 21 2 1 1 38 40 25 64 63 121 122 91 90 123
30 21 2 1 1 41 43 10 106 105 114 113 48 47 124
31 21 2 1 1 5 44 42 111 110 99 98 51 50 125
32 21 2 1 1 25 40 24 122 121 119 118 31 32 126
33 21 2 1 1 37 41 16 76 75 56 55 96 95 127
34 21 2 1 1 15 42 37 59 58 79 78 94 93 128
35 21 2 1 1 4 43 26 116 115 129 130 35 36 131
36 21 2 1 1 23 44 2 132 133 109 108 27 28 134
37 21 2 1 1 26 43 38 130 129 104 103 89 88 135
38 21 2 1 1 39 44 23 101 100 133 132 86 85 136
$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
3
5 10
7 12
2 4
1 3
2 4
$EndPeriodic
+129 -13
View File
@@ -1,25 +1,141 @@
SetFactory("OpenCASCADE");
// Select periodic mesh by setting this to either 0 - standard, 1 - periodic
periodic = 1;
R = 1.5;
r = 0.5;
// Set the geometry order (1, 2, ..., 10 for tetrahedra or 9 for other types)
order = 3;
Torus(1) = {0,0,0, R, r, Pi/3};
// Set the element type (4 - tetrahedra, 6 - wedges, 8 - hexahedra)
type = 8;
pts() = PointsOf{ Volume{1}; };
// Minor and major radii
R1 = 1.0;
R2 = 2.0;
Characteristic Length{ pts() } = 0.25;
// Side length of interior square
A1 = 0.8;
// Angular size of the sector
Phi = Pi/3.0;
// Number of azimuthal elements
nazm = 3;
// Number of elements around a quarter of the circle
narc = 2;
// Number of elements between surface and interior square
nshl = 1;
lc = 0.5;
a1 = A1 / Sqrt(2.0);
Point(1) = {R2+R1, 0, 0, lc};
Point(2) = {R2, 0, R1, lc};
Point(3) = {R2-R1, 0, 0, lc};
Point(4) = {R2, 0, -R1, lc};
Point(5) = {R2, 0, 0, lc};
Point(6) = {R2+a1, 0, 0, lc};
Point(7) = {R2, 0, a1, lc};
Point(8) = {R2-a1, 0, 0, lc};
Point(9) = {R2, 0, -a1, lc};
Circle(1) = {1,5,2};
Circle(2) = {2,5,3};
Circle(3) = {3,5,4};
Circle(4) = {4,5,1};
Line(5) = {6,1};
Line(6) = {7,2};
Line(7) = {8,3};
Line(8) = {9,4};
Line(9) = {6, 7};
Line(10) = {7, 8};
Line(11) = {8, 9};
Line(12) = {9, 6};
Line Loop(101) = {1, -6, -9, 5};
Line Loop(102) = {2, -7, -10, 6};
Line Loop(103) = {3, -8, -11, 7};
Line Loop(104) = {4, -5, -12, 8};
Line Loop(105) = {9, 10, 11, 12};
Plane Surface(201) = {101};
Plane Surface(202) = {102};
Plane Surface(203) = {103};
Plane Surface(204) = {104};
Plane Surface(205) = {105};
Transfinite Curve{1} = narc+1;
Transfinite Curve{2} = narc+1;
Transfinite Curve{3} = narc+1;
Transfinite Curve{4} = narc+1;
Transfinite Curve{5} = nshl+1;
Transfinite Curve{6} = nshl+1;
Transfinite Curve{7} = nshl+1;
Transfinite Curve{8} = nshl+1;
Transfinite Curve{9} = narc+1;
Transfinite Curve{10} = narc+1;
Transfinite Curve{11} = narc+1;
Transfinite Curve{12} = narc+1;
If (type == 8)
Recombine Surface {201};
Recombine Surface {202};
Recombine Surface {203};
Recombine Surface {204};
Recombine Surface {205};
Transfinite Surface {201} = {1,2,7,6};
Transfinite Surface {202} = {2,3,8,7};
Transfinite Surface {203} = {3,4,9,8};
Transfinite Surface {204} = {4,1,6,9};
Transfinite Surface {205} = {6,7,8,9};
EndIf
If (type == 4)
Extrude { {0,0,1} , {0,0,0} , Phi} {
Surface{201,202,203,204,205}; Layers{nazm};
}
Else
Extrude { {0,0,1} , {0,0,0} , Phi} {
Surface{201,202,203,204,205}; Layers{nazm}; Recombine;
}
EndIf
// Set a rotation periodicity constraint:
Periodic Surface{3} = {2} Rotate{{0,0,1}, {0,0,0}, Pi/3};
If (periodic)
Periodic Surface{227} = {201} Rotate{{0,0,1}, {0,0,0}, Phi};
Periodic Surface{249} = {202} Rotate{{0,0,1}, {0,0,0}, Phi};
Periodic Surface{271} = {203} Rotate{{0,0,1}, {0,0,0}, Phi};
Periodic Surface{293} = {204} Rotate{{0,0,1}, {0,0,0}, Phi};
Periodic Surface{315} = {205} Rotate{{0,0,1}, {0,0,0}, Phi};
EndIf
// Tag surfaces and volumes with positive integers
Physical Surface(1) = {1};
Physical Surface(2) = {2};
Physical Surface(3) = {3};
Physical Volume(1) = {1};
Physical Surface(1) = {201,202,203,204,205};
Physical Surface(2) = {227,249,271,293,315};
Physical Surface(3) = {214,236,258,280};
Physical Volume(1) = {1,2,3,4,5};
// Optimize the high-order mesh
// See https://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eHighOrderOptimize
// Mesh.ElementOrder = order;
// Mesh.HighOrderOptimize = 1;
// Generate 3D mesh
Mesh 3;
SetOrder order;
Mesh.MshFileVersion = 2.2;
Save "periodic-torus-sector.msh";
// Check the element quality (the Plugin may be called AnalyseCurvedMesh)
// Plugin(AnalyseMeshQuality).JacobianDeterminant = 1;
// Plugin(AnalyseMeshQuality).Run;
If (periodic)
Save Sprintf("periodic-torus-sector-t%01g-o%01g.msh", type, order);
Else
Save Sprintf("torus-sector-t%01g-o%01g.msh", type, order);
EndIf
File diff suppressed because it is too large Load Diff
+118
View File
@@ -0,0 +1,118 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
2
elements
20
1 3 0 1 6 5
1 3 1 2 7 6
1 3 2 3 8 7
1 3 3 4 9 8
1 3 5 6 11 10
1 2 6 7 11
1 2 7 12 11
1 2 7 8 13
1 2 7 13 12
1 3 8 9 14 13
1 3 10 11 16 15
1 2 11 12 17
1 2 11 17 16
1 2 12 13 17
1 2 13 18 17
1 3 13 14 19 18
1 3 15 16 21 20
1 3 16 17 22 21
1 3 17 18 23 22
1 3 18 19 24 23
boundary
16
2 1 0 1
2 1 1 2
2 1 2 3
2 1 3 4
2 1 21 20
2 1 22 21
2 1 23 22
2 1 24 23
1 1 5 0
1 1 10 5
1 1 15 10
1 1 20 15
1 1 4 9
1 1 9 14
1 1 14 19
1 1 19 24
vertices
25
nodes
FiniteElementSpace
FiniteElementCollection: H1_2D_P1
VDim: 2
Ordering: 0
0
0.25
0.5
0.75
1
0
0.25
0.5
0.75
1
0
0.25
0.5
0.75
1
0
0.25
0.5
0.75
1
0
0.25
0.5
0.75
1
0
0
0
0
0
0.25
0.25
0.25
0.25
0.25
0.5
0.5
0.5
0.5
0.5
0.75
0.75
0.75
0.75
0.75
1
1
1
1
1
+1 -2
View File
@@ -144,8 +144,7 @@ namespace mfem {
* - <a class="el" href="maxwell_8cpp_source.html">Maxwell</a>: simple transient full-wave electromagnetics simulation code
* - <a class="el" href="joule_8cpp_source.html">Joule</a>: transient magnetics and Joule heating miniapp
* - <a class="el" href="classmfem_1_1navier_1_1NavierSolver.html">Navier</a>: solve the transient incompressible Navier-Stokes equations
* - <a class="el" href="mobius-strip_8cpp_source.html">Mobius Strip</a>: generate various Mobius strip-like meshes
* - <a class="el" href="mobius-strip_8cpp_source.html">Mobius Strip</a>: generate various Mobius strip-like meshes
* - <a class="el" href="klein-bottle_8cpp_source.html">Klein Bottle</a>: generate three types of Klein bottle surfaces
* - <a class="el" href="toroid_8cpp_source.html">Toroid</a>: generate simple toroidal meshes
* - <a class="el" href="twist_8cpp_source.html">Twist</a>: generate simple periodic meshes
+1 -1
View File
@@ -19,7 +19,7 @@ html: $(DOXYGEN_CONF)
@# Generate the html documentation
@doxygen $(DOXYGEN_CONF)
@echo "<meta http-equiv=\"REFRESH\" content=\"0;URL=CodeDocumentation/html/index.html\">" > CodeDocumentation.html
@cat warnings.log
@cat warnings.log 1>&2
@# 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
+28 -6
View File
@@ -175,7 +175,8 @@ int main(int argc, char *argv[])
// domain integrator.
BilinearForm a(&fespace);
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a.AddDomainIntegrator(new DiffusionIntegrator(one));
//a.AddDomainIntegrator(new DiffusionIntegrator(one));
a.AddDomainIntegrator(new MassIntegrator(one));
// 10. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
@@ -184,19 +185,40 @@ int main(int argc, char *argv[])
if (static_cond) { a.EnableStaticCondensation(); }
a.Assemble();
OperatorPtr A;
OperatorPtr A, As;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
Array<int> empty_list;
a.FormSystemMatrix(empty_list, As);
//a.FormLinearSystem(empty_list, x, b, A, X, B);
//a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
cout << "Size of linear system: " << A->Height() << endl;
//cout << "Size of linear system: " << A->Height() << endl;
// 11. Solve the linear system A X = B.
if (!pa)
{
#ifndef MFEM_USE_SUITESPARSE
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 1, 200, 1e-12, 0.0);
//GSSmoother M((SparseMatrix&)(*A));
//SparseMatrix &Asp = *As.As<SparseMatrix>();
SparseMatrix &Asp = a.SpMat();
Asp.Finalize();
Asp.SortColumnIndices();
Vector tmpx(B.Size());
Vector tmpy(B.Size());
tmpx = 1.0;
tmpy = 0.0;
//As.As<SparseMatrix>()->Mult(tmpx, tmpy);
Asp.Mult(tmpx, tmpy);
//IncompleteCholesky M(*As.As<SparseMatrix>());
IncompleteCholesky M(Asp);
//ILUcusparse M(*A.As<SparseMatrix>());
PCG(*As, M, B, X, 1, 200, 1e-12, 0.0);
#else
// If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
+20 -3
View File
@@ -122,7 +122,7 @@ int main(int argc, char *argv[])
{
int ref_levels =
(int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
for (int l = 0; l < ref_levels-1; l++)
{
mesh.UniformRefinement();
}
@@ -134,7 +134,7 @@ int main(int argc, char *argv[])
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
{
int par_ref_levels = 2;
int par_ref_levels = 1;
for (int l = 0; l < par_ref_levels; l++)
{
pmesh.UniformRefinement();
@@ -216,6 +216,13 @@ int main(int argc, char *argv[])
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
SparseMatrix Asp;
A.As<HypreParMatrix>()->GetDiag(Asp);
Vector diag;
StopWatch sw;
sw.Start();
// 13. Solve the linear system A X = B.
// * With full assembly, use the BoomerAMG preconditioner from hypre.
// * With partial assembly, use Jacobi smoothing, for now.
@@ -229,7 +236,14 @@ int main(int argc, char *argv[])
}
else
{
prec = new HypreBoomerAMG;
//prec = new HypreBoomerAMG;
Asp.Finalize();
Asp.SortColumnIndices();
Asp.GetDiag(diag);
prec = new OperatorJacobiSmoother(diag, ess_tdof_list);
//prec = new IncompleteCholesky(Asp);
//prec = new ILUcusparse(Asp);
}
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
@@ -240,6 +254,9 @@ int main(int argc, char *argv[])
cg.Mult(B, X);
delete prec;
sw.Stop();
cout << "Step 13 solve time " << sw.RealTime() << endl;
// 14. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a.RecoverFEMSolution(X, b, x);
+1 -1
View File
@@ -70,7 +70,7 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: H(Curl) or 1: H(Div)");
"Choose between 0: grad, 1: curl, 2: div");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
+1 -1
View File
@@ -76,7 +76,7 @@ int main(int argc, char *argv[])
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: H(Curl) or 1: H(Div)");
"Choose between 0: grad, 1: curl, 2: div");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
+27
View File
@@ -627,6 +627,33 @@ void BilinearForm::AssembleDiagonal(Vector &diag) const
MFEM_ASSERT(diag.Size() == fes->GetTrueVSize(),
"Vector for holding diagonal has wrong size!");
const Operator *P = fes->GetProlongationMatrix();
// For an AMR mesh, a convergent diagonal is assembled with |P^T| d_e,
// where |P^T| has the entry-wise absolute values of the conforming
// prolongation transpose operator.
if (P && !fes->Conforming())
{
Vector local_diag(P->Height());
ext->AssembleDiagonal(local_diag);
const SparseMatrix *SP = dynamic_cast<const SparseMatrix*>(P);
#ifdef MFEM_USE_MPI
const HypreParMatrix *HP = dynamic_cast<const HypreParMatrix*>(P);
#endif
if (SP)
{
SP->AbsMultTranspose(local_diag, diag);
}
#ifdef MFEM_USE_MPI
else if (HP)
{
HP->AbsMultTranspose(1.0, local_diag, 0.0, diag);
}
#endif
else
{
MFEM_ABORT("Prolongation matrix has unexpected type.");
}
return;
}
if (!IsIdentityProlongation(P))
{
Vector local_diag(P->Height());
+12
View File
@@ -96,6 +96,9 @@ void PABilinearFormExtension::Assemble()
integrators[i]->AssemblePA(*a->FESpace());
}
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
"Partial assembly does not support AddBoundaryIntegrator yet.");
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int intFaceIntegratorCount = intFaceIntegrators.Size();
for (int i = 0; i < intFaceIntegratorCount; ++i)
@@ -320,6 +323,9 @@ void EABilinearFormExtension::Assemble()
GetTraceElement(0, trialFes->GetMesh()->GetFaceBaseGeometry(0)) ->
GetDof();
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
"Element assembly does not support AddBoundaryIntegrator yet.");
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int intFaceIntegratorCount = intFaceIntegrators.Size();
if (intFaceIntegratorCount>0)
@@ -794,6 +800,12 @@ void PAMixedBilinearFormExtension::Assemble()
{
integrators[i]->AssemblePA(*trialFes, *testFes);
}
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
"Partial assembly does not support AddBoundaryIntegrator yet.");
MFEM_VERIFY(a->GetTFBFI()->Size() == 0,
"Partial assembly does not support AddTraceFaceIntegrator yet.");
MFEM_VERIFY(a->GetBTFBFI()->Size() == 0,
"Partial assembly does not support AddBdrTraceFaceIntegrator yet.");
}
void PAMixedBilinearFormExtension::Update()
+13 -1
View File
@@ -20,6 +20,13 @@
namespace mfem
{
// Local maximum size of dofs and quads in 1D
constexpr int HCURL_MAX_D1D = 5;
constexpr int HCURL_MAX_Q1D = 6;
constexpr int HDIV_MAX_D1D = 5;
constexpr int HDIV_MAX_Q1D = 6;
/// Abstract base class BilinearFormIntegrator
class BilinearFormIntegrator : public NonlinearFormIntegrator
{
@@ -2390,8 +2397,11 @@ protected:
Vector pa_data;
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
const DofToQuad *mapsOtest; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsCtest; ///< Not owned. DOF-to-quad map, closed.
const GeometricFactors *geom; ///< Not owned
int dim, ne, nq, dofs1D, quad1D, fetype;
int dim, ne, nq, dofs1D, dofs1Dtest, quad1D, trial_fetype, test_fetype;
bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient
public:
VectorFEMassIntegrator() { Init(NULL, NULL, NULL); }
@@ -2412,6 +2422,8 @@ public:
using BilinearFormIntegrator::AssemblePA;
virtual void AssemblePA(const FiniteElementSpace &fes);
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes);
virtual void AddMultPA(const Vector &x, Vector &y) const;
virtual void AssembleDiagonalPA(Vector& diag);
};
+1 -1
View File
@@ -130,8 +130,8 @@ static void EADiffusionAssemble2D(const int NE,
template<int T_D1D = 0, int T_Q1D = 0>
static void EADiffusionAssemble3D(const int NE,
const Array<double> &g,
const Array<double> &b,
const Array<double> &g,
const Vector &padata,
Vector &eadata,
const int d1d = 0,
+89 -79
View File
@@ -96,26 +96,28 @@ void PADiffusionSetup2D<2>(const int Q1D,
const Vector &c,
Vector &d)
{
const int NQ = Q1D*Q1D;
const bool const_c = c.Size() == 1;
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
auto D = Reshape(d.Write(), NQ, 3, NE);
MFEM_FORALL(e, NE,
const auto W = Reshape(w.Read(), Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,2,2,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
Reshape(c.Read(), Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
{
for (int q = 0; q < NQ; ++q)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const double J11 = J(q,0,0,e);
const double J21 = J(q,1,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double coeff = const_c ? C(0,0) : C(q,e);
const double c_detJ = W[q] * coeff / ((J11*J22)-(J21*J12));
D(q,0,e) = c_detJ * (J12*J12 + J22*J22); // 1,1
D(q,1,e) = -c_detJ * (J12*J11 + J22*J21); // 1,2
D(q,2,e) = c_detJ * (J11*J11 + J21*J21); // 2,2
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double J11 = J(qx,qy,0,0,e);
const double J21 = J(qx,qy,1,0,e);
const double J12 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
const double c_detJ = W(qx,qy) * coeff / ((J11*J22)-(J21*J12));
D(qx,qy,0,e) = c_detJ * (J12*J12 + J22*J22); // 1,1
D(qx,qy,1,e) = -c_detJ * (J12*J11 + J22*J21); // 1,2
D(qx,qy,2,e) = c_detJ * (J11*J11 + J21*J21); // 2,2
}
}
});
}
@@ -131,33 +133,35 @@ void PADiffusionSetup2D<3>(const int Q1D,
{
constexpr int DIM = 2;
constexpr int SDIM = 3;
const int NQ = Q1D*Q1D;
const bool const_c = c.Size() == 1;
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, SDIM, DIM, NE);
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
auto D = Reshape(d.Write(), NQ, 3, NE);
MFEM_FORALL(e, NE,
const auto W = Reshape(w.Read(), Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,SDIM,DIM,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
Reshape(c.Read(), Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
{
for (int q = 0; q < NQ; ++q)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const double wq = W[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 E = J11*J11 + J21*J21 + J31*J31;
const double G = J12*J12 + J22*J22 + J32*J32;
const double F = J11*J12 + J21*J22 + J31*J32;
const double iw = 1.0 / sqrt(E*G - F*F);
const double coeff = const_c ? C(0,0) : C(q,e);
const double alpha = wq * coeff * iw;
D(q,0,e) = alpha * G; // 1,1
D(q,1,e) = -alpha * F; // 1,2
D(q,2,e) = alpha * E; // 2,2
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double wq = W(qx,qy);
const double J11 = J(qx,qy,0,0,e);
const double J21 = J(qx,qy,1,0,e);
const double J31 = J(qx,qy,2,0,e);
const double J12 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double J32 = J(qx,qy,2,1,e);
const double E = J11*J11 + J21*J21 + J31*J31;
const double G = J12*J12 + J22*J22 + J32*J32;
const double F = J11*J12 + J21*J22 + J31*J32;
const double iw = 1.0 / sqrt(E*G - F*F);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
const double alpha = wq * coeff * iw;
D(qx,qy,0,e) = alpha * G; // 1,1
D(qx,qy,1,e) = -alpha * F; // 1,2
D(qx,qy,2,e) = alpha * E; // 2,2
}
}
});
}
@@ -170,47 +174,53 @@ static void PADiffusionSetup3D(const int Q1D,
const Vector &c,
Vector &d)
{
const int NQ = Q1D*Q1D*Q1D;
const bool const_c = c.Size() == 1;
auto W = w.Read();
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,
const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1) :
Reshape(c.Read(), Q1D,Q1D,Q1D,NE);
auto D = Reshape(d.Write(), Q1D,Q1D,Q1D, 6, NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
{
for (int q = 0; q < NQ; ++q)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
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
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double J11 = J(qx,qy,qz,0,0,e);
const double J21 = J(qx,qy,qz,1,0,e);
const double J31 = J(qx,qy,qz,2,0,e);
const double J12 = J(qx,qy,qz,0,1,e);
const double J22 = J(qx,qy,qz,1,1,e);
const double J32 = J(qx,qy,qz,2,1,e);
const double J13 = J(qx,qy,qz,0,2,e);
const double J23 = J(qx,qy,qz,1,2,e);
const double J33 = J(qx,qy,qz,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,0,0) : C(qx,qy,qz,e);
const double c_detJ = W(qx,qy,qz) * 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(qx,qy,qz,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
D(qx,qy,qz,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
D(qx,qy,qz,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
D(qx,qy,qz,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
D(qx,qy,qz,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
D(qx,qy,qz,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
}
}
}
});
}
+141 -58
View File
@@ -19,10 +19,6 @@ using namespace std;
namespace mfem
{
// Local maximum size of dofs and quads in 1D
constexpr int HCURL_MAX_D1D = 5;
constexpr int HCURL_MAX_Q1D = 6;
// PA H(curl) Mass Assemble 2D kernel
void PAHcurlSetup2D(const int Q1D,
const int coeffDim,
@@ -33,11 +29,11 @@ void PAHcurlSetup2D(const int Q1D,
Vector &op)
{
const int NQ = Q1D*Q1D;
const bool symmetric = (coeffDim != 4);
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
auto y = Reshape(op.Write(), NQ, 3, NE);
auto y = Reshape(op.Write(), NQ, symmetric ? 3 : 4, NE);
MFEM_FORALL(e, NE,
{
@@ -47,12 +43,39 @@ void PAHcurlSetup2D(const int Q1D,
const double J21 = J(q,1,0,e);
const double J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double c_detJ1 = W[q] * coeff(0, q, e) / ((J11*J22)-(J21*J12));
const double c_detJ2 = coeffDim == 2 ? W[q] * coeff(1, q, e)
/ ((J11*J22)-(J21*J12)) : c_detJ1;
y(q,0,e) = (c_detJ2*J12*J12 + c_detJ1*J22*J22); // 1,1
y(q,1,e) = -(c_detJ2*J12*J11 + c_detJ1*J22*J21); // 1,2
y(q,2,e) = (c_detJ2*J11*J11 + c_detJ1*J21*J21); // 2,2
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient version
{
// First compute entries of R = MJ^{-T}, without det J factor.
const double M11 = coeff(0, q, e);
const double M12 = coeff(1, q, e);
const double M21 = symmetric ? M12 : coeff(2, q, e);
const double M22 = symmetric ? coeff(2, q, e) : coeff(3, q, e);
const double R11 = M11*J22 - M12*J12;
const double R21 = M21*J22 - M22*J12;
const double R12 = -M11*J21 + M12*J11;
const double R22 = -M21*J21 + M22*J11;
// Now set y to J^{-1}R.
const double w_detJ = W[q] / ((J11*J22)-(J21*J12));
y(q,0,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
y(q,1,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
y(q,2,e) = w_detJ * (symmetric ? (-J21*R12 + J11*R22) :
(J22*R12 - J12*R22)); // 2,2 or 1,2
if (!symmetric)
{
y(q,3,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
}
}
else // Vector or scalar coefficient version
{
const double c_detJ1 = W[q] * coeff(0, q, e) / ((J11*J22)-(J21*J12));
const double c_detJ2 = (coeffDim == 2) ? W[q] * coeff(1, q, e)
/ ((J11*J22)-(J21*J12)) : c_detJ1;
y(q,0,e) = (c_detJ2*J12*J12 + c_detJ1*J22*J22); // 1,1
y(q,1,e) = -(c_detJ2*J12*J11 + c_detJ1*J22*J21); // 1,2
y(q,2,e) = (c_detJ2*J11*J11 + c_detJ1*J21*J21); // 2,2
}
}
});
}
@@ -67,10 +90,11 @@ void PAHcurlSetup3D(const int Q1D,
Vector &op)
{
const int NQ = Q1D*Q1D*Q1D;
const bool symmetric = (coeffDim != 9);
auto W = w.Read();
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
auto y = Reshape(op.Write(), NQ, 6, NE);
auto y = Reshape(op.Write(), NQ, symmetric ? 6 : 9, NE);
MFEM_FORALL(e, NE,
{
@@ -89,9 +113,6 @@ void PAHcurlSetup3D(const int Q1D,
/* */ J21 * (J12 * J33 - J32 * J13) +
/* */ J31 * (J12 * J23 - J22 * J13);
const double w_detJ = W[q] / detJ;
const double D1 = coeff(0, q, e);
const double D2 = coeffDim == 3 ? coeff(1, q, e) : D1;
const double D3 = coeffDim == 3 ? coeff(2, q, e) : D1;
// adj(J)
const double A11 = (J22 * J33) - (J23 * J32);
const double A12 = (J32 * J13) - (J12 * J33);
@@ -102,13 +123,66 @@ void PAHcurlSetup3D(const int Q1D,
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) D adj(J)^T
y(q,0,e) = w_detJ * (D1*A11*A11 + D2*A12*A12 + D3*A13*A13); // 1,1
y(q,1,e) = w_detJ * (D1*A11*A21 + D2*A12*A22 + D3*A13*A23); // 2,1
y(q,2,e) = w_detJ * (D1*A11*A31 + D2*A12*A32 + D3*A13*A33); // 3,1
y(q,3,e) = w_detJ * (D1*A21*A21 + D2*A22*A22 + D3*A23*A23); // 2,2
y(q,4,e) = w_detJ * (D1*A21*A31 + D2*A22*A32 + D3*A23*A33); // 3,2
y(q,5,e) = w_detJ * (D1*A31*A31 + D2*A32*A32 + D3*A33*A33); // 3,3
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
{
// First compute entries of R = MJ^{-T} = M adj(J)^T, without det J factor.
const double M11 = coeff(0, q, e);
const double M12 = coeff(1, q, e);
const double M13 = coeff(2, q, e);
const double M21 = (!symmetric) ? coeff(3, q, e) : M12;
const double M22 = (!symmetric) ? coeff(4, q, e) : coeff(3, q, e);
const double M23 = (!symmetric) ? coeff(5, q, e) : coeff(4, q, e);
const double M31 = (!symmetric) ? coeff(6, q, e) : M13;
const double M32 = (!symmetric) ? coeff(7, q, e) : M23;
const double M33 = (!symmetric) ? coeff(8, q, e) : coeff(5, q, e);
const double R11 = M11*A11 + M12*A12 + M13*A13;
const double R12 = M11*A21 + M12*A22 + M13*A23;
const double R13 = M11*A31 + M12*A32 + M13*A33;
const double R21 = M21*A11 + M22*A12 + M23*A13;
const double R22 = M21*A21 + M22*A22 + M23*A23;
const double R23 = M21*A31 + M22*A32 + M23*A33;
const double R31 = M31*A11 + M32*A12 + M33*A13;
const double R32 = M31*A21 + M32*A22 + M33*A23;
const double R33 = M31*A31 + M32*A32 + M33*A33;
// Now set y to J^{-1} R = adj(J) R
y(q,0,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
const double Y12 = w_detJ * (A11*R12 + A12*R22 + A13*R32);
y(q,1,e) = Y12; // 1,2
y(q,2,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
const double Y21 = w_detJ * (A21*R11 + A22*R21 + A23*R31);
const double Y22 = w_detJ * (A21*R12 + A22*R22 + A23*R32);
const double Y23 = w_detJ * (A21*R13 + A22*R23 + A23*R33);
const double Y33 = w_detJ * (A31*R13 + A32*R23 + A33*R33);
y(q,3,e) = symmetric ? Y22 : Y21; // 2,2 or 2,1
y(q,4,e) = symmetric ? Y23 : Y22; // 2,3 or 2,2
y(q,5,e) = symmetric ? Y33 : Y23; // 3,3 or 2,3
if (!symmetric)
{
y(q,6,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
y(q,7,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
y(q,8,e) = Y33; // 3,3
}
}
else // Vector or scalar coefficient version
{
const double D1 = coeff(0, q, e);
const double D2 = coeffDim == 3 ? coeff(1, q, e) : D1;
const double D3 = coeffDim == 3 ? coeff(2, q, e) : D1;
// detJ J^{-1} D J^{-T} = (1/detJ) adj(J) D adj(J)^T
y(q,0,e) = w_detJ * (D1*A11*A11 + D2*A12*A12 + D3*A13*A13); // 1,1
y(q,1,e) = w_detJ * (D1*A11*A21 + D2*A12*A22 + D3*A13*A23); // 2,1
y(q,2,e) = w_detJ * (D1*A11*A31 + D2*A12*A32 + D3*A13*A33); // 3,1
y(q,3,e) = w_detJ * (D1*A21*A21 + D2*A22*A22 + D3*A23*A23); // 2,2
y(q,4,e) = w_detJ * (D1*A21*A31 + D2*A22*A32 + D3*A23*A33); // 3,2
y(q,5,e) = w_detJ * (D1*A31*A31 + D2*A32*A32 + D3*A33*A33); // 3,3
}
}
});
}
@@ -116,6 +190,7 @@ void PAHcurlSetup3D(const int Q1D,
void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
@@ -132,7 +207,7 @@ void PAHcurlMassApply2D(const int D1D,
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
auto Bot = Reshape(_Bot.Read(), D1D-1, Q1D);
auto Bct = Reshape(_Bct.Read(), D1D, Q1D);
auto op = Reshape(_op.Read(), Q1D, Q1D, 3, NE);
auto op = Reshape(_op.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
auto x = Reshape(_x.Read(), 2*(D1D-1)*D1D, NE);
auto y = Reshape(_y.ReadWrite(), 2*(D1D-1)*D1D, NE);
@@ -194,12 +269,13 @@ void PAHcurlMassApply2D(const int D1D,
for (int qx = 0; qx < Q1D; ++qx)
{
const double O11 = op(qx,qy,0,e);
const double O12 = op(qx,qy,1,e);
const double O22 = op(qx,qy,2,e);
const double O21 = op(qx,qy,1,e);
const double O12 = symmetric ? O21 : op(qx,qy,2,e);
const double O22 = symmetric ? op(qx,qy,2,e) : op(qx,qy,3,e);
const double massX = mass[qy][qx][0];
const double massY = mass[qy][qx][1];
mass[qy][qx][0] = (O11*massX)+(O12*massY);
mass[qy][qx][1] = (O12*massX)+(O22*massY);
mass[qy][qx][1] = (O21*massX)+(O22*massY);
}
}
@@ -215,7 +291,7 @@ void PAHcurlMassApply2D(const int D1D,
double massX[MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0;
massX[dx] = 0.0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
@@ -244,6 +320,7 @@ void PAHcurlMassApply2D(const int D1D,
void PAHcurlMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
@@ -254,7 +331,7 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
auto op = Reshape(_op.Read(), Q1D, Q1D, 3, NE);
auto op = Reshape(_op.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
auto diag = Reshape(_diag.ReadWrite(), 2*(D1D-1)*D1D, NE);
MFEM_FORALL(e, NE,
@@ -277,7 +354,8 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
{
const double wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
mass[qx] += wy * wy * ((c == 0) ? op(qx,qy,0,e) : op(qx,qy,2,e));
mass[qx] += wy * wy * ((c == 0) ? op(qx,qy,0,e) :
op(qx,qy,symmetric ? 2 : 3, e));
}
}
@@ -299,6 +377,7 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
void PAHcurlMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
@@ -313,7 +392,7 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
auto op = Reshape(_op.Read(), Q1D, Q1D, Q1D, 6, NE);
auto op = Reshape(_op.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
auto diag = Reshape(_diag.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
MFEM_FORALL(e, NE,
@@ -326,7 +405,8 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
const int D1Dy = (c == 1) ? D1D - 1 : D1D;
const int D1Dx = (c == 0) ? D1D - 1 : D1D;
const int opc = (c == 0) ? 0 : ((c == 1) ? 3 : 5);
const int opc = (c == 0) ? 0 : ((c == 1) ? (symmetric ? 3 : 4) :
(symmetric ? 5 : 8));
double mass[MAX_Q1D];
@@ -369,6 +449,7 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
@@ -388,7 +469,7 @@ void PAHcurlMassApply3D(const int D1D,
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
auto Bot = Reshape(_Bot.Read(), D1D-1, Q1D);
auto Bct = Reshape(_Bct.Read(), D1D, Q1D);
auto op = Reshape(_op.Read(), Q1D, Q1D, Q1D, 6, NE);
auto op = Reshape(_op.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
auto x = Reshape(_x.Read(), 3*(D1D-1)*D1D*D1D, NE);
auto y = Reshape(_y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
@@ -483,15 +564,18 @@ void PAHcurlMassApply3D(const int D1D,
const double O11 = op(qx,qy,qz,0,e);
const double O12 = op(qx,qy,qz,1,e);
const double O13 = op(qx,qy,qz,2,e);
const double O22 = op(qx,qy,qz,3,e);
const double O23 = op(qx,qy,qz,4,e);
const double O33 = op(qx,qy,qz,5,e);
const double O21 = symmetric ? O12 : op(qx,qy,qz,3,e);
const double O22 = symmetric ? op(qx,qy,qz,3,e) : op(qx,qy,qz,4,e);
const double O23 = symmetric ? op(qx,qy,qz,4,e) : op(qx,qy,qz,5,e);
const double O31 = symmetric ? O13 : op(qx,qy,qz,6,e);
const double O32 = symmetric ? O23 : op(qx,qy,qz,7,e);
const double O33 = symmetric ? op(qx,qy,qz,5,e) : op(qx,qy,qz,8,e);
const double massX = mass[qz][qy][qx][0];
const double massY = mass[qz][qy][qx][1];
const double massZ = mass[qz][qy][qx][2];
mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
mass[qz][qy][qx][1] = (O12*massX)+(O22*massY)+(O23*massZ);
mass[qz][qy][qx][2] = (O13*massX)+(O23*massY)+(O33*massZ);
mass[qz][qy][qx][1] = (O21*massX)+(O22*massY)+(O23*massZ);
mass[qz][qy][qx][2] = (O31*massX)+(O32*massY)+(O33*massZ);
}
}
}
@@ -512,7 +596,7 @@ void PAHcurlMassApply3D(const int D1D,
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] = 0;
massXY[dy][dx] = 0.0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
@@ -727,7 +811,7 @@ static void PACurlCurlApply2D(const int D1D,
{
for (int qx = 0; qx < Q1D; ++qx)
{
curl[qy][qx] = 0;
curl[qy][qx] = 0.0;
}
}
@@ -789,7 +873,7 @@ static void PACurlCurlApply2D(const int D1D,
double gradX[MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
gradX[dx] = 0;
gradX[dx] = 0.0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
@@ -1757,7 +1841,7 @@ void PAHcurlH1Apply3D(const int D1D,
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] = 0;
massXY[dy][dx] = 0.0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
@@ -1900,7 +1984,7 @@ void PAHcurlH1Apply2D(const int D1D,
double massX[MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0;
massX[dx] = 0.0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
@@ -1926,15 +2010,14 @@ void PAHcurlH1Apply2D(const int D1D,
}); // end of element loop
}
// PA H(curl) Mass Assemble 3D kernel
static void PAHcurlL2Setup3D(const int Q1D,
const int coeffDim,
const int NE,
const Array<double> &w,
Vector &_coeff,
Vector &op)
// PA H(curl) assemble kernel
void PAHcurlL2Setup(const int NQ,
const int coeffDim,
const int NE,
const Array<double> &w,
Vector &_coeff,
Vector &op)
{
const int NQ = Q1D*Q1D*Q1D;
auto W = w.Read();
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
auto y = Reshape(op.Write(), coeffDim, NQ, NE);
@@ -2035,7 +2118,7 @@ void MixedVectorCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
if (testType == mfem::FiniteElement::CURL &&
trialType == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlL2Setup3D(quad1D, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
PAHcurlL2Setup(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
}
else if (testType == mfem::FiniteElement::DIV &&
trialType == mfem::FiniteElement::CURL && dim == 3 &&
@@ -2346,7 +2429,7 @@ static void PAHcurlL2Apply3D(const int D1D,
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] = 0;
massXY[dy][dx] = 0.0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
@@ -2354,7 +2437,7 @@ static void PAHcurlL2Apply3D(const int D1D,
double massX[MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0;
massX[dx] = 0.0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
@@ -2425,7 +2508,7 @@ static void PAHcurlHdivApply3D(const int D1D,
auto Gc = Reshape(_Gc.Read(), Q1D, D1D);
auto op = Reshape(_op.Read(), Q1D, Q1D, Q1D, 6, NE);
auto x = Reshape(_x.Read(), 3*(D1D-1)*D1D*D1D, NE);
auto y = Reshape(_y.ReadWrite(), 3*(D1Dtest-1)*(D1Dtest-1)*D1D, NE);
auto y = Reshape(_y.ReadWrite(), 3*(D1Dtest-1)*(D1Dtest-1)*D1Dtest, NE);
MFEM_FORALL(e, NE,
{
@@ -2700,7 +2783,7 @@ static void PAHcurlHdivApply3D(const int D1D,
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] = 0;
massXY[dy][dx] = 0.0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
@@ -2708,7 +2791,7 @@ static void PAHcurlHdivApply3D(const int D1D,
double massX[HCURL_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0;
massX[dx] = 0.0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
@@ -2844,7 +2927,7 @@ void MixedVectorWeakCurlIntegrator::AssemblePA(const FiniteElementSpace
if (trialType == mfem::FiniteElement::CURL && dim == 3)
{
PAHcurlL2Setup3D(quad1D, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
PAHcurlL2Setup(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
}
else
{
-5
View File
@@ -23,11 +23,6 @@ using namespace std;
namespace mfem
{
// Local maximum size of dofs and quads in 1D
constexpr int HDIV_MAX_D1D = 5;
constexpr int HDIV_MAX_Q1D = 6;
// PA H(div) Mass Assemble 2D kernel
void PAHdivSetup2D(const int Q1D,
const int NE,
+46 -31
View File
@@ -92,49 +92,64 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
if (dim==2)
{
const int NE = ne;
const int NQ = nq;
const int Q1D = quad1D;
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);
auto v = Reshape(pa_data.Write(), NQ, NE);
MFEM_FORALL(e, NE,
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,2,2,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D, NE);
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
{
for (int q = 0; q < NQ; ++q)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const double J11 = J(q,0,0,e);
const double J12 = J(q,1,0,e);
const double J21 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double detJ = (J11*J22)-(J21*J12);
const double coeff = const_c ? C(0,0) : C(q,e);
v(q,e) = w[q] * coeff * detJ;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const double J11 = J(qx,qy,0,0,e);
const double J12 = J(qx,qy,1,0,e);
const double J21 = J(qx,qy,0,1,e);
const double J22 = J(qx,qy,1,1,e);
const double detJ = (J11*J22)-(J21*J12);
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
v(qx,qy,e) = W(qx,qy) * coeff * detJ;
}
}
});
}
if (dim==3)
{
const int NE = ne;
const int NQ = nq;
const int Q1D = quad1D;
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);
auto v = Reshape(pa_data.Write(), NQ,NE);
MFEM_FORALL(e, NE,
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D,Q1D);
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,Q1D,3,3,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D,Q1D,NE);
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
{
for (int q = 0; q < NQ; ++q)
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const double J11 = J(q,0,0,e), J12 = J(q,0,1,e), J13 = J(q,0,2,e);
const double J21 = J(q,1,0,e), J22 = J(q,1,1,e), J23 = J(q,1,2,e);
const double J31 = J(q,2,0,e), J32 = J(q,2,1,e), 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);
v(q,e) = W[q] * coeff * detJ;
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
const double J11 = J(qx,qy,qz,0,0,e);
const double J21 = J(qx,qy,qz,1,0,e);
const double J31 = J(qx,qy,qz,2,0,e);
const double J12 = J(qx,qy,qz,0,1,e);
const double J22 = J(qx,qy,qz,1,1,e);
const double J32 = J(qx,qy,qz,2,1,e);
const double J13 = J(qx,qy,qz,0,2,e);
const double J23 = J(qx,qy,qz,1,2,e);
const double J33 = J(qx,qy,qz,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,0,0) : C(qx,qy,qz,e);
v(qx,qy,qz,e) = W(qx,qy,qz) * coeff * detJ;
}
}
}
});
}
+701 -35
View File
@@ -34,6 +34,7 @@ void PAHcurlSetup3D(const int Q1D,
void PAHcurlMassAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
@@ -42,6 +43,7 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
void PAHcurlMassAssembleDiagonal3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Vector &_op,
@@ -50,6 +52,7 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
@@ -61,6 +64,7 @@ void PAHcurlMassApply2D(const int D1D,
void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
@@ -143,20 +147,573 @@ void PAHdivMassApply3D(const int D1D,
const Vector &_x,
Vector &_y);
void PAHcurlL2Setup(const int NQ,
const int coeffDim,
const int NE,
const Array<double> &w,
Vector &_coeff,
Vector &op);
// PA H(curl) x H(div) mass assemble 3D kernel, with factor
// dF^{-1} C dF for a vector or matrix coefficient C.
// If transpose, use dF^T C dF^{-T} for H(div) x H(curl).
void PAHcurlHdivSetup3D(const int Q1D,
const int coeffDim,
const int NE,
const bool transpose,
const Array<double> &_w,
const Vector &j,
Vector &_coeff,
Vector &op)
{
const int NQ = Q1D*Q1D*Q1D;
const bool symmetric = (coeffDim != 9);
auto W = _w.Read();
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
auto y = Reshape(op.Write(), 9, NQ, NE);
const int i11 = 0;
const int i12 = transpose ? 3 : 1;
const int i13 = transpose ? 6 : 2;
const int i21 = transpose ? 1 : 3;
const int i22 = 4;
const int i23 = transpose ? 7 : 5;
const int i31 = transpose ? 2 : 6;
const int i32 = transpose ? 5 : 7;
const int i33 = 8;
MFEM_FORALL(e, NE,
{
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 w_detJ = W[q] / 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);
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
{
// First compute entries of R = MJ
const double M11 = (!symmetric) ? coeff(i11, q, e) : coeff(0, q, e);
const double M12 = (!symmetric) ? coeff(i12, q, e) : coeff(1, q, e);
const double M13 = (!symmetric) ? coeff(i13, q, e) : coeff(2, q, e);
const double M21 = (!symmetric) ? coeff(i21, q, e) : M12;
const double M22 = (!symmetric) ? coeff(i22, q, e) : coeff(3, q, e);
const double M23 = (!symmetric) ? coeff(i23, q, e) : coeff(4, q, e);
const double M31 = (!symmetric) ? coeff(i31, q, e) : M13;
const double M32 = (!symmetric) ? coeff(i32, q, e) : M23;
const double M33 = (!symmetric) ? coeff(i33, q, e) : coeff(5, q, e);
const double R11 = M11*J11 + M12*J12 + M13*J13;
const double R12 = M11*J21 + M12*J22 + M13*J23;
const double R13 = M11*J31 + M12*J32 + M13*J33;
const double R21 = M21*J11 + M22*J12 + M23*J13;
const double R22 = M21*J21 + M22*J22 + M23*J23;
const double R23 = M21*J31 + M22*J32 + M23*J33;
const double R31 = M31*J11 + M32*J12 + M33*J13;
const double R32 = M31*J21 + M32*J22 + M33*J23;
const double R33 = M31*J31 + M32*J32 + M33*J33;
// Now set y to detJ J^{-1} R = adj(J) R
y(i11,q,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
y(i12,q,e) = w_detJ * (A11*R12 + A12*R22 + A13*R32); // 1,2
y(i13,q,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
y(i21,q,e) = w_detJ * (A21*R11 + A22*R21 + A23*R31); // 2,1
y(i22,q,e) = w_detJ * (A21*R12 + A22*R22 + A23*R32); // 2,2
y(i23,q,e) = w_detJ * (A21*R13 + A22*R23 + A23*R33); // 2,3
y(i31,q,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
y(i32,q,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
y(i33,q,e) = w_detJ * (A31*R13 + A32*R23 + A33*R33); // 3,3
}
else if (coeffDim == 3) // Vector coefficient version
{
const double D1 = coeff(0, q, e);
const double D2 = coeff(1, q, e);
const double D3 = coeff(2, q, e);
// detJ J^{-1} DJ = adj(J) DJ
y(i11,q,e) = w_detJ * (D1*A11*J11 + D2*A12*J21 + D3*A13*J31); // 1,1
y(i12,q,e) = w_detJ * (D1*A11*J12 + D2*A12*J22 + D3*A13*J32); // 1,2
y(i13,q,e) = w_detJ * (D1*A11*J13 + D2*A12*J23 + D3*A13*J33); // 1,3
y(i21,q,e) = w_detJ * (D1*A21*J11 + D2*A22*J21 + D3*A23*J31); // 2,1
y(i22,q,e) = w_detJ * (D1*A21*J12 + D2*A22*J22 + D3*A23*J32); // 2,2
y(i23,q,e) = w_detJ * (D1*A21*J13 + D2*A22*J23 + D3*A23*J33); // 2,3
y(i31,q,e) = w_detJ * (D1*A31*J11 + D2*A32*J21 + D3*A33*J31); // 3,1
y(i32,q,e) = w_detJ * (D1*A31*J12 + D2*A32*J22 + D3*A33*J32); // 3,2
y(i33,q,e) = w_detJ * (D1*A31*J13 + D2*A32*J23 + D3*A33*J33); // 3,3
}
}
});
}
// PA H(curl) x H(div) mass assemble 2D kernel, with factor
// dF^{-1} C dF for a vector or matrix coefficient C.
// If transpose, use dF^T C dF^{-T} for H(div) x H(curl).
void PAHcurlHdivSetup2D(const int Q1D,
const int coeffDim,
const int NE,
const bool transpose,
const Array<double> &_w,
const Vector &j,
Vector &_coeff,
Vector &op)
{
const int NQ = Q1D*Q1D;
const bool symmetric = (coeffDim != 4);
auto W = _w.Read();
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
auto y = Reshape(op.Write(), 4, NQ, NE);
const int i11 = 0;
const int i12 = transpose ? 2 : 1;
const int i21 = transpose ? 1 : 2;
const int i22 = 3;
MFEM_FORALL(e, NE,
{
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 J12 = J(q,0,1,e);
const double J22 = J(q,1,1,e);
const double w_detJ = W[q] / (J11*J22) - (J21*J12);
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient version
{
// First compute entries of R = MJ
const double M11 = coeff(i11, q, e);
const double M12 = (!symmetric) ? coeff(i12, q, e) : coeff(1, q, e);
const double M21 = (!symmetric) ? coeff(i21, q, e) : M12;
const double M22 = (!symmetric) ? coeff(i22, q, e) : coeff(2, q, e);
const double R11 = M11*J11 + M12*J21;
const double R12 = M11*J12 + M12*J22;
const double R21 = M21*J11 + M22*J21;
const double R22 = M21*J12 + M22*J22;
// Now set y to J^{-1} R
y(i11,q,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
y(i12,q,e) = w_detJ * ( J22*R12 - J12*R22); // 1,2
y(i21,q,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
y(i22,q,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
}
else if (coeffDim == 2) // Vector coefficient version
{
const double D1 = coeff(0, q, e);
const double D2 = coeff(1, q, e);
const double R11 = D1*J11;
const double R12 = D1*J12;
const double R21 = D2*J21;
const double R22 = D2*J22;
y(i11,q,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
y(i12,q,e) = w_detJ * ( J22*R12 - J12*R22); // 1,2
y(i21,q,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
y(i22,q,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
}
}
});
}
// Mass operator for H(curl) and H(div) functions, using Piola transformations
// u = dF^{-T} \hat{u} in H(curl), v = (1 / det dF) dF \hat{v} in H(div).
void PAHcurlHdivMassApply3D(const int D1D,
const int D1Dtest,
const int Q1D,
const int NE,
const bool scalarCoeff,
const bool trialHcurl,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
{
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 3;
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
auto Bot = Reshape(_Bot.Read(), D1Dtest-1, Q1D);
auto Bct = Reshape(_Bct.Read(), D1Dtest, Q1D);
auto op = Reshape(_op.Read(), scalarCoeff ? 1 : 9, Q1D, Q1D, Q1D, NE);
auto x = Reshape(_x.Read(), 3*(D1D-1)*D1D*(trialHcurl ? D1D : D1D-1), NE);
auto y = Reshape(_y.ReadWrite(), 3*(D1Dtest-1)*D1Dtest*
(trialHcurl ? D1Dtest-1 : D1Dtest), NE);
MFEM_FORALL(e, NE,
{
double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
for (int c = 0; c < VDIM; ++c)
{
mass[qz][qy][qx][c] = 0.0;
}
}
}
}
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z trial components
{
const int D1Dz = trialHcurl ? ((c == 2) ? D1D - 1 : D1D) :
((c == 2) ? D1D : D1D - 1);
const int D1Dy = trialHcurl ? ((c == 1) ? D1D - 1 : D1D) :
((c == 1) ? D1D : D1D - 1);
const int D1Dx = trialHcurl ? ((c == 0) ? D1D - 1 : D1D) :
((c == 0) ? D1D : D1D - 1);
for (int dz = 0; dz < D1Dz; ++dz)
{
double massXY[MAX_Q1D][MAX_Q1D];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
massXY[qy][qx] = 0.0;
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
double massX[MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] = 0.0;
}
for (int dx = 0; dx < D1Dx; ++dx)
{
const double t = x(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] += t * (trialHcurl ? ((c == 0) ? Bo(qx,dx) : Bc(qx,dx)) :
((c == 0) ? Bc(qx,dx) : Bo(qx,dx)));
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = trialHcurl ? ((c == 1) ? Bo(qy,dy) : Bc(qy,dy)) :
((c == 1) ? Bc(qy,dy) : Bo(qy,dy));
for (int qx = 0; qx < Q1D; ++qx)
{
const double wx = massX[qx];
massXY[qy][qx] += wx * wy;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
const double wz = trialHcurl ? ((c == 2) ? Bo(qz,dz) : Bc(qz,dz)) :
((c == 2) ? Bc(qz,dz) : Bo(qz,dz));
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
mass[qz][qy][qx][c] += massXY[qy][qx] * wz;
}
}
}
}
osc += D1Dx * D1Dy * D1Dz;
} // loop (c) over components
// Apply D operator.
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const double O11 = op(0,qx,qy,qz,e);
const double O12 = scalarCoeff ? 0.0 : op(1,qx,qy,qz,e);
const double O13 = scalarCoeff ? 0.0 : op(2,qx,qy,qz,e);
const double O21 = scalarCoeff ? 0.0 : op(3,qx,qy,qz,e);
const double O22 = scalarCoeff ? O11 : op(4,qx,qy,qz,e);
const double O23 = scalarCoeff ? 0.0 : op(5,qx,qy,qz,e);
const double O31 = scalarCoeff ? 0.0 : op(6,qx,qy,qz,e);
const double O32 = scalarCoeff ? 0.0 : op(7,qx,qy,qz,e);
const double O33 = scalarCoeff ? O11 : op(8,qx,qy,qz,e);
const double massX = mass[qz][qy][qx][0];
const double massY = mass[qz][qy][qx][1];
const double massZ = mass[qz][qy][qx][2];
mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
mass[qz][qy][qx][1] = (O21*massX)+(O22*massY)+(O23*massZ);
mass[qz][qy][qx][2] = (O31*massX)+(O32*massY)+(O33*massZ);
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
double massXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z test components
{
const int D1Dz = trialHcurl ? ((c == 2) ? D1Dtest : D1Dtest - 1) :
((c == 2) ? D1Dtest - 1 : D1Dtest);
const int D1Dy = trialHcurl ? ((c == 1) ? D1Dtest : D1Dtest - 1) :
((c == 1) ? D1Dtest - 1 : D1Dtest);
const int D1Dx = trialHcurl ? ((c == 0) ? D1Dtest : D1Dtest - 1) :
((c == 0) ? D1Dtest - 1 : D1Dtest);
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] = 0.0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
double massX[HDIV_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0.0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] += mass[qz][qy][qx][c] * (trialHcurl ?
((c == 0) ? Bct(dx,qx) : Bot(dx,qx)) :
((c == 0) ? Bot(dx,qx) : Bct(dx,qx)));
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
const double wy = trialHcurl ? ((c == 1) ? Bct(dy,qy) : Bot(dy,qy)) :
((c == 1) ? Bot(dy,qy) : Bct(dy,qy));
for (int dx = 0; dx < D1Dx; ++dx)
{
massXY[dy][dx] += massX[dx] * wy;
}
}
}
for (int dz = 0; dz < D1Dz; ++dz)
{
const double wz = trialHcurl ? ((c == 2) ? Bct(dz,qz) : Bot(dz,qz)) :
((c == 2) ? Bot(dz,qz) : Bct(dz,qz));
for (int dy = 0; dy < D1Dy; ++dy)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) +=
massXY[dy][dx] * wz;
}
}
}
osc += D1Dx * D1Dy * D1Dz;
} // loop c
} // loop qz
}); // end of element loop
}
// Mass operator for H(curl) and H(div) functions, using Piola transformations
// u = dF^{-T} \hat{u} in H(curl), v = (1 / det dF) dF \hat{v} in H(div).
void PAHcurlHdivMassApply2D(const int D1D,
const int D1Dtest,
const int Q1D,
const int NE,
const bool scalarCoeff,
const bool trialHcurl,
const Array<double> &_Bo,
const Array<double> &_Bc,
const Array<double> &_Bot,
const Array<double> &_Bct,
const Vector &_op,
const Vector &_x,
Vector &_y)
{
constexpr static int MAX_D1D = HCURL_MAX_D1D;
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
constexpr static int VDIM = 2;
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
auto Bot = Reshape(_Bot.Read(), D1Dtest-1, Q1D);
auto Bct = Reshape(_Bct.Read(), D1Dtest, Q1D);
auto op = Reshape(_op.Read(), scalarCoeff ? 1 : 4, Q1D, Q1D, NE);
auto x = Reshape(_x.Read(), 2*(D1D-1)*D1D, NE);
auto y = Reshape(_y.ReadWrite(), 2*(D1Dtest-1)*D1Dtest, NE);
MFEM_FORALL(e, NE,
{
double mass[MAX_Q1D][MAX_Q1D][VDIM];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
for (int c = 0; c < VDIM; ++c)
{
mass[qy][qx][c] = 0.0;
}
}
}
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y trial components
{
const int D1Dy = trialHcurl ? ((c == 1) ? D1D - 1 : D1D) :
((c == 1) ? D1D : D1D - 1);
const int D1Dx = trialHcurl ? ((c == 0) ? D1D - 1 : D1D) :
((c == 0) ? D1D : D1D - 1);
for (int dy = 0; dy < D1Dy; ++dy)
{
double massX[MAX_Q1D];
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] = 0.0;
}
for (int dx = 0; dx < D1Dx; ++dx)
{
const double t = x(dx + (dy * D1Dx) + osc, e);
for (int qx = 0; qx < Q1D; ++qx)
{
massX[qx] += t * (trialHcurl ? ((c == 0) ? Bo(qx,dx) : Bc(qx,dx)) :
((c == 0) ? Bc(qx,dx) : Bo(qx,dx)));
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const double wy = trialHcurl ? ((c == 1) ? Bo(qy,dy) : Bc(qy,dy)) :
((c == 1) ? Bc(qy,dy) : Bo(qy,dy));
for (int qx = 0; qx < Q1D; ++qx)
{
mass[qy][qx][c] += massX[qx] * wy;
}
}
}
osc += D1Dx * D1Dy;
} // loop (c) over components
// Apply D operator.
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const double O11 = op(0,qx,qy,e);
const double O12 = scalarCoeff ? 0.0 : op(1,qx,qy,e);
const double O21 = scalarCoeff ? 0.0 : op(2,qx,qy,e);
const double O22 = scalarCoeff ? O11 : op(3,qx,qy,e);
const double massX = mass[qy][qx][0];
const double massY = mass[qy][qx][1];
mass[qy][qx][0] = (O11*massX)+(O12*massY);
mass[qy][qx][1] = (O21*massX)+(O22*massY);
}
}
osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y test components
{
const int D1Dy = trialHcurl ? ((c == 1) ? D1Dtest : D1Dtest - 1) :
((c == 1) ? D1Dtest - 1 : D1Dtest);
const int D1Dx = trialHcurl ? ((c == 0) ? D1Dtest : D1Dtest - 1) :
((c == 0) ? D1Dtest - 1 : D1Dtest);
for (int qy = 0; qy < Q1D; ++qy)
{
double massX[HDIV_MAX_D1D];
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] = 0.0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
for (int dx = 0; dx < D1Dx; ++dx)
{
massX[dx] += mass[qy][qx][c] * (trialHcurl ?
((c == 0) ? Bct(dx,qx) : Bot(dx,qx)) :
((c == 0) ? Bot(dx,qx) : Bct(dx,qx)));
}
}
for (int dy = 0; dy < D1Dy; ++dy)
{
const double wy = trialHcurl ? ((c == 1) ? Bct(dy,qy) : Bot(dy,qy)) :
((c == 1) ? Bot(dy,qy) : Bct(dy,qy));
for (int dx = 0; dx < D1Dx; ++dx)
{
y(dx + (dy * D1Dx) + osc, e) += massX[dx] * wy;
}
}
}
osc += D1Dx * D1Dy;
} // loop c
}); // end of element loop
}
void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assumes tensor-product elements
Mesh *mesh = fes.GetMesh();
const FiniteElement *fel = fes.GetFE(0);
AssemblePA(fes, fes);
}
const VectorTensorFiniteElement *el =
dynamic_cast<const VectorTensorFiniteElement*>(fel);
MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes)
{
// Assumes tensor-product elements
Mesh *mesh = trial_fes.GetMesh();
const FiniteElement *trial_fel = trial_fes.GetFE(0);
const VectorTensorFiniteElement *trial_el =
dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
const FiniteElement *test_fel = test_fes.GetFE(0);
const VectorTensorFiniteElement *test_el =
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
const IntegrationRule *ir
= IntRule ? IntRule : &MassIntegrator::GetRule(*el, *el,
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
*mesh->GetElementTransformation(0));
const int dims = el->GetDim();
const int dims = trial_el->GetDim();
MFEM_VERIFY(dims == 2 || dims == 3, "");
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
@@ -164,36 +721,101 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "");
ne = fes.GetNE();
ne = trial_fes.GetNE();
MFEM_VERIFY(ne == test_fes.GetNE(),
"Different meshes for test and trial spaces");
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
mapsC = &trial_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsO = &trial_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1D = mapsC->ndof;
quad1D = mapsC->nqpt;
mapsCtest = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
mapsOtest = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
dofs1Dtest = mapsCtest->ndof;
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
trial_fetype = trial_el->GetDerivType();
test_fetype = test_el->GetDerivType();
const int coeffDim = VQ ? VQ->GetVDim() : 1;
const int MQsymmDim = MQ ? (MQ->GetWidth() * (MQ->GetWidth() + 1)) / 2 : 0;
const int MQfullDim = MQ ? (MQ->GetHeight() * MQ->GetWidth()) : 0;
const int MQdim = MQ ? (MQ->IsSymmetric() ? MQsymmDim : MQfullDim) : 0;
const int coeffDim = MQ ? MQdim : (VQ ? VQ->GetVDim() : 1);
symmetric = MQ ? MQ->IsSymmetric() : true;
const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
if ((trial_curl && test_div) || (trial_div && test_curl))
pa_data.SetSize((coeffDim == 1 ? 1 : dim*dim) * nq * ne,
Device::GetMemoryType());
else
pa_data.SetSize((symmetric ? symmDims : MQfullDim) * nq * ne,
Device::GetMemoryType());
Vector coeff(coeffDim * ne * nq);
coeff = 1.0;
auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
if (Q || VQ)
if (Q || VQ || MQ)
{
Vector D(VQ ? coeffDim : 0);
DenseMatrix M;
Vector Msymm;
if (MQ)
{
if (symmetric)
{
Msymm.SetSize(MQsymmDim);
}
else
{
M.SetSize(dim);
}
}
if (VQ)
{
MFEM_VERIFY(coeffDim == dim, "");
}
if (MQ)
{
MFEM_VERIFY(coeffDim == MQdim, "");
MFEM_VERIFY(MQ->GetHeight() == dim && MQ->GetWidth() == dim, "");
}
for (int e=0; e<ne; ++e)
{
ElementTransformation *tr = mesh->GetElementTransformation(e);
for (int p=0; p<nq; ++p)
{
if (VQ)
if (MQ)
{
if (MQ->IsSymmetric())
{
MQ->EvalSymmetric(Msymm, *tr, ir->IntPoint(p));
for (int i=0; i<MQsymmDim; ++i)
{
coeffh(i, p, e) = Msymm[i];
}
}
else
{
MQ->Eval(M, *tr, ir->IntPoint(p));
for (int i=0; i<dim; ++i)
for (int j=0; j<dim; ++j)
{
coeffh(j+(i*dim), p, e) = M(i,j);
}
}
}
else if (VQ)
{
VQ->Eval(D, *tr, ir->IntPoint(p));
for (int i=0; i<coeffDim; ++i)
@@ -209,28 +831,44 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
}
}
fetype = el->GetDerivType();
if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
if (trial_curl && test_curl && dim == 3)
{
PAHcurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
else if (trial_curl && test_curl && dim == 2)
{
PAHcurlSetup2D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 3)
else if (trial_div && test_div && dim == 3)
{
PAHdivSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 2)
else if (trial_div && test_div && dim == 2)
{
PAHdivSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
coeff, pa_data);
}
else if (((trial_curl && test_div) || (trial_div && test_curl)) &&
test_fel->GetOrder() == trial_fel->GetOrder())
{
if (coeffDim == 1)
{
PAHcurlL2Setup(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
}
else
{
const bool tr = (trial_div && test_curl);
if (dim == 3)
PAHcurlHdivSetup3D(quad1D, coeffDim, ne, tr, ir->GetWeights(),
geom->J, coeff, pa_data);
else
PAHcurlHdivSetup2D(quad1D, coeffDim, ne, tr, ir->GetWeights(),
geom->J, coeff, pa_data);
}
}
else
{
MFEM_ABORT("Unknown kernel.");
@@ -241,12 +879,13 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
{
if (dim == 3)
{
if (fetype == mfem::FiniteElement::CURL)
if (trial_fetype == mfem::FiniteElement::CURL && test_fetype == trial_fetype)
{
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne,
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, pa_data, diag);
}
else if (fetype == mfem::FiniteElement::DIV)
else if (trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == trial_fetype)
{
PAHdivMassAssembleDiagonal3D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
@@ -258,12 +897,13 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
}
else
{
if (fetype == mfem::FiniteElement::CURL)
if (trial_fetype == mfem::FiniteElement::CURL && test_fetype == trial_fetype)
{
PAHcurlMassAssembleDiagonal2D(dofs1D, quad1D, ne,
PAHcurlMassAssembleDiagonal2D(dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, pa_data, diag);
}
else if (fetype == mfem::FiniteElement::DIV)
else if (trial_fetype == mfem::FiniteElement::DIV &&
test_fetype == trial_fetype)
{
PAHdivMassAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->B, pa_data, diag);
@@ -277,18 +917,37 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
if (dim == 3)
{
if (fetype == mfem::FiniteElement::CURL)
if (trial_curl && test_curl)
{
PAHcurlMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
PAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
}
else if (fetype == mfem::FiniteElement::DIV)
else if (trial_div && test_div)
{
PAHdivMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if (trial_curl && test_div)
{
const bool scalarCoeff = !(VQ || MQ);
PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
true, mapsO->B, mapsC->B, mapsOtest->Bt,
mapsCtest->Bt, pa_data, x, y);
}
else if (trial_div && test_curl)
{
const bool scalarCoeff = !(VQ || MQ);
PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
false, mapsO->B, mapsC->B, mapsOtest->Bt,
mapsCtest->Bt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
@@ -296,16 +955,23 @@ void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
}
else
{
if (fetype == mfem::FiniteElement::CURL)
if (trial_curl && test_curl)
{
PAHcurlMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
PAHcurlMassApply2D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
}
else if (fetype == mfem::FiniteElement::DIV)
else if (trial_div && test_div)
{
PAHdivMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if ((trial_curl && test_div) || (trial_div && test_curl))
{
const bool scalarCoeff = !(VQ || MQ);
PAHcurlHdivMassApply2D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
trial_curl, mapsO->B, mapsC->B, mapsOtest->Bt,
mapsCtest->Bt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
+25
View File
@@ -319,6 +319,31 @@ void MatrixFunctionCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
}
}
void MatrixFunctionCoefficient::EvalSymmetric(Vector &K,
ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_VERIFY(symmetric && height == width && height < 4 && SymmFunction,
"MatrixFunctionCoefficient is not symmetric");
double x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
K.SetSize((width * (width + 1)) / 2); // 1x1: 1, 2x2: 3, 3x3: 6
if (SymmFunction)
{
(*SymmFunction)(transip, K);
}
if (Q)
{
K *= Q->Eval(T, ip, GetTime());
}
}
MatrixArrayCoefficient::MatrixArrayCoefficient (int dim)
: MatrixCoefficient (dim)
{
+34 -2
View File
@@ -695,13 +695,16 @@ class MatrixCoefficient
protected:
int height, width;
double time;
bool symmetric;
public:
/// Construct a dim x dim matrix coefficient.
explicit MatrixCoefficient(int dim) { height = width = dim; time = 0.; }
explicit MatrixCoefficient(int dim, bool symm=false)
{ height = width = dim; time = 0.; symmetric = symm; }
/// Construct a h x w matrix coefficient.
MatrixCoefficient(int h, int w) : height(h), width(w), time(0.) { }
MatrixCoefficient(int h, int w, bool symm=false) :
height(h), width(w), time(0.), symmetric(symm) { }
/// Set the time for time dependent coefficients
void SetTime(double t) { time = t; }
@@ -718,6 +721,9 @@ public:
/// For backward compatibility get the width of the matrix.
int GetVDim() const { return width; }
void SetSymmetric(bool s) { symmetric = s; }
bool IsSymmetric() const { return symmetric; }
/** @brief Evaluate the matrix coefficient in the element described by @a T
at the point @a ip, storing the result in @a K. */
/** @note When this method is called, the caller must make sure that the
@@ -726,6 +732,15 @@ public:
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip) = 0;
/** @brief Evaluate the upper triangular entries of the matrix coefficient
in the symmetric case, similarly to Eval. Matrix entry (i,j) is stored
in K[j - i + os_i] for 0 <= i <= j < width, os_0 = 0,
os_{i+1} = os_i + width - i. That is, K = {M(0,0), ..., M(0,w-1),
M(1,1), ..., M(1,w-1), ..., M(w-1,w-1) with w = width. */
virtual void EvalSymmetric(Vector &K, ElementTransformation &T,
const IntegrationPoint &ip)
{ mfem_error("MatrixCoefficient::EvalSymmetric"); }
virtual ~MatrixCoefficient() { }
};
@@ -753,6 +768,7 @@ class MatrixFunctionCoefficient : public MatrixCoefficient
{
private:
void (*Function)(const Vector &, DenseMatrix &);
void (*SymmFunction)(const Vector &, Vector &);
void (*TDFunction)(const Vector &, double, DenseMatrix &);
Coefficient *Q;
DenseMatrix mat;
@@ -790,10 +806,26 @@ public:
mat.SetSize(0);
}
/// Construct a symmetric square matrix coefficient from a C-function
/// defining a vector function used by EvalSymmetric
MatrixFunctionCoefficient(int dim, void (*F)(const Vector &, Vector &),
Coefficient *q = NULL)
: MatrixCoefficient(dim, true), Q(q)
{
SymmFunction = F;
Function = NULL;
TDFunction = NULL;
mat.SetSize(0);
}
/// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
/// Evaluate the symmetric matrix coefficient at @a ip.
virtual void EvalSymmetric(Vector &K, ElementTransformation &T,
const IntegrationPoint &ip);
virtual ~MatrixFunctionCoefficient() { }
};
+17 -3
View File
@@ -77,6 +77,9 @@ public:
ElementTransformation();
/** @brief Force the reevaluation of the Jacobian in the next call. */
void Reset() { EvalState = 0; }
/** @brief Set the integration point @a ip that weights and Jacobians will
be evaluated at. */
void SetIntPoint(const IntegrationPoint *ip)
@@ -357,9 +360,17 @@ private:
// Evaluate the Hessian of the transformation at the IntPoint and store it
// in d2Fdx2.
virtual const DenseMatrix &EvalHessian();
public:
IsoparametricTransformation() : FElem(NULL) {}
/// Set the element that will be used to compute the transformations
void SetFE(const FiniteElement *FE) { FElem = FE; geom = FE->GetGeomType(); }
void SetFE(const FiniteElement *FE)
{
MFEM_ASSERT(FE != NULL, "Must provide a valid FiniteElement object!");
EvalState = (FE != FElem) ? 0 : EvalState;
FElem = FE; geom = FE->GetGeomType();
}
/// Get the current element used to compute the transformations
const FiniteElement* GetFE() const { return FElem; }
@@ -374,12 +385,15 @@ public:
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; }
void SetPointMat(const DenseMatrix &pm) { PointMat = pm; EvalState = 0; }
/// Return the stored point matrix.
const DenseMatrix &GetPointMat() const { return PointMat; }
/// Write access to the stored point matrix. Use with caution.
/// @brief Write access to the stored point matrix. Use with caution.
/** If the point matrix is altered using this member function the Reset
function should also be called to force the reevaluation of the
Jacobian, etc.. */
DenseMatrix &GetPointMat() { return PointMat; }
/// Set the FiniteElement Geometry for the reference elements being used.
+167
View File
@@ -7034,6 +7034,95 @@ void Poly_1D::Basis::Eval(const double y, Vector &u, Vector &d) const
}
}
void Poly_1D::Basis::Eval(const double y, Vector &u, Vector &d,
Vector &d2) const
{
MFEM_VERIFY(etype == Barycentric,
"Basis::Eval with second order derivatives not implemented for"
" etype = " << etype);
switch (etype)
{
case ChangeOfBasis:
{
CalcBasis(Ai.Width() - 1, y, x, w);
Ai.Mult(x, u);
Ai.Mult(w, d);
// set d2 (not implemented yet)
break;
}
case Barycentric:
{
int i, k, p = x.Size() - 1;
double l, lp, lp2, lk, sk, si, sk2;
if (p == 0)
{
u(0) = 1.0;
d(0) = 0.0;
d2(0) = 0.0;
return;
}
lk = 1.0;
for (k = 0; k < p; k++)
{
if (y >= (x(k) + x(k+1))/2)
{
lk *= y - x(k);
}
else
{
for (i = k+1; i <= p; i++)
{
lk *= y - x(i);
}
break;
}
}
l = lk * (y - x(k));
sk = 0.0;
sk2 = 0.0;
for (i = 0; i < k; i++)
{
si = 1.0/(y - x(i));
sk += si;
sk2 -= si * si;
u(i) = l * si * w(i);
}
u(k) = lk * w(k);
for (i++; i <= p; i++)
{
si = 1.0/(y - x(i));
sk += si;
sk2 -= si * si;
u(i) = l * si * w(i);
}
lp = l * sk + lk;
lp2 = lp * sk + l * sk2 + sk * lk;
for (i = 0; i < k; i++)
{
d(i) = (lp * w(i) - u(i))/(y - x(i));
d2(i) = (lp2 * w(i) - 2 * d(i))/(y - x(i));
}
d(k) = sk * u(k);
d2(k) = sk2 * u(k) + sk * d(k);
for (i++; i <= p; i++)
{
d(i) = (lp * w(i) - u(i))/(y - x(i));
d2(i) = (lp2 * w(i) - 2 * d(i))/(y - x(i));
}
break;
}
case Positive:
CalcBernstein(x.Size() - 1, y, u, d);
break;
default: break;
}
}
const int *Poly_1D::Binom(const int p)
{
if (binom.NumCols() <= p)
@@ -7589,6 +7678,7 @@ H1_SegmentElement::H1_SegmentElement(const int p, const int btype)
#ifndef MFEM_THREAD_SAFE
shape_x.SetSize(p+1);
dshape_x.SetSize(p+1);
d2shape_x.SetSize(p+1);
#endif
Nodes.IntPoint(0).x = cp[0];
@@ -7637,6 +7727,25 @@ void H1_SegmentElement::CalcDShape(const IntegrationPoint &ip,
}
}
void H1_SegmentElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), dshape_x(p+1), d2shape_x(p+1);
#endif
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
Hessian(0,0) = d2shape_x(0);
Hessian(1,0) = d2shape_x(p);
for (int i = 1; i < p; i++)
{
Hessian(i+1,0) = d2shape_x(i);
}
}
void H1_SegmentElement::ProjectDelta(int vertex, Vector &dofs) const
{
const int p = order;
@@ -7677,6 +7786,8 @@ H1_QuadrilateralElement::H1_QuadrilateralElement(const int p, const int btype)
shape_y.SetSize(p1);
dshape_x.SetSize(p1);
dshape_y.SetSize(p1);
d2shape_x.SetSize(p1);
d2shape_y.SetSize(p1);
#endif
int o = 0;
@@ -7730,6 +7841,30 @@ void H1_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
}
}
void H1_QuadrilateralElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1),
d2shape_x(p+1), d2shape_y(p+1);
#endif
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
basis1d.Eval(ip.y, shape_y, dshape_y, d2shape_y);
for (int o = 0, j = 0; j <= p; j++)
{
for (int i = 0; i <= p; i++)
{
Hessian(dof_map[o],0) = d2shape_x(i)* shape_y(j);
Hessian(dof_map[o],1) = dshape_x(i)* dshape_y(j);
Hessian(dof_map[o],2) = shape_x(i)*d2shape_y(j); o++;
}
}
}
void H1_QuadrilateralElement::ProjectDelta(int vertex, Vector &dofs) const
{
const int p = order;
@@ -7793,6 +7928,9 @@ H1_HexahedronElement::H1_HexahedronElement(const int p, const int btype)
dshape_x.SetSize(p1);
dshape_y.SetSize(p1);
dshape_z.SetSize(p1);
d2shape_x.SetSize(p1);
d2shape_y.SetSize(p1);
d2shape_z.SetSize(p1);
#endif
int o = 0;
@@ -7849,6 +7987,35 @@ void H1_HexahedronElement::CalcDShape(const IntegrationPoint &ip,
}
}
void H1_HexahedronElement::CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p+1), shape_y(p+1), shape_z(p+1);
Vector dshape_x(p+1), dshape_y(p+1), dshape_z(p+1);
Vector d2shape_x(p+1), d2shape_y(p+1), ds2hape_z(p+1);
#endif
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
basis1d.Eval(ip.y, shape_y, dshape_y, d2shape_y);
basis1d.Eval(ip.z, shape_z, dshape_z, d2shape_z);
for (int o = 0, k = 0; k <= p; k++)
for (int j = 0; j <= p; j++)
for (int i = 0; i <= p; i++)
{
Hessian(dof_map[o],0) = d2shape_x(i)* shape_y(j)* shape_z(k);
Hessian(dof_map[o],1) = dshape_x(i)* dshape_y(j)* shape_z(k);
Hessian(dof_map[o],2) = dshape_x(i)* shape_y(j)* dshape_z(k);
Hessian(dof_map[o],3) = shape_x(i)*d2shape_y(j)* shape_z(k);
Hessian(dof_map[o],4) = shape_x(i)* dshape_y(j)* dshape_z(k);
Hessian(dof_map[o],5) = shape_x(i)* shape_y(j)*d2shape_z(k);
o++;
}
}
void H1_HexahedronElement::ProjectDelta(int vertex, Vector &dofs) const
{
const int p = order;
+12 -4
View File
@@ -446,7 +446,7 @@ public:
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
part of the Hessian of one shape function.
The order in 2D is {u_xx, u_xy, u_yy}.
The size (#dof x (#dim (#dim-1)/2) of @a Hessian must be set in advance.*/
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
virtual void CalcHessian (const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
@@ -1850,6 +1850,7 @@ public:
Basis(const int p, const double *nodes, EvalType etype = Barycentric);
void Eval(const double x, Vector &u) const;
void Eval(const double x, Vector &u, Vector &d) const;
void Eval(const double x, Vector &u, Vector &d, Vector &d2) const;
};
private:
@@ -2100,7 +2101,7 @@ class H1_SegmentElement : public NodalTensorFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, dshape_x;
mutable Vector shape_x, dshape_x, d2shape_x;
#endif
public:
@@ -2109,6 +2110,8 @@ public:
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
@@ -2118,7 +2121,7 @@ class H1_QuadrilateralElement : public NodalTensorFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, dshape_x, dshape_y;
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
#endif
public:
@@ -2128,6 +2131,8 @@ public:
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
@@ -2137,7 +2142,8 @@ class H1_HexahedronElement : public NodalTensorFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z;
mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z,
d2shape_x, d2shape_y, d2shape_z;
#endif
public:
@@ -2146,6 +2152,8 @@ public:
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const;
};
+14 -8
View File
@@ -62,6 +62,7 @@ void QuadratureInterpolator::Eval2D(
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_ND2D, "");
MFEM_VERIFY(NQ <= MAX_NQ2D, "");
@@ -72,22 +73,24 @@ void QuadratureInterpolator::Eval2D(
auto val = Reshape(q_val.Write(), NQ, VDIM, NE);
auto der = Reshape(q_der.Write(), NQ, VDIM, 2, 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_ND2D;
constexpr int max_VDIM = T_VDIM ? T_VDIM : MAX_VDIM2D;
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)
{
@@ -150,6 +153,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 +164,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)
{
+46 -48
View File
@@ -1968,11 +1968,11 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
Jpt.SetSize(dim);
PMatI.UseExternalData(elfun.GetData(), dof, dim);
const IntegrationRule *ir = EnergyIntegrationRule(el);
const IntegrationRule &ir = EnergyIntegrationRule(el);
energy = 0.0;
DenseTensor Jtr(dim, dim, ir->GetNPoints());
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
DenseTensor Jtr(dim, dim, ir.GetNPoints());
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
// Limited case.
Vector shape, p, p0, d_vals;
@@ -1989,11 +1989,11 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
nodes0->GetSubVector(pos_dofs, pos0V);
if (lim_dist)
{
lim_dist->GetValues(T.ElementNo, *ir, d_vals);
lim_dist->GetValues(T.ElementNo, ir, d_vals);
}
else
{
d_vals.SetSize(ir->GetNPoints()); d_vals = 1.0;
d_vals.SetSize(ir.GetNPoints()); d_vals = 1.0;
}
}
@@ -2019,13 +2019,13 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
Vector zeta_q, zeta0_q;
if (adaptive_limiting)
{
zeta->GetValues(T.ElementNo, *ir, zeta_q);
zeta_0->GetValues(T.ElementNo, *ir, zeta0_q);
zeta->GetValues(T.ElementNo, ir, zeta_q);
zeta_0->GetValues(T.ElementNo, ir, zeta0_q);
}
for (int i = 0; i < ir->GetNPoints(); i++)
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
const IntegrationPoint &ip = ir.IntPoint(i);
const DenseMatrix &Jtr_i = Jtr(i);
metric->SetTargetJacobian(Jtr_i);
CalcInverse(Jtr_i, Jrt);
@@ -2105,14 +2105,14 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
elvect.SetSize(dof*dim);
PMatO.UseExternalData(elvect.GetData(), dof, dim);
const IntegrationRule *ir = ActionIntegrationRule(el);
const int nqp = ir->GetNPoints();
const IntegrationRule &ir = ActionIntegrationRule(el);
const int nqp = ir.GetNPoints();
elvect = 0.0;
Vector weights(nqp);
DenseTensor Jtr(dim, dim, nqp);
DenseTensor dJtr(dim, dim, dim*nqp);
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
// Limited case.
DenseMatrix pos0;
@@ -2129,7 +2129,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
nodes0->GetSubVector(pos_dofs, pos0V);
if (lim_dist)
{
lim_dist->GetValues(T.ElementNo, *ir, d_vals);
lim_dist->GetValues(T.ElementNo, ir, d_vals);
}
else
{
@@ -2149,7 +2149,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
if (exact_action)
{
targetC->ComputeElementTargetsGradient(*ir, elfun, *Tpr, dJtr);
targetC->ComputeElementTargetsGradient(ir, elfun, *Tpr, dJtr);
}
}
@@ -2159,7 +2159,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir->IntPoint(q);
const IntegrationPoint &ip = ir.IntPoint(q);
const DenseMatrix &Jtr_q = Jtr(q);
metric->SetTargetJacobian(Jtr_q);
CalcInverse(Jtr_q, Jrt);
@@ -2186,7 +2186,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
DenseMatrix dwdx(dim);
for (int d = 0; d < dim; d++)
{
const DenseMatrix &dJtr_q = dJtr(q + d*ir->GetNPoints());
const DenseMatrix &dJtr_q = dJtr(q + d * nqp);
Mult(Jrt, dJtr_q, dwdx );
d_detW_dx(d) = dwdx.Trace();
}
@@ -2221,7 +2221,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
}
}
if (zeta) { AssembleElemVecAdaptLim(el, weights, *Tpr, *ir, PMatO); }
if (zeta) { AssembleElemVecAdaptLim(el, weights, *Tpr, ir, PMatO); }
delete Tpr;
}
@@ -2240,13 +2240,13 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
PMatI.UseExternalData(elfun.GetData(), dof, dim);
elmat.SetSize(dof*dim);
const IntegrationRule *ir = GradientIntegrationRule(el);
const int nqp = ir->GetNPoints();
const IntegrationRule &ir = GradientIntegrationRule(el);
const int nqp = ir.GetNPoints();
elmat = 0.0;
Vector weights(nqp);
DenseTensor Jtr(dim, dim, nqp);
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
// Limited case.
DenseMatrix pos0, grad_grad;
@@ -2263,7 +2263,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
nodes0->GetSubVector(pos_dofs, pos0V);
if (lim_dist)
{
lim_dist->GetValues(T.ElementNo, *ir, d_vals);
lim_dist->GetValues(T.ElementNo, ir, d_vals);
}
else
{
@@ -2285,7 +2285,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir->IntPoint(q);
const IntegrationPoint &ip = ir.IntPoint(q);
const DenseMatrix &Jtr_q = Jtr(q);
metric->SetTargetJacobian(Jtr_q);
CalcInverse(Jtr_q, Jrt);
@@ -2302,7 +2302,6 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
// TODO: derivatives of adaptivity-based targets.
// TODO optimize by symmetry.
if (coeff0)
{
el.CalcShape(ip, shape);
@@ -2328,7 +2327,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
}
}
if (zeta) { AssembleElemGradAdaptLim(el, weights, *Tpr, *ir, elmat); }
if (zeta) { AssembleElemGradAdaptLim(el, weights, *Tpr, ir, elmat); }
delete Tpr;
}
@@ -2499,10 +2498,10 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el,
// Contributions from adaptive limiting (exact derivatives).
if (zeta)
{
const IntegrationRule *ir = ActionIntegrationRule(el);
const int nqp = ir->GetNPoints();
const IntegrationRule &ir = ActionIntegrationRule(el);
const int nqp = ir.GetNPoints();
DenseTensor Jtr(dim, dim, nqp);
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
IsoparametricTransformation Tpr;
Tpr.SetFE(&el);
@@ -2514,11 +2513,11 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el,
Vector weights(nqp);
for (int q = 0; q < nqp; q++)
{
weights(q) = ir->IntPoint(q).weight * Jtr(q).Det();
weights(q) = ir.IntPoint(q).weight * Jtr(q).Det();
}
PMatO.UseExternalData(elvect.GetData(), dof, dim);
AssembleElemVecAdaptLim(el, weights, Tpr, *ir, PMatO);
AssembleElemVecAdaptLim(el, weights, Tpr, ir, PMatO);
}
}
@@ -2595,10 +2594,10 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
// Contributions from adaptive limiting.
if (zeta)
{
const IntegrationRule *ir = GradientIntegrationRule(el);
const int nqp = ir->GetNPoints();
const IntegrationRule &ir = GradientIntegrationRule(el);
const int nqp = ir.GetNPoints();
DenseTensor Jtr(dim, dim, nqp);
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
IsoparametricTransformation Tpr;
Tpr.SetFE(&el);
@@ -2610,10 +2609,10 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
Vector weights(nqp);
for (int q = 0; q < nqp; q++)
{
weights(q) = ir->IntPoint(q).weight * Jtr(q).Det();
weights(q) = ir.IntPoint(q).weight * Jtr(q).Det();
}
AssembleElemGradAdaptLim(el, weights, Tpr, *ir, elmat);
AssembleElemGradAdaptLim(el, weights, Tpr, ir, elmat);
}
}
@@ -2643,33 +2642,32 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x,
Array<int> vdofs;
Vector x_vals;
const FiniteElementSpace* const fes = x.FESpace();
const FiniteElement *fe = fes->GetFE(0);
const int dof = fes->GetFE(0)->GetDof(), dim = fes->GetFE(0)->GetDim();
DSh.SetSize(dof, dim);
const int dim = fes->GetMesh()->Dimension();
Jrt.SetSize(dim);
Jpr.SetSize(dim);
Jpt.SetSize(dim);
const IntegrationRule *ir = EnergyIntegrationRule(*fe);
const int nqp = ir->GetNPoints();
DenseTensor Jtr(dim, dim, nqp);
metric_energy = 0.0;
lim_energy = 0.0;
for (int i = 0; i < fes->GetNE(); i++)
{
fe = fes->GetFE(i);
const FiniteElement *fe = fes->GetFE(i);
const IntegrationRule &ir = EnergyIntegrationRule(*fe);
const int nqp = ir.GetNPoints();
DenseTensor Jtr(dim, dim, nqp);
const int dof = fe->GetDof();
DSh.SetSize(dof, dim);
fes->GetElementVDofs(i, vdofs);
x.GetSubVector(vdofs, x_vals);
PMatI.UseExternalData(x_vals.GetData(), dof, dim);
targetC->ComputeElementTargets(i, *fe, *ir, x_vals, Jtr);
targetC->ComputeElementTargets(i, *fe, ir, x_vals, Jtr);
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir->IntPoint(q);
const IntegrationPoint &ip = ir.IntPoint(q);
metric->SetTargetJacobian(Jtr(q));
CalcInverse(Jtr(q), Jrt);
const double weight = ip.weight * Jtr(q).Det();
@@ -2693,9 +2691,9 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x,
const FiniteElementSpace &fes)
{
const FiniteElement *fe = fes.GetFE(0);
const IntegrationRule *ir = EnergyIntegrationRule(*fe);
const IntegrationRule &ir = EnergyIntegrationRule(*fe);
const int NE = fes.GetMesh()->GetNE(), dim = fe->GetDim(),
dof = fe->GetDof(), nsp = ir->GetNPoints();
dof = fe->GetDof(), nsp = ir.GetNPoints();
Array<int> xdofs(dof * dim);
DenseMatrix Jpr(dim), dshape(dof, dim), pos(dof, dim);
@@ -2712,7 +2710,7 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x,
detv_sum = 0.;
for (int j = 0; j < nsp; j++)
{
fes.GetFE(i)->CalcDShape(ir->IntPoint(j), dshape);
fes.GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
MultAtB(pos, dshape, Jpr);
detv_sum += std::fabs(Jpr.Det());
}
+22 -6
View File
@@ -890,6 +890,10 @@ protected:
TMOP_QualityMetric *metric; // not owned
const TargetConstructor *targetC; // not owned
// Custom integration rules.
IntegrationRules *IntegRules;
int integ_order;
// Weight Coefficient multiplying the quality metric term.
Coefficient *coeff1; // not owned, if NULL -> coeff1 is 1.
// Normalization factor for the metric term.
@@ -988,17 +992,21 @@ protected:
nodes0 = NULL; coeff0 = NULL; lim_dist = NULL; lim_func = NULL;
}
const IntegrationRule *EnergyIntegrationRule(const FiniteElement &el) const
const IntegrationRule &EnergyIntegrationRule(const FiniteElement &el) const
{
return (IntRule) ? IntRule
/* */ : &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3));
if (IntegRules)
{
return IntegRules->Get(el.GetGeomType(), integ_order);
}
return (IntRule) ? *IntRule
/* */ : IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3);
}
const IntegrationRule *ActionIntegrationRule(const FiniteElement &el) const
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
const IntegrationRule &GradientIntegrationRule(const FiniteElement &el) const
{
// TODO the action and energy most likely need less integration points.
return EnergyIntegrationRule(el);
@@ -1008,7 +1016,7 @@ public:
/** @param[in] m TMOP_QualityMetric that will be integrated (not owned).
@param[in] tc Target-matrix construction algorithm to use (not owned). */
TMOP_Integrator(TMOP_QualityMetric *m, TargetConstructor *tc)
: metric(m), targetC(tc),
: metric(m), targetC(tc), IntegRules(NULL), integ_order(-1),
coeff1(NULL), metric_normal(1.0),
nodes0(NULL), coeff0(NULL),
lim_dist(NULL), lim_func(NULL), lim_normal(1.0),
@@ -1019,6 +1027,14 @@ public:
~TMOP_Integrator();
/// Prescribe a set of integration rules; relevant for mixed meshes.
/** This function has priority over SetIntRule(), if both are called. */
void SetIntegrationRules(IntegrationRules &irules, int order)
{
IntegRules = &irules;
integ_order = order;
}
/// Sets a scaling Coefficient for the quality metric term of the integrator.
/** With this addition, the integrator becomes
@f$ \int w1 W(Jpt) dx @f$.
+29 -15
View File
@@ -176,8 +176,8 @@ SerialAdvectorCGOper::SerialAdvectorCGOper(const Vector &x_start,
MassIntegrator *Minteg = new MassIntegrator;
M.AddDomainIntegrator(Minteg);
M.Assemble();
M.Finalize();
M.Assemble(0);
M.Finalize(0);
}
void SerialAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
@@ -220,8 +220,8 @@ ParAdvectorCGOper::ParAdvectorCGOper(const Vector &x_start,
MassIntegrator *Minteg = new MassIntegrator;
M.AddDomainIntegrator(Minteg);
M.Assemble();
M.Finalize();
M.Assemble(0);
M.Finalize(0);
}
void ParAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
@@ -353,13 +353,12 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
energy_in = nlf->GetEnergy(x);
}
const int NE = fes->GetMesh()->GetNE(), dim = fes->GetFE(0)->GetDim(),
dof = fes->GetFE(0)->GetDof(), nsp = ir.GetNPoints();
Array<int> xdofs(dof * dim);
DenseMatrix Jpr(dim), dshape(dof, dim), pos(dof, dim);
Vector posV(pos.Data(), dof * dim);
Vector x_out_loc(fes->GetVSize());
const int NE = fes->GetMesh()->GetNE(), dim = fes->GetMesh()->Dimension();
Array<int> xdofs;
DenseMatrix Jpr(dim);
// Get the local prolongation of the solution vector.
Vector x_out_loc(fes->GetVSize());
if (serial)
{
const SparseMatrix *cP = fes->GetConformingProlongation();
@@ -373,15 +372,23 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
}
#endif
// Check if the starting mesh (given by x) is inverted.
// Note that x hasn't been modified by the Newton update yet.
double min_detJ = infinity();
for (int i = 0; i < NE; i++)
{
const int dof = fes->GetFE(i)->GetDof();
DenseMatrix dshape(dof, dim), pos(dof, dim);
Vector posV(pos.Data(), dof * dim);
fes->GetElementVDofs(i, xdofs);
x_out_loc.GetSubVector(xdofs, posV);
const IntegrationRule &irule = GetIntegrationRule(*fes->GetFE(i));
const int nsp = irule.GetNPoints();
for (int j = 0; j < nsp; j++)
{
fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
fes->GetFE(i)->CalcDShape(irule.IntPoint(j), dshape);
MultAtB(pos, dshape, Jpr);
min_detJ = std::min(min_detJ, Jpr.Det());
}
@@ -394,18 +401,18 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
p_nlf->ParFESpace()->GetComm());
}
#endif
bool untangling = false;
if (min_detJ_all <= 0) { untangling = true; }
const bool untangling = (min_detJ_all <= 0) ? true : false;
const bool have_b = (b.Size() == Height());
Vector x_out(x.Size());
bool x_out_ok = false;
double scale = 1.0, energy_out = 0.0;
double norm0 = Norm(r);
const double norm0 = Norm(r);
const double detJ_factor = (solver_type == 1) ? 0.25 : 0.5;
// Perform the line search.
for (int i = 0; i < 12; i++)
{
add(x, -scale, c, x_out);
@@ -429,11 +436,18 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
int jac_ok = 1;
for (int i = 0; i < NE; i++)
{
const int dof = fes->GetFE(i)->GetDof();
DenseMatrix dshape(dof, dim), pos(dof, dim);
Vector posV(pos.Data(), dof * dim);
fes->GetElementVDofs(i, xdofs);
x_out_loc.GetSubVector(xdofs, posV);
const IntegrationRule &irule = GetIntegrationRule(*fes->GetFE(i));
const int nsp = irule.GetNPoints();
for (int j = 0; j < nsp; j++)
{
fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
fes->GetFE(i)->CalcDShape(irule.IntPoint(j), dshape);
MultAtB(pos, dshape, Jpr);
if (Jpr.Det() <= 0.0) { jac_ok = 0; goto break2; }
}
+25 -2
View File
@@ -118,16 +118,39 @@ protected:
// Quadrature points that are checked for negative Jacobians etc.
const IntegrationRule &ir;
// These fields are relevant for mixed meshes.
IntegrationRules *IntegRules;
int integ_order;
const IntegrationRule &GetIntegrationRule(const FiniteElement &el) const
{
if (IntegRules)
{
return IntegRules->Get(el.GetGeomType(), integ_order);
}
return ir;
}
void UpdateDiscreteTC(const TMOP_Integrator &ti, const Vector &x_new) const;
public:
#ifdef MFEM_USE_MPI
TMOPNewtonSolver(MPI_Comm comm, const IntegrationRule &irule, int type = 0)
: LBFGSSolver(comm), solver_type(type), parallel(true), ir(irule) { }
: LBFGSSolver(comm), solver_type(type), parallel(true),
ir(irule), IntegRules(NULL), integ_order(-1) { }
#endif
TMOPNewtonSolver(const IntegrationRule &irule, int type = 0)
: LBFGSSolver(), solver_type(type), parallel(false), ir(irule) { }
: LBFGSSolver(), solver_type(type), parallel(false),
ir(irule), IntegRules(NULL), integ_order(-1) { }
/// Prescribe a set of integration rules; relevant for mixed meshes.
/** If called, this function has priority over the IntegrationRule given to
the constructor of the class. */
void SetIntegrationRules(IntegrationRules &irules, int order)
{
IntegRules = &irules;
integ_order = order;
}
virtual double ComputeScalingFactor(const Vector &x, const Vector &b) const;
+30
View File
@@ -1048,6 +1048,36 @@ HYPRE_Int HypreParMatrix::MultTranspose(HypreParVector & x, HypreParVector & y,
return hypre_ParCSRMatrixMatvecT(a, A, x, b, y);
}
void HypreParMatrix::AbsMult(double a, const Vector &x,
double b, Vector &y) const
{
MFEM_ASSERT(x.Size() == Width(), "invalid x.Size() = " << x.Size()
<< ", expected size = " << Width());
MFEM_ASSERT(y.Size() == Height(), "invalid y.Size() = " << y.Size()
<< ", expected size = " << Height());
auto x_data = x.HostRead();
auto y_data = (b == 0.0) ? y.HostWrite() : y.HostReadWrite();
internal::hypre_ParCSRMatrixAbsMatvec(A, a, const_cast<double*>(x_data),
b, y_data);
}
void HypreParMatrix::AbsMultTranspose(double a, const Vector &x,
double b, Vector &y) const
{
MFEM_ASSERT(x.Size() == Height(), "invalid x.Size() = " << x.Size()
<< ", expected size = " << Height());
MFEM_ASSERT(y.Size() == Width(), "invalid y.Size() = " << y.Size()
<< ", expected size = " << Width());
auto x_data = x.HostRead();
auto y_data = (b == 0.0) ? y.HostWrite() : y.HostReadWrite();
internal::hypre_ParCSRMatrixAbsMatvecT(A, a, const_cast<double*>(x_data),
b, y_data);
}
HypreParMatrix* HypreParMatrix::LeftDiagMult(const SparseMatrix &D,
HYPRE_Int* row_starts) const
{
+6
View File
@@ -446,6 +446,12 @@ public:
virtual void MultTranspose(const Vector &x, Vector &y) const
{ MultTranspose(1.0, x, 0.0, y); }
/// Computes y = a * |A| * x + b * y, using entry-wise absolute values of matrix A
void AbsMult(double a, const Vector &x, double b, Vector &y) const;
/// Computes y = a * |At| * x + b * y, using entry-wise absolute values of the transpose of matrix A
void AbsMultTranspose(double a, const Vector &x, double b, Vector &y) const;
/** The "Boolean" analog of y = alpha * A * x + beta * y, where elements in
the sparsity pattern of the matrix are treated as "true". */
void BooleanMult(int alpha, const int *x, int beta, int *y)
+328
View File
@@ -16,6 +16,7 @@
#include "hypre_parcsr.hpp"
#include <limits>
#include <cmath>
namespace mfem
{
@@ -977,6 +978,196 @@ void hypre_ParCSRMatrixSplit(hypre_ParCSRMatrix *A,
}
}
/* Based on hypre_CSRMatrixMatvec in hypre's csr_matvec.c */
void hypre_CSRMatrixAbsMatvec(hypre_CSRMatrix *A,
HYPRE_Real alpha,
HYPRE_Real *x,
HYPRE_Real beta,
HYPRE_Real *y)
{
HYPRE_Real *A_data = hypre_CSRMatrixData(A);
HYPRE_Int *A_i = hypre_CSRMatrixI(A);
HYPRE_Int *A_j = hypre_CSRMatrixJ(A);
HYPRE_Int num_rows = hypre_CSRMatrixNumRows(A);
HYPRE_Int *A_rownnz = hypre_CSRMatrixRownnz(A);
HYPRE_Int num_rownnz = hypre_CSRMatrixNumRownnz(A);
HYPRE_Real *x_data = x;
HYPRE_Real *y_data = y;
HYPRE_Real temp, tempx;
HYPRE_Int i, jj;
HYPRE_Int m;
HYPRE_Real xpar=0.7;
/*-----------------------------------------------------------------------
* Do (alpha == 0.0) computation - RDF: USE MACHINE EPS
*-----------------------------------------------------------------------*/
if (alpha == 0.0)
{
for (i = 0; i < num_rows; i++)
{
y_data[i] *= beta;
}
return;
}
/*-----------------------------------------------------------------------
* y = (beta/alpha)*y
*-----------------------------------------------------------------------*/
temp = beta / alpha;
if (temp != 1.0)
{
if (temp == 0.0)
{
for (i = 0; i < num_rows; i++)
{
y_data[i] = 0.0;
}
}
else
{
for (i = 0; i < num_rows; i++)
{
y_data[i] *= temp;
}
}
}
/*-----------------------------------------------------------------
* y += abs(A)*x
*-----------------------------------------------------------------*/
/* use rownnz pointer to do the abs(A)*x multiplication
when num_rownnz is smaller than num_rows */
if (num_rownnz < xpar*(num_rows))
{
for (i = 0; i < num_rownnz; i++)
{
m = A_rownnz[i];
tempx = 0;
for (jj = A_i[m]; jj < A_i[m+1]; jj++)
{
tempx += std::abs(A_data[jj])*x_data[A_j[jj]];
}
y_data[m] += tempx;
}
}
else
{
for (i = 0; i < num_rows; i++)
{
tempx = 0;
for (jj = A_i[i]; jj < A_i[i+1]; jj++)
{
tempx += std::abs(A_data[jj])*x_data[A_j[jj]];
}
y_data[i] += tempx;
}
}
/*-----------------------------------------------------------------
* y = alpha*y
*-----------------------------------------------------------------*/
if (alpha != 1.0)
{
for (i = 0; i < num_rows; i++)
{
y_data[i] *= alpha;
}
}
}
/* Based on hypre_CSRMatrixMatvecT in hypre's csr_matvec.c */
void hypre_CSRMatrixAbsMatvecT(hypre_CSRMatrix *A,
HYPRE_Real alpha,
HYPRE_Real *x,
HYPRE_Real beta,
HYPRE_Real *y)
{
HYPRE_Real *A_data = hypre_CSRMatrixData(A);
HYPRE_Int *A_i = hypre_CSRMatrixI(A);
HYPRE_Int *A_j = hypre_CSRMatrixJ(A);
HYPRE_Int num_rows = hypre_CSRMatrixNumRows(A);
HYPRE_Int num_cols = hypre_CSRMatrixNumCols(A);
HYPRE_Real *x_data = x;
HYPRE_Real *y_data = y;
HYPRE_Int i, j, jj;
HYPRE_Real temp;
if (alpha == 0.0)
{
for (i = 0; i < num_cols; i++)
{
y_data[i] *= beta;
}
return;
}
/*-----------------------------------------------------------------------
* y = (beta/alpha)*y
*-----------------------------------------------------------------------*/
temp = beta / alpha;
if (temp != 1.0)
{
if (temp == 0.0)
{
for (i = 0; i < num_cols; i++)
{
y_data[i] = 0.0;
}
}
else
{
for (i = 0; i < num_cols; i++)
{
y_data[i] *= temp;
}
}
}
/*-----------------------------------------------------------------
* y += abs(A)^T*x
*-----------------------------------------------------------------*/
for (i = 0; i < num_rows; i++)
{
for (jj = A_i[i]; jj < A_i[i+1]; jj++)
{
j = A_j[jj];
y_data[j] += std::abs(A_data[jj]) * x_data[i];
}
}
/*-----------------------------------------------------------------
* y = alpha*y
*-----------------------------------------------------------------*/
if (alpha != 1.0)
{
for (i = 0; i < num_cols; i++)
{
y_data[i] *= alpha;
}
}
}
/* Based on hypre_CSRMatrixMatvec in hypre's csr_matvec.c */
void hypre_CSRMatrixBooleanMatvec(hypre_CSRMatrix *A,
HYPRE_Bool alpha,
@@ -1236,6 +1427,143 @@ hypre_ParCSRCommHandleCreate_bool(HYPRE_Int job,
return comm_handle;
}
/* Based on hypre_ParCSRMatrixMatvec in par_csr_matvec.c */
void hypre_ParCSRMatrixAbsMatvec(hypre_ParCSRMatrix *A,
HYPRE_Real alpha,
HYPRE_Real *x,
HYPRE_Real beta,
HYPRE_Real *y)
{
hypre_ParCSRCommHandle *comm_handle;
hypre_ParCSRCommPkg *comm_pkg = hypre_ParCSRMatrixCommPkg(A);
hypre_CSRMatrix *diag = hypre_ParCSRMatrixDiag(A);
hypre_CSRMatrix *offd = hypre_ParCSRMatrixOffd(A);
HYPRE_Int num_cols_offd = hypre_CSRMatrixNumCols(offd);
HYPRE_Int num_sends, i, j, index;
HYPRE_Real *x_tmp, *x_buf;
x_tmp = mfem_hypre_CTAlloc(HYPRE_Real, num_cols_offd);
/*---------------------------------------------------------------------
* If there exists no CommPkg for A, a CommPkg is generated using
* equally load balanced partitionings
*--------------------------------------------------------------------*/
if (!comm_pkg)
{
hypre_MatvecCommPkgCreate(A);
comm_pkg = hypre_ParCSRMatrixCommPkg(A);
}
num_sends = hypre_ParCSRCommPkgNumSends(comm_pkg);
x_buf = mfem_hypre_CTAlloc(
HYPRE_Real, hypre_ParCSRCommPkgSendMapStart(comm_pkg, num_sends));
index = 0;
for (i = 0; i < num_sends; i++)
{
j = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for ( ; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
{
x_buf[index++] = x[hypre_ParCSRCommPkgSendMapElmt(comm_pkg, j)];
}
}
comm_handle = hypre_ParCSRCommHandleCreate(1, comm_pkg, x_buf, x_tmp);
hypre_CSRMatrixAbsMatvec(diag, alpha, x, beta, y);
hypre_ParCSRCommHandleDestroy(comm_handle);
if (num_cols_offd)
{
hypre_CSRMatrixAbsMatvec(offd, alpha, x_tmp, 1.0, y);
}
mfem_hypre_TFree(x_buf);
mfem_hypre_TFree(x_tmp);
}
/* Based on hypre_ParCSRMatrixMatvecT in par_csr_matvec.c */
void hypre_ParCSRMatrixAbsMatvecT(hypre_ParCSRMatrix *A,
HYPRE_Real alpha,
HYPRE_Real *x,
HYPRE_Real beta,
HYPRE_Real *y)
{
hypre_ParCSRCommHandle *comm_handle;
hypre_ParCSRCommPkg *comm_pkg = hypre_ParCSRMatrixCommPkg(A);
hypre_CSRMatrix *diag = hypre_ParCSRMatrixDiag(A);
hypre_CSRMatrix *offd = hypre_ParCSRMatrixOffd(A);
HYPRE_Real *y_tmp;
HYPRE_Real *y_buf;
HYPRE_Int num_cols_offd = hypre_CSRMatrixNumCols(offd);
HYPRE_Int i, j, jj, end, num_sends;
y_tmp = mfem_hypre_TAlloc(HYPRE_Real, num_cols_offd);
/*---------------------------------------------------------------------
* If there exists no CommPkg for A, a CommPkg is generated using
* equally load balanced partitionings
*--------------------------------------------------------------------*/
if (!comm_pkg)
{
hypre_MatvecCommPkgCreate(A);
comm_pkg = hypre_ParCSRMatrixCommPkg(A);
}
num_sends = hypre_ParCSRCommPkgNumSends(comm_pkg);
y_buf = mfem_hypre_CTAlloc(
HYPRE_Real, hypre_ParCSRCommPkgSendMapStart(comm_pkg, num_sends));
if (num_cols_offd)
{
#if MFEM_HYPRE_VERSION >= 21100
if (A->offdT)
{
// offdT is optional. Used only if it's present.
hypre_CSRMatrixAbsMatvec(A->offdT, alpha, x, 0., y_tmp);
}
else
#endif
{
hypre_CSRMatrixAbsMatvecT(offd, alpha, x, 0., y_tmp);
}
}
comm_handle = hypre_ParCSRCommHandleCreate(2, comm_pkg, y_tmp, y_buf);
#if MFEM_HYPRE_VERSION >= 21100
if (A->diagT)
{
// diagT is optional. Used only if it's present.
hypre_CSRMatrixAbsMatvec(A->diagT, alpha, x, beta, y);
}
else
#endif
{
hypre_CSRMatrixAbsMatvecT(diag, alpha, x, beta, y);
}
hypre_ParCSRCommHandleDestroy(comm_handle);
for (i = 0; i < num_sends; i++)
{
end = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1);
for (j = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i); j < end; j++)
{
jj = hypre_ParCSRCommPkgSendMapElmt(comm_pkg, j);
y[jj] += y_buf[j];
}
}
mfem_hypre_TFree(y_buf);
mfem_hypre_TFree(y_tmp);
}
/* Based on hypre_ParCSRMatrixMatvec in par_csr_matvec.c */
void hypre_ParCSRMatrixBooleanMatvec(hypre_ParCSRMatrix *A,
HYPRE_Bool alpha,
+28
View File
@@ -118,6 +118,34 @@ void hypre_ParCSRMatrixSplit(hypre_ParCSRMatrix *A,
typedef int HYPRE_Bool;
#define HYPRE_MPI_BOOL MPI_INT
/// Computes y = alpha * |A| * x + beta * y, using entry-wise absolute values of matrix A
void hypre_CSRMatrixAbsMatvec(hypre_CSRMatrix *A,
HYPRE_Real alpha,
HYPRE_Real *x,
HYPRE_Real beta,
HYPRE_Real *y);
/// Computes y = alpha * |At| * x + beta * y, using entry-wise absolute values of the transpose of matrix A
void hypre_CSRMatrixAbsMatvecT(hypre_CSRMatrix *A,
HYPRE_Real alpha,
HYPRE_Real *x,
HYPRE_Real beta,
HYPRE_Real *y);
/// Computes y = alpha * |A| * x + beta * y, using entry-wise absolute values of matrix A
void hypre_ParCSRMatrixAbsMatvec(hypre_ParCSRMatrix *A,
HYPRE_Real alpha,
HYPRE_Real *x,
HYPRE_Real beta,
HYPRE_Real *y);
/// Computes y = alpha * |At| * x + beta * y, using entry-wise absolute values of the transpose of matrix A
void hypre_ParCSRMatrixAbsMatvecT(hypre_ParCSRMatrix *A,
HYPRE_Real alpha,
HYPRE_Real *x,
HYPRE_Real beta,
HYPRE_Real *y);
/** The "Boolean" analog of y = alpha * A * x + beta * y, where elements in the
sparsity pattern of the CSR matrix A are treated as "true". */
void hypre_CSRMatrixBooleanMatvec(hypre_CSRMatrix *A,
+68
View File
@@ -2665,6 +2665,42 @@ void BlockILU::Mult(const Vector &b, Vector &x) const
}
}
void ResidualBCMonitor::MonitorResidual(
int it, double norm, const Vector &r, bool final)
{
if (!ess_dofs_list) { return; }
double bc_norm_squared = 0.0;
r.HostRead();
ess_dofs_list->HostRead();
for (int i = 0; i < ess_dofs_list->Size(); i++)
{
const double r_entry = r((*ess_dofs_list)[i]);
bc_norm_squared += r_entry*r_entry;
}
bool print = true;
#ifdef MFEM_USE_MPI
MPI_Comm comm = iter_solver->GetComm();
if (comm != MPI_COMM_NULL)
{
double glob_bc_norm_squared = 0.0;
MPI_Reduce(&bc_norm_squared, &glob_bc_norm_squared, 1, MPI_DOUBLE,
MPI_SUM, 0, comm);
bc_norm_squared = glob_bc_norm_squared;
int rank;
MPI_Comm_rank(comm, &rank);
print = (rank == 0);
}
#endif
if ((it == 0 || final || bc_norm_squared > 0.0) && print)
{
mfem::out << " ResidualBCMonitor : b.c. residual norm = "
<< sqrt(bc_norm_squared) << endl;
}
}
#ifdef MFEM_USE_SUITESPARSE
void UMFPackSolver::Init()
@@ -2936,4 +2972,36 @@ KLUSolver::~KLUSolver()
#endif // MFEM_USE_SUITESPARSE
IncompleteCholesky::IncompleteCholesky(SparseMatrix &A_) : A(&A_)
{
#ifdef MFEM_USE_CUDA
A->IncompleteCholeskySetup();
#endif
}
void IncompleteCholesky::Mult(const Vector &b, Vector &x) const
{
#ifdef MFEM_USE_CUDA
A->IncompleteCholeskyMult(b, x);
#else
x = b;
#endif
}
ILUcusparse::ILUcusparse(SparseMatrix &A_) : A(&A_)
{
#ifdef MFEM_USE_CUDA
A->ILUSetup();
#endif
}
void ILUcusparse::Mult(const Vector &b, Vector &x) const
{
#ifdef MFEM_USE_CUDA
A->ILUMult(b, x);
#else
x = b;
#endif
}
}
+60 -2
View File
@@ -33,8 +33,12 @@ class BilinearForm;
/// Abstract base class for an iterative solver monitor
class IterativeSolverMonitor
{
protected:
/// The last IterativeSolver to which this monitor was attached.
const class IterativeSolver *iter_solver;
public:
IterativeSolverMonitor() {}
IterativeSolverMonitor() : iter_solver(nullptr) {}
virtual ~IterativeSolverMonitor() {}
@@ -49,6 +53,11 @@ public:
bool final)
{
}
/** @brief This method is invoked by ItertiveSolver::SetMonitor, informing
the monitor which IterativeSolver is using it. */
void SetIterativeSolver(const IterativeSolver &solver)
{ iter_solver = &solver; }
};
/// Abstract base class for iterative solver
@@ -100,7 +109,15 @@ public:
virtual void SetOperator(const Operator &op);
/// Set the iterative solver monitor
void SetMonitor(IterativeSolverMonitor &m) { monitor = &m; }
void SetMonitor(IterativeSolverMonitor &m)
{ monitor = &m; m.SetIterativeSolver(*this); }
#ifdef MFEM_USE_MPI
/** @brief Return the associated MPI communicator, or MPI_COMM_NULL if no
communicator is set. */
MPI_Comm GetComm() const
{ return dot_prod_type == 0 ? MPI_COMM_NULL : comm; }
#endif
};
@@ -689,6 +706,25 @@ private:
mutable Array<int> ipiv;
};
/// Monitor that checks whether the residual is zero at a given set of dofs.
/** This monitor is useful for checking if the initial guess, rhs, operator, and
preconditioner are properly setup for solving in the subspace with imposed
essential boundary conditions. */
class ResidualBCMonitor : public IterativeSolverMonitor
{
protected:
const Array<int> *ess_dofs_list; ///< Not owned
public:
ResidualBCMonitor(const Array<int> &ess_dofs_list_)
: ess_dofs_list(&ess_dofs_list_) { }
void MonitorResidual(int it, double norm, const Vector &r,
bool final) override;
};
#ifdef MFEM_USE_SUITESPARSE
/// Direct sparse solver using UMFPACK
@@ -763,6 +799,28 @@ public:
#endif // MFEM_USE_SUITESPARSE
class IncompleteCholesky : public IterativeSolver
{
private:
SparseMatrix *A;
public:
IncompleteCholesky(SparseMatrix &A_);
virtual void Mult(const Vector &b, Vector &x) const;
};
class ILUcusparse : public IterativeSolver
{
private:
SparseMatrix *A;
public:
ILUcusparse(SparseMatrix &A_);
virtual void Mult(const Vector &b, Vector &x) const;
};
}
#endif // MFEM_SOLVERS
+529 -8
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,6 +144,8 @@ SparseMatrix::SparseMatrix(int nrows, int ncols, int rowsize)
{
I[i] = i * rowsize;
}
InitCuSparse();
}
SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph)
@@ -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
@@ -569,7 +610,7 @@ void SparseMatrix::AddMult(const Vector &x, Vector &y, const double a) const
const double *xp = x.HostRead();
double *yp = y.HostReadWrite();
// The matrix is not finalized, but multiplication is still possible
// The matrix is not finalized, but multiplication is still possible
for (int i = 0; i < height; i++)
{
RowNode *row = Rows[i];
@@ -592,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 kernel space. 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 we 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();
@@ -784,6 +881,101 @@ void SparseMatrix::BooleanMultTranspose(const Array<int> &x,
}
}
void SparseMatrix::AbsMult(const Vector &x, Vector &y) const
{
MFEM_ASSERT(width == x.Size(), "Input vector size (" << x.Size()
<< ") must match matrix width (" << width << ")");
MFEM_ASSERT(height == y.Size(), "Output vector size (" << y.Size()
<< ") must match matrix height (" << height << ")");
if (Finalized()) { y.UseDevice(true); }
y = 0.0;
if (!Finalized())
{
const double *xp = x.HostRead();
double *yp = y.HostReadWrite();
// The matrix is not finalized, but multiplication is still possible
for (int i = 0; i < height; i++)
{
RowNode *row = Rows[i];
double b = 0.0;
for ( ; row != NULL; row = row->Prev)
{
b += std::abs(row->Value) * xp[row->Column];
}
*yp += b;
yp++;
}
return;
}
const int height = this->height;
const int nnz = J.Capacity();
auto d_I = Read(I, height+1);
auto d_J = Read(J, nnz);
auto d_A = Read(A, nnz);
auto d_x = x.Read();
auto d_y = y.ReadWrite();
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 += std::abs(d_A[j]) * d_x[d_J[j]];
}
d_y[i] += d;
});
}
void SparseMatrix::AbsMultTranspose(const Vector &x, Vector &y) const
{
MFEM_ASSERT(height == x.Size(), "Input vector size (" << x.Size()
<< ") must match matrix height (" << height << ")");
MFEM_ASSERT(width == y.Size(), "Output vector size (" << y.Size()
<< ") must match matrix width (" << width << ")");
y = 0.0;
if (!Finalized())
{
double *yp = y.GetData();
// The matrix is not finalized, but multiplication is still possible
for (int i = 0; i < height; i++)
{
RowNode *row = Rows[i];
double b = x(i);
for ( ; row != NULL; row = row->Prev)
{
yp[row->Column] += fabs(row->Value) * b;
}
}
return;
}
if (At)
{
At->AbsMult(x, y);
}
else
{
MFEM_VERIFY(Device::IsDisabled(), "transpose action on device is not "
"enabled; see BuildTranspose() for details.");
for (int i = 0; i < height; i++)
{
const double xi = x[i];
const int end = I[i+1];
for (int j = I[i]; j < end; j++)
{
const int Jj = J[j];
y[Jj] += std::abs(A[j]) * xi;
}
}
}
}
double SparseMatrix::InnerProduct(const Vector &x, const Vector &y) const
{
MFEM_ASSERT(x.Size() == Width(), "x.Size() = " << x.Size()
@@ -2962,6 +3154,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
@@ -3697,4 +3899,323 @@ void SparseMatrix::Swap(SparseMatrix &other)
mfem::Swap(isSorted, other.isSorted);
}
#ifdef MFEM_USE_CUDA
void SparseMatrix::IncompleteCholeskyMult(const Vector &x, Vector &y) const
{
if (!(Device::Allows(Backend::CUDA_MASK) && useCuSparse))
{
y = x;
return;
}
MFEM_VERIFY(initCholesky, "Setup not done");
const double alpha = 1.0;
auto d_x = x.Read();
auto d_y = y.ReadWrite();
auto d_z = vecZ.ReadWrite();
const int height = this->height;
const int nnz = J.Capacity();
int64_t m = height;
auto d_csrRowPtr = Read(I, height+1);
auto d_csrColInd = Read(J, nnz);
auto d_csrVal = Read(A, nnz);
cusparseDnVecSetValues(vecX_descr, const_cast<double *>(d_x));
cusparseDnVecSetValues(vecY_descr, d_y);
cusparseDnVecSetValues(vecZ_descr, d_z);
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
const cusparseOperation_t trans_Lt = CUSPARSE_OPERATION_TRANSPOSE;
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
const cusparseSolvePolicy_t policy_Lt = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
// Solve L*z = x
cusparseDcsrsv2_solve(handle, trans_L, m, nnz, &alpha, descr_L,
d_csrVal, d_csrRowPtr, d_csrColInd, info_L,
d_x, d_z, policy_L, pBuffer);
// Solve L'*y = z
cusparseDcsrsv2_solve(handle, trans_Lt, m, nnz, &alpha, descr_L,
d_csrVal, d_csrRowPtr, d_csrColInd, info_Lt,
d_z, d_y, policy_Lt, pBuffer);
}
void SparseMatrix::IncompleteCholeskySetup()
{
if (!(Device::Allows(Backend::CUDA_MASK) && useCuSparse))
{
return;
}
MFEM_VERIFY(!initILU && !initCholesky, "");
const int height = this->height;
const int nnz = J.Capacity();
auto d_csrRowPtr = Read(I, height+1);
auto d_csrColInd = Read(J, nnz);
auto d_csrVal = Read(A, nnz);
//MFEM_VERIFY(I[0] == 0, "cusparse thinks this is not zero based");
csric02Info_t info_M = 0;
int bufferSize_M;
int pBufferSize_L;
int pBufferSize_Lt;
int pBufferSize;
int structural_zero;
int numerical_zero;
const cusparseSolvePolicy_t policy_M = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
const cusparseSolvePolicy_t policy_Lt = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
const cusparseOperation_t trans_Lt = CUSPARSE_OPERATION_TRANSPOSE;
// step 1: create a descriptor which contains
// - matrix M is base-0
// - matrix L is base-0
// - matrix L is lower triangular
// - matrix L has non-unit diagonal
cusparseCreateMatDescr(&descr_M);
cusparseSetMatIndexBase(descr_M, CUSPARSE_INDEX_BASE_ZERO);
cusparseSetMatType(descr_M, CUSPARSE_MATRIX_TYPE_GENERAL);
cusparseCreateMatDescr(&descr_L);
cusparseSetMatIndexBase(descr_L, CUSPARSE_INDEX_BASE_ZERO);
cusparseSetMatType(descr_L, CUSPARSE_MATRIX_TYPE_GENERAL);
cusparseSetMatFillMode(descr_L, CUSPARSE_FILL_MODE_LOWER);
cusparseSetMatDiagType(descr_L, CUSPARSE_DIAG_TYPE_NON_UNIT);
// step 2: create a empty info structure
// we need one info for csric02 and two info's for csrsv2
cusparseCreateCsric02Info(&info_M);
cusparseCreateCsrsv2Info(&info_L);
cusparseCreateCsrsv2Info(&info_Lt);
int64_t m = height;
// step 3: query how much memory used in csric02 and csrsv2, and allocate the buffer
cusparseDcsric02_bufferSize(handle, m, nnz,
descr_M, const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
const_cast<int *>(d_csrColInd), info_M, &bufferSize_M);
cusparseDcsrsv2_bufferSize(handle, trans_L, m, nnz,
descr_L, const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
const_cast<int *>(d_csrColInd), info_L, &pBufferSize_L);
cusparseDcsrsv2_bufferSize(handle, trans_Lt, m, nnz,
descr_L, const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
const_cast<int *>(d_csrColInd), info_Lt,&pBufferSize_Lt);
pBufferSize = max(bufferSize_M, max(pBufferSize_L, pBufferSize_Lt));
// pBuffer returned by cudaMalloc is automatically aligned to 128 bytes.
cudaMalloc((void**)&pBuffer, pBufferSize);
// step 4: perform analysis of incomplete Cholesky on M
// perform analysis of triangular solve on L
// perform analysis of triangular solve on L'
// The lower triangular part of M has the same sparsity pattern as L, so
// we can do analysis of csric02 and csrsv2 simultaneously.
cusparseDcsric02_analysis(handle, m, nnz, descr_M,
d_csrVal, d_csrRowPtr, d_csrColInd, info_M,
policy_M, pBuffer);
status = cusparseXcsric02_zeroPivot(handle, info_M, &structural_zero);
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
{
printf("A(%d,%d) is missing\n", structural_zero, structural_zero);
}
cusparseDcsrsv2_analysis(handle, trans_L, m, nnz, descr_L,
d_csrVal, d_csrRowPtr, d_csrColInd,
info_L, policy_L, pBuffer);
cusparseDcsrsv2_analysis(handle, trans_Lt, m, nnz, descr_L,
d_csrVal, d_csrRowPtr, d_csrColInd,
info_Lt, policy_Lt, pBuffer);
// step 5: M = L * L'
cusparseDcsric02(handle, m, nnz, descr_M,
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
const_cast<int *>(d_csrColInd), info_M, policy_M, pBuffer);
status = cusparseXcsric02_zeroPivot(handle, info_M, &numerical_zero);
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
{
printf("L(%d,%d) is zero\n", numerical_zero, numerical_zero);
}
vecZ.SetSize(height);
vecZ = 0.0;
auto d_z = vecZ.ReadWrite();
cusparseCreateDnVec(&vecZ_descr, vecZ.Size(), d_z, CUDA_R_64F);
initCholesky = true;
}
void SparseMatrix::ILUMult(const Vector &x, Vector &y) const
{
MFEM_VERIFY(initILU, "Setup not done");
const double alpha = 1.0;
auto d_x = x.Read();
auto d_y = y.ReadWrite();
auto d_z = vecZ.ReadWrite();
const int height = this->height;
const int nnz = J.Capacity();
int64_t m = height;
auto d_csrRowPtr = Read(I, height+1);
auto d_csrColInd = Read(J, nnz);
auto d_csrVal = Read(A, nnz);
cusparseDnVecSetValues(vecX_descr, const_cast<double *>(d_x));
cusparseDnVecSetValues(vecY_descr, d_y);
cusparseDnVecSetValues(vecZ_descr, d_z);
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
const cusparseSolvePolicy_t policy_U = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
const cusparseOperation_t trans_U = CUSPARSE_OPERATION_NON_TRANSPOSE;
// Solve L*z = x
cusparseDcsrsv2_solve(handle, trans_L, m, nnz, &alpha, descr_L,
d_csrVal, d_csrRowPtr, d_csrColInd, info_L,
d_x, d_z, policy_L, pBuffer);
// Solve U*y = z
cusparseDcsrsv2_solve(handle, trans_U, m, nnz, &alpha, descr_U,
d_csrVal, d_csrRowPtr, d_csrColInd, info_U,
d_z, d_y, policy_U, pBuffer);
// TODO: destructor
}
void SparseMatrix::ILUSetup()
{
if (!(Device::Allows(Backend::CUDA_MASK) && useCuSparse))
{
return;
}
MFEM_VERIFY(!initILU && !initCholesky, "");
const int height = this->height;
const int nnz = J.Capacity();
auto d_csrRowPtr = Read(I, height+1);
auto d_csrColInd = Read(J, nnz);
auto d_csrVal = Read(A, nnz);
csrilu02Info_t info_M = 0;
int pBufferSize_M;
int pBufferSize_L;
int pBufferSize_U;
int pBufferSize;
int structural_zero;
int numerical_zero;
const cusparseSolvePolicy_t policy_M = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
const cusparseSolvePolicy_t policy_U = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
const cusparseOperation_t trans_U = CUSPARSE_OPERATION_NON_TRANSPOSE;
// step 1: create a descriptor which contains
// - matrix M is base-0
// - matrix L is base-0
// - matrix L is lower triangular
// - matrix L has unit diagonal
// - matrix U is base-0
// - matrix U is upper triangular
// - matrix U has non-unit diagonal
cusparseCreateMatDescr(&descr_M);
cusparseSetMatIndexBase(descr_M, CUSPARSE_INDEX_BASE_ZERO);
cusparseSetMatType(descr_M, CUSPARSE_MATRIX_TYPE_GENERAL);
cusparseCreateMatDescr(&descr_L);
cusparseSetMatIndexBase(descr_L, CUSPARSE_INDEX_BASE_ZERO);
cusparseSetMatType(descr_L, CUSPARSE_MATRIX_TYPE_GENERAL);
cusparseSetMatFillMode(descr_L, CUSPARSE_FILL_MODE_LOWER);
cusparseSetMatDiagType(descr_L, CUSPARSE_DIAG_TYPE_UNIT);
cusparseCreateMatDescr(&descr_U);
cusparseSetMatIndexBase(descr_U, CUSPARSE_INDEX_BASE_ZERO);
cusparseSetMatType(descr_U, CUSPARSE_MATRIX_TYPE_GENERAL);
cusparseSetMatFillMode(descr_U, CUSPARSE_FILL_MODE_UPPER);
cusparseSetMatDiagType(descr_U, CUSPARSE_DIAG_TYPE_NON_UNIT);
// step 2: create a empty info structure
// we need one info for csrilu02 and two info's for csrsv2
cusparseCreateCsrilu02Info(&info_M);
cusparseCreateCsrsv2Info(&info_L);
cusparseCreateCsrsv2Info(&info_U);
// step 3: query how much memory used in csrilu02 and csrsv2, and allocate the buffer
int64_t m = height;
cusparseDcsrilu02_bufferSize(handle, m, nnz, descr_M,
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
const_cast<int *>(d_csrColInd), info_M, &pBufferSize_M);
cusparseDcsrsv2_bufferSize(handle, trans_L, m, nnz, descr_L,
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
const_cast<int *>(d_csrColInd), info_L, &pBufferSize_L);
cusparseDcsrsv2_bufferSize(handle, trans_U, m, nnz, descr_U,
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
const_cast<int *>(d_csrColInd), info_U, &pBufferSize_U);
pBufferSize = max(pBufferSize_M, max(pBufferSize_L, pBufferSize_U));
// pBuffer returned by cudaMalloc is automatically aligned to 128 bytes.
cudaMalloc((void**)&pBuffer, pBufferSize);
// step 4: perform analysis of incomplete Cholesky on M
// perform analysis of triangular solve on L
// perform analysis of triangular solve on U
// The lower(upper) triangular part of M has the same sparsity pattern as L(U),
// we can do analysis of csrilu0 and csrsv2 simultaneously.
cusparseDcsrilu02_analysis(handle, m, nnz, descr_M,
d_csrVal, d_csrRowPtr, d_csrColInd, info_M,
policy_M, pBuffer);
status = cusparseXcsrilu02_zeroPivot(handle, info_M, &structural_zero);
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
{
printf("A(%d,%d) is missing\n", structural_zero, structural_zero);
}
cusparseDcsrsv2_analysis(handle, trans_L, m, nnz, descr_L,
d_csrVal, d_csrRowPtr, d_csrColInd,
info_L, policy_L, pBuffer);
cusparseDcsrsv2_analysis(handle, trans_U, m, nnz, descr_U,
d_csrVal, d_csrRowPtr, d_csrColInd,
info_U, policy_U, pBuffer); // bug?
// step 5: M = L * U
cusparseDcsrilu02(handle, m, nnz, descr_M,
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
const_cast<int *>(d_csrColInd), info_M, policy_M, pBuffer);
status = cusparseXcsrilu02_zeroPivot(handle, info_M, &numerical_zero);
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
{
printf("U(%d,%d) is zero\n", numerical_zero, numerical_zero);
}
vecZ.SetSize(height);
vecZ = 0.0;
auto d_z = vecZ.ReadWrite();
cusparseCreateDnVec(&vecZ_descr, vecZ.Size(), d_z, CUDA_R_64F);
initILU = true;
// TODO: destructor
}
#endif // MFEM_USE_CUDA
}
+76 -4
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,48 @@ 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;
mutable cusparseDnVecDescr_t vecZ_descr;
mutable Vector vecZ;
cusparseMatDescr_t descr_M = 0;
cusparseMatDescr_t descr_L = 0;
cusparseMatDescr_t descr_U = 0;
csrsv2Info_t info_L = 0;
csrsv2Info_t info_Lt = 0;
csrsv2Info_t info_U = 0;
void *pBuffer = 0;
bool initILU = false;
bool initCholesky = false;
#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. */
@@ -118,6 +163,8 @@ public:
/// 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);
@@ -308,16 +355,22 @@ public:
/// y = A * x, treating all entries as booleans (zero=false, nonzero=true).
/** The actual values stored in the data array, #A, are not used - this means
and that all entries in the sparsity pattern are considered to be true by
that all entries in the sparsity pattern are considered to be true by
this method. */
void BooleanMult(const Array<int> &x, Array<int> &y) const;
/// y = At * x, treating all entries as booleans (zero=false, nonzero=true).
/** The actual values stored in the data array, #A, are not used - this means
and that all entries in the sparsity pattern are considered to be true by
that all entries in the sparsity pattern are considered to be true by
this method. */
void BooleanMultTranspose(const Array<int> &x, Array<int> &y) const;
/// y = |A| * x, using entry-wise absolute values of matrix A
void AbsMult(const Vector &x, Vector &y) const;
/// y = |At| * x, using entry-wise absolute values of the transpose of matrix A
void AbsMultTranspose(const Vector &x, Vector &y) const;
/// Compute y^t A x
double InnerProduct(const Vector &x, const Vector &y) const;
@@ -572,8 +625,27 @@ public:
void Swap(SparseMatrix &other);
#ifdef MFEM_USE_CUDA
void IncompleteCholeskySetup();
void IncompleteCholeskyMult(const Vector &x, Vector &y) const;
void ILUSetup();
void ILUMult(const Vector &x, Vector &y) const;
#endif
/// 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; }
};
+2
View File
@@ -11,6 +11,7 @@
set(SRCS
element.cpp
gmsh.cpp
hexahedron.cpp
mesh.cpp
mesh_operators.cpp
@@ -29,6 +30,7 @@ set(SRCS
set(HDRS
element.hpp
gmsh.hpp
hexahedron.hpp
mesh.hpp
mesh_headers.hpp
+487
View File
@@ -0,0 +1,487 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "gmsh.hpp"
#include "vtk.hpp"
namespace mfem
{
int BarycentricToGmshTet(int *b, int ref)
{
int i = b[0];
int j = b[1];
int k = b[2];
int l = b[3];
bool ibdr = (i == 0);
bool jbdr = (j == 0);
bool kbdr = (k == 0);
bool lbdr = (l == 0);
if (ibdr && jbdr && kbdr)
{
return 0;
}
else if (jbdr && kbdr && lbdr)
{
return 1;
}
else if (ibdr && kbdr && lbdr)
{
return 2;
}
else if (ibdr && jbdr && lbdr)
{
return 3;
}
int offset = 4;
if (jbdr && kbdr) // Edge DOF on j == 0 and k == 0
{
return offset + i - 1;
}
else if (kbdr && lbdr) // Edge DOF on k == 0 and l == 0
{
return offset + ref - 1 + j - 1;
}
else if (ibdr && kbdr) // Edge DOF on i == 0 and k == 0
{
return offset + 2 * (ref - 1) + ref - j - 1;
}
else if (ibdr && jbdr) // Edge DOF on i == 0 and j == 0
{
return offset + 3 * (ref - 1) + ref - k - 1;
}
else if (ibdr && lbdr) // Edge DOF on i == 0 and l == 0
{
return offset + 4 * (ref - 1) + ref - k - 1;
}
else if (jbdr && lbdr) // Edge DOF on j == 0 and l == 0
{
return offset + 5 * (ref - 1) + ref - k - 1;
}
// Recursive numbering for the faces
offset += 6 * (ref - 1);
if (kbdr)
{
int b_out[3];
b_out[0] = j-1;
b_out[1] = i-1;
b_out[2] = ref - i - j - 1;
return offset + BarycentricToVTKTriangle(b_out, ref-3);
}
else if (jbdr)
{
int b_out[3];
b_out[0] = i-1;
b_out[1] = k-1;
b_out[2] = ref - i - k - 1;
offset += (ref - 1) * (ref - 2) / 2;
return offset + BarycentricToVTKTriangle(b_out, ref-3);
}
else if (ibdr)
{
int b_out[3];
b_out[0] = k-1;
b_out[1] = j-1;
b_out[2] = ref - j - k - 1;
offset += (ref - 1) * (ref - 2);
return offset + BarycentricToVTKTriangle(b_out, ref-3);
}
else if (lbdr)
{
int b_out[3];
b_out[0] = ref-j-k-1;
b_out[1] = j-1;
b_out[2] = k-1;
offset += 3 * (ref - 1) * (ref - 2) / 2;
return offset + BarycentricToVTKTriangle(b_out, ref-3);
}
// Recursive numbering for interior
{
int b_out[4];
b_out[0] = i-1;
b_out[1] = j-1;
b_out[2] = k-1;
b_out[3] = ref - i - j - k - 1;
offset += 2 * (ref - 1) * (ref - 2);
return offset + BarycentricToGmshTet(b_out, ref-4);
}
}
int CartesianToGmshQuad(int idx_in[], int ref)
{
int i = idx_in[0];
int j = idx_in[1];
// Do we lie on any of the edges
bool ibdr = (i == 0 || i == ref);
bool jbdr = (j == 0 || j == ref);
if (ibdr && jbdr) // Vertex DOF
{
return (i ? (j ? 2 : 1) : (j ? 3 : 0));
}
int offset = 4;
if (jbdr) // Edge DOF on j==0 or j==ref
{
return offset + (j ? 3*ref - 3 - i : i - 1);
}
else if (ibdr) // Edge DOF on i==0 or i==ref
{
return offset + (i ? ref - 1 + j - 1 : 4*ref - 4 - j);
}
else // Recursive numbering for interior
{
int idx_out[2];
idx_out[0] = i-1;
idx_out[1] = j-1;
offset += 4 * (ref - 1);
return offset + CartesianToGmshQuad(idx_out, ref-2);
}
}
int CartesianToGmshHex(int idx_in[], int ref)
{
int i = idx_in[0];
int j = idx_in[1];
int k = idx_in[2];
// Do we lie on any of the edges
bool ibdr = (i == 0 || i == ref);
bool jbdr = (j == 0 || j == ref);
bool kbdr = (k == 0 || k == ref);
if (ibdr && jbdr && kbdr) // Vertex DOF
{
return (i ? (j ? (k ? 6 : 2) : (k ? 5 : 1)) :
(j ? (k ? 7 : 3) : (k ? 4 : 0)));
}
int offset = 8;
if (jbdr && kbdr) // Edge DOF on x-directed edge
{
return offset + (j ? (k ? 12*ref-12-i: 6*ref-6-i) :
(k ? 8*ref-9+i: i-1));
}
else if (ibdr && kbdr) // Edge DOF on y-directed edge
{
return offset + (k ? (i ? 10*ref-11+j: 9*ref-10+j) :
(i ? 3*ref-4+j: ref-2+j));
}
else if (ibdr && jbdr) // Edge DOF on z-directed edge
{
return offset + (i ? (j ? 6*ref-7+k: 4*ref-5+k) :
(j ? 7*ref-8+k: 2*ref-3+k));
}
else if (ibdr) // Face DOF on x-directed face
{
int idx_out[2];
idx_out[0] = i ? j-1 : k-1;
idx_out[1] = i ? k-1 : j-1;
offset += (12 + (i ? 3 : 2) * (ref - 1)) * (ref - 1);
return offset + CartesianToGmshQuad(idx_out, ref-2);
}
else if (jbdr) // Face DOF on y-directed face
{
int idx_out[2];
idx_out[0] = j ? ref-i-1 : i-1;
idx_out[1] = j ? k-1 : k-1;
offset += (12 + (j ? 4 : 1) * (ref - 1)) * (ref - 1);
return offset + CartesianToGmshQuad(idx_out, ref-2);
}
else if (kbdr) // Face DOF on z-directed face
{
int idx_out[2];
idx_out[0] = k ? i-1 : j-1;
idx_out[1] = k ? j-1 : i-1;
offset += (12 + (k ? 5 : 0) * (ref - 1)) * (ref - 1);
return offset + CartesianToGmshQuad(idx_out, ref-2);
}
else // Recursive numbering for interior
{
int idx_out[3];
idx_out[0] = i-1;
idx_out[1] = j-1;
idx_out[2] = k-1;
offset += (12 + 6 * (ref - 1)) * (ref - 1);
return offset + CartesianToGmshHex(idx_out, ref-2);
}
}
int WedgeToGmshPri(int idx_in[], int ref)
{
int i = idx_in[0];
int j = idx_in[1];
int k = idx_in[2];
int l = ref - i -j;
bool ibdr = (i == 0);
bool jbdr = (j == 0);
bool kbdr = (k == 0 || k == ref);
bool lbdr = (l == 0);
if (ibdr && jbdr && kbdr)
{
return k ? 3 : 0;
}
else if (jbdr && lbdr && kbdr)
{
return k ? 4 : 1;
}
else if (ibdr && lbdr && kbdr)
{
return k ? 5 : 2;
}
int offset = 6;
if (jbdr && kbdr)
{
return offset + (k ? 6 * (ref - 1) + i - 1: i - 1);
}
else if (ibdr && kbdr)
{
return offset + (k ? 7 * (ref -1) + j-1 : ref - 1 + j - 1);
}
else if (ibdr && jbdr)
{
return offset + 2 * (ref - 1) + k - 1;
}
else if (lbdr && kbdr)
{
return offset + (k ? 8 * (ref -1) + j - 1 : 3 * (ref - 1) + j - 1);
}
else if (jbdr && lbdr)
{
return offset + 4 * (ref - 1) + k - 1;
}
else if (ibdr && lbdr)
{
return offset + 5 * (ref - 1) + k - 1;
}
offset += 9 * (ref-1);
if (kbdr) // Triangular faces at k=0 and k=ref
{
int b_out[3];
b_out[0] = k ? i-1 : j-1;
b_out[1] = k ? j-1 : i-1;
b_out[2] = ref - i - j - 1;
offset += k ? (ref-1)*(ref-2) / 2: 0;
return offset + BarycentricToVTKTriangle(b_out, ref-3);
}
offset += (ref-1)*(ref-2);
if (jbdr) // Quadrilateral face at j=0
{
int idx_out[2];
idx_out[0] = i-1;
idx_out[1] = k-1;
return offset + CartesianToGmshQuad(idx_out, ref-2);
}
else if (ibdr) // Quadrilateral face at i=0
{
int idx_out[2];
idx_out[0] = k-1;
idx_out[1] = j-1;
offset += (ref-1)*(ref-1);
return offset + CartesianToGmshQuad(idx_out, ref-2);
}
else if (lbdr) // Quadrilateral face at l=ref-i-j=0
{
int idx_out[2];
idx_out[0] = j-1;
idx_out[1] = k-1;
offset += 2*(ref-1)*(ref-1);
return offset + CartesianToGmshQuad(idx_out, ref-2);
}
offset += 3*(ref-1)*(ref-1);
// The Gmsh Prism interiors are a tensor product of segments of order ref-2
// and triangles of order ref-3
{
int b_out[3];
b_out[0] = i-1;
b_out[1] = j-1;
b_out[2] = ref - i - j - 1;
int ot = BarycentricToVTKTriangle(b_out, ref-3);
int os = (k==1) ? 0 : (k == ref-1 ? 1 : k);
return offset + (ref-1) * ot + os;
}
}
int CartesianToGmshPyramid(int idx_in[], int ref)
{
int i = idx_in[0];
int j = idx_in[1];
int k = idx_in[2];
// Do we lie on any of the edges
bool ibdr = (i == 0 || i == ref-k);
bool jbdr = (j == 0 || j == ref-k);
bool kbdr = (k == 0);
if (ibdr && jbdr && kbdr)
{
return i ? (j ? 2 : 1): (j ? 3 : 0);
}
else if (k == ref)
{
return 4;
}
int offset = 5;
if (jbdr && kbdr)
{
return offset + (j ? (6 * ref - 6 - i) : (i - 1));
}
else if (ibdr && kbdr)
{
return offset + (i ? (3 * ref - 4 + j) : (ref - 2 + j));
}
else if (ibdr && jbdr)
{
return offset + (i ? (j ? 6 : 4) : (j ? 7 : 2 )) * (ref-1) + k - 1;
}
offset += 8*(ref-1);
if (jbdr)
{
int b_out[3];
b_out[0] = j ? ref - i - k - 1 : i - 1;
b_out[1] = k - 1;
b_out[2] = (j ? i - 1 : ref - i - k - 1);
offset += (j ? 3 : 0) * (ref - 1) * (ref - 2) / 2;
return offset + BarycentricToVTKTriangle(b_out, ref-3);
}
else if (ibdr)
{
int b_out[3];
b_out[0] = i ? j - 1: ref - j - k - 1;
b_out[1] = k - 1;
b_out[2] = (i ? ref - j - k - 1: j - 1);
offset += (i ? 2 : 1) * (ref - 1) * (ref - 2) / 2;
return offset + BarycentricToVTKTriangle(b_out, ref-3);
}
else if (kbdr)
{
int idx_out[2];
idx_out[0] = k ? i-1 : j-1;
idx_out[1] = k ? j-1 : i-1;
offset += 2 * (ref - 1) * (ref - 2);
return offset + CartesianToGmshQuad(idx_out, ref-2);
}
offset += (2 * (ref - 2) + (ref - 1)) * (ref - 1) ;
{
int idx_out[3];
idx_out[0] = i-1;
idx_out[1] = j-1;
idx_out[2] = k-1;
return offset + CartesianToGmshPyramid(idx_out, ref-3);
}
}
void GmshHOSegmentMapping(int order, int *map)
{
map[0] = 0;
map[order] = 1;
for (int i=1; i<order; i++)
{
map[i] = i + 1;
}
}
void GmshHOTriangleMapping(int order, int *map)
{
int b[3];
int o = 0;
for (b[1]=0; b[1]<=order; ++b[1])
{
for (b[0]=0; b[0]<=order-b[1]; ++b[0])
{
b[2] = order - b[0] - b[1];
map[o] = BarycentricToVTKTriangle(b, order);
o++;
}
}
}
void GmshHOQuadrilateralMapping(int order, int *map)
{
int b[2];
int o = 0;
for (b[1]=0; b[1]<=order; b[1]++)
{
for (b[0]=0; b[0]<=order; b[0]++)
{
map[o] = CartesianToGmshQuad(b, order);
o++;
}
}
}
void GmshHOTetrahedronMapping(int order, int *map)
{
int b[4];
int o = 0;
for (b[2]=0; b[2]<=order; ++b[2])
{
for (b[1]=0; b[1]<=order-b[2]; ++b[1])
{
for (b[0]=0; b[0]<=order-b[1]-b[2]; ++b[0])
{
b[3] = order - b[0] - b[1] - b[2];
map[o] = BarycentricToGmshTet(b, order);
o++;
}
}
}
}
void GmshHOHexahedronMapping(int order, int *map)
{
int b[3];
int o = 0;
for (b[2]=0; b[2]<=order; b[2]++)
{
for (b[1]=0; b[1]<=order; b[1]++)
{
for (b[0]=0; b[0]<=order; b[0]++)
{
map[o] = CartesianToGmshHex(b, order);
o++;
}
}
}
}
void GmshHOWedgeMapping(int order, int *map)
{
int b[3];
int o = 0;
for (b[2]=0; b[2]<=order; b[2]++)
{
for (b[1]=0; b[1]<=order; b[1]++)
{
for (b[0]=0; b[0]<=order - b[1]; b[0]++)
{
map[o] = WedgeToGmshPri(b, order);
o++;
}
}
}
}
void GmshHOPyramidMapping(int order, int *map)
{
int b[3];
int o = 0;
for (b[2]=0; b[2]<=order; b[2]++)
{
for (b[1]=0; b[1]<=order - b[2]; b[1]++)
{
for (b[0]=0; b[0]<=order - b[2]; b[0]++)
{
map[o] = CartesianToGmshPyramid(b, order);
o++;
}
}
}
}
} // namespace mfem
+55
View File
@@ -0,0 +1,55 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_GMSH
#define MFEM_GMSH
namespace mfem
{
// Helpers for reading high order elements in Gmsh format
/** @name Gmsh High-Order Vertex Mappings
These functions generate the mappings needed to translate the order of
Gmsh's high-order vertices into MFEM's L2 degree of freedom ordering. The
mapping is defined so that MFEM_DoF[i] = Gmsh_Vert[map[i]]. The @a map
array must already be allocated with the proper number of entries for the
element type at the given element @a order.
*/
///@{
/// @brief Generate Gmsh vertex mapping for a Segment
void GmshHOSegmentMapping(int order, int *map);
/// @brief Generate Gmsh vertex mapping for a Triangle
void GmshHOTriangleMapping(int order, int *map);
/// @brief Generate Gmsh vertex mapping for a Quadrilateral
void GmshHOQuadrilateralMapping(int order, int *map);
/// @brief Generate Gmsh vertex mapping for a Tetrahedron
void GmshHOTetrahedronMapping(int order, int *map);
/// @brief Generate Gmsh vertex mapping for a Hexahedron
void GmshHOHexahedronMapping(int order, int *map);
/// @brief Generate Gmsh vertex mapping for a Wedge
void GmshHOWedgeMapping(int order, int *map);
/// @brief Generate Gmsh vertex mapping for a Pyramid
void GmshHOPyramidMapping(int order, int *map);
///@}
} // namespace mfem
#endif
+12
View File
@@ -338,6 +338,7 @@ void Mesh::GetElementTransformation(int i, IsoparametricTransformation *ElTr)
ElTr->Attribute = GetAttribute(i);
ElTr->ElementNo = i;
ElTr->ElementType = ElementTransformation::ELEMENT;
ElTr->Reset();
if (Nodes == NULL)
{
GetPointMatrix(i, ElTr->GetPointMat());
@@ -370,6 +371,7 @@ void Mesh::GetElementTransformation(int i, const Vector &nodes,
ElTr->ElementNo = i;
ElTr->ElementType = ElementTransformation::ELEMENT;
DenseMatrix &pm = ElTr->GetPointMat();
ElTr->Reset();
nodes.HostRead();
if (Nodes == NULL)
{
@@ -424,6 +426,7 @@ void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr)
ElTr->ElementNo = i; // boundary element number
ElTr->ElementType = ElementTransformation::BDR_ELEMENT;
DenseMatrix &pm = ElTr->GetPointMat();
ElTr->Reset();
if (Nodes == NULL)
{
GetBdrPointMatrix(i, pm);
@@ -480,6 +483,7 @@ void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr)
FTr->ElementNo = FaceNo;
FTr->ElementType = ElementTransformation::FACE;
DenseMatrix &pm = FTr->GetPointMat();
FTr->Reset();
if (Nodes == NULL)
{
const int *v = (Dim == 1) ? &FaceNo : faces[FaceNo]->GetVertices();
@@ -562,6 +566,7 @@ void Mesh::GetEdgeTransformation(int EdgeNo, IsoparametricTransformation *EdTr)
EdTr->ElementNo = EdgeNo;
EdTr->ElementType = ElementTransformation::EDGE;
DenseMatrix &pm = EdTr->GetPointMat();
EdTr->Reset();
if (Nodes == NULL)
{
Array<int> v;
@@ -614,6 +619,7 @@ void Mesh::GetLocalPtToSegTransformation(
{
const IntegrationRule *SegVert;
DenseMatrix &locpm = Transf.GetPointMat();
Transf.Reset();
Transf.SetFE(&PointFE);
SegVert = Geometries.GetVertices(Geometry::SEGMENT);
@@ -629,6 +635,7 @@ void Mesh::GetLocalSegToTriTransformation(
const int *tv, *so;
const IntegrationRule *TriVert;
DenseMatrix &locpm = Transf.GetPointMat();
Transf.Reset();
Transf.SetFE(&SegmentFE);
tv = tri_t::Edges[i/64]; // (i/64) is the local face no. in the triangle
@@ -648,6 +655,7 @@ void Mesh::GetLocalSegToQuadTransformation(
const int *qv, *so;
const IntegrationRule *QuadVert;
DenseMatrix &locpm = Transf.GetPointMat();
Transf.Reset();
Transf.SetFE(&SegmentFE);
qv = quad_t::Edges[i/64]; // (i/64) is the local face no. in the quad
@@ -665,6 +673,7 @@ void Mesh::GetLocalTriToTetTransformation(
IsoparametricTransformation &Transf, int i)
{
DenseMatrix &locpm = Transf.GetPointMat();
Transf.Reset();
Transf.SetFE(&TriangleFE);
// (i/64) is the local face no. in the tet
@@ -688,6 +697,7 @@ void Mesh::GetLocalTriToWdgTransformation(
IsoparametricTransformation &Transf, int i)
{
DenseMatrix &locpm = Transf.GetPointMat();
Transf.Reset();
Transf.SetFE(&TriangleFE);
// (i/64) is the local face no. in the pri
@@ -713,6 +723,7 @@ void Mesh::GetLocalQuadToHexTransformation(
IsoparametricTransformation &Transf, int i)
{
DenseMatrix &locpm = Transf.GetPointMat();
Transf.Reset();
Transf.SetFE(&QuadrilateralFE);
// (i/64) is the local face no. in the hex
@@ -734,6 +745,7 @@ void Mesh::GetLocalQuadToWdgTransformation(
IsoparametricTransformation &Transf, int i)
{
DenseMatrix &locpm = Transf.GetPointMat();
Transf.Reset();
Transf.SetFE(&QuadrilateralFE);
// (i/64) is the local face no. in the pri
+823 -109
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -1691,6 +1691,7 @@ void ParMesh::GetFaceNbrElementTransformation(
ElTr->Attribute = elem->GetAttribute();
ElTr->ElementNo = NumOfElements + i;
ElTr->ElementType = ElementTransformation::ELEMENT;
ElTr->Reset();
if (Nodes == NULL)
{
@@ -2370,6 +2371,7 @@ void ParMesh::GetGhostFaceTransformation(
{
// calculate composition of FETr->Loc1 and FETr->Elem1
DenseMatrix &face_pm = FETr->GetPointMat();
FETr->Reset();
if (Nodes == NULL)
{
FETr->Elem1->Transform(FETr->Loc1.Transf.GetPointMat(), face_pm);
+2
View File
@@ -37,6 +37,8 @@ void CreateVTKElementConnectivity(Array<int> &con, Geometry::Type geom,
void WriteVTKEncodedCompressed(std::ostream &out, const void *bytes,
uint32_t nbytes, int compression_level);
int BarycentricToVTKTriangle(int *b, int ref);
const char *VTKByteOrder();
} // namespace mfem
+62 -2
View File
@@ -39,7 +39,7 @@
using namespace mfem;
using namespace std;
// This tranformation can be applied to a mesh with the 't' menu option.
// This transformation can be applied to a mesh with the 't' menu option.
void transformation(const Vector &p, Vector &v)
{
// simple shear transformation
@@ -72,6 +72,28 @@ double region(const Vector &p)
return std::max(std::max(x - 0.25, -y), y - 1.0);
}
// The projection of this function can be plotted with the 'l' menu option
double f(const Vector &p)
{
double x = p(0);
double y = p.Size() > 1 ? p(1) : 0.0;
double z = p.Size() > 2 ? p(2) : 0.0;
if (1)
{
// torus in the xy-plane
const double r_big = 2.0;
const double r_small = 1.0;
return hypot(r_big - hypot(x, y), z) - r_small;
}
if (0)
{
// sphere at the origin:
const double r = 1.0;
return hypot(hypot(x, y), z) - r;
}
}
Mesh *read_par_mesh(int np, const char *mesh_prefix)
{
Mesh *mesh;
@@ -329,6 +351,7 @@ int main (int argc, char *argv[])
"e) View elements\n"
"h) View element sizes, h\n"
"k) View element ratios, kappa\n"
"l) Plot a function\n"
"x) Print sub-element stats\n"
"f) Find physical point in reference space\n"
"p) Generate a partitioning\n"
@@ -667,7 +690,7 @@ int main (int argc, char *argv[])
}
}
// These are the cases that open a new GLVis window
// These are most of the cases that open a new GLVis window
if (mk == 'm' || mk == 'b' || mk == 'e' || mk == 'v' || mk == 'h' ||
mk == 'k' || mk == 'p')
{
@@ -980,6 +1003,43 @@ int main (int argc, char *argv[])
delete bdr_attr_fespace;
}
if (mk == 'l')
{
// Project and plot the function 'f'
int p;
FiniteElementCollection *fec = NULL;
cout << "Enter projection space order: " << flush;
cin >> p;
if (p >= 1)
{
fec = new H1_FECollection(p, mesh->Dimension(),
BasisType::GaussLobatto);
}
else
{
fec = new DG_FECollection(-p, mesh->Dimension(),
BasisType::GaussLegendre);
}
FiniteElementSpace fes(mesh, fec);
GridFunction level(&fes);
FunctionCoefficient coeff(f);
level.ProjectCoefficient(coeff);
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
if (sol_sock.is_open())
{
sol_sock.precision(14);
sol_sock << "solution\n" << *mesh << level << flush;
}
else
{
cout << "Unable to connect to "
<< vishost << ':' << visport << endl;
}
delete fec;
}
if (mk == 'S')
{
const char mesh_file[] = "mesh-explorer.mesh";
+52 -27
View File
@@ -41,7 +41,8 @@
//
// Adapted discrete size:
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor
// Adapted discrete size; explicit combo of metrics; mixed tri/quad mesh:
// mesh-optimizer -m ../../data/square-mixed.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -bnd -qo 6 -cmb 2 -nor
// Adapted discrete size+aspect_ratio:
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -qo 6 -ex -st 1 -nor
@@ -75,6 +76,8 @@
// mesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -lc 10
// ICF combo shape + size (rings, slow convergence):
// mesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 1000 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 1
// Mixed tet / cube / hex mesh with limiting:
// mesh-optimizer -m ../../data/fichera-mixed-p2.mesh -o 4 -rs 1 -mid 301 -tid 1 -fix-bnd -qo 6 -nor -lc 0.25
// 3D pinched sphere shape (the mesh is in the mfem/data GitHub repository):
// * mesh-optimizer -m ../../../mfem_data/ball-pert.mesh -o 4 -rs 0 -mid 303 -tid 1 -ni 20 -ls 2 -li 500 -fix-bnd
// 2D non-conforming shape and equal size:
@@ -546,23 +549,36 @@ int main(int argc, char *argv[])
if (fdscheme) { he_nlf_integ->EnableFiniteDifferences(x); }
he_nlf_integ->SetExactActionFlag(exactaction);
// 12. Setup the quadrature rule for the non-linear form integrator.
const IntegrationRule *ir = NULL;
const int geom_type = fespace->GetFE(0)->GetGeomType();
// Setup the quadrature rules for the TMOP integrator.
IntegrationRules *irules = NULL;
switch (quad_type)
{
case 1: ir = &IntRulesLo.Get(geom_type, quad_order); break;
case 2: ir = &IntRules.Get(geom_type, quad_order); break;
case 3: ir = &IntRulesCU.Get(geom_type, quad_order); break;
default: cout << "Unknown quad_type: " << quad_type << endl;
delete he_nlf_integ; return 3;
case 1: irules = &IntRulesLo; break;
case 2: irules = &IntRules; break;
case 3: irules = &IntRulesCU; break;
default: cout << "Unknown quad_type: " << quad_type << endl; return 3;
}
he_nlf_integ->SetIntegrationRules(*irules, quad_order);
if (dim == 2)
{
cout << "Triangle quadrature points: "
<< irules->Get(Geometry::TRIANGLE, quad_order).GetNPoints()
<< "\nQuadrilateral quadrature points: "
<< irules->Get(Geometry::SQUARE, quad_order).GetNPoints() << endl;
}
if (dim == 3)
{
cout << "Tetrahedron quadrature points: "
<< irules->Get(Geometry::TETRAHEDRON, quad_order).GetNPoints()
<< "\nHexahedron quadrature points: "
<< irules->Get(Geometry::CUBE, quad_order).GetNPoints()
<< "\nPrism quadrature points: "
<< irules->Get(Geometry::PRISM, quad_order).GetNPoints() << endl;
}
cout << "Quadrature points per cell: " << ir->GetNPoints() << endl;
he_nlf_integ->SetIntegrationRule(*ir);
if (normalization) { he_nlf_integ->EnableNormalization(x0); }
// 13. Limit the node movement.
// Limit the node movement.
// The limiting distances can be given by a general function of space.
GridFunction dist(fespace);
dist = 1.0;
@@ -600,7 +616,7 @@ int main(int argc, char *argv[])
}
}
// 14. Setup the final NonlinearForm (which defines the integral of interest,
// 12. Setup the final NonlinearForm (which defines the integral of interest,
// its first and second derivatives). Here we can use a combination of
// metrics, i.e., optimize the sum of two integrals, where both are
// scaled by used-defined space-dependent weights. Note that there are no
@@ -612,6 +628,7 @@ int main(int argc, char *argv[])
TargetConstructor *target_c2 = NULL;
FunctionCoefficient coeff2(weight_fun);
// Explicit combination of metrics.
if (combomet > 0)
{
// First metric.
@@ -631,7 +648,7 @@ int main(int argc, char *argv[])
he_nlf_integ2->SetCoefficient(coeff2);
}
else { he_nlf_integ2 = new TMOP_Integrator(metric2, target_c); }
he_nlf_integ2->SetIntegrationRule(*ir);
he_nlf_integ2->SetIntegrationRules(*irules, quad_order);
if (fdscheme) { he_nlf_integ2->EnableFiniteDifferences(x); }
he_nlf_integ2->SetExactActionFlag(exactaction);
@@ -647,14 +664,15 @@ int main(int argc, char *argv[])
const double init_energy = a.GetGridFunctionEnergy(x);
// 15. Visualize the starting mesh and metric values.
// Visualize the starting mesh and metric values.
// Note that for combinations of metrics, this only shows the first metric.
if (visualization)
{
char title[] = "Initial metric values";
vis_tmop_metric_s(mesh_poly_deg, *metric, *target_c, *mesh, title, 0);
}
// 16. Fix all boundary nodes, or fix only a given component depending on the
// 13. Fix all boundary nodes, or fix only a given component depending on the
// boundary attributes of the given mesh. Attributes 1/2/3 correspond to
// fixed x/y/z components of the node. Attribute 4 corresponds to an
// entirely fixed node. Other boundary attributes do not affect the node
@@ -667,10 +685,10 @@ int main(int argc, char *argv[])
}
else
{
const int nd = fespace->GetBE(0)->GetDof();
int n = 0;
for (int i = 0; i < mesh->GetNBE(); i++)
{
const int nd = fespace->GetBE(i)->GetDof();
const int attr = mesh->GetBdrElement(i)->GetAttribute();
MFEM_VERIFY(!(dim == 2 && attr == 3),
"Boundary attribute 3 must be used only for 3D meshes. "
@@ -683,6 +701,7 @@ int main(int argc, char *argv[])
n = 0;
for (int i = 0; i < mesh->GetNBE(); i++)
{
const int nd = fespace->GetBE(i)->GetDof();
const int attr = mesh->GetBdrElement(i)->GetAttribute();
fespace->GetBdrElementVDofs(i, vdofs);
if (attr == 1) // Fix x components.
@@ -709,7 +728,7 @@ int main(int argc, char *argv[])
a.SetEssentialVDofs(ess_vdofs);
}
// 17. As we use the Newton method to solve the resulting nonlinear system,
// 14. As we use the Newton method to solve the resulting nonlinear system,
// here we setup the linear solver for the system's Jacobian.
Solver *S = NULL;
const double linsol_rtol = 1e-12;
@@ -736,15 +755,17 @@ int main(int argc, char *argv[])
S = minres;
}
// 18. Compute the minimum det(J) of the starting mesh.
// Compute the minimum det(J) of the starting mesh.
tauval = infinity();
const int NE = mesh->GetNE();
for (int i = 0; i < NE; i++)
{
const IntegrationRule &ir =
irules->Get(fespace->GetFE(i)->GetGeomType(), quad_order);
ElementTransformation *transf = mesh->GetElementTransformation(i);
for (int j = 0; j < ir->GetNPoints(); j++)
for (int j = 0; j < ir.GetNPoints(); j++)
{
transf->SetIntPoint(&ir->IntPoint(j));
transf->SetIntPoint(&ir.IntPoint(j));
tauval = min(tauval, transf->Jacobian().Det());
}
}
@@ -752,7 +773,11 @@ int main(int argc, char *argv[])
tauval -= 0.01 * h0.Min(); // Slightly below minJ0 to avoid div by 0.
// Perform the nonlinear optimization.
TMOPNewtonSolver solver(*ir, solver_type);
const IntegrationRule &ir =
irules->Get(fespace->GetFE(0)->GetGeomType(), quad_order);
TMOPNewtonSolver solver(ir, solver_type);
// Provide all integration rules in case of a mixed mesh.
solver.SetIntegrationRules(*irules, quad_order);
if (solver_type == 0)
{
// Specify linear solver when we use a Newton-based solver.
@@ -770,7 +795,7 @@ int main(int argc, char *argv[])
cout << "Nonlinear solver: rtol = " << solver_rtol << " not achieved.\n";
}
// 20. Save the optimized mesh to a file. This output can be viewed later
// 15. Save the optimized mesh to a file. This output can be viewed later
// using GLVis: "glvis -m optimized.mesh".
{
ofstream mesh_ofs("optimized.mesh");
@@ -778,7 +803,7 @@ int main(int argc, char *argv[])
mesh->Print(mesh_ofs);
}
// 21. Compute the amount of energy decrease.
// 16. Compute the amount of energy decrease.
const double fin_energy = a.GetGridFunctionEnergy(x);
double metric_part = fin_energy;
if (lim_const > 0.0 || adapt_lim_const > 0.0)
@@ -798,7 +823,7 @@ int main(int argc, char *argv[])
cout << "The strain energy decreased by: " << setprecision(12)
<< (init_energy - fin_energy) * 100.0 / init_energy << " %." << endl;
// 22. Visualize the final mesh and metric values.
// 17. Visualize the final mesh and metric values.
if (visualization)
{
char title[] = "Final metric values";
@@ -812,7 +837,7 @@ int main(int argc, char *argv[])
600, 600, 300, 300);
}
// 23. Visualize the mesh displacement.
// 18. Visualize the mesh displacement.
if (visualization)
{
x0 -= x;
@@ -827,7 +852,7 @@ int main(int argc, char *argv[])
<< "keys jRmclA" << endl;
}
// 24. Free the used memory.
// 19. Free the used memory.
delete S;
delete target_c2;
delete metric2;
+52 -28
View File
@@ -41,7 +41,8 @@
//
// Adapted discrete size:
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor
// Adapted discrete size; explicit combo of metrics; mixed tri/quad mesh:
// mpirun -np 4 pmesh-optimizer -m ../../data/square-mixed.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -bnd -qo 6 -cmb 2 -nor
// Adapted discrete size+aspect_ratio:
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -qo 6 -ex -st 1 -nor
@@ -75,6 +76,8 @@
// mpirun -np 4 pmesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -lc 10
// ICF combo shape + size (rings, slow convergence):
// mpirun -np 4 pmesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 1000 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 1
// Mixed tet / cube / hex mesh with limiting:
// mpirun -np 4 pmesh-optimizer -m ../../data/fichera-mixed-p2.mesh -o 4 -rs 1 -mid 301 -tid 1 -fix-bnd -qo 6 -nor -lc 0.25
// 3D pinched sphere shape (the mesh is in the mfem/data GitHub repository):
// * mpirun -np 4 pmesh-optimizer -m ../../../mfem_data/ball-pert.mesh -o 4 -rs 0 -mid 303 -tid 1 -ni 20 -ls 2 -li 500 -fix-bnd
// 2D non-conforming shape and equal size:
@@ -482,11 +485,10 @@ int main (int argc, char *argv[])
}
}
double volume_all, volume_ind_all;
int NE_ALL;
MPI_Allreduce(&volume, &volume_all, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce(&volume_ind, &volume_ind_all, 1, MPI_DOUBLE, MPI_SUM,
MPI_COMM_WORLD);
MPI_Allreduce(&NE, &NE_ALL, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
const int NE_ALL = pmesh->GetGlobalNE();
const double avg_zone_size = volume_all / NE_ALL;
@@ -586,25 +588,38 @@ int main (int argc, char *argv[])
if (fdscheme) { he_nlf_integ->EnableFiniteDifferences(x); }
he_nlf_integ->SetExactActionFlag(exactaction);
// 13. Setup the quadrature rule for the non-linear form integrator.
const IntegrationRule *ir = NULL;
const int geom_type = pfespace->GetFE(0)->GetGeomType();
// Setup the quadrature rules for the TMOP integrator.
IntegrationRules *irules = NULL;
switch (quad_type)
{
case 1: ir = &IntRulesLo.Get(geom_type, quad_order); break;
case 2: ir = &IntRules.Get(geom_type, quad_order); break;
case 3: ir = &IntRulesCU.Get(geom_type, quad_order); break;
case 1: irules = &IntRulesLo; break;
case 2: irules = &IntRules; break;
case 3: irules = &IntRulesCU; break;
default:
if (myid == 0) { cout << "Unknown quad_type: " << quad_type << endl; }
return 3;
}
if (myid == 0)
{ cout << "Quadrature points per cell: " << ir->GetNPoints() << endl; }
he_nlf_integ->SetIntegrationRule(*ir);
he_nlf_integ->SetIntegrationRules(*irules, quad_order);
if (myid == 0 && dim == 2)
{
cout << "Triangle quadrature points: "
<< irules->Get(Geometry::TRIANGLE, quad_order).GetNPoints()
<< "\nQuadrilateral quadrature points: "
<< irules->Get(Geometry::SQUARE, quad_order).GetNPoints() << endl;
}
if (myid == 0 && dim == 3)
{
cout << "Tetrahedron quadrature points: "
<< irules->Get(Geometry::TETRAHEDRON, quad_order).GetNPoints()
<< "\nHexahedron quadrature points: "
<< irules->Get(Geometry::CUBE, quad_order).GetNPoints()
<< "\nPrism quadrature points: "
<< irules->Get(Geometry::PRISM, quad_order).GetNPoints() << endl;
}
if (normalization) { he_nlf_integ->ParEnableNormalization(x0); }
// 14. Limit the node movement.
// Limit the node movement.
// The limiting distances can be given by a general function of space.
ParGridFunction dist(pfespace);
dist = 1.0;
@@ -642,7 +657,7 @@ int main (int argc, char *argv[])
}
}
// 15. Setup the final NonlinearForm (which defines the integral of interest,
// 13. Setup the final NonlinearForm (which defines the integral of interest,
// its first and second derivatives). Here we can use a combination of
// metrics, i.e., optimize the sum of two integrals, where both are
// scaled by used-defined space-dependent weights. Note that there are
@@ -654,6 +669,7 @@ int main (int argc, char *argv[])
TargetConstructor *target_c2 = NULL;
FunctionCoefficient coeff2(weight_fun);
// Explicit combination of metrics.
if (combomet > 0)
{
// First metric.
@@ -673,7 +689,7 @@ int main (int argc, char *argv[])
he_nlf_integ2->SetCoefficient(coeff2);
}
else { he_nlf_integ2 = new TMOP_Integrator(metric2, target_c); }
he_nlf_integ2->SetIntegrationRule(*ir);
he_nlf_integ2->SetIntegrationRules(*irules, quad_order);
if (fdscheme) { he_nlf_integ2->EnableFiniteDifferences(x); }
he_nlf_integ2->SetExactActionFlag(exactaction);
@@ -689,14 +705,15 @@ int main (int argc, char *argv[])
const double init_energy = a.GetParGridFunctionEnergy(x);
// 16. Visualize the starting mesh and metric values.
// Visualize the starting mesh and metric values.
// Note that for combinations of metrics, this only shows the first metric.
if (visualization)
{
char title[] = "Initial metric values";
vis_tmop_metric_p(mesh_poly_deg, *metric, *target_c, *pmesh, title, 0);
}
// 17. Fix all boundary nodes, or fix only a given component depending on the
// 14. Fix all boundary nodes, or fix only a given component depending on the
// boundary attributes of the given mesh. Attributes 1/2/3 correspond to
// fixed x/y/z components of the node. Attribute 4 corresponds to an
// entirely fixed node. Other boundary attributes do not affect the node
@@ -709,10 +726,10 @@ int main (int argc, char *argv[])
}
else
{
const int nd = pfespace->GetBE(0)->GetDof();
int n = 0;
for (int i = 0; i < pmesh->GetNBE(); i++)
{
const int nd = pfespace->GetBE(i)->GetDof();
const int attr = pmesh->GetBdrElement(i)->GetAttribute();
MFEM_VERIFY(!(dim == 2 && attr == 3),
"Boundary attribute 3 must be used only for 3D meshes. "
@@ -725,6 +742,7 @@ int main (int argc, char *argv[])
n = 0;
for (int i = 0; i < pmesh->GetNBE(); i++)
{
const int nd = pfespace->GetBE(i)->GetDof();
const int attr = pmesh->GetBdrElement(i)->GetAttribute();
pfespace->GetBdrElementVDofs(i, vdofs);
if (attr == 1) // Fix x components.
@@ -751,7 +769,7 @@ int main (int argc, char *argv[])
a.SetEssentialVDofs(ess_vdofs);
}
// 18. As we use the Newton method to solve the resulting nonlinear system,
// 15. As we use the Newton method to solve the resulting nonlinear system,
// here we setup the linear solver for the system's Jacobian.
Solver *S = NULL;
const double linsol_rtol = 1e-12;
@@ -778,15 +796,17 @@ int main (int argc, char *argv[])
S = minres;
}
// 19. Compute the minimum det(J) of the starting mesh.
// Compute the minimum det(J) of the starting mesh.
tauval = infinity();
const int NE = pmesh->GetNE();
for (int i = 0; i < NE; i++)
{
const IntegrationRule &ir =
irules->Get(pfespace->GetFE(i)->GetGeomType(), quad_order);
ElementTransformation *transf = pmesh->GetElementTransformation(i);
for (int j = 0; j < ir->GetNPoints(); j++)
for (int j = 0; j < ir.GetNPoints(); j++)
{
transf->SetIntPoint(&ir->IntPoint(j));
transf->SetIntPoint(&ir.IntPoint(j));
tauval = min(tauval, transf->Jacobian().Det());
}
}
@@ -800,7 +820,11 @@ int main (int argc, char *argv[])
tauval -= 0.01 * h0min_all; // Slightly below minJ0 to avoid div by 0.
// Perform the nonlinear optimization.
TMOPNewtonSolver solver(pfespace->GetComm(), *ir, solver_type);
const IntegrationRule &ir =
irules->Get(pfespace->GetFE(0)->GetGeomType(), quad_order);
TMOPNewtonSolver solver(pfespace->GetComm(), ir, solver_type);
// Provide all integration rules in case of a mixed mesh.
solver.SetIntegrationRules(*irules, quad_order);
if (solver_type == 0)
{
// Specify linear solver when we use a Newton-based solver.
@@ -818,7 +842,7 @@ int main (int argc, char *argv[])
cout << "Nonlinear solver: rtol = " << solver_rtol << " not achieved.\n";
}
// 21. Save the optimized mesh to a file. This output can be viewed later
// 16. Save the optimized mesh to a file. This output can be viewed later
// using GLVis: "glvis -m optimized -np num_mpi_tasks".
{
ostringstream mesh_name;
@@ -828,7 +852,7 @@ int main (int argc, char *argv[])
pmesh->PrintAsOne(mesh_ofs);
}
// 22. Compute the amount of energy decrease.
// 17. Compute the amount of energy decrease.
const double fin_energy = a.GetParGridFunctionEnergy(x);
double metric_part = fin_energy;
if (lim_const > 0.0 || adapt_lim_const > 0.0)
@@ -851,7 +875,7 @@ int main (int argc, char *argv[])
<< (init_energy - fin_energy) * 100.0 / init_energy << " %." << endl;
}
// 23. Visualize the final mesh and metric values.
// 18. Visualize the final mesh and metric values.
if (visualization)
{
char title[] = "Final metric values";
@@ -865,7 +889,7 @@ int main (int argc, char *argv[])
600, 600, 300, 300);
}
// 23. Visualize the mesh displacement.
// 19. Visualize the mesh displacement.
if (visualization)
{
x0 -= x;
@@ -886,7 +910,7 @@ int main (int argc, char *argv[])
}
}
// 24. Free the used memory.
// 20. Free the used memory.
delete S;
delete target_c2;
delete metric2;
+54 -24
View File
@@ -20,9 +20,10 @@ sub usage {
printf STDOUT <<EOF;
$0 [-h|--help]
$0 {mfem_dir}
$0 [-b <branch>] {mfem_dir}
where: {mfem_dir} is the MFEM source directory [default value: ../..]
-b <branch> is the branch to check [default: HEAD]
-h|--help prints this usage information and exits
This script checks if the current branch history, defined as the commits that
@@ -37,16 +38,14 @@ EOF
}
my $mfem_dir = "../..";
if (scalar @ARGV > 2) {
printf STDERR "Error: too many command line arguments\n";
usage 1;
}
my $branch = "HEAD";
while (my $opt = shift) {
if ($opt) {
if ($opt eq "-h" || $opt eq "--help") {
usage 0;
} elsif ($opt eq "-b") {
$branch = shift;
} else {
$mfem_dir = $opt;
}
@@ -73,7 +72,7 @@ my $max_branch_kb = 1000;
my $status = 0; # Return code
# Get SHA hash of all commits in this branch
my @commits = split /\n/, `git log --pretty=format:%H master..HEAD`;
my @commits = split /\n/, `git log --pretty=format:%H master..$branch`;
# Check if total number of commits in this branch exceeds the maximum allowable
my $ncommits = scalar @commits;
@@ -104,7 +103,7 @@ sub formatSize {
# Loop over each commit in this branch, and check for large diffs
my $total_size = 0;
foreach my $sha (@commits) {
my @blobs = `git diff-tree -r --no-commit-id $sha`;
my @blobs = `git diff-tree -r -c --root --no-commit-id $sha`;
my $nfiles_changed = scalar @blobs;
if ($nfiles_changed > $commit_max_files_changed) {
printf STDERR
@@ -117,23 +116,53 @@ foreach my $sha (@commits) {
my $commit_size = 0;
foreach my $blob (@blobs) {
my @blob_split = (split /\s/, $blob);
my $src = @blob_split[2];
my $dst = @blob_split[3];
my $mode = @blob_split[4];
my $fname = @blob_split[5];
my $nfields = scalar @blob_split;
my $fname = "(no-filename)";
my $blob_size = 0;
# File was added
if ($mode eq "A") { $blob_size += int(`git cat-file -s $dst`); }
# File was copied
elsif ($mode =~ m/C\d*/) { $blob_size += int(`git cat-file -s $dst`); }
elsif ($mode eq "D") { }
# File was modified, use the gzip'ed diff as a proxy of the required git storage
elsif ($mode =~ m/M\d*/) { $blob_size += int(`git diff -U0 --binary $src $dst | gzip -c | wc -c`); }
elsif ($mode =~ m/R\d*/) { }
elsif ($mode eq "T") { }
elsif ($mode eq "U") { }
else { die "Unknown git status letter." }
if ($nfields == 6) {
# 0 or 1 parents
my $src = @blob_split[2];
my $dst = @blob_split[3];
my $mode = @blob_split[4];
$fname = @blob_split[5];
# File was added
if ($mode eq "A") { $blob_size += int(`git cat-file -s $dst`); }
# File was copied
elsif ($mode =~ m/C\d*/) { $blob_size += int(`git cat-file -s $dst`); }
elsif ($mode eq "D") { }
# File was modified, use the gzip'ed diff as a proxy of the required git storage
elsif ($mode =~ m/M\d*/) { $blob_size += int(`git diff -U0 --binary $src $dst | gzip -c | wc -c`); }
elsif ($mode =~ m/R\d*/) { }
elsif ($mode eq "T") { }
elsif ($mode eq "U") { }
else { die "Unknown git status letter." }
} elsif ($nfields == 8) {
# 2 parents
my $src1 = @blob_split[3];
my $src2 = @blob_split[4];
my $dst = @blob_split[5];
my $mode = @blob_split[6];
$fname = @blob_split[7];
if ($mode eq "AA") {
# File was added
$blob_size += int(`git cat-file -s $dst`); }
elsif ($mode eq "DD") { }
elsif ($mode eq "MM") {
# File was modified, use the gzip'ed diff as a proxy of the required git
# storage
my $sz1 = int(`git diff -U0 --binary $src1 $dst | gzip -c | wc -c`);
my $sz2 = int(`git diff -U0 --binary $src2 $dst | gzip -c | wc -c`);
$blob_size += $sz1 < $sz2 ? $sz1 : $sz2; }
elsif ($mode eq "AM") {
my $sz2 = int(`git diff -U0 --binary $src2 $dst | gzip -c | wc -c`);
$blob_size += $sz2; }
elsif ($mode eq "MA") {
my $sz1 = int(`git diff -U0 --binary $src1 $dst | gzip -c | wc -c`);
$blob_size += $sz1; }
else { die "Unknown git status letter: $mode, commit: $sha, file: $fname.\n\t" }
}
if ($blob_size > $max_blob_kb*1024) {
$status = 1;
printf STDERR "\033[31mLarge change of size %s in file %s.\033[0m\n", formatSize($blob_size), $fname;
@@ -155,6 +184,7 @@ if ($total_size > $max_branch_kb*1024) {
}
if ($status) {
printf STDERR "\033[36mBranch $branch has errors.\033[0m\n";
chdir $cur_dir;
my $testname = basename $0;
open(my $f, '>', "$testname.msg");
+3
View File
@@ -25,7 +25,9 @@ set(UNIT_TESTS_SRCS
linalg/test_ilu.cpp
linalg/test_matrix_block.cpp
linalg/test_matrix_dense.cpp
linalg/test_matrix_hypre.cpp
linalg/test_matrix_rectangular.cpp
linalg/test_matrix_sparse.cpp
linalg/test_matrix_square.cpp
linalg/test_ode.cpp
linalg/test_ode2.cpp
@@ -33,6 +35,7 @@ set(UNIT_TESTS_SRCS
linalg/test_cg_indefinite.cpp
linalg/test_vector.cpp
mesh/test_mesh.cpp
mesh/test_ncmesh.cpp
fem/test_1d_bilininteg.cpp
fem/test_2d_bilininteg.cpp
fem/test_3d_bilininteg.cpp
+219 -63
View File
@@ -17,9 +17,107 @@ using namespace mfem;
namespace assemblediagonalpa
{
int dimension;
double coeffFunction(const Vector& x)
{
if (dimension == 2)
{
return sin(8.0 * M_PI * x[0]) * cos(6.0 * M_PI * x[1]) + 2.0;
}
else
{
return sin(8.0 * M_PI * x[0]) * cos(6.0 * M_PI * x[1]) *
sin(4.0 * M_PI * x[2]) +
2.0;
}
}
void vectorCoeffFunction(const Vector & x, Vector & f)
{
f = 0.0;
if (dimension > 1)
{
f[0] = sin(M_PI * x[1]);
f[1] = sin(2.5 * M_PI * x[0]);
}
if (dimension == 3)
{
f[2] = sin(6.1 * M_PI * x[2]);
}
}
void asymmetricMatrixCoeffFunction(const Vector & x, DenseMatrix & f)
{
f = 0.0;
if (dimension == 2)
{
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
f(1,0) = cos(1.3 * M_PI * x[1]); // 2,1
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
f(1,1) = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
}
else if (dimension == 3)
{
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
f(0,2) = sin(4.9 * M_PI * x[2]); // 1,3
f(1,0) = cos(M_PI * x[0]); // 2,1
f(1,1) = 1.1 + sin(6.1 * M_PI * x[1]); // 2,2
f(1,2) = cos(6.1 * M_PI * x[2]); // 2,3
f(2,0) = sin(1.5 * M_PI * x[1]); // 3,1
f(2,1) = cos(2.9 * M_PI * x[0]); // 3,2
f(2,2) = 1.1 + sin(6.1 * M_PI * x[2]); // 3,3
}
}
void fullSymmetricMatrixCoeffFunction(const Vector & x, DenseMatrix & f)
{
f = 0.0;
if (dimension == 2)
{
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
f(1,1) = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
f(1,0) = f(0,1);
}
else if (dimension == 3)
{
f(0,0) = sin(M_PI * x[1]); // 1,1
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
f(0,2) = sin(4.9 * M_PI * x[2]); // 1,3
f(1,1) = sin(6.1 * M_PI * x[1]); // 2,2
f(1,2) = cos(6.1 * M_PI * x[2]); // 2,3
f(2,2) = sin(6.1 * M_PI * x[2]); // 3,3
f(1,0) = f(0,1);
f(2,0) = f(0,2);
f(2,1) = f(1,2);
}
}
void symmetricMatrixCoeffFunction(const Vector & x, Vector & f)
{
f = 0.0;
if (dimension == 2)
{
f[0] = 1.1 + sin(M_PI * x[1]); // 1,1
f[1] = cos(2.5 * M_PI * x[0]); // 1,2
f[2] = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
}
else if (dimension == 3)
{
f[0] = sin(M_PI * x[1]); // 1,1
f[1] = cos(2.5 * M_PI * x[0]); // 1,2
f[2] = sin(4.9 * M_PI * x[2]); // 1,3
f[3] = sin(6.1 * M_PI * x[1]); // 2,2
f[4] = cos(6.1 * M_PI * x[2]); // 2,3
f[5] = sin(6.1 * M_PI * x[2]); // 3,3
}
}
TEST_CASE("massdiag")
{
for (int dimension = 2; dimension < 4; ++dimension)
for (dimension = 2; dimension < 4; ++dimension)
{
for (int ne = 1; ne < 3; ++ne)
{
@@ -67,7 +165,7 @@ TEST_CASE("massdiag")
TEST_CASE("diffusiondiag")
{
for (int dimension = 2; dimension < 4; ++dimension)
for (dimension = 2; dimension < 4; ++dimension)
{
for (int ne = 1; ne < 3; ++ne)
{
@@ -199,81 +297,139 @@ TEST_CASE("Vector Diffusion Diagonal PA",
TEST_CASE("Hcurl/Hdiv diagonal PA")
{
for (int dimension = 2; dimension < 4; ++dimension)
for (dimension = 2; dimension < 4; ++dimension)
{
for (int spaceType = 0; spaceType < 2; ++spaceType)
for (int integrator = 0; integrator < 2; ++integrator)
for (int coeffType = 0; coeffType < 5; ++coeffType)
{
const int numSpaces = (coeffType == 0) ? 2 : 1;
const int numIntegrators = (coeffType == 0) ? 2 : 1;
Coefficient* coeff = nullptr;
VectorCoefficient* vcoeff = nullptr;
MatrixCoefficient* mcoeff = nullptr;
MatrixCoefficient* smcoeff = nullptr;
if (coeffType == 0)
{
for (int ne = 1; ne < 3; ++ne)
coeff = new ConstantCoefficient(12.34);
}
else if (coeffType == 1)
{
coeff = new FunctionCoefficient(&coeffFunction);
}
else if (coeffType == 2)
{
vcoeff = new VectorFunctionCoefficient(dimension, &vectorCoeffFunction);
}
else if (coeffType == 3)
{
mcoeff = new MatrixFunctionCoefficient(dimension,
&fullSymmetricMatrixCoeffFunction);
smcoeff = new MatrixFunctionCoefficient(dimension,
&symmetricMatrixCoeffFunction);
}
else if (coeffType == 4)
{
mcoeff = new MatrixFunctionCoefficient(dimension,
&asymmetricMatrixCoeffFunction);
smcoeff = new MatrixFunctionCoefficient(dimension,
&asymmetricMatrixCoeffFunction);
}
for (int spaceType = 0; spaceType < numSpaces; ++spaceType)
{
for (int integrator = 0; integrator < numIntegrators; ++integrator)
{
if (spaceType == 0)
std::cout << "Testing " << dimension <<
"D partial assembly H(curl) diagonal for integrator " << integrator << ": "
<< std::pow(ne, dimension) << " elements." << std::endl;
else
std::cout << "Testing " << dimension <<
"D partial assembly H(div) diagonal for integrator " << integrator << ": "
<< std::pow(ne, dimension) << " elements." << std::endl;
for (int order = 1; order < 4; ++order)
for (int ne = 1; ne < 3; ++ne)
{
Mesh * mesh;
if (dimension == 2)
{
mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
}
if (spaceType == 0)
std::cout << "Testing " << dimension <<
"D partial assembly H(curl) diagonal for integrator " << integrator
<< " and coeffType " << coeffType << ": "
<< std::pow(ne, dimension) << " elements." << std::endl;
else
{
mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
}
std::cout << "Testing " << dimension <<
"D partial assembly H(div) diagonal for integrator " << integrator
<< " and coeffType " << coeffType << ": "
<< std::pow(ne, dimension) << " elements." << std::endl;
FiniteElementCollection* fec = (spaceType == 0) ?
(FiniteElementCollection*) new ND_FECollection(order, dimension) :
(FiniteElementCollection*) new RT_FECollection(order, dimension);
FiniteElementSpace fespace(mesh, fec);
BilinearForm paform(&fespace);
BilinearForm faform(&fespace);
ConstantCoefficient one(1.0);
paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
if (integrator == 0)
for (int order = 1; order < 4; ++order)
{
paform.AddDomainIntegrator(new VectorFEMassIntegrator(one));
faform.AddDomainIntegrator(new VectorFEMassIntegrator(one));
}
else
{
if (spaceType == 0)
Mesh * mesh;
if (dimension == 2)
{
paform.AddDomainIntegrator(new CurlCurlIntegrator(one));
faform.AddDomainIntegrator(new CurlCurlIntegrator(one));
mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
}
else
{
paform.AddDomainIntegrator(new DivDivIntegrator(one));
faform.AddDomainIntegrator(new DivDivIntegrator(one));
mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
}
FiniteElementCollection* fec = (spaceType == 0) ?
(FiniteElementCollection*) new ND_FECollection(order, dimension) :
(FiniteElementCollection*) new RT_FECollection(order, dimension);
FiniteElementSpace fespace(mesh, fec);
BilinearForm paform(&fespace);
BilinearForm faform(&fespace);
paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
if (integrator == 0)
{
if (coeffType >= 3)
{
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*smcoeff));
faform.AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff));
}
else if (coeffType == 2)
{
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
faform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
}
else
{
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
faform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
}
}
else
{
if (spaceType == 0)
{
paform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff));
faform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff));
}
else
{
paform.AddDomainIntegrator(new DivDivIntegrator(*coeff));
faform.AddDomainIntegrator(new DivDivIntegrator(*coeff));
}
}
paform.Assemble();
Vector pa_diag(fespace.GetVSize());
paform.AssembleDiagonal(pa_diag);
faform.Assemble();
faform.Finalize();
Vector assembly_diag(fespace.GetVSize());
faform.SpMat().GetDiag(assembly_diag);
assembly_diag -= pa_diag;
double error = assembly_diag.Norml2();
std::cout << " order: " << order << ", error norm: " << error << std::endl;
REQUIRE(assembly_diag.Norml2() < 1.e-11);
delete mesh;
delete fec;
}
paform.Assemble();
Vector pa_diag(fespace.GetVSize());
paform.AssembleDiagonal(pa_diag);
} // ne
} // integrator
} // spaceType
faform.Assemble();
faform.Finalize();
Vector assembly_diag(fespace.GetVSize());
faform.SpMat().GetDiag(assembly_diag);
assembly_diag -= pa_diag;
double error = assembly_diag.Norml2();
std::cout << " order: " << order << ", error norm: " << error << std::endl;
REQUIRE(assembly_diag.Norml2() < 1.e-12);
delete mesh;
delete fec;
}
}
}
}
delete coeff;
delete vcoeff;
delete mcoeff;
delete smcoeff;
} // coeffType
} // dimension
}
} // namespace assemblediagonalpa
+81 -26
View File
@@ -48,7 +48,6 @@ void test_assembly_level(Mesh &&mesh, int order, bool dg, const int pb,
const AssemblyLevel assembly)
{
mesh.EnsureNodes();
mesh.SetCurvature(mesh.GetNodalFESpace()->GetOrder(0));
int dim = mesh.Dimension();
FiniteElementCollection *fec;
@@ -107,13 +106,77 @@ void test_assembly_level(Mesh &&mesh, int order, bool dg, const int pb,
TEST_CASE("Assembly Levels", "[AssemblyLevel]")
{
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
SECTION("Continuous Galerkin")
{
for (int pb : {0, 1, 2})
const bool dg = false;
SECTION("2D")
{
for (bool dg : {true, false})
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
{
SECTION("2D")
for (int pb : {0, 1, 2})
{
for (int order : {2, 3, 4})
{
test_assembly_level(Mesh("../../data/inline-quad.mesh", 1, 1),
order, dg, pb, assembly);
test_assembly_level(Mesh("../../data/periodic-hexagon.mesh", 1, 1),
order, dg, pb, assembly);
test_assembly_level(Mesh("../../data/star-q3.mesh", 1, 1),
order, dg, pb, assembly);
}
}
}
}
SECTION("3D")
{
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
{
for (int pb : {0, 1, 2})
{
int order = 2;
test_assembly_level(Mesh("../../data/inline-hex.mesh", 1, 1),
order, dg, pb, assembly);
test_assembly_level(Mesh("../../data/fichera-q3.mesh", 1, 1),
order, dg, pb, assembly);
}
}
}
SECTION("AMR 2D")
{
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
{
for (int pb : {0, 1, 2})
{
for (int order : {2, 3, 4})
{
test_assembly_level(Mesh("../../data/amr-quad.mesh", 1, 1),
order, false, 0, assembly);
}
}
}
}
SECTION("AMR 3D")
{
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
{
for (int pb : {0, 1, 2})
{
int order = 2;
test_assembly_level(Mesh("../../data/fichera-amr.mesh", 1, 1),
order, false, 0, assembly);
}
}
}
}
SECTION("Discontinuous Galerkin")
{
const bool dg = true;
SECTION("2D")
{
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
{
for (int pb : {0, 1, 2})
{
for (int order : {2, 3, 4})
{
@@ -125,32 +188,24 @@ TEST_CASE("Assembly Levels", "[AssemblyLevel]")
order, dg, pb, assembly);
}
}
SECTION("3D")
{
int order = 2;
test_assembly_level(Mesh("../../data/periodic-cube.mesh", 1, 1),
order, dg, pb, assembly);
test_assembly_level(Mesh("../../data/fichera-q3.mesh", 1, 1),
order, dg, pb, assembly);
}
}
// Test AMR cases (DG not implemented)
SECTION("AMR 2D")
}
SECTION("3D")
{
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
{
for (int order : {2, 3, 4})
for (int pb : {0, 1, 2})
{
test_assembly_level(Mesh("../../data/amr-quad.mesh", 1, 1),
order, false, 0, assembly);
for (bool dg : {true, false})
{
int order = 2;
test_assembly_level(Mesh("../../data/periodic-cube.mesh", 1, 1),
order, dg, pb, assembly);
test_assembly_level(Mesh("../../data/fichera-q3.mesh", 1, 1),
order, dg, pb, assembly);
}
}
}
SECTION("AMR 3D")
{
int order = 2;
test_assembly_level(Mesh("../../data/fichera-amr.mesh", 1, 1),
order, false, 0, assembly);
}
}
}
} // test case
+235 -54
View File
@@ -59,6 +59,74 @@ double linearFunction(const Vector & x)
}
}
void asymmetricMatrixCoeffFunction(const Vector & x, DenseMatrix & f)
{
f = 0.0;
if (dimension == 2)
{
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
f(1,0) = cos(1.3 * M_PI * x[1]); // 2,1
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
f(1,1) = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
}
else if (dimension == 3)
{
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
f(0,2) = sin(4.9 * M_PI * x[2]); // 1,3
f(1,0) = cos(M_PI * x[0]); // 2,1
f(1,1) = 1.1 + sin(6.1 * M_PI * x[1]); // 2,2
f(1,2) = cos(6.1 * M_PI * x[2]); // 2,3
f(2,0) = sin(1.5 * M_PI * x[1]); // 3,1
f(2,1) = cos(2.9 * M_PI * x[0]); // 3,2
f(2,2) = 1.1 + sin(6.1 * M_PI * x[2]); // 3,3
}
}
void fullSymmetricMatrixCoeffFunction(const Vector & x, DenseMatrix & f)
{
f = 0.0;
if (dimension == 2)
{
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
f(1,1) = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
f(1,0) = f(0,1);
}
else if (dimension == 3)
{
f(0,0) = sin(M_PI * x[1]); // 1,1
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
f(0,2) = sin(4.9 * M_PI * x[2]); // 1,3
f(1,1) = sin(6.1 * M_PI * x[1]); // 2,2
f(1,2) = cos(6.1 * M_PI * x[2]); // 2,3
f(2,2) = sin(6.1 * M_PI * x[2]); // 3,3
f(1,0) = f(0,1);
f(2,0) = f(0,2);
f(2,1) = f(1,2);
}
}
void symmetricMatrixCoeffFunction(const Vector & x, Vector & f)
{
f = 0.0;
if (dimension == 2)
{
f[0] = 1.1 + sin(M_PI * x[1]); // 1,1
f[1] = cos(2.5 * M_PI * x[0]); // 1,2
f[2] = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
}
else if (dimension == 3)
{
f[0] = sin(M_PI * x[1]); // 1,1
f[1] = cos(2.5 * M_PI * x[0]); // 1,2
f[2] = sin(4.9 * M_PI * x[2]); // 1,3
f[3] = sin(6.1 * M_PI * x[1]); // 2,2
f[4] = cos(6.1 * M_PI * x[2]); // 2,3
f[5] = sin(6.1 * M_PI * x[2]); // 3,3
}
}
TEST_CASE("H1 pa_coeff")
{
for (dimension = 2; dimension < 4; ++dimension)
@@ -185,11 +253,13 @@ TEST_CASE("Hcurl/Hdiv pa_coeff")
mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
}
for (int coeffType = 0; coeffType < 3; ++coeffType)
for (int coeffType = 0; coeffType < 5; ++coeffType)
{
Coefficient* coeff = nullptr;
Coefficient* coeff2 = nullptr;
VectorCoefficient* vcoeff = nullptr;
MatrixCoefficient* mcoeff = nullptr;
MatrixCoefficient* smcoeff = nullptr;
if (coeffType == 0)
{
coeff = new ConstantCoefficient(12.34);
@@ -205,33 +275,73 @@ TEST_CASE("Hcurl/Hdiv pa_coeff")
vcoeff = new VectorFunctionCoefficient(dimension, &vectorCoeffFunction);
coeff2 = new FunctionCoefficient(&linearFunction);
}
for (int spaceType = 0; spaceType < 2; ++spaceType)
else if (coeffType == 3)
{
if (spaceType == 1 && coeffType == 2)
mcoeff = new MatrixFunctionCoefficient(dimension,
&fullSymmetricMatrixCoeffFunction);
smcoeff = new MatrixFunctionCoefficient(dimension,
&symmetricMatrixCoeffFunction);
coeff2 = new FunctionCoefficient(&linearFunction);
}
else if (coeffType == 4)
{
mcoeff = new MatrixFunctionCoefficient(dimension,
&asymmetricMatrixCoeffFunction);
smcoeff = new MatrixFunctionCoefficient(dimension,
&asymmetricMatrixCoeffFunction);
coeff2 = new FunctionCoefficient(&linearFunction);
}
enum MixedSpaces {Hcurl, Hdiv, HcurlHdiv, HdivHcurl, NumSpaceTypes};
for (int spaceType = 0; spaceType < NumSpaceTypes; ++spaceType)
{
if (spaceType == Hdiv && coeffType >= 2)
{
continue; // Case not implemented yet
}
const int numIntegrators = (coeffType == 2) ? 2 : 3;
const int numIntegrators =
(spaceType >= HcurlHdiv) ? 1 : ((coeffType == 2) ? 2 : 3);
for (int integrator = 0; integrator < numIntegrators; ++integrator)
{
if (spaceType == 0)
if (spaceType == Hcurl)
std::cout << "Testing " << dimension
<< "D ND partial assembly with " << "coeffType "
<< coeffType << " and " << "integrator "
<< "D ND partial assembly with coeffType "
<< coeffType << " and integrator "
<< integrator << std::endl;
else
else if (spaceType == Hdiv)
std::cout << "Testing " << dimension
<< "D RT partial assembly with " << "coeffType "
<< coeffType << " and " << "integrator "
<< "D RT partial assembly with coeffType "
<< coeffType << " and integrator "
<< integrator << std::endl;
else if (spaceType == HcurlHdiv)
std::cout << "Testing " << dimension
<< "D ND x RT partial assembly with coeffType "
<< coeffType << " and integrator "
<< integrator << std::endl;
else // HdivHcurl
std::cout << "Testing " << dimension
<< "D RT x ND partial assembly with coeffType "
<< coeffType << " and integrator "
<< integrator << std::endl;
for (int order = 1; order < 4; ++order)
{
FiniteElementCollection* fec = (spaceType == 0) ?
(FiniteElementCollection*) new ND_FECollection(order, dimension) :
(FiniteElementCollection*) new RT_FECollection(order, dimension);
FiniteElementCollection* fec = nullptr;
if (spaceType == Hcurl || spaceType == HcurlHdiv)
{
fec = (FiniteElementCollection*) new ND_FECollection(order, dimension);
}
else if (spaceType == HdivHcurl)
{
fec = (FiniteElementCollection*) new RT_FECollection(order - 1, dimension);
}
else
{
fec = (FiniteElementCollection*) new RT_FECollection(order, dimension);
}
FiniteElementSpace fespace(mesh, fec);
@@ -270,59 +380,127 @@ TEST_CASE("Hcurl/Hdiv pa_coeff")
}
}
BilinearForm paform(&fespace);
paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
BilinearForm assemblyform(&fespace);
if (integrator < 2)
Vector xin(fespace.GetTrueVSize());
xin.Randomize();
Vector y_mat, y_assembly, y_pa;
if (spaceType >= HcurlHdiv)
{
if (coeffType == 2)
FiniteElementCollection* fecTest = nullptr;
if (spaceType == HcurlHdiv)
{
fecTest = (FiniteElementCollection*) new RT_FECollection(order - 1, dimension);
}
else
{
fecTest = (FiniteElementCollection*) new ND_FECollection(order, dimension);
}
FiniteElementSpace fespaceTest(mesh, fecTest);
MixedBilinearForm paform(&fespace, &fespaceTest);
paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
MixedBilinearForm assemblyform(&fespace, &fespaceTest);
const int testSize = fespaceTest.GetTrueVSize();
y_mat.SetSize(testSize);
y_mat = 0.0;
y_assembly.SetSize(testSize);
y_assembly = 0.0;
y_pa.SetSize(testSize);
y_pa = 0.0;
if (coeffType >= 3)
{
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*smcoeff));
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff));
}
else if (coeffType == 2)
{
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
assemblyform.AddDomainIntegrator(
new VectorFEMassIntegrator(*vcoeff));
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
}
else
{
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
assemblyform.AddDomainIntegrator(
new VectorFEMassIntegrator(*coeff));
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
}
Array<int> empty_ess; // empty
paform.Assemble();
OperatorHandle paopr;
paform.FormRectangularSystemMatrix(ess_tdof_list, empty_ess, paopr);
assemblyform.Assemble();
SparseMatrix A_explicit;
assemblyform.FormRectangularSystemMatrix(ess_tdof_list, empty_ess, A_explicit);
paopr->Mult(xin, y_pa);
assemblyform.Mult(xin, y_assembly);
A_explicit.Mult(xin, y_mat);
delete fecTest;
}
if (integrator > 0)
else
{
if (spaceType == 0)
BilinearForm paform(&fespace);
paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
BilinearForm assemblyform(&fespace);
y_mat.SetSize(xin.Size());
y_mat = 0.0;
y_assembly.SetSize(xin.Size());
y_assembly = 0.0;
y_pa.SetSize(xin.Size());
y_pa = 0.0;
if (integrator < 2)
{
paform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff2));
assemblyform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff2));
if (coeffType >= 3)
{
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*smcoeff));
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff));
}
else if (coeffType == 2)
{
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
}
else
{
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
}
}
else
if (integrator > 0)
{
paform.AddDomainIntegrator(new DivDivIntegrator(*coeff2));
assemblyform.AddDomainIntegrator(new DivDivIntegrator(*coeff2));
if (spaceType == Hcurl)
{
paform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff2));
assemblyform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff2));
}
else
{
paform.AddDomainIntegrator(new DivDivIntegrator(*coeff2));
assemblyform.AddDomainIntegrator(new DivDivIntegrator(*coeff2));
}
}
paform.Assemble();
OperatorHandle paopr;
paform.FormSystemMatrix(ess_tdof_list, paopr);
assemblyform.SetDiagonalPolicy(Matrix::DIAG_ONE);
assemblyform.Assemble();
SparseMatrix A_explicit;
assemblyform.FormSystemMatrix(ess_tdof_list, A_explicit);
paopr->Mult(xin, y_pa);
assemblyform.Mult(xin, y_assembly);
A_explicit.Mult(xin, y_mat);
}
paform.Assemble();
OperatorHandle paopr;
paform.FormSystemMatrix(ess_tdof_list, paopr);
assemblyform.SetDiagonalPolicy(Matrix::DIAG_ONE);
assemblyform.Assemble();
assemblyform.Finalize();
SparseMatrix A_explicit;
assemblyform.FormSystemMatrix(ess_tdof_list, A_explicit);
Vector xin(fespace.GetTrueVSize());
xin.Randomize();
Vector y_mat(xin);
y_mat = 0.0;
Vector y_assembly(xin);
y_assembly = 0.0;
Vector y_pa(xin);
y_pa = 0.0;
paopr->Mult(xin, y_pa);
assemblyform.Mult(xin, y_assembly);
A_explicit.Mult(xin, y_mat);
y_pa -= y_mat;
double pa_error = y_pa.Norml2();
@@ -344,6 +522,9 @@ TEST_CASE("Hcurl/Hdiv pa_coeff")
delete coeff;
delete coeff2;
delete vcoeff;
delete mcoeff;
delete smcoeff;
}
delete mesh;
@@ -382,9 +563,9 @@ TEST_CASE("Hcurl/Hdiv mixed pa_coeff")
vcoeff = new VectorFunctionCoefficient(dimension, &vectorCoeffFunction);
}
enum MixedSpaces {HcurlH1, HcurlL2, HdivL2};
enum MixedSpaces {HcurlH1, HcurlL2, HdivL2, NumSpaceTypes};
for (int spaceType = 0; spaceType < 3; ++spaceType)
for (int spaceType = 0; spaceType < NumSpaceTypes; ++spaceType)
{
if (spaceType == HdivL2 && coeffType == 1)
{
+8 -6
View File
@@ -422,9 +422,9 @@ void test_pa_convection(Mesh &&mesh, int order, bool dg)
//Basic unit test for convection
TEST_CASE("PA Convection", "[PartialAssembly]")
{
for (bool dg : {true, false})
SECTION("2D")
{
SECTION("2D")
for (bool dg : {true, false})
{
for (int order : {2, 3, 4})
{
@@ -433,8 +433,10 @@ TEST_CASE("PA Convection", "[PartialAssembly]")
test_pa_convection(Mesh("../../data/star-q3.mesh", 1, 1), order, dg);
}
}
SECTION("3D")
}
SECTION("3D")
{
for (bool dg : {true, false})
{
int order = 2;
test_pa_convection(Mesh("../../data/periodic-cube.mesh", 1, 1), order, dg);
@@ -442,9 +444,9 @@ TEST_CASE("PA Convection", "[PartialAssembly]")
}
}
// Test AMR cases (DG not implemented)
for (int order : {2, 3, 4})
SECTION("AMR 2D")
{
SECTION("AMR 2D")
for (int order : {2, 3, 4})
{
test_pa_convection(Mesh("../../data/amr-quad.mesh", 1, 1), order, false);
}
+106
View File
@@ -0,0 +1,106 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "catch.hpp"
#include "mfem.hpp"
namespace mfem
{
constexpr double EPS = 1.e-12;
#ifdef MFEM_USE_MPI
TEST_CASE("HypreParMatrixAbsMult", "[Parallel], [HypreParMatrixAbsMult]")
{
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int dim = 2;
int ne = 4;
for (int order = 1; order <= 3; ++order)
{
Mesh * mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
FiniteElementCollection *hdiv_coll(new RT_FECollection(order, dim));
FiniteElementCollection *l2_coll(new L2_FECollection(order, dim));
ParFiniteElementSpace R_space(pmesh, hdiv_coll);
ParFiniteElementSpace W_space(pmesh, l2_coll);
int n = R_space.GetTrueVSize();
int m = W_space.GetTrueVSize();
ParMixedBilinearForm a(&R_space, &W_space);
a.AddDomainIntegrator(new VectorFEDivergenceIntegrator);
a.Assemble();
a.Finalize();
HypreParMatrix *A = a.ParallelAssemble();
HypreParMatrix *Aabs = new HypreParMatrix(*A);
hypre_ParCSRMatrix * AparCSR = *Aabs;
int nnzd = AparCSR->diag->num_nonzeros;
for (int j = 0; j < nnzd; j++)
{
AparCSR->diag->data[j] = fabs(AparCSR->diag->data[j]);
}
int nnzoffd = AparCSR->offd->num_nonzeros;
for (int j = 0; j < nnzoffd; j++)
{
AparCSR->offd->data[j] = fabs(AparCSR->offd->data[j]);
}
Vector X0(n), X1(n);
Vector Y0(m), Y1(m);
X0.Randomize();
Y0.Randomize(1);
Y1.Randomize(1);
A->AbsMult(3.4,X0,-2.3,Y0);
Aabs->Mult(3.4,X0,-2.3,Y1);
Y1 -=Y0;
double error = Y1.Norml2();
std::cout << "Testing AbsMult: order: " << order
<< ", error norm on rank "
<< rank << ": " << error << std::endl;
REQUIRE(error == Approx(EPS));
MPI_Barrier(MPI_COMM_WORLD);
Y0.Randomize();
X0.Randomize(1);
X1.Randomize(1);
A->AbsMultTranspose(3.4,Y0,-2.3,X0);
Aabs->MultTranspose(3.4,Y0,-2.3,X1);
X1 -=X0;
error = X1.Norml1();
std::cout << "Testing AbsMultT: order: " << order
<< ", error norm on rank "
<< rank << ": " << error << std::endl;
REQUIRE(error == Approx(EPS));
delete A;
delete Aabs;
delete hdiv_coll;
delete l2_coll;
delete pmesh;
}
}
#endif // MFEM_USE_MPI
} // namespace mfem
+89
View File
@@ -0,0 +1,89 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "catch.hpp"
#include "mfem.hpp"
namespace mfem
{
constexpr double EPS = 1.e-12;
TEST_CASE("SparseMatrixAbsMult", "[SparseMatrixAbsMult]")
{
int dim = 2;
int ne = 4;
for (int order = 1; order <= 3; ++order)
{
Mesh * mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
FiniteElementCollection *hdiv_coll(new RT_FECollection(order, dim));
FiniteElementCollection *l2_coll(new L2_FECollection(order, dim));
FiniteElementSpace R_space(mesh, hdiv_coll);
FiniteElementSpace W_space(mesh, l2_coll);
int n = R_space.GetTrueVSize();
int m = W_space.GetTrueVSize();
MixedBilinearForm a(&R_space, &W_space);
a.AddDomainIntegrator(new VectorFEDivergenceIntegrator);
a.Assemble();
a.Finalize();
SparseMatrix &A = a.SpMat();
SparseMatrix *Aabs = new SparseMatrix(A);
int nnz = Aabs->NumNonZeroElems();
for (int j = 0; j < nnz; j++)
{
Aabs->GetData()[j] = fabs(Aabs->GetData()[j]);
}
Vector X0(n), X1(n);
Vector Y0(m), Y1(m);
X0.Randomize();
Y0.Randomize(1);
Y1.Randomize(1);
A.AbsMult(X0,Y0);
Aabs->Mult(X0,Y1);
Y1 -=Y0;
double error = Y1.Norml2();
std::cout << "Testing AbsMult: order: " << order
<< ", error norm: "
<< error << std::endl;
REQUIRE(error == Approx(EPS));
Y0.Randomize();
X0.Randomize(1);
X1.Randomize(1);
A.AbsMultTranspose(Y0,X0);
Aabs->MultTranspose(Y0,X1);
X1 -=X0;
error = X1.Norml2();
std::cout << "Testing AbsMultT: order: " << order
<< ", error norm: "
<< error << std::endl;
REQUIRE(error == Approx(EPS));
delete Aabs;
delete hdiv_coll;
delete l2_coll;
delete mesh;
}
}
} // namespace mfem
+241
View File
@@ -0,0 +1,241 @@
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "mfem.hpp"
#include "catch.hpp"
namespace mfem
{
constexpr double EPS = 1.e-12;
// Test case: Verify that a conforming mesh yields the same norm for the
// assembled diagonal with PA when using the standard (conforming)
// Mesh vs. the corresponding (non-conforming) NCMesh.
// (note: permutations of the values in the diagonal are expected)
TEST_CASE("NCMesh PA diagonal", "[NCMesh]")
{
SECTION("Quad mesh")
{
int ne = 2;
Mesh mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
Mesh nc_mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
nc_mesh.EnsureNCMesh();
mesh.UniformRefinement();
nc_mesh.UniformRefinement();
int dim = 2;
for (int order = 1; order <= 3; ++order)
{
ND_FECollection fec(order, dim);
FiniteElementSpace fes(&mesh, &fec);
FiniteElementSpace nc_fes(&nc_mesh, &fec);
BilinearForm a(&fes);
BilinearForm nc_a(&nc_fes);
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
nc_a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
ConstantCoefficient coef(1.0);
a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
nc_a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
a.Assemble();
nc_a.Assemble();
Vector diag(fes.GetTrueVSize());
Vector nc_diag(nc_fes.GetTrueVSize());
a.AssembleDiagonal(diag);
nc_a.AssembleDiagonal(nc_diag);
double error = fabs(diag.Norml2() - nc_diag.Norml2());
std::cout << "Testing quad NCMesh PA diag: "
"order: " << order << ", error: " << error << std::endl;
REQUIRE(error == Approx(EPS));
}
}
SECTION("Hexa mesh")
{
int ne = 2;
Mesh mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
Mesh nc_mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
nc_mesh.EnsureNCMesh();
mesh.UniformRefinement();
nc_mesh.UniformRefinement();
int dim = 3;
for (int order = 1; order <= 3; ++order)
{
ND_FECollection fec(order, dim);
FiniteElementSpace fes(&mesh, &fec);
FiniteElementSpace nc_fes(&nc_mesh, &fec);
BilinearForm a(&fes);
BilinearForm nc_a(&nc_fes);
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
nc_a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
ConstantCoefficient coef(1.0);
a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
nc_a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
a.Assemble();
nc_a.Assemble();
Vector diag(fes.GetTrueVSize());
Vector nc_diag(nc_fes.GetTrueVSize());
a.AssembleDiagonal(diag);
nc_a.AssembleDiagonal(nc_diag);
double error = fabs(diag.Sum() - nc_diag.Sum());
std::cout << "Testing hexa NCMesh PA diag: "
"order: " << order << ", error: " << error << std::endl;
REQUIRE(error == Approx(EPS));
}
}
} // test case
#ifdef MFEM_USE_MPI
// Test case: Verify that a conforming mesh yields the same norm for the
// assembled diagonal with PA when using the standard (conforming)
// Mesh vs. the corresponding (non-conforming) NCMesh.
// (note: permutations of the values in the diagonal are expected)
TEST_CASE("pNCMesh PA diagonal", "[Parallel], [NCMesh]")
{
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
SECTION("Quad pmesh")
{
int ne = 2;
Mesh mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
Mesh nc_mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
nc_mesh.EnsureNCMesh();
mesh.UniformRefinement();
nc_mesh.UniformRefinement();
ParMesh pmesh(MPI_COMM_WORLD, mesh);
ParMesh nc_pmesh(MPI_COMM_WORLD, nc_mesh);
int dim = 2;
for (int order = 1; order <= 3; ++order)
{
ND_FECollection fec(order, dim);
ParFiniteElementSpace pfes(&pmesh, &fec);
ParFiniteElementSpace nc_pfes(&nc_pmesh, &fec);
ParBilinearForm a(&pfes);
ParBilinearForm nc_a(&nc_pfes);
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
nc_a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
ConstantCoefficient coef(1.0);
a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
nc_a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
a.Assemble();
nc_a.Assemble();
Vector diag(pfes.GetTrueVSize());
Vector nc_diag(nc_pfes.GetTrueVSize());
a.AssembleDiagonal(diag);
nc_a.AssembleDiagonal(nc_diag);
double diag_lsum = diag.Sum(), nc_diag_lsum = nc_diag.Sum();
double diag_gsum = 0.0, nc_diag_gsum = 0.0;
MPI_Allreduce(&diag_lsum, &diag_gsum, 1, MPI_DOUBLE, MPI_SUM,
MPI_COMM_WORLD);
MPI_Allreduce(&nc_diag_lsum, &nc_diag_gsum, 1, MPI_DOUBLE, MPI_SUM,
MPI_COMM_WORLD);
double error = fabs(diag_gsum - nc_diag_gsum);
if (rank==0)
{
std::cout << "Testing quad pNCMesh PA diag: "
"order: " << order << ", error: " << error << std::endl;
}
REQUIRE(error == Approx(EPS));
MPI_Barrier(MPI_COMM_WORLD);
}
}
SECTION("Hexa pmesh")
{
int ne = 2;
Mesh mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
Mesh nc_mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
nc_mesh.EnsureNCMesh();
mesh.UniformRefinement();
nc_mesh.UniformRefinement();
ParMesh pmesh(MPI_COMM_WORLD, mesh);
ParMesh nc_pmesh(MPI_COMM_WORLD, nc_mesh);
int dim = 3;
for (int order = 1; order <= 3; ++order)
{
ND_FECollection fec(order, dim);
ParFiniteElementSpace pfes(&pmesh, &fec);
ParFiniteElementSpace nc_pfes(&nc_pmesh, &fec);
ParBilinearForm a(&pfes);
ParBilinearForm nc_a(&nc_pfes);
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
nc_a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
ConstantCoefficient coef(1.0);
a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
nc_a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
a.Assemble();
nc_a.Assemble();
Vector diag(pfes.GetTrueVSize());
Vector nc_diag(nc_pfes.GetTrueVSize());
a.AssembleDiagonal(diag);
nc_a.AssembleDiagonal(nc_diag);
double diag_lsum = diag.Sum(), nc_diag_lsum = nc_diag.Sum();
double diag_gsum = 0.0, nc_diag_gsum = 0.0;
MPI_Allreduce(&diag_lsum, &diag_gsum, 1, MPI_DOUBLE, MPI_SUM,
MPI_COMM_WORLD);
MPI_Allreduce(&nc_diag_lsum, &nc_diag_gsum, 1, MPI_DOUBLE, MPI_SUM,
MPI_COMM_WORLD);
double error = fabs(diag_gsum - nc_diag_gsum);
if (rank==0)
{
std::cout << "Testing hexa pNCMesh PA diag: "
"order: " << order << ", error: " << error << std::endl;
}
REQUIRE(error == Approx(EPS));
MPI_Barrier(MPI_COMM_WORLD);
}
}
} // test case
#endif // MFEM_USE_MPI
} // namespace mfem