Compare commits

...
475 Commits
Author SHA1 Message Date
Bernardo e9044a627f Merge branch 'eigen-dev' of github.com:mfem/mfem into eigen-dev 2021-09-03 12:38:04 +02:00
bernardo ce70a6fff0 Minors. 2021-09-03 12:27:49 +02:00
bernardo 3e4deba10c Fixed MFEM build dir path. 2021-09-03 12:27:49 +02:00
bernardo c524be911a Added compilation support for Eigen/Spectra integration. 2021-09-03 12:27:49 +02:00
bernardo 8fe7bea02f Example for Laplace Eigenproblem based on Spectra solver. 2021-09-03 12:27:10 +02:00
bernardo 1e47f7f633 Minor fixes. 2021-09-03 12:27:10 +02:00
bernardo d49881f5e2 Fixed includes. 2021-09-03 12:27:10 +02:00
bernardo b27a28040b Sphere mesh in Gmsh for testing Laplace-Beltrami eigenfunctions calculation. 2021-09-03 12:27:10 +02:00
bernardo ecaf0c15ba Eigen integration for math objects conversion. 2021-09-03 12:27:10 +02:00
bernardo 37f4c9cc5d Support for eigensolver based on Spectra. 2021-09-03 12:27:10 +02:00
bernardo bebeca1311 Added ignores for arpack and spectra eigendecomposition examples. 2021-09-03 12:27:10 +02:00
bernardo 324320d4b4 Added compiling support for ARPACK. 2021-09-03 12:27:09 +02:00
bernardo bb03b99903 Added ARPACK support necessary files. 2021-09-03 12:23:11 +02:00
bernardo ddcea536c1 ARPACK support for eigenvalue problems. 2021-09-03 12:23:11 +02:00
bernardo 4cae939bb4 Include ARPACK solver necessary headers if requested. 2021-09-03 12:23:11 +02:00
bernardo c9e82c3512 Added ignore for ARPACK example output. 2021-09-03 12:23:11 +02:00
bernardo a9bc9c7eb0 Example using ARPACK for eigenvalue decomposition. 2021-09-03 12:23:11 +02:00
bernardo e04c8d4230 Added option to activate ARPACK. 2021-09-03 12:23:11 +02:00
bernardo 8ee2bb39bb Added ARPACK variable. 2021-09-03 12:23:11 +02:00
bernardo 2d09fc56f7 Added define to enable ARPACK support. 2021-09-03 12:23:11 +02:00
bernardo 5380faba38 Added useful ignores for vscode, build folder and user-*.mk files. 2021-09-03 12:23:11 +02:00
Tzanio Kolev 6095628e27 Merge pull request #2489 from mfem/gmsh-zero-attributes
Allow reading Gmsh meshes where all elements have attribute zero [gmsh-zero-attributes]
2021-09-02 08:48:04 -07:00
Will Pazner 8506904200 Update CHANGELOG 2021-09-02 08:43:18 -07:00
Tzanio Kolev 12c7976b2e Merge pull request #2400 from mfem/lin-penta-dev
Linear Prism and Pyramid basis functions [lin-penta-dev]
2021-08-29 18:44:52 -07:00
Tzanio Kolev 3e5e301263 Merge branch 'master' into lin-penta-dev 2021-08-29 18:44:43 -07:00
Will Pazner b76734c582 Add warning if changing element attributes to 1 in gmsh reader 2021-08-25 20:30:16 -07:00
Will Pazner 1ddd1f0f3b Allow reading Gmsh meshes where all elements have attribute zero 2021-08-25 16:06:37 -07:00
Tzanio Kolev b1e84b8127 Merge pull request #2476 from mfem/hypre-fix
Hypre fix due to latest changes [hypre-fix]
2021-08-25 15:29:21 -07:00
Tzanio Kolev 44af467936 Merge pull request #2455 from mfem/kelly_total_error2
Fix total error definition in KellyErrorEstimator
2021-08-25 10:51:11 -07:00
Tzanio Kolev d404934819 Merge pull request #2482 from mfem/ex16doc
Documenting the linearization of K(u) in ex16(p).
2021-08-24 16:06:45 -07:00
Veselin Dobrev e908685036 Fix a couple of issues that came up in nightly testing. 2021-08-24 15:27:39 -07:00
Tzanio d79f5c6c92 Added sample runs with pyramids/wedges in examples 1, 3, 4 and 22 2021-08-22 15:06:00 -07:00
Tzanio Kolev 5b93ea7484 Update CHANGELOG 2021-08-22 14:23:54 -07:00
Tzanio Kolev c7c552f56a Merge branch 'master' into lin-penta-dev 2021-08-22 14:16:46 -07:00
Stowell, Mark L d09bc9b76c Adding CHANGELOG entry 2021-08-20 19:41:49 -07:00
Stowell, Mark L a637478552 Altering pyramid handling in Mesh::MeshGenerator 2021-08-20 19:35:19 -07:00
Tzanio 827a48e31b Update CHANGELOG and INSTALL 2021-08-20 16:59:12 -07:00
Tzanio 7feb27958b Merge branch 'master' into hypre-fix
Conflicts:
	CHANGELOG
2021-08-20 16:58:41 -07:00
Stowell, Mark L 89423a10e7 Modify RT0PyrFiniteElement to match RT_TetrahedronElement as well as RT0TetFiniteElement (which differ from eachother) 2021-08-20 14:48:39 -07:00
Stowell, Mark L 47fa9c6a07 Add ProjectCurl to RT0Wdg and RT0Pyr finite elements 2021-08-20 14:47:44 -07:00
Stowell, Mark L 4390216bca Adding linear ND RT and L2 wedge and pyramid elements to arbitrary order FE collections 2021-08-20 14:46:33 -07:00
Tzanio Kolev 6206c775cc Merge pull request #1046 from mfem/no-tet-reorder-dev
Removing need for ReorientTetMesh [no-tet-reorder-dev]
2021-08-20 14:07:45 -07:00
Tzanio Kolev a078107c51 Merge pull request #2479 from mfem/ads-cuda-use-jacobi
Use l1-Jacobi smoother for ADS with CUDA [ads-cuda-use-jacobi]
2021-08-20 14:07:10 -07:00
victor 7121a753ba Update Changelog 2021-08-20 10:32:53 -07:00
Stowell, Mark L 0b065bc850 Adding linear H1 pyramids to H1_FECollection 2021-08-19 20:11:01 -07:00
Tzanio 1b97908085 Mention that ReorientTetMesh is now deprecated 2021-08-19 18:44:56 -07:00
Stowell, Mark L f8ca84ecc8 Deprecating ParMesh::ReorientTetMesh 2021-08-19 17:56:20 -07:00
Stowell, Mark L 772ed7d894 Deprecating Mesh::ReorientTetMesh and other small changes 2021-08-19 17:53:34 -07:00
Stowell, Mark L 4adcc35a20 Adjusting comment 2021-08-19 17:46:25 -07:00
Stowell, Mark L 8b03d1ba85 Adjusting other comment blocks 2021-08-19 17:40:27 -07:00
Stowell, Mark L c7a2971f0d Removing temporary examples 2021-08-19 17:35:17 -07:00
Stowell, Mark L 7e48976f2f Removing new mesh files 2021-08-19 17:33:36 -07:00
victor 1361e3907d Update with new fix based on hypre's version 2021-08-19 17:18:21 -07:00
Stowell, Mark L a03943e158 Adjusting comments to fill 80 columns 2021-08-19 17:15:07 -07:00
Tzanio 283f5fe681 Editorial changes 2021-08-19 16:13:45 -07:00
Dylan Copeland 6f5ceb97e8 Documenting the linearization of K(u). 2021-08-19 16:02:22 -07:00
Tzanio 6086132442 Moved CHANGELOG comment to correct section + simplified 2021-08-19 15:49:24 -07:00
Tzanio 6a3e6c5d41 Merge branch 'master' into no-tet-reorder-dev 2021-08-19 15:47:19 -07:00
Tzanio Kolev c6e7e72fa6 Merge pull request #2481 from mfem/citation-dev
Add citation links to the GitHub repo
2021-08-19 15:19:03 -07:00
Tzanio Kolev 9148258da9 Update CITATION.cff 2021-08-19 15:06:57 -07:00
Tzanio Kolev 8aa988ad5d Update CITATION.cff 2021-08-19 15:06:09 -07:00
Tzanio Kolev 3a2ec16125 Merge pull request #2478 from mfem/caliper-examples-style
Add caliper to the list of sub-directories under examples
2021-08-19 14:55:40 -07:00
Tzanio Kolev 5e6df07adb Update CITATION.cff 2021-08-19 14:41:09 -07:00
Tzanio Kolev f65f931764 Update CITATION.cff 2021-08-19 14:07:05 -07:00
camierjs 76b41b3ec0 Update CITATION.cff 2021-08-19 12:55:44 -07:00
Veselin Dobrev 58dda43f19 Add ORCID for V. Dobrev 2021-08-19 11:59:46 -07:00
Tzanio Kolev fbf82e4ff6 Added a few more ORCIDs I found. Please correct if wrong... 2021-08-19 11:52:02 -07:00
Tzanio Kolev 105f89079e Update CITATION.cff 2021-08-19 11:45:47 -07:00
Tzanio KolevandStefano Zampini 945636ed0e Update CITATION.cff
Co-authored-by: Stefano Zampini <stefano.zampini@gmail.com>
2021-08-19 11:32:23 -07:00
Tzanio KolevandWill Pazner 967a18eb8c Update CITATION.cff
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2021-08-19 11:02:42 -07:00
Will Pazner 682584d49c Add Will's ORCID 2021-08-19 10:58:28 -07:00
Jakub Červený fe9454abb6 Update CITATION.cff 2021-08-19 19:54:03 +02:00
Tzanio KolevandYohann b75f13682a Update CITATION.cff
Co-authored-by: Yohann <dudouit1@llnl.gov>
2021-08-19 10:45:34 -07:00
Tzanio Kolev 8173b468c7 Tzanio's ORCID 2021-08-19 10:44:50 -07:00
Tzanio f7fa5055c7 Fixed parsing issues 2021-08-19 10:27:21 -07:00
Tzanio 6699f71e2e Added CITATION.cff 2021-08-19 10:10:29 -07:00
Tzanio Kolev 7de0131815 Merge pull request #2468 from mfem/artv3/adjust-pbilinearform-TrueAddMult
Adjust true add mult to use MFEM's GetProlongationMatrix()
2021-08-18 18:33:15 -07:00
Will Pazner 4cd960bd3a Use l1-Jacobi smoother for ADS with CUDA 2021-08-18 17:24:02 -07:00
Veselin Dobrev 88082dc136 Add caliper to the list of sub-directories under examples.
Apply 'make style'.
2021-08-18 16:40:25 -07:00
victor 8da76d18d2 Fix comment 2021-08-18 13:56:08 -07:00
victor 0a6e5734fe Merge branch 'master' into hypre-fix 2021-08-18 13:35:37 -07:00
victor 18336a2936 Run make style 2021-08-18 13:34:00 -07:00
Tzanio Kolev 9af03fc80b Merge pull request #2467 from mfem/artv3/caliper-adjustments
Add additional caliper macros
2021-08-18 13:28:03 -07:00
victor baf09ea081 Update calls according to latest changes in hypre 2021-08-18 13:27:20 -07:00
Stowell, Mark L a23a47b216 Changing order of global object creation 2021-08-18 10:52:24 -07:00
Arturo Vargas 2129d9a4f1 add example with MFEM_PERF_SCOPE 2021-08-17 17:20:12 -07:00
Stowell, Mark L 528154d68d Merge remote-tracking branch 'origin/master' into lin-penta-dev 2021-08-17 12:11:22 -07:00
Arturo Vargas a8deea5def make temp vector mutable 2021-08-17 09:19:31 -07:00
Arturo Vargas fa7d17e0da use vector for temporary, use Gettruevsize to set size 2021-08-17 09:15:31 -07:00
Veselin Dobrev 9f7d5736d3 Merge pull request #2470 from mfem/testing/bernede1/pre-alloc-fix
SLURM update workaround
2021-08-16 21:24:14 -07:00
Adrien M. Bernede 229b94e3fb Finally found an acceptable workaround 2021-08-16 16:00:27 -07:00
Tzanio Kolev 6e149b75e5 Merge pull request #2456 from mfem/const-mesh-ctor-dev
Const parameter for mesh copy assignment
2021-08-15 18:16:37 -07:00
Tzanio Kolev 90d6afb814 Merge pull request #2445 from mfem/jacobf/2021-08-02/fix-cusparse-deprecated-alg
Improve CUSPARSE SPMV alg selection
2021-08-15 18:16:01 -07:00
Arturo Vargas 94aa25e138 make style 2021-08-15 11:13:51 -07:00
Arturo Vargas 998f7bd093 adjust true add mult 2021-08-15 11:11:13 -07:00
Arturo Vargas df093c9c41 add additional caliper macros 2021-08-14 16:45:45 -07:00
Tzanio 8f25a46d5c Merge branch 'bug-fix-tmop' 2021-08-10 18:09:33 -07:00
Veselin Dobrev 1682ade22e Add constructors for the classes Vector and (Par)GridFunction that
use the data from another Vector or sub-Vector.

In class DiscreteAdaptTC, remove calls to tspec.HostReadWrite() that
are no longer needed when constructing (Par)GrindFunction from data in
a Vector.

Add some MFEM_ASSERT statements in Memory::MakeAlias.
2021-08-10 13:39:41 -07:00
Ketan Mittal be9fc95d6f enforce support for hr on cpus only 2021-08-10 11:46:30 -07:00
Tzanio Kolev 5dd706208a Merge pull request #2425 from mfem/build/bernede1/update-spack-package
Update spack package [build/bernede1/update-spack-package]
2021-08-10 10:23:18 -07:00
Ketan Mittal 7735de95d2 fix parallel version also for tspec pointer 2021-08-09 11:59:56 -07:00
Ketan Mittal 2f023c6e53 get host pointer for tspec 2021-08-09 11:48:54 -07:00
Ketan Mittal 4cf47eca13 minor fix to coef_zeta for final energy calculation 2021-08-09 09:27:52 -07:00
Tzanio 883a5843cd Merge branch 'master' into build/bernede1/update-spack-package 2021-08-09 08:39:26 -07:00
Tzanio Kolev ef5dbd0bf6 Merge pull request #1922 from mfem/tmop-amr-dev
hr-adaptivity with TMOP-based error estimators
2021-08-08 16:31:14 -07:00
Tzanio Kolev b02eaf34a1 Merge pull request #2447 from mfem/artv3/bugfix/trueAddMult
Fix MFEM_VERIFY in TrueAddMult
2021-08-08 16:29:45 -07:00
Tzanio Kolev f26765afa1 Merge pull request #2357 from mfem/yohann/mem/copy-checks
Verify that sizes in `Memory<T>` copy methods are compatible.
2021-08-08 16:29:27 -07:00
Stowell, Mark L d13f3903e6 Fixing memory leak in ParFiniteElementSpace::Update 2021-08-07 13:45:14 -07:00
Stowell, Mark L bc0c2a1460 Swapping ownership of data structure to avoid double free 2021-08-06 11:02:49 -07:00
Stowell, Mark L e15c28140d Fixing memory leak in FiniteElementSpace 2021-08-06 09:44:31 -07:00
Tzanio Kolev f81a681203 Merge pull request #2399 from mfem/bugfix-face-restriction
Face neighbor data bugfix [bugfix-face-restriction]
2021-08-06 09:30:49 -07:00
Tzanio Kolev 5705de1507 Merge pull request #2441 from mfem/GetElementSize_fix
fix GetElementSize for surface meshes
2021-08-05 12:17:03 -07:00
Tzanio Kolev 1958f8de19 Merge pull request #2422 from trevilo/master
Bug fix in FindPointsGSLIB::Interpolate when using L2_FECollection in parallel
2021-08-05 12:16:32 -07:00
Stowell, Mark L 23a8f83785 Swapping ex3p_o1.cpp for ex3_o1.cpp 2021-08-05 09:55:12 -07:00
Josh Essman aacc159390 fix: const param for mesh copy assignment 2021-08-05 09:30:26 -05:00
Keith c91e698800 small bug fix: total error should be sum of squared local errors 2021-08-04 17:17:33 -07:00
Stowell, Mark L ee776a8d0e Updating CHANGELOG 2021-08-03 09:53:11 -07:00
Arturo Vargas 3b26d08793 revert bilinearform_ext 2021-08-02 21:27:02 -07:00
Stowell, Mark L 60082f90b6 Creating el_to_face during ReadGmshMesh when Nodes GridFunction is needed 2021-08-02 15:52:09 -07:00
Arturo Vargas 13892eed2b remove interior face integrators from bilinearforms where they do not exist; 2021-08-02 14:30:22 -07:00
Arturo Vargas 50907081fd fix trueAddMult 2021-08-02 14:08:40 -07:00
Jamie A. Bramwell 9409b7ab3b Merge branch 'master' of github.com:mfem/mfem into bugfix-face-restriction 2021-08-02 10:53:02 -07:00
Jacob Faibussowitsch 86747dd076 check for cusparse version rather than cuda version when selecting cusparse algorithm 2021-08-02 06:37:55 -07:00
Tzanio 9d6a7fe30b Small changes 2021-08-01 14:33:36 -07:00
Tzanio e717f619e7 Moved CHANGELOG entry to the right place 2021-08-01 14:25:36 -07:00
Tzanio 2f2534be10 Merge branch 'master' into tmop-amr-dev 2021-08-01 14:24:05 -07:00
Tzanio 3b8c4323fb Merge branch 'master' into yohann/mem/copy-checks 2021-08-01 14:18:29 -07:00
Keith e786ad65eb fixe GetElementSize for surface meshes 2021-07-30 16:28:24 -07:00
Stowell, Mark L ef1ddbceea Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2021-07-30 11:06:20 -07:00
Stowell, Mark L f69a26e3df Merge remote-tracking branch 'origin/master' into lin-penta-dev 2021-07-24 10:48:34 -07:00
Ketan Mittal ecacadacf2 update changelog 2021-07-23 14:51:45 -07:00
Stowell, Mark L 9c97b6cca0 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	fem/bilinearform.cpp
#	fem/linearform.cpp
2021-07-23 14:42:08 -07:00
Ketan Mittal 98a6ae7baa merge and resolve conflicts 2021-07-23 14:28:53 -07:00
Ketan Mittal 8f28244cab Merge branch 'tmop-amr-dev' of https://github.com/mfem/mfem into tmop-amr-dev 2021-07-23 14:23:05 -07:00
Ketan Mittal 8dd6b3d2b7 minor 2021-07-23 14:22:55 -07:00
Vladimir Z Tomov ee5efb4e36 Minor. 2021-07-23 14:09:38 -07:00
Vladimir Z Tomov 26e67ee06c Minor. 2021-07-23 13:43:36 -07:00
Vladimir Z Tomov f05ef4e164 Minor. 2021-07-23 09:23:52 -07:00
Adrien M. Bernede f39cf60559 Merge branch 'master' into build/bernede1/update-spack-package 2021-07-23 09:14:45 -07:00
Adrien M. Bernede 7b26fe1dc8 Update mfem-uberenv with merge commit 2021-07-23 06:30:25 -07:00
Adrien M. Bernede 81b7c820bf Update netlib for Hypre 2021-07-23 02:59:53 -07:00
Vladimir Z Tomov a7cba43e12 Minor edits in tmop_amr.hpp/cpp. 2021-07-22 16:39:05 -07:00
Ketan Mittal 9e077ffe59 address reviewer comments 2021-07-22 11:06:41 -07:00
Vladimir Z Tomov 2667d3935d Minor. 2021-07-22 07:46:48 -07:00
Todd A. Oliver 9148a1d942 Bug fix in FindPointsGSLIB::Interpolate with L2_FECollection in parallel
Previously if a given MPI task did not find any local points with
gsl_code==1 (indicating a boundary), that task would exit
FindPointsGSLIB::Interpolate before tasks that found boundary points.
This could lead to the program hanging due to subsequent communication
calls.  To avoid this behavior, we only return early if no MPI task
found any boundary points.
2021-07-22 09:21:51 -05:00
Todd A. Oliver 7859c93931 Add command line options --search-on-r0 to pfindpts miniapp
This option forces only MPI task 0 to own any points to search for, as
opposed to the default behavior where all tasks search for the same
points.  The purpose of this is to test the situation where some MPI
tasks find boundary points, meaning those tasks have points with
gsl_code=1, but other tasks do not.
2021-07-22 09:15:13 -05:00
Todd A. Oliver 55573cbe4e Minor fix s.t. schwarz_ex1p builds 2021-07-22 09:13:00 -05:00
Vladimir Z Tomov 0c68ab8e06 Minor. 2021-07-21 14:55:42 -07:00
Vladimir Z Tomov 18ce336b68 Simplified the hr input options. 2021-07-21 14:37:48 -07:00
Stowell, Mark L ada0a17521 Expanding comment 2021-07-20 10:34:38 -07:00
Stowell, Mark L 94a8232cdc Fixing unit test syntax 2021-07-20 10:19:07 -07:00
Stowell, Mark L e2127ad549 Updating comment to reflect removal of ReorientTetMesh 2021-07-20 09:57:52 -07:00
Tzanio ff384ebb03 Merge branch 'master' into lin-penta-dev 2021-07-20 09:04:26 -07:00
Adrien M. BERNEDE 08941bcbe3 Update uberenv 2021-07-20 03:27:23 -07:00
Stowell, Mark L 89301ba3ca Removing outdated code 2021-07-19 20:47:33 -07:00
Stowell, Mark L 24195b4502 Fixing comments 2021-07-19 16:41:19 -07:00
Stowell, Mark L 979b4ae736 Adding comment on pyramid integration rule implementation 2021-07-19 14:37:53 -07:00
Stowell, Mark L f37a91e99c Adding a simple mixed mesh borrowed from Fuentes et al 2021-07-19 14:33:33 -07:00
Stowell, Mark L 1600263109 Fixing comments in header 2021-07-19 13:48:20 -07:00
Stowell, Mark L 2ffcea6578 Moving to uniform implementation for limits at apex of pyramid 2021-07-19 13:48:06 -07:00
Stowell, Mark L 1a982e0671 Adding penta support to LinearDiscont3DFECollection 2021-07-19 13:41:33 -07:00
Stowell, Mark L fa3642d1b8 make style 2021-07-19 10:52:42 -07:00
Stowell, Mark L 4a40a3e863 Removing Nedelec eigenmode example because AMS requires arbitrary order H1 elements 2021-07-19 10:16:28 -07:00
Stowell, Mark L d9cd325a92 hacking pyramid intrule (needs more work) 2021-07-19 10:09:07 -07:00
Stowell, Mark L 20f2d74e20 Adding two H1 and RT examples for testing purposes only 2021-07-19 10:07:44 -07:00
Stowell, Mark L 50097f912c Using 'dof' member data rather than hard coded numbers in RT0 classes 2021-07-19 09:46:50 -07:00
Stowell, Mark L 25d58bbe16 Adjusting RT0 Wedge normals 2021-07-19 09:45:25 -07:00
Stowell, Mark L 4d789d01ed Bugfix in Nedelec1PyrFiniteElement::CalcVShape 2021-07-19 09:44:45 -07:00
Stowell, Mark L 75dae20268 Bugfix in RT0PyrFiniteElement::CalcDivShape 2021-07-19 09:44:06 -07:00
Stowell, Mark L b9c3501d37 Temporarily adding linear Nedelec test codes 2021-07-16 11:16:32 -07:00
Stowell, Mark L 8099e80b5c Implementing ProjectGrad for linear Nedelec hexes and tets 2021-07-16 11:13:26 -07:00
Stowell, Mark L bcf08e1e84 Adding linear Nedelec elements on Wedges and Pyramids 2021-07-16 11:12:40 -07:00
Stowell, Mark L ee9347075e Adding RT0 finite elements for wedges and pyramids 2021-07-16 01:04:26 -07:00
Adrien M. Bernede ec845d006c Update cuda arch to new naming 2021-07-15 07:19:48 -07:00
Adrien M. Bernede ea8be0b691 Oversight 2021-07-14 14:07:23 -07:00
Stowell, Mark L c9154db2b3 Bugfix: need to set initial size of vector 2021-07-14 14:02:13 -07:00
Adrien M. Bernede 0e4dff7f58 Update MFEM Uberenv 2021-07-13 16:51:39 -07:00
bernardo d2b028b98f Minors. 2021-07-13 09:49:12 +02:00
Stowell, Mark L a1d7a34927 Adding two more simple fichera meshes for comparison 2021-07-12 11:32:11 -07:00
Stowell, Mark L 3287622a0b Adding new source files to CMakeLists.txt 2021-07-09 17:43:41 -07:00
Stowell, Mark L 234d66d56b Adding temporary example code for the reviewers 2021-07-09 17:22:25 -07:00
Stowell, Mark L 10a0103662 Removing previously added code which appears to be unnecessary 2021-07-09 17:20:20 -07:00
Stowell, Mark L e6bd619d6b Adding pyramid support to Mesh::GetFacesTable 2021-07-09 17:13:13 -07:00
Jamie BramwellandWill Pazner 6d83ac94c9 style: Move the dynamic cast into the if statement
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2021-07-09 16:32:37 -07:00
Stowell, Mark L c8a53bc4bd Adding pyramid test meshes 2021-07-09 16:28:23 -07:00
Stowell, Mark L a88d4e9904 Switching to rational basis functions for LineatPyramidFiniteElement 2021-07-09 11:43:58 -07:00
Stowell, Mark L e5d0c8fd70 Creating simple pyramid int rule 2021-07-08 18:05:15 -07:00
Stowell, Mark L 8828890cc8 Setting up GeomToPerfGeomJac for pyramids 2021-07-08 18:04:53 -07:00
Stowell, Mark L a71babd667 Adding reference pyramid mesh file 2021-07-08 17:12:00 -07:00
Stowell, Mark L 73ca8408af Altering mesh file header to include the pyramid geometry type 2021-07-08 17:11:36 -07:00
Stowell, Mark L bbc4aea7e9 Adding constant finite elements for prisms and pyramids 2021-07-08 17:10:46 -07:00
Jamie A. Bramwell 3297173552 fix: Ensure that face neighbor data exists when building FaceRestriction operators in parallel 2021-07-08 16:57:14 -07:00
Stowell, Mark L f104863a21 Adding pyramid support to mesh readers 2021-07-08 16:53:54 -07:00
Stowell, Mark L 8b17dea125 Adding pyramid support to mesh class 2021-07-08 16:52:08 -07:00
Stowell, Mark L 7cad5815c1 Adding LinearWedgeFiniteElement 2021-07-08 16:22:39 -07:00
Stowell, Mark L 5da7d11d8b Adding LinearPyramidFiniteElement 2021-07-08 16:22:06 -07:00
Stowell, Mark L a597ba69d7 Adding pyramid geometry type 2021-07-08 16:20:05 -07:00
Mark L. Stowell 7762b23d0a Merge pull request #2386 from mfem/sqr-dof-trans-dev
Switching to in-place transformations [sqr-dof-trans-dev]
2021-07-07 13:12:24 -07:00
Stowell, Mark L c2f2f0a769 Switching to in-place transformations 2021-07-03 12:05:18 -07:00
Ketan Mittal ccb0feb4a4 remove unused variable 2021-07-02 13:08:07 -07:00
Ketan Mittal b877eee42a minor 2021-07-02 11:37:14 -07:00
Ketan Mittal b2b8407f50 add documentation and improve readability 2021-07-02 11:28:52 -07:00
Ketan Mittal d19734afbd removing user input gridfunction ptr 2021-07-01 16:23:26 -07:00
Ketan Mittal 7756b62a35 Merge branch 'tmop-amr-dev' of https://github.com/mfem/mfem into tmop-amr-dev 2021-06-30 18:27:30 -07:00
Ketan Mittal 58a304ebda reviewer comments plus fix discrete aspect-ratio component in target construction 2021-06-30 18:27:14 -07:00
Vladimir Z Tomov a3d9280b26 Minor. 2021-06-30 17:40:03 -07:00
Vladimir Z Tomov e74104e4de Merge branch 'master' into tmop-amr-dev 2021-06-30 16:23:39 -07:00
Stowell, Mark L 6c687ff50c Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2021-06-29 13:31:19 -07:00
Yohann Dudouit b356865de2 Add MFEM_VERIFY to CopyTo. 2021-06-28 16:50:30 -07:00
Yohann Dudouit 81366c926c Readd the documentation. 2021-06-25 11:20:01 -07:00
Yohann Dudouit d4a6ac6507 Verify that sizes in Copy are compatible. 2021-06-24 16:59:47 -07:00
Stowell, Mark L 4c0e29057c make style 2021-06-15 13:26:12 -07:00
Stowell, Mark L 6a6a59f612 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	fem/bilinearform.cpp
#	fem/linearform.cpp
2021-06-15 13:24:33 -07:00
Ketan Mittal ac9e93485c update copyright statement 2021-06-01 16:38:20 -07:00
Ketan Mittal 7809f1b5a1 update mesh constructor 2021-06-01 16:34:59 -07:00
Ketan Mittal e08a9971fb comment formatting 2021-06-01 16:30:48 -07:00
Ketan Mittal 6ab84c49ea merge with master 2021-06-01 16:26:27 -07:00
Ketan Mittal 0e6e19c2cf address reviewer comments and remove some redundance objects 2021-06-01 16:08:47 -07:00
Stowell, Mark L 0c4277cf73 Fixing copyright statement in new unit test 2021-06-01 11:00:20 -07:00
Stowell, Mark L 0563913e28 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2021-06-01 10:37:24 -07:00
bernardo 858f7f55e0 Fixed MFEM build dir path. 2021-05-26 22:19:47 +02:00
bernardo 0634911d3e Added compilation support for Eigen/Spectra integration. 2021-05-26 22:19:10 +02:00
bernardo 6a19948453 Example for Laplace Eigenproblem based on Spectra solver. 2021-05-26 22:17:20 +02:00
bernardo 96e5ac90ba Minor fixes. 2021-05-26 22:15:28 +02:00
bernardo 309aa9e0d2 Fixed includes. 2021-05-26 22:12:59 +02:00
bernardo 5c7c3afce2 Sphere mesh in Gmsh for testing Laplace-Beltrami eigenfunctions calculation. 2021-05-26 22:10:47 +02:00
bernardo 05ce415114 Eigen integration for math objects conversion. 2021-05-26 22:08:20 +02:00
bernardo e0c66e5907 Support for eigensolver based on Spectra. 2021-05-26 22:04:42 +02:00
bernardo ede8395c35 Added ignores for arpack and spectra eigendecomposition examples. 2021-05-26 22:03:24 +02:00
bernardo 65b257a6b2 Added compiling support for ARPACK. 2021-05-25 17:54:48 +02:00
bernardo 48135213d6 Added ARPACK support necessary files. 2021-05-25 17:22:02 +02:00
bernardo 31a05638bf ARPACK support for eigenvalue problems. 2021-05-25 17:20:07 +02:00
bernardo ed39966f65 Include ARPACK solver necessary headers if requested. 2021-05-25 17:17:19 +02:00
bernardo d800b55e13 Added ignore for ARPACK example output. 2021-05-25 17:14:38 +02:00
bernardo 3876f77f1f Example using ARPACK for eigenvalue decomposition. 2021-05-25 17:13:07 +02:00
bernardo d7891e73c0 Added option to activate ARPACK. 2021-05-25 17:04:50 +02:00
bernardo 1fc011fa6d Added ARPACK variable. 2021-05-25 17:03:08 +02:00
bernardo 5f0bfc5770 Added define to enable ARPACK support. 2021-05-25 17:01:01 +02:00
bernardo 931fc6d919 Added useful ignores for vscode, build folder and user-*.mk files. 2021-05-25 16:48:46 +02:00
bernardo 19c69d6f70 Adapated ParcsrAdd function to PR https://github.com/hypre-space/hypre/pull/341 2021-05-25 16:45:32 +02:00
Stowell, Mark L 3ca23bb830 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2021-05-21 18:08:45 -07:00
Stowell, Mark L 9172fc12db Updating copyright statements 2021-05-21 13:18:25 -07:00
Stowell, Mark L 8e0c0de7ba Removing temporary examples 2021-05-21 13:05:17 -07:00
Stowell, Mark L 3546747222 Post merge changes 2021-05-21 10:50:49 -07:00
Stowell, Mark L 15a52d57d8 make style 2021-05-21 10:18:01 -07:00
Stowell, Mark L cb8566ed91 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	fem/fespace.cpp
#	fem/gridfunc.cpp
#	fem/pfespace.cpp
#	tests/unit/fem/test_domain_int.cpp
2021-05-21 10:02:19 -07:00
Stowell, Mark L 1b16d8fbca Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	fem/fespace.cpp
#	fem/fespace.hpp
#	fem/pfespace.cpp
#	linalg/densemat.hpp
#	mesh/mesh.cpp
#	mesh/pmesh.cpp
#	mesh/pmesh.hpp
#	tests/unit/fem/test_3d_bilininteg.cpp
#	tests/unit/fem/test_get_value.cpp
#	tests/unit/fem/test_lin_interp.cpp
2021-04-08 19:44:11 -07:00
Stowell, Mark L b942c04bbe Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2021-02-22 14:01:16 -08:00
Stowell, Mark L ab718835c0 Changing the default mesh in a test code 2021-02-18 16:58:14 -08:00
Stowell, Mark L 4fc94b5310 Switching to MFEM_ABORT 2021-02-18 10:34:49 -08:00
Stowell, Mark L 95c5e19748 Removing whitespace in 'if' conditions 2021-02-18 09:39:06 -08:00
Stowell, Mark L 491b582a48 Adding argument names to member functions in header 2021-02-18 09:33:38 -08:00
Stowell, Mark L 3d02a0e788 Fixing typo in comment block 2021-02-18 09:32:57 -08:00
Stowell, Mark L d2d8908df3 Adding command line option to select conforming or non-conforming tets 2021-02-15 15:23:40 -08:00
Stowell, Mark L 8f2e581db3 Adding user-defined rhs vector 2021-02-15 15:23:07 -08:00
Stowell, Mark L 88bbd78f1c make style 2021-02-09 16:47:29 -08:00
Stowell, Mark L 731b7c0d41 Adding a short comment block to an example 2021-02-09 14:04:34 -08:00
Stowell, Mark L fb32d4fb3d Updating unit test and adding an AMR example (for testing) 2021-02-08 18:47:11 -08:00
Stowell, Mark L e9637d1780 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	fem/gridfunc.cpp
2021-02-08 16:37:37 -08:00
Ketan Mittal 4a0fd1525e Merge branch 'master' of https://github.com/mfem/mfem into tmop-amr-dev 2021-01-12 10:44:34 -08:00
Ketan Mittal 72b58b0ad7 bug related to serial run with parallel build 2021-01-12 10:20:19 -08:00
Ketan Mittal d36cf7858f minor changes to ncmesh/pncmesh 2021-01-12 09:11:15 -08:00
Ketan Mittal f162e36168 refactoring code and changing dtc update 2021-01-11 15:41:56 -08:00
Stowell, Mark L 02402b2860 Disabling serial eigenvalue test when LAPACK is not available 2021-01-11 14:21:44 -08:00
Stowell, Mark L ad79a151ff Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	examples/ex25.cpp
#	examples/ex25p.cpp
#	fem/gridfunc.cpp
2021-01-11 13:30:33 -08:00
Ketan Mittal 9afefcdf52 minor 2021-01-07 12:52:39 -08:00
Ketan Mittal d4b7c3ca11 merging tmopamr and tmopamrsolver 2021-01-07 12:27:45 -08:00
Ketan Mittal e974f12ddb Merge branch 'tmop-amr-dev' of https://github.com/mfem/mfem into tmop-amr-dev 2021-01-06 08:54:59 -08:00
Ketan Mittal b836e0ca6b make style 2021-01-05 17:49:01 -08:00
Ketan Mittal 6543546dc0 minor 2021-01-05 14:43:52 -08:00
Ketan Mittal addb6529ce modifying parallel miniapp 2021-01-05 14:43:37 -08:00
Ketan Mittal d57eeb99b0 moved hr-adaptivity classes to tmop_amr.hpp/cpp 2021-01-05 10:06:14 -08:00
Ketan Mittal 6a12b440bf merge with master and resolve conflicts 2020-12-25 06:53:09 +05:30
Ketan Mittal 7b2633066f modifying sample runs 2020-12-14 11:22:12 -08:00
Ketan Mittal 3115e2cfa1 Merge branch 'master' of https://github.com/mfem/mfem into tmop-amr-dev 2020-12-14 08:14:24 -08:00
Ketan Mittal 01a0e88422 add sample runs 2020-12-14 08:14:10 -08:00
Ketan Mittal a588dd33e8 clean up 2020-12-13 18:02:53 -08:00
Ketan Mittal 38ada18a0e style 2020-12-08 11:35:40 -08:00
Ketan Mittal 4e49041d72 pedantic 2020-12-08 10:47:20 -08:00
Ketan Mittal a3235c4029 missed tmoptools 2020-12-08 10:00:35 -08:00
Ketan Mittal 95b1bf73f9 clean up 2020-12-08 09:38:33 -08:00
Ketan Mittal 2d5818daa0 clean up miniapps 2020-12-07 16:16:24 -08:00
Ketan Mittal ea2f3933da merge with master 2020-12-07 15:07:55 -08:00
Ketan Mittal 7ac7fcf8b5 minor 2020-12-07 15:04:31 -08:00
Stowell, Mark L 15f839e349 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-12-01 09:22:41 -08:00
Stowell, Mark L 8e2c36a109 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-11-02 08:49:29 -08:00
Stowell, Mark L fc0303dc3f Adding more test meshes to test code 2020-10-28 11:13:27 -07:00
Stowell, Mark L 092605c07e Adding parallel eigenvalue test 2020-10-28 11:12:14 -07:00
Stowell, Mark L 1caab5cd44 Setting eigenvalue test to aim for <5% relative error 2020-10-28 10:49:05 -07:00
Stowell, Mark L c1c04e5b14 Adding boundary to 1D test mesh 2020-10-28 09:50:13 -07:00
Stowell, Mark L 2056e9be48 Adding eigenvalue computation as unit test 2020-10-28 09:49:44 -07:00
Stowell, Mark L 641fdaa958 Merge branch 'no-tet-reorder-dev' of github.com:mfem/mfem into no-tet-reorder-dev 2020-10-27 16:12:28 -07:00
Stowell, Mark L d09e3b2647 Adding unit test of domain integration on various mesh types 2020-10-27 16:11:59 -07:00
Stowell, Mark L 5a3dcb824b make style 2020-10-27 16:10:37 -07:00
Stowell, Mark L 6a2e44da9c Fix to support INTEGRAL type basis functions in DomainLFIntegrator 2020-10-27 16:10:26 -07:00
Stowell, Mark L 1983f3deb7 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-10-26 15:37:39 -07:00
Stowell, Mark L fc564d228c Fix compiler warnings 2020-10-26 15:00:51 -07:00
Stowell, Mark L c04b7e9425 Bypassing the new prolongation operator when high order Nedelec shared triangles are present 2020-10-22 09:57:05 -07:00
Stowell, Mark L 2a2b7922d6 Updating licensing declaration 2020-10-22 09:44:25 -07:00
Stowell, Mark L bc9e58e420 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-10-22 09:28:18 -07:00
Stowell, Mark L 7bc3b5e886 Test code cleanup 2020-10-21 16:20:00 -07:00
Stowell, Mark L 9626adb81a Move bugfix to the correct method... 2020-10-21 14:22:49 -07:00
Stowell, Mark L 2730cab765 Bugfix in STable3D 2020-10-21 14:12:52 -07:00
Stowell, Mark L 673ab658f9 Resolving compiler warning 2020-10-21 12:57:40 -07:00
Stowell, Mark L d04c3b366e Removing debug output files 2020-10-21 11:06:01 -07:00
Stowell, Mark L d0facf7fd9 Building Dof_TrueDof_Matrix which incorporates Nedelec Dof transformation for high order triangular faces 2020-10-21 10:26:15 -07:00
Stowell, Mark L 2dfda4db70 Adding method to check for shared triangular faces 2020-10-21 10:25:05 -07:00
Stowell, Mark L 1a9c191e1f Cleanup of test app 2020-10-21 10:24:16 -07:00
Stowell, Mark L 8a3bb90e67 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-10-14 19:50:24 -07:00
Stowell, Mark L 5f9d9ca11c Removing temporary test code 2020-10-14 14:11:01 -07:00
Stowell, Mark L ffd2101e02 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-10-14 14:02:52 -07:00
Stowell, Mark L 923f5b6051 Removing debugging code 2020-10-14 14:01:37 -07:00
Stowell, Mark L f194891195 make style 2020-10-14 10:18:10 -07:00
Stowell, Mark L 8b1edd63bb Restricting new code to the 3D case 2020-10-14 10:17:57 -07:00
Stowell, Mark L b3f3f40df3 Removing selected debugging output 2020-10-14 10:10:48 -07:00
Stowell, Mark L 9cebfc6611 Fixing Table usage in ExchangeFaceNbrData 2020-10-14 09:55:35 -07:00
Stowell, Mark L 91c805ff02 Adding simple debugging example 2020-10-14 09:32:36 -07:00
Stowell, Mark L bc40d5954b More debugging committs 2020-10-14 09:27:30 -07:00
Stowell, Mark L b15032407a Committing debug code to run elsewhere in totalview 2020-10-13 09:31:54 -07:00
Stowell, Mark L 65c10cd5e4 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	fem/gridfunc.cpp
2020-10-07 14:06:05 -07:00
Ketan Mittal 898964a6b7 misc minor changes.. stopping criterion updated, and changed derefinement interface 2020-09-24 11:30:19 -07:00
Ketan Mittal 8a76a96dd7 minor 2020-09-03 12:53:35 -07:00
Ketan Mittal 6665a69afb minor updates 2020-09-03 11:26:40 -07:00
Ketan Mittal 30ea12a346 Merge branch 'master' of https://github.com/mfem/mfem into tmop-amr-dev 2020-09-03 11:12:23 -07:00
Ketan Mittal d2763f0d56 add support for mixed meshes 2020-08-24 10:23:35 -07:00
Ketan Mittal 05e6ad9369 added spatial weight and threshold capability 2020-08-20 08:57:10 -07:00
Ketan Mittal a3c1a26fd7 added spatial weight and threshold capability 2020-08-20 08:56:44 -07:00
Ketan Mittal d189391502 minor changes 2020-08-17 12:19:33 -07:00
Ketan Mittal 23d3d45547 3D support and other minor changes 2020-08-12 13:50:20 -07:00
Ketan Mittal 3a497d4698 update interface 2020-08-12 11:42:52 -07:00
Ketan Mittal 46c7045d79 checkpointing new local approach.. still need to streamline 2020-08-11 17:59:11 -07:00
Ketan Mittal 6708ff1b73 work in parallel 2020-08-04 08:58:09 -07:00
Ketan Mittal a7f602fb8f adding derefinement and streamlined interface 2020-07-22 10:40:06 -07:00
Stowell, Mark L 94527c2abf make style 2020-07-04 11:06:46 -07:00
Stowell, Mark L ad857cea1b Moving declaration of temporary vector 2020-07-04 11:06:31 -07:00
Stowell, Mark L 781a550b3c No need for DofTrans below 3D 2020-07-04 10:53:36 -07:00
Stowell, Mark L c27716f35a Removing ReorientTetMesh from examples 2020-07-04 10:22:36 -07:00
Stowell, Mark L 00828a3b8f Removing ReorientTetMesh from unit test 2020-07-04 10:18:33 -07:00
Stowell, Mark L 845e0a880b Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	fem/fespace.cpp
#	fem/fespace.hpp
#	fem/gridfunc.cpp
2020-07-04 10:18:02 -07:00
Stowell, Mark L 7e89d0b709 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	fem/gridfunc.cpp
2020-05-20 13:54:19 -07:00
Stowell, Mark L d936e5b936 Returning DofTrans from ParFiniteElementSpace classes 2020-05-14 15:55:25 -07:00
Stowell, Mark L acea5fb524 Initializing pointers 2020-05-14 15:54:30 -07:00
Stowell, Mark L a7c648d9ac Style tweaks 2020-05-14 15:54:10 -07:00
Ketan Mittal b381b41c65 another approach- ref and dref 2020-05-14 06:48:10 -07:00
Ketan Mittal 2d25fda0fa checkpoint 2020-05-07 08:48:17 -07:00
Ketan Mittal eb2fa948b5 checkpoint method2 2020-05-07 08:47:37 -07:00
Stowell, Mark L 6f27e7b292 Fixing issue in 2D 2020-05-05 15:34:59 -07:00
Stowell, Mark L 586f1fb5ab Removing ReorientTetMesh from newer examples 2020-05-05 14:30:11 -07:00
Stowell, Mark L 767b9d400a Implementing DofTransformation changes for boundary elements 2020-05-05 14:24:35 -07:00
Stowell, Mark L 0a91022bba Reintroducing tetrahedral tests 2020-05-05 14:22:19 -07:00
Stowell, Mark L 3f8f7a186a Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-05-04 13:56:45 -07:00
Stowell, Mark L 2927da6955 Adding accessor method to DofTrans 2020-05-04 13:55:51 -07:00
Ketan Mittal 376424035e checkpoint 2020-04-29 18:59:37 -07:00
Stowell, Mark L b748dfa9f5 Initializing member data to avoid segfault in d'tor 2020-04-20 14:53:39 -07:00
Stowell, Mark L f09837f7f7 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	fem/fespace.cpp
2020-04-20 14:21:36 -07:00
Stowell, Mark L 1180bc4798 Removing Mesh::ReorientTetMesh from newer tests 2020-04-17 15:30:10 -07:00
Stowell, Mark L 41574d6537 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	mesh/mesh.cpp
2020-04-17 15:27:53 -07:00
Ketan Mittal 5bd2da8d65 fix aspect-ratio calculation 2020-04-14 10:02:35 -07:00
Ketan Mittal b9fc33f98c updated iso/aniso requirements 2020-04-06 10:33:37 -07:00
Ketan Mittal 0a1c1fe415 misc 2020-04-01 09:55:21 -07:00
Stowell, Mark L f164e703ea Removing reorientTetMesh calls from new examples 2020-03-18 11:59:03 -07:00
Stowell, Mark L 58adbfe9de Small post-merge fixes 2020-03-18 11:45:08 -07:00
Stowell, Mark L c029b16d34 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	fem/fespace.hpp
#	fem/pfespace.cpp
#	tests/unit/fem/test_3d_bilininteg.cpp
2020-03-18 11:06:04 -07:00
Ketan Mittal c5a6f654db Merge branch 'master' of https://github.com/mfem/mfem into tmop-amr-dev 2020-02-19 09:16:18 -08:00
Ketan Mittal dd6f7dcad6 working in serial and parallel on analytic and discrete functions 2020-02-19 09:15:27 -08:00
Stowell, Mark L 19961d1493 Removing similar confusing comment 2020-02-15 14:53:37 -08:00
Stowell, Mark L 9decf3a4aa Removing comment which may lead to confusion 2020-02-15 14:51:46 -08:00
Stowell, Mark L 8514657bf5 Reverting to standard refinement strategies 2020-02-15 14:49:12 -08:00
Stowell, Mark L f6828172d5 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-02-14 10:10:20 -08:00
Ketan Mittal fd5742e3f0 Newton and AMR in a loop 2020-02-13 12:57:08 -08:00
Stowell, Mark L a2ea1dd6b5 Adding comments to clarify some of the test cases 2020-02-13 12:53:10 -08:00
Stowell, Mark L d37f35258e Adding testing of VDofTransformation class 2020-02-13 11:27:20 -08:00
Stowell, Mark L 7ec5ea089e Adding testing of standalone DoF transformation functions 2020-02-13 11:26:58 -08:00
Stowell, Mark L c4791180f9 Removing unnecessary matrix and vector sizing 2020-02-13 11:26:09 -08:00
Stowell, Mark L 074ba95836 Adding tests of the DoFTransformation classes 2020-02-12 15:36:24 -08:00
Stowell, Mark L 0a8127c6a7 Fixing small typo 2020-02-12 15:35:33 -08:00
Ketan Mittal a1ba70e6a8 minor 2020-02-11 09:25:51 -08:00
Stowell, Mark L 4cf36c89ba Adding tetrahedral test cases and using GSSmoother to improve convergence 2020-02-05 14:09:12 -08:00
Stowell, Mark L c927ccb89b Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-02-03 13:31:04 -08:00
Stowell, Mark L a6687d00a2 make style 2020-02-03 13:30:25 -08:00
Stowell, Mark L a61f3864f0 Adjusting the number of eigenmodes 2020-02-03 11:10:53 -08:00
Stowell, Mark L e8f7bc8e45 Adding temporary test codes (which may become convergence tests eventually) 2020-01-31 16:11:33 -08:00
Stowell, Mark L 97e5bae5e8 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-01-24 15:49:56 -08:00
Ketan Mittal 4da7b73965 Merge branch 'master' of https://github.com/mfem/mfem into tmop-amr-dev 2020-01-24 10:14:49 -08:00
Ketan Mittal 01bf7d6e9e updating to work for analytic adaptivity 2020-01-24 10:14:24 -08:00
Ketan Mittal 0c06ad86fd initializing branch 2020-01-23 11:46:53 -08:00
Stowell, Mark L 06d0539dca Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-01-19 19:45:56 -08:00
Stowell, Mark L e471c02f49 make style 2020-01-13 14:36:20 -08:00
Stowell, Mark L 035aa608f8 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2020-01-13 13:04:36 -08:00
Stowell, Mark L 25452671fb Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2019-12-28 10:00:16 -08:00
Stowell, Mark L ffa13d0e65 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2019-12-19 09:38:56 -08:00
Stowell, Mark L 0d1399cca2 Attempting to resolve a Travis CI error 2019-11-22 12:46:19 -08:00
Stowell, Mark L 9fb0d69cde Fixing bug that arose in parallel performance example ex1p 2019-11-22 08:56:36 -08:00
Stowell, Mark L 2251d41f2c Setting up DoFTrans during Update 2019-11-21 21:35:38 -08:00
Stowell, Mark L 1e743b7c52 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	examples/ex3p.cpp
#	fem/fespace.cpp
#	mesh/mesh.cpp
#	mesh/pmesh.cpp
2019-11-21 20:29:20 -08:00
Stowell, Mark L 34c395cc2d Experiment to hopefully resolve crash in MPI_Allreduce call on some platforms 2019-08-29 16:11:38 -07:00
Stowell, Mark L c10d72c877 Fixing memory leak in FiniteElementSpace due to DoFTransformation objects 2019-08-29 14:54:07 -07:00
Stowell, Mark L f2f12cfdc6 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2019-08-29 10:22:51 -07:00
Stowell, Mark L 886cfc1122 Adding new source files to CMakeLists 2019-08-27 15:43:37 -07:00
Stowell, Mark L 4c59e8105d Small fixes after merging with master 2019-08-22 20:51:10 -07:00
Stowell, Mark L 603cb4cb28 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	fem/bilinearform.cpp
#	fem/pfespace.cpp
2019-08-22 20:15:22 -07:00
Stowell, Mark L c09baf7d95 Returning early from CheckNDSTriaDofs if possible (to avoid issue with NURBS_FECollection) 2019-05-23 10:51:01 -07:00
Stowell, Mark L f370b414d5 Moving call to ExchangeFaceNbrData into ParFiniteElementSpace 2019-05-21 11:29:13 -07:00
Stowell, Mark L b806829091 Avoiding the use of VDoFTrans when vdim == 1 2019-05-21 10:45:15 -07:00
Stowell, Mark L a8fde54f20 Adding explanation of the uses of the DofTransformation objects (so that I won't forget why it's designed the way it is). 2019-05-20 17:03:07 -07:00
Stowell, Mark L bc22e8a464 Fixing a bug in DofTransformation that impacts the discrete curl operator and hence ex4p 2019-05-20 16:41:53 -07:00
Stowell, Mark L b55bad2778 Adding documentation to the classes declared in the doftrans file 2019-05-19 11:59:31 -07:00
Stowell, Mark L f4f4df493c Adding a missing method to DofTransformation 2019-05-19 11:36:22 -07:00
Stowell, Mark L 19725ed3f4 Constructor of an abstract base class should be protected 2019-05-19 11:35:24 -07:00
Stowell, Mark L 08139ab379 Removing unneeded test code 2019-05-18 10:59:02 -07:00
Stowell, Mark L 36eebb4992 Removing unneeded test meshes 2019-05-18 10:56:22 -07:00
Stowell, Mark L ef97a8f73d Removing outdated error 2019-05-18 10:54:56 -07:00
Stowell, Mark L 32f254b50f Replacing ReorientTetMesh with ExchangeFaceNbrData (also changing related comments) 2019-05-18 10:54:22 -07:00
Stowell, Mark L 86c9b0bd37 Removing commented code 2019-05-18 10:40:06 -07:00
Stowell, Mark L 7325eec877 Adding refinement level controls to ex3 and ex3p 2019-05-18 10:39:28 -07:00
Stowell, Mark L d5dfb6c52e Replacing ReorientTetMesh with ExchangeFaceNbrData 2019-05-18 10:39:01 -07:00
Stowell, Mark L 1cfcb66003 Placing some reminder comments regarding uspport for DofTransformation 2019-05-15 00:13:44 -07:00
Stowell, Mark L f37cda5337 Implementing the RefinementOperator for vdim != 1 2019-05-15 00:06:45 -07:00
Stowell, Mark L 69f42498a3 Extending RefinementOperator to work with DofTransformations 2019-05-14 20:18:45 -07:00
Stowell, Mark L 0cab2cbcf0 Adding a SetVDim method to VDofTransformation 2019-05-14 13:57:21 -07:00
Stowell, Mark L 5af52493f5 Fixing issues found with unit tests 2019-05-13 15:48:13 -07:00
Stowell, Mark L f40fb18204 Bugfixes for multiprocessor case 2019-05-13 12:04:14 -07:00
Stowell, Mark L 2e4d1c58d4 Removing debugging info and adding TODO comments 2019-05-10 16:58:48 -07:00
Stowell, Mark L e4fb6187a4 make style 2019-05-10 16:52:16 -07:00
Stowell, Mark L 873bfe9ac4 Removing unneeded code 2019-05-10 16:51:55 -07:00
Stowell, Mark L dccd58ebe7 Ensuring all processors agree about the existence of high-order shared faces 2019-05-10 16:50:40 -07:00
Stowell, Mark L 746f022a43 Fixing incorrect size argument 2019-05-10 16:49:52 -07:00
Stowell, Mark L 5e4df7625a Skipping offd portion on owning proc 2019-05-10 15:00:58 -07:00
Stowell, Mark L d407199412 make style 2019-05-10 14:25:10 -07:00
Stowell, Mark L 06ee1a8c4b Adding ND dof mapping to ConformingProlongationOperator 2019-05-10 14:24:46 -07:00
Stowell, Mark L fb802bab76 Fixing initialization of static member data 2019-05-10 11:49:09 -07:00
Stowell, Mark L dbe41d23f9 Removing old implementations 2019-05-10 11:35:22 -07:00
Stowell, Mark L 795d2339bd Setting flag for shared ND dofs 2019-05-10 11:34:50 -07:00
Stowell, Mark L 1c79ab091b Adding member function to check for high-order ND dofs on shared triangular faces 2019-05-10 11:33:19 -07:00
Stowell, Mark L 0ab9469674 Redesigning doftrans classes to enable sharing common member data 2019-05-10 11:31:53 -07:00
Stowell, Mark L 27928a3fed Adding another simple test mesh 2019-05-07 11:49:24 -07:00
Stowell, Mark L fac3033bc6 Fixing range on num groups 2019-05-07 11:48:40 -07:00
Stowell, Mark L 93abad38db Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2019-05-06 13:31:56 -07:00
Stowell, Mark L 890b865cce Simple test mesh 2019-05-06 11:22:16 -07:00
Stowell, Mark L 0cf9feb7f7 Updated test code 2019-05-06 11:21:53 -07:00
Stowell, Mark L 74e66f6aec Hack to share transformation matrices with other classes 2019-05-06 11:21:32 -07:00
Stowell, Mark L 69c77420e3 Adding an alternative prolongation matrix for Nedelec basis on meshes with shared triangles and orer >= 2 2019-05-06 11:20:53 -07:00
Stowell, Mark L 42a726f5de Backing out changes to ExchangeFaceNbrData 2019-05-06 11:19:47 -07:00
Stowell, Mark L f067ee01c5 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2019-05-01 10:06:13 -07:00
Stowell, Mark L 60ee23b290 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2019-04-12 15:05:52 -07:00
Stowell, Mark L 0a6297b21e Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2019-04-09 14:01:45 -07:00
Stowell, Mark L 1f600856ed Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2019-04-01 10:58:40 -07:00
Stowell, Mark L 71b01350b7 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev
# Conflicts:
#	linalg/strumpack.cpp
#	linalg/strumpack.hpp
2019-03-28 22:04:31 -07:00
Stowell, Mark L 1938b66414 Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2019-01-20 00:04:12 -08:00
Stowell, Mark L f33a43f28a Cleaning up a few warnings 2018-12-24 18:08:56 -08:00
Stowell, Mark L 95b349f68c Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2018-12-24 17:58:23 -08:00
Stowell, Mark L bbfc1bef1e Outputting parallel mesh 2018-12-23 17:14:22 -08:00
Stowell, Mark L eeff4bef88 Replacing the original implementation but commented out for comparison 2018-12-18 18:14:59 -08:00
Stowell, Mark L afaae976be Adding temporary test code 2018-12-17 14:29:27 -08:00
Stowell, Mark L 5e902dd313 Disabling outdated STRUMPACK method 2018-12-17 14:10:33 -08:00
Stowell, Mark L c213bab266 Adding doftrans to various other methods in GridFunction 2018-12-10 15:44:13 -08:00
Stowell, Mark L 6de33e89ea Altering the orientation of shared faces on slaves processors 2018-11-29 14:06:56 -08:00
Stowell, Mark L 2b72a7617c Merge remote-tracking branch 'origin/master' into no-tet-reorder-dev 2018-11-26 14:57:46 -08:00
Stowell, Mark L 227d366140 Only prepare face orientation caching when Dim>2 2018-11-20 16:27:43 -08:00
Stowell, Mark L fcf59cc559 Add caching of face orientations 2018-11-20 16:17:51 -08:00
Stowell, Mark L f7e74f190b Adding convenience functions for transforming rectangular matrices 2018-11-18 17:49:22 -08:00
Stowell, Mark L 4112e9319a Changing method names 2018-11-18 17:00:17 -08:00
Stowell, Mark L 94123f82cb Adding test code to FES and PFES to support dof transformations 2018-11-18 10:55:52 -08:00
Stowell, Mark L f8aeeda21c Adding transformation to LinearForm object 2018-11-18 10:54:40 -08:00
Stowell, Mark L fd9f21fad6 Adding transformation to various get value methods in GridFunction 2018-11-18 10:53:25 -08:00
Stowell, Mark L f002728b9b adding partial support for discrete linear operator transformation 2018-11-18 10:51:34 -08:00
Stowell, Mark L 6bd70ae4a5 fixing nd triangular face dof mappings 2018-11-18 10:50:21 -08:00
Stowell, Mark L a06bb99cce Bugfix in nd triangular face dof remapping 2018-11-18 10:49:28 -08:00
Stowell, Mark L 3ee2ab0db4 Adding ability to transform linear and bilinear forms 2018-11-18 10:48:37 -08:00
Stowell, Mark L 87e1b0d2e5 Implementing ND_TetDofTransform and VDofTransform 2018-11-15 00:33:24 -08:00
Stowell, Mark L 8483beb771 Adding DenseTensor c'tor which takes an external data array 2018-11-15 00:32:33 -08:00
Stowell, Mark L 1f9a109c30 Adding DoF reorderings for Nedelec bases on triangular faces 2018-11-14 13:40:02 -08:00
Stowell, Mark L dab06bc0a3 Initial changes to test DofTransformation classes 2018-11-14 13:39:11 -08:00
Stowell, Mark L 6a898e4d32 Adding experimental type to handle DoF transformations at element interfaces 2018-11-14 13:38:02 -08:00
Stowell, Mark L 4d51451bfb Removing ReorientTetMesh methods (and breaking high order ND tets) 2018-11-13 21:48:09 -08:00
123 changed files with 15161 additions and 637 deletions
+15 -1
View File
@@ -145,6 +145,14 @@ examples/petsc/velocity.*
examples/petsc/elastic_energy.*
examples/petsc/mode_*
examples/arpack/ex11
examples/arpack/mode_*
examples/arpack/ex11.mesh
examples/spectra/ex11
examples/spectra/mode_*
examples/spectra/ex11.mesh
examples/pumi/ex1
examples/pumi/ex[126]p
examples/pumi/refined.mesh
@@ -310,7 +318,13 @@ tests/convergence/prates
tests/par-mesh-format/ex1p
# VPATH builds
build-*/*
build-*/
# User config
user-*
# VSCode
.vscode
# PETSc automated build
petsc-build/*
+1
View File
@@ -50,6 +50,7 @@ variables:
AUTOTEST_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/autotest.git
MFEM_DATA_REPO: https://github.com/mfem/data.git
ARTIFACTS_DIR: artifacts
SLURM_OVERLAP: 1
# The pipeline is divided into stages. Usually, jobs in a given stage wait for
# the preceding stages to complete before to start. However, we sometimes use
+1 -1
View File
@@ -30,5 +30,5 @@
opt_mpi_cuda_xl_16_1_1_8:
variables:
SPEC: "%xl@16.1.1.8 +mpi +cuda cuda_arch=sm_70"
SPEC: "%xl@16.1.1.8 +mpi +cuda cuda_arch=70"
extends: .build_and_test_on_lassen
+19
View File
@@ -10,7 +10,26 @@
Version 4.3.1 (development)
===========================
- Added support for hr-adaptivity using TMOP-based error estimator.
- Adding lowest order Nedelec and Raviart-Thomas basis functions on wedge
shaped elements.
- Added initial support for meshes with pyramidal elements, including several
pyramidal meshes in the data/ directory and support for the lowest order H1,
Nedelec, Raviart-Thomas, and L2 basis functions on pyramids.
- Updated the hypre interface according to changes in hypre-2.22.1. The ADS
solver is now fully working on GPUs.
- Tetrahedral meshes no longer need to be reordered to support high order
Nedelec basis functions. This will allow future support for Nedelec basis
functions on wedges and pyramids which are not amenable to reordering. The
ReorientTetMesh method of the Mesh and ParMesh classes has been deprecated.
- Gmsh meshes where all elements have zero physical tag (the default Gmsh
output format if no physical groups are defined) are now successfully loaded,
and elements are reassigned attribute number 1.
Version 4.3, released on July 29, 2021
======================================
+66
View File
@@ -0,0 +1,66 @@
cff-version: 1.2.0
message: "If you use MFEM, please cite it as follows."
authors:
- family-names: "MFEM Team"
title: "MFEM: Modular Finite Element Methods [Software]"
doi: 10.11578/dc.20171025.1248
url: "https://mfem.org"
preferred-citation:
type: article
authors:
- family-names: "Anderson"
given-names: "Robert"
orcid: "https://orcid.org/0000-0002-3508-9944"
- family-names: "Andrej"
given-names: "Julian"
orcid: "https://orcid.org/0000-0001-7661-4840"
- family-names: "Barker"
given-names: "Andrew"
orcid: "https://orcid.org/0000-0003-3572-911X"
- family-names: "Bramwell"
given-names: "Jamie"
- family-names: "Camier"
given-names: "Jean-Sylvain"
orcid: "https://orcid.org/0000-0003-2421-1999"
- family-names: "Cerveny"
given-names: "Jakub"
orcid: "https://orcid.org/0000-0003-4231-2531"
- family-names: "Dobrev"
given-names: "Veselin"
orcid: "https://orcid.org/0000-0003-1793-5622"
- family-names: "Dudouit"
given-names: "Yohann"
orcid: "https://orcid.org/0000-0001-5831-561X"
- family-names: "Fisher"
given-names: "Aaron"
- family-names: "Kolev"
given-names: "Tzanio"
orcid: "https://orcid.org/0000-0002-2810-3090"
- family-names: "Pazner"
given-names: "Will"
orcid: "https://orcid.org/0000-0003-4885-2934"
- family-names: "Stowell"
given-names: "Mark"
orcid: "https://orcid.org/0000-0002-5389-7435"
- family-names: "Tomov"
given-names: "Vladimir"
orcid: "https://orcid.org/0000-0002-1846-6816"
- family-names: "Akkerman"
given-names: "Ido"
orcid: "https://orcid.org/0000-0002-5937-0300"
- family-names: "Dahm"
given-names: "Johann"
orcid: "https://orcid.org/0000-0001-9657-3564"
- family-names: "Medina"
given-names: "David"
- family-names: "Zampini"
given-names: "Stefano"
orcid: "https://orcid.org/0000-0002-0435-0433"
doi: "10.1016/j.camwa.2020.06.009"
journal: "Computers \\& Mathematics with Applications"
month: 1
start: 42 # First page number
end: 74 # Last page number
title: "MFEM: A Modular Finite Element Methods Library"
volume: 81
year: 2021
+1 -1
View File
@@ -549,7 +549,7 @@ The specific libraries and their options are:
Options: HYPRE_OPT, HYPRE_LIB.
Versions: HYPRE >= 2.10.0b (HYPRE built without CUDA)
HYPRE >= 2.20.0 (HYPRE built with '--enable-mixedint')
HYPRE >= 2.22.0 (HYPRE built with CUDA)
HYPRE >= 2.22.1 (HYPRE built with CUDA)
- METIS, used when MFEM_USE_METIS = YES. If using METIS 5, set
MFEM_USE_METIS_5 = YES (default is to use METIS 4).
+6
View File
@@ -91,6 +91,12 @@
// Enable MFEM functionality based on the SuiteSparse library.
// #define MFEM_USE_SUITESPARSE
// Enable MFEM functionality based on the ARPACK library.
// #define MFEM_USE_ARPACK
// Enable MFEM functionality based on the SPECTRA library.
// #define MFEM_USE_SPECTRA
// Enable MFEM functionality based on the SuperLU library.
// #define MFEM_USE_SUPERLU
// #define MFEM_USE_SUPERLU5
+2
View File
@@ -31,6 +31,8 @@ MFEM_TIMER_TYPE = @MFEM_TIMER_TYPE@
MFEM_USE_SUNDIALS = @MFEM_USE_SUNDIALS@
MFEM_USE_MESQUITE = @MFEM_USE_MESQUITE@
MFEM_USE_SUITESPARSE = @MFEM_USE_SUITESPARSE@
MFEM_USE_ARPACK = @MFEM_USE_ARPACK@
MFEM_USE_SPECTRA = @MFEM_USE_SPECTRA@
MFEM_USE_SUPERLU = @MFEM_USE_SUPERLU@
MFEM_USE_SUPERLU5 = @MFEM_USE_SUPERLU5@
MFEM_USE_MUMPS = @MFEM_USE_MUMPS@
+15
View File
@@ -151,6 +151,8 @@ MFEM_USE_UMPIRE = NO
MFEM_USE_SIMD = NO
MFEM_USE_ADIOS2 = NO
MFEM_USE_MKL_CPARDISO = NO
MFEM_USE_ARPACK = NO
MFEM_USE_SPECTRA = NO
# MPI library compile and link flags
# These settings are used only when building MFEM with MPI + HIP
@@ -328,6 +330,19 @@ NETCDF_LIB = $(XLINKER)-rpath,$(NETCDF_DIR)/lib -L$(NETCDF_DIR)/lib\
$(XLINKER)-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib\
-lnetcdf -lhdf5_hl -lhdf5 $(ZLIB_LIB)
# ARPACK library configuration
ARPACK_DIR = @MFEM_DIR@/../ARPACK
ARPACK_OPT = -I$(ARPACK_DIR)
ARPACK_LIB = -L$(ARPACK_DIR) -lparpack -larpack
# EIGEN library configuration
EIGEN_DIR = @MFEM_DIR@/../eigen
EIGEN_OPT = -I$(EIGEN_DIR)
# SPECTRA library configuration
SPECTRA_DIR = @MFEM_DIR@/../spectra/include
SPECTRA_OPT = -I$(SPECTRA_DIR) $(EIGEN_OPT)
# PETSc library configuration (version greater or equal to 3.8 or the dev branch)
PETSC_ARCH := arch-linux2-c-debug
PETSC_DIR := $(MFEM_DIR)/../petsc/$(PETSC_ARCH)
+9
View File
@@ -0,0 +1,9 @@
MFEM INLINE mesh v1.0
type = pyramid
nx = 4
ny = 4
nz = 4
sx = 1.0
sy = 1.0
sz = 1.0
+43
View File
@@ -0,0 +1,43 @@
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
# PYRAMID = 7
#
dimension
3
elements
2
1 7 4 3 2 1 0
1 7 1 2 3 4 5
boundary
8
1 2 0 2 1
2 2 0 3 2
3 2 0 4 3
4 2 0 1 4
5 2 1 2 5
6 2 2 3 5
7 2 3 4 5
8 2 4 1 5
vertices
6
3
0 0 -1
1 0 0
0 1 0
-1 0 0
0 -1 0
0 0 1
+38
View File
@@ -0,0 +1,38 @@
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
# PYRAMID = 7
#
dimension
3
elements
1
1 7 0 1 2 3 4
boundary
5
1 3 3 2 1 0
2 2 0 1 4
3 2 1 2 4
4 2 2 3 4
5 2 3 0 4
vertices
5
3
0 0 0
1 0 0
1 1 0
0 1 0
0 0 1
+47
View File
@@ -0,0 +1,47 @@
Mesh.Algorithm = 6;
lc = 0.1;
Point(1) = {0.0,0.0,0.0,lc};
Point(2) = {1,0.0,0.0,lc};
Point(3) = {0,1,0.0,lc};
Circle(1) = {2,1,3};
Point(4) = {-1,0,0.0,lc};
Point(5) = {0,-1,0.0,lc};
Circle(2) = {3,1,4};
Circle(3) = {4,1,5};
Circle(4) = {5,1,2};
Point(6) = {0,0,-1,lc};
Point(7) = {0,0,1,lc};
Circle(5) = {3,1,6};
Circle(6) = {6,1,5};
Circle(7) = {5,1,7};
Circle(8) = {7,1,3};
Circle(9) = {2,1,7};
Circle(10) = {7,1,4};
Circle(11) = {4,1,6};
Circle(12) = {6,1,2};
Curve Loop(13) = {2,8,-10};
Surface(14) = {13};
Curve Loop(15) = {10,3,7};
Surface(16) = {15};
Curve Loop(17) = {-8,-9,1};
Surface(18) = {17};
Curve Loop(19) = {-11,-2,5};
Surface(20) = {19};
Curve Loop(21) = {-5,-12,-1};
Surface(22) = {21};
Curve Loop(23) = {-3,11,6};
Surface(24) = {23};
Curve Loop(25) = {-7,4,9};
Surface(26) = {25};
Curve Loop(27) = {-4,12,-6};
Surface(28) = {27};
Surface Loop(29) = {28,26,16,14,20,24,22,18};
Volume(30) = {29};
Physical Surface(1) = {28,26,16,14,20,24,22,18};
Physical Volume(2) = 30;
// Generate 2D mesh
Mesh 2;
Mesh.MshFileVersion = 2.2;
+4793
View File
File diff suppressed because it is too large Load Diff
+286
View File
@@ -0,0 +1,286 @@
// MFEM Example 11 - Serial Version
//
// Compile with: make ex11
//
// Sample runs: ex11 -m ../data/square-disc.mesh
// ex11 -m ../data/star.mesh
// ex11 -m ../data/star-mixed.mesh
// ex11 -m ../data/periodic-annulus-sector.msh
// ex11 -m ../data/square-disc-p2.vtk -o 2
// ex11 -m ../data/square-disc-p3.mesh -o 3
// ex11 -m ../data/square-disc-nurbs.mesh -o -1
// ex11 -m ../data/disc-nurbs.mesh -o -1 -n 20
// ex11 -m ../data/star-surf.mesh
// ex11 -m ../data/square-disc-surf.mesh
// ex11 -m ../data/inline-segment.mesh
// ex11 -m ../data/inline-quad.mesh
// ex11 -m ../data/inline-tri.mesh
// ex11 -m ../data/amr-quad.mesh
// ex11 -m ../data/amr-hex.mesh
// ex11 -m ../data/mobius-strip.mesh -n 8
//
// Description: This example code demonstrates the use of MFEM to solve the
// eigenvalue problem -Delta u = lambda u with homogeneous
// Dirichlet boundary conditions.
//
// We compute a number of the lowest eigenmodes by discretizing
// the Laplacian and Mass operators using a FE space of the
// specified order, or an isoparametric/isogeometric space if
// order < 1 (quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of the ARPACK eigenvalue solver
// (regular inverse mode). Reusing a single GLVis visualization
// window for multiple eigenfunctions is also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/star.mesh";
int ser_ref_levels = 3;
int order = 1;
int nev = 5;
double dbc_eig = 1e3;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&nev, "-n", "--num-eigs",
"Number of desired eigenmodes.");
args.AddOption(&dbc_eig, "-d", "--dbc-eig",
"Eigenvalues associated with Dirichlet BC "
"(should be larger than the maximum desired eigenvalue).");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh;
ifstream imesh(mesh_file);
if (!imesh)
{
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
return 2;
}
mesh = new Mesh(imesh, 1, 1);
imesh.close();
int dim = mesh->Dimension();
// 3. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement (2 by default, or
// specified on the command line with -rs).
for (int lev = 0; lev < ser_ref_levels; lev++)
{
mesh->UniformRefinement();
}
// 4. Define a finite element space on the mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
int size = fespace->GetVSize();
cout << "Number of unknowns: " << size << endl;
// 5. Set up the parallel bilinear forms a(.,.) and m(.,.) on the finite
// element space. The first corresponds to the Laplacian operator -Delta,
// while the second is a simple mass matrix needed on the right hand side
// of the generalized eigenvalue problem below. The boundary conditions
// are implemented by elimination with special values on the diagonal to
// shift the Dirichlet eigenvalues out of the computational range. After
// serial and parallel assembly we extract the corresponding parallel
// matrices A and M.
ConstantCoefficient one(1.0);
Array<int> ess_bdr;
if (mesh->bdr_attributes.Size())
{
ess_bdr.SetSize(mesh->bdr_attributes.Max());
ess_bdr = 1;
}
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
if (mesh->bdr_attributes.Size() == 0)
{
// Add a mass term if the mesh has no boundary, e.g. periodic mesh or
// closed surface.
a->AddDomainIntegrator(new MassIntegrator(one));
}
a->Assemble();
if (mesh->bdr_attributes.Size() != 0)
{
a->EliminateEssentialBCDiag(ess_bdr, dbc_eig);
}
a->Finalize();
BilinearForm *m = new BilinearForm(fespace);
m->AddDomainIntegrator(new MassIntegrator(one));
m->Assemble();
if (mesh->bdr_attributes.Size() != 0)
{
// shift the eigenvalue corresponding to eliminated dofs to a large value
m->EliminateEssentialBCDiag(ess_bdr, 1.0);
}
m->Finalize();
// 6. Define and configure the ARPACK eigensolver
ArPackSym * arpack = new ArPackSym();
Solver * solver = NULL;
#ifndef MFEM_USE_SUITESPARSE
// 7. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system A X = B with PCG.
cout << "Building CGSolver" << endl;
GSSmoother M(m->SpMat());
CGSolver * cg_solver = new CGSolver;
cg_solver->SetPreconditioner(M);
cg_solver->SetRelTol(1.0e-12);
solver = cg_solver;
#else
// 7. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
cout << "Building UMFPackSolver" << endl;
UMFPackSolver * umf_solver = new UMFPackSolver;
umf_solver->Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
solver = umf_solver;
#endif
solver->SetOperator(m->SpMat());
arpack->SetNumModes(nev);
arpack->SetMaxIter(400);
arpack->SetTol(1e-8);
arpack->SetMode(2);
arpack->SetPrintLevel(2);
arpack->SetOperator(*a);
arpack->SetMassMatrix(*m);
arpack->SetSolver(*solver);
// 8. Compute the eigenmodes and extract the array of eigenvalues. Define a
// parallel grid function to represent each of the eigenmodes returned by
// the solver.
Array<double> eigenvalues;
arpack->Solve();
arpack->GetEigenvalues(eigenvalues);
cout << endl;
std::ios::fmtflags old_fmt = cout.flags();
cout.setf(std::ios::scientific);
std::streamsize old_prec = cout.precision(14);
for (int i=0; i<nev; i++)
{
cout << "Eigenvalue lambda " << eigenvalues[i] << endl;
}
cout.precision(old_prec);
cout.flags(old_fmt);
cout << endl;
GridFunction x(fespace);
// 9. Save the refined mesh and the modes in parallel. This output can be
// viewed later using GLVis: "glvis -np <np> -m mesh -g mode".
{
ostringstream mesh_name, mode_name;
mesh_name << "ex11.mesh";
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
for (int i=0; i<nev; i++)
{
// convert eigenvector from HypreParVector to ParGridFunction
x = arpack->GetEigenvector(i);
mode_name << "mode_" << setfill('0') << setw(2) << i;
ofstream mode_ofs(mode_name.str().c_str());
mode_ofs.precision(8);
x.Save(mode_ofs);
mode_name.str("");
}
}
// 10. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream mode_sock(vishost, visport);
mode_sock.precision(8);
for (int i=0; i<nev; i++)
{
cout << "Eigenmode " << i+1 << '/' << nev
<< ", Lambda = " << eigenvalues[i] << endl;
// convert eigenvector from HypreParVector to ParGridFunction
x = arpack->GetEigenvector(i);
mode_sock << "solution\n" << *mesh << x << flush
<< "window_title 'Eigenmode " << i+1 << '/' << nev
<< ", Lambda = " << eigenvalues[i] << "'" << endl;
char c;
cout << "press (q)uit or (c)ontinue --> " << flush;
cin >> c;
if (c != 'c')
{
break;
}
}
mode_sock.close();
}
// 11. Free the used memory.
delete arpack;
delete solver;
delete m;
delete a;
delete fespace;
if (order > 0)
{
delete fec;
}
delete mesh;
return 0;
}
+69
View File
@@ -0,0 +1,69 @@
# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/arpack/,)
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_EXAMPLES = ex11
PAR_EXAMPLES =
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
else
EXAMPLES = $(PAR_EXAMPLES)
endif
RC_FILES = $(patsubst $(SRC)%,%,$(wildcard $(SRC)rc_*))
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all clean clean-build clean-exec
# Remove built-in rule
%: %.cpp
# Replace the default implicit rule for *.cpp files
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
all: $(EXAMPLES)
# Examples depend on their corresponding rc_* files:
make-rc-rule = $(1): | $(filter rc_$(1)%,$(RC_FILES))
$(foreach ex,$(EXAMPLES),$(eval $(call make-rc-rule,$(ex))))
# Rules to copy the rc_* files when building out-of-source:
ifneq ($(SRC),)
$(RC_FILES): %: $(SRC)%
cp -pf $(<) .
endif
# Generate an error message if the MFEM library is not built and exit
$(MFEM_LIB_FILE):
$(error The MFEM library is not built)
clean: clean-build clean-exec
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -rf mesh.* sol.* sol_p.* sol_u.* Example5*
@rm -f ex9-mesh.* ex9-init.* ex9-final.* Example9*
@rm -f deformed.* velocity.* elastic_energy.*
+2 -2
View File
@@ -206,9 +206,9 @@ int main(int argc, char *argv[])
cout << "Size of linear system: " << A->Height() << endl;
// 11. Solve the linear system A X = B.
MFEM_PERF_BEGIN("Solve A X=B");
if (!pa)
{
MFEM_PERF_SCOPE("Solve A X=B (FA)");
#ifndef MFEM_USE_SUITESPARSE
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
GSSmoother M((SparseMatrix&)(*A));
@@ -223,6 +223,7 @@ int main(int argc, char *argv[])
}
else // Jacobi preconditioning in partial assembly mode
{
MFEM_PERF_SCOPE("Solve A X=B (PA)");
if (UsesTensorBasis(fespace))
{
OperatorJacobiSmoother M(a, ess_tdof_list);
@@ -233,7 +234,6 @@ int main(int argc, char *argv[])
CG(*A, B, X, 1, 400, 1e-12, 0.0);
}
}
MFEM_PERF_END("Solve A X=B");
// 12. Recover the solution as a finite element grid function.
a.RecoverFEMSolution(X, b, x);
+19 -18
View File
@@ -231,28 +231,29 @@ int main(int argc, char *argv[])
// 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.
MFEM_PERF_BEGIN("Solve A X = B");
Solver *prec = NULL;
if (pa)
{
if (UsesTensorBasis(fespace))
MFEM_PERF_SCOPE("Solve A X=B");
Solver *prec = NULL;
if (pa)
{
prec = new OperatorJacobiSmoother(a, ess_tdof_list);
if (UsesTensorBasis(fespace))
{
prec = new OperatorJacobiSmoother(a, ess_tdof_list);
}
}
else
{
prec = new HypreBoomerAMG;
}
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
if (prec) { cg.SetPreconditioner(*prec); }
cg.SetOperator(*A);
cg.Mult(B, X);
delete prec;
}
else
{
prec = new HypreBoomerAMG;
}
CGSolver cg(MPI_COMM_WORLD);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
if (prec) { cg.SetPreconditioner(*prec); }
cg.SetOperator(*A);
cg.Mult(B, X);
delete prec;
MFEM_PERF_END("Solve A X = B");
// 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
View File
@@ -9,6 +9,7 @@
// ex1 -m ../data/fichera.mesh
// ex1 -m ../data/fichera-mixed.mesh
// ex1 -m ../data/toroid-wedge.mesh
// ex1 -m ../data/octahedron.mesh -o 1
// ex1 -m ../data/periodic-annulus-sector.msh
// ex1 -m ../data/periodic-torus-sector.msh
// ex1 -m ../data/square-disc-p2.vtk -o 2
-1
View File
@@ -118,7 +118,6 @@ int main(int argc, char *argv[])
{
pmesh->UniformRefinement();
}
pmesh->ReorientTetMesh();
// 7. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
+7 -4
View File
@@ -24,7 +24,10 @@
// class ConductionOperator defining C(u)), as well as their
// implicit time integration. Note that implementing the method
// ConductionOperator::ImplicitSolve is the only requirement for
// high-order implicit (SDIRK) time integration.
// high-order implicit (SDIRK) time integration. In this example,
// the diffusion operator is linearized by evaluating with the
// lagged solution from the previous timestep, so there is only
// a linear solve.
//
// We recommend viewing examples 2, 9 and 10 before viewing this
// example.
@@ -326,8 +329,8 @@ ConductionOperator::ConductionOperator(FiniteElementSpace &f, double al,
void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
{
// Compute:
// du_dt = M^{-1}*-K(u)
// for du_dt
// du_dt = M^{-1}*-Ku
// for du_dt, where K is linearized by using u from the previous timestep
Kmat.Mult(u, z);
z.Neg(); // z = -z
M_solver.Mult(z, du_dt);
@@ -338,7 +341,7 @@ void ConductionOperator::ImplicitSolve(const double dt,
{
// Solve the equation:
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
// for du_dt
// for du_dt, where K is linearized by using u from the previous timestep
if (!T)
{
T = Add(1.0, Mmat, dt, Kmat);
+8 -5
View File
@@ -24,8 +24,11 @@
// class ConductionOperator defining C(u)), as well as their
// implicit time integration. Note that implementing the method
// ConductionOperator::ImplicitSolve is the only requirement for
// high-order implicit (SDIRK) time integration. Optional saving
// with ADIOS2 (adios2.readthedocs.io) is also illustrated.
// high-order implicit (SDIRK) time integration. In this example,
// the diffusion operator is linearized by evaluating with the
// lagged solution from the previous timestep, so there is only
// a linear solve. Optional saving with ADIOS2
// (adios2.readthedocs.io) is also illustrated.
//
// We recommend viewing examples 2, 9 and 10 before viewing this
// example.
@@ -420,8 +423,8 @@ ConductionOperator::ConductionOperator(ParFiniteElementSpace &f, double al,
void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
{
// Compute:
// du_dt = M^{-1}*-K(u)
// for du_dt
// du_dt = M^{-1}*-Ku
// for du_dt, where K is linearized by using u from the previous timestep
Kmat.Mult(u, z);
z.Neg(); // z = -z
M_solver.Mult(z, du_dt);
@@ -432,7 +435,7 @@ void ConductionOperator::ImplicitSolve(const double dt,
{
// Solve the equation:
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
// for du_dt
// for du_dt, where K is linearized by using u from the previous timestep
if (!T)
{
T = Add(1.0, Mmat, dt, Kmat);
+1
View File
@@ -9,6 +9,7 @@
// mpirun -np 4 ex1p -m ../data/fichera.mesh
// mpirun -np 4 ex1p -m ../data/fichera-mixed.mesh
// mpirun -np 4 ex1p -m ../data/toroid-wedge.mesh
// mpirun -np 4 ex1p -m ../data/octahedron.mesh -o 1
// mpirun -np 4 ex1p -m ../data/periodic-annulus-sector.msh
// mpirun -np 4 ex1p -m ../data/periodic-torus-sector.msh
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
+2
View File
@@ -13,6 +13,8 @@
// ex22 -m ../data/inline-hex.mesh -o 2 -p 1
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2 -pa
// ex22 -m ../data/inline-wedge.mesh -o 1
// ex22 -m ../data/inline-pyramid.mesh -o 1
// ex22 -m ../data/star.mesh -r 1 -o 2 -sigma 10.0
//
// Device sample runs:
+2
View File
@@ -13,6 +13,8 @@
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2 -p 1
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2 -p 2
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 1 -p 2 -pa
// mpirun -np 4 ex22p -m ../data/inline-wedge.mesh -o 1
// mpirun -np 4 ex22p -m ../data/inline-pyramid.mesh -o 1
// mpirun -np 4 ex22p -m ../data/star.mesh -o 2 -sigma 10.0
//
// Device sample runs:
-1
View File
@@ -113,7 +113,6 @@ int main(int argc, char *argv[])
mesh->UniformRefinement();
}
}
mesh->ReorientTetMesh();
// 5. Define a finite element space on the mesh. Here we use Nedelec or
// Raviart-Thomas finite elements of the specified order.
-1
View File
@@ -141,7 +141,6 @@ int main(int argc, char *argv[])
pmesh->UniformRefinement();
}
}
pmesh->ReorientTetMesh();
// 7. Define a parallel finite element space on the parallel mesh. Here we
// use Nedelec or Raviart-Thomas finite elements of the specified order.
+2 -4
View File
@@ -277,10 +277,8 @@ int main(int argc, char *argv[])
mesh->UniformRefinement();
}
// 6. Reorient mesh in case of a tet mesh
mesh->ReorientTetMesh();
// Set element attributes in order to distinguish elements in the PML region
// 6. Set element attributes in order to distinguish elements in the
// PML region
pml->SetAttributes(mesh);
// 7. Define a finite element space on the mesh. Here we use the Nedelec
-3
View File
@@ -316,9 +316,6 @@ int main(int argc, char *argv[])
}
}
// 7a. Reorient mesh in case of a tet mesh
pmesh->ReorientTetMesh();
// 8. Set element attributes in order to distinguish elements in the PML
pml->SetAttributes(pmesh);
+2 -1
View File
@@ -16,6 +16,8 @@
// ex3 -m ../data/beam-hex-nurbs.mesh
// ex3 -m ../data/amr-hex.mesh
// ex3 -m ../data/fichera-amr.mesh
// ex3 -m ../data/ref-prism.mesh -o 1
// ex3 -m ../data/octahedron.mesh -o 1
// ex3 -m ../data/star-surf.mesh -o 1
// ex3 -m ../data/mobius-strip.mesh -f 0.1
// ex3 -m ../data/klein-bottle.mesh -f 0.1
@@ -113,7 +115,6 @@ int main(int argc, char *argv[])
mesh->UniformRefinement();
}
}
mesh->ReorientTetMesh();
// 5. Define a finite element space on the mesh. Here we use the Nedelec
// finite elements of the specified order.
+3 -4
View File
@@ -16,6 +16,8 @@
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
// mpirun -np 4 ex3p -m ../data/ref-prism.mesh -o 1
// mpirun -np 4 ex3p -m ../data/octahedron.mesh -o 1
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
@@ -139,9 +141,7 @@ int main(int argc, char *argv[])
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them.
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
{
@@ -151,7 +151,6 @@ int main(int argc, char *argv[])
pmesh->UniformRefinement();
}
}
pmesh->ReorientTetMesh();
// 7. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
+2
View File
@@ -19,6 +19,8 @@
// ex4 -m ../data/amr-hex.mesh
// ex4 -m ../data/amr-hex.mesh -o 2 -hb
// ex4 -m ../data/fichera-amr.mesh -o 2 -sc
// ex4 -m ../data/ref-prism.mesh -o 1
// ex4 -m ../data/octahedron.mesh -o 1
// ex4 -m ../data/star-surf.mesh -o 1
//
// Device sample runs:
+3 -4
View File
@@ -19,6 +19,8 @@
// mpirun -np 3 ex4p -m ../data/amr-quad.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/ref-prism.mesh -o 1
// mpirun -np 4 ex4p -m ../data/octahedron.mesh -o 1
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
//
// Device sample runs:
@@ -135,9 +137,7 @@ int main(int argc, char *argv[])
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them (this is needed in the ADS solver below).
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
{
@@ -147,7 +147,6 @@ int main(int argc, char *argv[])
pmesh->UniformRefinement();
}
}
pmesh->ReorientTetMesh();
// 7. Define a parallel finite element space on the parallel mesh. Here we
// use the Raviart-Thomas finite elements of the specified order.
-1
View File
@@ -106,7 +106,6 @@ int main(int argc, char *argv[])
pmesh->UniformRefinement();
}
}
pmesh->ReorientTetMesh();
// 6. Define the trial, interfacial (trace) and test DPG spaces:
// - The trial space, x0_space, contains the non-interfacial unknowns and
+1 -4
View File
@@ -121,9 +121,7 @@ int main(int argc, char *argv[])
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them.
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
{
@@ -133,7 +131,6 @@ int main(int argc, char *argv[])
pmesh->UniformRefinement();
}
}
pmesh->ReorientTetMesh();
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
+1 -4
View File
@@ -122,9 +122,7 @@ int main(int argc, char *argv[])
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them (this is needed in the ADS solver below).
// parallel mesh is defined, the serial mesh can be deleted.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
{
@@ -134,7 +132,6 @@ int main(int argc, char *argv[])
pmesh->UniformRefinement();
}
}
pmesh->ReorientTetMesh();
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Raviart-Thomas finite elements of the specified order.
+250
View File
@@ -0,0 +1,250 @@
// MFEM Example 11 - Serial Version
//
// Compile with: make ex11
//
// Sample runs: ex11 -m ../data/square-disc.mesh
// ex11 -m ../data/star.mesh
// ex11 -m ../data/star-mixed.mesh
// ex11 -m ../data/periodic-annulus-sector.msh
// ex11 -m ../data/square-disc-p2.vtk -o 2
// ex11 -m ../data/square-disc-p3.mesh -o 3
// ex11 -m ../data/square-disc-nurbs.mesh -o -1
// ex11 -m ../data/disc-nurbs.mesh -o -1 -n 20
// ex11 -m ../data/star-surf.mesh
// ex11 -m ../data/square-disc-surf.mesh
// ex11 -m ../data/inline-segment.mesh
// ex11 -m ../data/inline-quad.mesh
// ex11 -m ../data/inline-tri.mesh
// ex11 -m ../data/amr-quad.mesh
// ex11 -m ../data/amr-hex.mesh
// ex11 -m ../data/mobius-strip.mesh -n 8
//
// Description: This example code demonstrates the use of MFEM to solve the
// eigenvalue problem -Delta u = lambda u with homogeneous
// Dirichlet boundary conditions.
//
// We compute a number of the lowest eigenmodes by discretizing
// the Laplacian and Mass operators using a FE space of the
// specified order, or an isoparametric/isogeometric space if
// order < 1 (quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of the ARPACK eigenvalue solver
// (regular inverse mode). Reusing a single GLVis visualization
// window for multiple eigenfunctions is also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/star.mesh";
int ser_ref_levels = 1;
int order = 1;
int nev = 5;
double dbc_eig = 1e3;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&nev, "-n", "--num-eigs",
"Number of desired eigenmodes.");
args.AddOption(&dbc_eig, "-d", "--dbc-eig",
"Eigenvalues associated with Dirichlet BC "
"(should be larger than the maximum desired eigenvalue).");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh;
ifstream imesh(mesh_file);
if (!imesh)
{
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
return 2;
}
mesh = new Mesh(imesh, 1, 1);
imesh.close();
int dim = mesh->Dimension();
// 3. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement (2 by default, or
// specified on the command line with -rs).
for (int lev = 0; lev < ser_ref_levels; lev++)
{
mesh->UniformRefinement();
}
// 4. Define a finite element space on the mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
int size = fespace->GetVSize();
cout << "Number of unknowns: " << size << endl;
// 5. Set up the parallel bilinear forms a(.,.) and m(.,.) on the finite
// element space. The first corresponds to the Laplacian operator -Delta,
// while the second is a simple mass matrix needed on the right hand side
// of the generalized eigenvalue problem below. The boundary conditions
// are implemented by elimination with special values on the diagonal to
// shift the Dirichlet eigenvalues out of the computational range. After
// serial and parallel assembly we extract the corresponding parallel
// matrices A and M.
ConstantCoefficient one(1.0);
Array<int> ess_bdr;
if (mesh->bdr_attributes.Size())
{
ess_bdr.SetSize(mesh->bdr_attributes.Max());
ess_bdr = 1;
}
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
if (mesh->bdr_attributes.Size() == 0)
{
// Add a mass term if the mesh has no boundary, e.g. periodic mesh or
// closed surface.
a->AddDomainIntegrator(new MassIntegrator(one));
}
a->Assemble();
if (mesh->bdr_attributes.Size() != 0)
{
a->EliminateEssentialBCDiag(ess_bdr, dbc_eig);
}
a->Finalize();
BilinearForm *m = new BilinearForm(fespace);
m->AddDomainIntegrator(new MassIntegrator(one));
m->Assemble();
if (mesh->bdr_attributes.Size() != 0)
{
// shift the eigenvalue corresponding to eliminated dofs to a large value
m->EliminateEssentialBCDiag(ess_bdr, 1.0);
}
m->Finalize();
// 6. Define and configure the SPECTRA eigensolver and solve problem
SpectraEigenSolver spectra;
spectra.SetNumModes(nev)
.SetKrylov(10)
.SetMaxIter(5000)
.SetTol(1e-5)
.SetOperators(*a, *m)
.Solve();
Eigen::VectorXd eigenvalues = spectra.GetEigenvalues(nev);
// 7. Define a grid function to represent each of the eigenmodes returned by the solver.
GridFunction x(fespace);
// 8. Save the refined mesh and the modes in parallel.
// This output can be viewed later using GLVis: "glvis -np <np> -m mesh -g mode"
{
ostringstream mesh_name, mode_name;
mesh_name << "ex11.mesh";
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
for (int i = 0; i < nev; i++) {
// conver Eigen Vector to MFEM Vector
Vector eigenvector = VectorConverter<double>::from(spectra.GetEigenvector(i));
// convert eigenvector from Vector to GridFunction
x = eigenvector;
mode_name << "mode_" << setfill('0') << setw(2) << i;
ofstream mode_ofs(mode_name.str().c_str());
mode_ofs.precision(8);
x.Save(mode_ofs);
mode_name.str("");
}
}
// 10. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream mode_sock(vishost, visport);
mode_sock.precision(8);
for (int i=0; i<nev; i++)
{
cout << "Eigenmode " << i+1 << '/' << nev
<< ", Lambda = " << eigenvalues[i] << endl;
// convert eigenvector from HypreParVector to ParGridFunction
Vector eigenvector = VectorConverter<double>::from(spectra.GetEigenvector(i));
x = eigenvector;
mode_sock << "solution\n" << *mesh << x << flush
<< "window_title 'Eigenmode " << i+1 << '/' << nev
<< ", Lambda = " << eigenvalues[i] << "'" << endl;
char c;
cout << "press (q)uit or (c)ontinue --> " << flush;
cin >> c;
if (c != 'c')
{
break;
}
}
mode_sock.close();
}
// 10. Free the used memory.
delete m;
delete a;
delete fespace;
if (order > 0)
{
delete fec;
}
delete mesh;
return 0;
}
+67
View File
@@ -0,0 +1,67 @@
# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Use the MFEM build directory
MFEM_DIR ?= ../..
MFEM_BUILD_DIR ?= ../..
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/spectra/,)
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
# Use the MFEM install directory
# MFEM_INSTALL_DIR = ../../mfem
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_EXAMPLES = ex11
PAR_EXAMPLES =
ifeq ($(MFEM_USE_MPI),NO)
EXAMPLES = $(SEQ_EXAMPLES)
else
EXAMPLES = $(PAR_EXAMPLES)
endif
RC_FILES = $(patsubst $(SRC)%,%,$(wildcard $(SRC)rc_*))
.SUFFIXES:
.SUFFIXES: .o .cpp .mk
.PHONY: all clean clean-build clean-exec
# Remove built-in rule
%: %.cpp
# Replace the default implicit rule for *.cpp files
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
all: $(EXAMPLES)
# Examples depend on their corresponding rc_* files:
make-rc-rule = $(1): | $(filter rc_$(1)%,$(RC_FILES))
$(foreach ex,$(EXAMPLES),$(eval $(call make-rc-rule,$(ex))))
# Rules to copy the rc_* files when building out-of-source:
ifneq ($(SRC),)
$(RC_FILES): %: $(SRC)%
cp -pf $(<) .
endif
# Generate an error message if the MFEM library is not built and exit
$(MFEM_LIB_FILE):
$(error The MFEM library is not built)
clean: clean-build clean-exec
clean-build:
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -rf *.mesh mode_*
+4
View File
@@ -39,6 +39,7 @@ set(SRCS
complex_fem.cpp
convergence.cpp
datacollection.cpp
doftrans.cpp
eltrans.cpp
estimators.cpp
fe.cpp
@@ -105,6 +106,7 @@ set(SRCS
tmop/tmop_pa_w3.cpp
tmop/tmop_pa_w3_c0.cpp
tmop_tools.cpp
tmop_amr.cpp
gslib.cpp
transfer.cpp
lor.cpp
@@ -118,6 +120,7 @@ set(HDRS
complex_fem.hpp
convergence.hpp
datacollection.hpp
doftrans.hpp
eltrans.hpp
estimators.hpp
fe.hpp
@@ -164,6 +167,7 @@ set(HDRS
tmop.hpp
tmop/tmop_pa.hpp
tmop_tools.hpp
tmop_amr.hpp
gslib.hpp
transfer.hpp
lor.hpp
+58 -24
View File
@@ -391,6 +391,7 @@ void BilinearForm::Assemble(int skip_zeros)
}
ElementTransformation *eltrans;
DofTransformation * doftrans;
Mesh *mesh = fes -> GetMesh();
DenseMatrix elmat, *elmat_p;
@@ -424,7 +425,7 @@ void BilinearForm::Assemble(int skip_zeros)
for (int i = 0; i < fes -> GetNE(); i++)
{
int elem_attr = fes->GetMesh()->GetAttribute(i);
fes->GetElementVDofs(i, vdofs);
doftrans = fes->GetElementVDofs(i, vdofs);
if (element_matrices)
{
elmat_p = &(*element_matrices)(i);
@@ -458,6 +459,11 @@ void BilinearForm::Assemble(int skip_zeros)
{
elmat_p = &elmat;
}
if (doftrans)
{
doftrans->TransformDual(elmat);
}
elmat_p = &elmat;
}
if (static_cond)
{
@@ -503,7 +509,7 @@ void BilinearForm::Assemble(int skip_zeros)
if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
const FiniteElement &be = *fes->GetBE(i);
fes -> GetBdrElementVDofs (i, vdofs);
doftrans = fes -> GetBdrElementVDofs (i, vdofs);
eltrans = fes -> GetBdrElementTransformation (i);
int k = 0;
for (; k < boundary_integs.Size(); k++)
@@ -523,17 +529,22 @@ void BilinearForm::Assemble(int skip_zeros)
boundary_integs[k]->AssembleElementMatrix(be, *eltrans, elemmat);
elmat += elemmat;
}
if (doftrans)
{
doftrans->TransformDual(elmat);
}
elmat_p = &elmat;
if (!static_cond)
{
mat->AddSubMatrix(vdofs, vdofs, elmat, skip_zeros);
mat->AddSubMatrix(vdofs, vdofs, *elmat_p, skip_zeros);
if (hybridization)
{
hybridization->AssembleBdrMatrix(i, elmat);
hybridization->AssembleBdrMatrix(i, *elmat_p);
}
}
else
{
static_cond->AssembleBdrMatrix(i, elmat);
static_cond->AssembleBdrMatrix(i, *elmat_p);
}
}
}
@@ -1318,9 +1329,10 @@ void MixedBilinearForm::Assemble (int skip_zeros)
return;
}
Array<int> tr_vdofs, te_vdofs;
ElementTransformation *eltrans;
DenseMatrix elemmat;
DofTransformation * dom_dof_trans;
DofTransformation * ran_dof_trans;
DenseMatrix elmat;
Mesh *mesh = test_fes -> GetMesh();
@@ -1333,16 +1345,24 @@ void MixedBilinearForm::Assemble (int skip_zeros)
{
for (int i = 0; i < test_fes -> GetNE(); i++)
{
trial_fes -> GetElementVDofs (i, tr_vdofs);
test_fes -> GetElementVDofs (i, te_vdofs);
dom_dof_trans = trial_fes -> GetElementVDofs (i, trial_vdofs);
ran_dof_trans = test_fes -> GetElementVDofs (i, test_vdofs);
eltrans = test_fes -> GetElementTransformation (i);
elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
elmat = 0.0;
for (int k = 0; k < domain_integs.Size(); k++)
{
domain_integs[k] -> AssembleElementMatrix2 (*trial_fes -> GetFE(i),
*test_fes -> GetFE(i),
*eltrans, elemmat);
mat -> AddSubMatrix (te_vdofs, tr_vdofs, elemmat, skip_zeros);
elmat += elemmat;
}
if (ran_dof_trans || dom_dof_trans)
{
TransformDual(ran_dof_trans, dom_dof_trans, elmat);
}
mat -> AddSubMatrix (test_vdofs, trial_vdofs, elmat, skip_zeros);
}
}
@@ -1374,9 +1394,12 @@ void MixedBilinearForm::Assemble (int skip_zeros)
const int bdr_attr = mesh->GetBdrAttribute(i);
if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
trial_fes -> GetBdrElementVDofs (i, tr_vdofs);
test_fes -> GetBdrElementVDofs (i, te_vdofs);
dom_dof_trans = trial_fes -> GetBdrElementVDofs (i, trial_vdofs);
ran_dof_trans = test_fes -> GetBdrElementVDofs (i, test_vdofs);
eltrans = test_fes -> GetBdrElementTransformation (i);
elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
elmat = 0.0;
for (int k = 0; k < boundary_integs.Size(); k++)
{
if (boundary_integs_marker[k] &&
@@ -1385,29 +1408,34 @@ void MixedBilinearForm::Assemble (int skip_zeros)
boundary_integs[k]->AssembleElementMatrix2 (*trial_fes -> GetBE(i),
*test_fes -> GetBE(i),
*eltrans, elemmat);
mat -> AddSubMatrix (te_vdofs, tr_vdofs, elemmat, skip_zeros);
elmat += elemmat;
}
if (ran_dof_trans || dom_dof_trans)
{
TransformDual(ran_dof_trans, dom_dof_trans, elmat);
}
mat -> AddSubMatrix (test_vdofs, trial_vdofs, elmat, skip_zeros);
}
}
if (trace_face_integs.Size())
{
FaceElementTransformations *ftr;
Array<int> te_vdofs2;
Array<int> test_vdofs2;
const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
int nfaces = mesh->GetNumFaces();
for (int i = 0; i < nfaces; i++)
{
ftr = mesh->GetFaceElementTransformations(i);
trial_fes->GetFaceVDofs(i, tr_vdofs);
test_fes->GetElementVDofs(ftr->Elem1No, te_vdofs);
trial_fes->GetFaceVDofs(i, trial_vdofs);
test_fes->GetElementVDofs(ftr->Elem1No, test_vdofs);
trial_face_fe = trial_fes->GetFaceElement(i);
test_fe1 = test_fes->GetFE(ftr->Elem1No);
if (ftr->Elem2No >= 0)
{
test_fes->GetElementVDofs(ftr->Elem2No, te_vdofs2);
te_vdofs.Append(te_vdofs2);
test_fes->GetElementVDofs(ftr->Elem2No, test_vdofs2);
test_vdofs.Append(test_vdofs2);
test_fe2 = test_fes->GetFE(ftr->Elem2No);
}
else
@@ -1421,7 +1449,7 @@ void MixedBilinearForm::Assemble (int skip_zeros)
{
trace_face_integs[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1,
*test_fe2, *ftr, elemmat);
mat->AddSubMatrix(te_vdofs, tr_vdofs, elemmat, skip_zeros);
mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
}
}
}
@@ -1461,8 +1489,8 @@ void MixedBilinearForm::Assemble (int skip_zeros)
ftr = mesh->GetBdrFaceTransformations(i);
if (ftr)
{
trial_fes->GetFaceVDofs(ftr->ElementNo, tr_vdofs);
test_fes->GetElementVDofs(ftr->Elem1No, te_vdofs);
trial_fes->GetFaceVDofs(ftr->ElementNo, trial_vdofs);
test_fes->GetElementVDofs(ftr->Elem1No, test_vdofs);
trial_face_fe = trial_fes->GetFaceElement(ftr->ElementNo);
test_fe1 = test_fes->GetFE(ftr->Elem1No);
// The test_fe2 object is really a dummy and not used on the
@@ -1479,7 +1507,7 @@ void MixedBilinearForm::Assemble (int skip_zeros)
*test_fe1,
*test_fe2,
*ftr, elemmat);
mat->AddSubMatrix(te_vdofs, tr_vdofs, elemmat, skip_zeros);
mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
}
}
}
@@ -1841,6 +1869,8 @@ void DiscreteLinearOperator::Assemble(int skip_zeros)
Array<int> dom_vdofs, ran_vdofs;
ElementTransformation *T;
DofTransformation * dom_dof_trans;
DofTransformation * ran_dof_trans;
const FiniteElement *dom_fe, *ran_fe;
DenseMatrix totelmat, elmat;
@@ -1853,8 +1883,8 @@ void DiscreteLinearOperator::Assemble(int skip_zeros)
{
for (int i = 0; i < test_fes->GetNE(); i++)
{
trial_fes->GetElementVDofs(i, dom_vdofs);
test_fes->GetElementVDofs(i, ran_vdofs);
dom_dof_trans = trial_fes->GetElementVDofs(i, dom_vdofs);
ran_dof_trans = test_fes->GetElementVDofs(i, ran_vdofs);
T = test_fes->GetElementTransformation(i);
dom_fe = trial_fes->GetFE(i);
ran_fe = test_fes->GetFE(i);
@@ -1867,6 +1897,10 @@ void DiscreteLinearOperator::Assemble(int skip_zeros)
elmat);
totelmat += elmat;
}
if (ran_dof_trans || dom_dof_trans)
{
TransformPrimal(ran_dof_trans, dom_dof_trans, totelmat);
}
mat->SetSubMatrix(ran_vdofs, dom_vdofs, totelmat, skip_zeros);
}
}
+358
View File
@@ -0,0 +1,358 @@
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "fem.hpp"
namespace mfem
{
void DofTransformation::TransformPrimal(Vector &v) const
{
TransformPrimal(v.GetData());
}
void DofTransformation::TransformPrimalCols(DenseMatrix &V) const
{
for (int c=0; c<V.Width(); c++)
{
TransformPrimal(V.GetColumn(c));
}
}
void DofTransformation::TransformDual(Vector &v) const
{
TransformDual(v.GetData());
}
void DofTransformation::TransformDual(DenseMatrix &V) const
{
TransformDualCols(V);
TransformDualRows(V);
}
void DofTransformation::TransformDualRows(DenseMatrix &V) const
{
Vector row;
for (int r=0; r<V.Height(); r++)
{
V.GetRow(r, row);
TransformDual(row);
V.SetRow(r, row);
}
}
void DofTransformation::TransformDualCols(DenseMatrix &V) const
{
for (int c=0; c<V.Width(); c++)
{
TransformDual(V.GetColumn(c));
}
}
void DofTransformation::InvTransformPrimal(Vector &v) const
{
InvTransformPrimal(v.GetData());
}
void TransformPrimal(const DofTransformation *ran_dof_trans,
const DofTransformation *dom_dof_trans,
DenseMatrix &elmat)
{
if (ran_dof_trans && dom_dof_trans)
{
ran_dof_trans->TransformPrimalCols(elmat);
dom_dof_trans->TransformDualRows(elmat);
}
else if (ran_dof_trans)
{
ran_dof_trans->TransformPrimalCols(elmat);
}
else if (dom_dof_trans)
{
dom_dof_trans->TransformDualRows(elmat);
}
else
{
// If both transformations are NULL this function should not be called
}
}
void TransformDual(const DofTransformation *ran_dof_trans,
const DofTransformation *dom_dof_trans,
DenseMatrix &elmat)
{
if (ran_dof_trans && dom_dof_trans)
{
ran_dof_trans->TransformDualCols(elmat);
dom_dof_trans->TransformDualRows(elmat);
}
else if (ran_dof_trans)
{
ran_dof_trans->TransformDualCols(elmat);
}
else if (dom_dof_trans)
{
dom_dof_trans->TransformDualRows(elmat);
}
else
{
// If both transformations are NULL this function should not be called
}
}
void VDofTransformation::TransformPrimal(double *v) const
{
int size = doftrans_->Size();
if ((Ordering::Type)ordering_ == Ordering::byNODES || vdim_ == 1)
{
for (int i=0; i<vdim_; i++)
{
doftrans_->TransformPrimal(&v[i*size]);
}
}
else
{
Vector vec(size);
for (int i=0; i<vdim_; i++)
{
for (int j=0; j<size; j++)
{
vec(j) = v[j*vdim_+i];
}
doftrans_->TransformPrimal(vec);
for (int j=0; j<size; j++)
{
v[j*vdim_+i] = vec(j);
}
}
}
}
void VDofTransformation::InvTransformPrimal(double *v) const
{
int size = doftrans_->Height();
if ((Ordering::Type)ordering_ == Ordering::byNODES)
{
for (int i=0; i<vdim_; i++)
{
doftrans_->InvTransformPrimal(&v[i*size]);
}
}
else
{
Vector vec(size);
for (int i=0; i<vdim_; i++)
{
for (int j=0; j<size; j++)
{
vec(j) = v[j*vdim_+i];
}
doftrans_->InvTransformPrimal(vec);
for (int j=0; j<size; j++)
{
v[j*vdim_+i] = vec(j);
}
}
}
}
void VDofTransformation::TransformDual(double *v) const
{
int size = doftrans_->Size();
if ((Ordering::Type)ordering_ == Ordering::byNODES)
{
for (int i=0; i<vdim_; i++)
{
doftrans_->TransformDual(&v[i*size]);
}
}
else
{
Vector vec(size);
for (int i=0; i<vdim_; i++)
{
for (int j=0; j<size; j++)
{
vec(j) = v[j*vdim_+i];
}
doftrans_->TransformDual(vec);
for (int j=0; j<size; j++)
{
v[j*vdim_+i] = vec(j);
}
}
}
}
const double ND_DofTransformation::T_data[24] =
{
1.0, 0.0, 0.0, 1.0,
-1.0, -1.0, 0.0, 1.0,
0.0, 1.0, -1.0, -1.0,
1.0, 0.0, -1.0, -1.0,
-1.0, -1.0, 1.0, 0.0,
0.0, 1.0, 1.0, 0.0
};
const DenseTensor ND_DofTransformation
::T(const_cast<double*>(ND_DofTransformation::T_data), 2, 2, 6);
const double ND_DofTransformation::TInv_data[24] =
{
1.0, 0.0, 0.0, 1.0,
-1.0, -1.0, 0.0, 1.0,
-1.0, -1.0, 1.0, 0.0,
1.0, 0.0, -1.0, -1.0,
0.0, 1.0, -1.0, -1.0,
0.0, 1.0, 1.0, 0.0
};
const DenseTensor ND_DofTransformation
::TInv(const_cast<double*>(TInv_data), 2, 2, 6);
ND_DofTransformation::ND_DofTransformation(int size, int p)
: DofTransformation(size),
order(p)
{
}
ND_TriDofTransformation::ND_TriDofTransformation(int p)
: ND_DofTransformation(p*(p + 2), p)
{
}
void ND_TriDofTransformation::TransformPrimal(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<1; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[3*nedofs + f*nfdofs + 2*i];
T(Fo[f]).Mult(v2, &v[3*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_TriDofTransformation::InvTransformPrimal(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<1; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[3*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).Mult(v2, &v[3*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_TriDofTransformation::TransformDual(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<1; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[3*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).MultTranspose(v2, &v[3*nedofs + f*nfdofs + 2*i]);
}
}
}
ND_TetDofTransformation::ND_TetDofTransformation(int p)
: ND_DofTransformation(p*(p + 2)*(p + 3)/2, p)
{
}
void ND_TetDofTransformation::TransformPrimal(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<4; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[6*nedofs + f*nfdofs + 2*i];
T(Fo[f]).Mult(v2, &v[6*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_TetDofTransformation::InvTransformPrimal(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<4; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[6*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).Mult(v2, &v[6*nedofs + f*nfdofs + 2*i]);
}
}
}
void
ND_TetDofTransformation::TransformDual(double *v) const
{
int nedofs = order; // number of DoFs per edge
int nfdofs = order*(order-1); // number of DoFs per face
double data[2];
Vector v2(data, 2);
// Transform face DoFs
for (int f=0; f<4; f++)
{
for (int i=0; i<nfdofs/2; i++)
{
v2 = &v[6*nedofs + f*nfdofs + 2*i];
TInv(Fo[f]).MultTranspose(v2, &v[6*nedofs + f*nfdofs + 2*i]);
}
}
}
} // namespace mfem
+277
View File
@@ -0,0 +1,277 @@
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_DOFTRANSFORM
#define MFEM_DOFTRANSFORM
#include "../config/config.hpp"
#include "../linalg/linalg.hpp"
#include "intrules.hpp"
#include "fe.hpp"
namespace mfem
{
/** The DofTransformation class is an abstract base class for a family of
transformations that map local degrees of freedom (DoFs), contained within
individual elements, to global degrees of freedom, stored within
GridFunction objects. These transformations are necessary to ensure that
basis functions in neighboring elements align correctly. Closely related but
complementary transformations are required for the entries stored in
LinearForm and BilinearForm objects. The DofTransformation class is designed
to apply the action of both of these types of DoF transformations.
Let the "primal transformation" be given by the operator T. This means that
given a local element vector v the data that must be placed into a
GridFunction object is v_t = T * v.
We also need the inverse of the primal transformation T^{-1} so that we can
recover the local element vector from data read out of a GridFunction
e.g. v = T^{-1} * v_t.
We need to preserve the action of our linear forms applied to primal
vectors. In other words, if f is the local vector computed by a linear
form then f * v = f_t * v_t (where "*" represents an inner product of
vectors). This requires that f_t = T^{-T} * f i.e. the "dual transform" is
given by the transpose of the inverse of the primal transformation.
For bilinear forms we require that v^T * A * v = v_t^T * A_t * v_t. This
implies that A_t = T^{-T} * A * T^{-1}. This can be accomplished by
performing dual transformations of the rows and columns of the matrix A.
For discrete linear operators the range must be modified with the primal
transformation rather than the dual transformation because the result is a
primal vector rather than a dual vector. This leads to the transformation
D_t = T * D * T^{-1}. This can be accomplished by using a primal
transformation on the columns of D and a dual transformation on its rows.
*/
class DofTransformation
{
protected:
int size_;
Array<int> Fo;
DofTransformation(int size)
: size_(size) {}
public:
inline int Size() const { return size_; }
inline int Height() const { return size_; }
inline int NumRows() const { return size_; }
inline int Width() const { return size_; }
inline int NumCols() const { return size_; }
/** @brief Configure the transformation using face orientations for the
current element. */
/// The face_orientation array can be obtained from Mesh::GetElementFaces.
inline void SetFaceOrientations(const Array<int> & face_orientation)
{ Fo = face_orientation; }
inline const Array<int> & GetFaceOrientations() const { return Fo; }
/** Transform local DoFs to align with the global DoFs. For example, this
transformation can be used to map the local vector computed by
FiniteElement::Project() to the transformed vector stored within a
GridFunction object. */
virtual void TransformPrimal(double *v) const = 0;
virtual void TransformPrimal(Vector &v) const;
/// Transform groups of DoFs stored as dense matrices
virtual void TransformPrimalCols(DenseMatrix &V) const;
/** Inverse transform local DoFs. Used to transform DoFs from a global vector
back to their element-local form. For example, this must be used to
transform the vector obtained using GridFunction::GetSubVector before it
can be used to compute a local interpolation.
*/
virtual void InvTransformPrimal(double *v) const = 0;
virtual void InvTransformPrimal(Vector &v) const;
/** Transform dual DoFs as computed by a LinearFormIntegrator before summing
into a LinearForm object. */
virtual void TransformDual(double *v) const = 0;
virtual void TransformDual(Vector &v) const;
/** Transform a matrix of dual DoFs entries as computed by a
BilinearFormIntegrator before summing into a BilinearForm object. */
virtual void TransformDual(DenseMatrix &V) const;
/// Transform groups of dual DoFs stored as dense matrices
virtual void TransformDualRows(DenseMatrix &V) const;
virtual void TransformDualCols(DenseMatrix &V) const;
virtual ~DofTransformation() {}
};
/** Transform a matrix of DoFs entries from different finite element spaces as
computed by a DiscreteInterpolator before copying into a
DiscreteLinearOperator.
*/
void TransformPrimal(const DofTransformation *ran_dof_trans,
const DofTransformation *dom_dof_trans,
DenseMatrix &elmat);
/** Transform a matrix of dual DoFs entries from different finite element spaces
as computed by a BilinearFormIntegrator before summing into a
MixedBilinearForm object.
*/
void TransformDual(const DofTransformation *ran_dof_trans,
const DofTransformation *dom_dof_trans,
DenseMatrix &elmat);
/** The VDofTransformation class implements a nested transformation where an
arbitrary DofTransformation is replicated with a vdim >= 1.
*/
class VDofTransformation : public DofTransformation
{
private:
int vdim_;
int ordering_;
DofTransformation * doftrans_;
public:
/** @brief Default constructor which requires that SetDofTransformation be
called before use. */
VDofTransformation(int vdim = 1, int ordering = 0)
: DofTransformation(0),
vdim_(vdim), ordering_(ordering),
doftrans_(NULL) {}
/// Constructor with a known DofTransformation
VDofTransformation(DofTransformation & doftrans, int vdim = 1,
int ordering = 0)
: DofTransformation(vdim * doftrans.Size()),
vdim_(vdim), ordering_(ordering),
doftrans_(&doftrans) {}
/// Set or change the vdim parameter
inline void SetVDim(int vdim)
{
vdim_ = vdim;
if (doftrans_)
{
size_ = vdim_ * doftrans_->Size();
}
}
/// Return the current vdim value
inline int GetVDim() const { return vdim_; }
/// Set or change the nested DofTransformation object
inline void SetDofTransformation(DofTransformation & doftrans)
{
size_ = vdim_ * doftrans.Size();
doftrans_ = &doftrans;
}
/// Return the nested DofTransformation object
inline DofTransformation * GetDofTransformation() const { return doftrans_; }
inline void SetFaceOrientation(const Array<int> & face_orientation)
{ Fo = face_orientation; doftrans_->SetFaceOrientations(face_orientation); }
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
};
/** Abstract base class for high-order Nedelec spaces on elements with
triangular faces.
The Nedelec DoFs on the interior of triangular faces come in pairs which
share an interpolation point but have different vector directions. These
directions depend on the orientation of the face and can therefore differ in
neighboring elements. The mapping required to transform these DoFs can be
implemented as series of 2x2 linear transformations. The raw data for these
linear transformations is stored in the T_data and TInv_data arrays and can
be accessed as DenseMatrices using the GetFaceTransform() and
GetFaceInverseTransform() methods.
*/
class ND_DofTransformation : public DofTransformation
{
protected:
static const double T_data[24];
static const double TInv_data[24];
static const DenseTensor T, TInv;
int order;
ND_DofTransformation(int size, int order);
public:
// Return the 2x2 transformation operator for the given face orientation
static const DenseMatrix & GetFaceTransform(int ori) { return T(ori); }
// Return the 2x2 inverse transformation operator
static const DenseMatrix & GetFaceInverseTransform(int ori)
{ return TInv(ori); }
};
/// DoF transformation implementation for the Nedelec basis on triangles
class ND_TriDofTransformation : public ND_DofTransformation
{
public:
ND_TriDofTransformation(int order);
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
};
/// DoF transformation implementation for the Nedelec basis on tetrahedra
class ND_TetDofTransformation : public ND_DofTransformation
{
public:
ND_TetDofTransformation(int order);
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
};
/// DoF transformation implementation for the Nedelec basis on wedge elements
/** TODO: (Under development) */
class ND_WedgeDofTransformation : public ND_DofTransformation
{
public:
ND_WedgeDofTransformation(int order);
using DofTransformation::TransformPrimal;
using DofTransformation::InvTransformPrimal;
using DofTransformation::TransformDual;
void TransformPrimal(double *v) const;
void InvTransformPrimal(double *v) const;
void TransformDual(double *v) const;
};
} // namespace mfem
#endif // MFEM_DOFTRANSFORM
+1
View File
@@ -380,6 +380,7 @@ void IsoparametricTransformation::SetIdentityTransformation(
case Geometry::TETRAHEDRON : FElem = &TetrahedronFE; break;
case Geometry::CUBE : FElem = &HexahedronFE; break;
case Geometry::PRISM : FElem = &WedgeFE; break;
case Geometry::PYRAMID : FElem = &PyramidFE; break;
default:
MFEM_ABORT("unknown Geometry::Type!");
}
+3 -2
View File
@@ -329,7 +329,7 @@ void KellyErrorEstimator::ComputeEstimates()
error_estimates(e) = sqrt(factor * error_estimates(e));
}
total_error = error_estimates.Sum();
total_error = error_estimates.Norml2();
delete flux;
return;
}
@@ -452,9 +452,10 @@ void KellyErrorEstimator::ComputeEstimates()
auto pfes = dynamic_cast<ParFiniteElementSpace*>(xfes);
MFEM_VERIFY(pfes, "xfes is not a ParFiniteElementSpace pointer");
double process_local_error = error_estimates.Sum();
double process_local_error = pow(error_estimates.Norml2(),2.0);
MPI_Allreduce(&process_local_error, &total_error, 1, MPI_DOUBLE,
MPI_SUM, pfes->GetComm());
total_error = sqrt(total_error);
#endif // MFEM_USE_MPI
}
+1204 -18
View File
File diff suppressed because it is too large Load Diff
+219
View File
@@ -1313,6 +1313,64 @@ public:
DenseMatrix &dshape) const;
};
/// A linear element defined on a triangular prism
class LinearWedgeFiniteElement : public NodalFiniteElement
{
public:
/// Construct the LinearWedgeFiniteElement
LinearWedgeFiniteElement();
/** @brief virtual function which evaluates the values of all
shape functions at a given point ip and stores
them in the vector shape of dimension Dof (4) */
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
/** @brief virtual function which evaluates the values of all
partial derivatives of all shape functions at a given
point ip and stores them in the matrix dshape (Dof x Dim) (4 x 3)
so that each row contains the derivatives of one shape function */
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const
{ dofs = 0.0; dofs(vertex) = 1.0; }
/** @brief Get the dofs associated with the given @a face.
@a *dofs is set to an internal array of the local dofc on the
face, while *ndofs is set to the number of dofs on that face.
*/
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
};
/// A linear element defined on a square pyramid
class LinearPyramidFiniteElement : public NodalFiniteElement
{
public:
/// Construct the LinearPyramidFiniteElement
LinearPyramidFiniteElement();
/** @brief virtual function which evaluates the values of all
shape functions at a given point ip and stores
them in the vector shape of dimension Dof (4) */
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
/** @brief virtual function which evaluates the values of all
partial derivatives of all shape functions at a given
point ip and stores them in the matrix dshape (Dof x Dim) (4 x 3)
so that each row contains the derivatives of one shape function */
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const
{ dofs = 0.0; dofs(vertex) = 1.0; }
/** @brief Get the dofs associated with the given @a face.
@a *dofs is set to an internal array of the local dofc on the
face, while *ndofs is set to the number of dofs on that face.
*/
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
};
/// A 2D constant element on a triangle
class P0TriangleFiniteElement : public NodalFiniteElement
{
@@ -1690,6 +1748,32 @@ public:
{ dofs(0) = 1.0; }
};
/// A 3D constant element on a wedge
class P0WdgFiniteElement : public NodalFiniteElement
{
public:
/// Construct the P0WdgFiniteElement
P0WdgFiniteElement ();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const
{ dofs(0) = 1.0; }
};
/// A 3D constant element on a pyramid
class P0PyrFiniteElement : public NodalFiniteElement
{
public:
/// Construct the P0PyrFiniteElement
P0PyrFiniteElement ();
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
virtual void ProjectDelta(int vertex, Vector &dofs) const
{ dofs(0) = 1.0; }
};
/** @brief Tensor products of 1D Lagrange1DFiniteElement
(only degree 2 is functional) */
class LagrangeHexFiniteElement : public NodalFiniteElement
@@ -1828,6 +1912,10 @@ public:
using FiniteElement::Project;
virtual void Project (VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const;
virtual void ProjectGrad(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &grad) const;
};
@@ -1852,6 +1940,66 @@ public:
using FiniteElement::Project;
virtual void Project (VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const;
virtual void ProjectGrad(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &grad) const;
};
/// A 3D 1st order Nedelec element on a wedge
class Nedelec1WdgFiniteElement : public VectorFiniteElement
{
private:
static const double tk[9][3];
public:
/// Construct the Nedelec1WdgFiniteElement
Nedelec1WdgFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{ CalcVShape_ND(Trans, shape); }
virtual void CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const;
virtual void GetLocalInterpolation (ElementTransformation &Trans,
DenseMatrix &I) const;
using FiniteElement::Project;
virtual void Project (VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const;
virtual void ProjectGrad(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &grad) const;
};
/// A 3D 1st order Nedelec element on a pyramid
class Nedelec1PyrFiniteElement : public VectorFiniteElement
{
private:
static const double tk[8][3];
public:
/// Construct the Nedelec1PyrFiniteElement
Nedelec1PyrFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{ CalcVShape_ND(Trans, shape); }
virtual void CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const;
virtual void GetLocalInterpolation (ElementTransformation &Trans,
DenseMatrix &I) const;
using FiniteElement::Project;
virtual void Project (VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const;
virtual void ProjectGrad(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &grad) const;
};
@@ -1945,6 +2093,77 @@ public:
};
/// A 3D 0th order Raviert-Thomas element on a wedge
class RT0WdgFiniteElement : public VectorFiniteElement
{
private:
static const double nk[5][3];
public:
/// Construct the RT0WdgFiniteElement
RT0WdgFiniteElement();
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{ CalcVShape_RT(Trans, shape); }
virtual void CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const;
virtual void GetLocalInterpolation (ElementTransformation &Trans,
DenseMatrix &I) const;
using FiniteElement::Project;
virtual void Project (VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const;
virtual void ProjectCurl(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &curl) const;
};
/// A 3D 0th order Raviert-Thomas element on a pyramid
class RT0PyrFiniteElement : public VectorFiniteElement
{
private:
static const double nk[5][3];
// If true match RT0TetFiniteElement rather than RT_TetrahedronElement(0)
bool rt0;
public:
/// Construct the RT0PyrFiniteElement
RT0PyrFiniteElement(bool rt0tets = true);
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{ CalcVShape_RT(Trans, shape); }
virtual void CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const;
virtual void GetLocalInterpolation (ElementTransformation &Trans,
DenseMatrix &I) const;
using FiniteElement::Project;
virtual void Project (VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const;
virtual void ProjectCurl(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &curl) const;
};
class RotTriLinearHexFiniteElement : public NodalFiniteElement
{
public:
+122 -16
View File
@@ -33,6 +33,9 @@ int FiniteElementCollection::HasFaceDofs(Geometry::Type geom, int p) const
case Geometry::PRISM:
return max(GetNumDof(Geometry::TRIANGLE, p),
GetNumDof(Geometry::SQUARE, p));
case Geometry::PYRAMID:
return max(GetNumDof(Geometry::TRIANGLE, p),
GetNumDof(Geometry::SQUARE, p));
default:
MFEM_ABORT("unknown geometry type");
}
@@ -574,6 +577,7 @@ LinearFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::TETRAHEDRON: return &TetrahedronFE;
case Geometry::CUBE: return &ParallelepipedFE;
case Geometry::PRISM: return &WedgeFE;
case Geometry::PYRAMID: return &PyramidFE;
default:
mfem_error ("LinearFECollection: unknown geometry type.");
}
@@ -591,6 +595,7 @@ int LinearFECollection::DofForGeometry(Geometry::Type GeomType) const
case Geometry::TETRAHEDRON: return 0;
case Geometry::CUBE: return 0;
case Geometry::PRISM: return 0;
case Geometry::PYRAMID: return 0;
default:
mfem_error ("LinearFECollection: unknown geometry type.");
}
@@ -1240,6 +1245,7 @@ Const3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::TETRAHEDRON: return &TetrahedronFE;
case Geometry::CUBE: return &ParallelepipedFE;
case Geometry::PRISM: return &WedgeFE;
case Geometry::PYRAMID: return &PyramidFE;
default:
mfem_error ("Const3DFECollection: unknown geometry type.");
}
@@ -1257,6 +1263,7 @@ int Const3DFECollection::DofForGeometry(Geometry::Type GeomType) const
case Geometry::TETRAHEDRON: return 1;
case Geometry::CUBE: return 1;
case Geometry::PRISM: return 1;
case Geometry::PYRAMID: return 1;
default:
mfem_error ("Const3DFECollection: unknown geometry type.");
}
@@ -1277,6 +1284,8 @@ LinearDiscont3DFECollection::FiniteElementForGeometry(
switch (GeomType)
{
case Geometry::TETRAHEDRON: return &TetrahedronFE;
case Geometry::PYRAMID: return &PyramidFE;
case Geometry::PRISM: return &WedgeFE;
case Geometry::CUBE: return &ParallelepipedFE;
default:
mfem_error ("LinearDiscont3DFECollection: unknown geometry type.");
@@ -1293,6 +1302,8 @@ int LinearDiscont3DFECollection::DofForGeometry(Geometry::Type GeomType) const
case Geometry::TRIANGLE: return 0;
case Geometry::SQUARE: return 0;
case Geometry::TETRAHEDRON: return 4;
case Geometry::PYRAMID: return 5;
case Geometry::PRISM: return 6;
case Geometry::CUBE: return 8;
default:
mfem_error ("LinearDiscont3DFECollection: unknown geometry type.");
@@ -1394,6 +1405,8 @@ ND1_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
case Geometry::CUBE: return &HexahedronFE;
case Geometry::TETRAHEDRON: return &TetrahedronFE;
case Geometry::PRISM: return &WedgeFE;
case Geometry::PYRAMID: return &PyramidFE;
default:
mfem_error ("ND1_3DFECollection: unknown geometry type.");
}
@@ -1410,6 +1423,8 @@ int ND1_3DFECollection::DofForGeometry(Geometry::Type GeomType) const
case Geometry::SQUARE: return 0;
case Geometry::TETRAHEDRON: return 0;
case Geometry::CUBE: return 0;
case Geometry::PRISM: return 0;
case Geometry::PYRAMID: return 0;
default:
mfem_error ("ND1_3DFECollection: unknown geometry type.");
}
@@ -1439,6 +1454,8 @@ RT0_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
case Geometry::SQUARE: return &QuadrilateralFE;
case Geometry::CUBE: return &HexahedronFE;
case Geometry::TETRAHEDRON: return &TetrahedronFE;
case Geometry::PRISM: return &WedgeFE;
case Geometry::PYRAMID: return &PyramidFE;
default:
mfem_error ("RT0_3DFECollection: unknown geometry type.");
}
@@ -1455,6 +1472,8 @@ int RT0_3DFECollection::DofForGeometry(Geometry::Type GeomType) const
case Geometry::SQUARE: return 1;
case Geometry::TETRAHEDRON: return 0;
case Geometry::CUBE: return 0;
case Geometry::PRISM: return 0;
case Geometry::PYRAMID: return 0;
default:
mfem_error ("RT0_3DFECollection: unknown geometry type.");
}
@@ -1730,6 +1749,7 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
H1_dof[Geometry::TETRAHEDRON] = (TriDof*pm3)/3;
H1_dof[Geometry::CUBE] = QuadDof*pm1;
H1_dof[Geometry::PRISM] = TriDof*pm1;
H1_dof[Geometry::PYRAMID] = 0;
if (b_type == BasisType::Positive)
{
H1_Elements[Geometry::TETRAHEDRON] = new H1Pos_TetrahedronElement(p);
@@ -1743,6 +1763,7 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
H1_Elements[Geometry::CUBE] = new H1_HexahedronElement(p, btype);
H1_Elements[Geometry::PRISM] = new H1_WedgeElement(p, btype);
}
H1_Elements[Geometry::PYRAMID] = new LinearPyramidFiniteElement;
const int &TetDof = H1_dof[Geometry::TETRAHEDRON];
TetDofOrd[0] = new int[24*TetDof];
@@ -1837,6 +1858,21 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
}
}
const FiniteElement *
H1_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
if (GeomType != Geometry::PYRAMID || this->GetOrder() == 1)
{
return H1_Elements[GeomType];
}
else
{
MFEM_ABORT("H1 Pyramid basis functions are not yet supported "
"for order > 1.");
return NULL;
}
}
const int *H1_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
int Or) const
{
@@ -2076,9 +2112,12 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
L2_Elements[Geometry::CUBE] = new L2_HexahedronElement(p, btype);
L2_Elements[Geometry::PRISM] = new L2_WedgeElement(p, btype);
}
L2_Elements[Geometry::PYRAMID] = new P0PyrFiniteElement;
L2_Elements[Geometry::TETRAHEDRON]->SetMapType(map_type);
L2_Elements[Geometry::CUBE]->SetMapType(map_type);
L2_Elements[Geometry::PRISM]->SetMapType(map_type);
L2_Elements[Geometry::PYRAMID]->SetMapType(map_type);
// Trace element use the default Gauss-Legendre nodal points for positive basis
if (b_type == BasisType::Positive)
{
@@ -2199,6 +2238,21 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
}
}
const FiniteElement *
L2_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
if (GeomType != Geometry::PYRAMID || this->GetOrder() == 0)
{
return L2_Elements[GeomType];
}
else
{
MFEM_ABORT("L2 Pyramid basis functions are not yet supported "
"for order > 0.");
return NULL;
}
}
const int *L2_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
int Or) const
{
@@ -2290,6 +2344,12 @@ RT_FECollection::RT_FECollection(const int order, const int dim,
RT_Elements[Geometry::CUBE] = new RT_HexahedronElement(p, cb_type, ob_type);
RT_dof[Geometry::CUBE] = 3*p*pp1*pp1;
RT_Elements[Geometry::PRISM] = new RT0WdgFiniteElement;
RT_dof[Geometry::PRISM] = 0;
RT_Elements[Geometry::PYRAMID] = new RT0PyrFiniteElement(false);
RT_dof[Geometry::PYRAMID] = 0;
}
else
{
@@ -2433,6 +2493,22 @@ void RT_FECollection::InitFaces(const int p, const int dim,
}
}
const FiniteElement *
RT_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
if ((GeomType != Geometry::PRISM && GeomType != Geometry::PYRAMID) ||
this->GetOrder() == 1)
{
return RT_Elements[GeomType];
}
else
{
MFEM_ABORT("RT Wedge and Pyramid basis functions are not yet supported "
"for order > 0.");
return NULL;
}
}
const int *RT_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
int Or) const
{
@@ -2656,18 +2732,31 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
{
for (int i = 0; i + j <= pm2; i++)
{
int k1 = p*pm1 - (p - j)*(pm1 - j) + 2*i;
int k2 = p*pm1 - (p - i)*(pm1 - i) + 2*j;
// (0,1,2)
TriDofOrd[0][k1 ] = k1;
TriDofOrd[0][k1+1] = k1 + 1;
// (0,2,1)
TriDofOrd[5][k1 ] = k2 + 1;
TriDofOrd[5][k1+1] = k2;
int k0 = p*pm1 - (p - j)*(pm1 - j) + 2*i;
int k1 = 2*pm2 - 2*i + ((2*p-3)-j)*j;
int k2 = 2*pm2 - 2*j + ((2*p-3)-i)*i;
int k3 = p*pm1 - 2 - 3*j - i - (i+j)*(i+j);
int k4 = p*pm1 - 2 - 3*i - j - (i+j)*(i+j);
int k5 = p*pm1 - (p - i)*(pm1 - i) + 2*j;
// The other orientations can not be supported with the current
// interface. The method Mesh::ReorientTetMesh will ensure that
// only orientations 0 and 5 are generated.
// (0,1,2)
TriDofOrd[0][k0 ] = k0;
TriDofOrd[0][k0+1] = k0 + 1;
// (1,0,2)
TriDofOrd[1][k0 ] = k1;
TriDofOrd[1][k0+1] = k1 + 1;
// (2,0,1)
TriDofOrd[2][k0 ] = k2;
TriDofOrd[2][k0+1] = k2 + 1;
// (2,1,0)
TriDofOrd[3][k0 ] = k3;
TriDofOrd[3][k0+1] = k3 + 1;
// (1,2,0)
TriDofOrd[4][k0 ] = k4;
TriDofOrd[4][k0+1] = k4 + 1;
// (0,2,1)
TriDofOrd[5][k0 ] = k5;
TriDofOrd[5][k0+1] = k5 + 1;
}
}
}
@@ -2680,6 +2769,28 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
// TODO: cb_type and ob_type for tets
ND_Elements[Geometry::TETRAHEDRON] = new ND_TetrahedronElement(p);
ND_dof[Geometry::TETRAHEDRON] = p*pm1*pm2/2;
ND_Elements[Geometry::PRISM] = new Nedelec1WdgFiniteElement;
ND_dof[Geometry::PRISM] = 0;
ND_Elements[Geometry::PYRAMID] = new Nedelec1PyrFiniteElement;
ND_dof[Geometry::PYRAMID] = 0;
}
}
const FiniteElement *
ND_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
if ((GeomType != Geometry::PRISM && GeomType != Geometry::PYRAMID) ||
this->GetOrder() == 1)
{
return ND_Elements[GeomType];
}
else
{
MFEM_ABORT("ND Wedge and Pyramid basis functions are not yet supported "
"for order > 1.");
return NULL;
}
}
@@ -2692,11 +2803,6 @@ const int *ND_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
}
else if (GeomType == Geometry::TRIANGLE)
{
if (Or != 0 && Or != 5)
{
MFEM_ABORT("triangle face orientation " << Or << " is not supported! "
"Use Mesh::ReorientTetMesh to fix it.");
}
return TriDofOrd[Or%6];
}
else if (GeomType == Geometry::SQUARE)
+16 -14
View File
@@ -228,8 +228,7 @@ public:
const int btype = BasisType::GaussLobatto);
virtual const FiniteElement *FiniteElementForGeometry(
Geometry::Type GeomType) const
{ return H1_Elements[GeomType]; }
Geometry::Type GeomType) const;
virtual int DofForGeometry(Geometry::Type GeomType) const
{ return H1_dof[GeomType]; }
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
@@ -302,10 +301,7 @@ public:
const int map_type = FiniteElement::VALUE);
virtual const FiniteElement *FiniteElementForGeometry(
Geometry::Type GeomType) const
{
return L2_Elements[GeomType];
}
Geometry::Type GeomType) const;
virtual int DofForGeometry(Geometry::Type GeomType) const
{
if (L2_Elements[GeomType])
@@ -371,8 +367,7 @@ public:
const int ob_type = BasisType::GaussLegendre);
virtual const FiniteElement *FiniteElementForGeometry(
Geometry::Type GeomType) const
{ return RT_Elements[GeomType]; }
Geometry::Type GeomType) const;
virtual int DofForGeometry(Geometry::Type GeomType) const
{ return RT_dof[GeomType]; }
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
@@ -430,8 +425,7 @@ public:
const int ob_type = BasisType::GaussLegendre);
virtual const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const
{ return ND_Elements[GeomType]; }
FiniteElementForGeometry(Geometry::Type GeomType) const;
virtual int DofForGeometry(Geometry::Type GeomType) const
{ return ND_dof[GeomType]; }
@@ -529,9 +523,10 @@ private:
const BiLinear2DFiniteElement QuadrilateralFE;
const Linear3DFiniteElement TetrahedronFE;
const TriLinear3DFiniteElement ParallelepipedFE;
const H1_WedgeElement WedgeFE;
const LinearWedgeFiniteElement WedgeFE;
const LinearPyramidFiniteElement PyramidFE;
public:
LinearFECollection() : FiniteElementCollection(1), WedgeFE(1) { }
LinearFECollection() : FiniteElementCollection(1) { }
virtual const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const;
@@ -936,10 +931,11 @@ class Const3DFECollection : public FiniteElementCollection
private:
const P0TetFiniteElement TetrahedronFE;
const P0HexFiniteElement ParallelepipedFE;
const L2_WedgeElement WedgeFE;
const P0WdgFiniteElement WedgeFE;
const P0PyrFiniteElement PyramidFE;
public:
Const3DFECollection() : FiniteElementCollection(0), WedgeFE(0) { }
Const3DFECollection() : FiniteElementCollection(0) { }
virtual const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const;
@@ -960,6 +956,8 @@ class LinearDiscont3DFECollection : public FiniteElementCollection
{
private:
const Linear3DFiniteElement TetrahedronFE;
const LinearPyramidFiniteElement PyramidFE;
const LinearWedgeFiniteElement WedgeFE;
const TriLinear3DFiniteElement ParallelepipedFE;
public:
@@ -1036,6 +1034,8 @@ class ND1_3DFECollection : public FiniteElementCollection
private:
const Nedelec1HexFiniteElement HexahedronFE;
const Nedelec1TetFiniteElement TetrahedronFE;
const Nedelec1WdgFiniteElement WedgeFE;
const Nedelec1PyrFiniteElement PyramidFE;
public:
ND1_3DFECollection() : FiniteElementCollection(1) { }
@@ -1061,6 +1061,8 @@ private:
const P0QuadFiniteElement QuadrilateralFE;
const RT0HexFiniteElement HexahedronFE;
const RT0TetFiniteElement TetrahedronFE;
const RT0WdgFiniteElement WedgeFE;
const RT0PyrFiniteElement PyramidFE;
public:
RT0_3DFECollection() : FiniteElementCollection(1) { }
+2
View File
@@ -16,6 +16,7 @@
#include "geom.hpp"
#include "fe.hpp"
#include "fe_coll.hpp"
#include "doftrans.hpp"
#include "eltrans.hpp"
#include "coefficient.hpp"
#include "complex_fem.hpp"
@@ -34,6 +35,7 @@
#include "staticcond.hpp"
#include "tmop.hpp"
#include "tmop_tools.hpp"
#include "tmop_amr.hpp"
#include "gslib.hpp"
#include "restriction.hpp"
#include "quadinterpolator.hpp"
+323 -50
View File
@@ -58,9 +58,12 @@ DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim, Array<int> &dofs)
FiniteElementSpace::FiniteElementSpace()
: mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0), bdofs(NULL),
elem_dof(NULL), bdr_elem_dof(NULL), face_dof(NULL),
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
bdofs(NULL),
elem_dof(NULL), elem_fos(NULL), bdr_elem_dof(NULL), bdr_elem_fos(NULL),
face_dof(NULL),
NURBSext(NULL), own_ext(false),
DoFTrans(0), VDoFTrans(vdim, ordering),
cP(NULL), cR(NULL), cR_hp(NULL), cP_is_set(false),
Th(Operator::ANY_TYPE),
sequence(0), mesh_sequence(0), orders_changed(false), relaxed_hp(false)
@@ -69,6 +72,7 @@ FiniteElementSpace::FiniteElementSpace()
FiniteElementSpace::FiniteElementSpace(const FiniteElementSpace &orig,
Mesh *mesh,
const FiniteElementCollection *fec)
: VDoFTrans(orig.vdim, orig.ordering)
{
mesh = mesh ? mesh : orig.mesh;
fec = fec ? fec : orig.fec;
@@ -259,16 +263,36 @@ void FiniteElementSpace::AdjustVDofs (Array<int> &vdofs)
}
}
void FiniteElementSpace::GetElementVDofs(int i, Array<int> &vdofs) const
DofTransformation *
FiniteElementSpace::GetElementVDofs(int i, Array<int> &vdofs) const
{
GetElementDofs(i, vdofs);
DofTransformation * doftrans = GetElementDofs(i, vdofs);
DofsToVDofs(vdofs);
if (vdim == 1 || doftrans == NULL)
{
return doftrans;
}
else
{
VDoFTrans.SetDofTransformation(*doftrans);
return &VDoFTrans;
}
}
void FiniteElementSpace::GetBdrElementVDofs(int i, Array<int> &vdofs) const
DofTransformation *
FiniteElementSpace::GetBdrElementVDofs(int i, Array<int> &vdofs) const
{
GetBdrElementDofs(i, vdofs);
DofTransformation * doftrans = GetBdrElementDofs(i, vdofs);
DofsToVDofs(vdofs);
if (vdim == 1 || doftrans == NULL)
{
return doftrans;
}
else
{
VDoFTrans.SetDofTransformation(*doftrans);
return &VDoFTrans;
}
}
void FiniteElementSpace::GetFaceVDofs(int i, Array<int> &vdofs) const
@@ -307,21 +331,39 @@ void FiniteElementSpace::BuildElementToDofTable() const
// TODO: can we call GetElementDofs only once per element?
Table *el_dof = new Table;
Table *el_fos = (mesh->Dimension() > 2) ? (new Table) : NULL;
Array<int> dofs;
Array<int> F, Fo;
el_dof -> MakeI (mesh -> GetNE());
if (el_fos) { el_fos -> MakeI (mesh -> GetNE()); }
for (int i = 0; i < mesh -> GetNE(); i++)
{
GetElementDofs (i, dofs);
el_dof -> AddColumnsInRow (i, dofs.Size());
if (el_fos)
{
mesh->GetElementFaces(i, F, Fo);
el_fos -> AddColumnsInRow (i, Fo.Size());
}
}
el_dof -> MakeJ();
if (el_fos) { el_fos -> MakeJ(); }
for (int i = 0; i < mesh -> GetNE(); i++)
{
GetElementDofs (i, dofs);
el_dof -> AddConnections (i, (int *)dofs, dofs.Size());
if (el_fos)
{
mesh->GetElementFaces(i, F, Fo);
el_fos -> AddConnections (i, (int *)Fo, Fo.Size());
}
}
el_dof -> ShiftUpI();
if (el_fos) { el_fos -> ShiftUpI(); }
elem_dof = el_dof;
elem_fos = el_fos;
}
void FiniteElementSpace::BuildBdrElementToDofTable() const
@@ -375,7 +417,9 @@ void FiniteElementSpace::BuildFaceToDofTable() const
void FiniteElementSpace::RebuildElementToDofTable()
{
delete elem_dof;
delete elem_fos;
elem_dof = NULL;
elem_fos = NULL;
BuildElementToDofTable();
}
@@ -1315,8 +1359,10 @@ const FaceQuadratureInterpolator
SparseMatrix *FiniteElementSpace::RefinementMatrix_main(
const int coarse_ndofs, const Table &coarse_elem_dof,
const DenseTensor localP[]) const
const Table *coarse_elem_fos, const DenseTensor localP[]) const
{
/// TODO: Implement DofTransformation support
MFEM_VERIFY(mesh->GetLastOperation() == Mesh::REFINE, "");
Array<int> dofs, coarse_dofs, coarse_vdofs;
@@ -1399,7 +1445,8 @@ void FiniteElementSpace::GetLocalRefinementMatrices(
}
SparseMatrix* FiniteElementSpace::RefinementMatrix(int old_ndofs,
const Table* old_elem_dof)
const Table* old_elem_dof,
const Table* old_elem_fos)
{
MFEM_VERIFY(GetNE() >= old_elem_dof->Size(),
"Previous mesh is not coarser.");
@@ -1412,13 +1459,16 @@ SparseMatrix* FiniteElementSpace::RefinementMatrix(int old_ndofs,
GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
return RefinementMatrix_main(old_ndofs, *old_elem_dof, localP);
return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
localP);
}
FiniteElementSpace::RefinementOperator::RefinementOperator
(const FiniteElementSpace* fespace, Table* old_elem_dof, int old_ndofs)
(const FiniteElementSpace* fespace, Table* old_elem_dof, Table* old_elem_fos,
int old_ndofs)
: fespace(fespace)
, old_elem_dof(old_elem_dof)
, old_elem_fos(old_elem_fos)
{
MFEM_VERIFY(fespace->GetNE() >= old_elem_dof->Size(),
"Previous mesh is not coarser.");
@@ -1432,12 +1482,14 @@ FiniteElementSpace::RefinementOperator::RefinementOperator
{
fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
ConstructDoFTrans();
}
FiniteElementSpace::RefinementOperator::RefinementOperator(
const FiniteElementSpace *fespace, const FiniteElementSpace *coarse_fes)
: Operator(fespace->GetVSize(), coarse_fes->GetVSize()),
fespace(fespace), old_elem_dof(NULL)
fespace(fespace), old_elem_dof(NULL), old_elem_fos(NULL)
{
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
@@ -1449,11 +1501,50 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
// Make a copy of the coarse elem_dof Table.
old_elem_dof = new Table(coarse_fes->GetElementToDofTable());
// Make a copy of the coarse elem_fos Table if it exists.
if (coarse_fes->GetElementToFaceOrientationTable())
{
old_elem_fos = new Table(*coarse_fes->GetElementToFaceOrientationTable());
}
ConstructDoFTrans();
}
FiniteElementSpace::RefinementOperator::~RefinementOperator()
{
delete old_elem_dof;
delete old_elem_fos;
}
void FiniteElementSpace::RefinementOperator
::ConstructDoFTrans()
{
old_DoFTrans.SetSize(Geometry::NUM_GEOMETRIES);
for (int i=0; i<old_DoFTrans.Size(); i++)
{
old_DoFTrans[i] = NULL;
}
const FiniteElementCollection *fec = fespace->FEColl();
if (dynamic_cast<const ND_FECollection*>(fec))
{
const FiniteElement * nd_tri =
fec->FiniteElementForGeometry(Geometry::TRIANGLE);
if (nd_tri)
{
old_DoFTrans[Geometry::TRIANGLE] =
new ND_TriDofTransformation(nd_tri->GetOrder());
}
const FiniteElement * nd_tet =
fec->FiniteElementForGeometry(Geometry::TETRAHEDRON);
if (nd_tet)
{
old_DoFTrans[Geometry::TETRAHEDRON] =
new ND_TetDofTransformation(nd_tet->GetOrder());
}
}
}
void FiniteElementSpace::RefinementOperator
@@ -1462,7 +1553,7 @@ void FiniteElementSpace::RefinementOperator
Mesh* mesh = fespace->GetMesh();
const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
Array<int> dofs, vdofs, old_dofs, old_vdofs;
Array<int> dofs, vdofs, old_dofs, old_vdofs, old_Fo;
int vdim = fespace->GetVDim();
int old_ndofs = width / vdim;
@@ -1477,18 +1568,53 @@ void FiniteElementSpace::RefinementOperator
subY.SetSize(lP.Height());
fespace->GetElementDofs(k, dofs);
DofTransformation *doftrans = fespace->GetElementDofs(k, dofs);
old_elem_dof->GetRow(emb.parent, old_dofs);
for (int vd = 0; vd < vdim; vd++)
if (!doftrans)
{
dofs.Copy(vdofs);
fespace->DofsToVDofs(vd, vdofs);
old_dofs.Copy(old_vdofs);
fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
x.GetSubVector(old_vdofs, subX);
lP.Mult(subX, subY);
y.SetSubVector(vdofs, subY);
for (int vd = 0; vd < vdim; vd++)
{
dofs.Copy(vdofs);
fespace->DofsToVDofs(vd, vdofs);
old_dofs.Copy(old_vdofs);
fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
x.GetSubVector(old_vdofs, subX);
lP.Mult(subX, subY);
y.SetSubVector(vdofs, subY);
}
}
else
{
old_elem_fos->GetRow(emb.parent, old_Fo);
old_DoFTrans[geom]->SetFaceOrientations(old_Fo);
DofTransformation *new_doftrans = NULL;
VDofTransformation *vdoftrans =
dynamic_cast<VDofTransformation*>(doftrans);
if (vdoftrans)
{
new_doftrans = doftrans;
doftrans = vdoftrans->GetDofTransformation();
}
for (int vd = 0; vd < vdim; vd++)
{
dofs.Copy(vdofs);
fespace->DofsToVDofs(vd, vdofs);
old_dofs.Copy(old_vdofs);
fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
x.GetSubVector(old_vdofs, subX);
old_DoFTrans[geom]->InvTransformPrimal(subX);
lP.Mult(subX, subY);
doftrans->TransformPrimal(subY);
y.SetSubVector(vdofs, subY);
}
if (vdoftrans)
{
doftrans = new_doftrans;
}
}
}
}
@@ -1504,12 +1630,12 @@ void FiniteElementSpace::RefinementOperator
Array<char> processed(fespace->GetVSize());
processed = 0;
Array<int> f_dofs, c_dofs, f_vdofs, c_vdofs;
Array<int> f_dofs, c_dofs, f_vdofs, c_vdofs, old_Fo;
int vdim = fespace->GetVDim();
int old_ndofs = width / vdim;
Vector subY, subX;
Vector subY, subX, subYt, subXt;
for (int k = 0; k < mesh->GetNE(); k++)
{
@@ -1517,30 +1643,77 @@ void FiniteElementSpace::RefinementOperator
const Geometry::Type geom = mesh->GetElementBaseGeometry(k);
const DenseMatrix &lP = localP[geom](emb.matrix);
fespace->GetElementDofs(k, f_dofs);
DofTransformation * doftrans = fespace->GetElementDofs(k, f_dofs);
old_elem_dof->GetRow(emb.parent, c_dofs);
subY.SetSize(lP.Width());
for (int vd = 0; vd < vdim; vd++)
if (!doftrans)
{
f_dofs.Copy(f_vdofs);
fespace->DofsToVDofs(vd, f_vdofs);
c_dofs.Copy(c_vdofs);
fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
subY.SetSize(lP.Width());
x.GetSubVector(f_vdofs, subX);
for (int p = 0; p < f_dofs.Size(); ++p)
for (int vd = 0; vd < vdim; vd++)
{
if (processed[DecodeDof(f_dofs[p])])
f_dofs.Copy(f_vdofs);
fespace->DofsToVDofs(vd, f_vdofs);
c_dofs.Copy(c_vdofs);
fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
x.GetSubVector(f_vdofs, subX);
for (int p = 0; p < f_dofs.Size(); ++p)
{
subX[p] = 0.0;
if (processed[DecodeDof(f_dofs[p])])
{
subX[p] = 0.0;
}
}
lP.MultTranspose(subX, subY);
y.AddElementVector(c_vdofs, subY);
}
}
else
{
subYt.SetSize(lP.Width());
old_elem_fos->GetRow(emb.parent, old_Fo);
old_DoFTrans[geom]->SetFaceOrientations(old_Fo);
DofTransformation *new_doftrans = NULL;
VDofTransformation *vdoftrans =
dynamic_cast<VDofTransformation*>(doftrans);
if (vdoftrans)
{
new_doftrans = doftrans;
doftrans = vdoftrans->GetDofTransformation();
}
lP.MultTranspose(subX, subY);
y.AddElementVector(c_vdofs, subY);
for (int vd = 0; vd < vdim; vd++)
{
f_dofs.Copy(f_vdofs);
fespace->DofsToVDofs(vd, f_vdofs);
c_dofs.Copy(c_vdofs);
fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
x.GetSubVector(f_vdofs, subX);
old_DoFTrans[geom]->InvTransformPrimal(subX);
for (int p = 0; p < f_dofs.Size(); ++p)
{
if (processed[DecodeDof(f_dofs[p])])
{
subX[p] = 0.0;
}
}
lP.MultTranspose(subX, subY);
doftrans->TransformPrimal(subY);
y.AddElementVector(c_vdofs, subY);
}
if (vdoftrans)
{
doftrans = new_doftrans;
}
}
for (int p = 0; p < f_dofs.Size(); ++p)
@@ -1550,6 +1723,7 @@ void FiniteElementSpace::RefinementOperator
}
}
/// TODO: Implement DofTransformation support
FiniteElementSpace::DerefinementOperator::DerefinementOperator(
const FiniteElementSpace *f_fes, const FiniteElementSpace *c_fes,
BilinearFormIntegrator *mass_integ)
@@ -1707,8 +1881,11 @@ void FiniteElementSpace::GetLocalDerefinementMatrices(Geometry::Type geom,
}
SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
const Table* old_elem_dof)
const Table* old_elem_dof,
const Table* old_elem_fos)
{
/// TODO: Implement DofTransformation support
MFEM_VERIFY(Nonconforming(), "Not implemented for conforming meshes.");
MFEM_VERIFY(old_ndofs, "Missing previous (finer) space.");
MFEM_VERIFY(ndofs <= old_ndofs, "Previous space is not finer.");
@@ -1814,6 +1991,7 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext,
this->ordering = (Ordering::Type) ordering;
elem_dof = NULL;
elem_fos = NULL;
face_dof = NULL;
sequence = 0;
@@ -1841,6 +2019,8 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext,
UpdateNURBS();
cP = cR = cR_hp = NULL;
cP_is_set = false;
ConstructDoFTrans();
}
else
{
@@ -1848,9 +2028,41 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext,
own_ext = 0;
Construct();
}
BuildElementToDofTable();
}
void FiniteElementSpace::ConstructDoFTrans()
{
DestroyDoFTrans();
VDoFTrans.SetVDim(vdim);
DoFTrans.SetSize(Geometry::NUM_GEOMETRIES);
for (int i=0; i<DoFTrans.Size(); i++)
{
DoFTrans[i] = NULL;
}
if (mesh->Dimension() < 3) { return; }
if (dynamic_cast<const ND_FECollection*>(fec))
{
const FiniteElement * nd_tri =
fec->FiniteElementForGeometry(Geometry::TRIANGLE);
if (nd_tri)
{
DoFTrans[Geometry::TRIANGLE] =
new ND_TriDofTransformation(nd_tri->GetOrder());
}
const FiniteElement * nd_tet =
fec->FiniteElementForGeometry(Geometry::TETRAHEDRON);
if (nd_tet)
{
DoFTrans[Geometry::TETRAHEDRON] =
new ND_TetDofTransformation(nd_tet->GetOrder());
}
}
}
NURBSExtension *FiniteElementSpace::StealNURBSext()
{
if (NURBSext && !own_ext)
@@ -1946,7 +2158,9 @@ void FiniteElementSpace::Construct()
"Variable order space requires a nonconforming mesh.");
elem_dof = NULL;
elem_fos = NULL;
bdr_elem_dof = NULL;
bdr_elem_fos = NULL;
face_dof = NULL;
ndofs = 0;
@@ -2044,6 +2258,8 @@ void FiniteElementSpace::Construct()
ndofs = nvdofs + nedofs + nfdofs + nbdofs;
ConstructDoFTrans();
// record the current mesh sequence number to detect refinement etc.
mesh_sequence = mesh->GetSequence();
@@ -2295,14 +2511,22 @@ int FiniteElementSpace::GetNVariants(int entity, int index) const
static const char* msg_orders_changed =
"Element orders changed, you need to Update() the space first.";
void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs) const
DofTransformation *
FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs) const
{
MFEM_VERIFY(!orders_changed, msg_orders_changed);
if (elem_dof)
{
elem_dof->GetRow(elem, dofs);
return;
if (DoFTrans[mesh->GetElementBaseGeometry(elem)])
{
Array<int> Fo;
elem_fos -> GetRow (elem, Fo);
DoFTrans[mesh->GetElementBaseGeometry(elem)]->SetFaceOrientations(Fo);
}
return DoFTrans[mesh->GetElementBaseGeometry(elem)];
}
Array<int> V, E, Eo, F, Fo; // TODO: LocalArray
@@ -2326,6 +2550,11 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs) const
{
nfd += fec->GetNumDof(mesh->GetFaceGeometry(F[i]), order);
}
if (DoFTrans[mesh->GetElementBaseGeometry(elem)])
{
DoFTrans[mesh->GetElementBaseGeometry(elem)]
-> SetFaceOrientations(Fo);
}
}
dofs.SetSize(0);
@@ -2383,6 +2612,7 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs) const
dofs.Append(bbase + j);
}
}
return DoFTrans[mesh->GetElementBaseGeometry(elem)];
}
const FiniteElement *FiniteElementSpace::GetFE(int i) const
@@ -2415,18 +2645,27 @@ const FiniteElement *FiniteElementSpace::GetFE(int i) const
return FE;
}
void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs) const
DofTransformation *
FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs) const
{
MFEM_VERIFY(!orders_changed, msg_orders_changed);
if (bdr_elem_dof)
{
bdr_elem_dof->GetRow(bel, dofs);
return;
if (DoFTrans[mesh->GetBdrElementBaseGeometry(bel)])
{
Array<int> Fo;
bdr_elem_fos -> GetRow (bel, Fo);
DoFTrans[mesh->GetBdrElementBaseGeometry(bel)]->
SetFaceOrientations(Fo);
}
return DoFTrans[mesh->GetBdrElementBaseGeometry(bel)];
}
Array<int> V, E, Eo; // TODO: LocalArray
int F, Fo;
Array<int> V, E, Eo, Fo; // TODO: LocalArray
int F, oF;
int dim = mesh->Dimension();
auto geom = mesh->GetBdrElementGeometry(bel);
@@ -2445,7 +2684,17 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs) const
if (nv) { mesh->GetBdrElementVertices(bel, V); }
if (ne) { mesh->GetBdrElementEdges(bel, E, Eo); }
if (nf) { mesh->GetBdrElementFace(bel, &F, &Fo); }
if (nf)
{
mesh->GetBdrElementFace(bel, &F, &oF);
if (DoFTrans[mesh->GetBdrElementBaseGeometry(bel)])
{
Fo.Append(oF);
DoFTrans[mesh->GetBdrElementBaseGeometry(bel)]->
SetFaceOrientations(Fo);
}
}
dofs.SetSize(0);
dofs.Reserve(nv*V.Size() + ne*E.Size() + nf);
@@ -2478,13 +2727,15 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs) const
if (nf) // face DOFs
{
int fbase = (var_face_dofs.Size() > 0) ? FindFaceDof(F, nf) : F*nf;
const int *ind = fec->GetDofOrdering(geom, order, Fo);
const int *ind = fec->GetDofOrdering(geom, order, oF);
for (int j = 0; j < nf; j++)
{
dofs.Append(EncodeDof(nvdofs + nedofs + fbase, ind[j]));
}
}
return DoFTrans[mesh->GetBdrElementBaseGeometry(bel)];
}
int FiniteElementSpace::GetFaceDofs(int face, Array<int> &dofs,
@@ -2794,6 +3045,8 @@ void FiniteElementSpace::Destroy()
}
E2BFQ_array.SetSize(0);
DestroyDoFTrans();
dof_elem_array.DeleteAll();
dof_ldof_array.DeleteAll();
@@ -2806,7 +3059,9 @@ void FiniteElementSpace::Destroy()
else
{
delete elem_dof;
delete elem_fos;
delete bdr_elem_dof;
delete bdr_elem_fos;
delete face_dof;
delete [] bdofs;
@@ -2814,6 +3069,15 @@ void FiniteElementSpace::Destroy()
ceed::RemoveBasisAndRestriction(this);
}
void FiniteElementSpace::DestroyDoFTrans()
{
for (int i = 0; i < DoFTrans.Size(); i++)
{
delete DoFTrans[i];
}
DoFTrans.SetSize(0);
}
void FiniteElementSpace::GetTransferOperator(
const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
{
@@ -2831,6 +3095,8 @@ void FiniteElementSpace::GetTransferOperator(
}
T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
coarse_fes.GetElementToDofTable(),
coarse_fes.
GetElementToFaceOrientationTable(),
localP));
}
else
@@ -2933,6 +3199,7 @@ void FiniteElementSpace::Update(bool want_transform)
}
Table* old_elem_dof = NULL;
Table* old_elem_fos = NULL;
int old_ndofs;
bool old_orders_changed = orders_changed;
@@ -2940,7 +3207,9 @@ void FiniteElementSpace::Update(bool want_transform)
if (want_transform)
{
old_elem_dof = elem_dof;
old_elem_fos = elem_fos;
elem_dof = NULL;
elem_fos = NULL;
old_ndofs = ndofs;
}
@@ -2966,15 +3235,18 @@ void FiniteElementSpace::Update(bool want_transform)
{
if (Th.Type() != Operator::MFEM_SPARSEMAT)
{
Th.Reset(new RefinementOperator(this, old_elem_dof, old_ndofs));
Th.Reset(new RefinementOperator(this, old_elem_dof,
old_elem_fos, old_ndofs));
// The RefinementOperator takes ownership of 'old_elem_dof', so
// we no longer own it:
old_elem_dof = NULL;
old_elem_fos = NULL;
}
else
{
// calculate fully assembled matrix
Th.Reset(RefinementMatrix(old_ndofs, old_elem_dof));
Th.Reset(RefinementMatrix(old_ndofs, old_elem_dof,
old_elem_fos));
}
break;
}
@@ -2982,7 +3254,7 @@ void FiniteElementSpace::Update(bool want_transform)
case Mesh::DEREFINE:
{
BuildConformingInterpolation();
Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof));
Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
if (cP && cR)
{
Th.SetOperatorOwner(false);
@@ -2997,6 +3269,7 @@ void FiniteElementSpace::Update(bool want_transform)
}
delete old_elem_dof;
delete old_elem_fos;
}
}
+30 -7
View File
@@ -16,6 +16,7 @@
#include "../linalg/sparsemat.hpp"
#include "../mesh/mesh.hpp"
#include "fe_coll.hpp"
#include "doftrans.hpp"
#include "restriction.hpp"
#include <iostream>
#include <unordered_map>
@@ -128,7 +129,9 @@ protected:
// precalculated DOFs for each element, boundary element, and face
mutable Table *elem_dof; // owned (except in NURBS FE space)
mutable Table *elem_fos; // face orientations by element index
mutable Table *bdr_elem_dof; // owned (except in NURBS FE space)
mutable Table *bdr_elem_fos; // bdr face orientations by bdr element index
mutable Table *face_dof; // owned; in var-order space contains variant 0 DOFs
Array<int> dof_elem_array, dof_ldof_array;
@@ -137,6 +140,9 @@ protected:
int own_ext;
mutable Array<int> face_to_be; // NURBS FE space only
Array<DofTransformation*> DoFTrans;
mutable VDofTransformation VDoFTrans;
/** Matrix representing the prolongation from the global conforming dofs to
a set of intermediate partially conforming dofs, e.g. the dofs associated
with a "cut" space on a non-conforming mesh. */
@@ -189,6 +195,9 @@ protected:
void Construct();
void Destroy();
void ConstructDoFTrans();
void DestroyDoFTrans();
void BuildElementToDofTable() const;
void BuildBdrElementToDofTable() const;
void BuildFaceToDofTable() const;
@@ -283,12 +292,19 @@ protected:
const FiniteElementSpace* fespace;
DenseTensor localP[Geometry::NumGeom];
Table* old_elem_dof; // Owned.
Table* old_elem_fos; // Owned.
Array<DofTransformation*> old_DoFTrans;
mutable VDofTransformation old_VDoFTrans;
void ConstructDoFTrans();
public:
/** Construct the operator based on the elem_dof table of the original
(coarse) space. The class takes ownership of the table. */
RefinementOperator(const FiniteElementSpace* fespace,
Table *old_elem_dof/*takes ownership*/, int old_ndofs);
Table *old_elem_dof/*takes ownership*/,
Table *old_elem_fos/*takes ownership*/, int old_ndofs);
RefinementOperator(const FiniteElementSpace *fespace,
const FiniteElementSpace *coarse_fes);
virtual void Mult(const Vector &x, Vector &y) const;
@@ -302,6 +318,7 @@ protected:
const FiniteElementSpace *fine_fes; // Not owned.
DenseTensor localR[Geometry::NumGeom];
Table *coarse_elem_dof; // Owned.
// Table *coarse_elem_fos; // Owned.
Table coarse_to_fine;
Array<int> coarse_to_ref_type;
Array<Geometry::Type> ref_type_to_geom;
@@ -323,6 +340,7 @@ protected:
the same vector dimension, vdim. */
SparseMatrix *RefinementMatrix_main(const int coarse_ndofs,
const Table &coarse_elem_dof,
const Table *coarse_elem_fos,
const DenseTensor localP[]) const;
void GetLocalRefinementMatrices(Geometry::Type geom,
@@ -333,10 +351,12 @@ protected:
/** Calculate explicit GridFunction interpolation matrix (after mesh
refinement). NOTE: consider using the RefinementOperator class instead
of the fully assembled matrix, which can take a lot of memory. */
SparseMatrix* RefinementMatrix(int old_ndofs, const Table* old_elem_dof);
SparseMatrix* RefinementMatrix(int old_ndofs, const Table* old_elem_dof,
const Table* old_elem_fos);
/// Calculate GridFunction restriction matrix after mesh derefinement.
SparseMatrix* DerefinementMatrix(int old_ndofs, const Table* old_elem_dof);
SparseMatrix* DerefinementMatrix(int old_ndofs, const Table* old_elem_dof,
const Table* old_elem_fos);
/** @brief Return in @a localP the local refinement matrices that map
between fespaces after mesh refinement. */
@@ -614,10 +634,11 @@ public:
int GetBdrAttribute(int i) const { return mesh->GetBdrAttribute(i); }
/// Returns indices of degrees of freedom of element 'elem'.
virtual void GetElementDofs(int elem, Array<int> &dofs) const;
virtual DofTransformation *GetElementDofs(int elem, Array<int> &dofs) const;
/// Returns indices of degrees of freedom for boundary element 'bel'.
virtual void GetBdrElementDofs(int bel, Array<int> &dofs) const;
virtual DofTransformation *GetBdrElementDofs(int bel,
Array<int> &dofs) const;
/** @brief Returns the indices of the degrees of freedom for the specified
face, including the DOFs for the edges and the vertices of the face. */
@@ -666,10 +687,10 @@ public:
static void AdjustVDofs(Array<int> &vdofs);
/// Returns indexes of degrees of freedom in array dofs for i'th element.
void GetElementVDofs(int i, Array<int> &vdofs) const;
DofTransformation *GetElementVDofs(int i, Array<int> &vdofs) const;
/// Returns indexes of degrees of freedom for i'th boundary element.
void GetBdrElementVDofs(int i, Array<int> &vdofs) const;
DofTransformation *GetBdrElementVDofs(int i, Array<int> &vdofs) const;
/// Returns indexes of degrees of freedom for i'th face element (2D and 3D).
void GetFaceVDofs(int i, Array<int> &vdofs) const;
@@ -695,6 +716,8 @@ public:
is preserved. */
void ReorderElementToDofTable();
const Table *GetElementToFaceOrientationTable() const { return elem_fos; }
/** @brief Return a reference to the internal Table that stores the lists of
scalar dofs, for each mesh element, as returned by GetElementDofs(). */
const Table &GetElementToDofTable() const { return *elem_dof; }
+262 -7
View File
@@ -11,15 +11,19 @@
#include "fem.hpp"
#include "../mesh/wedge.hpp"
#include "../mesh/pyramid.hpp"
namespace mfem
{
const char *Geometry::Name[NumGeom] =
{ "Point", "Segment", "Triangle", "Square", "Tetrahedron", "Cube", "Prism" };
{
"Point", "Segment", "Triangle", "Square", "Tetrahedron", "Cube", "Prism",
"Pyramid"
};
const double Geometry::Volume[NumGeom] =
{ 1.0, 1.0, 0.5, 1.0, 1./6, 1.0, 0.5 };
{ 1.0, 1.0, 0.5, 1.0, 1./6, 1.0, 0.5, 1./3 };
Geometry::Geometry()
{
@@ -139,6 +143,28 @@ Geometry::Geometry()
GeomVert[6]->IntPoint(5).y = 1.0;
GeomVert[6]->IntPoint(5).z = 1.0;
// Vertices for Geometry::PYRAMID
GeomVert[7] = new IntegrationRule(5);
GeomVert[7]->IntPoint(0).x = 0.0;
GeomVert[7]->IntPoint(0).y = 0.0;
GeomVert[7]->IntPoint(0).z = 0.0;
GeomVert[7]->IntPoint(1).x = 1.0;
GeomVert[7]->IntPoint(1).y = 0.0;
GeomVert[7]->IntPoint(1).z = 0.0;
GeomVert[7]->IntPoint(2).x = 1.0;
GeomVert[7]->IntPoint(2).y = 1.0;
GeomVert[7]->IntPoint(2).z = 0.0;
GeomVert[7]->IntPoint(3).x = 0.0;
GeomVert[7]->IntPoint(3).y = 1.0;
GeomVert[7]->IntPoint(3).z = 0.0;
GeomVert[7]->IntPoint(4).x = 0.0;
GeomVert[7]->IntPoint(4).y = 0.0;
GeomVert[7]->IntPoint(4).z = 1.0;
GeomCenter[POINT].x = 0.0;
GeomCenter[POINT].y = 0.0;
GeomCenter[POINT].z = 0.0;
@@ -167,6 +193,10 @@ Geometry::Geometry()
GeomCenter[PRISM].y = 1.0 / 3.0;
GeomCenter[PRISM].z = 0.5;
GeomCenter[PYRAMID].x = 0.375;
GeomCenter[PYRAMID].y = 0.375;
GeomCenter[PYRAMID].z = 0.25;
GeomToPerfGeomJac[POINT] = NULL;
GeomToPerfGeomJac[SEGMENT] = new DenseMatrix(1);
GeomToPerfGeomJac[TRIANGLE] = new DenseMatrix(2);
@@ -174,6 +204,7 @@ Geometry::Geometry()
GeomToPerfGeomJac[TETRAHEDRON] = new DenseMatrix(3);
GeomToPerfGeomJac[CUBE] = new DenseMatrix(3);
GeomToPerfGeomJac[PRISM] = new DenseMatrix(3);
GeomToPerfGeomJac[PYRAMID] = new DenseMatrix(3);
PerfGeomToGeomJac[POINT] = NULL;
PerfGeomToGeomJac[SEGMENT] = NULL;
@@ -182,6 +213,7 @@ Geometry::Geometry()
PerfGeomToGeomJac[TETRAHEDRON] = new DenseMatrix(3);
PerfGeomToGeomJac[CUBE] = NULL;
PerfGeomToGeomJac[PRISM] = new DenseMatrix(3);
PerfGeomToGeomJac[PYRAMID] = new DenseMatrix(3);
GeomToPerfGeomJac[SEGMENT]->Diag(1.0, 1);
{
@@ -210,6 +242,14 @@ Geometry::Geometry()
*GeomToPerfGeomJac[PRISM] = pri_T.Jacobian();
CalcInverse(pri_T.Jacobian(), *PerfGeomToGeomJac[PRISM]);
}
{
IsoparametricTransformation pyr_T;
pyr_T.SetFE(&PyramidFE);
GetPerfPointMat (PYRAMID, pyr_T.GetPointMat());
pyr_T.SetIntPoint(&GeomCenter[PYRAMID]);
*GeomToPerfGeomJac[PYRAMID] = pyr_T.Jacobian();
CalcInverse(pyr_T.Jacobian(), *PerfGeomToGeomJac[PYRAMID]);
}
}
Geometry::~Geometry()
@@ -233,6 +273,7 @@ const IntegrationRule * Geometry::GetVertices(int GeomType)
case Geometry::TETRAHEDRON: return GeomVert[4];
case Geometry::CUBE: return GeomVert[5];
case Geometry::PRISM: return GeomVert[6];
case Geometry::PYRAMID: return GeomVert[7];
default:
mfem_error ("Geometry::GetVertices(...)");
}
@@ -310,6 +351,25 @@ void Geometry::GetRandomPoint(int GeomType, IntegrationPoint &ip)
ip.y = 1.0 - ip.y;
}
break;
case Geometry::PYRAMID:
ip.x = double(rand()) / RAND_MAX;
ip.y = double(rand()) / RAND_MAX;
ip.z = double(rand()) / RAND_MAX;
if (ip.x + ip.z > 1.0 && ip.y < ip.x)
{
double x = ip.x;
ip.x = ip.y;
ip.y = 1.0 - ip.z;
ip.z = 1.0 - x;
}
else if (ip.y + ip.z > 1.0)
{
double z = ip.z;
ip.z = 1.0 - ip.y;
ip.y = ip.x;
ip.x = 1.0 - z;
}
break;
default:
MFEM_ABORT("Unknown type of reference element!");
}
@@ -371,6 +431,10 @@ bool Geometry::CheckPoint(int GeomType, const IntegrationPoint &ip)
if (ip.x < 0.0 || ip.y < 0.0 || ip.x+ip.y > 1.0 ||
ip.z < 0.0 || ip.z > 1.0) { return false; }
break;
case Geometry::PYRAMID:
if (ip.x < 0.0 || ip.y < 0.0 || ip.x+ip.z > 1.0 || ip.y+ip.z > 1.0 ||
ip.z < 0.0 || ip.z > 1.0) { return false; }
break;
default:
MFEM_ABORT("Unknown type of reference element!");
}
@@ -441,6 +505,17 @@ bool Geometry::CheckPoint(int GeomType, const IntegrationPoint &ip, double eps)
return false;
}
break;
case Geometry::PYRAMID:
if (internal::FuzzyLT(ip.x, 0.0, eps)
|| internal::FuzzyLT(ip.y, 0.0, eps)
|| internal::FuzzyGT(ip.x+ip.z, 1.0, eps)
|| internal::FuzzyGT(ip.y+ip.z, 1.0, eps)
|| internal::FuzzyLT(ip.z, 0.0, eps)
|| internal::FuzzyGT(ip.z, 1.0, eps) )
{
return false;
}
break;
default:
MFEM_ABORT("Unknown type of reference element!");
}
@@ -555,6 +630,16 @@ bool Geometry::ProjectPoint(int GeomType, const IntegrationPoint &beg,
double lbeg[5] = { beg.x, beg.y, beg.z, 1.0-beg.x-beg.y, 1.0-beg.z };
return internal::IntersectSegment<5,3>(lbeg, lend, end);
}
case Geometry::PYRAMID:
{
double lend[6] = { end.x, end.y, end.z,
1.0-end.x-end.z, 1.0-end.y-end.z, 1.0-end.z
};
double lbeg[6] = { beg.x, beg.y, beg.z,
1.0-beg.x-beg.z, 1.0-beg.y-beg.z, 1.0-beg.z
};
return internal::IntersectSegment<6,3>(lbeg, lend, end);
}
default:
MFEM_ABORT("Unknown type of reference element!");
}
@@ -652,6 +737,43 @@ bool Geometry::ProjectPoint(int GeomType, IntegrationPoint &ip)
return in_tri && in_z;
}
case PYRAMID:
{
if (ip.x < 0.0)
{
ip.x = 0.0;
internal::ProjectTriangle(ip.y, ip.z);
return false;
}
if (ip.y < 0.0)
{
ip.y = 0.0;
internal::ProjectTriangle(ip.x, ip.z);
return false;
}
if (ip.z < 0.0)
{
ip.z = 0.0;
if (ip.x > 1.0) { ip.x = 1.0; }
if (ip.y > 1.0) { ip.y = 1.0; }
return false;
}
if (ip.x >= ip.y)
{
bool in_y = true;
bool in_tri = internal::ProjectTriangle(ip.x, ip.z);
if (ip.y > ip.z) { in_y = false; ip.y = ip.z; }
return in_tri && in_y;
}
else
{
bool in_x = true;
bool in_tri = internal::ProjectTriangle(ip.y, ip.z);
if (ip.x > ip.z) { in_x = false; ip.x = ip.z; }
return in_tri && in_x;
}
}
default:
MFEM_ABORT("Reference element type is not supported!");
}
@@ -726,6 +848,17 @@ void Geometry::GetPerfPointMat(int GeomType, DenseMatrix &pm)
}
break;
case Geometry::PYRAMID:
{
pm.SetSize (3, 5);
pm(0,0) = 0.0; pm(1,0) = 0.0; pm(2,0) = 0.0;
pm(0,1) = 1.0; pm(1,1) = 0.0; pm(2,1) = 0.0;
pm(0,2) = 1.0; pm(1,2) = 1.0; pm(2,2) = 0.0;
pm(0,3) = 0.0; pm(1,3) = 1.0; pm(2,3) = 0.0;
pm(0,4) = 0.5; pm(1,4) = 0.5; pm(2,4) = 0.7071067811865475;
}
break;
default:
mfem_error ("Geometry::GetPerfPointMat (...)");
}
@@ -744,13 +877,13 @@ void Geometry::JacToPerfJac(int GeomType, const DenseMatrix &J,
}
}
const int Geometry::NumBdrArray[NumGeom] = { 0, 2, 3, 4, 4, 6, 5 };
const int Geometry::Dimension[NumGeom] = { 0, 1, 2, 2, 3, 3, 3 };
const int Geometry::NumBdrArray[NumGeom] = { 0, 2, 3, 4, 4, 6, 5, 5 };
const int Geometry::Dimension[NumGeom] = { 0, 1, 2, 2, 3, 3, 3, 3 };
const int Geometry::DimStart[MaxDim+2] =
{ POINT, SEGMENT, TRIANGLE, TETRAHEDRON, NUM_GEOMETRIES };
const int Geometry::NumVerts[NumGeom] = { 1, 2, 3, 4, 4, 8, 6 };
const int Geometry::NumEdges[NumGeom] = { 0, 1, 3, 4, 6, 12, 9 };
const int Geometry::NumFaces[NumGeom] = { 0, 0, 1, 1, 4, 6, 5 };
const int Geometry::NumVerts[NumGeom] = { 1, 2, 3, 4, 4, 8, 6, 5 };
const int Geometry::NumEdges[NumGeom] = { 0, 1, 3, 4, 6, 12, 9, 8 };
const int Geometry::NumFaces[NumGeom] = { 0, 0, 1, 1, 4, 6, 5, 5 };
const int Geometry::
Constants<Geometry::POINT>::Orient[1][1] = {{0}};
@@ -897,6 +1030,30 @@ Constants<Geometry::PRISM>::VertToVert::J[9][2] =
{5, 4} // 4,5:4
};
const int Geometry::
Constants<Geometry::PYRAMID>::Edges[8][2] =
{{0, 1}, {1, 2}, {3, 2}, {0, 3}, {0, 4}, {1, 4}, {2, 4}, {3, 4}};
const int Geometry::
Constants<Geometry::PYRAMID>::FaceTypes[5] =
{
Geometry::SQUARE,
Geometry::TRIANGLE, Geometry::TRIANGLE,
Geometry::TRIANGLE, Geometry::TRIANGLE
};
const int Geometry::
Constants<Geometry::PYRAMID>::FaceVert[5][4] =
{{3, 2, 1, 0}, {0, 1, 4, -1}, {1, 2, 4, -1}, {2, 3, 4, -1}, {3, 0, 4, -1}};
const int Geometry::
Constants<Geometry::PYRAMID>::VertToVert::I[5] = {0, 3, 5, 7, 8};
const int Geometry::
Constants<Geometry::PYRAMID>::VertToVert::J[8][2] =
{
{1, 0}, {3, 3}, {4, 4}, // 0,1:0 0,3:3 0,4:4
{2, 1}, {4, 5}, // 1,2:1 1,4:5
{3,-3}, {4, 6}, // 2,3:-3 2,4:6
{4, 7} // 3,4:7
};
GeometryRefiner::GeometryRefiner()
{
@@ -1262,6 +1419,104 @@ RefinedGeometry * GeometryRefiner::Refine(Geometry::Type Geom,
return RG;
}
case Geometry::PYRAMID:
{
const int n = Times;
RG = new RefinedGeometry ((n+1)*(n+2)*(2*n+3)/6,
5*n*(2*n-1)*(2*n+1)/3, 0);
RG->Times = Times;
RG->ETimes = ETimes;
RG->Type = type;
// enumerate and define the vertices
m = 0;
for (k = 0; k <= n; k++)
{
const double *cpij =
poly1d.GetPoints(Times - k, BasisType::GetNodalBasis(type));
for (j = 0; j <= n - k; j++)
for (i = 0; i <= n - k; i++)
{
IntegrationPoint &ip = RG->RefPts.IntPoint(m);
if (type == 0)
{
ip.x = (n > k) ? (double(i) / (n - k)) : 0.0;
ip.y = (n > k) ? (double(j) / (n - k)) : 0.0;
ip.z = double(k) / n;
}
else
{
ip.x = cpij[i] * (1.0 - cp[k]);
ip.y = cpij[j] * (1.0 - cp[k]);
ip.z = cp[k];
}
m++;
}
}
if (m != (n+1)*(n+2)*(2*n+3)/6)
{
mfem_error("GeometryRefiner::Refine() for PYRAMID #1");
}
// elements
Array<int> &G = RG->RefGeoms;
m = 0;
for (k = 0; k < n; k++)
{
int lk = k * (k * (2 * k - 6 * n - 9) + 6 * n * (n + 3) + 13) / 6;
int lkp1 = (k + 1) *
(k * (2 * k - 6 * n -5) + 6 * n * (n + 2) + 6) / 6;
for (j = 0; j < n - k; j++)
{
for (i = 0; i < n - k; i++)
{
G[m++] = lk + j * (n - k + 1) + i;
G[m++] = lk + j * (n - k + 1) + i + 1;
G[m++] = lk + (j + 1) * (n - k + 1) + i + 1;
G[m++] = lk + (j + 1) * (n - k + 1) + i;
G[m++] = lkp1 + j * (n - k) + i;
}
}
for (j = 0; j < n - k - 1; j++)
{
for (i = 0; i < n - k - 1; i++)
{
G[m++] = lkp1 + j * (n - k) + i;
G[m++] = lkp1 + (j + 1) * (n - k) + i;
G[m++] = lkp1 + (j + 1) * (n - k) + i + 1;
G[m++] = lkp1 + j * (n - k) + i + 1;
G[m++] = lk + (j + 1) * (n - k + 1) + i + 1;
}
}
for (j = 0; j < n - k; j++)
{
for (i = 0; i < n - k - 1; i++)
{
G[m++] = lk + j * (n - k + 1) + i + 1;
G[m++] = lk + (j + 1) * (n - k + 1) + i + 1;
G[m++] = lkp1 + j * (n - k) + i;
G[m++] = lkp1 + j * (n - k) + i + 1;
G[m++] = -1;
}
}
for (j = 0; j < n - k - 1; j++)
{
for (i = 0; i < n - k; i++)
{
G[m++] = lk + (j + 1) * (n - k + 1) + i;
G[m++] = lk + (j + 1) * (n - k + 1) + i + 1;
G[m++] = lkp1 + (j + 1) * (n - k) + i;
G[m++] = lkp1 + j * (n - k) + i;
G[m++] = -1;
}
}
}
if (m != 5*n*(2*n-1)*(2*n+1)/3)
{
mfem_error("GeometryRefiner::Refine() for PYRAMID #2");
}
RGeom[Geometry::PYRAMID].Append(RG);
return RG;
}
case Geometry::PRISM:
{
const int n = Times;
+22 -2
View File
@@ -27,6 +27,7 @@ namespace mfem
Geometry::TETRAHEDRON - w/ vert. (0,0,0),(1,0,0),(0,1,0),(0,0,1)
Geometry::CUBE - the unit cube
Geometry::PRISM - w/ vert. (0,0,0),(1,0,0),(0,1,0),(0,0,1),(1,0,1),(0,1,1)
Geometry::PYRAMID - w/ vert. (0,0,0),(1,0,0),(1,1,0),(0,1,0),(0,0,1)
*/
class Geometry
{
@@ -34,7 +35,7 @@ public:
enum Type
{
INVALID = -1,
POINT = 0, SEGMENT, TRIANGLE, SQUARE, TETRAHEDRON, CUBE, PRISM,
POINT = 0, SEGMENT, TRIANGLE, SQUARE, TETRAHEDRON, CUBE, PRISM, PYRAMID,
NUM_GEOMETRIES
};
@@ -251,7 +252,26 @@ template <> struct Geometry::Constants<Geometry::PRISM>
};
};
// Defined in fe.cpp to ensure construction after 'mfem::WedgeFE'.
template <> struct Geometry::Constants<Geometry::PYRAMID>
{
static const int Dimension = 3;
static const int NumVert = 5;
static const int NumEdges = 8;
static const int Edges[NumEdges][2];
static const int NumFaces = 5;
static const int FaceTypes[NumFaces];
static const int MaxFaceVert = 4;
static const int FaceVert[NumFaces][MaxFaceVert];
// Upper-triangular part of the local vertex-to-vertex graph.
struct VertToVert
{
static const int I[NumVert];
static const int J[NumEdges][2]; // {end,edge_idx}
};
};
// Defined in fe.cpp to ensure construction after 'mfem::TriangleFE' and
// `mfem::TetrahedronFE`.
extern Geometry Geometries;
+166 -54
View File
@@ -255,6 +255,8 @@ void GridFunction::SumFluxAndCount(BilinearFormIntegrator &blfi,
GridFunction &u = *this;
ElementTransformation *Transf;
DofTransformation *udoftrans;
DofTransformation *fdoftrans;
FiniteElementSpace *ufes = u.FESpace();
FiniteElementSpace *ffes = flux.FESpace();
@@ -274,15 +276,23 @@ void GridFunction::SumFluxAndCount(BilinearFormIntegrator &blfi,
continue;
}
ufes->GetElementVDofs(i, udofs);
ffes->GetElementVDofs(i, fdofs);
udoftrans = ufes->GetElementVDofs(i, udofs);
fdoftrans = ffes->GetElementVDofs(i, fdofs);
u.GetSubVector(udofs, ul);
if (udoftrans)
{
udoftrans->InvTransformPrimal(ul);
}
Transf = ufes->GetElementTransformation(i);
blfi.ComputeElementFlux(*ufes->GetFE(i), *Transf, ul,
*ffes->GetFE(i), fl, wcoef);
if (fdoftrans)
{
fdoftrans->TransformPrimal(fl);
}
flux.AddElementVector(fdofs, fl);
FiniteElementSpace::AdjustVDofs(fdofs);
@@ -364,7 +374,7 @@ void GridFunction::GetNodalValues(int i, Array<double> &nval, int vdim) const
int k;
fes->GetElementVDofs(i, vdofs);
DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
const FiniteElement *FElem = fes->GetFE(i);
const IntegrationRule *ElemVert =
Geometries.GetVertices(FElem->GetGeomType());
@@ -374,6 +384,10 @@ void GridFunction::GetNodalValues(int i, Array<double> &nval, int vdim) const
vdim--;
Vector loc_data;
GetSubVector(vdofs, loc_data);
if (doftrans)
{
doftrans->InvTransformPrimal(loc_data);
}
if (FElem->GetRangeType() == FiniteElement::SCALAR)
{
@@ -403,7 +417,7 @@ double GridFunction::GetValue(int i, const IntegrationPoint &ip, int vdim)
const
{
Array<int> dofs;
fes->GetElementDofs(i, dofs);
DofTransformation * doftrans = fes->GetElementDofs(i, dofs);
fes->DofsToVDofs(vdim-1, dofs);
Vector DofVal(dofs.Size()), LocVec;
const FiniteElement *fe = fes->GetFE(i);
@@ -418,6 +432,10 @@ const
fe->CalcPhysShape(*Tr, DofVal);
}
GetSubVector(dofs, LocVec);
if (doftrans)
{
doftrans->InvTransformPrimal(LocVec);
}
return (DofVal * LocVec);
}
@@ -428,9 +446,13 @@ void GridFunction::GetVectorValue(int i, const IntegrationPoint &ip,
const FiniteElement *FElem = fes->GetFE(i);
int dof = FElem->GetDof();
Array<int> vdofs;
fes->GetElementVDofs(i, vdofs);
DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
Vector loc_data;
GetSubVector(vdofs, loc_data);
if (doftrans)
{
doftrans->InvTransformPrimal(loc_data);
}
if (FElem->GetRangeType() == FiniteElement::SCALAR)
{
Vector shape(dof);
@@ -470,30 +492,35 @@ const
Array<int> dofs;
int n = ir.GetNPoints();
vals.SetSize(n);
fes->GetElementDofs(i, dofs);
DofTransformation * doftrans = fes->GetElementDofs(i, dofs);
fes->DofsToVDofs(vdim-1, dofs);
const FiniteElement *FElem = fes->GetFE(i);
int dof = FElem->GetDof();
Vector DofVal(dof), loc_data(dof);
GetSubVector(dofs, loc_data);
if (FElem->GetMapType() == FiniteElement::VALUE)
if (doftrans)
{
for (int k = 0; k < n; k++)
{
FElem->CalcShape(ir.IntPoint(k), DofVal);
vals(k) = DofVal * loc_data;
}
doftrans->InvTransformPrimal(loc_data);
}
else
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
for (int k = 0; k < n; k++)
for (int k = 0; k < n; k++)
if (FElem->GetMapType() == FiniteElement::VALUE)
{
Tr->SetIntPoint(&ir.IntPoint(k));
FElem->CalcPhysShape(*Tr, DofVal);
vals(k) = DofVal * loc_data;
for (int k = 0; k < n; k++)
{
FElem->CalcShape(ir.IntPoint(k), DofVal);
vals(k) = DofVal * loc_data;
}
}
else
{
ElementTransformation *Tr = fes->GetElementTransformation(i);
for (int k = 0; k < n; k++)
{
Tr->SetIntPoint(&ir.IntPoint(k));
FElem->CalcPhysShape(*Tr, DofVal);
vals(k) = DofVal * loc_data;
}
}
}
}
void GridFunction::GetValues(int i, const IntegrationRule &ir, Vector &vals,
@@ -861,11 +888,12 @@ void GridFunction::GetVectorValue(ElementTransformation &T,
Array<int> vdofs;
const FiniteElement *fe = NULL;
DofTransformation * doftrans = NULL;
switch (T.ElementType)
{
case ElementTransformation::ELEMENT:
fes->GetElementVDofs(T.ElementNo, vdofs);
doftrans = fes->GetElementVDofs(T.ElementNo, vdofs);
fe = fes->GetFE(T.ElementNo);
break;
case ElementTransformation::EDGE:
@@ -956,6 +984,10 @@ void GridFunction::GetVectorValue(ElementTransformation &T,
int dof = fe->GetDof();
Vector loc_data;
GetSubVector(vdofs, loc_data);
if (doftrans)
{
doftrans->InvTransformPrimal(loc_data);
}
if (fe->GetRangeType() == FiniteElement::SCALAR)
{
Vector shape(dof);
@@ -998,10 +1030,14 @@ void GridFunction::GetVectorValues(ElementTransformation &T,
int dof = FElem->GetDof();
Array<int> vdofs;
fes->GetElementVDofs(T.ElementNo, vdofs);
DofTransformation * doftrans = fes->GetElementVDofs(T.ElementNo, vdofs);
Vector loc_data;
GetSubVector(vdofs, loc_data);
if (doftrans)
{
doftrans->InvTransformPrimal(loc_data);
}
int nip = ir.GetNPoints();
if (FElem->GetRangeType() == FiniteElement::SCALAR)
@@ -1089,6 +1125,8 @@ void GridFunction::GetValuesFrom(const GridFunction &orig_func)
// Without averaging ...
const FiniteElementSpace *orig_fes = orig_func.FESpace();
DofTransformation * doftrans;
DofTransformation * orig_doftrans;
Array<int> vdofs, orig_vdofs;
Vector shape, loc_values, orig_loc_values;
int i, j, d, ne, dof, odof, vdim;
@@ -1097,9 +1135,13 @@ void GridFunction::GetValuesFrom(const GridFunction &orig_func)
vdim = fes->GetVDim();
for (i = 0; i < ne; i++)
{
fes->GetElementVDofs(i, vdofs);
orig_fes->GetElementVDofs(i, orig_vdofs);
doftrans = fes->GetElementVDofs(i, vdofs);
orig_doftrans = orig_fes->GetElementVDofs(i, orig_vdofs);
orig_func.GetSubVector(orig_vdofs, orig_loc_values);
if (orig_doftrans)
{
orig_doftrans->InvTransformPrimal(orig_loc_values);
}
const FiniteElement *fe = fes->GetFE(i);
const FiniteElement *orig_fe = orig_fes->GetFE(i);
dof = fe->GetDof();
@@ -1117,6 +1159,10 @@ void GridFunction::GetValuesFrom(const GridFunction &orig_func)
shape * ((const double *)orig_loc_values + d * odof) ;
}
}
if (doftrans)
{
doftrans->TransformPrimal(loc_values);
}
SetSubVector(vdofs, loc_values);
}
}
@@ -1126,8 +1172,10 @@ void GridFunction::GetBdrValuesFrom(const GridFunction &orig_func)
// Without averaging ...
const FiniteElementSpace *orig_fes = orig_func.FESpace();
// DofTransformation * doftrans;
// DofTransformation * orig_doftrans;
Array<int> vdofs, orig_vdofs;
Vector shape, loc_values, orig_loc_values;
Vector shape, loc_values, loc_values_t, orig_loc_values, orig_loc_values_t;
int i, j, d, nbe, dof, odof, vdim;
nbe = fes->GetNBE();
@@ -1165,37 +1213,33 @@ void GridFunction::GetVectorFieldValues(
Array<int> vdofs;
ElementTransformation *transf;
int d, j, k, n, sdim, dof, ind;
int d, k, n, sdim, dof;
n = ir.GetNPoints();
fes->GetElementVDofs(i, vdofs);
DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
const FiniteElement *fe = fes->GetFE(i);
dof = fe->GetDof();
sdim = fes->GetMesh()->SpaceDimension();
int *dofs = &vdofs[comp*dof];
// int *dofs = &vdofs[comp*dof];
transf = fes->GetElementTransformation(i);
transf->Transform(ir, tr);
vals.SetSize(n, sdim);
DenseMatrix vshape(dof, sdim);
double a;
Vector loc_data, val(sdim);
GetSubVector(vdofs, loc_data);
if (doftrans)
{
doftrans->InvTransformPrimal(loc_data);
}
for (k = 0; k < n; k++)
{
const IntegrationPoint &ip = ir.IntPoint(k);
transf->SetIntPoint(&ip);
fe->CalcVShape(*transf, vshape);
vshape.MultTranspose(loc_data, val);
for (d = 0; d < sdim; d++)
{
a = 0.0;
for (j = 0; j < dof; j++)
if ( (ind=dofs[j]) >= 0 )
{
a += vshape(j, d) * data[ind];
}
else
{
a -= vshape(j, d) * data[-1-ind];
}
vals(k, d) = a;
vals(k,d) = val(d);
}
}
}
@@ -1365,9 +1409,13 @@ void GridFunction::GetVectorGradientHat(
const FiniteElement *FElem = fes->GetFE(elNo);
int dim = FElem->GetDim(), dof = FElem->GetDof();
Array<int> vdofs;
fes->GetElementVDofs(elNo, vdofs);
DofTransformation * doftrans = fes->GetElementVDofs(elNo, vdofs);
Vector loc_data;
GetSubVector(vdofs, loc_data);
if (doftrans)
{
doftrans->InvTransformPrimal(loc_data);
}
// assuming scalar FE
int vdim = fes->GetVDim();
DenseMatrix dshape(dof, dim);
@@ -1406,9 +1454,13 @@ double GridFunction::GetDivergence(ElementTransformation &T) const
{
// Assuming RT-type space
Array<int> dofs;
fes->GetElementDofs(elNo, dofs);
DofTransformation * doftrans = fes->GetElementDofs(elNo, dofs);
Vector loc_data, divshape(fe->GetDof());
GetSubVector(dofs, loc_data);
if (doftrans)
{
doftrans->InvTransformPrimal(loc_data);
}
fe->CalcDivShape(T.GetIntPoint(), divshape);
return (loc_data * divshape) / T.Weight();
}
@@ -1499,9 +1551,13 @@ void GridFunction::GetCurl(ElementTransformation &T, Vector &curl) const
{
// Assuming ND-type space
Array<int> dofs;
fes->GetElementDofs(elNo, dofs);
DofTransformation * doftrans = fes->GetElementDofs(elNo, dofs);
Vector loc_data;
GetSubVector(dofs, loc_data);
if (doftrans)
{
doftrans->InvTransformPrimal(loc_data);
}
DenseMatrix curl_shape(fe->GetDof(), fe->GetDim() == 3 ? 3 : 1);
fe->CalcCurlShape(T.GetIntPoint(), curl_shape);
curl.SetSize(curl_shape.Width());
@@ -1643,8 +1699,12 @@ void GridFunction::GetGradients(ElementTransformation &tr,
DenseMatrix dshape(fe->GetDof(), fe->GetDim());
Vector lval, gh(fe->GetDim()), gcol;
Array<int> dofs;
fes->GetElementDofs(elNo, dofs);
DofTransformation * doftrans = fes->GetElementDofs(elNo, dofs);
GetSubVector(dofs, lval);
if (doftrans)
{
doftrans->InvTransformPrimal(lval);
}
grad.SetSize(fe->GetDim(), ir.GetNPoints());
for (int i = 0; i < ir.GetNPoints(); i++)
{
@@ -1724,6 +1784,8 @@ void GridFunction::GetElementAverages(GridFunction &avgs) const
{
MassIntegrator Mi;
DenseMatrix loc_mass;
DofTransformation * te_doftrans;
DofTransformation * tr_doftrans;
Array<int> te_dofs, tr_dofs;
Vector loc_avgs, loc_this;
Vector int_psi(avgs.Size());
@@ -1734,11 +1796,19 @@ void GridFunction::GetElementAverages(GridFunction &avgs) const
{
Mi.AssembleElementMatrix2(*fes->GetFE(i), *avgs.FESpace()->GetFE(i),
*fes->GetElementTransformation(i), loc_mass);
fes->GetElementDofs(i, tr_dofs);
avgs.FESpace()->GetElementDofs(i, te_dofs);
tr_doftrans = fes->GetElementDofs(i, tr_dofs);
te_doftrans = avgs.FESpace()->GetElementDofs(i, te_dofs);
GetSubVector(tr_dofs, loc_this);
if (tr_doftrans)
{
tr_doftrans->InvTransformPrimal(loc_this);
}
loc_avgs.SetSize(te_dofs.Size());
loc_mass.Mult(loc_this, loc_avgs);
if (te_doftrans)
{
te_doftrans->TransformPrimal(loc_avgs);
}
avgs.AddElementVector(te_dofs, loc_avgs);
loc_this = 1.0; // assume the local basis for 'this' sums to 1
loc_mass.Mult(loc_this, loc_avgs);
@@ -1753,8 +1823,12 @@ void GridFunction::GetElementAverages(GridFunction &avgs) const
void GridFunction::GetElementDofValues(int el, Vector &dof_vals) const
{
Array<int> dof_idx;
fes->GetElementVDofs(el, dof_idx);
DofTransformation * doftrans = fes->GetElementVDofs(el, dof_idx);
GetSubVector(dof_idx, dof_vals);
if (doftrans)
{
doftrans->InvTransformPrimal(dof_vals);
}
}
void GridFunction::ProjectGridFunction(const GridFunction &src)
@@ -1790,13 +1864,21 @@ void GridFunction::ProjectGridFunction(const GridFunction &src)
cached_geom = geom;
}
src.fes->GetElementVDofs(i, src_vdofs);
DofTransformation * src_doftrans = src.fes->GetElementVDofs(i, src_vdofs);
src.GetSubVector(src_vdofs, src_lvec);
if (src_doftrans)
{
src_doftrans->InvTransformPrimal(src_lvec);
}
for (int vd = 0; vd < vdim; vd++)
{
P.Mult(&src_lvec[vd*P.Width()], &dest_lvec[vd*P.Height()]);
}
fes->GetElementVDofs(i, dest_vdofs);
DofTransformation * doftrans = fes->GetElementVDofs(i, dest_vdofs);
if (doftrans)
{
doftrans->TransformPrimal(dest_lvec);
}
SetSubVector(dest_vdofs, dest_lvec);
}
}
@@ -1805,10 +1887,15 @@ void GridFunction::ImposeBounds(int i, const Vector &weights,
const Vector &lo_, const Vector &hi_)
{
Array<int> vdofs;
fes->GetElementVDofs(i, vdofs);
DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
int size = vdofs.Size();
Vector vals, new_vals(size);
GetSubVector(vdofs, vals);
if (doftrans)
{
doftrans->InvTransformPrimal(vals);
}
MFEM_ASSERT(weights.Size() == size, "Different # of weights and dofs.");
MFEM_ASSERT(lo_.Size() == size, "Different # of lower bounds and dofs.");
@@ -1825,6 +1912,10 @@ void GridFunction::ImposeBounds(int i, const Vector &weights,
slbqp.SetPrintLevel(0); // print messages only if not converged
slbqp.Mult(vals, new_vals);
if (doftrans)
{
doftrans->TransformPrimal(new_vals);
}
SetSubVector(vdofs, new_vals);
}
@@ -1832,10 +1923,14 @@ void GridFunction::ImposeBounds(int i, const Vector &weights,
double min_, double max_)
{
Array<int> vdofs;
fes->GetElementVDofs(i, vdofs);
DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
int size = vdofs.Size();
Vector vals, new_vals(size);
GetSubVector(vdofs, vals);
if (doftrans)
{
doftrans->InvTransformPrimal(vals);
}
double max_val = vals.Max();
double min_val = vals.Min();
@@ -1843,6 +1938,10 @@ void GridFunction::ImposeBounds(int i, const Vector &weights,
if (max_val <= min_)
{
new_vals = min_;
if (doftrans)
{
doftrans->TransformPrimal(new_vals);
}
SetSubVector(vdofs, new_vals);
return;
}
@@ -2278,6 +2377,7 @@ void GridFunction::ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff,
void GridFunction::ProjectCoefficient(Coefficient &coeff)
{
DeltaCoefficient *delta_c = dynamic_cast<DeltaCoefficient *>(&coeff);
DofTransformation * doftrans = NULL;
if (delta_c == NULL)
{
@@ -2286,9 +2386,13 @@ void GridFunction::ProjectCoefficient(Coefficient &coeff)
for (int i = 0; i < fes->GetNE(); i++)
{
fes->GetElementVDofs(i, vdofs);
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
{
doftrans->TransformPrimal(vals);
}
SetSubVector(vdofs, vals);
}
}
@@ -2334,11 +2438,17 @@ void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff)
Array<int> vdofs;
Vector vals;
DofTransformation * doftrans = NULL;
for (i = 0; i < fes->GetNE(); i++)
{
fes->GetElementVDofs(i, vdofs);
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
{
doftrans->TransformPrimal(vals);
}
SetSubVector(vdofs, vals);
}
}
@@ -2401,6 +2511,7 @@ void GridFunction::ProjectCoefficient(Coefficient *coeff[])
double val;
const FiniteElement *fe;
ElementTransformation *transf;
// DofTransformation * doftrans;
Array<int> vdofs;
vdim = fes->GetVDim();
@@ -2410,6 +2521,7 @@ void GridFunction::ProjectCoefficient(Coefficient *coeff[])
fdof = fe->GetDof();
transf = fes->GetElementTransformation(i);
const IntegrationRule &ir = fe->GetNodes();
// doftrans = fes->GetElementVDofs(i, vdofs);
fes->GetElementVDofs(i, vdofs);
for (j = 0; j < fdof; j++)
{
+6
View File
@@ -95,6 +95,12 @@ public:
: Vector(data, f->GetVSize())
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/** @brief Construct a GridFunction using previously allocated Vector @a base
starting at the given offset, @a base_offset. */
GridFunction(FiniteElementSpace *f, Vector &base, int base_offset = 0)
: Vector(base, base_offset, f->GetVSize())
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/// Construct a GridFunction on the given Mesh, using the data from @a input.
/** The content of @a input should be in the format created by the method
Save(). The reconstructed FiniteElementSpace and FiniteElementCollection
+6 -1
View File
@@ -610,7 +610,12 @@ void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
{
if (gsl_code[i] == 1) { indl2.Append(i); }
}
if (indl2.Size() == 0) { return; } // no points on element borders
int borderPts = indl2.Size();
#ifdef MFEM_USE_MPI
MPI_Allreduce(MPI_IN_PLACE, &borderPts, 1, MPI_INT, MPI_SUM, gsl_comm->c);
#endif
if (borderPts == 0) { return; } // no points on element borders
Vector field_out_l2(field_out.Size());
VectorGridFunctionCoefficient field_in_dg(&field_in);
+32
View File
@@ -910,6 +910,9 @@ IntegrationRules::IntegrationRules(int Ref, int type_):
TetrahedronIntRules.SetSize(32, h_mt);
TetrahedronIntRules = NULL;
PyramidIntRules.SetSize(32, h_mt);
PyramidIntRules = NULL;
PrismIntRules.SetSize(32, h_mt);
PrismIntRules = NULL;
@@ -930,6 +933,7 @@ const IntegrationRule &IntegrationRules::Get(int GeomType, int Order)
case Geometry::TETRAHEDRON: ir_array = &TetrahedronIntRules; break;
case Geometry::CUBE: ir_array = &CubeIntRules; break;
case Geometry::PRISM: ir_array = &PrismIntRules; break;
case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
default:
mfem_error("IntegrationRules::Get(...) : Unknown geometry type!");
ir_array = NULL;
@@ -976,6 +980,7 @@ void IntegrationRules::Set(int GeomType, int Order, IntegrationRule &IntRule)
case Geometry::TETRAHEDRON: ir_array = &TetrahedronIntRules; break;
case Geometry::CUBE: ir_array = &CubeIntRules; break;
case Geometry::PRISM: ir_array = &PrismIntRules; break;
case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
default:
mfem_error("IntegrationRules::Set(...) : Unknown geometry type!");
ir_array = NULL;
@@ -1019,6 +1024,7 @@ IntegrationRules::~IntegrationRules()
DeleteIntRuleArray(TetrahedronIntRules);
DeleteIntRuleArray(CubeIntRules);
DeleteIntRuleArray(PrismIntRules);
DeleteIntRuleArray(PyramidIntRules);
}
@@ -1041,6 +1047,8 @@ IntegrationRule *IntegrationRules::GenerateIntegrationRule(int GeomType,
return CubeIntegrationRule(Order);
case Geometry::PRISM:
return PrismIntegrationRule(Order);
case Geometry::PYRAMID:
return PyramidIntegrationRule(Order);
default:
mfem_error("IntegrationRules::Set(...) : Unknown geometry type!");
return NULL;
@@ -1648,6 +1656,30 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
}
}
// Integration rules for reference pyramid
IntegrationRule *IntegrationRules::PyramidIntegrationRule(int Order)
{
// This is a simple integration rule adapted from an integration
// rule for a cube which seems to be adequate for now. When we
// implement high order finite elements for pyramids we should
// revisit this and see if we can improve upon it.
const IntegrationRule &irc = Get(Geometry::CUBE, Order);
int npts = irc.GetNPoints();
AllocIntRule(PyramidIntRules, Order);
PyramidIntRules[Order] = new IntegrationRule(npts);
for (int k=0; k<npts; k++)
{
const IntegrationPoint & ipc = irc.IntPoint(k);
IntegrationPoint & ipp = PyramidIntRules[Order]->IntPoint(k);
ipp.x = ipc.x * (1.0 - ipc.z);
ipp.y = ipc.y * (1.0 - ipc.z);
ipp.z = ipc.z;
ipp.weight = ipc.weight / 3.0;
}
return PyramidIntRules[Order];
}
// Integration rules for reference prism
IntegrationRule *IntegrationRules::PrismIntegrationRule(int Order)
{
+2
View File
@@ -323,6 +323,7 @@ private:
Array<IntegrationRule *> TriangleIntRules;
Array<IntegrationRule *> SquareIntRules;
Array<IntegrationRule *> TetrahedronIntRules;
Array<IntegrationRule *> PyramidIntRules;
Array<IntegrationRule *> PrismIntRules;
Array<IntegrationRule *> CubeIntRules;
@@ -351,6 +352,7 @@ private:
IntegrationRule *TriangleIntegrationRule(int Order);
IntegrationRule *SquareIntegrationRule(int Order);
IntegrationRule *TetrahedronIntegrationRule(int Order);
IntegrationRule *PyramidIntegrationRule(int Order);
IntegrationRule *PrismIntegrationRule(int Order);
IntegrationRule *CubeIntegrationRule(int Order);
+11 -2
View File
@@ -103,6 +103,7 @@ void LinearForm::Assemble()
{
Array<int> vdofs;
ElementTransformation *eltrans;
DofTransformation *doftrans;
Vector elemvect;
int i;
@@ -134,10 +135,14 @@ void LinearForm::Assemble()
if ( domain_integs_marker[k] == NULL ||
(*(domain_integs_marker[k]))[elem_attr-1] == 1 )
{
fes -> GetElementVDofs (i, vdofs);
doftrans = fes -> GetElementVDofs (i, vdofs);
eltrans = fes -> GetElementTransformation (i);
domain_integs[k]->AssembleRHSElementVect(*fes->GetFE(i),
*eltrans, elemvect);
if (doftrans)
{
doftrans->TransformDual(elemvect);
}
AddElementVector (vdofs, elemvect);
}
}
@@ -174,7 +179,7 @@ void LinearForm::Assemble()
{
const int bdr_attr = mesh->GetBdrAttribute(i);
if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
fes -> GetBdrElementVDofs (i, vdofs);
doftrans = fes -> GetBdrElementVDofs (i, vdofs);
eltrans = fes -> GetBdrElementTransformation (i);
for (int k=0; k < boundary_integs.Size(); k++)
{
@@ -184,6 +189,10 @@ void LinearForm::Assemble()
boundary_integs[k]->AssembleRHSElementVect(*fes->GetBE(i),
*eltrans, elemvect);
if (doftrans)
{
doftrans->TransformDual(elemvect);
}
AddElementVector (vdofs, elemvect);
}
}
+6 -5
View File
@@ -317,14 +317,11 @@ ParallelEliminateEssentialBC(const Array<int> &bdr_attr_is_ess,
void ParBilinearForm::TrueAddMult(const Vector &x, Vector &y, const double a)
const
{
MFEM_VERIFY(interior_face_integs.Size() == 0,
"the case of interior face integrators is not"
" implemented");
if (X.ParFESpace() != pfes)
{
X.SetSpace(pfes);
Y.SetSpace(pfes);
Ytmp.SetSize(pfes->GetTrueVSize());
}
X.Distribute(&x);
@@ -334,9 +331,13 @@ const
}
else
{
MFEM_VERIFY(interior_face_integs.Size() == 0,
"the case of interior face integrators is not"
" implemented");
mat->Mult(X, Y);
}
pfes->Dof_TrueDof_Matrix()->MultTranspose(a, Y, 1.0, y);
pfes->GetProlongationMatrix()->MultTranspose(Y, Ytmp);
y.Add(a,Ytmp);
}
void ParBilinearForm::FormLinearSystem(
+1
View File
@@ -33,6 +33,7 @@ protected:
/// Auxiliary objects used in TrueAddMult().
mutable ParGridFunction X, Y;
mutable Vector Ytmp;
OperatorHandle p_mat, p_mat_e;
+319 -53
View File
@@ -128,6 +128,9 @@ void ParFiniteElementSpace::ParInit(ParMesh *pm)
{
ApplyLDofSigns(*elem_dof);
}
// Check for shared trianglular faces with interior Nedelec DoFs
CheckNDSTriaDofs();
}
void ParFiniteElementSpace::Construct()
@@ -464,32 +467,53 @@ void ParFiniteElementSpace::ApplyLDofSigns(Table &el_dof) const
ApplyLDofSigns(all_dofs);
}
void ParFiniteElementSpace::GetElementDofs(int i, Array<int> &dofs) const
DofTransformation *
ParFiniteElementSpace::GetElementDofs(int i, Array<int> &dofs) const
{
if (elem_dof)
{
elem_dof->GetRow(i, dofs);
return;
if (DoFTrans[mesh->GetElementBaseGeometry(i)])
{
Array<int> Fo;
elem_fos->GetRow(i, Fo);
DoFTrans[mesh->GetElementBaseGeometry(i)]->SetFaceOrientations(Fo);
return DoFTrans[mesh->GetElementBaseGeometry(i)];
}
return NULL;
}
FiniteElementSpace::GetElementDofs(i, dofs);
DofTransformation * doftrans = FiniteElementSpace::GetElementDofs(i, dofs);
if (Conforming())
{
ApplyLDofSigns(dofs);
}
return doftrans;
}
void ParFiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
DofTransformation *
ParFiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
{
if (bdr_elem_dof)
{
bdr_elem_dof->GetRow(i, dofs);
return;
if (DoFTrans[mesh->GetBdrElementBaseGeometry(i)])
{
Array<int> Fo;
bdr_elem_fos -> GetRow (i, Fo);
DoFTrans[mesh->GetBdrElementBaseGeometry(i)]->SetFaceOrientations(Fo);
return DoFTrans[mesh->GetBdrElementBaseGeometry(i)];
}
return NULL;
}
FiniteElementSpace::GetBdrElementDofs(i, dofs);
DofTransformation * doftrans =
FiniteElementSpace::GetBdrElementDofs(i, dofs);
if (Conforming())
{
ApplyLDofSigns(dofs);
}
return doftrans;
}
int ParFiniteElementSpace::GetFaceDofs(int i, Array<int> &dofs,
@@ -657,59 +681,266 @@ void ParFiniteElementSpace::GenerateGlobalOffsets() const
}
}
void ParFiniteElementSpace::CheckNDSTriaDofs()
{
// Check for Nedelec basis
bool nd_basis = dynamic_cast<const ND_FECollection*>(fec);
if (!nd_basis)
{
nd_strias = false;
return;
}
// Check for interior face dofs on triangles (the use of TETRAHEDRON
// is not an error)
bool nd_fdof = fec->HasFaceDofs(Geometry::TETRAHEDRON,
GetMaxElementOrder());
if (!nd_fdof)
{
nd_strias = false;
return;
}
// Check for shared triangle faces
bool strias = false;
{
int ngrps = pmesh->GetNGroups();
for (int g = 1; g < ngrps; g++)
{
strias |= pmesh->GroupNTriangles(g);
}
}
// Combine results
int loc_nd_strias = strias ? 1 : 0;
int glb_nd_strias = 0;
MPI_Allreduce(&loc_nd_strias, &glb_nd_strias, 1,
MPI_INTEGER, MPI_SUM, MyComm);
nd_strias = glb_nd_strias > 0;
}
void ParFiniteElementSpace::Build_Dof_TrueDof_Matrix() const // matrix P
{
MFEM_ASSERT(Conforming(), "wrong code path");
if (P) { return; }
int ldof = GetVSize();
int ltdof = TrueVSize();
HYPRE_Int *i_diag = Memory<HYPRE_Int>(ldof+1);
HYPRE_Int *j_diag = Memory<HYPRE_Int>(ltdof);
int diag_counter;
HYPRE_Int *i_offd = Memory<HYPRE_Int>(ldof+1);
HYPRE_Int *j_offd = Memory<HYPRE_Int>(ldof-ltdof);
int offd_counter;
HYPRE_BigInt *cmap = Memory<HYPRE_BigInt>(ldof-ltdof);
HYPRE_BigInt *col_starts = GetTrueDofOffsets();
HYPRE_BigInt *row_starts = GetDofOffsets();
Array<Pair<HYPRE_BigInt, int> > cmap_j_offd(ldof-ltdof);
i_diag[0] = i_offd[0] = 0;
diag_counter = offd_counter = 0;
for (int i = 0; i < ldof; i++)
if (!nd_strias)
{
int ltdof = GetLocalTDofNumber(i);
if (ltdof >= 0)
// Safe to assume 1-1 correspondence between shared dofs
int ldof = GetVSize();
int ltdof = TrueVSize();
HYPRE_Int *i_diag = Memory<HYPRE_Int>(ldof+1);
HYPRE_Int *j_diag = Memory<HYPRE_Int>(ltdof);
int diag_counter;
HYPRE_Int *i_offd = Memory<HYPRE_Int>(ldof+1);
HYPRE_Int *j_offd = Memory<HYPRE_Int>(ldof-ltdof);
int offd_counter;
HYPRE_BigInt *cmap = Memory<HYPRE_BigInt>(ldof-ltdof);
HYPRE_BigInt *col_starts = GetTrueDofOffsets();
HYPRE_BigInt *row_starts = GetDofOffsets();
Array<Pair<HYPRE_BigInt, int> > cmap_j_offd(ldof-ltdof);
i_diag[0] = i_offd[0] = 0;
diag_counter = offd_counter = 0;
for (int i = 0; i < ldof; i++)
{
j_diag[diag_counter++] = ltdof;
int ltdof = GetLocalTDofNumber(i);
if (ltdof >= 0)
{
j_diag[diag_counter++] = ltdof;
}
else
{
cmap_j_offd[offd_counter].one = GetGlobalTDofNumber(i);
cmap_j_offd[offd_counter].two = offd_counter;
offd_counter++;
}
i_diag[i+1] = diag_counter;
i_offd[i+1] = offd_counter;
}
else
SortPairs<HYPRE_BigInt, int>(cmap_j_offd, offd_counter);
for (int i = 0; i < offd_counter; i++)
{
cmap_j_offd[offd_counter].one = GetGlobalTDofNumber(i);
cmap_j_offd[offd_counter].two = offd_counter;
offd_counter++;
cmap[i] = cmap_j_offd[i].one;
j_offd[cmap_j_offd[i].two] = i;
}
i_diag[i+1] = diag_counter;
i_offd[i+1] = offd_counter;
P = new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts,
i_diag, j_diag, i_offd, j_offd,
cmap, offd_counter);
}
SortPairs<HYPRE_BigInt, int>(cmap_j_offd, offd_counter);
for (int i = 0; i < offd_counter; i++)
else
{
cmap[i] = cmap_j_offd[i].one;
j_offd[cmap_j_offd[i].two] = i;
}
// Some shared dofs will be linear combinations of others
int ldof = GetVSize();
int ltdof = TrueVSize();
P = new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts,
i_diag, j_diag, i_offd, j_offd, cmap, offd_counter);
HYPRE_Int gdof = -1;
HYPRE_Int gtdof = -1;
MPI_Allreduce(&ldof, &gdof, 1, HYPRE_MPI_INT, MPI_SUM, MyComm);
MPI_Allreduce(&ltdof, &gtdof, 1, HYPRE_MPI_INT, MPI_SUM, MyComm);
// Ensure face orientations have been communicated
pmesh->ExchangeFaceNbrData();
// Locate and count non-zeros in off-diagonal portion of P
int nnz_offd = 0;
Array<int> ldsize(ldof); ldsize = 0;
Array<int> ltori(ldof); ltori = 0; // Local triangle orientations
{
int ngrps = pmesh->GetNGroups();
int nedofs = fec->DofForGeometry(Geometry::SEGMENT);
Array<int> sdofs;
for (int g = 1; g < ngrps; g++)
{
if (pmesh->gtopo.IAmMaster(g))
{
continue;
}
for (int ei=0; ei<pmesh->GroupNEdges(g); ei++)
{
this->GetSharedEdgeDofs(g, ei, sdofs);
for (int i=0; i<sdofs.Size(); i++)
{
int ind = (sdofs[i]>=0) ? sdofs[i] : (-sdofs[i]-1);
if (ldsize[ind] == 0) { nnz_offd++; }
ldsize[ind] = 1;
}
}
for (int fi=0; fi<pmesh->GroupNTriangles(g); fi++)
{
int face, ori, info1, info2;
pmesh->GroupTriangle(g, fi, face, ori);
pmesh->GetFaceInfos(face, &info1, &info2);
this->GetSharedTriangleDofs(g, fi, sdofs);
for (int i=0; i<3*nedofs; i++)
{
int ind = (sdofs[i]>=0) ? sdofs[i] : (-sdofs[i]-1);
if (ldsize[ind] == 0) { nnz_offd++; }
ldsize[ind] = 1;
}
for (int i=3*nedofs; i<sdofs.Size(); i++)
{
if (ldsize[sdofs[i]] == 0) { nnz_offd += 2; }
ldsize[sdofs[i]] = 2;
ltori[sdofs[i]] = info2 % 64;
}
}
for (int fi=0; fi<pmesh->GroupNQuadrilaterals(g); fi++)
{
this->GetSharedQuadrilateralDofs(g, fi, sdofs);
for (int i=0; i<sdofs.Size(); i++)
{
int ind = (sdofs[i]>=0) ? sdofs[i] : (-sdofs[i]-1);
if (ldsize[ind] == 0) { nnz_offd++; }
ldsize[ind] = 1;
}
}
}
}
HYPRE_Int *i_diag = new HYPRE_Int[ldof+1];
HYPRE_Int *j_diag = new HYPRE_Int[ltdof];
double *d_diag = new double[ltdof];
int diag_counter;
HYPRE_Int *i_offd = new HYPRE_Int[ldof+1];
HYPRE_Int *j_offd = new HYPRE_Int[nnz_offd];
double *d_offd = new double[nnz_offd];
int offd_counter;
HYPRE_BigInt *cmap = new HYPRE_BigInt[ldof-ltdof];
HYPRE_BigInt *col_starts = GetTrueDofOffsets();
HYPRE_BigInt *row_starts = GetDofOffsets();
Array<Pair<HYPRE_BigInt, int> > cmap_j_offd(ldof-ltdof);
i_diag[0] = i_offd[0] = 0;
diag_counter = offd_counter = 0;
int offd_col_counter = 0;
for (int i = 0; i < ldof; i++)
{
int ltdof = GetLocalTDofNumber(i);
if (ltdof >= 0)
{
j_diag[diag_counter] = ltdof;
d_diag[diag_counter++] = 1.0;
}
else
{
if (ldsize[i] == 1)
{
cmap_j_offd[offd_col_counter].one = GetGlobalTDofNumber(i);
cmap_j_offd[offd_col_counter].two = offd_counter;
offd_counter++;
offd_col_counter++;
}
else
{
cmap_j_offd[offd_col_counter].one = GetGlobalTDofNumber(i);
cmap_j_offd[offd_col_counter].two = offd_counter;
offd_counter += 2;
offd_col_counter++;
i_diag[i+1] = diag_counter;
i_offd[i+1] = offd_counter;
i++;
cmap_j_offd[offd_col_counter].one = GetGlobalTDofNumber(i);
cmap_j_offd[offd_col_counter].two = offd_counter;
offd_counter += 2;
offd_col_counter++;
}
}
i_diag[i+1] = diag_counter;
i_offd[i+1] = offd_counter;
}
SortPairs<HYPRE_BigInt, int>(cmap_j_offd, offd_col_counter);
for (int i = 0; i < nnz_offd; i++)
{
j_offd[i] = -1;
d_offd[i] = 0.0;
}
for (int i = 0; i < offd_col_counter; i++)
{
cmap[i] = cmap_j_offd[i].one;
j_offd[cmap_j_offd[i].two] = i;
}
for (int i = 0; i < ldof; i++)
{
if (i_offd[i+1] == i_offd[i] + 1)
{
d_offd[i_offd[i]] = 1.0;
}
else if (i_offd[i+1] == i_offd[i] + 2)
{
const double * T = ND_DofTransformation
::GetFaceTransform(ltori[i]).GetData();
j_offd[i_offd[i] + 1] = j_offd[i_offd[i]] + 1;
d_offd[i_offd[i]] = T[0]; d_offd[i_offd[i] + 1] = T[2];
i++;
j_offd[i_offd[i] + 1] = j_offd[i_offd[i]];
j_offd[i_offd[i]] = j_offd[i_offd[i] + 1] - 1;
d_offd[i_offd[i]] = T[1]; d_offd[i_offd[i] + 1] = T[3];
}
}
P = new HypreParMatrix(MyComm, gdof, gtdof, row_starts, col_starts,
i_diag, j_diag, d_diag, i_offd, j_offd, d_offd,
offd_col_counter, cmap);
}
SparseMatrix Pdiag;
P->GetDiag(Pdiag);
@@ -913,6 +1144,8 @@ const Operator *ParFiniteElementSpace::GetProlongationMatrix() const
{
if (Pconf) { return Pconf; }
if (nd_strias) { return Dof_TrueDof_Matrix(); }
if (NRanks == 1)
{
Pconf = new IdentityOperator(GetTrueVSize());
@@ -1216,10 +1449,29 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
delete [] requests;
}
void ParFiniteElementSpace::GetFaceNbrElementVDofs(
DofTransformation *ParFiniteElementSpace::GetFaceNbrElementVDofs(
int i, Array<int> &vdofs) const
{
face_nbr_element_dof.GetRow(i, vdofs);
DofTransformation *doftrans = NULL;
Geometry::Type geom = GetFaceNbrFE(i)->GetGeomType();
if (DoFTrans[geom])
{
Array<int> F, Fo;
pmesh->GetFaceNbrElementFaces(pmesh->GetNE() + i, F, Fo);
doftrans = DoFTrans[geom];
doftrans->SetFaceOrientations(Fo);
}
if (vdim == 1 || doftrans == NULL)
{
return doftrans;
}
else
{
VDoFTrans.SetDofTransformation(*doftrans);
return &VDoFTrans;
}
}
void ParFiniteElementSpace::GetFaceNbrFaceVDofs(int i, Array<int> &vdofs) const
@@ -1278,12 +1530,17 @@ const FiniteElement *ParFiniteElementSpace::GetFaceNbrFaceFE(int i) const
void ParFiniteElementSpace::Lose_Dof_TrueDof_Matrix()
{
P -> StealData();
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParCSRMatrix *csrP = (hypre_ParCSRMatrix*)(*P);
hypre_ParCSRMatrixOwnsRowStarts(csrP) = 1;
hypre_ParCSRMatrixOwnsColStarts(csrP) = 1;
P -> StealData();
dof_offsets.LoseData();
tdof_offsets.LoseData();
#else
dof_offsets.DeleteAll();
tdof_offsets.DeleteAll();
#endif
}
void ParFiniteElementSpace::ConstructTrueDofs()
@@ -2526,7 +2783,8 @@ static int_type* make_j_array(int_type* I, int nrows)
HypreParMatrix*
ParFiniteElementSpace::RebalanceMatrix(int old_ndofs,
const Table* old_elem_dof)
const Table* old_elem_dof,
const Table* old_elem_fos)
{
MFEM_VERIFY(Nonconforming(), "Only supported for nonconforming meshes.");
MFEM_VERIFY(old_dof_offsets.Size(), "ParFiniteElementSpace::Update needs to "
@@ -2651,7 +2909,8 @@ struct DerefDofMessage
HypreParMatrix*
ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
const Table* old_elem_dof)
const Table* old_elem_dof,
const Table *old_elem_fos)
{
int nrk = HYPRE_AssumedPartitionCheck() ? 2 : NRanks;
@@ -3007,13 +3266,16 @@ void ParFiniteElementSpace::Update(bool want_transform)
}
Table* old_elem_dof = NULL;
Table* old_elem_fos = NULL;
int old_ndofs;
// save old DOF table
if (want_transform)
{
old_elem_dof = elem_dof;
old_elem_fos = elem_fos;
elem_dof = NULL;
elem_fos = NULL;
old_ndofs = ndofs;
Swap(dof_offsets, old_dof_offsets);
}
@@ -3035,22 +3297,25 @@ void ParFiniteElementSpace::Update(bool want_transform)
{
if (Th.Type() != Operator::MFEM_SPARSEMAT)
{
Th.Reset(new RefinementOperator(this, old_elem_dof, old_ndofs));
Th.Reset(new RefinementOperator(this, old_elem_dof,
old_elem_fos, old_ndofs));
// The RefinementOperator takes ownership of 'old_elem_dofs', so
// we no longer own it:
old_elem_dof = NULL;
old_elem_fos = NULL;
}
else
{
// calculate fully assembled matrix
Th.Reset(RefinementMatrix(old_ndofs, old_elem_dof));
Th.Reset(RefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
}
break;
}
case Mesh::DEREFINE:
{
Th.Reset(ParallelDerefinementMatrix(old_ndofs, old_elem_dof));
Th.Reset(ParallelDerefinementMatrix(old_ndofs, old_elem_dof,
old_elem_fos));
if (Nonconforming())
{
Th.SetOperatorOwner(false);
@@ -3062,7 +3327,7 @@ void ParFiniteElementSpace::Update(bool want_transform)
case Mesh::REBALANCE:
{
Th.Reset(RebalanceMatrix(old_ndofs, old_elem_dof));
Th.Reset(RebalanceMatrix(old_ndofs, old_elem_dof, old_elem_fos));
break;
}
@@ -3071,6 +3336,7 @@ void ParFiniteElementSpace::Update(bool want_transform)
}
delete old_elem_dof;
delete old_elem_fos;
}
}
+17 -5
View File
@@ -87,6 +87,12 @@ private:
this is a TransposeOperator wrapping R. */
mutable Operator *R_transpose;
/// Flag indicating the existence of shared triangles with interior ND dofs
bool nd_strias;
/// Resets nd_strias flag at constuction or after rebalancing
void CheckNDSTriaDofs();
ParNURBSExtension *pNURBSext() const
{ return dynamic_cast<ParNURBSExtension *>(NURBSext); }
@@ -174,14 +180,16 @@ private:
The result is a parallel permutation matrix that can be used to update
all grid functions defined on this space. */
HypreParMatrix* RebalanceMatrix(int old_ndofs,
const Table* old_elem_dof);
const Table* old_elem_dof,
const Table* old_elem_fos);
/** Calculate a GridFunction restriction matrix after mesh derefinement.
The matrix is constructed so that the new grid function interpolates
the original function, i.e., the original function is evaluated at the
nodes of the coarse function. */
HypreParMatrix* ParallelDerefinementMatrix(int old_ndofs,
const Table *old_elem_dof);
const Table *old_elem_dof,
const Table *old_elem_fos);
/// Updates the internal mesh pointer. @warning @a new_mesh must be
/// <b>topologically identical</b> to the existing mesh. Used if the address
@@ -202,6 +210,8 @@ public:
int num_face_nbr_dofs;
// Face-neighbor-element to face-neighbor dof
Table face_nbr_element_dof;
// Face-neighbor-element face orientations
Table face_nbr_element_fos;
// Face-neighbor to ldof in the face-neighbor numbering
Table face_nbr_ldof;
// The global ldof indices of the face-neighbor dofs
@@ -279,10 +289,10 @@ public:
virtual int GetTrueVSize() const { return ltdof_size; }
/// Returns indexes of degrees of freedom in array dofs for i'th element.
virtual void GetElementDofs(int i, Array<int> &dofs) const;
virtual DofTransformation *GetElementDofs(int i, Array<int> &dofs) const;
/// Returns indexes of degrees of freedom for i'th boundary element.
virtual void GetBdrElementDofs(int i, Array<int> &dofs) const;
virtual DofTransformation *GetBdrElementDofs(int i, Array<int> &dofs) const;
/** Returns the indexes of the degrees of freedom for i'th face
including the dofs for the edges and the vertices of the face. */
@@ -382,7 +392,7 @@ public:
// Face-neighbor functions
void ExchangeFaceNbrData();
int GetFaceNbrVSize() const { return num_face_nbr_dofs; }
void GetFaceNbrElementVDofs(int i, Array<int> &vdofs) const;
DofTransformation *GetFaceNbrElementVDofs(int i, Array<int> &vdofs) const;
void GetFaceNbrFaceVDofs(int i, Array<int> &vdofs) const;
const FiniteElement *GetFaceNbrFE(int i) const;
const FiniteElement *GetFaceNbrFaceFE(int i) const;
@@ -397,6 +407,8 @@ public:
bool Conforming() const { return pmesh->pncmesh == NULL && !nonconf_P; }
bool Nonconforming() const { return pmesh->pncmesh != NULL || nonconf_P; }
bool SharedNDTriangleDofs() const { return nd_strias; }
// Transfer parallel true-dof data from coarse_fes, defined on a coarse mesh,
// to this FE space, defined on a refined mesh. See full documentation in the
// base class, FiniteElementSpace::GetTrueTransferOperator.
+12 -2
View File
@@ -325,9 +325,14 @@ void ParGridFunction::GetVectorValue(int i, const IntegrationPoint &ip,
if (nbr_el_no >= 0)
{
Array<int> dofs;
pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs);
DofTransformation * doftrans = pfes->GetFaceNbrElementVDofs(nbr_el_no,
dofs);
Vector loc_data;
face_nbr_data.GetSubVector(dofs, loc_data);
if (doftrans)
{
doftrans->InvTransformPrimal(loc_data);
}
const FiniteElement *FElem = pfes->GetFaceNbrFE(nbr_el_no);
int dof = FElem->GetDof();
if (FElem->GetRangeType() == FiniteElement::SCALAR)
@@ -437,12 +442,17 @@ void ParGridFunction::GetVectorValue(ElementTransformation &T,
}
Array<int> vdofs;
pfes->GetFaceNbrElementVDofs(nbr_el_no, vdofs);
DofTransformation * doftrans = pfes->GetFaceNbrElementVDofs(nbr_el_no,
vdofs);
const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no);
int dof = fe->GetDof();
Vector loc_data;
face_nbr_data.GetSubVector(vdofs, loc_data);
if (doftrans)
{
doftrans->InvTransformPrimal(loc_data);
}
if (fe->GetRangeType() == FiniteElement::SCALAR)
{
Vector shape(dof);
+5
View File
@@ -65,6 +65,11 @@ public:
ParGridFunction(ParFiniteElementSpace *pf, double *data) :
GridFunction(pf, data), pfes(pf) { }
/** @brief Construct a ParGridFunction using previously allocated Vector
@a base starting at the given offset, @a base_offset. */
ParGridFunction(ParFiniteElementSpace *pf, Vector &base, int base_offset = 0)
: GridFunction(pf, base, base_offset), pfes(pf) { }
/// Construct a ParGridFunction using a GridFunction as external data.
/** The parallel space @a *pf and the space used by @a *gf should match. The
data from @a *gf is used as the local data of the ParGridFunction on each
+4
View File
@@ -33,6 +33,10 @@ ParL2FaceRestriction::ParL2FaceRestriction(const ParFiniteElementSpace &fes,
// If fespace == L2
const ParFiniteElementSpace &pfes =
static_cast<const ParFiniteElementSpace&>(this->fes);
// Ensure the face neighbor data is constructed
pfes.GetParMesh()->ExchangeFaceNbrData();
const FiniteElement *fe = pfes.GetFE(0);
const TensorBasisElement *tfe = dynamic_cast<const TensorBasisElement*>(fe);
MFEM_VERIFY(tfe != NULL &&
+19
View File
@@ -15,6 +15,12 @@
#include "../general/forall.hpp"
#include <climits>
#ifdef MFEM_USE_MPI
#include "pfespace.hpp"
#endif
namespace mfem
{
@@ -675,6 +681,19 @@ H1FaceRestriction::H1FaceRestriction(const FiniteElementSpace &fes,
gather_indices(nf*dof)
{
if (nf==0) { return; }
#ifdef MFEM_USE_MPI
// If the underlying finite element space is parallel, ensure the face
// neighbor information is generated.
if (const ParFiniteElementSpace *pfes
= dynamic_cast<const ParFiniteElementSpace*>(&fes))
{
pfes->GetParMesh()->ExchangeFaceNbrData();
}
#endif
// If fespace == H1
const FiniteElement *fe = fes.GetFE(0);
const TensorBasisElement *tfe = dynamic_cast<const TensorBasisElement*>(fe);
+382 -67
View File
@@ -1314,33 +1314,61 @@ static inline void device_copy(double *d_dest, const double *d_src, int size)
} // namespace internal
#ifdef MFEM_USE_MPI
void DiscreteAdaptTC::FinalizeParDiscreteTargetSpec(const ParGridFunction
&tspec_)
void DiscreteAdaptTC::FinalizeParDiscreteTargetSpec(const ParGridFunction &t)
{
MFEM_VERIFY(adapt_eval, "SetAdaptivityEvaluator() has not been called!")
MFEM_VERIFY(ncomp > 0, "No target specifications have been set!");
ParFiniteElementSpace *ptspec_fes = tspec_.ParFESpace();
ParFiniteElementSpace *ptspec_fes = t.ParFESpace();
adapt_eval->SetParMetaInfo(*ptspec_fes->GetParMesh(),
*ptspec_fes->FEColl(), ncomp);
adapt_eval->SetInitialField(*tspec_fes->GetMesh()->GetNodes(), tspec);
adapt_eval->SetInitialField(*ptspec_fes->GetMesh()->GetNodes(), tspec);
tspec_sav = tspec;
delete tspec_fesv;
tspec_fesv = new FiniteElementSpace(tspec_fes->GetMesh(),
tspec_fes->FEColl(), ncomp);
tspec_fesv = new FiniteElementSpace(ptspec_fes->GetMesh(),
ptspec_fes->FEColl(), ncomp);
delete ptspec_fesv;
ptspec_fesv = new ParFiniteElementSpace(ptspec_fes->GetParMesh(),
ptspec_fes->FEColl(), ncomp);
delete tspec_pgf;
tspec_pgf = new ParGridFunction(ptspec_fesv, tspec);
tspec_gf = tspec_pgf;
}
void DiscreteAdaptTC::ParUpdateAfterMeshTopologyChange()
{
ptspec_fesv->Update();
if (tspec_fesv)
{
delete tspec_fesv;
tspec_fesv = new FiniteElementSpace(ptspec_fesv->GetMesh(),
ptspec_fesv->FEColl(), ncomp);
}
tspec_pgf->Update();
tspec_gf = tspec_pgf;
tspec.SetDataAndSize(tspec_pgf->GetData(), tspec_pgf->Size());
tspec_sav = tspec;
adapt_eval->SetParMetaInfo(*ptspec_fesv->GetParMesh(),
*ptspec_fesv->FEColl(), ncomp);
adapt_eval->SetInitialField(*ptspec_fesv->GetMesh()->GetNodes(), tspec);
}
void DiscreteAdaptTC::SetTspecAtIndex(int idx, const ParGridFunction &tspec_)
{
const int vdim = tspec_.FESpace()->GetVDim(),
dof_cnt = tspec_.Size()/vdim;
const int vdim = tspec_.FESpace()->GetVDim(),
ndof = tspec_.FESpace()->GetNDofs();
MFEM_VERIFY(ndof == tspec.Size()/ncomp, "Inconsistency in SetTspecAtIndex.");
const auto tspec__d = tspec_.Read();
auto tspec_d = tspec.ReadWrite();
const int offset = idx*dof_cnt;
internal::device_copy(tspec_d + offset, tspec__d, dof_cnt*vdim);
const int offset = idx*ndof;
internal::device_copy(tspec_d + offset, tspec__d, ndof*vdim);
FinalizeParDiscreteTargetSpec(tspec_);
}
@@ -1360,78 +1388,71 @@ void DiscreteAdaptTC::SetParDiscreteTargetSkew(const ParGridFunction &tspec_)
FinalizeParDiscreteTargetSpec(tspec_);
}
void DiscreteAdaptTC::SetParDiscreteTargetAspectRatio(const ParGridFunction
&tspec_)
void DiscreteAdaptTC::SetParDiscreteTargetAspectRatio(const ParGridFunction &ar)
{
if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, tspec_); return; }
if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, ar); return; }
aspectratioidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeParDiscreteTargetSpec(tspec_);
SetDiscreteTargetBase(ar);
FinalizeParDiscreteTargetSpec(ar);
}
void DiscreteAdaptTC::SetParDiscreteTargetOrientation(const ParGridFunction
&tspec_)
void DiscreteAdaptTC::SetParDiscreteTargetOrientation(const ParGridFunction &o)
{
if (orientationidx > -1) { SetTspecAtIndex(orientationidx, tspec_); return; }
if (orientationidx > -1) { SetTspecAtIndex(orientationidx, o); return; }
orientationidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeParDiscreteTargetSpec(tspec_);
SetDiscreteTargetBase(o);
FinalizeParDiscreteTargetSpec(o);
}
void DiscreteAdaptTC::SetParDiscreteTargetSpec(const ParGridFunction &tspec_)
{
SetParDiscreteTargetSize(tspec_);
FinalizeParDiscreteTargetSpec(tspec_);
}
#endif // MFEM_USE_MPI
void DiscreteAdaptTC::SetDiscreteTargetBase(const GridFunction &tspec_)
{
const int vdim = tspec_.FESpace()->GetVDim(),
dof_cnt = tspec_.Size()/vdim;
const int vdim = tspec_.FESpace()->GetVDim(),
ndof = tspec_.FESpace()->GetNDofs();
ncomp += vdim;
delete tspec_fes;
tspec_fes = new FiniteElementSpace(tspec_.FESpace()->GetMesh(),
tspec_.FESpace()->FEColl(), 1);
// need to append data to tspec
// make a copy of tspec->tspec_temp, increase its size, and
// copy data from tspec_temp -> tspec, then add new entries
Vector tspec_temp = tspec;
tspec.UseDevice(true);
tspec_sav.UseDevice(true);
tspec.SetSize(ncomp*dof_cnt);
tspec.SetSize(ncomp*ndof);
const auto tspec_temp_d = tspec_temp.Read();
auto tspec_d = tspec.ReadWrite();
internal::device_copy(tspec_d, tspec_temp_d, tspec_temp.Size());
const auto tspec__d = tspec_.Read();
const int offset = (ncomp-vdim)*dof_cnt;
internal::device_copy(tspec_d + offset, tspec__d, dof_cnt*vdim);
const int offset = (ncomp-vdim)*ndof;
internal::device_copy(tspec_d + offset, tspec__d, ndof*vdim);
}
void DiscreteAdaptTC::SetTspecAtIndex(int idx, const GridFunction &tspec_)
{
const int vdim = tspec_.FESpace()->GetVDim(),
dof_cnt = tspec_.Size()/vdim;
const int vdim = tspec_.FESpace()->GetVDim(),
ndof = tspec_.FESpace()->GetNDofs();
MFEM_VERIFY(ndof == tspec.Size()/ncomp, "Inconsistency in SetTargetSpec.");
const auto tspec__d = tspec_.Read();
auto tspec_d = tspec.ReadWrite();
const int offset = idx*dof_cnt;
internal::device_copy(tspec_d + offset, tspec__d, dof_cnt*vdim);
FinalizeSerialDiscreteTargetSpec();
const int offset = idx*ndof;
internal::device_copy(tspec_d + offset, tspec__d, ndof*vdim);
FinalizeSerialDiscreteTargetSpec(tspec_);
}
void DiscreteAdaptTC::SetSerialDiscreteTargetSize(const GridFunction &tspec_)
{
if (sizeidx > -1) { SetTspecAtIndex(sizeidx, tspec_); return; }
sizeidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeSerialDiscreteTargetSpec();
FinalizeSerialDiscreteTargetSpec(tspec_);
}
void DiscreteAdaptTC::SetSerialDiscreteTargetSkew(const GridFunction &tspec_)
@@ -1439,32 +1460,31 @@ void DiscreteAdaptTC::SetSerialDiscreteTargetSkew(const GridFunction &tspec_)
if (skewidx > -1) { SetTspecAtIndex(skewidx, tspec_); return; }
skewidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeSerialDiscreteTargetSpec();
FinalizeSerialDiscreteTargetSpec(tspec_);
}
void DiscreteAdaptTC::SetSerialDiscreteTargetAspectRatio(
const GridFunction &tspec_)
void DiscreteAdaptTC::SetSerialDiscreteTargetAspectRatio(const GridFunction &ar)
{
if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, tspec_); return; }
if (aspectratioidx > -1) { SetTspecAtIndex(aspectratioidx, ar); return; }
aspectratioidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeSerialDiscreteTargetSpec();
SetDiscreteTargetBase(ar);
FinalizeSerialDiscreteTargetSpec(ar);
}
void DiscreteAdaptTC::SetSerialDiscreteTargetOrientation(
const GridFunction &tspec_)
void DiscreteAdaptTC::SetSerialDiscreteTargetOrientation(const GridFunction &o)
{
if (orientationidx > -1) { SetTspecAtIndex(orientationidx, tspec_); return; }
if (orientationidx > -1) { SetTspecAtIndex(orientationidx, o); return; }
orientationidx = ncomp;
SetDiscreteTargetBase(tspec_);
FinalizeSerialDiscreteTargetSpec();
SetDiscreteTargetBase(o);
FinalizeSerialDiscreteTargetSpec(o);
}
void DiscreteAdaptTC::FinalizeSerialDiscreteTargetSpec()
void DiscreteAdaptTC::FinalizeSerialDiscreteTargetSpec(const GridFunction &t)
{
MFEM_VERIFY(adapt_eval, "SetAdaptivityEvaluator() has not been called!")
MFEM_VERIFY(ncomp > 0, "No target specifications have been set!");
const FiniteElementSpace *tspec_fes = t.FESpace();
adapt_eval->SetSerialMetaInfo(*tspec_fes->GetMesh(),
*tspec_fes->FEColl(), ncomp);
adapt_eval->SetInitialField(*tspec_fes->GetMesh()->GetNodes(), tspec);
@@ -1474,12 +1494,40 @@ void DiscreteAdaptTC::FinalizeSerialDiscreteTargetSpec()
delete tspec_fesv;
tspec_fesv = new FiniteElementSpace(tspec_fes->GetMesh(),
tspec_fes->FEColl(), ncomp);
delete tspec_gf;
tspec_gf = new GridFunction(tspec_fesv, tspec);
}
void DiscreteAdaptTC::GetDiscreteTargetSpec(GridFunction &tspec_, int idx)
{
if (idx < 0) { return; }
const int ndof = tspec_.FESpace()->GetNDofs(),
vdim = tspec_.FESpace()->GetVDim();
MFEM_VERIFY(ndof == tspec.Size()/ncomp,
"Inconsistency in GetSerialDiscreteTargetSpec.");
for (int i = 0; i < ndof*vdim; i++)
{
tspec_(i) = tspec(i + idx*ndof);
}
}
void DiscreteAdaptTC::UpdateAfterMeshTopologyChange()
{
tspec_fesv->Update();
tspec_gf->Update();
tspec.SetDataAndSize(tspec_gf->GetData(), tspec_gf->Size());
tspec_sav = tspec;
adapt_eval->SetSerialMetaInfo(*tspec_fesv->GetMesh(),
*tspec_fesv->FEColl(), ncomp);
adapt_eval->SetInitialField(*tspec_fesv->GetMesh()->GetNodes(), tspec);
}
void DiscreteAdaptTC::SetSerialDiscreteTargetSpec(const GridFunction &tspec_)
{
SetSerialDiscreteTargetSize(tspec_);
FinalizeSerialDiscreteTargetSpec();
}
@@ -1509,7 +1557,7 @@ void DiscreteAdaptTC::UpdateTargetSpecificationAtNode(const FiniteElement &el,
MFEM_VERIFY(tspec.Size() > 0, "Target specification is not set!");
Array<int> dofs;
tspec_fes->GetElementDofs(T.ElementNo, dofs);
tspec_fesv->GetElementDofs(T.ElementNo, dofs);
const int cnt = tspec.Size()/ncomp; // dofs per scalar-field
for (int i = 0; i < ncomp; i++)
@@ -1524,7 +1572,7 @@ void DiscreteAdaptTC::RestoreTargetSpecificationAtNode(ElementTransformation &T,
MFEM_VERIFY(tspec.Size() > 0, "Target specification is not set!");
Array<int> dofs;
tspec_fes->GetElementDofs(T.ElementNo, dofs);
tspec_fesv->GetElementDofs(T.ElementNo, dofs);
const int cnt = tspec.Size()/ncomp;
for (int i = 0; i < ncomp; i++)
{
@@ -1532,6 +1580,40 @@ void DiscreteAdaptTC::RestoreTargetSpecificationAtNode(ElementTransformation &T,
}
}
void DiscreteAdaptTC::SetTspecFromIntRule(int e_id,
const IntegrationRule &intrule)
{
switch (target_type)
{
case IDEAL_SHAPE_GIVEN_SIZE:
case GIVEN_SHAPE_AND_SIZE:
{
const int ndofs = tspec_fesv->GetFE(e_id)->GetDof(),
ntspec_dofs = ndofs*ncomp;
Vector tspec_vals(ntspec_dofs);
Array<int> dofs;
tspec_fesv->GetElementVDofs(e_id, dofs);
tspec.GetSubVector(dofs, tspec_vals);
DenseMatrix tr;
tspec_gf->GetVectorValues(e_id, intrule, tspec_refine, tr);
tspec_refine.Transpose();
break;
}
default:
MFEM_ABORT("Incompatible target type for discrete adaptation!");
}
}
void DiscreteAdaptTC::SetTspecDataForDerefinement(FiniteElementSpace *fes)
{
coarse_tspec_fesv = fes;
const Operator *c_op = fes->GetUpdateOperator();
tspec_derefine.SetSize(c_op->Height());
c_op->Mult(tspec, tspec_derefine);
}
void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
const IntegrationRule &ir,
const Vector &elfun,
@@ -1542,6 +1624,8 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
nqp = ir.GetNPoints();
Jtrcomp.SetSize(dim, dim, 4*nqp);
FiniteElementSpace *src_fes = tspec_fesv;
switch (target_type)
{
case IDEAL_SHAPE_GIVEN_SIZE:
@@ -1550,7 +1634,7 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
const DenseMatrix &Wideal =
Geometries.GetGeomToPerfGeomJac(fe.GetGeomType());
const int dim = Wideal.Height(),
ndofs = tspec_fes->GetFE(e_id)->GetDof(),
ndofs = tspec_fesv->GetFE(e_id)->GetDof(),
ntspec_dofs = ndofs*ncomp;
Vector shape(ndofs), tspec_vals(ntspec_dofs), par_vals,
@@ -1561,11 +1645,29 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
tspec_fesv->GetElementVDofs(e_id, dofs);
tspec.UseDevice(true);
tspec.GetSubVector(dofs, tspec_vals);
if (tspec_refine.NumCols() > 0) // Refinement
{
MFEM_VERIFY(amr_el >= 0, " Target being constructed for an AMR element.");
for (int i = 0; i < ncomp; i++)
{
for (int j = 0; j < ndofs; j++)
{
tspec_vals(j + i*ndofs) = tspec_refine(j + amr_el*ndofs, i);
}
}
}
else if (tspec_derefine.Size() > 0) // Derefinement
{
dofs.SetSize(0);
coarse_tspec_fesv->GetElementVDofs(e_id, dofs);
tspec_derefine.GetSubVector(dofs, tspec_vals);
src_fes = coarse_tspec_fesv;
}
for (int q = 0; q < nqp; q++)
{
const IntegrationPoint &ip = ir.IntPoint(q);
tspec_fes->GetFE(e_id)->CalcShape(ip, shape);
src_fes->GetFE(e_id)->CalcShape(ip, shape);
Jtr(q) = Wideal; // Initialize to identity
for (int d = 0; d < 4; d++)
{
@@ -1576,9 +1678,16 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
if (sizeidx != -1) // Set size
{
par_vals.SetDataAndSize(tspec_vals.GetData()+sizeidx*ndofs, ndofs);
const double min_size = par_vals.Min();
MFEM_VERIFY(min_size > 0.0,
"Non-positive size propagated in the target definition.");
double min_size = par_vals.Min();//0.001; //
if (lim_min_size > 0.)
{
min_size = lim_min_size;
}
else
{
MFEM_VERIFY(min_size > 0.0,
"Non-positive size propagated in the target definition.");
}
const double size = std::max(shape * par_vals, min_size);
Jtr(q).Set(std::pow(size, 1.0/dim), Jtr(q));
DenseMatrix Jtrcomp_q(Jtrcomp.GetData(0 + 4*q), dim, dim);
@@ -1593,6 +1702,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
{
par_vals.SetDataAndSize(tspec_vals.GetData()+
aspectratioidx*ndofs, ndofs);
const double min_size = par_vals.Min();
MFEM_VERIFY(min_size > 0.0,
"Non-positive aspect-ratio propagated in the target definition.");
const double aspectratio = shape * par_vals;
D_rho = 0.;
@@ -1777,7 +1889,7 @@ void DiscreteAdaptTC::ComputeElementTargetsGradient(const IntegrationRule &ir,
grad_phys.Mult(par_vals, grad_ptr_c1);
Vector grad_q(dim);
tspec_fes->GetFE(e_id)->CalcShape(ip, shape);
tspec_fesv->GetFE(e_id)->CalcShape(ip, shape);
grad_e_c1.MultTranspose(shape, grad_q);
const double min_size = par_vals.Min();
@@ -1810,7 +1922,7 @@ void DiscreteAdaptTC::ComputeElementTargetsGradient(const IntegrationRule &ir,
grad_phys.Mult(par_vals, grad_ptr_c1);
Vector grad_q(dim);
tspec_fes->GetFE(e_id)->CalcShape(ip, shape);
tspec_fesv->GetFE(e_id)->CalcShape(ip, shape);
grad_e_c1.MultTranspose(shape, grad_q);
const double aspectratio = shape * par_vals;
@@ -1841,7 +1953,7 @@ void DiscreteAdaptTC::ComputeElementTargetsGradient(const IntegrationRule &ir,
grad_phys.Mult(par_vals_c2, grad_ptr_c2);
grad_phys.Mult(par_vals_c3, grad_ptr_c3);
Vector grad_q1(dim), grad_q2(dim), grad_q3(dim);
tspec_fes->GetFE(e_id)->CalcShape(ip, shape);
tspec_fesv->GetFE(e_id)->CalcShape(ip, shape);
grad_e_c1.MultTranspose(shape, grad_q1);
grad_e_c2.MultTranspose(shape, grad_q2);
grad_e_c3.MultTranspose(shape, grad_q3);
@@ -1880,7 +1992,7 @@ void DiscreteAdaptTC::ComputeElementTargetsGradient(const IntegrationRule &ir,
grad_phys.Mult(par_vals, grad_ptr_c1);
Vector grad_q(dim);
tspec_fes->GetFE(e_id)->CalcShape(ip, shape);
tspec_fesv->GetFE(e_id)->CalcShape(ip, shape);
grad_e_c1.MultTranspose(shape, grad_q);
const double skew = shape * par_vals;
@@ -1913,7 +2025,7 @@ void DiscreteAdaptTC::ComputeElementTargetsGradient(const IntegrationRule &ir,
grad_phys.Mult(par_vals_c2, grad_ptr_c2);
grad_phys.Mult(par_vals_c3, grad_ptr_c3);
Vector grad_q1(dim), grad_q2(dim), grad_q3(dim);
tspec_fes->GetFE(e_id)->CalcShape(ip, shape);
tspec_fesv->GetFE(e_id)->CalcShape(ip, shape);
grad_e_c1.MultTranspose(shape, grad_q1);
grad_e_c2.MultTranspose(shape, grad_q2);
grad_e_c3.MultTranspose(shape, grad_q3);
@@ -1960,7 +2072,7 @@ void DiscreteAdaptTC::ComputeElementTargetsGradient(const IntegrationRule &ir,
grad_phys.Mult(par_vals, grad_ptr_c1);
Vector grad_q(dim);
tspec_fes->GetFE(e_id)->CalcShape(ip, shape);
tspec_fesv->GetFE(e_id)->CalcShape(ip, shape);
grad_e_c1.MultTranspose(shape, grad_q);
const double theta = shape * par_vals;
@@ -1991,7 +2103,7 @@ void DiscreteAdaptTC::ComputeElementTargetsGradient(const IntegrationRule &ir,
grad_phys.Mult(par_vals_c2, grad_ptr_c2);
grad_phys.Mult(par_vals_c3, grad_ptr_c3);
Vector grad_q1(dim), grad_q2(dim), grad_q3(dim);
tspec_fes->GetFE(e_id)->CalcShape(ip, shape);
tspec_fesv->GetFE(e_id)->CalcShape(ip, shape);
grad_e_c1.MultTranspose(shape, grad_q1);
grad_e_c2.MultTranspose(shape, grad_q2);
grad_e_c3.MultTranspose(shape, grad_q3);
@@ -2071,7 +2183,7 @@ void DiscreteAdaptTC::UpdateGradientTargetSpecification(const Vector &x,
{
if (use_flag && good_tspec_grad) { return; }
const int dim = tspec_fes->GetFE(0)->GetDim(),
const int dim = tspec_fesv->GetFE(0)->GetDim(),
cnt = x.Size()/dim;
tspec_pert1h.SetSize(x.Size()*ncomp);
@@ -2097,7 +2209,7 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x,
if (use_flag && good_tspec_hess) { return; }
const int dim = tspec_fes->GetFE(0)->GetDim(),
const int dim = tspec_fesv->GetFE(0)->GetDim(),
cnt = x.Size()/dim,
totmix = 1+2*(dim-2);
@@ -2145,6 +2257,16 @@ void DiscreteAdaptTC::UpdateHessianTargetSpecification(const Vector &x,
good_tspec_hess = use_flag;
}
DiscreteAdaptTC::~DiscreteAdaptTC()
{
delete tspec_gf;
delete adapt_eval;
delete tspec_fesv;
#ifdef MFEM_USE_MPI
delete ptspec_fesv;
#endif
}
void AdaptivityEvaluator::SetSerialMetaInfo(const Mesh &m,
const FiniteElementCollection &fec,
int num_comp)
@@ -2258,6 +2380,7 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &z0,
AdaptivityEvaluator &ae)
{
zeta_0 = &z0;
pzeta_0 = &z0;
delete zeta;
zeta = new GridFunction(z0);
coeff_zeta = &coeff;
@@ -2270,6 +2393,33 @@ void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &z0,
}
#endif
void TMOP_Integrator::UpdateAfterMeshTopologyChange()
{
if (zeta)
{
zeta->Update();
adapt_eval->SetSerialMetaInfo(*zeta->FESpace()->GetMesh(),
*zeta->FESpace()->FEColl(), 1);
adapt_eval->SetInitialField
(*zeta->FESpace()->GetMesh()->GetNodes(), *zeta);
}
}
#ifdef MFEM_USE_MPI
void TMOP_Integrator::ParUpdateAfterMeshTopologyChange()
{
if (zeta)
{
zeta->Update();
adapt_eval->SetParMetaInfo(*pzeta_0->ParFESpace()->GetParMesh(),
*pzeta_0->ParFESpace()->FEColl(), 1);
adapt_eval->SetInitialField
(*zeta->FESpace()->GetMesh()->GetNodes(), *zeta);
}
}
#endif
double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun)
@@ -2378,6 +2528,145 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
return energy;
}
double TMOP_Integrator::GetRefinementElementEnergy(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun,
const IntegrationRule &irule)
{
int dof = el.GetDof(), dim = el.GetDim(),
NEsplit = elfun.Size() / (dof*dim), el_id = T.ElementNo;
double energy = 0.;
TargetConstructor *tc = const_cast<TargetConstructor *>(targetC);
DiscreteAdaptTC *dtc = dynamic_cast<DiscreteAdaptTC *>(tc);
// For DiscreteAdaptTC the GridFunctions used to set the targets must be
// mapped onto the fine elements.
if (dtc) { dtc->SetTspecFromIntRule(el_id, irule); }
for (int e = 0; e < NEsplit; e++)
{
DSh.SetSize(dof, dim);
Jrt.SetSize(dim);
Jpr.SetSize(dim);
Jpt.SetSize(dim);
Vector elfun_child(dof*dim);
for (int i = 0; i < dof; i++)
{
for (int d = 0; d < dim; d++)
{
// elfun is (xe1,xe2,...xen,ye1,ye2...yen) and has nodal coordinates
// for all the children element of the parent element being considered.
// So we must index and get (xek, yek) i.e. nodal coordinates for
// the fine element being considered.
elfun_child(i + d*dof) = elfun(i + e*dof + d*dof*NEsplit);
}
}
PMatI.UseExternalData(elfun_child.GetData(), dof, dim);
const IntegrationRule &ir = EnergyIntegrationRule(el);
double el_energy = 0;
DenseTensor Jtr(dim, dim, ir.GetNPoints());
if (dtc)
{
// This is used to index into the tspec vector inside DiscreteAdaptTC.
dtc->SetRefinementSubElement(e);
}
targetC->ComputeElementTargets(el_id, el, ir, elfun_child, Jtr);
// Define ref->physical transformation, wn a Coefficient is specified.
IsoparametricTransformation *Tpr = NULL;
if (coeff1 || coeff0)
{
Tpr = new IsoparametricTransformation;
Tpr->SetFE(&el);
Tpr->ElementNo = T.ElementNo;
Tpr->ElementType = ElementTransformation::ELEMENT;
Tpr->Attribute = T.Attribute;
Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
}
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
const DenseMatrix &Jtr_i = Jtr(i);
h_metric->SetTargetJacobian(Jtr_i);
CalcInverse(Jtr_i, Jrt);
const double weight = ip.weight * Jtr_i.Det();
el.CalcDShape(ip, DSh);
MultAtB(PMatI, DSh, Jpr);
Mult(Jpr, Jrt, Jpt);
double val = metric_normal * h_metric->EvalW(Jpt);
if (coeff1) { val *= coeff1->Eval(*Tpr, ip); }
el_energy += weight * val;
delete Tpr;
}
energy += el_energy;
}
energy /= NEsplit;
if (dtc) { dtc->ResetRefinementTspecData(); }
return energy;
}
double TMOP_Integrator::GetDerefinementElementEnergy(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun)
{
int dof = el.GetDof(), dim = el.GetDim();
double energy = 0.;
DSh.SetSize(dof, dim);
Jrt.SetSize(dim);
Jpr.SetSize(dim);
Jpt.SetSize(dim);
PMatI.UseExternalData(elfun.GetData(), dof, dim);
const IntegrationRule &ir = EnergyIntegrationRule(el);
energy = 0.0;
DenseTensor Jtr(dim, dim, ir.GetNPoints());
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
// Define ref->physical transformation, wn a Coefficient is specified.
IsoparametricTransformation *Tpr = NULL;
if (coeff1)
{
Tpr = new IsoparametricTransformation;
Tpr->SetFE(&el);
Tpr->ElementNo = T.ElementNo;
Tpr->ElementType = ElementTransformation::ELEMENT;
Tpr->Attribute = T.Attribute;
Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
}
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
const DenseMatrix &Jtr_i = Jtr(i);
h_metric->SetTargetJacobian(Jtr_i);
CalcInverse(Jtr_i, Jrt);
const double weight = ip.weight * Jtr_i.Det();
el.CalcDShape(ip, DSh);
MultAtB(PMatI, DSh, Jpr);
Mult(Jpr, Jrt, Jpt);
double val = metric_normal * h_metric->EvalW(Jpt);
if (coeff1) { val *= coeff1->Eval(*Tpr, ip); }
energy += weight * val;
}
delete Tpr;
return energy;
}
void TMOP_Integrator::AssembleElementVector(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun, Vector &elvect)
@@ -3039,7 +3328,7 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x,
dx = detv_avg_min / dxscale;
}
void TMOP_Integrator::UpdateAfterMeshChange(const Vector &new_x)
void TMOP_Integrator::UpdateAfterMeshPositionChange(const Vector &new_x)
{
if (discr_tc)
{
@@ -3168,6 +3457,32 @@ void TMOPComboIntegrator::AssembleElementGrad(const FiniteElement &el,
}
}
double TMOPComboIntegrator::GetRefinementElementEnergy(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun,
const IntegrationRule &irule)
{
double energy= 0.0;
for (int i = 0; i < tmopi.Size(); i++)
{
energy += tmopi[i]->GetRefinementElementEnergy(el, T, elfun, irule);
}
return energy;
}
double TMOPComboIntegrator::GetDerefinementElementEnergy(
const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun)
{
double energy= 0.0;
for (int i = 0; i < tmopi.Size(); i++)
{
energy += tmopi[i]->GetDerefinementElementEnergy(el, T, elfun);
}
return energy;
}
void TMOPComboIntegrator::EnableNormalization(const GridFunction &x)
{
const int cnt = tmopi.Size();
+118 -16
View File
@@ -1057,14 +1057,31 @@ protected:
// eta1(x+h,y), eta2(x+h,y) ... etan(x+h,y), eta1(x,y+h), eta2(x,y+h) ...
// same for tspec_pert2h and tspec_pertmix.
// DenseMatrix to hold target_spec values for the (children of the)
// element being refined to consider for h-refinement.
DenseMatrix tspec_refine;
// Vector to hold the target_spec values for the coarse version of the
// current mesh. Used for derefinement decision with hr-adaptivity.
Vector tspec_derefine;
// Components of Target Jacobian at each quadrature point of an element. This
// is required for computation of the derivative using chain rule.
mutable DenseTensor Jtrcomp;
// Note: do not use the Nodes of this space as they may not be on the
// positions corresponding to the values of tspec.
const FiniteElementSpace *tspec_fes;
const FiniteElementSpace *tspec_fesv;
FiniteElementSpace *tspec_fesv; //owned
FiniteElementSpace *coarse_tspec_fesv; //not owned, derefinement FESpace
GridFunction *tspec_gf; //owned, uses tspec and tspec_fes
// discrete adaptivity
#ifdef MFEM_USE_MPI
ParFiniteElementSpace *ptspec_fesv; //owned, needed for derefinement to
// get update operator.
ParGridFunction *tspec_pgf; // similar to tspec_gf
#endif
int amr_el;
double lim_min_size;
// These flags can be used by outside functions to avoid recomputing the
// tspec and tspec_perth fields again on the same mesh.
@@ -1076,7 +1093,7 @@ protected:
void SetDiscreteTargetBase(const GridFunction &tspec_);
void SetTspecAtIndex(int idx, const GridFunction &tspec_);
void FinalizeSerialDiscreteTargetSpec();
void FinalizeSerialDiscreteTargetSpec(const GridFunction &tspec_);
#ifdef MFEM_USE_MPI
void SetTspecAtIndex(int idx, const ParGridFunction &tspec_);
void FinalizeParDiscreteTargetSpec(const ParGridFunction &tspec_);
@@ -1088,16 +1105,16 @@ public:
ncomp(0),
sizeidx(-1), skewidx(-1), aspectratioidx(-1), orientationidx(-1),
tspec(), tspec_sav(), tspec_pert1h(), tspec_pert2h(), tspec_pertmix(),
tspec_fes(NULL), tspec_fesv(NULL),
tspec_refine(), tspec_derefine(),
tspec_fesv(NULL), coarse_tspec_fesv(NULL), tspec_gf(NULL),
#ifdef MFEM_USE_MPI
ptspec_fesv(NULL), tspec_pgf(NULL),
#endif
amr_el(-1), lim_min_size(-0.1),
good_tspec(false), good_tspec_grad(false), good_tspec_hess(false),
adapt_eval(NULL) { }
virtual ~DiscreteAdaptTC()
{
delete adapt_eval;
delete tspec_fes;
delete tspec_fesv;
}
virtual ~DiscreteAdaptTC();
/** @name Target specification methods.
The following methods are used to specify geometric parameters of the
@@ -1128,6 +1145,20 @@ public:
void ResetUpdateFlags()
{ good_tspec = good_tspec_grad = good_tspec_hess = false; }
/// Get one of the discrete fields from tspec.
void GetDiscreteTargetSpec(GridFunction &tspec_, int idx);
/// Get the FESpace associated with tspec.
FiniteElementSpace *GetTSpecFESpace() { return tspec_fesv; }
/// Get the entire tspec.
GridFunction *GetTSpecData() { return tspec_gf; }
/// Update all discrete fields based on tspec and update for AMR
void UpdateAfterMeshTopologyChange();
#ifdef MFEM_USE_MPI
ParFiniteElementSpace *GetTSpecParFESpace() { return ptspec_fesv; }
void ParUpdateAfterMeshTopologyChange();
#endif
/** Used to update the target specification after the mesh has changed. The
new mesh positions are given by new_x. If @a use_flags is true, repeated
calls won't do anything until ResetUpdateFlags() is called. */
@@ -1184,6 +1215,36 @@ public:
const Vector &elfun,
IsoparametricTransformation &Tpr,
DenseTensor &dJtr) const;
// Generates tspec_vals for target construction using intrule
// Used for the refinement component in hr-adaptivity.
void SetTspecFromIntRule(int e_id, const IntegrationRule &intrule);
// Targets based on discrete functions can result in invalid (negative)
// size at the quadrature points. This method can be used to set a
// minimum target size.
void SetMinSizeForTargets(double min_size_) { lim_min_size = min_size_; }
/// Computes target specification data with respect to the coarse FE space.
void SetTspecDataForDerefinement(FiniteElementSpace *fes);
// Reset refinement data associated with h-adaptivity component.
void ResetRefinementTspecData()
{
tspec_refine.Clear();
amr_el = -1;
}
// Reset derefinement data associated with h-adaptivity component.
void ResetDerefinementTspecData()
{
tspec_derefine.Destroy();
coarse_tspec_fesv = NULL;
}
// Used to specify the fine element for determining energy of children of a
// parent element.
void SetRefinementSubElement(int amr_el_) { amr_el = amr_el_; }
};
class TMOPNewtonSolver;
@@ -1201,6 +1262,7 @@ protected:
friend class TMOPNewtonSolver;
friend class TMOPComboIntegrator;
TMOP_QualityMetric *h_metric;
TMOP_QualityMetric *metric; // not owned
const TargetConstructor *targetC; // not owned
@@ -1227,6 +1289,9 @@ protected:
// Adaptive limiting.
const GridFunction *zeta_0; // Not owned.
#ifdef MFEM_USE_MPI
const ParGridFunction *pzeta_0;
#endif
GridFunction *zeta; // Owned. Updated by adapt_eval.
Coefficient *coeff_zeta; // Not owned.
AdaptivityEvaluator *adapt_eval; // Not owned.
@@ -1337,7 +1402,7 @@ protected:
#endif
void ComputeMinJac(const Vector &x, const FiniteElementSpace &fes);
void UpdateAfterMeshChange(const Vector &new_x);
void UpdateAfterMeshPositionChange(const Vector &new_x);
void DisableLimiting()
{
@@ -1395,11 +1460,13 @@ protected:
void ComputeAllElementTargets(const Vector &xe = Vector()) const;
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), IntegRules(NULL), integ_order(-1),
coeff1(NULL), metric_normal(1.0),
/** @param[in] m TMOP_QualityMetric for r-adaptivity (not owned).
@param[in] tc Target-matrix construction algorithm to use (not owned).
@param[in] hm TMOP_QualityMetric for h-adaptivity (not owned). */
TMOP_Integrator(TMOP_QualityMetric *m, TargetConstructor *tc,
TMOP_QualityMetric *hm)
: h_metric(hm), 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),
zeta_0(NULL), zeta(NULL), coeff_zeta(NULL), adapt_eval(NULL),
@@ -1407,6 +1474,9 @@ public:
fdflag(false), dxscale(1.0e3), fd_call_flag(false), exact_action(false)
{ PA.enabled = false; }
TMOP_Integrator(TMOP_QualityMetric *m, TargetConstructor *tc)
: TMOP_Integrator(m, tc, m) { }
~TMOP_Integrator();
/// Release the device memory of large PA allocations. This will copy device
@@ -1478,6 +1548,22 @@ public:
ElementTransformation &T,
const Vector &elfun);
/** @brief Computes the mean of the energies of the given element's children.
In addition to the inputs for GetElementEnergy, this function requires an
IntegrationRule to be specified that will give the decomposition of the
given element based on the refinement type being considered. */
virtual double GetRefinementElementEnergy(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun,
const IntegrationRule &irule);
/// This function is similar to GetElementEnergy, but ignores components
/// such as limiting etc. to compute the element energy.
virtual double GetDerefinementElementEnergy(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun);
virtual void AssembleElementVector(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun, Vector &elvect);
@@ -1486,6 +1572,13 @@ public:
ElementTransformation &T,
const Vector &elfun, DenseMatrix &elmat);
TMOP_QualityMetric &GetAMRQualityMetric() { return *h_metric; }
void UpdateAfterMeshTopologyChange();
#ifdef MFEM_USE_MPI
void ParUpdateAfterMeshTopologyChange();
#endif
// PA extension
using NonlinearFormIntegrator::AssemblePA;
virtual void AssemblePA(const FiniteElementSpace&);
@@ -1564,6 +1657,15 @@ public:
ElementTransformation &T,
const Vector &elfun, DenseMatrix &elmat);
virtual double GetRefinementElementEnergy(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun,
const IntegrationRule &irule);
virtual double GetDerefinementElementEnergy(const FiniteElement &el,
ElementTransformation &T,
const Vector &elfun);
/// Normalization factor that considers all integrators in the combination.
void EnableNormalization(const GridFunction &x);
#ifdef MFEM_USE_MPI
+896
View File
@@ -0,0 +1,896 @@
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "tmop_amr.hpp"
namespace mfem
{
using namespace mfem;
void TMOPRefinerEstimator::ComputeEstimates()
{
bool iso = false;
bool aniso = false;
if (amrmetric == 1 || amrmetric == 2 || amrmetric == 58)
{
aniso = true;
}
if (amrmetric == 55 || amrmetric == 56 || amrmetric == 77 ||
amrmetric == 315 || amrmetric == 316 || amrmetric == 321)
{
iso = true;
}
if (amrmetric == 7 || amrmetric == 9)
{
iso = true; aniso = true;
}
MFEM_VERIFY(iso || aniso, "Metric type not supported in hr-adaptivity.");
const int dim = mesh->Dimension();
const int num_ref_types = 3 + 4*(dim-2);
const int NEorig = mesh->GetNE();
aniso_flags.SetSize(NEorig);
error_estimates.SetSize(NEorig);
Vector amr_base_energy(NEorig), amr_temp_energy(NEorig);
error_estimates = 1.*std::numeric_limits<float>::max();
aniso_flags = -1;
GetTMOPRefinementEnergy(0, amr_base_energy);
for (int i = 1; i < num_ref_types+1; i++)
{
if ( dim == 2 && i < 3 && aniso != true ) { continue; }
if ( dim == 2 && i == 3 && iso != true ) { continue; }
if ( dim == 3 && i < 7 && aniso != true ) { continue; }
if ( dim == 3 && i == 7 && iso != true ) { continue; }
GetTMOPRefinementEnergy(i, amr_temp_energy);
for (int e = 0; e < NEorig; e++)
{
if ( amr_temp_energy(e) < error_estimates(e) )
{
error_estimates(e) = amr_temp_energy(e);
aniso_flags[e] = i;
}
}
}
error_estimates *= energy_scaling_factor;
if (spat_gf)
{
L2_FECollection avg_fec(0, mesh->Dimension());
FiniteElementSpace avg_fes(spat_gf->FESpace()->GetMesh(), &avg_fec);
GridFunction elem_avg(&avg_fes);
spat_gf->GetElementAverages(elem_avg);
for (int i = 0; i < amr_base_energy.Size(); i++)
{
if (elem_avg(i) < spat_gf_critical) { amr_base_energy(i) = 0.; }
}
}
error_estimates -= amr_base_energy;
error_estimates *= -1; // error = E(parent) - scaling_factor*mean(E(children))
current_sequence = mesh->GetSequence();
}
void TMOPRefinerEstimator::GetTMOPRefinementEnergy(int reftype,
Vector &el_energy_vec)
{
const FiniteElementSpace *fes = mesh->GetNodalFESpace();
const int NE = fes->GetNE();
GridFunction *xdof = mesh->GetNodes();
xdof->SetTrueVector();
xdof->SetFromTrueVector();
el_energy_vec.SetSize(NE);
el_energy_vec = std::numeric_limits<float>::max();
for (int e = 0; e < NE; e++)
{
Geometry::Type gtype = fes->GetFE(e)->GetGeomType();
DenseMatrix tr, xsplit;
IntegrationRule *irule = NULL;
if ( (gtype == Geometry::TRIANGLE && reftype > 0 && reftype < 3) ||
(gtype == Geometry::CUBE && reftype > 0 && reftype < 7) ||
(gtype == Geometry::TETRAHEDRON && reftype > 0 && reftype < 7) )
{
continue;
}
switch (gtype)
{
case Geometry::TRIANGLE:
{
int ref_access = reftype == 0 ? 0 : 1;
xdof->GetVectorValues(e, *TriIntRule[ref_access], xsplit, tr);
irule = TriIntRule[ref_access];
break;
}
case Geometry::TETRAHEDRON:
{
int ref_access = reftype == 0 ? 0 : 1;
xdof->GetVectorValues(e, *TetIntRule[ref_access], xsplit, tr);
irule = TetIntRule[ref_access];
break;
}
case Geometry::SQUARE:
{
MFEM_VERIFY(QuadIntRule[reftype], " Integration rule does not exist.");
xdof->GetVectorValues(e, *QuadIntRule[reftype], xsplit, tr);
irule = QuadIntRule[reftype];
break;
}
case Geometry::CUBE:
{
int ref_access = reftype == 0 ? 0 : 1;
xdof->GetVectorValues(e, *HexIntRule[ref_access], xsplit, tr);
irule = HexIntRule[ref_access];
break;
}
default:
MFEM_ABORT("Incompatible geometry type!");
}
xsplit.Transpose();
el_energy_vec(e) = 0.; // Re-set to 0
// The data format is xe1,xe2,..xen,ye1,ye2..yen.
// We will reformat it inside GetRefinementElementEnergy
Vector elfun(xsplit.GetData(), xsplit.NumCols()*xsplit.NumRows());
Array<NonlinearFormIntegrator*> &integs = *(nlf->GetDNFI());
TMOP_Integrator *ti = NULL;
TMOPComboIntegrator *co = NULL;
for (int i = 0; i < integs.Size(); i++)
{
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
if (ti)
{
el_energy_vec(e) = ti->GetRefinementElementEnergy(*fes->GetFE(e),
*mesh->GetElementTransformation(e),
elfun,
*irule);
}
co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
if (co)
{
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
for (int j = 0; j < ati.Size(); j++)
{
el_energy_vec(e) += ati[j]->GetRefinementElementEnergy(*fes->GetFE(e),
*mesh->GetElementTransformation(e),
elfun,
*irule);
}
}
}
}
}
void TMOPRefinerEstimator::SetHexIntRules()
{
HexIntRule.SetSize(1+1);
// Reftype = 0 -> original element
Mesh meshsplit = Mesh::MakeCartesian3D(1, 1, 1, Element::HEXAHEDRON);
Mesh base_mesh_copy(meshsplit);
HexIntRule[0] = SetIntRulesFromMesh(meshsplit);
meshsplit.Clear();
// Reftype = 7
for (int i = 7; i < 8; i++)
{
Array<Refinement> marked_elements;
Mesh mesh_ref(base_mesh_copy);
for (int e = 0; e < mesh_ref.GetNE(); e++)
{
marked_elements.Append(Refinement(e, i));
}
mesh_ref.GeneralRefinement(marked_elements, 1, 0);
HexIntRule[1] = SetIntRulesFromMesh(mesh_ref);
mesh_ref.Clear();
}
}
void TMOPRefinerEstimator::SetQuadIntRules()
{
QuadIntRule.SetSize(3+1);
// Reftype = 0 -> original element
Mesh meshsplit = Mesh::MakeCartesian2D(1, 1, Element::QUADRILATERAL);
Mesh base_mesh_copy(meshsplit);
QuadIntRule[0] = SetIntRulesFromMesh(meshsplit);
meshsplit.Clear();
// Reftype = 1-3
for (int i = 1; i < 4; i++)
{
Array<Refinement> marked_elements;
Mesh mesh_ref(base_mesh_copy);
for (int e = 0; e < mesh_ref.GetNE(); e++)
{
marked_elements.Append(Refinement(e, i));
}
mesh_ref.GeneralRefinement(marked_elements, 1, 0);
QuadIntRule[i] = SetIntRulesFromMesh(mesh_ref);
mesh_ref.Clear();
}
}
void TMOPRefinerEstimator::SetTriIntRules()
{
TriIntRule.SetSize(1+1);
// Reftype = 0 // original element
const int Nvert = 3, NEsplit = 1;
Mesh meshsplit(2, Nvert, NEsplit, 0 ,2);
const double tri_v[3][2] =
{
{0, 0}, {1, 0}, {0, 1}
};
const int tri_e[1][3] =
{
{0, 1, 2}
};
for (int j = 0; j < Nvert; j++)
{
meshsplit.AddVertex(tri_v[j]);
}
meshsplit.AddTriangle(tri_e[0], 1);
meshsplit.FinalizeTriMesh(1, 1, true);
Mesh base_mesh_copy(meshsplit);
TriIntRule[0] = SetIntRulesFromMesh(meshsplit);
meshsplit.Clear();
// no anisotropic refinements for triangle
// Reftype = 3
for (int i = 1; i < 2; i++)
{
Array<Refinement> marked_elements;
Mesh mesh_ref(base_mesh_copy);
for (int e = 0; e < mesh_ref.GetNE(); e++)
{
marked_elements.Append(Refinement(e, i));
}
mesh_ref.GeneralRefinement(marked_elements, 1, 0);
TriIntRule[i] = SetIntRulesFromMesh(mesh_ref);
mesh_ref.Clear();
}
}
void TMOPRefinerEstimator::SetTetIntRules()
{
TetIntRule.SetSize(1+1);
// Reftype = 0 // original element
const int Nvert = 4, NEsplit = 1;
Mesh meshsplit(3, Nvert, NEsplit, 0, 3);
const double tet_v[4][3] =
{
{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {0, 0, 1}
};
const int tet_e[1][4] =
{
{0, 1, 2, 3}
};
for (int j = 0; j < Nvert; j++)
{
meshsplit.AddVertex(tet_v[j]);
}
meshsplit.AddTet(tet_e[0], 1);
meshsplit.FinalizeTetMesh(1, 1, true);
Mesh base_mesh_copy(meshsplit);
TetIntRule[0] = SetIntRulesFromMesh(meshsplit);
meshsplit.Clear();
// no anisotropic refinements for triangle
// Reftype = 7
for (int i = 1; i < 2; i++)
{
Array<Refinement> marked_elements;
Mesh mesh_ref(base_mesh_copy);
for (int e = 0; e < mesh_ref.GetNE(); e++)
{
marked_elements.Append(Refinement(e, i)); //ref_type will default to 7
}
mesh_ref.GeneralRefinement(marked_elements, 1, 0);
TetIntRule[i] = SetIntRulesFromMesh(mesh_ref);
mesh_ref.Clear();
}
}
IntegrationRule* TMOPRefinerEstimator::SetIntRulesFromMesh(Mesh &meshsplit)
{
const int dim = meshsplit.Dimension();
H1_FECollection fec(order, dim);
FiniteElementSpace nodal_fes(&meshsplit, &fec, dim);
meshsplit.SetNodalFESpace(&nodal_fes);
const int NEsplit = meshsplit.GetNE();
const int dof_cnt = nodal_fes.GetFE(0)->GetDof(),
pts_cnt = NEsplit * dof_cnt;
DenseMatrix pos(dof_cnt, dim);
Vector posV(pos.Data(), dof_cnt * dim);
Array<int> xdofs(dof_cnt * dim);
// Create an IntegrationRule on the nodes of the reference submesh.
IntegrationRule *irule = new IntegrationRule(pts_cnt);
GridFunction *nodesplit = meshsplit.GetNodes();
int pt_id = 0;
for (int i = 0; i < NEsplit; i++)
{
nodal_fes.GetElementVDofs(i, xdofs);
nodesplit->GetSubVector(xdofs, posV);
for (int j = 0; j < dof_cnt; j++)
{
if (dim == 2)
{
irule->IntPoint(pt_id).Set2(pos(j, 0), pos(j, 1));
}
else if (dim == 3)
{
irule->IntPoint(pt_id).Set3(pos(j, 0), pos(j, 1), pos(j, 2));
}
pt_id++;
}
}
return irule;
}
bool TMOPDeRefinerEstimator::GetDerefineEnergyForIntegrator(
TMOP_Integrator &tmopi,
Vector &fine_energy)
{
DiscreteAdaptTC *tcd = tmopi.GetDiscreteAdaptTC();
fine_energy.SetSize(mesh->GetNE());
if (serial)
{
Mesh meshcopy(*mesh);
FiniteElementSpace *tcdfes = NULL;
if (tcd)
{
tcdfes = new FiniteElementSpace(*tcd->GetTSpecFESpace(), &meshcopy);
}
Vector local_err(meshcopy.GetNE());
local_err = 0.;
double threshold = std::numeric_limits<float>::max();
meshcopy.DerefineByError(local_err, threshold, 0, 1);
if (meshcopy.GetGlobalNE() == mesh->GetGlobalNE())
{
delete tcdfes;
return false;
}
if (tcd)
{
tcdfes->Update();
tcd->SetTspecDataForDerefinement(tcdfes);
}
Vector coarse_energy(meshcopy.GetNE());
GetTMOPDerefinementEnergy(meshcopy, tmopi, coarse_energy);
if (tcd) { tcd->ResetDerefinementTspecData(); }
GetTMOPDerefinementEnergy(*mesh, tmopi, fine_energy);
const CoarseFineTransformations &dtrans =
meshcopy.ncmesh->GetDerefinementTransforms();
Table coarse_to_fine;
dtrans.GetCoarseToFineMap(meshcopy, coarse_to_fine);
for (int pe = 0; pe < coarse_to_fine.Size(); pe++)
{
Array<int> tabrow;
coarse_to_fine.GetRow(pe, tabrow);
int nchild = tabrow.Size();
double parent_energy = coarse_energy(pe);
for (int fe = 0; fe < nchild; fe++)
{
int child = tabrow[fe];
MFEM_VERIFY(child < mesh->GetNE(), " invalid coarse to fine mapping");
fine_energy(child) -= parent_energy;
}
}
delete tcdfes;
}
else
{
#ifdef MFEM_USE_MPI
ParMesh meshcopy(*pmesh);
ParFiniteElementSpace *tcdfes = NULL;
if (tcd)
{
tcdfes = new ParFiniteElementSpace(*tcd->GetTSpecParFESpace(), meshcopy);
}
Vector local_err(meshcopy.GetNE());
local_err = 0.;
double threshold = std::numeric_limits<float>::max();
meshcopy.DerefineByError(local_err, threshold, 0, 1);
if (meshcopy.GetGlobalNE() == pmesh->GetGlobalNE())
{
delete tcdfes;
return false;
}
if (tcd)
{
tcdfes->Update();
tcd->SetTspecDataForDerefinement(tcdfes);
}
Vector coarse_energy(meshcopy.GetNE());
GetTMOPDerefinementEnergy(meshcopy, tmopi, coarse_energy);
if (tcd) { tcd->ResetDerefinementTspecData(); }
GetTMOPDerefinementEnergy(*pmesh, tmopi, fine_energy);
const CoarseFineTransformations &dtrans =
meshcopy.pncmesh->GetDerefinementTransforms();
Table coarse_to_fine;
dtrans.GetCoarseToFineMap(meshcopy, coarse_to_fine);
for (int pe = 0; pe < meshcopy.GetNE(); pe++)
{
Array<int> tabrow;
coarse_to_fine.GetRow(pe, tabrow);
int nchild = tabrow.Size();
double parent_energy = coarse_energy(pe);
for (int fe = 0; fe < nchild; fe++)
{
int child = tabrow[fe];
MFEM_VERIFY(child < pmesh->GetNE(), " invalid coarse to fine mapping");
fine_energy(child) -= parent_energy;
}
}
delete tcdfes;
#endif
}
// error_estimate(e) = energy(parent_of_e)-energy(e)
// Negative energy means derefinement is desirable.
fine_energy *= -1;
return true;
}
void TMOPDeRefinerEstimator::ComputeEstimates()
{
Array<NonlinearFormIntegrator*> &integs = *(nlf->GetDNFI());
TMOP_Integrator *ti = NULL;
TMOPComboIntegrator *co = NULL;
error_estimates.SetSize(mesh->GetNE());
error_estimates = 0.;
Vector fine_energy(mesh->GetNE());
for (int i = 0; i < integs.Size(); i++)
{
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
if (ti)
{
bool deref = GetDerefineEnergyForIntegrator(*ti, fine_energy);
if (!deref) { error_estimates = 1; return; }
error_estimates += fine_energy;
}
co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
if (co)
{
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
for (int j = 0; j < ati.Size(); j++)
{
bool deref = GetDerefineEnergyForIntegrator(*ati[j], fine_energy);
if (!deref) { error_estimates = 1; return; }
error_estimates += fine_energy;
}
}
}
}
void TMOPDeRefinerEstimator::GetTMOPDerefinementEnergy(Mesh &cmesh,
TMOP_Integrator &tmopi,
Vector &el_energy_vec)
{
const int cNE = cmesh.GetNE();
el_energy_vec.SetSize(cNE);
const FiniteElementSpace *fespace = cmesh.GetNodalFESpace();
GridFunction *cxdof = cmesh.GetNodes();
Array<int> vdofs;
Vector el_x;
const FiniteElement *fe;
ElementTransformation *T;
for (int j = 0; j < cNE; j++)
{
fe = fespace->GetFE(j);
fespace->GetElementVDofs(j, vdofs);
T = cmesh.GetElementTransformation(j);
cxdof->GetSubVector(vdofs, el_x);
el_energy_vec(j) = tmopi.GetDerefinementElementEnergy(*fe, *T, el_x);
}
}
TMOPHRSolver::TMOPHRSolver(Mesh &mesh_, NonlinearForm &nlf_,
TMOPNewtonSolver &tmopns_, GridFunction &x_,
bool move_bnd_, bool hradaptivity_,
int mesh_poly_deg_, int amr_metric_id_,
int hr_iter_, int h_per_r_iter_) :
mesh(&mesh_), nlf(&nlf_), tmopns(&tmopns_), x(&x_),
gridfuncarr(), fespacearr(),
move_bnd(move_bnd_), hradaptivity(hradaptivity_),
mesh_poly_deg(mesh_poly_deg_), amr_metric_id(amr_metric_id_),
serial(true), hr_iter(hr_iter_), h_per_r_iter(h_per_r_iter_)
{
if (!hradaptivity) { return; }
tmop_r_est = new TMOPRefinerEstimator(*mesh, *nlf, mesh_poly_deg,
amr_metric_id);
tmop_r = new ThresholdRefiner(*tmop_r_est);
tmop_r->SetTotalErrorFraction(0.0);
tmop_r_est->SetEnergyScalingFactor(1.);
tmop_dr_est= new TMOPDeRefinerEstimator(*mesh, *nlf);
tmop_dr = new ThresholdDerefiner(*tmop_dr_est);
AddGridFunctionForUpdate(x);
}
#ifdef MFEM_USE_MPI
TMOPHRSolver::TMOPHRSolver(ParMesh &pmesh_, ParNonlinearForm &pnlf_,
TMOPNewtonSolver &tmopns_, ParGridFunction &px_,
bool move_bnd_, bool hradaptivity_,
int mesh_poly_deg_, int amr_metric_id_,
int hr_iter_, int h_per_r_iter_) :
mesh(&pmesh_), nlf(&pnlf_), tmopns(&tmopns_), x(&px_),
gridfuncarr(), fespacearr(),
move_bnd(move_bnd_), hradaptivity(hradaptivity_),
mesh_poly_deg(mesh_poly_deg_), amr_metric_id(amr_metric_id_),
pmesh(&pmesh_), pnlf(&pnlf_), pgridfuncarr(), pfespacearr(),
serial(false), hr_iter(hr_iter_), h_per_r_iter(h_per_r_iter_)
{
if (!hradaptivity) { return; }
tmop_r_est = new TMOPRefinerEstimator(*pmesh, *pnlf, mesh_poly_deg,
amr_metric_id);
tmop_r = new ThresholdRefiner(*tmop_r_est);
tmop_r->SetTotalErrorFraction(0.0);
tmop_r_est->SetEnergyScalingFactor(1.);
tmop_dr_est= new TMOPDeRefinerEstimator(*pmesh, *pnlf);
tmop_dr = new ThresholdDerefiner(*tmop_dr_est);
AddGridFunctionForUpdate(&px_);
}
#endif
void TMOPHRSolver::Mult()
{
Vector b(0);
int myid = 0;
if (serial)
{
tmopns->SetOperator(*nlf);
}
else
{
#ifdef MFEM_USE_MPI
myid = pnlf->ParFESpace()->GetMyRank();
tmopns->SetOperator(*pnlf);
#endif
}
if (!hradaptivity)
{
tmopns->Mult(b, x->GetTrueVector());
if (tmopns->GetConverged() == false)
{
if (myid == 0) { mfem::out << "Nonlinear solver: rtol not achieved.\n"; }
}
x->SetFromTrueVector();
return;
}
bool radaptivity = true;
tmop_dr->Reset();
tmop_r->Reset();
if (serial)
{
for (int i_hr = 0; i_hr < hr_iter; i_hr++)
{
if (!radaptivity)
{
break;
}
mfem::out << i_hr << " r-adaptivity iteration.\n";
tmopns->SetOperator(*nlf);
tmopns->Mult(b, x->GetTrueVector());
x->SetFromTrueVector();
mfem::out << "TMOP energy after r-adaptivity: " <<
nlf->GetGridFunctionEnergy(*x)/mesh->GetNE() <<
", Elements: " << mesh->GetNE() << std::endl;
for (int i_h = 0; i_h < h_per_r_iter; i_h++)
{
// Derefinement step.
if (mesh->ncmesh)
{
tmop_dr->Apply(*mesh);
Update();
}
mfem::out << "TMOP energy after derefinement: " <<
nlf->GetGridFunctionEnergy(*x)/mesh->GetNE() <<
", Elements: " << mesh->GetNE() << std::endl;
// Refinement step.
tmop_r->Apply(*mesh);
Update();
mfem::out << "TMOP energy after refinement: " <<
nlf->GetGridFunctionEnergy(*x)/mesh->GetNE() <<
", Elements: " << mesh->GetNE() << std::endl;
if (!tmop_dr->Derefined() && tmop_r->Stop())
{
radaptivity = false;
mfem::out << "AMR stopping criterion satisfied. Stop.\n";
break;
}
} //n_h
} //n_hr
}
else
{
#ifdef MFEM_USE_MPI
int NEGlob;
double tmopenergy;
for (int i_hr = 0; i_hr < hr_iter; i_hr++)
{
if (!radaptivity)
{
break;
}
if (myid == 0) { mfem::out << i_hr << " r-adaptivity iteration.\n"; }
tmopns->SetOperator(*pnlf);
tmopns->Mult(b, x->GetTrueVector());
x->SetFromTrueVector();
NEGlob = pmesh->GetGlobalNE();
tmopenergy = pnlf->GetParGridFunctionEnergy(*x) / NEGlob;
if (myid == 0)
{
mfem::out << "TMOP energy after r-adaptivity: " << tmopenergy <<
", Elements: " << NEGlob << std::endl;
}
for (int i_h = 0; i_h < h_per_r_iter; i_h++)
{
// Derefinement step.
if (pmesh->pncmesh)
{
RebalanceParNCMesh();
ParUpdate();
tmop_dr->Apply(*pmesh);
ParUpdate();
}
NEGlob = pmesh->GetGlobalNE();
tmopenergy = pnlf->GetParGridFunctionEnergy(*x) / NEGlob;
if (myid == 0)
{
mfem::out << "TMOP energy after derefinement: " << tmopenergy <<
", Elements: " << NEGlob << std::endl;
}
// Refinement step.
tmop_r->Apply(*pmesh);
ParUpdate();
NEGlob = pmesh->GetGlobalNE();
tmopenergy = pnlf->GetParGridFunctionEnergy(*x) / NEGlob;
if (myid == 0)
{
mfem::out << "TMOP energy after refinement: " << tmopenergy <<
", Elements: " << NEGlob << std::endl;
}
if (!tmop_dr->Derefined() && tmop_r->Stop())
{
radaptivity = false;
if (myid == 0)
{
mfem::out << "AMR stopping criterion satisfied. Stop.\n";
}
break;
}
} //n_r limit
} //n_hr
#endif
}
}
#ifdef MFEM_USE_MPI
void TMOPHRSolver::RebalanceParNCMesh()
{
ParNCMesh *pncmesh = pmesh->pncmesh;
if (pncmesh)
{
const Table &dreftable = pncmesh->GetDerefinementTable();
Array<int> drefs, new_ranks;
for (int i = 0; i < dreftable.Size(); i++)
{
drefs.Append(i);
}
pncmesh->GetFineToCoarsePartitioning(drefs, new_ranks);
pmesh->Rebalance(new_ranks);
}
}
#endif
void TMOPHRSolver::Update()
{
// Update FESpace
for (int i = 0; i < fespacearr.Size(); i++)
{
fespacearr[i]->Update();
}
// Update nodal GF
for (int i = 0; i < gridfuncarr.Size(); i++)
{
gridfuncarr[i]->Update();
gridfuncarr[i]->SetTrueVector();
gridfuncarr[i]->SetFromTrueVector();
}
// Update Discrete Indicator for all the TMOP_Integrators in NonLinearForm
Array<NonlinearFormIntegrator*> &integs = *(nlf->GetDNFI());
TMOP_Integrator *ti = NULL;
TMOPComboIntegrator *co = NULL;
DiscreteAdaptTC *dtc = NULL;
for (int i = 0; i < integs.Size(); i++)
{
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
if (ti)
{
ti->UpdateAfterMeshTopologyChange();
dtc = ti->GetDiscreteAdaptTC();
if (dtc) { dtc->UpdateAfterMeshTopologyChange(); }
}
co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
if (co)
{
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
for (int j = 0; j < ati.Size(); j++)
{
ati[j]->UpdateAfterMeshTopologyChange();
dtc = ati[j]->GetDiscreteAdaptTC();
if (dtc) { dtc->UpdateAfterMeshTopologyChange(); }
}
}
}
// Update the Nonlinear form and set Essential BC.
UpdateNonlinearFormAndBC(mesh, nlf);
}
#ifdef MFEM_USE_MPI
void TMOPHRSolver::ParUpdate()
{
// Update FESpace
for (int i = 0; i < pfespacearr.Size(); i++)
{
pfespacearr[i]->Update();
}
// Update nodal GF
for (int i = 0; i < pgridfuncarr.Size(); i++)
{
pgridfuncarr[i]->Update();
pgridfuncarr[i]->SetTrueVector();
pgridfuncarr[i]->SetFromTrueVector();
}
// Update Discrete Indicator
Array<NonlinearFormIntegrator*> &integs = *(nlf->GetDNFI());
TMOP_Integrator *ti = NULL;
TMOPComboIntegrator *co = NULL;
DiscreteAdaptTC *dtc = NULL;
for (int i = 0; i < integs.Size(); i++)
{
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
if (ti)
{
ti->ParUpdateAfterMeshTopologyChange();
dtc = ti->GetDiscreteAdaptTC();
if (dtc) { dtc->ParUpdateAfterMeshTopologyChange(); }
}
co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
if (co)
{
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
for (int j = 0; j < ati.Size(); j++)
{
ati[j]->ParUpdateAfterMeshTopologyChange();
dtc = ati[j]->GetDiscreteAdaptTC();
if (dtc) { dtc->ParUpdateAfterMeshTopologyChange(); }
}
}
}
// Update the Nonlinear form and set Essential BC.
UpdateNonlinearFormAndBC(pmesh, pnlf);
}
#endif
void TMOPHRSolver::UpdateNonlinearFormAndBC(Mesh *mesh, NonlinearForm *nlf)
{
const FiniteElementSpace &fes = *mesh->GetNodalFESpace();
// Update Nonlinear form and Set Essential BC
nlf->Update();
const int dim = fes.GetFE(0)->GetDim();
if (move_bnd == false)
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
nlf->SetEssentialBC(ess_bdr);
}
else
{
const int nd = fes.GetBE(0)->GetDof();
int n = 0;
for (int i = 0; i < mesh->GetNBE(); i++)
{
const int attr = mesh->GetBdrElement(i)->GetAttribute();
MFEM_VERIFY(!(dim == 2 && attr == 3),
"Boundary attribute 3 must be used only for 3D meshes. "
"Adjust the attributes (1/2/3/4 for fixed x/y/z/all "
"components, rest for free nodes), or use -fix-bnd.");
if (attr == 1 || attr == 2 || attr == 3) { n += nd; }
if (attr == 4) { n += nd * dim; }
}
Array<int> ess_vdofs(n), vdofs;
n = 0;
for (int i = 0; i < mesh->GetNBE(); i++)
{
const int attr = mesh->GetBdrElement(i)->GetAttribute();
fes.GetBdrElementVDofs(i, vdofs);
if (attr == 1) // Fix x components.
{
for (int j = 0; j < nd; j++)
{ ess_vdofs[n++] = vdofs[j]; }
}
else if (attr == 2) // Fix y components.
{
for (int j = 0; j < nd; j++)
{ ess_vdofs[n++] = vdofs[j+nd]; }
}
else if (attr == 3) // Fix z components.
{
for (int j = 0; j < nd; j++)
{ ess_vdofs[n++] = vdofs[j+2*nd]; }
}
else if (attr == 4) // Fix all components.
{
for (int j = 0; j < vdofs.Size(); j++)
{ ess_vdofs[n++] = vdofs[j]; }
}
}
nlf->SetEssentialVDofs(ess_vdofs);
}
}
}
+284
View File
@@ -0,0 +1,284 @@
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_TMOP_AMR_HPP
#define MFEM_TMOP_AMR_HPP
#include "tmop_tools.hpp"
#include "nonlinearform.hpp"
#include "pnonlinearform.hpp"
#include "estimators.hpp"
#include "../mesh/mesh_operators.hpp"
namespace mfem
{
class TMOPRefinerEstimator : public AnisotropicErrorEstimator
{
protected:
Mesh *mesh; // not owned
NonlinearForm *nlf; // not owned
int order;
int amrmetric;
Array<IntegrationRule *> TriIntRule, QuadIntRule, TetIntRule, HexIntRule;
long current_sequence;
Vector error_estimates;
Array<int> aniso_flags;
// An element is refined only if
// [mean TMOPEnergy(children)]*energy_scaling_factor < TMOPEnergy(parent)
double energy_scaling_factor;
GridFunction *spat_gf; // If specified, can be used to specify the
double spat_gf_critical; // region where hr-adaptivity is done.
/// Check if the mesh of the solution was modified.
bool MeshIsModified()
{
long mesh_sequence = mesh->GetSequence();
MFEM_ASSERT(mesh_sequence >= current_sequence, "");
return (mesh_sequence > current_sequence);
}
/// Compute the element error estimates. For an element E in the mesh,
/// error(E) = TMOPEnergy(E)*energy_scaling_factor-Mean(TMOPEnergy(ChildofE)),
/// where TMOPEnergy of Children of E is obtained by assuming the element E
/// is refined using the refinement type being considered based on the TMOP
/// mesh quality metric.
void ComputeEstimates();
/// Construct the integration rules to model how each element type is split
/// using different refinement types. ref_type = 0 is the original element
/// and reftype \ in [1, 7] represent different refinement type based on
/// NCMesh class.
void SetQuadIntRules(); // supports ref_type = 1 to 3.
void SetTriIntRules(); // currently supports only isotropic refinement.
void SetHexIntRules(); // currently supports only isotropic refinement.
void SetTetIntRules(); // currently supports only isotropic refinement.
/// Get TMOP energy for each element corresponding to the refinement type
/// specified.
void GetTMOPRefinementEnergy(int reftype, Vector &el_energy_vec);
/// Use a mesh to setup an integration rule that will mimic the different
/// refinement types.
IntegrationRule* SetIntRulesFromMesh(Mesh &meshsplit);
public:
TMOPRefinerEstimator(Mesh &mesh_, NonlinearForm &nlf_, int order_,
int amrmetric_) :
mesh(&mesh_), nlf(&nlf_), order(order_), amrmetric(amrmetric_),
TriIntRule(0), QuadIntRule(0), TetIntRule(0), HexIntRule(0),
current_sequence(-1), error_estimates(), aniso_flags(),
energy_scaling_factor(1.), spat_gf(NULL), spat_gf_critical(0.)
{
if (mesh->Dimension() == 2)
{
SetQuadIntRules();
SetTriIntRules();
}
else
{
SetHexIntRules();
SetTetIntRules();
}
}
~TMOPRefinerEstimator()
{
for (int i = 0; i < QuadIntRule.Size(); i++) { delete QuadIntRule[i]; }
for (int i = 0; i < TriIntRule.Size(); i++) { delete TriIntRule[i]; }
for (int i = 0; i < HexIntRule.Size(); i++) { delete HexIntRule[i]; }
for (int i = 0; i < TetIntRule.Size(); i++) { delete TetIntRule[i]; }
}
/// Get TMOP-based errors for each element in the mesh computed based on the
/// refinement types being considered.
virtual const Vector &GetLocalErrors()
{
if (MeshIsModified()) { ComputeEstimates(); }
return error_estimates;
}
/// For anisotropic refinements, get the refinement type (e.g., x or y)
virtual const Array<int> &GetAnisotropicFlags()
{
if (MeshIsModified()) { ComputeEstimates(); }
return aniso_flags;
}
/// Scaling factor for the TMOP refinement energy. An element is refined if
/// [mean TMOPEnergy(children)]*energy_scaling_factor < TMOPEnergy(parent)
void SetEnergyScalingFactor(double scale) { energy_scaling_factor = scale; }
/// Spatial indicator function (eta) that can be used to prevent elements
/// from being refined even if the energy criterion is met. Using this,
/// an element E is not refined if mean(@a spat_gf(E)) < @a spat_gf_critical.
void SetSpatialIndicator(GridFunction &spat_gf_,
double spat_gf_critical_ = 0.5)
{ spat_gf = &spat_gf_; spat_gf_critical = spat_gf_critical_; }
void SetSpatialIndicatorCritical(double val_) { spat_gf_critical = val_; }
/// Reset the error estimator.
virtual void Reset() { current_sequence = -1; }
};
class TMOPDeRefinerEstimator : public ErrorEstimator
{
protected:
Mesh *mesh;
NonlinearForm *nlf;
#ifdef MFEM_USE_MPI
ParMesh *pmesh;
ParNonlinearForm *pnlf;
#endif
int order;
int amrmetric;
long current_sequence;
Vector error_estimates;
bool serial;
/// Check if the mesh of the solution was modified.
bool MeshIsModified()
{
long mesh_sequence = mesh->GetSequence();
MFEM_ASSERT(mesh_sequence >= current_sequence, "");
return (mesh_sequence > current_sequence);
}
/// Compute the element error estimates. For a given element E in the mesh,
/// error(E) = TMOPEnergy(parent_of_E)-TMOPEnergy(E). Children element of an
/// element are derefined if the mean TMOP energy of children is greated than
/// the TMOP energy associated with their parent.
void ComputeEstimates();
void GetTMOPDerefinementEnergy(Mesh &cmesh,
TMOP_Integrator &tmopi,
Vector &el_energy_vec);
bool GetDerefineEnergyForIntegrator(TMOP_Integrator &tmopi,
Vector &fine_energy);
public:
TMOPDeRefinerEstimator(Mesh &mesh_, NonlinearForm &nlf_) :
mesh(&mesh_), nlf(&nlf_),
current_sequence(-1), error_estimates(), serial(true) { }
#ifdef MFEM_USE_MPI
TMOPDeRefinerEstimator(ParMesh &pmesh_, ParNonlinearForm &pnlf_) :
mesh(&pmesh_), nlf(&pnlf_), pmesh(&pmesh_), pnlf(&pnlf_),
current_sequence(-1), error_estimates(), serial(false) { }
#endif
~TMOPDeRefinerEstimator() { }
virtual const Vector &GetLocalErrors()
{
if (MeshIsModified()) { ComputeEstimates(); }
return error_estimates;
}
/// Reset the error estimator.
virtual void Reset() { current_sequence = -1; }
};
// hr-adaptivity using TMOP.
// If hr-adaptivity is disabled, r-adaptivity is done once using the
// TMOPNewtonSolver.
// Otherwise, "hr_iter" iterations of r-adaptivity are done followed by
// "h_per_r_iter" iterations of h-adaptivity after each r-adaptivity iteration.
// The solver terminates early if an h-adaptivity iteration does not
// refine/derefine any element in the mesh.
class TMOPHRSolver
{
protected:
Mesh *mesh;
NonlinearForm *nlf;
TMOPNewtonSolver *tmopns;
GridFunction *x;
Array<GridFunction *> gridfuncarr;
Array<FiniteElementSpace *> fespacearr;
bool move_bnd, hradaptivity;
const int mesh_poly_deg, amr_metric_id;
#ifdef MFEM_USE_MPI
ParMesh *pmesh;
ParNonlinearForm *pnlf;
Array<ParGridFunction *> pgridfuncarr;
Array<ParFiniteElementSpace *> pfespacearr;
#endif
bool serial;
// All are owned.
TMOPRefinerEstimator *tmop_r_est;
ThresholdRefiner *tmop_r;
TMOPDeRefinerEstimator *tmop_dr_est;
ThresholdDerefiner *tmop_dr;
int hr_iter, h_per_r_iter;
void Update();
#ifdef MFEM_USE_MPI
void ParUpdate();
#endif
void UpdateNonlinearFormAndBC(Mesh *mesh, NonlinearForm *nlf);
#ifdef MFEM_USE_MPI
// Rebalance ParMesh such that all the children elements are moved to the same
// MPI rank where the parent will be if the mesh were to be derefined.
void RebalanceParNCMesh();
#endif
public:
TMOPHRSolver(Mesh &mesh_, NonlinearForm &nlf_,
TMOPNewtonSolver &tmopns_, GridFunction &x_,
bool move_bnd_, bool hradaptivity_,
int mesh_poly_deg_, int amr_metric_id_,
int hr_iter_ = 5, int h_per_r_iter_ = 1);
#ifdef MFEM_USE_MPI
TMOPHRSolver(ParMesh &pmesh_, ParNonlinearForm &pnlf_,
TMOPNewtonSolver &tmopns_, ParGridFunction &x_,
bool move_bnd_, bool hradaptivity_,
int mesh_poly_deg_, int amr_metric_id_,
int hr_iter_ = 5, int h_per_r_iter_ = 1);
#endif
void Mult();
/// These are used to update spaces and functions that are not owned by the
/// TMOPIntegrator or DiscreteAdaptTC. The owned ones are updated in the
/// functions UpdateAfterMeshTopologyChange() of both classes.
void AddGridFunctionForUpdate(GridFunction *gf) { gridfuncarr.Append(gf); }
void AddFESpaceForUpdate(FiniteElementSpace *fes) { fespacearr.Append(fes); }
#ifdef MFEM_USE_MPI
void AddGridFunctionForUpdate(ParGridFunction *pgf_)
{
pgridfuncarr.Append(pgf_);
}
void AddFESpaceForUpdate(ParFiniteElementSpace *pfes_)
{
pfespacearr.Append(pfes_);
}
#endif
~TMOPHRSolver()
{
if (!hradaptivity) { return; }
delete tmop_dr;
delete tmop_dr_est;
delete tmop_r;
delete tmop_r_est;
}
/// Total number of hr-adaptivity iterations. At each iteration, we do an
/// r-adaptivity iteration followed by a number of h-adaptivity iterations.
void SetHRAdaptivityIterations(int iter) { hr_iter = iter; }
/// Total number of h-adaptivity iterations per r-adaptivity iteration.
void SetHAdaptivityIterations(int iter) { h_per_r_iter = iter; }
};
}
#endif
+6 -4
View File
@@ -407,6 +407,8 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
{
// Needed for the line search below. The untangling metrics see this
// reference to detect deteriorations.
MFEM_VERIFY(min_det_ptr != NULL, " Initial mesh was valid, but"
" intermediate mesh is invalid. Contact TMOP Developers.");
*min_det_ptr = untangle_factor * min_detT_in;
}
@@ -576,7 +578,7 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
if (ti)
{
ti->UpdateAfterMeshChange(x_loc);
ti->UpdateAfterMeshPositionChange(x_loc);
ti->ComputeFDh(x_loc, *pfesc);
UpdateDiscreteTC(*ti, x_loc);
}
@@ -586,7 +588,7 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
for (int j = 0; j < ati.Size(); j++)
{
ati[j]->UpdateAfterMeshChange(x_loc);
ati[j]->UpdateAfterMeshPositionChange(x_loc);
ati[j]->ComputeFDh(x_loc, *pfesc);
UpdateDiscreteTC(*ati[j], x_loc);
}
@@ -613,7 +615,7 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
if (ti)
{
ti->UpdateAfterMeshChange(x_loc);
ti->UpdateAfterMeshPositionChange(x_loc);
ti->ComputeFDh(x_loc, *fesc);
UpdateDiscreteTC(*ti, x_loc);
}
@@ -623,7 +625,7 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
for (int j = 0; j < ati.Size(); j++)
{
ati[j]->UpdateAfterMeshChange(x_loc);
ati[j]->UpdateAfterMeshPositionChange(x_loc);
ati[j]->ComputeFDh(x_loc, *fesc);
UpdateDiscreteTC(*ati[j], x_loc);
}
+2 -1
View File
@@ -175,7 +175,8 @@ const Operator &InterpolationGridTransfer::ForwardOperator()
localP[elem_geoms[i]]);
}
F.Reset(ran_fes.RefinementMatrix_main(
dom_fes.GetNDofs(), dom_fes.GetElementToDofTable(), localP));
dom_fes.GetNDofs(), dom_fes.GetElementToDofTable(),
dom_fes.GetElementToFaceOrientationTable(), localP));
}
else
{
+4
View File
@@ -21,12 +21,16 @@
#define MFEM_PERF_FUNCTION CALI_CXX_MARK_FUNCTION
#define MFEM_PERF_BEGIN(s) CALI_MARK_BEGIN(s)
#define MFEM_PERF_END(s) CALI_MARK_END(s)
#define MFEM_PERF_SCOPE(name) \
cali::Annotation::Guard cali_autogenerated_guard_name(cali::Annotation("function").begin(std::string(name).c_str()))
#else
#define MFEM_PERF_FUNCTION
#define MFEM_PERF_BEGIN(s)
#define MFEM_PERF_END(s)
#define MFEM_PERF_SCOPE(name)
#endif
+1
View File
@@ -13,6 +13,7 @@
#define MFEM_FORALL_HPP
#include "../config/config.hpp"
#include "annotation.hpp"
#include "error.hpp"
#include "backends.hpp"
#include "device.hpp"
+16 -2
View File
@@ -494,8 +494,7 @@ public:
/// Copy @a size entries from @a *this to @a dest.
/** The given @a size should not exceed the Capacity() of @a *this and the
destination, @a dest. */
inline void CopyTo(Memory &dest, int size) const
{ dest.CopyFrom(*this, size); }
inline void CopyTo(Memory &dest, int size) const;
/// Copy @a size entries from @a *this to the host pointer @a dest.
/** The given @a size should not exceed the Capacity() of @a *this. */
@@ -923,6 +922,11 @@ inline void Memory<T>::Wrap(T *ptr, T *d_ptr, int size, MemoryType mt, bool own)
template <typename T>
inline void Memory<T>::MakeAlias(const Memory &base, int offset, int size)
{
MFEM_ASSERT(0 <= offset, "invalid offset = " << offset);
MFEM_ASSERT(0 <= size, "invalid size = " << size);
MFEM_ASSERT(offset + size <= base.capacity,
"invalid offset + size = " << offset + size
<< " > base capacity = " << base.capacity);
capacity = size;
h_mt = base.h_mt;
h_ptr = base.h_ptr + offset;
@@ -1136,6 +1140,7 @@ inline bool Memory<T>::DeviceIsValid() const
template <typename T>
inline void Memory<T>::CopyFrom(const Memory &src, int size)
{
MFEM_VERIFY(src.capacity>=size && capacity>=size, "Incorrect size");
if (!(flags & REGISTERED) && !(src.flags & REGISTERED))
{
if (h_ptr != src.h_ptr && size != 0)
@@ -1155,6 +1160,7 @@ inline void Memory<T>::CopyFrom(const Memory &src, int size)
template <typename T>
inline void Memory<T>::CopyFromHost(const T *src, int size)
{
MFEM_VERIFY(capacity>=size, "Incorrect size");
if (!(flags & REGISTERED))
{
if (h_ptr != src && size != 0)
@@ -1171,9 +1177,17 @@ inline void Memory<T>::CopyFromHost(const T *src, int size)
}
}
template <typename T>
inline void Memory<T>::CopyTo(Memory &dest, int size) const
{
MFEM_VERIFY(capacity>=size, "Incorrect size");
dest.CopyFrom(*this, size);
}
template <typename T>
inline void Memory<T>::CopyToHost(T *dest, int size) const
{
MFEM_VERIFY(capacity>=size, "Incorrect size");
if (!(flags & REGISTERED))
{
if (h_ptr != dest && size != 0)
+5
View File
@@ -118,6 +118,11 @@ int STable3D::Index (int r, int c, int f) const
{
STable3DNode *node;
if (r >= Size)
{
return -1;
}
Sort3 (r, c, f);
for (node = Rows[r]; node != NULL; node = node->Prev)
+10
View File
@@ -78,6 +78,16 @@ if (MFEM_USE_MPI)
endif()
endif()
if (MFEM_USE_ARPACK)
list(APPEND SRCS eigensolvers.cpp arpack.cpp)
list(APPEND HDRS eigensolvers.hpp arpack.hpp)
endif()
if (MFEM_USE_SPECTRA)
list(APPEND SRCS spectra.cpp)
list(APPEND HDRS eigen.hpp spectra.hpp)
endif()
if (MFEM_USE_SUNDIALS)
list(APPEND SRCS sundials.cpp)
list(APPEND HDRS sundials.hpp)
+1122
View File
File diff suppressed because it is too large Load Diff
+240
View File
@@ -0,0 +1,240 @@
// 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_ARPACK
#define MFEM_ARPACK
#include "../config/config.hpp"
#ifdef MFEM_USE_ARPACK
#include <string>
using namespace std;
#ifdef MFEM_USE_MPI
#include <mpi.h>
#include "hypre.hpp"
#endif
#include "operator.hpp"
#define DSAUPD dsaupd_
#define DSEUPD dseupd_
#ifdef MFEM_USE_MPI
#define PDSAUPD pdsaupd_
#define PDSEUPD pdseupd_
#endif
extern "C" void DSAUPD(int *ido,char *bmat, int *n,
char *which, int *nev,double *tol,double *resid,
int *ncv,double *v, int *ldv,
int *iparam, int *ipntr,
double *workd, double *workl, int *lworkl, int *info);
extern "C" void DSEUPD(int *, char *,int *, double *,
double *,int *, double *,char *, int *, char *,
int *,double *,double *,int *, double *,
int *, int *,int *, double *,
double *,int *, int *);
#ifdef MFEM_USE_MPI
extern "C" void PDSAUPD(int *comm, int *ido,char *bmat, int *n,
char *which, int *nev,double *tol,double *resid,
int *ncv,double *v, int *ldv,
int *iparam, int *ipntr,
double *workd, double *workl, int *lworkl, int *info);
extern "C" void PDSEUPD(int *comm, int *, char *,int *, double *,
double *,int *, double *,char *, int *, char *,
int *,double *,double *,int *, double *,
int *, int *,int *, double *,
double *,int *, int *);
#endif
extern "C" {
void arpackgetcommdbg_(int *,int *,int *);
void arpacksetcommdbg_(int *,int *,int *);
void arpacksymdbg_(int *,int *,int *,int *,int *,int *,int *);
void arpacknonsymdbg_(int *,int *,int *,int *,int *,int *,int *);
void arpackcmplxdbg_(int *,int *,int *,int *,int *,int *,int *);
}
namespace mfem
{
class ArPackSym : public Eigensolver
{
public:
ArPackSym();
virtual ~ArPackSym();
/** ARPACK modes are described in section 3.5 of the ARPACK manual.
Mode 1: regular mode to solve A x = lambda x
No solver and no mass matrix are needed.
Mode 2: regular inverse mode to solve A x = lambda M x
Both A and M are needed and the solver should compute M^{-1}.
Mode 3: shift-invert mode to solve either A x = lambda x
or A x = lambda M x
Mass matrix is optional. The solver should compute
(A-sigma I)^{-1} or (A-sigma M)^{-1}. The shift parameter,
sigma, also needs to be set with SetShift().
Mode 4: Buckling mode to solve K x = lambda K_G x
K is set using SetMassMatrix(), K_G is set using SetOperator(),
and the solver should compute (K-sigma K_G)^{-1}. The shift
parameter, sigma, also needs to be set with SetShift().
Mode 5: Cayley mode to solve A x = lambda M x
Both A and M are needed and the solver should compute
(A - sigma M)^{-1}. The shift parameter, sigma, also needs
to be set with SetShift().
*/
void SetMode(int mode);
inline void SetTol(double tol) { tol_ = tol; }
inline void SetMaxIter(int max_iter) { max_iter_ = max_iter; }
inline void SetPrintLevel(int logging) { logging_ = logging; }
inline void SetShift(double sigma) { sigma_ = sigma; }
inline void SetNumModes(int num_eigs) { nev_ = num_eigs; }
virtual void SetSolver(Solver & solver);
virtual void SetOperator(Operator & A);
virtual void SetMassMatrix(Operator & M);
void Solve();
/// Collect the converged eigenvalues
virtual void GetEigenvalues(Array<double> & eigenvalues);
/// Extract a single eigenvector
virtual Vector & GetEigenvector(unsigned int i);
/// Transfer ownership of the converged eigenvectors
Vector ** StealEigenvectors();
protected:
int myid_; // Index of this processor
int max_iter_;
int logging_;
// The following variables are for ARPACK
int nloc_; // number of items stored locally
int nev_; // number of requested eigenvalues
int ncv_; // number of ritz vectors
int rvec_; // boolean to return eigenvectors as well
int mode_; // 1 = standard, 2 = generalized, 3 = shift invert,
// 4 = buckling, 5 = Cayley
int lworkl_; // length of lworkl_ work array
int iparam_[12]; // arpack parameters
int ipntr_[12]; // arpack pointers
char bmat_; // I for standard problem, G for generalized
char which_[3]; // spectrum portion: LA, SA, LM, SM, BE
char hwmny_; // DSEUPD: A for all eigenvalues, S for some
double tol_; // relative accuracy bound for Ritz values
double sigma_; // eigenvalue shift parameter
int * select_;// workspace used during eigenvalue computation
double * dv_; // Ritz values
double * v_; // ncv Lanczos basis vectors
double * resid_; // residual vector
double * workd_; // work array for 3 vectors used in Arnoldi iteration
double * workl_; // work array
// Operators and Vectors needed outside of ARPACK
Solver * solver_;
Operator * A_;
Operator * B_;
Vector * w_;
Vector * x_;
Vector * y_;
Vector * z_;
Vector ** eigenvectors_;
string solverName_;
void reverseComm();
int reverseCommMode1();
int reverseCommMode2();
int reverseCommMode3();
int reverseCommMode4();
int reverseCommMode5();
virtual void prepareEigenvectors();
void printErrors(const int & info, const int iparam[],
const char & bmat, const int & n,
const char which[],
const int & nev, const int & ncv,
const int & lworkl );
private:
virtual int computeNlocf() { return nloc_; }
virtual int computeIter(int & ido);
virtual int computeEigs();
};
#ifdef MFEM_USE_MPI
class ParArPackSym : public ArPackSym
{
public:
ParArPackSym(MPI_Comm comm);
virtual ~ParArPackSym() {}
void SetOperator(Operator & A);
void SetMassMatrix(Operator & M);
/// Collect the converged eigenvalues
void GetEigenvalues(Array<double> & eigenvalues);
/// Extract a single eigenvector
Vector & GetEigenvector(unsigned int i);
/// Transfer ownership of the converged eigenvectors
// HypreParVector ** StealEigenvectors();
Vector ** StealEigenvectors();
protected:
void prepareEigenvectors();
private:
MPI_Comm comm_;
MPI_Fint commf_; // Fortran style MPI communicator
int numProcs_; // Number of processors
HYPRE_Int * part_; // parallel partitioning for eigenvectors
int computeNlocf();
int computeIter(int & ido);
int computeEigs();
};
#endif // MFEM_USE_MPI
};
#endif // MFEM_USE_ARPACK
#endif // MFEM_ARPACK
+6
View File
@@ -787,10 +787,16 @@ HypreParMatrix * ComplexHypreParMatrix::GetSystemMatrix() const
2 * num_cols_offd, cmap,
true);
#if MFEM_HYPRE_VERSION <= 22200
// Give the new matrix ownership of row_starts and col_starts
hypre_ParCSRMatrix *hA = (hypre_ParCSRMatrix*)(*A);
hypre_ParCSRMatrixSetRowStartsOwner(hA,1);
hypre_ParCSRMatrixSetColStartsOwner(hA,1);
#else
mfem_hypre_TFree_host(row_starts);
mfem_hypre_TFree_host(col_starts);
#endif
return A;
}
+7
View File
@@ -763,6 +763,13 @@ public:
tdata.New(i*j*k);
}
DenseTensor(double *d, int i, int j, int k)
: Mk(NULL, i, j)
{
nk = k;
tdata.Wrap(d, i*j*k, false);
}
DenseTensor(int i, int j, int k, MemoryType mt)
: Mk(NULL, i, j)
{
+94
View File
@@ -0,0 +1,94 @@
#ifndef MFEM_EIGEN_HPP
#define MFEM_EIGEN_HPP
#include <vector>
#include <Eigen/Sparse>
#include "vector.hpp"
#include "sparsemat.hpp"
#include "densemat.hpp"
namespace mfem{
/** @brief Eigen template specialization for vector conversion */
template <typename T>
struct VectorConverter {
static Vector from(const Eigen::Matrix<T, Eigen::Dynamic, 1>& other)
{
Vector v(other.rows());
for (size_t i = 0; i < v.Size(); i++)
v(i) = other(i);
return std::move(v);
}
static Eigen::Matrix<T, Eigen::Dynamic, 1> to(const Vector& other)
{
Eigen::Matrix<T, Eigen::Dynamic, 1> v(other.Size());
for (size_t i = 0; i < v.Size(); i++)
v(i) = other(i);
return std::move(v);
}
};
/** @brief Eigen template specialization for dense matrix conversion */
template <typename T>
struct DenseMatrixConverter {
static DenseMatrix from(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& other)
{
DenseMatrix mat(other.rows(), other.cols());
for (size_t j = 0; j < mat.Width(); j++)
for (size_t i = 0; i < mat.Height(); i++)
mat(i, j) = other(i, j);
return mat;
}
static Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> to(const DenseMatrix& other)
{
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> mat(other.Height(), other.Width());
for (size_t j = 0; j < mat.cols(); j++)
for (size_t i = 0; i < mat.rows(); i++)
mat(i, j) = other(i, j);
return mat;
}
};
/** @brief Eigen template specialization for sparse matrix conversion */
template <class T>
struct SparseMatrixConverter {
static SparseMatrix from(const Eigen::SparseMatrix<T, Eigen::RowMajor>& other)
{
return SparseMatrix(other.outerIndexPtr(), other.innerIndexPtr(), other.valuePtr(), other.rows(), other.cols());
}
static Eigen::SparseMatrix<T, Eigen::RowMajor> to(const SparseMatrix& other)
{
// MFEM memory info
const int *I = other.GetI(), *J = other.GetJ();
const T* Data = other.GetData();
// Eigen triplet
std::vector<Eigen::Triplet<double>> tripletList;
tripletList.reserve(other.GetMemoryData().Capacity());
for (size_t i = 0; i < other.Size(); i++) {
for (size_t k = I[i], end = I[i + 1]; k < end; k++)
tripletList.push_back(Eigen::Triplet<double>(i, J[k], Data[k]));
}
// Create Eigen sparse matrix
Eigen::SparseMatrix<T, Eigen::RowMajor> mat(other.Height(), other.Width());
mat.setFromTriplets(tripletList.begin(), tripletList.end());
return mat;
}
};
}
#endif // MFEM_EIGEN_HPP
+23
View File
@@ -0,0 +1,23 @@
// 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 "linalg.hpp"
#include "eigensolver.hpp"
using namespace std;
namespace mfem
{
Eigensolver::Eigensolver()
{}
};
+53
View File
@@ -0,0 +1,53 @@
// 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_EIGENSOLVERS
#define MFEM_EIGENSOLVERS
#include "vector.hpp"
#include "operator.hpp"
namespace mfem
{
/// Abstract Eigensolver
class Eigensolver
{
public:
Eigensolver();
virtual ~Eigensolver() {}
virtual void SetTol(double tol) = 0;
virtual void SetMaxIter(int max_iter) = 0;
virtual void SetPrintLevel(int logging) = 0;
virtual void SetNumModes(int num_eigs) = 0;
virtual void SetOperator(Operator & A) = 0;
virtual void SetMassMatrix(Operator & M) = 0;
/// Perform the eigenvalue solve
virtual void Solve() = 0;
/// Collect the converged eigenvalues
virtual void GetEigenvalues(Array<double> & eigenvalues) = 0;
/// Extract a single eigenvector
virtual Vector & GetEigenvector(unsigned int i) = 0;
/// Transfer ownership of the converged eigenvectors
virtual Vector ** StealEigenvectors() = 0;
};
}
#endif
+63 -1
View File
@@ -88,7 +88,9 @@ HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size,
{
x = hypre_ParVectorCreate(comm,glob_size,col);
hypre_ParVectorInitialize(x);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParVectorSetPartitioningOwner(x,0);
#endif
// The data will be destroyed by hypre (this is the default)
hypre_ParVectorSetDataOwner(x,1);
hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
@@ -105,7 +107,9 @@ HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size,
hypre_ParVectorSetDataOwner(x,1); // owns the seq vector
hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
hypre_SeqVectorSetDataOwner(x_loc,0);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParVectorSetPartitioningOwner(x,0);
#endif
double tmp = 0.0;
hypre_VectorData(x_loc) = &tmp;
#ifdef HYPRE_USING_CUDA
@@ -128,7 +132,9 @@ HypreParVector::HypreParVector(const HypreParVector &y) : Vector()
x = hypre_ParVectorCreate(y.x -> comm, y.x -> global_size,
y.x -> partitioning);
hypre_ParVectorInitialize(x);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParVectorSetPartitioningOwner(x,0);
#endif
hypre_ParVectorSetDataOwner(x,1);
hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
_SetDataAndSize_();
@@ -162,7 +168,9 @@ HypreParVector::HypreParVector(ParFiniteElementSpace *pfes)
x = hypre_ParVectorCreate(pfes->GetComm(), pfes->GlobalTrueVSize(),
pfes->GetTrueDofOffsets());
hypre_ParVectorInitialize(x);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParVectorSetPartitioningOwner(x,0);
#endif
// The data will be destroyed by hypre (this is the default)
hypre_ParVectorSetDataOwner(x,1);
hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
@@ -683,8 +691,10 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, HYPRE_BigInt glob_size,
A = hypre_ParCSRMatrixCreate(comm, glob_size, glob_size, row_starts,
row_starts, 0, diag->NumNonZeroElems(), 0);
hypre_ParCSRMatrixSetDataOwner(A,1);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
hypre_ParCSRMatrixSetColStartsOwner(A,0);
#endif
hypre_CSRMatrixSetDataOwner(A->diag,0);
diagOwner = CopyCSR(diag, mem_diag, A->diag, false);
@@ -726,8 +736,10 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
row_starts, col_starts,
0, diag->NumNonZeroElems(), 0);
hypre_ParCSRMatrixSetDataOwner(A,1);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
hypre_ParCSRMatrixSetColStartsOwner(A,0);
#endif
hypre_CSRMatrixSetDataOwner(A->diag,0);
diagOwner = CopyCSR(diag, mem_diag, A->diag, false);
@@ -770,8 +782,10 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
offd->Width(), diag->NumNonZeroElems(),
offd->NumNonZeroElems());
hypre_ParCSRMatrixSetDataOwner(A,1);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
hypre_ParCSRMatrixSetColStartsOwner(A,0);
#endif
hypre_CSRMatrixSetDataOwner(A->diag,0);
diagOwner = CopyCSR(diag, mem_diag, A->diag, own_diag_offd);
@@ -817,8 +831,10 @@ HypreParMatrix::HypreParMatrix(
A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
row_starts, col_starts, offd_num_cols, 0, 0);
hypre_ParCSRMatrixSetDataOwner(A,1);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
hypre_ParCSRMatrixSetColStartsOwner(A,0);
#endif
HYPRE_Int local_num_rows = hypre_CSRMatrixNumRows(A->diag);
@@ -931,8 +947,10 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
row_starts, col_starts, 0, nnz, 0);
hypre_ParCSRMatrixSetDataOwner(A,1);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
hypre_ParCSRMatrixSetColStartsOwner(A,0);
#endif
hypre_CSRMatrixSetDataOwner(A->diag,0);
diagOwner = CopyBoolCSR(diag, mem_diag, A->diag);
@@ -989,8 +1007,10 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int id, int np,
}
hypre_ParCSRMatrixSetDataOwner(A,1);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
hypre_ParCSRMatrixSetColStartsOwner(A,0);
#endif
mem_diag.data.New(diag_nnz);
for (HYPRE_Int i = 0; i < diag_nnz; i++)
@@ -1177,6 +1197,13 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
{
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
}
#if MFEM_HYPRE_VERSION > 22200
mfem_hypre_TFree_host(row_starts);
if (rows != cols)
{
mfem_hypre_TFree_host(col_starts);
}
#endif
hypre_MatvecCommPkgCreate(A);
height = GetNumRows();
@@ -1263,6 +1290,7 @@ void HypreParMatrix::SetOwnerFlags(signed char diag, signed char offd,
void HypreParMatrix::CopyRowStarts()
{
#if MFEM_HYPRE_VERSION <= 22200
if (!A || hypre_ParCSRMatrixOwnsRowStarts(A) ||
(hypre_ParCSRMatrixRowStarts(A) == hypre_ParCSRMatrixColStarts(A) &&
hypre_ParCSRMatrixOwnsColStarts(A)))
@@ -1297,10 +1325,12 @@ void HypreParMatrix::CopyRowStarts()
hypre_ParCSRMatrixColStarts(A) = new_row_starts;
hypre_ParCSRMatrixOwnsColStarts(A) = 0;
}
#endif
}
void HypreParMatrix::CopyColStarts()
{
#if MFEM_HYPRE_VERSION <= 22200
if (!A || hypre_ParCSRMatrixOwnsColStarts(A) ||
(hypre_ParCSRMatrixRowStarts(A) == hypre_ParCSRMatrixColStarts(A) &&
hypre_ParCSRMatrixOwnsRowStarts(A)))
@@ -1339,6 +1369,7 @@ void HypreParMatrix::CopyColStarts()
{
hypre_ParCSRMatrixOwnsColStarts(A) = 1;
}
#endif
}
void HypreParMatrix::GetDiag(Vector &diag) const
@@ -1791,9 +1822,14 @@ HypreParMatrix* HypreParMatrix::LeftDiagMult(const SparseMatrix &D,
DA_diag, DA_offd, new_col_map_offd,
own_diag_offd);
#if MFEM_HYPRE_VERSION <= 22200
// Give ownership of row_starts, col_starts, and col_map_offd to DA
hypre_ParCSRMatrixSetRowStartsOwner(DA->A, 1);
hypre_ParCSRMatrixSetColStartsOwner(DA->A, 1);
#else
mfem_hypre_TFree_host(new_row_starts);
mfem_hypre_TFree_host(new_col_starts);
#endif
DA->colMapOwner = 1;
return DA;
@@ -1948,18 +1984,22 @@ void HypreParMatrix::Threshold(double threshold)
row_starts = hypre_ParCSRMatrixRowStarts(A);
col_starts = hypre_ParCSRMatrixColStarts(A);
#if MFEM_HYPRE_VERSION <= 22200
bool old_owns_row = hypre_ParCSRMatrixOwnsRowStarts(A);
bool old_owns_col = hypre_ParCSRMatrixOwnsColStarts(A);
#endif
HYPRE_BigInt global_num_rows = hypre_ParCSRMatrixGlobalNumRows(A);
HYPRE_BigInt global_num_cols = hypre_ParCSRMatrixGlobalNumCols(A);
parcsr_A_ptr = hypre_ParCSRMatrixCreate(comm, global_num_rows,
global_num_cols,
row_starts, col_starts,
0, 0, 0);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParCSRMatrixOwnsRowStarts(parcsr_A_ptr) = old_owns_row;
hypre_ParCSRMatrixOwnsColStarts(parcsr_A_ptr) = old_owns_col;
hypre_ParCSRMatrixOwnsRowStarts(A) = 0;
hypre_ParCSRMatrixOwnsColStarts(A) = 0;
#endif
csr_A = hypre_MergeDiagAndOffd(A);
@@ -1994,7 +2034,12 @@ void HypreParMatrix::Threshold(double threshold)
hypre_ParCSRMatrixSetNumNonzeros(A);
/* Make sure that the first entry in each row is the diagonal one. */
#if MFEM_HYPRE_VERSION <= 22200
if (row_starts == col_starts)
#else
if ((row_starts[0] == col_starts[0]) &&
(row_starts[1] == col_starts[1]))
#endif
{
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
}
@@ -2503,11 +2548,14 @@ HypreParMatrix * RAP(const HypreParMatrix *A, const HypreParMatrix *P)
// hypre_ParCSRMatrixRAPKT
}
#else
#if MFEM_HYPRE_VERSION <= 22200
HYPRE_Int P_owns_its_col_starts =
hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*P));
#endif
hypre_BoomerAMGBuildCoarseOperator(*P,*A,*P,&rap);
#if MFEM_HYPRE_VERSION <= 22200
/* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts
from P (even if it does not own them)! */
hypre_ParCSRMatrixSetRowStartsOwner(rap,0);
@@ -2516,6 +2564,7 @@ HypreParMatrix * RAP(const HypreParMatrix *A, const HypreParMatrix *P)
{
hypre_ParCSRMatrixSetColStartsOwner(*P, 1);
}
#endif
#endif
hypre_ParCSRMatrixSetNumNonzeros(rap);
@@ -2536,13 +2585,16 @@ HypreParMatrix * RAP(const HypreParMatrix * Rt, const HypreParMatrix *A,
hypre_ParCSRMatrixDestroy(Q);
}
#else
#if MFEM_HYPRE_VERSION <= 22200
HYPRE_Int P_owns_its_col_starts =
hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*P));
HYPRE_Int Rt_owns_its_col_starts =
hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*Rt));
#endif
hypre_BoomerAMGBuildCoarseOperator(*Rt,*A,*P,&rap);
#if MFEM_HYPRE_VERSION <= 22200
/* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts
from Rt and P (even if they do not own them)! */
hypre_ParCSRMatrixSetRowStartsOwner(rap,0);
@@ -2555,6 +2607,7 @@ HypreParMatrix * RAP(const HypreParMatrix * Rt, const HypreParMatrix *A,
{
hypre_ParCSRMatrixSetColStartsOwner(*Rt, 1);
}
#endif
#endif
hypre_ParCSRMatrixSetNumNonzeros(rap);
@@ -3144,8 +3197,12 @@ void HypreSmoother::SetOperator(const Operator &op)
}
else
{
#if MFEM_HYPRE_VERSION <= 22200
min_eig_est = 0;
hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est);
#else
hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est, &min_eig_est);
#endif
}
Z = new HypreParVector(*A);
}
@@ -3159,8 +3216,12 @@ void HypreSmoother::SetOperator(const Operator &op)
}
else
{
#if MFEM_HYPRE_VERSION <= 22200
min_eig_est = 0;
hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est);
#else
hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est, &min_eig_est);
#endif
}
// The Taubin and FIR polynomials are defined on [0, 2]
@@ -4997,11 +5058,11 @@ HypreADS::HypreADS(const HypreParMatrix &A, ParFiniteElementSpace *face_fespace)
void HypreADS::Init(ParFiniteElementSpace *face_fespace)
{
int cycle_type = 11;
int rlx_type = 2;
int rlx_sweeps = 1;
double rlx_weight = 1.0;
double rlx_omega = 1.0;
#ifndef HYPRE_USING_CUDA
int rlx_type = 2;
int amg_coarsen_type = 10;
int amg_agg_levels = 1;
int amg_rlx_type = 8;
@@ -5009,6 +5070,7 @@ void HypreADS::Init(ParFiniteElementSpace *face_fespace)
int amg_interp_type = 6;
int amg_Pmax = 4;
#else
int rlx_type = 1;
int amg_coarsen_type = 8;
int amg_agg_levels = 0;
int amg_rlx_type = 18;
+12
View File
@@ -508,8 +508,10 @@ void hypre_ParCSRMatrixEliminateAAe(hypre_ParCSRMatrix *A,
hypre_ParCSRMatrixColStarts(A),
0, 0, 0);
#if MFEM_HYPRE_VERSION <= 22200
hypre_ParCSRMatrixSetRowStartsOwner(*Ae, 0);
hypre_ParCSRMatrixSetColStartsOwner(*Ae, 0);
#endif
hypre_CSRMatrix *Ae_diag = hypre_ParCSRMatrixDiag(*Ae);
hypre_CSRMatrix *Ae_offd = hypre_ParCSRMatrixOffd(*Ae);
@@ -1002,10 +1004,17 @@ void hypre_ParCSRMatrixSplit(hypre_ParCSRMatrix *A,
hypre_ParCSRMatrixOwnsData(blocks[i]) = 1;
#if MFEM_HYPRE_VERSION <= 22200
/* only the first block will own the row/col_starts */
hypre_ParCSRMatrixOwnsRowStarts(blocks[i]) = !i;
hypre_ParCSRMatrixOwnsColStarts(blocks[i]) = !i;
#endif
}
#if MFEM_HYPRE_VERSION > 22200
mfem_hypre_TFree_host(row_starts);
mfem_hypre_TFree_host(col_starts);
#endif
}
/* Based on hypre_CSRMatrixMatvec in hypre's csr_matvec.c */
@@ -1916,9 +1925,12 @@ hypre_ParCSRMatrixAdd(hypre_ParCSRMatrix *A,
/* C owns diag, offd, and cmap. */
hypre_ParCSRMatrixSetDataOwner(C, 1);
#if MFEM_HYPRE_VERSION <= 22200
/* C does not own row and column starts. */
hypre_ParCSRMatrixSetRowStartsOwner(C, 0);
hypre_ParCSRMatrixSetColStartsOwner(C, 0);
#endif
return C;
}
+10
View File
@@ -48,6 +48,16 @@
#include "ginkgo.hpp"
#endif
#ifdef MFEM_USE_ARPACK
#include "eigensolver.hpp"
#include "arpack.hpp"
#endif
#ifdef MFEM_USE_SPECTRA
#include "eigen.hpp"
#include "spectra.hpp"
#endif
#ifdef MFEM_USE_MPI
#include "hypre_parcsr.hpp"
#include "hypre.hpp"
+11 -23
View File
@@ -33,7 +33,12 @@ int SparseMatrix::SparseMatrixCount = 0;
cusparseHandle_t SparseMatrix::handle = nullptr;
size_t SparseMatrix::bufferSize = 0;
void * SparseMatrix::dBuffer = nullptr;
#endif
# if CUSPARSE_VERSION >= 11400
# define MFEM_CUSPARSE_ALG CUSPARSE_SPMV_CSR_ALG1
# else
# define MFEM_CUSPARSE_ALG CUSPARSE_CSRMV_ALG1
# endif // CUSPARSE_VERSION >= 11400
#endif // MFEM_USE_CUDA
void SparseMatrix::InitCuSparse()
{
@@ -679,25 +684,16 @@ void SparseMatrix::AddMult(const Vector &x, Vector &y, const double a) const
cusparseCreateMatDescr(&matA_descr);
cusparseSetMatIndexBase(matA_descr, CUSPARSE_INDEX_BASE_ZERO);
cusparseSetMatType(matA_descr, CUSPARSE_MATRIX_TYPE_GENERAL);
#endif
initBuffers = true;
}
// Allocate kernel space. Buffer is shared between different sparsemats
size_t newBufferSize = 0;
#if CUDA_VERSION >= 11020
cusparseSpMV_bufferSize(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha,
matA_descr,
vecX_descr, &beta, vecY_descr, CUDA_R_64F,
CUSPARSE_SPMV_CSR_ALG1, &newBufferSize);
#elif CUDA_VERSION >= 10010
cusparseSpMV_bufferSize(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha,
matA_descr,
vecX_descr, &beta, vecY_descr, CUDA_R_64F,
CUSPARSE_CSRMV_ALG1, &newBufferSize);
#endif
MFEM_CUSPARSE_ALG, &newBufferSize);
// Check if we need to resize
if (newBufferSize > bufferSize)
@@ -707,30 +703,22 @@ void SparseMatrix::AddMult(const Vector &x, Vector &y, const double a) const
CuMemAlloc(&dBuffer, bufferSize);
}
#if CUDA_VERSION >= 11020
#if CUDA_VERSION >= 10010
// 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_SPMV_CSR_ALG1, dBuffer);
#elif CUDA_VERSION >= 10010
// 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);
vecX_descr, &beta, vecY_descr, CUDA_R_64F, MFEM_CUSPARSE_ALG, dBuffer);
#else
cusparseDcsrmv(handle, CUSPARSE_OPERATION_NON_TRANSPOSE,
Height(), Width(), J.Capacity(),
&alpha, matA_descr,
const_cast<double *>(d_A), const_cast<int *>(d_I), const_cast<int *>(d_J),
const_cast<double *>(d_x), &beta, d_y);
#endif
#endif
#endif // CUDA_VERSION >= 10010
#endif // MFEM_USE_CUDA
}
else
{
+157
View File
@@ -0,0 +1,157 @@
#include "spectra.hpp"
#include "../fem/bilinearform.hpp"
namespace mfem {
SpectraEigenSolver::SpectraEigenSolver()
{
// Init params
_nconv = 0;
_nev = 1;
_ncv = 1;
_max_iter = 1000;
_tol = 1e-3;
}
SpectraEigenSolver::~SpectraEigenSolver()
{
delete _A_s, _B_s, _S, _G;
}
/// Set dimension of Krylov subspace in the Lanczos method
SpectraEigenSolver& SpectraEigenSolver::SetKrylov(double ncv)
{
_ncv = ncv;
return *this;
}
/// Set solver tolerance
SpectraEigenSolver& SpectraEigenSolver::SetTol(double tol)
{
_tol = tol;
return *this;
}
/// Set maximum number of iterations
SpectraEigenSolver& SpectraEigenSolver::SetMaxIter(int max_iter)
{
_max_iter = max_iter;
return *this;
}
/// Set the number of required eigenmodes
SpectraEigenSolver& SpectraEigenSolver::SetNumModes(int nev)
{
_nev = nev;
return *this;
}
/// Set operator for standard eigenvalue problem (A*x = lambda*x)
SpectraEigenSolver& SpectraEigenSolver::SetOperator(const Operator& A)
{
// Set EIGEN operators
_A_e = SparseMatrixConverter<double>::to(static_cast<const BilinearForm&>(A).SpMat());
// Set SPECTRA operators
_A_s = new SparseSymMatProd<double>(_A_e);
return *this;
}
/// Set operator for generalized eigenvalue problem (A*x = lambda*B*x)
SpectraEigenSolver& SpectraEigenSolver::SetOperators(const Operator& A, const Operator& B)
{
// Set EIGEN operators
_A_e = SparseMatrixConverter<double>::to(static_cast<const BilinearForm&>(A).SpMat());
_B_e = SparseMatrixConverter<double>::to(static_cast<const BilinearForm&>(B).SpMat());
// Set SPECTRA operators
_A_s = new SparseSymMatProd<double>(_A_e);
_B_s = new SparseCholesky<double>(_B_e);
return *this;
}
/// Solve the eigenvalue problem for the specified number of eigenvalues
void SpectraEigenSolver::Solve()
{
// Set the dimension of the Krilov space equal to the number of requested eigenvalues if necessary
if (_ncv < _nev)
_ncv = _nev;
if (!_B_s) {
_S = new SymEigsSolver<SparseSymMatProd<double>>(*_A_s, _nev, _ncv);
_S->init();
_nconv = _S->compute(SortRule::SmallestMagn, _max_iter, _tol, SortRule::SmallestMagn);
}
else {
_G = new SymGEigsSolver<SparseSymMatProd<double>, SparseCholesky<double>, GEigsMode::Cholesky>(*_A_s, *_B_s, _nev, _ncv);
_G->init();
_nconv = _G->compute(SortRule::SmallestMagn, _max_iter, _tol, SortRule::SmallestMagn);
}
}
/// Get the number of converged eigenvalues
int SpectraEigenSolver::GetNumConverged()
{
return _nconv;
}
/// Get the corresponding eigenvalue
double SpectraEigenSolver::GetEigenvalue(unsigned int i) const
{
if (!_B_s) {
if (_S->info() == CompInfo::Successful && i < _nconv)
return _S->eigenvalues()[i];
else
return 0;
}
else {
if (_G->info() == CompInfo::Successful && i < _nconv)
return _G->eigenvalues()[i];
else
return 0;
}
}
Eigen::VectorXd SpectraEigenSolver::GetEigenvalues(unsigned int i) const
{
if (!_B_s) {
if (_S->info() == CompInfo::Successful && i < _nconv)
return _S->eigenvalues().segment(0, i);
}
else {
if (_G->info() == CompInfo::Successful && i < _nconv)
return _G->eigenvalues().segment(0, i);
}
}
/// Get the corresponding eigenvector
Eigen::VectorXd SpectraEigenSolver::GetEigenvector(unsigned int i) const
{
if (!_B_s) {
if (_S->info() == CompInfo::Successful && i < _nconv)
return _S->eigenvectors().col(i);
}
else {
if (_G->info() == CompInfo::Successful && i < _nconv)
return _G->eigenvectors().col(i);
}
}
Eigen::MatrixXd SpectraEigenSolver::GetEigenvectors(unsigned int i) const
{
if (!_B_s) {
if (_S->info() == CompInfo::Successful && i < _nconv)
return _S->eigenvectors().topRows(i);
}
else {
if (_G->info() == CompInfo::Successful && i < _nconv)
return _G->eigenvectors().topRows(i);
}
}
} // namespace mfem
+77
View File
@@ -0,0 +1,77 @@
#ifndef MFEM_SPECTRA_HPP
#define MFEM_SPECTRA_HPP
#include <Spectra/GenEigsSolver.h>
#include <Spectra/MatOp/SparseCholesky.h>
#include <Spectra/MatOp/SparseGenMatProd.h>
#include <Spectra/SymEigsSolver.h>
#include <Spectra/SymGEigsSolver.h>
#include "eigen.hpp"
using namespace Spectra;
namespace mfem {
class SpectraEigenSolver {
public:
SpectraEigenSolver();
virtual ~SpectraEigenSolver();
/// Set dimension of Krylov subspace in the Lanczos method
SpectraEigenSolver& SetKrylov(double ncv);
/// Set solver tolerance
SpectraEigenSolver& SetTol(double tol);
/// Set maximum number of iterations
SpectraEigenSolver& SetMaxIter(int max_iter);
/// Set the number of required eigenmodes
SpectraEigenSolver& SetNumModes(int nev);
/// Set operator for standard eigenvalue problem (A*x = lambda*x)
SpectraEigenSolver& SetOperator(const Operator& A);
/// Set operator for generalized eigenvalue problem (A*x = lambda*B*x)
SpectraEigenSolver& SetOperators(const Operator& A, const Operator& B);
/// Solve the eigenvalue problem for the specified number of eigenvalues
void Solve();
/// Get the number of converged eigenvalues
int GetNumConverged();
/// Get the corresponding eigenvalue
double GetEigenvalue(unsigned int i) const;
Eigen::VectorXd GetEigenvalues(unsigned int i = 0) const;
/// Get the corresponding eigenvector
Eigen::VectorXd GetEigenvector(unsigned int i) const;
Eigen::MatrixXd GetEigenvectors(unsigned int i) const;
protected:
// Params
int _nconv, _nev, _ncv, _max_iter;
double _tol;
// EIGEN Operators
Eigen::SparseMatrix<double> _A_e, _B_e;
// Spectra Operators
SparseSymMatProd<double>* _A_s = nullptr;
SparseCholesky<double>* _B_s = nullptr;
// Eigenvalue solution based on Spectra
SymEigsSolver<SparseSymMatProd<double>>* _S = nullptr;
SymGEigsSolver<SparseSymMatProd<double>, SparseCholesky<double>, GEigsMode::Cholesky>* _G = nullptr;
// // Eigenvalue solution based on Eigen
// Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd>* _S = nullptr;
// Eigen::GeneralizedSelfAdjointEigenSolver<Eigen::MatrixXd>* _G = nullptr;
};
} // namespace mfem
#endif // MFEM_SPECTRA_HPP
+5
View File
@@ -82,6 +82,11 @@ public:
Vector(double *data_, int size_)
{ data.Wrap(data_, size_, false); size = size_; }
/** @brief Create a Vector referencing a sub-vector of the Vector @a base
starting at the given offset, @a base_offset, and size @a size_. */
Vector(Vector &base, int base_offset, int size_)
: data(base.data, base_offset, size_), size(size_) { }
/// Create a Vector of size @a size_ using MemoryType @a mt.
Vector(int size_, MemoryType mt)
: data(size_, mt), size(size_) { }
+6 -4
View File
@@ -119,7 +119,7 @@ $(if $(word 2,$(SRC)),$(error Spaces in SRC = "$(SRC)" are not supported))
MFEM_GIT_STRING = $(shell [ -d $(MFEM_DIR)/.git ] && git -C $(MFEM_DIR) \
describe --all --long --abbrev=40 --dirty --always 2> /dev/null)
EXAMPLE_SUBDIRS = amgx ginkgo hiop petsc pumi sundials superlu
EXAMPLE_SUBDIRS = amgx caliper ginkgo hiop petsc pumi sundials superlu
EXAMPLE_DIRS := examples $(addprefix examples/,$(EXAMPLE_SUBDIRS))
EXAMPLE_TEST_DIRS := examples
@@ -274,7 +274,7 @@ endif
# List of MFEM dependencies, that require the *_LIB variable to be non-empty
MFEM_REQ_LIB_DEPS = SUPERLU MUMPS METIS FMS CONDUIT SIDRE LAPACK SUNDIALS MESQUITE\
SUITESPARSE STRUMPACK GINKGO GNUTLS NETCDF PETSC SLEPC MPFR PUMI HIOP GSLIB\
OCCA CEED RAJA UMPIRE MKL_CPARDISO AMGX CALIPER
OCCA CEED RAJA UMPIRE MKL_CPARDISO AMGX CALIPER ARPACK
PETSC_ERROR_MSG = $(if $(PETSC_FOUND),,. PETSC config not found: $(PETSC_VARS))
SLEPC_ERROR_MSG = $(if $(SLEPC_FOUND),,. SLEPC config not found: $(SLEPC_VARS))
@@ -292,7 +292,7 @@ ifeq ($(MAKECMDGOALS),config)
endif
# List of MFEM dependencies, processed below
MFEM_DEPENDENCIES = $(MFEM_REQ_LIB_DEPS) LIBUNWIND OPENMP CUDA HIP
MFEM_DEPENDENCIES = $(MFEM_REQ_LIB_DEPS) SPECTRA LIBUNWIND OPENMP CUDA HIP
# List of deprecated MFEM dependencies, processed below
MFEM_LEGACY_DEPENDENCIES = OPENMP
@@ -340,7 +340,7 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\
MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\
MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE MFEM_USE_SIMD\
MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO MFEM_USE_AMGX MFEM_USE_MUMPS\
MFEM_USE_CALIPER MFEM_SOURCE_DIR MFEM_INSTALL_DIR
MFEM_USE_CALIPER MFEM_USE_ARPACK MFEM_USE_SPECTRA MFEM_SOURCE_DIR MFEM_INSTALL_DIR
# List of makefile variables that will be written to config.mk:
MFEM_CONFIG_VARS = MFEM_CXX MFEM_HOST_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS\
@@ -652,6 +652,8 @@ status info:
$(info MFEM_USE_SUNDIALS = $(MFEM_USE_SUNDIALS))
$(info MFEM_USE_MESQUITE = $(MFEM_USE_MESQUITE))
$(info MFEM_USE_SUITESPARSE = $(MFEM_USE_SUITESPARSE))
$(info MFEM_USE_ARPACK = $(MFEM_USE_ARPACK))
$(info MFEM_USE_SPECTRA = $(MFEM_USE_SPECTRA))
$(info MFEM_USE_SUPERLU = $(MFEM_USE_SUPERLU))
$(info MFEM_USE_MUMPS = $(MFEM_USE_MUMPS))
$(info MFEM_USE_STRUMPACK = $(MFEM_USE_STRUMPACK))
+2
View File
@@ -19,6 +19,7 @@ set(SRCS
ncmesh.cpp
nurbs.cpp
point.cpp
pyramid.cpp
quadrilateral.cpp
segment.cpp
tetrahedron.cpp
@@ -38,6 +39,7 @@ set(HDRS
ncmesh.hpp
nurbs.hpp
point.hpp
pyramid.hpp
quadrilateral.hpp
segment.hpp
tetrahedron.hpp
+1 -1
View File
@@ -39,7 +39,7 @@ public:
/// Constants for the classes derived from Element.
enum Type { POINT, SEGMENT, TRIANGLE, QUADRILATERAL,
TETRAHEDRON, HEXAHEDRON, WEDGE
TETRAHEDRON, HEXAHEDRON, WEDGE, PYRAMID
};
/// Default element constructor.
+311 -12
View File
@@ -75,7 +75,7 @@ void Mesh::GetElementCenter(int i, Vector &center)
double Mesh::GetElementSize(ElementTransformation *T, int type)
{
DenseMatrix J(Dim);
DenseMatrix J(spaceDim,Dim);
Geometry::Type geom = T->GetGeometryType();
T->SetIntPoint(&Geometries.GetCenter(geom));
@@ -83,7 +83,7 @@ double Mesh::GetElementSize(ElementTransformation *T, int type)
if (type == 0)
{
return pow(fabs(J.Det()), 1./Dim);
return pow(fabs(J.Weight()), 1./Dim);
}
else if (type == 1)
{
@@ -102,7 +102,7 @@ double Mesh::GetElementSize(int i, int type)
double Mesh::GetElementSize(int i, const Vector &dir)
{
DenseMatrix J(Dim);
DenseMatrix J(spaceDim,Dim);
Vector d_hat(Dim);
GetElementJacobian(i, J);
J.MultTranspose(dir, d_hat);
@@ -335,6 +335,7 @@ FiniteElement *Mesh::GetTransformationFEforElementType(Element::Type ElemType)
case Element::TETRAHEDRON : return &TetrahedronFE;
case Element::HEXAHEDRON : return &HexahedronFE;
case Element::WEDGE : return &WedgeFE;
case Element::PYRAMID : return &PyramidFE;
default:
MFEM_ABORT("Unknown element type \"" << ElemType << "\"");
break;
@@ -735,6 +736,31 @@ void Mesh::GetLocalTriToWdgTransformation(
}
}
void Mesh::GetLocalTriToPyrTransformation(
IsoparametricTransformation &Transf, int i)
{
DenseMatrix &locpm = Transf.GetPointMat();
Transf.SetFE(&TriangleFE);
// (i/64) is the local face no. in the pyr
MFEM_VERIFY(i >= 64, "Local face index " << i/64
<< " is not a triangular face of a pyramid.");
const int *pv = pyr_t::FaceVert[i/64];
// (i%64) is the orientation of the pyramid face
// w.r.t. the face element
const int *to = tri_t::Orient[i%64];
const IntegrationRule *PyrVert =
Geometries.GetVertices(Geometry::PYRAMID);
locpm.SetSize(3, 3);
for (int j = 0; j < 3; j++)
{
const IntegrationPoint &vert = PyrVert->IntPoint(pv[to[j]]);
locpm(0, j) = vert.x;
locpm(1, j) = vert.y;
locpm(2, j) = vert.z;
}
}
void Mesh::GetLocalQuadToHexTransformation(
IsoparametricTransformation &Transf, int i)
{
@@ -781,6 +807,29 @@ void Mesh::GetLocalQuadToWdgTransformation(
}
}
void Mesh::GetLocalQuadToPyrTransformation(
IsoparametricTransformation &Transf, int i)
{
DenseMatrix &locpm = Transf.GetPointMat();
Transf.SetFE(&QuadrilateralFE);
// (i/64) is the local face no. in the pyr
MFEM_VERIFY(i < 64, "Local face index " << i/64
<< " is not a quadrilateral face of a pyramid.");
const int *pv = pyr_t::FaceVert[i/64];
// (i%64) is the orientation of the quad
const int *qo = quad_t::Orient[i%64];
const IntegrationRule *PyrVert = Geometries.GetVertices(Geometry::PYRAMID);
locpm.SetSize(3, 4);
for (int j = 0; j < 4; j++)
{
const IntegrationPoint &vert = PyrVert->IntPoint(pv[qo[j]]);
locpm(0, j) = vert.x;
locpm(1, j) = vert.y;
locpm(2, j) = vert.z;
}
}
const GeometricFactors* Mesh::GetGeometricFactors(const IntegrationRule& ir,
const int flags,
MemoryType d_mt)
@@ -862,10 +911,19 @@ void Mesh::GetLocalFaceTransformation(
{
GetLocalTriToTetTransformation(Transf, info);
}
else if (elem_type == Element::WEDGE)
{
GetLocalTriToWdgTransformation(Transf, info);
}
else if (elem_type == Element::PYRAMID)
{
GetLocalTriToPyrTransformation(Transf, info);
}
else
{
MFEM_ASSERT(elem_type == Element::WEDGE, "");
GetLocalTriToWdgTransformation(Transf, info);
MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
"face type " << face_type
<< " and element type " << elem_type << "\n");
}
break;
@@ -874,10 +932,19 @@ void Mesh::GetLocalFaceTransformation(
{
GetLocalQuadToHexTransformation(Transf, info);
}
else if (elem_type == Element::WEDGE)
{
GetLocalQuadToWdgTransformation(Transf, info);
}
else if (elem_type == Element::PYRAMID)
{
GetLocalQuadToPyrTransformation(Transf, info);
}
else
{
MFEM_ASSERT(elem_type == Element::WEDGE, "");
GetLocalQuadToWdgTransformation(Transf, info);
MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
"face type " << face_type
<< " and element type " << elem_type << "\n");
}
break;
}
@@ -1370,6 +1437,20 @@ int Mesh::AddWedge(const int *vi, int attr)
return NumOfElements++;
}
int Mesh::AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr)
{
CheckEnlarge(elements, NumOfElements);
elements[NumOfElements] = new Pyramid(v1, v2, v3, v4, v5, attr);
return NumOfElements++;
}
int Mesh::AddPyramid(const int *vi, int attr)
{
CheckEnlarge(elements, NumOfElements);
elements[NumOfElements] = new Pyramid(vi, attr);
return NumOfElements++;
}
int Mesh::AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
int attr)
{
@@ -1423,6 +1504,25 @@ void Mesh::AddHexAsWedges(const int *vi, int attr)
}
}
void Mesh::AddHexAsPyramids(const int *vi, int attr)
{
static const int hex_to_pyr[6][5] =
{
{ 0, 1, 2, 3, 8 }, { 0, 4, 5, 1, 8 }, { 1, 5, 6, 2, 8 },
{ 2, 6, 7, 3, 8 }, { 3, 7, 4, 0, 8 }, { 7, 6, 5, 4, 8 }
};
int ti[5];
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 5; j++)
{
ti[j] = vi[hex_to_pyr[i][j]];
}
AddPyramid(ti, attr);
}
}
int Mesh::AddElement(Element *elem)
{
CheckEnlarge(elements, NumOfElements);
@@ -2692,11 +2792,16 @@ void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
NElem *= 2;
NBdrElem += 2*nx*ny;
}
else if (type == Element::PYRAMID)
{
NElem *= 6;
NVert += nx * ny * nz;
}
InitMesh(3, 3, NVert, NElem, NBdrElem);
double coord[3];
int ind[8];
int ind[9];
// Sets vertices and the corresponding coordinates
for (z = 0; z <= nz; z++)
@@ -2712,8 +2817,25 @@ void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
}
}
}
if (type == Element::PYRAMID)
{
for (z = 0; z < nz; z++)
{
coord[2] = (((double) z + 0.5) / nz) * sz;
for (y = 0; y < ny; y++)
{
coord[1] = (((double) y + 0.5 ) / ny) * sy;
for (x = 0; x < nx; x++)
{
coord[0] = (((double) x + 0.5 ) / nx) * sx;
AddVertex(coord);
}
}
}
}
#define VTX(XC, YC, ZC) ((XC)+((YC)+(ZC)*(ny+1))*(nx+1))
#define VTXP(XC, YC, ZC) ((nx+1)*(ny+1)*(nz+1)+(XC)+((YC)+(ZC)*ny)*nx)
// Sets elements and the corresponding indices of vertices
if (sfc_ordering && type == Element::HEXAHEDRON)
@@ -2764,6 +2886,11 @@ void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
{
AddHexAsWedges(ind, 1);
}
else if (type == Element::PYRAMID)
{
ind[8] = VTXP( x, y, z);
AddHexAsPyramids(ind, 1);
}
else
{
AddHex(ind, 1);
@@ -3428,6 +3555,7 @@ Element *Mesh::NewElement(int geom)
#endif
case Geometry::CUBE: return (new Hexahedron);
case Geometry::PRISM: return (new Wedge);
case Geometry::PYRAMID: return (new Pyramid);
default:
MFEM_ABORT("invalid Geometry::Type, geom = " << geom);
}
@@ -3520,6 +3648,15 @@ void Mesh::SetMeshGen()
meshgen |= 4;
break;
case Element::PYRAMID:
mesh_geoms |= (1 << Geometry::PYRAMID);
mesh_geoms |= (1 << Geometry::SQUARE);
mesh_geoms |= (1 << Geometry::TRIANGLE);
mesh_geoms |= (1 << Geometry::SEGMENT);
mesh_geoms |= (1 << Geometry::POINT);
meshgen |= 8;
break;
default:
MFEM_ABORT("invalid element type: " << type);
break;
@@ -3974,6 +4111,12 @@ void Mesh::MakeRefined_(Mesh &orig_mesh, const Array<int> ref_factors,
}
}
if (Dim > 2)
{
GetElementToFaceTable(false);
GenerateFaces();
}
// Add refined boundary elements
for (int el = 0; el < orig_mesh.GetNBE(); el++)
{
@@ -5054,6 +5197,19 @@ int Mesh::CheckElementOrientation(bool fix_it)
}
break;
case Element::PYRAMID:
// only check the Jacobian at the center of the element
GetElementJacobian(i, J);
if (J.Det() < 0.0)
{
wo++;
if (fix_it)
{
// how?
}
}
break;
case Element::HEXAHEDRON:
// only check the Jacobian at the center of the element
GetElementJacobian(i, J);
@@ -6136,6 +6292,22 @@ void Mesh::GenerateFaces()
}
break;
}
case Element::PYRAMID:
{
for (int j = 0; j < 1; j++)
{
const int *fv = pyr_t::FaceVert[j];
AddQuadFaceElement(j, ef[j], i,
v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
}
for (int j = 1; j < 5; j++)
{
const int *fv = pyr_t::FaceVert[j];
AddTriangleFaceElement(j, ef[j], i,
v[fv[0]], v[fv[1]], v[fv[2]]);
}
break;
}
case Element::HEXAHEDRON:
{
for (int j = 0; j < 6; j++)
@@ -6228,6 +6400,20 @@ STable3D *Mesh::GetFacesTable()
}
break;
}
case Element::PYRAMID:
{
for (int j = 0; j < 1; j++)
{
const int *fv = pyr_t::FaceVert[j];
faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
}
for (int j = 1; j < 5; j++)
{
const int *fv = pyr_t::FaceVert[j];
faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
}
break;
}
case Element::WEDGE:
{
for (int j = 0; j < 2; j++)
@@ -6302,6 +6488,22 @@ STable3D *Mesh::GetElementToFaceTable(int ret_ftbl)
}
break;
}
case Element::PYRAMID:
{
for (int j = 0; j < 1; j++)
{
const int *fv = pyr_t::FaceVert[j];
el_to_face->Push(
i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
}
for (int j = 1; j < 5; j++)
{
const int *fv = pyr_t::FaceVert[j];
el_to_face->Push(
i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
}
break;
}
case Element::HEXAHEDRON:
{
// find the face by the vertices with the smallest 3 numbers
@@ -7638,8 +7840,22 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
}
}
int pyr_counter = 0;
if (HasGeometry(Geometry::PYRAMID))
{
for (int i = 0; i < elements.Size(); i++)
{
if (elements[i]->GetType() == Element::PYRAMID)
{
pyr_counter++;
}
}
}
// Map from edge-index to vertex-index, needed for ReorientTetMesh() for
// parallel meshes.
// Note: with the removal of ReorientTetMesh() this may no longer
// be needed. Unfortunately, it's hard to be sure.
Array<int> e2v;
if (HasGeometry(Geometry::TETRAHEDRON))
{
@@ -7695,7 +7911,7 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
Array<Element*> new_boundary;
vertices.SetSize(oelem + hex_counter);
new_elements.SetSize(8 * NumOfElements);
new_elements.SetSize(8 * NumOfElements + 2 * pyr_counter);
CoarseFineTr.embeddings.SetSize(new_elements.Size());
hex_counter = 0;
@@ -7961,6 +8177,73 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
}
break;
case Element::PYRAMID:
{
const int *f = el_to_face->GetRow(i);
// pyr_counter++;
for (int fi = 0; fi < 1; fi++)
{
for (int k = 0; k < 4; k++)
{
vv[k] = v[pyr_t::FaceVert[fi][k]];
}
AverageVertices(vv, 4, oface + f2qf[f[fi]]);
}
for (int ei = 0; ei < 8; ei++)
{
for (int k = 0; k < 2; k++)
{
vv[k] = v[pyr_t::Edges[ei][k]];
}
AverageVertices(vv, 2, oedge+e[ei]);
}
const int qf0 = f2qf[f[0]];
new_elements[j++] =
new Pyramid(v[0], oedge+e[0], oface+qf0,
oedge+e[3], oedge+e[4], attr);
new_elements[j++] =
new Pyramid(oedge+e[0], v[1], oedge+e[1],
oface+qf0, oedge+e[5], attr);
new_elements[j++] =
new Pyramid(oface+qf0, oedge+e[1], v[2],
oedge+e[2], oedge+e[6], attr);
new_elements[j++] =
new Pyramid(oedge+e[3], oface+qf0, oedge+e[2],
v[3], oedge+e[7], attr);
new_elements[j++] =
new Pyramid(oedge+e[4], oedge+e[5], oedge+e[6],
oedge+e[7], v[4], attr);
new_elements[j++] =
new Pyramid(oedge+e[7], oedge+e[6], oedge+e[5],
oedge+e[4], oface+qf0, attr);
new_elements[j++] =
new Tetrahedron(oedge+e[0], oedge+e[4], oedge+e[5],
oface+qf0, attr);
new_elements[j++] =
new Tetrahedron(oedge+e[1], oedge+e[5], oedge+e[6],
oface+qf0, attr);
new_elements[j++] =
new Tetrahedron(oedge+e[2], oedge+e[6], oedge+e[7],
oface+qf0, attr);
new_elements[j++] =
new Tetrahedron(oedge+e[3], oedge+e[7], oedge+e[4],
oface+qf0, attr);
}
break;
case Element::HEXAHEDRON:
{
const int *f = el_to_face->GetRow(i);
@@ -8092,7 +8375,7 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
}
mfem::Swap(boundary, new_boundary);
static const double A = 0.0, B = 0.5, C = 1.0;
static const double A = 0.0, B = 0.5, C = 1.0, D = -1.0;
static double tet_children[3*4*16] =
{
A,A,A, B,A,A, A,B,A, A,A,B,
@@ -8118,6 +8401,19 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
A,A,B, A,B,B, B,A,B, B,B,A,
A,A,B, B,A,B, B,A,A, B,B,A
};
static double pyr_children[3*5*10] =
{
A,A,A, B,A,A, B,B,A, A,B,A, A,A,B,
B,A,A, C,A,A, C,B,A, B,B,A, B,A,B,
B,B,A, C,B,A, C,C,A, B,C,A, B,B,B,
A,B,A, B,B,A, B,C,A, A,C,A, A,B,B,
A,A,B, B,A,B, B,B,B, A,B,B, A,A,C,
A,B,B, B,B,B, B,A,B, A,A,B, B,B,A,
B,A,A, A,A,B, B,A,B, B,B,A, D,D,D,
C,B,A, B,A,B, B,B,B, B,B,A, D,D,D,
B,C,A, B,B,B, A,B,B, B,B,A, D,D,D,
A,B,A, A,B,B, A,A,B, B,B,A, D,D,D
};
static double pri_children[3*6*8] =
{
A,A,A, B,A,A, A,B,A, A,A,B, B,A,B, A,B,B,
@@ -8143,6 +8439,8 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
CoarseFineTr.point_matrices[Geometry::TETRAHEDRON]
.UseExternalData(tet_children, 3, 4, 16);
CoarseFineTr.point_matrices[Geometry::PYRAMID]
.UseExternalData(pyr_children, 3, 5, 10);
CoarseFineTr.point_matrices[Geometry::PRISM]
.UseExternalData(pri_children, 3, 6, 8);
CoarseFineTr.point_matrices[Geometry::CUBE]
@@ -8159,7 +8457,7 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
}
NumOfVertices = vertices.Size();
NumOfElements = 8 * NumOfElements;
NumOfElements = 8 * NumOfElements + 2 * pyr_counter;
NumOfBdrElements = 4 * NumOfBdrElements;
GetElementToFaceTable();
@@ -8743,7 +9041,7 @@ void Mesh::GeneralRefinement(const Array<Refinement> &refinements,
else if (nonconforming < 0)
{
// determine if nonconforming refinement is suitable
if ((meshgen & 2) || (meshgen & 4))
if ((meshgen & 2) || (meshgen & 4) || (meshgen & 8))
{
nonconforming = 1; // tensor product elements and wedges
}
@@ -9527,6 +9825,7 @@ void Mesh::Printer(std::ostream &out, std::string section_delimiter) const
"# TETRAHEDRON = 4\n"
"# CUBE = 5\n"
"# PRISM = 6\n"
"# PYRAMID = 7\n"
"#\n";
out << "\ndimension\n" << Dim;
+20 -2
View File
@@ -177,6 +177,7 @@ protected:
int own_nodes;
static const int vtk_quadratic_tet[10];
static const int vtk_quadratic_pyramid[13];
static const int vtk_quadratic_wedge[18];
static const int vtk_quadratic_hex[27];
@@ -195,6 +196,7 @@ public:
typedef Geometry::Constants<Geometry::TETRAHEDRON> tet_t;
typedef Geometry::Constants<Geometry::CUBE> hex_t;
typedef Geometry::Constants<Geometry::PRISM> pri_t;
typedef Geometry::Constants<Geometry::PYRAMID> pyr_t;
enum Operation { NONE, REFINE, DEREFINE, REBALANCE };
@@ -373,11 +375,17 @@ protected:
void GetLocalTriToWdgTransformation (IsoparametricTransformation &loc,
int i);
/// Used in GetFaceElementTransformations (...)
void GetLocalTriToPyrTransformation (IsoparametricTransformation &loc,
int i);
/// Used in GetFaceElementTransformations (...)
void GetLocalQuadToHexTransformation (IsoparametricTransformation &loc,
int i);
/// Used in GetFaceElementTransformations (...)
void GetLocalQuadToWdgTransformation (IsoparametricTransformation &loc,
int i);
/// Used in GetFaceElementTransformations (...)
void GetLocalQuadToPyrTransformation (IsoparametricTransformation &loc,
int i);
/** Used in GetFaceElementTransformations to account for the fact that a
slave face occupies only a portion of its master face. */
@@ -503,7 +511,7 @@ public:
Mesh& operator=(Mesh &&mesh);
/// Explicitly delete the copy assignment operator.
Mesh& operator=(Mesh &mesh) = delete;
Mesh& operator=(const Mesh &mesh) = delete;
/** @name Named mesh constructors.
@@ -657,11 +665,15 @@ public:
int AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr = 1);
int AddWedge(const int *vi, int attr = 1);
int AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr = 1);
int AddPyramid(const int *vi, int attr = 1);
int AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
int attr = 1);
int AddHex(const int *vi, int attr = 1);
void AddHexAsTets(const int *vi, int attr = 1);
void AddHexAsWedges(const int *vi, int attr = 1);
void AddHexAsPyramids(const int *vi, int attr = 1);
/// The parameter @a elem should be allocated using the NewElement() method
int AddElement(Element *elem);
@@ -829,10 +841,16 @@ public:
/** @brief Get the mesh generator/type.
The purpose of this is to be able to quickly tell what type of elements
one has in the mesh. Examination of this bitmask along with knowledge
of the mesh dimension can be used to identify which element types are
present.
@return A bitmask:
- bit 0 - simplices are present in the mesh (triangles, tets),
- bit 1 - tensor product elements are present in the mesh (quads, hexes),
- bit 2 - the mesh has wedge elements.
- bit 3 - the mesh has pyramid elements.
In parallel, the result takes into account elements on all processors.
*/
@@ -1227,7 +1245,7 @@ public:
satisfy: v0 < min(v1, v2).
@note Refinement does not work after a call to this method! */
virtual void ReorientTetMesh();
MFEM_DEPRECATED virtual void ReorientTetMesh();
int *CartesianPartitioning(int nxyz[]);
int *GeneratePartitioning(int nparts, int part_method = 1);
+1
View File
@@ -27,6 +27,7 @@
#include "mesh_operators.hpp"
#include "nurbs.hpp"
#include "wedge.hpp"
#include "pyramid.hpp"
#ifdef MFEM_USE_MESQUITE
#include "mesquite.hpp"
+61 -21
View File
@@ -352,6 +352,11 @@ void Mesh::ReadTrueGridMesh(std::istream &input)
const int Mesh::vtk_quadratic_tet[10] =
{ 0, 1, 2, 3, 4, 7, 5, 6, 8, 9 };
// see Pyramid::edges & Mesh::GenerateFaces
// https://www.vtk.org/doc/nightly/html/classvtkBiQuadraticQuadraticWedge.html
const int Mesh::vtk_quadratic_pyramid[13] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
// see Wedge::edges & Mesh::GenerateFaces
// https://www.vtk.org/doc/nightly/html/classvtkBiQuadraticQuadraticWedge.html
const int Mesh::vtk_quadratic_wedge[18] =
@@ -514,8 +519,7 @@ void Mesh::CreateVTKMesh(const Vector &points, const Array<int> &cell_data,
}
}
}
// Generate faces and edges so that we can define
// FE space on the mesh
// Generate faces and edges so that we can define FE space on the mesh
FinalizeTopology();
FiniteElementCollection *fec;
@@ -546,6 +550,8 @@ void Mesh::CreateVTKMesh(const Vector &points, const Array<int> &cell_data,
vtk_mfem = vtk_quadratic_hex; break;
case Geometry::PRISM:
vtk_mfem = vtk_quadratic_wedge; break;
case Geometry::PYRAMID:
vtk_mfem = vtk_quadratic_pyramid; break;
default:
vtk_mfem = NULL; // suppress a warning
break;
@@ -1394,6 +1400,10 @@ void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges)
{
type = Element::WEDGE;
}
else if (eltype == "pyramid")
{
type = Element::PYRAMID;
}
else if (eltype == "tet")
{
type = Element::TETRAHEDRON;
@@ -1448,7 +1458,7 @@ void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges)
Make2D(nx, ny, type, sx, sy, generate_edges, true);
}
else if (type == Element::TETRAHEDRON || type == Element::WEDGE ||
type == Element::HEXAHEDRON)
type == Element::HEXAHEDRON || type == Element::PYRAMID)
{
MFEM_VERIFY(nx > 0 && ny > 0 && nz > 0 &&
sx > 0.0 && sy > 0.0 && sz > 0.0,
@@ -1885,6 +1895,9 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
ho_wdg[2] = wdg18; ho_wdg[3] = wdg40;
ho_pyr[2] = pyr14; ho_pyr[3] = pyr30;
bool has_nonpositive_phys_domain = false;
bool has_positive_phys_domain = false;
if (binary)
{
int n_elem_part = 0; // partial sum of elements that are read
@@ -1935,17 +1948,19 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
vert_indices[vi] = it->second;
}
// non-positive attributes are not allowed in MFEM
// Non-positive attributes are not allowed in MFEM. However,
// by default, Gmsh sets the physical domain of all elements
// to zero. In the case that all elements have physical domain
// zero, we will given them attribute 1. If only some elements
// have physical domain zero, we will throw an error.
if (phys_domain <= 0)
{
MFEM_ABORT("Non-positive element attribute in Gmsh mesh!\n"
"By default Gmsh sets element tags (attributes)"
" to '0' but MFEM requires that they be"
" positive integers.\n"
"Use \"Physical Curve\", \"Physical Surface\","
" or \"Physical Volume\" to set tags/attributes"
" for all curves, surfaces, or volumes in your"
" Gmsh geometry to values which are >= 1.");
has_nonpositive_phys_domain = true;
phys_domain = 1;
}
else
{
has_positive_phys_domain = true;
}
// initialize the mesh element
@@ -2162,17 +2177,19 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
vert_indices[vi] = it->second;
}
// non-positive attributes are not allowed in MFEM
// Non-positive attributes are not allowed in MFEM. However,
// by default, Gmsh sets the physical domain of all elements
// to zero. In the case that all elements have physical domain
// zero, we will given them attribute 1. If only some elements
// have physical domain zero, we will throw an error.
if (phys_domain <= 0)
{
MFEM_ABORT("Non-positive element attribute in Gmsh mesh!\n"
"By default Gmsh sets element tags (attributes)"
" to '0' but MFEM requires that they be"
" positive integers.\n"
"Use \"Physical Curve\", \"Physical Surface\","
" or \"Physical Volume\" to set tags/attributes"
" for all curves, surfaces, or volumes in your"
" Gmsh geometry to values which are >= 1.");
has_nonpositive_phys_domain = true;
phys_domain = 1;
}
else
{
has_positive_phys_domain = true;
}
// initialize the mesh element
@@ -2357,6 +2374,24 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
} // el (all elements)
} // if ASCII
if (has_positive_phys_domain && has_nonpositive_phys_domain)
{
MFEM_ABORT("Non-positive element attribute in Gmsh mesh!\n"
"By default Gmsh sets element tags (attributes)"
" to '0' but MFEM requires that they be"
" positive integers.\n"
"Use \"Physical Curve\", \"Physical Surface\","
" or \"Physical Volume\" to set tags/attributes"
" for all curves, surfaces, or volumes in your"
" Gmsh geometry to values which are >= 1.");
}
else if (has_nonpositive_phys_domain)
{
mfem::out << "\nGmsh reader: all element attributes were zero.\n"
<< "MFEM only supports positive element attributes.\n"
<< "Setting element attributes to 1.\n\n";
}
if (!elements_3D.empty())
{
Dim = 3;
@@ -2445,6 +2480,10 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
// initialize mesh_geoms so we can create Nodes FE space below
this->SetMeshGen();
// Generate faces and edges so that we can define
// FE space on the mesh
this->FinalizeTopology();
// Construct GridFunction for uniformly spaced high order coords
FiniteElementCollection* nfec;
FiniteElementSpace* nfes;
@@ -2666,6 +2705,7 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
// Convert nodes to discontinuous GridFunction (if they aren't already)
if (mesh_order == 1)
{
this->FinalizeTopology();
this->SetMeshGen();
this->SetCurvature(1, true, spaceDim, Ordering::byVDIM);
}
-1
View File
@@ -2283,7 +2283,6 @@ void NCMesh::GetMeshComponents(Mesh &mesh) const
// left uninitialized here; they will be initialized later by the Mesh from
// Nodes -- here we just make sure mesh.vertices has the correct size.
mesh.elements.SetSize(NElements);
mesh.elements.SetSize(0);
mesh.boundary.SetSize(0);

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