Compare commits

...
Author SHA1 Message Date
IdoAkkerman b09b5dbab5 Fix test error 2024-06-12 16:42:22 +02:00
IdoAkkerman ece1b1fd3d More merge fix stuff 2024-06-12 16:42:06 +02:00
IdoAkkerman 86f72cd22e Merge remote-tracking branch 'origin/master' into dev-stab-mini 2024-06-12 16:41:21 +02:00
IdoAkkerman 97c4aed444 Add nullspace unit test 2024-06-12 14:48:42 +02:00
IdoAkkerman 03199fe1fd Small parallel printing fix 2024-06-12 14:46:26 +02:00
IdoAkkerman aed9945c40 Clean up 2024-06-12 14:46:02 +02:00
IdoAkkerman 25d65f4275 Make style 2024-06-12 14:44:51 +02:00
IdoAkkerman 05989d5d29 Stab Navsto miniapps tweaks 2024-06-12 14:41:32 +02:00
IdoAkkerman 5d762f7cb5 Use EV routines in Dense=Matrix for InverseEstimate coefficients + make style 2024-06-12 14:37:11 +02:00
IdoAkkerman bf5c6ebd23 More eigen problem related routines to densemat 2024-06-12 14:36:08 +02:00
Tzanio Kolev 8153d11274 Merge pull request #3999 from mfem/hdiv-nurbs
Adding H(div) and H(curl) conforming NURBS FiniteElements
2024-06-11 22:37:08 +01:00
Tzanio Kolev 827ed64113 Merge branch 'master' into hdiv-nurbs 2024-06-11 22:36:58 +01:00
Tzanio Kolev ef9f02ba53 Merge pull request #2854 from mfem/var-order-href-op
Variable order space: h-(de)refinement transfer operator
2024-06-11 20:25:12 +01:00
Tzanio Kolev e9a0b0620a Update tests/unit/fem/test_hp_transfer.cpp 2024-06-11 12:24:39 -07:00
Tzanio Kolev 4d9d444248 Merge pull request #4343 from mfem/sample-runs-update
Sample runs update
2024-06-11 20:23:41 +01:00
Tzanio Kolev 6e2badecca Merge pull request #4337 from mfem/lapack-cleanup
Deduplicate single/double precision LAPACK
2024-06-11 20:22:01 +01:00
Tzanio Kolev 99b45fcb02 Merge pull request #4327 from mfem/sjg/mesh-vertex-bdr-table
Add `Mesh::GetVertexToBdrElementTable`
2024-06-11 20:20:12 +01:00
Will Pazner 9a327eeca6 Merge pull request #4332 from mfem/sjg/cuda-atomicadd-fix
Fix compiler error for `real_t` and old CUDA architectures < 60
2024-06-10 17:07:12 -04:00
IdoAkkerman a1d003aec0 Add parallel navsto 2024-06-10 15:31:07 +02:00
IdoAkkerman fa87595f9a Add elastic inverse estimate - a.o. 2024-06-10 15:30:44 +02:00
IdoAkkerman c4697ba253 Tweaks in powermethod 2024-06-10 15:29:19 +02:00
IdoAkkerman 5e01a5433d IMPORTANT: Add HESS as derivType 2024-06-10 09:16:46 +02:00
IdoAkkerman 4833b17636 IMPORTANT: reordering hessian 2024-06-10 09:12:02 +02:00
IdoAkkerman 34378ffc5b Stab navsto kind of works 2024-06-06 17:03:11 +02:00
IdoAkkerman a6e3e8e695 Begin of stab nav sto implementation 2024-06-06 14:47:27 +02:00
IdoAkkerman 8af34d985e Add delta 2024-06-06 11:59:31 +02:00
IdoAkkerman 0f55696c69 Remove print statement 2024-06-06 11:58:52 +02:00
IdoAkkerman f4a6f33284 Fix small bug -- add interface 2024-06-06 11:56:42 +02:00
IdoAkkerman 781efd2d50 Taus in seperate file + put tau in place for stab nav sto 2024-06-06 09:40:57 +02:00
IdoAkkerman 9035279bcb Reinstate scaling in inverse estimate computation 2024-06-06 09:39:20 +02:00
Will Pazner 262fa6173d Remove unneeded '#ifdef MFEM_USE_SINGLE' 2024-06-05 21:20:59 -07:00
Will Pazner e4b8584a16 Formatting 2024-06-05 21:20:59 -07:00
Socratis Petrides 7912d6915d silly mistake 2024-06-05 18:16:45 -07:00
Socratis Petrides 293d9009ae replace abort with skip so that make test passes with lapack 2024-06-05 17:25:00 -07:00
Socratis Petrides 51bde67bb1 fixing default tol in eltrans 2024-06-05 17:24:24 -07:00
Sebastian Grimberg 45e2636921 Address PR feedback: Add const 2024-06-05 14:19:49 -07:00
Tzanio Kolev c3eb769a2a Merge pull request #4330 from mfem/CurlDim-bugfix
GridFunction::CurlDim() nullptr fix
2024-06-05 11:49:58 +01:00
Tzanio Kolev 9286d89b0e Merge branch 'master' into CurlDim-bugfix 2024-06-05 11:49:08 +01:00
IdoAkkerman 613a55d318 Add convection to navsto 2024-06-05 10:58:06 +02:00
Veselin Dobrev 35225e045e Updated the script 'config/sample-runs.sh' to
* run examples 40-99
* run autodiff, dpg, hdiv-linear-solver, and moonolith miniapps
* run additional meshing miniapps
* add 'todo' comments for other missing miniapps

Updated the formatting of sample runs in miniapps/dpg.
2024-06-04 14:17:13 -07:00
Socratis Petrides 22c1087503 VariableOrderRefinementMatrix_main -> VariableOrderRefinementMatrix 2024-06-04 11:32:24 -07:00
IdoAkkerman 732e3c33f4 Galerkin Stokes -- > needs checking 2024-06-04 17:58:50 +02:00
IdoAkkerman 0586c0feee Tweak examples 2024-06-04 12:42:18 +02:00
IdoAkkerman 7e1186afd2 Tweaks 2024-06-04 12:24:10 +02:00
IdoAkkerman ffd3088722 Cleanup stuff 2024-06-04 11:47:54 +02:00
Socratis Petrides cd5d2f7c04 minor tweaks 2024-06-03 22:21:20 -07:00
Will Pazner cbae29ad06 Suppress Doxygen warnings in LAPACK header
Otherwise Doxygen complains:

warning: documented symbol 'void mfem::MFEM_LAPACK_PREFIX' was not declared or defined.
2024-06-02 13:21:37 -07:00
Will Pazner 4c1d842c72 Adjust tolerances depending on single or double precision
ex38 was not converging in single precision with previous tolerances
2024-06-02 13:21:37 -07:00
Will Pazner 4aa0ed52af Don't duplicate single and double precision LAPACK code
Introduce MFEM_LAPACK_PREFIX and MFEM_LAPACK_COMPLEX to prepend 's', 'd', 'c',
or 'z' to the BLAS/LAPACK function name according to the precision.

Add new header lapack.hpp with declarations of the LAPACK functions.
2024-06-02 13:06:51 -07:00
Tzanio Kolev 7e8fc14b25 Merge pull request #4248 from mfem/ex40
Eikonal solver for MFEM
2024-06-01 14:03:22 -07:00
Veselin Dobrev fca4c314d4 Remove the old field 'GridFunction::fec' since the deprecation
attribute does not work as expected with GCC.

Add a CHANGELOG entry about the renaming 'fec' -> 'fec_owned' in
class GridFunction.

Fixed two GCC warnings that do not show up in CI.
2024-05-31 17:53:18 -07:00
Socratis Petrides 8712d02570 remove leftover RT space from enum 2024-05-31 11:17:00 -07:00
Socratis Petrides e5fec6279b minor fix 2024-05-31 11:11:24 -07:00
Socratis Petrides e90e96f9a5 add unit L2 test 2024-05-31 11:04:51 -07:00
Veselin Dobrev 459def6d79 Fix the build with PUMI support enabled.
For backward compatibility, define `GridFunction::fec` as a deprecated
reference to `GridFunction::fec_owned`.

Fix a few warnings in the PUMI examples.
2024-05-31 10:15:56 -07:00
Will Pazner f252efd40a Merge pull request #4322 from mfem/bugfix/socketbuf-reporting
Change socketbuf::open return statement to account for no connections established.
2024-05-31 09:29:36 -07:00
Sebastian Grimberg cc00ef7d90 Fix compiler error for real_t and old CUDA architectures pre-6.0 2024-05-30 13:52:27 -07:00
Tzanio Kolev 9f7cc58596 Merge branch 'master' into ex40 2024-05-29 17:06:07 -07:00
Tzanio Kolev cf86062f95 minor 2024-05-29 16:30:01 -07:00
Socratis Petrides a5d230f199 minor 2024-05-29 12:11:32 -07:00
IdoAkkerman 62c535d0ee Merge branch 'hdiv-nurbs' of github.com:mfem/mfem into hdiv-nurbs 2024-05-29 17:56:33 +02:00
IdoAkkerman 17829d1c38 Seperate NURBS examples in dox - small typo 2024-05-29 17:56:15 +02:00
IdoAkkerman dd198ce3f9 Seperate NURBS examples in dox 2024-05-29 17:54:43 +02:00
IdoAkkerman b9f36468ba Move changes to v 4.7.1 2024-05-29 17:45:30 +02:00
IdoAkkerman d5b127caff Remove tad files from CMake 2024-05-29 17:24:53 +02:00
Brendan Keith a210103209 CHANGELOG and newlines 2024-05-29 11:00:11 -04:00
Tzanio Kolev 76bcd044d0 Merge branch 'master' into hdiv-nurbs 2024-05-29 07:49:33 -07:00
Tzanio Kolev 0d1d69c337 Merge pull request #4316 from mfem/woptim/gitlab-updates
gitlab updates
2024-05-29 07:34:57 -07:00
Socratis Petrides 84ce403ffb fix doxygen 2024-05-28 17:42:24 -07:00
Socratis Petrides df09aea4da rename GridFunction member variable fec 2024-05-28 17:31:15 -07:00
Socratis Petrides d2840464ba null fec pointer fix 2024-05-28 14:32:11 -07:00
Tzanio Kolev 41a40ebf57 Merge pull request #4231 from mfem/2x2_matrix_exponential
ExponentialMatrixCoefficient class
2024-05-28 12:15:31 -07:00
Tzanio Kolev 80f0f6cdb9 Merge pull request #4259 from mfem/hughcars/nc-internal-bdr-project-fix
Fix projection onto NC internal faces
2024-05-28 12:15:13 -07:00
Christopher vogl 3a65277b24 allowed for soft failures in socketbuf::open with OS X sockets setting NOSIGPIPE 2024-05-28 10:52:59 -07:00
IdoAkkerman a2132dac0c Add biharm example 2024-05-28 09:56:47 +02:00
IdoAkkerman 28916b23a4 Merge branch 'master' into hdiv-nurbs 2024-05-27 10:24:58 +02:00
IdoAkkerman 7476c00f2b Solenoidal convergence check SINGLE/DOUBLE 2024-05-27 10:23:03 +02:00
Tzanio Kolev c7772c33dc Merge branch 'master' into ex40 2024-05-26 14:23:41 -07:00
Tzanio Kolev 770bcab911 Merge branch 'master' into hughcars/nc-internal-bdr-project-fix 2024-05-26 12:27:32 -07:00
Tzanio Kolev ec519e1de4 Merge pull request #4266 from mfem/tmop-fitting-interface
Update surface fitting to support gradient and Hessian transfer from initial mesh
2024-05-26 12:27:12 -07:00
Tzanio Kolev 582f6a2f6e Merge pull request #4311 from mfem/ex14-device-tests
Add device tests for ex14 and ex14p
2024-05-26 12:26:15 -07:00
Tzanio Kolev 712a3941cf Merge pull request #4239 from mfem/vtu-attribute-material
Allow reading attributes from VTK meshes with "attribute" cell data
2024-05-26 12:25:36 -07:00
Socratis Petrides 7a0137c496 generalize unit test 2024-05-24 12:49:18 -07:00
Socratis Petrides 4267b2af05 fix for using Rhp in the deref case and addressing reviewer comments 2024-05-24 12:48:51 -07:00
Socratis Petrides e37daad5eb fix from Dylan 2024-05-24 12:48:10 -07:00
IdoAkkerman 289a241f81 Add an alpha term 2024-05-24 15:43:29 +02:00
IdoAkkerman d0850268e3 Removed files 2024-05-24 15:42:27 +02:00
IdoAkkerman 133bf60546 make style 2024-05-24 15:41:50 +02:00
IdoAkkerman 9f13192930 InverseEstimateFix 2024-05-24 15:41:10 +02:00
Socratis Petrides 20b4b72071 Merge branch 'master' into var-order-href-op 2024-05-23 19:25:48 -07:00
Sebastian Grimberg ddf80492c5 Add Mesh::GetVertexToBdrElementTable 2024-05-23 11:13:16 -07:00
Brendan Keith 2636fffda9 resolve merge conflict 2024-05-23 11:44:11 -04:00
Brendan Keith 2489c68047 addressing review suggestions 2024-05-23 11:40:12 -04:00
IdoAkkerman 60d70b7d3d Make style 2024-05-23 13:53:32 +02:00
IdoAkkerman 7f946e0920 Revert "Add MixedLaplaceIntegrator class"
This reverts commit 9dbc125598.
2024-05-23 13:48:11 +02:00
IdoAkkerman 0456014a32 Merge branch 'dev-stab-mini' of /home/ido/Data/mfem/mfem into dev-stab-mini 2024-05-23 13:39:48 +02:00
IdoAkkerman 77d98d68c3 Make style + bug fix 2024-05-23 13:39:45 +02:00
Adrien M. BERNEDE 569bb11b93 Update comment 2024-05-23 11:24:51 +02:00
Adrien M. BERNEDE cdd8128966 Update allocation queue in baseline script 2024-05-23 11:23:36 +02:00
Adrien M. BERNEDE a4e2605681 Merge branch 'master' into woptim/gitlab-updates 2024-05-23 11:17:24 +02:00
Brendan Keith f35451744f CHANGELOG and doc/CodeDocumentation.dox 2024-05-22 20:30:08 -04:00
Brendan KeithandSocratis Petrides b16a179b62 Update examples/ex40p.cpp
Co-authored-by: Socratis Petrides <petrides1@llnl.gov>
2024-05-22 20:21:47 -04:00
Brendan KeithandSocratis Petrides 12c096a256 Update examples/ex40.cpp
Co-authored-by: Socratis Petrides <petrides1@llnl.gov>
2024-05-22 20:21:21 -04:00
Christopher vogl d64b83e7fb implemented @v-dobrev's fix so that the socketbuf properly returns failure if no connection 2024-05-22 16:22:27 -07:00
Tzanio Kolev 77b081a4eb Merge branch 'master' into vtu-attribute-material 2024-05-22 14:08:56 -07:00
Tzanio Kolev 8c47291d30 Merge branch 'master' into ex14-device-tests 2024-05-22 14:08:48 -07:00
Tzanio Kolev 0406101e29 Merge pull request #4271 from mfem/symmatcoeff-project-fix
Fix `SymmetricMatrixCoefficient::ProjectSymmetric` bug
2024-05-22 14:03:43 -07:00
Mittal, Ketan 15600451c0 Merge branch 'tmop-fitting-interface' of https://github.com/mfem/mfem into tmop-fitting-interface 2024-05-22 13:23:09 -07:00
Mittal, Ketan 1f9c75585e add mfem_use_mpi guard in gslib 2024-05-22 11:59:42 -07:00
Vladimir Z Tomov c07bce73af Merge branch 'master' into tmop-fitting-interface 2024-05-22 11:23:35 -07:00
Will Pazner acf510594e Merge pull request #4302 from mfem/najlkin/doc-mesh-periodic
Improved documentation of Mesh::MakePeriodic()
2024-05-22 09:19:25 -07:00
IdoAkkerman f8d18cd4be Merge branch 'master' into hdiv-nurbs 2024-05-22 17:45:58 +02:00
IdoAkkerman 994d83dd80 Modify tolerance for single precision - more relaxed 2024-05-22 17:44:17 +02:00
Tzanio Kolev 14db63647d Merge pull request #4215 from mfem/tmop-fitting-convergence
TMOP+Fitting - enable residual based convergence with adaptive fitting weight
2024-05-22 08:43:02 -07:00
IdoAkkerman f218efae09 Modify tolerance for single precision 2024-05-22 16:06:11 +02:00
IdoAkkerman 9bea5c01b7 Merge remote-tracking branch 'origin/hdiv-nurbs' into dev-stab-mini 2024-05-22 10:43:37 +02:00
Veselin Dobrev 1bc5a0c5e4 Fix use-after-delete bug in one of the HypreParMatrix constructors 2024-05-21 21:53:12 -07:00
Veselin Dobrev be0d8751a4 Small GNU make tweak to support out-of-source testing in tests/unit
without the need to build 'all'.
2024-05-21 21:49:35 -07:00
Mittal, Ketan 4ee1bcd561 double -> real_t 2024-05-21 16:02:38 -07:00
Mittal, Ketan 69a4a38053 remove unneeded flag 2024-05-21 15:36:49 -07:00
Mittal, Ketan e195a709ff better documentation and changed some logic 2024-05-21 15:31:22 -07:00
Vladimir Z Tomov a910f49710 minor 2024-05-21 14:01:57 -07:00
Tzanio Kolev 6355d3f4c0 Merge branch 'master' into ex40 2024-05-21 11:37:20 -07:00
Tzanio Kolev 2392aac78e Merge branch 'master' into 2x2_matrix_exponential 2024-05-21 11:35:36 -07:00
Tzanio Kolev 198ccef4c1 Merge branch 'master' into najlkin/doc-mesh-periodic 2024-05-21 11:28:56 -07:00
Tzanio Kolev 627ff3ee7e Merge branch 'master' into vtu-attribute-material 2024-05-21 11:28:51 -07:00
Tzanio Kolev f393750bd6 Merge branch 'master' into ex14-device-tests 2024-05-21 11:28:24 -07:00
Mittal, Ketan 9cfae52d1e minor changes based on reviewer comments 2024-05-21 10:07:48 -07:00
michi002 9dbc125598 Add MixedLaplaceIntegrator class
This commit introduces the MixedLaplaceIntegrator class in bilininteg.hpp and implements its methods in bilininteg.cpp. This class is for integrating the bilinear form $(Q\Delta u,v)$ where $Q$ is a scalar coefficient, $u$ is in a $C^1$ nurbs space and $v$ is defined on the same nurbs mesh. It is a reimplementation of "LaplaceIntegrator" for mixed spaces. Attention: Don't we need a "CalcPhysLaplacian" in the original routine?
2024-05-21 12:42:03 +02:00
Ido Akkerman af24eaea27 Merge branch 'master' into hdiv-nurbs 2024-05-21 10:57:13 +02:00
Adrien M. BERNEDE a482722cda Use CI reservation on Lassen, use CI reservation at job level on quartz (for jobs re-run) 2024-05-21 10:44:40 +02:00
Adrien M. BERNEDE 41d3b5dfb5 Include changes required by LC relative to token management in GitLab 2024-05-21 10:39:44 +02:00
Veselin Dobrev 4d4d8c46a7 Forgot to change the names of the Gitlab tests on Lassen to use
'gcc' instead of 'xl'.
2024-05-21 00:52:56 -07:00
Veselin Dobrev b946917551 Switch the compiler for gitlab testing on Lassen from IBM XL C++ to
GCC 8.3.1 since the '-O3' flag breaks the XL C++ build. To facilitate
this switch, a new version of mfem-uberenv repository was needed and
it is now set in the 'tests/gitlab/get_mfem_uberenv' script.
2024-05-21 00:28:44 -07:00
Vladimir Z Tomov e358c400ab minor 2024-05-20 14:48:47 -07:00
Vladimir Z Tomov cd6b864e9c Merge branch 'master' into tmop-fitting-interface 2024-05-20 13:41:58 -07:00
Vladimir Z Tomov 792700d7b1 minor 2024-05-20 13:41:05 -07:00
Tzanio Kolev 8ed6d6d2d2 Merge pull request #4310 from mfem/hypre-reader-fixes
Hypre matrix reader fixes
2024-05-20 13:40:28 -07:00
Tzanio Kolev 800b17838a Merge pull request #4115 from mfem/operator-doc
Refactored TimeDependentOperator Documentation [operator-doc]
2024-05-20 13:39:29 -07:00
Jan Nikl a17333cb19 Fixed host access in SymmetricMatrixCoefficient::ProjectSymmetric(). 2024-05-20 09:21:54 -07:00
Jan Nikl e0982be906 Merge branch 'master' into symmatcoeff-project-fix 2024-05-20 09:21:08 -07:00
Hugh Carson c64f672dbf Merge remote-tracking branch 'origin/master' into hughcars/nc-internal-bdr-project-fix 2024-05-20 10:43:52 -04:00
Hugh Carson a7236656ad Fix double space, add assertion of coef > 0 2024-05-20 10:43:20 -04:00
Vladimir Z Tomov b4ccaa3a7b improved the fitting+gslib tests, removed -ni parameter from all. 2024-05-18 16:51:01 -07:00
Tzanio Kolev 3e8379105e Merge branch 'master' into operator-doc 2024-05-18 12:42:08 -07:00
Tzanio Kolev b8d7d71350 Merge branch 'master' into hypre-reader-fixes 2024-05-18 12:37:57 -07:00
Vladimir Z Tomov 9145b88b31 minor 2024-05-17 15:49:51 -07:00
Jan Nikl 271d3a74f5 Reformulated Mesh::MakePeriodic docstring a bit. 2024-05-17 10:18:11 -07:00
Tzanio Kolev 13e1067cd1 minor 2024-05-16 17:37:16 -07:00
Will Pazner 14b1c27dc5 Override flags for ex14 and ex14p device tests 2024-05-16 16:06:56 -07:00
Will Pazner 8da512d5cf Factor out hypre row and col start comparison logic
Create new static functions GetPartitioningArraySize and
RowAndColStartsAreEqual.
2024-05-16 14:46:20 -07:00
Will Pazner 8be0dee008 Use MPI_Allreduce in HypreParMatrix ctor to determine whether to reorder
This ensures the same decision is made across all ranks
2024-05-16 14:30:11 -07:00
Will Pazner 52d467de56 Add device tests for ex14 and ex14p 2024-05-16 12:38:41 -07:00
Will Pazner 8fa1374178 More robust check for diagonal blocks in HypreParMatrix constructor
If the owned rows and columns are the same, the block is diagonal, and the
matrix is reordered so that the diagonal entry comes first.

Previously this was done by checking pointer equality, which may have false
negatives.
2024-05-16 11:22:17 -07:00
Will Pazner a3ce26485f Use WrapHypreParCSRMatrix in HypreParMatrix::Read and HypreParMatrix::Read_IJMatrix
This ensures that the MemoryIJData is set up properly. Otherwise, many
operations will crash because Read(), HostRead(), HypreRead() will not work
properly.
2024-05-16 11:20:09 -07:00
Will Pazner 8342bc06f0 Clarify docs that files saved with HypreParMatrix::Print should be read with HypreParMatrix::Read_IJMatrix 2024-05-16 11:18:07 -07:00
Will Pazner c742675da0 Use const std::string& instead of const char* in Hypre API 2024-05-16 11:17:35 -07:00
Mittal, Ketan 1dd2c75a33 rename variables and methods for consistency 2024-05-16 10:29:50 -07:00
Hugh Carson 71ad30fc01 Merge remote-tracking branch 'origin/master' into hughcars/nc-internal-bdr-project-fix 2024-05-15 16:07:00 -04:00
Hugh Carson 75bffa67f5 Address reviewer feedback:
- Move unit test to serial code, fix missing one sided NC refinement
- Remove comment debris
2024-05-15 16:06:09 -04:00
Joseph Signorelli 98341269cc Randomize unit test vector values 2024-05-15 14:07:03 -05:00
Joseph Signorelli 54dcdc720f Keep but deprecated SymmetricMatrixCoefficient::GetMatrix 2024-05-15 14:01:53 -05:00
IdoAkkerman 8adb7461b0 Comment on array of NURBSexts 2024-05-15 10:38:14 +02:00
Joseph Signorelli 89bb3348eb style 2024-05-14 14:57:39 -05:00
Joseph Signorelli 69ac6a0d1a Add reg test for SymmetricMatrixCoefficient 2024-05-14 14:52:35 -05:00
Joseph Signorelli 2b6029a416 Rename auxiliary matrix used in SymmetricMatrixCoefficient + move GetMatrix to Constant one 2024-05-14 14:51:51 -05:00
Joseph Signorelli c54e92aff1 Add copy of DenseSymmetricMatrix = operator fxn 2024-05-14 14:51:12 -05:00
Joseph Signorelli d89cceaaca Do not override Matrix::Print with an un-implemented version in DenseSymmetricMatrix 2024-05-14 13:54:29 -05:00
Mittal, Ketan 59d40f14fc doxygen 2024-05-14 10:07:05 -07:00
Mittal, Ketan fbbc3bbad0 doxygen comments and modify miniapp to use new methods 2024-05-14 10:03:51 -07:00
Joseph Signorelli 62a57c30bd Merge branch 'master' of github.com:mfem/mfem into symmatcoeff-project-fix 2024-05-14 12:01:04 -05:00
Hugh Carson 8cc311191a Fix GetFaceDofs -> GetFaceVDofs 2024-05-14 09:57:27 -04:00
IdoAkkerman 716e370d35 Fix merge 2024-05-14 14:21:58 +02:00
IdoAkkerman 37c0768fe3 Merge branch 'master' into hdiv-nurbs 2024-05-14 14:12:44 +02:00
Vladimir Z Tomov 4eaa2c6d67 Edited some comments. 2024-05-13 17:16:01 -07:00
Vladimir Z Tomov 28bc92c034 Edited comments. 2024-05-13 16:15:28 -07:00
Vladimir Z Tomov 4e0bb41e58 Removed unused coefficient. 2024-05-13 16:12:48 -07:00
Vladimir Z Tomov 36a4df0494 Merge branch 'master' into tmop-fitting-convergence 2024-05-13 16:03:54 -07:00
Jan Nikl f2dfb6d83a Added a note about nodal function to Mesh::MakePeriodic(). 2024-05-13 10:04:50 -07:00
Tzanio Kolev f1af6fccd2 Merge branch 'master' into ex40 2024-05-11 08:44:59 -07:00
Tzanio Kolev 9290acab48 Merge branch 'master' into 2x2_matrix_exponential 2024-05-11 08:43:51 -07:00
Tzanio Kolev 263eabc81a Merge branch 'master' into vtu-attribute-material 2024-05-11 08:43:17 -07:00
Hugh Carson 63804ab6cb Merge branch 'master' into hughcars/nc-internal-bdr-project-fix 2024-05-08 14:39:35 -04:00
Joseph Signorelli 98e0f325f9 Merge branch 'master' into symmatcoeff-project-fix 2024-04-30 16:33:55 -05:00
Mittal, Ketan 6f3dc3e187 minor 2024-04-24 13:30:35 -07:00
Joseph Signorelli 365b2a027b Fix matrix dimension 2024-04-24 14:33:54 -05:00
Mittal, Ketan f037b23fb1 initial commit 2024-04-24 12:10:08 -07:00
Hugh Carson 2dabf82a0d Fix bug where projection onto internal boundaries fails to identify parent dofs in NC faces 2024-04-23 18:28:53 -04:00
Brendan Keith 65fe610f57 update CHANGELOG and add 3D example runs 2024-04-23 08:27:49 -04:00
Brendan Keith 032666afc9 update example description 2024-04-22 20:17:22 -04:00
IdoAkkerman 51860e9192 Add auto diff and inverse estimate 2024-04-19 11:06:41 +02:00
IdoAkkerman e81ad14586 Add inverse estimate coefficient 2024-04-19 11:05:03 +02:00
IdoAkkerman ef1d5f86bf Add mixed scalar laplace integrators 2024-04-19 11:03:57 +02:00
Brendan Keith 84631a1688 update comments 2024-04-17 09:34:06 -04:00
Brendan Keith 4b00ad0b03 update comments 2024-04-17 09:33:44 -04:00
Brendan Keith c29f70e220 typos 2024-04-17 07:52:06 -04:00
Brendan Keith 739dfbace1 memory leak fix 2024-04-16 20:55:11 -04:00
Brendan Keith 4cbe4358ef hyperparameter tuning 2024-04-16 20:50:36 -04:00
Brendan Keith d254f771c8 style 2024-04-16 20:18:42 -04:00
Brendan Keith f7dc6c7090 bug fixed in updating the mass matrix 2024-04-16 20:18:18 -04:00
Brendan Keith e1fc8bf3b2 dohyun's comments 2024-04-16 19:24:45 -04:00
Brendan Keith 8544e4ef9c minor 2024-04-16 18:02:15 -04:00
Brendan Keith 9e744d1f22 dohyun's comments on ex40p 2024-04-16 16:17:52 -04:00
Brendan Keith c772b2eaca Dohyun's comments on ex40.cpp 2024-04-16 14:50:31 -04:00
Brendan KeithandDohyun Kim d910bac841 Update examples/ex40p.cpp
Co-authored-by: Dohyun Kim <dhkim.cse@gmail.com>
2024-04-16 13:22:10 -04:00
Brendan KeithandDohyun Kim e8147b14cb Update examples/ex40.cpp
Co-authored-by: Dohyun Kim <dhkim.cse@gmail.com>
2024-04-16 13:21:37 -04:00
Brendan KeithandDohyun Kim 0c6d8b8417 Update examples/ex40.cpp
Co-authored-by: Dohyun Kim <dhkim.cse@gmail.com>
2024-04-16 13:20:47 -04:00
Brendan Keith 5bf66c6704 sign error in tichonov coefficient 2024-04-16 08:08:24 -04:00
Brendan Keith d51c62699c gitignore 2024-04-15 19:44:38 -04:00
Brendan Keith d17d8f2a45 gitignore 2024-04-15 17:46:36 -04:00
Brendan Keith 4483b664c2 HYPRE error fixed 2024-04-15 17:26:25 -04:00
Brendan Keith e7b2a09943 Merge branch 'ex40' of github.com:mfem/mfem into ex40 2024-04-15 11:01:56 -04:00
Brendan Keith 801cb497e1 bug fix 2024-04-15 11:01:51 -04:00
Brendan Keith d7542b843e Merge branch 'master' into ex40 2024-04-15 10:50:15 -04:00
Brendan Keith 4a5d81981b debugged ex40p 2024-04-15 10:46:49 -04:00
Brendan Keith 80c22eaae6 ex40p compiles 2024-04-14 22:17:45 -04:00
Brendan Keith 901a714fac ex40 2024-04-14 21:37:39 -04:00
Will Pazner dadbc18916 Add VTU attribute sample meshes and unit test 2024-04-11 10:59:37 -07:00
IdoAkkerman 6c5cfbfc65 Rough sketch of miniapss 2024-04-11 12:00:40 +02:00
Will Pazner 8acdb178c2 Allow reading attributes from VTK meshes with "attribute" cell data 2024-04-09 14:08:15 -07:00
Brendan Keith 6baf95a686 Merge branch 'master' into 2x2_matrix_exponential 2024-04-09 07:00:04 -04:00
IdoAkkerman 2bd8bb4c3b Add scalar laplace bilinear integrators 2024-04-08 12:29:03 +02:00
IdoAkkerman 1c38648d5f Add laplace linear form 2024-04-08 10:08:33 +02:00
Brendan Keith 4ebbbc45ae override 2024-04-07 22:20:52 -04:00
Brendan Keith 77a3bb103c style 2024-04-07 22:12:02 -04:00
Brendan Keith ae3b9e23e7 Merge branch 'master' into 2x2_matrix_exponential 2024-04-07 22:09:37 -04:00
Brendan KeithandDohyun Kim 0494eb22e6 Update fem/coefficient.hpp
Co-authored-by: Dohyun Kim <dhkim.cse@gmail.com>
2024-04-07 22:08:55 -04:00
Brendan KeithandDohyun Kim 31a977ac5f Update fem/coefficient.cpp
Co-authored-by: Dohyun Kim <dhkim.cse@gmail.com>
2024-04-07 22:08:33 -04:00
Brendan Keith 821c41fba9 remove comments 2024-04-06 11:50:53 -04:00
Brendan Keith af5a7844a8 test for MatrixArrayVectorCoefficient 2024-04-06 11:16:53 -04:00
Brendan Keith 9bfa6c051e Merge branch 'master' into 2x2_matrix_exponential 2024-04-05 18:04:26 -04:00
Brendan Keith 850f0f7e89 typo 2024-04-05 17:45:10 -04:00
Brendan Keith 90ecbf2bfb Adding TraceCoefficient 2024-04-05 17:44:29 -04:00
Brendan Keith b0a3350622 added MatrixArrayVectorCoefficient clas 2024-04-05 17:40:59 -04:00
Ido Akkerman 875b5f3f52 Update nurbs_naca_cmesh.cpp 2024-04-05 22:34:26 +02:00
IdoAkkerman be1f36a523 Merge branch 'master' into hdiv-nurbs 2024-04-05 21:54:43 +02:00
IdoAkkerman d4c7dd3490 Double -> Real 2024-04-05 21:53:48 +02:00
Brendan Keith 3f45c0a9d7 Merge branch '2x2_matrix_exponential' of github.com:mfem/mfem into 2x2_matrix_exponential 2024-04-05 12:38:40 -04:00
Brendan Keith 18bee592c4 move test out of #ifdef MFEM_USE_LAPACK 2024-04-05 12:38:35 -04:00
IdoAkkerman 637854fd90 Works 2024-04-05 17:44:30 +02:00
Brendan KeithandDohyun Kim bc0ab53d19 Update linalg/densemat.cpp
Co-authored-by: Dohyun Kim <dhkim.cse@gmail.com>
2024-04-05 08:45:33 -04:00
IdoAkkerman e55fb21538 Merge branch 'master' into mod-ex23 2024-04-05 14:36:47 +02:00
IdoAkkerman a966b0502f Rewrite BC enforcement 2024-04-05 12:59:41 +02:00
IdoAkkerman 1bac61ad1c Typos 2024-04-05 09:04:06 +02:00
IdoAkkerman c7451115d8 Typos 2024-04-05 09:00:12 +02:00
IdoAkkerman 72ae003a00 double -> real_t 2024-04-05 08:51:50 +02:00
Brendan Keith 99db13a3c2 missing break; 2024-04-04 17:22:06 -04:00
Brendan Keith 4dcb5933a9 bug in switch 2024-04-04 17:11:32 -04:00
Brendan Keith 1f5f30c9c4 3x3 abort message 2024-04-04 16:27:45 -04:00
Brendan Keith d453981d3c style 2024-04-04 16:09:13 -04:00
IdoAkkerman d67098b8f8 remove unused variable 2024-04-04 22:06:01 +02:00
IdoAkkerman 0e6dbaf050 remove 999 statement 2024-04-04 21:52:34 +02:00
Brendan Keith 00bf53ed90 introduce the ExponentialMatrixCoefficient class 2024-04-04 15:48:32 -04:00
IdoAkkerman 32afc8565c remove 9999 statement 2024-04-04 21:48:24 +02:00
IdoAkkerman 48ace60875 order[2] big fix + small cosmetic changes 2024-04-04 21:46:38 +02:00
Chris Vogl b89dc7fe56 Merge branch 'master' into operator-doc 2024-04-04 10:58:24 -07:00
IdoAkkerman 9b6ee6fcad Add papers -- comment flipped with previous commit 2024-04-04 14:44:54 +02:00
IdoAkkerman 1a1639b87e Add neumann example 2024-04-04 14:44:14 +02:00
IdoAkkerman 3735aa504b Comments dec 2023 2024-04-04 12:50:03 +02:00
Ido Akkerman 367dda6794 Merge branch 'master' into hdiv-nurbs 2024-04-04 11:59:43 +02:00
IdoAkkerman e4a85f79cd Remove multipatch examples in ex24 2024-04-03 22:30:00 +02:00
IdoAkkerman 678101938b Merge branch 'master' into hdiv-nurbs 2024-04-03 13:37:00 +02:00
IdoAkkerman 9a3aa18c62 Fix 3D Hcurl 2024-04-03 13:24:20 +02:00
IdoAkkerman 5a3ba1424a Update comments 2024-04-02 13:29:48 +02:00
IdoAkkerman 3bb8419a96 Add miniapp source to doc 2024-04-02 13:07:45 +02:00
IdoAkkerman ce29282f63 Add Hdiv and Hcurl NURBS to changelog 2024-04-02 12:51:37 +02:00
IdoAkkerman 9575299ae3 Merge branch 'master' into hdiv-nurbs 2024-04-02 09:04:07 +02:00
IdoAkkerman 995ceca6c2 Cosmetic fix of 2D Hcurl dof count 2024-04-02 09:03:04 +02:00
Mittal, Ketan 71da95b411 rename variables and replace double with real_t 2024-03-28 15:25:17 -07:00
IdoAkkerman 6abd0e6002 Fix 2d Curl 2024-03-28 13:29:15 +01:00
IdoAkkerman 656e3062b4 Fix mesh name in example 2024-03-28 13:14:40 +01:00
Christopher vogl 57cce6a74d minor piece missing in comments of TimeDependentOperator (copy/paste error) 2024-03-27 16:38:39 -07:00
Christopher vogl 0fba4035e3 updated comments for TimeDependentOperator::type as suggested by @v-dobrev 2024-03-27 16:33:40 -07:00
Mittal, Ketan 0ee0132e7c minor 2024-03-27 15:32:17 -07:00
Mittal, Ketan 691c328d38 merge with master and resolve conflicts 2024-03-27 13:42:36 -07:00
Mittal, Ketan f45d15149a add a couple options we never really use 2024-03-27 13:01:38 -07:00
Mittal, Ketan c32e986926 add criterion for residual based convergence with adaptive fitting weight 2024-03-27 12:57:15 -07:00
IdoAkkerman 9c9c519175 Add exso.mesh to gitignore -- prevent regression test error 2024-03-27 14:23:14 +01:00
IdoAkkerman 8300809562 Fix double real_t conversion 2024-03-27 13:57:51 +01:00
IdoAkkerman cce7296ffe Tweak example runs in miniapps; add comments; remove comments 2024-03-27 13:39:50 +01:00
IdoAkkerman a445ad00da Update clean statement in makefile 2024-03-27 13:38:26 +01:00
IdoAkkerman 4db7e1a107 Add comments to NURB extension mode 2024-03-27 13:37:36 +01:00
IdoAkkerman c51a1c4aa9 Remove comment in nurbs, tweak error statement 2024-03-27 13:37:09 +01:00
IdoAkkerman d489908e50 Merge branch 'master' into hdiv-nurbs 2024-03-26 16:55:17 +01:00
IdoAkkerman c4eda188d5 Tweak nurbs ex24 2024-03-26 16:31:27 +01:00
IdoAkkerman 677eb4c876 Change solver params for nurbs ex5 2024-03-26 16:30:57 +01:00
IdoAkkerman 69a4aa70b9 Fix mapping in NURBS Hdiv 3D 2024-03-26 15:37:49 +01:00
IdoAkkerman f07c2f460d Update copyright statement 2024-03-26 10:29:49 +01:00
Socratis Petrides 09c557bdd7 Merge branch 'master' into var-order-href-op 2024-03-21 19:45:57 -07:00
Socratis Petrides e487da01c5 adding unit tests 2024-03-21 19:44:43 -07:00
IdoAkkerman b6b6843ad2 Merge branch 'master' into hdiv-nurbs 2024-03-21 15:46:53 +01:00
Mittal, Ketan 66a1379947 Merge branch 'var-order-href-op' of https://github.com/mfem/mfem into var-order-href-op 2024-03-13 13:10:41 -07:00
Mittal, Ketan 546ba6c11e add support for h-derefinement 2024-03-13 13:10:24 -07:00
Mittal, Ketan 67ba63c2f4 Merge branch 'master' of https://github.com/mfem/mfem into var-order-href-op 2024-03-13 13:08:02 -07:00
Socratis Petrides 99c2967920 Merge branch 'master' into var-order-href-op 2024-03-08 12:07:52 -08:00
Socratis Petrides 2dc419f1ae Merge branch 'master' into var-order-href-op 2024-03-04 11:36:38 -08:00
Mittal, Ketan 450d6cea6d Merge branch 'master' of https://github.com/mfem/mfem into var-order-href-op 2024-03-04 09:51:05 -08:00
Chris VoglandVeselin Dobrev 17a24c71cd Formatting improvements by @v-dobrev
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2024-02-27 10:34:55 -08:00
Chris VoglandVeselin Dobrev 8a6f50f6cc Formatting improvements and class suggestions by @v-dobrev
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2024-02-27 10:34:21 -08:00
Chris VoglandVeselin Dobrev 5e856a6464 Formatting improvements by @v-dobrev
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2024-02-27 10:33:02 -08:00
Chris VoglandVeselin Dobrev 78aa8d60a8 Comments explaining TimeDependentOperator::Type by @v-dobrev
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2024-02-27 10:32:31 -08:00
Chris VoglandVeselin Dobrev f02247439b Formatting improvements by @v-dobrev
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2024-02-27 10:30:47 -08:00
Christopher vogl 70c6f713d5 fixed typos in backward Euler description to ImplicitSolve 2024-02-21 19:00:25 -08:00
Christopher vogl ca94342c04 added backward Euler description to ImplicitSolve 2024-02-21 18:57:16 -08:00
Christopher vogl 59a2657f06 Merge remote-tracking branch 'origin/master' into operator-doc
- addressed merge conflicts in operator.hpp b/c of use of $ instead of \f$
- modified the remainder of changes in operator.hpp to also use $ instead of \f$
2024-02-21 18:44:30 -08:00
Christopher vogl 35a328c342 forgot to rename an argument in SUNImplicitSetup that was screwing up the doxygen 2024-02-21 18:36:41 -08:00
Christopher vogl bcba29c6a2 cleaned up doc for Mult, ImplicitSolve, and SUN methods 2024-02-21 18:23:21 -08:00
Christopher vogl 2cc23787ab revert to prior explanation of Type and EvalMode with new notation 2024-02-21 18:22:37 -08:00
Christopher vogl 711df0e4fd added third example of ODE/DAE definition in TimeDependentOperator to reflect Petsc definitions 2024-02-21 18:06:44 -08:00
Socratis Petrides 75df4ad3e6 replace umfpack with PCG 2024-02-16 12:18:21 -08:00
Socratis Petrides 4048d46443 Merge branch 'master' into var-order-href-op 2024-02-16 12:02:58 -08:00
Christopher vogl 1ddcc6d421 switched from x to u in TimeDependentOperator and used v as result notation 2024-02-12 14:05:02 -08:00
Christopher vogl e7da202037 addressed some typos in TimeDependentOperator documentation 2024-02-06 16:27:41 -08:00
Christopher vogl dc9e6c5ffb forgot to update argument names in TimeDependentOperator::SUNImplicitSetup 2024-02-06 16:00:16 -08:00
Christopher vogl 0e74524f6d updated TimeDependentOperator::SUN* 2024-02-06 15:25:31 -08:00
Christopher vogl 8fb59b8251 updated TimeDependentOperator::ImplicitSolve 2024-02-06 15:24:51 -08:00
Christopher vogl 2012a9131b updated TimeDependentOperator::Mult 2024-02-06 15:24:19 -08:00
Christopher vogl 56d6841372 updated TimeDependentOperator constructors and getters 2024-02-06 15:23:28 -08:00
Christopher vogl 37a140c0e2 updated enumerated types in TimeDependentOperator to use new F and G 2024-02-06 15:21:34 -08:00
Christopher vogl 4f3a64d834 refactored TimeDependentOperator description to consistently use k instead of k and f 2024-02-06 15:20:52 -08:00
IdoAkkerman b03cf507be Fix debug stuff 2023-12-21 17:04:02 +01:00
IdoAkkerman 066dc9b078 Us prev. unused variable 2023-12-21 15:16:29 +01:00
IdoAkkerman 70854254e7 Report Dofs in boundary for ex5 2023-12-21 14:45:42 +01:00
IdoAkkerman 646df28ac8 Add sign to Hdiv bdr dof indices 2023-12-21 14:45:09 +01:00
IdoAkkerman 73d4f987e4 Add direction to 2D Hdiv bdr indices 2023-12-21 14:14:39 +01:00
IdoAkkerman c59d519c89 Allow for negative dof indices 2023-12-21 14:12:21 +01:00
IdoAkkerman 1ec2cba9e8 Allow for negative dof indices in Table merge constructor 2023-12-21 14:11:11 +01:00
IdoAkkerman 26cc1f8387 Fix 2D curl 2023-12-21 09:40:38 +01:00
IdoAkkerman b57fa2b127 Add neumann/periodic test case 2023-12-20 12:53:32 +01:00
IdoAkkerman 596909138a Cleaner bc selection/reporting in ex1 2023-12-20 12:53:07 +01:00
IdoAkkerman c11a76f2c1 Update make clean call 2023-12-19 16:52:34 +01:00
IdoAkkerman 51d32ad293 merge master - manual 2023-12-19 16:16:00 +01:00
IdoAkkerman a433e9e0b4 Fix small numbering issue 2023-12-19 14:33:07 +01:00
IdoAkkerman abac61f5b5 Add Hcurl boundary + allow GF read to set dim with seperate call 2023-12-19 14:32:26 +01:00
IdoAkkerman a121a9d186 Small order fix 2023-12-19 14:31:20 +01:00
IdoAkkerman 58ecbf6150 Use new ext and table modes 2023-12-19 14:30:23 +01:00
IdoAkkerman bad5ae41d1 Add bdr dof selection option 2023-12-19 14:29:35 +01:00
IdoAkkerman e773e07373 Make Table merge generic 2023-12-19 14:28:17 +01:00
IdoAkkerman c3ded3c003 Add dim for fe_coll and ess bc output 2023-12-19 14:27:47 +01:00
IdoAkkerman 76e04c4606 Make style 2023-12-15 17:24:11 +01:00
IdoAkkerman 83ccf77d2f Fixing gitignore 2023-12-15 17:00:57 +01:00
IdoAkkerman a0d53975d8 Adding boundary elements to Hdiv collection pt2 2023-12-15 16:17:49 +01:00
IdoAkkerman 1252c0fbb9 Merge branch 'hdiv-nurbs' of /home/ido/Data/mfem/mfem into hdiv-nurbs 2023-12-15 16:14:34 +01:00
IdoAkkerman 04acf613ae Adding boundary elements to Hdiv collection 2023-12-15 16:14:20 +01:00
IdoAkkerman c8bddb8035 Merge branch 'master' into hdiv-nurbs 2023-12-15 14:38:11 +01:00
IdoAkkerman 467e83da31 Fixed nurbs miniapps 2023-12-15 14:36:31 +01:00
IdoAkkerman 8b29ef1335 style fix in fe_nurbs 2023-12-15 14:26:34 +01:00
IdoAkkerman 1076700714 Cmake fixes 2023-12-15 14:26:03 +01:00
IdoAkkerman 978f1155c5 Update Makefile 2023-12-15 14:25:34 +01:00
IdoAkkerman 3096d9d9cb Fixed some sloppiness 2023-12-15 13:51:27 +01:00
IdoAkkerman ffea75abb2 Fixed Table comments 2023-12-15 13:47:04 +01:00
IdoAkkerman a44a8b8789 Made booleans const 2023-12-15 13:43:09 +01:00
IdoAkkerman 05106096c3 Symmetrice delete call 2023-12-15 13:41:43 +01:00
IdoAkkerman ba7fd7a9a9 Remove superfluous hdiv check 2023-12-15 13:38:44 +01:00
IdoAkkerman 9b0e4e0085 Fix nurbs miniapp cmake 2023-12-15 13:38:25 +01:00
IdoAkkerman 3cb64f7f7e Merge branch 'hdiv-nurbs' of /home/ido/Data/mfem/mfem into hdiv-nurbs 2023-12-15 13:25:28 +01:00
IdoAkkerman 6642857437 Fix uninit error 2023-11-29 17:19:52 +01:00
IdoAkkerman 91f00d643a Fix shadow varaibel in fespace 2023-11-29 17:12:17 +01:00
IdoAkkerman ce8b62cfe7 Add override keyword for macosx 2 2023-11-29 16:51:03 +01:00
IdoAkkerman 4064bda60d Add override keyword for macosx 2023-11-29 16:50:15 +01:00
IdoAkkerman 4a21554986 Remove unused variables from table 2023-11-29 16:43:10 +01:00
IdoAkkerman 165968dc26 Make style 2023-11-29 16:40:48 +01:00
IdoAkkerman 9eb70f7be0 Add tests 2023-11-29 16:38:01 +01:00
IdoAkkerman 8797a9cb00 Small ex24 tweaks 2023-11-29 16:37:42 +01:00
IdoAkkerman 8366a5a6d6 Fix documentation error 2023-11-29 12:17:15 +01:00
IdoAkkerman 63a9d5749b Delete parallel miniapp 2023-11-29 12:16:58 +01:00
IdoAkkerman 0e6aa41245 Update nurbs miniapps 2023-11-29 12:11:37 +01:00
IdoAkkerman bbcb054814 example update 2023-11-29 12:08:38 +01:00
IdoAkkerman 2e5a86db7a Merge branch 'master' into hdiv-nurbs 2023-11-29 09:24:21 +01:00
IdoAkkerman 057b15cefb miniapps/nurbs/nurbs_ex24p.cpp 2023-11-28 16:52:13 +01:00
IdoAkkerman 7c06741f36 Remove debug print statement 2023-11-28 15:37:41 +01:00
IdoAkkerman 3a0c42aea5 Add L2 projection for NURBS 2023-11-28 15:37:16 +01:00
IdoAkkerman 75d5555a5f Component output not necessary anymore 2023-11-28 10:35:37 +01:00
IdoAkkerman 10c1ac9a66 Add nurbs hdiv hcurl examples/tests 2023-11-28 10:34:06 +01:00
IdoAkkerman 692e15c088 Make style 2023-11-28 09:57:11 +01:00
IdoAkkerman 6be9665bfb Add mappings to VShape Trans calls 2023-11-27 17:24:23 +01:00
IdoAkkerman 9be617d754 Add Hdiv and Hcurl NURBS to fe coll selection mechanism 2023-11-27 16:58:10 +01:00
IdoAkkerman ec4f37fe25 Make style 2023-11-27 16:57:28 +01:00
IdoAkkerman 6bb4ae9d50 Small correction in solenoidal test app 2023-11-27 16:57:00 +01:00
IdoAkkerman c7a3f188c0 Add output 2023-11-21 17:28:15 +01:00
IdoAkkerman 8e44509585 Make style 2023-11-21 17:27:26 +01:00
IdoAkkerman 787954715b Make style and small compile order fix nurbs fe 2023-11-21 17:26:30 +01:00
IdoAkkerman 9f03260dd2 Fix Hcurl boundary dof table 2 2023-11-21 17:24:23 +01:00
IdoAkkerman 5c3a3f7fdf Add Curl miniapp 2023-11-21 13:08:20 +01:00
IdoAkkerman 6693b22c83 Small compile fixes 2023-11-21 12:55:01 +01:00
IdoAkkerman 49c7f60a57 Add routines to make a Hcurl fespace 2023-11-21 12:49:37 +01:00
IdoAkkerman ace4608f10 Add H curl NURBS collection 2023-11-21 12:41:06 +01:00
IdoAkkerman 3899dfcc64 Remove interfaces -- will implement in follow-up PR 2023-11-21 12:40:39 +01:00
IdoAkkerman 2dc98e9153 Add H curl NURBS elements 2023-11-21 12:39:47 +01:00
IdoAkkerman 90f8a2409f Add divergence free test case 2023-11-21 11:59:37 +01:00
IdoAkkerman 92dc0db889 Fix patch check 2023-11-21 10:23:42 +01:00
IdoAkkerman d8fc48e608 Clean up of projection miniapp 2023-11-20 14:21:05 +01:00
IdoAkkerman 611802f990 Rename extension routine 2023-11-20 14:18:27 +01:00
IdoAkkerman 606df86b0a Component Extension generator 2023-11-20 14:08:27 +01:00
IdoAkkerman 2f7d38e6f6 Fix typo 2023-11-20 14:00:19 +01:00
IdoAkkerman b90d665ced Clean fe collection 2023-11-20 14:00:04 +01:00
IdoAkkerman 50dd77ffd4 Make style 2023-11-20 13:53:10 +01:00
IdoAkkerman 5e5b79783c Other comment -- make style 2023-11-20 13:51:37 +01:00
IdoAkkerman c815114661 Add explaination to new table constructors 2023-11-20 13:48:53 +01:00
IdoAkkerman 93f6a53201 FES cleaning, renaming and memleak fix 2023-11-20 13:35:55 +01:00
IdoAkkerman a3ee0cfe79 Add 3D gradient and hessian -- compile fixes 2023-11-20 12:06:55 +01:00
IdoAkkerman 95b0178514 Add 3D gradient and hessian 2023-11-20 11:40:34 +01:00
IdoAkkerman afacf3db45 Add 3D function 2023-11-17 17:58:20 +01:00
IdoAkkerman 4a80321420 Add 3D output 2023-11-17 17:52:35 +01:00
IdoAkkerman 9295c69249 Hdiv 3D fixes 2023-11-17 17:44:58 +01:00
IdoAkkerman 893f04967c add geom option to NURBS HDiv fecoll 2023-11-17 17:16:05 +01:00
IdoAkkerman fa410a6e02 Correct type in fespace 2023-11-17 17:15:19 +01:00
IdoAkkerman aed2687743 Add 3D HDiv elements 2023-11-17 17:03:08 +01:00
IdoAkkerman 978c0d10bc Add 3D to fespace 2023-11-17 16:41:43 +01:00
IdoAkkerman 25b540e804 Add 3D table merge 2023-11-17 16:41:06 +01:00
IdoAkkerman 9aa58cd5c2 Modify fe space to accomodate Hdiv NURBS 2023-11-17 15:38:39 +01:00
IdoAkkerman 691be01bcc Add constructors to table that merge existing tables 2023-11-17 15:38:10 +01:00
IdoAkkerman 402ed45ee4 Add Hdiv fe collection 2023-11-17 15:37:31 +01:00
IdoAkkerman 07dfcd83b9 Add 2D Hdiv NURBS basis 2023-11-17 15:37:10 +01:00
IdoAkkerman 9845dfda2c Add VectorBasis derivative interfaces 2023-11-17 15:36:42 +01:00
IdoAkkerman da5ee77e61 Add div free option 2023-11-17 14:07:06 +01:00
IdoAkkerman e1d2966e42 Add neumann bcs to nurbs_ex1 miniapp 2023-11-17 14:05:09 +01:00
IdoAkkerman 17428ce198 Add div-free option 2023-11-17 13:21:40 +01:00
IdoAkkerman e87e790215 add nurbs solenoidal miniapp for checking Hdif elemenet 2023-11-16 16:46:41 +01:00
Socratis Petrides a6d4e17911 Transfer Operator as a SparseMatrix 2022-02-25 13:50:07 -08:00
Socratis Petrides bde7846b5a style 2022-02-24 17:43:11 -08:00
Socratis Petrides 01283767a6 variable order href transfer for the 'ANY_TYPE' transfer operator 2022-02-24 17:42:41 -08:00
110 changed files with 11569 additions and 1767 deletions
+13
View File
@@ -57,6 +57,8 @@ examples/ex2[0-9]
examples/ex2[0-9]p
examples/ex3[0-9]
examples/ex3[0-9]p
examples/ex4[0-9]
examples/ex4[0-9]p
examples/refined.mesh
examples/displaced.mesh
@@ -270,16 +272,27 @@ miniapps/navier/*_output
miniapps/nurbs/nurbs_ex1
miniapps/nurbs/nurbs_ex1p
miniapps/nurbs/nurbs_ex3
miniapps/nurbs/nurbs_ex5
miniapps/nurbs/nurbs_ex11p
miniapps/nurbs/nurbs_ex24
miniapps/nurbs/nurbs_solenoidal
miniapps/nurbs/nurbs_printfunc
miniapps/nurbs/nurbs_patch_ex1
miniapps/nurbs/nurbs_curveint
miniapps/nurbs/refined.mesh
miniapps/nurbs/mesh.*
miniapps/nurbs/sol_?.gf
miniapps/nurbs/sol.*
miniapps/nurbs/mode_*
miniapps/nurbs/Example1*
miniapps/nurbs/Example3*
miniapps/nurbs/Example5*
miniapps/nurbs/Solenoidal*
miniapps/nurbs/ParaView
miniapps/nurbs/sin-fit.mesh
miniapps/nurbs/ex5.mesh
miniapps/nurbs/exsol.mesh
miniapps/nurbs/CurveInt
miniapps/nurbs/nurbs_naca_cmesh
miniapps/nurbs/naca-cmesh.mesh
+3
View File
@@ -13,6 +13,9 @@
# at Lawrence Livermore National Laboratory (LLNL). This entire pipeline is
# LLNL-specific!
include:
- project: 'lc-templates/id_tokens'
file: 'id_tokens.yml'
# 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
+4
View File
@@ -9,6 +9,10 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
include:
- project: 'lc-templates/id_tokens'
file: 'id_tokens.yml'
# We define the following GitLab pipeline variables:
variables:
+3 -4
View File
@@ -35,9 +35,8 @@ variables:
- when: on_success
# Lassen uses a different job scheduler (spectrum lsf) that does not allow
# pre-allocation the same way slurm does. We use pdebug queue on lassen
# to speed-up the allocation. However this would not be scalable to
# multiple builds.
# pre-allocation the same way slurm does. We use the pci queue on lassen
# to speed-up the allocation.
.build_and_test_on_lassen:
extends: [.on_lassen]
stage: build_and_test
@@ -45,5 +44,5 @@ variables:
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
# Next script uses 'THREADS': leaving it empty --> it uses 'make all -j'
- lalloc 1 -W 45 -q pdebug --atsdisable tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
- lalloc 1 -W 45 -q pci --atsdisable tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
needs: [setup]
+1 -1
View File
@@ -52,4 +52,4 @@ variables:
- echo ${JOBID}
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 45 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) --reservation=ci -t 45 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
+4 -4
View File
@@ -14,14 +14,14 @@ stages:
- build_and_test
- report
opt_mpi_cuda_xl_16_1_1_12:
opt_mpi_cuda_gcc:
variables:
SPEC: "%xl@16.1.1.12 +mpi +cuda cuda_arch=70"
SPEC: "%gcc@8.3.1 +mpi +cuda cuda_arch=70"
extends: .build_and_test_on_lassen
opt_mpi_cuda_hypre_cuda_xl:
opt_mpi_cuda_hypre_cuda_gcc:
variables:
SPEC: "%xl@16.1.1.12 +mpi +cuda cuda_arch=70 ^hypre+cuda~shared cuda_arch=70"
SPEC: "%gcc@8.3.1 +mpi +cuda cuda_arch=70 ^hypre+cuda~shared cuda_arch=70"
extends: .build_and_test_on_lassen
# Jobs report
+2 -2
View File
@@ -32,11 +32,11 @@ mkdir _${BASELINE_TEST} && cd _${BASELINE_TEST}
# run
if [[ "${MACHINE_NAME}" == "quartz" || "${MACHINE_NAME}" == "ruby" ]]; then
salloc --nodes=1 -p pdebug ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
salloc --nodes=1 --reservation=ci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
elif [[ ${MACHINE_NAME} == "corona" ]]; then
salloc --nodes=1 -t 60 -p pbatch ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
elif [[ ${MACHINE_NAME} == "lassen" ]]; then
lalloc 1 -q pdebug ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
lalloc 1 -q pci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
else
echo "Unknown machine: MACHINE_NAME=$MACHINE_NAME"
exit 1
+10
View File
@@ -11,6 +11,16 @@
Version 4.7.1 (development)
===========================
- Added NURBS-based H(div) and H(curl) elements in 2D and 3D. Only on single
patch meshes. Only implemented for serial computations.
- Added miniapps to demonstrate the H(div) and H(curl) NURBS elements.
- Added an MFEM example for the eikonal equation. This new solver is based on
the proximal Galerkin method introduced by Keith and Surowiec.
- API change: in class GridFunction, 'fec' was renamed to 'fec_owned'.
Version 4.7, released on May 7, 2024
====================================
+83 -13
View File
@@ -32,7 +32,7 @@ groups_serial=(
'"examples"
"Examples:"
"examples"
"ex{,1,2,3}[0-9].cpp"'
"ex{,[1-9]}[0-9].cpp"'
# "ex1.cpp"'
'"sundials"
"SUNDIALS examples:"
@@ -58,6 +58,10 @@ groups_serial=(
"HiOp examples:"
"examples/hiop"
"ex9.cpp"'
'"moonolith"
"Moonolith examples:"
"examples/moonolith"
"ex1.cpp"'
'"pumi"
"PUMI examples:"
"examples/pumi"
@@ -66,25 +70,38 @@ groups_serial=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp mesh-quality.cpp
polar-nc.cpp reflector.cpp shaper.cpp trimmer.cpp twist.cpp
mesh-optimizer.cpp minimal-surface.cpp"'
'"adjoint"
"Adjoint miniapps:"
"miniapps/adjoint"
"cvsRoberts_ASAi_dns.cpp"'
'"autodiff"
"Autodiff miniapps:"
"miniapps/autodiff"
"seq_example.cpp seq_test.cpp"' # 'seq_test.cpp' has no sample runs
'"dpg"
"DPG miniapps:"
"miniapps/dpg"
"{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
'"gslib"
"GSLIB miniapps:"
"miniapps/gslib"
"field-diff.cpp field-interp.cpp findpts.cpp schwarz_ex1.cpp "'
# todo: miniapps/mtop
'"nurbs"
"NURBS miniapps:"
"miniapps/nurbs"
"nurbs_ex1.cpp"'
# todo: add other nurbs miniapps
# todo: miniapps/solvers (serial)
'"tools"
"Tools miniapps:"
"miniapps/tools"
"convert-dc.cpp display-basis.cpp get-values.cpp load-dc.cpp
lor-transfer.cpp"'
# todo: add other tools miniapps
'"toys"
"Toys miniapps:"
"miniapps/toys"
@@ -100,7 +117,7 @@ groups_parallel=(
'"examples"
"Examples:"
"examples"
"ex{,1,2,3}[0-9]p.cpp"'
"ex{,[1-9]}[0-9]p.cpp"'
# "ex1p.cpp"'
'"sundials"
"SUNDIALS examples:"
@@ -126,6 +143,10 @@ groups_parallel=(
"HiOp examples:"
"examples/hiop"
"ex9p.cpp"'
'"moonolith"
"Moonolith examples:"
"examples/moonolith"
"ex{1,2}p.cpp"'
'"pumi"
"PUMI examples:"
"examples/pumi"
@@ -138,24 +159,41 @@ groups_parallel=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"pmesh-optimizer.cpp pmesh-fitting.cpp pminimal-surface.cpp"'
"pmesh-optimizer.cpp pmesh-fitting.cpp pminimal-surface.cpp
fit-node-position.cpp"'
'"electromagnetics"
"Electromagnetics miniapps:"
"miniapps/electromagnetics"
"joule.cpp"'
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
# "{joule,maxwell,tesla,volta}.cpp"' # todo: multiline sample runs
'"adjoint"
"Adjoint miniapps:"
"miniapps/adjoint"
"adjoint_advection_diffusion.cpp"'
'"autodiff"
"Autodiff miniapps:"
"miniapps/autodiff"
"par_example.cpp"'
'"dpg"
"DPG miniapps:"
"miniapps/dpg"
"p{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
'"gslib"
"GSLIB miniapps:"
"miniapps/gslib"
"pfindpts.cpp schwarz_ex1p.cpp"'
'"hdiv-linear-solver"
"H(div) linear solver miniapps:"
"miniapps/hdiv-linear-solver"
"grad_div.cpp darcy.cpp"'
# 'miniapps/hooke/hooke.cpp' has no sample runs
# todo: miniapps/mtop
# todo: miniapps/multidomain
'"navier"
"Navier miniapps:"
"miniapps/navier"
"navier_cht.cpp"'
# todo: add other navier miniapps
'"nurbs"
"NURBS miniapps:"
"miniapps/nurbs"
@@ -164,14 +202,18 @@ groups_parallel=(
"Shifted miniapps:"
"miniapps/shifted"
"distance.cpp"'
# todo: add other shifted miniapps
'"solvers"
"Solvers miniapps:"
"miniapps/solvers"
"block-solvers.cpp"'
# todo: add other solvers miniapps
# todo: miniapps/spde
'"tools"
"Tools miniapps:"
"miniapps/tools"
"convert-cd.cpp get-values.cpp load-dc.cpp"'
"convert-dc.cpp get-values.cpp load-dc.cpp"'
# todo: add other tools miniapps
'"convergence"
"Convergence tests:"
"tests/convergence"
@@ -186,7 +228,7 @@ groups_all=(
'"examples"
"Examples:"
"examples"
"ex\"{,1,2,3}[0-9]\"{,p}.cpp"'
"ex\"{,[1-9]}[0-9]\"{,p}.cpp"'
'"sundials"
"SUNDIALS examples:"
"examples/sundials"
@@ -215,10 +257,14 @@ groups_all=(
"HiOp examples:"
"examples/hiop"
"ex9.cpp ex9p.cpp"'
'"moonolith"
"Moonolith examples:"
"examples/moonolith"
"ex1.cpp ex{1,2}p.cpp"'
'"pumi"
"PUMI examples:"
"examples/pumi"
"ex1.cpp ex1p.cpp ex2.cpp ex6p.cpp"'
"ex1.cpp ex2.cpp ex1p.cpp ex6p.cpp"'
'"superlu"
"Superlu examples:"
"examples/superlu"
@@ -226,43 +272,67 @@ groups_all=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
{,p}mesh-optimizer.cpp pmesh-fitting.cpp {,p}minimal-surface.cpp"'
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp mesh-quality.cpp
polar-nc.cpp reflector.cpp shaper.cpp trimmer.cpp twist.cpp
{,p}mesh-optimizer.cpp pmesh-fitting.cpp {,p}minimal-surface.cpp
fit-node-position.cpp"'
'"electromagnetics"
"Electromagnetics miniapps:"
"miniapps/electromagnetics"
"joule.cpp"'
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
# "{joule,maxwell,tesla,volta}.cpp"' # todo: multiline sample runs
'"adjoint"
"Adjoint miniapps:"
"miniapps/adjoint"
"adjoint_advection_diffusion.cpp cvsRoberts_ASAi_dns.cpp"'
"cvsRoberts_ASAi_dns.cpp adjoint_advection_diffusion.cpp"'
'"autodiff"
"Autodiff miniapps:"
"miniapps/autodiff"
"seq_example.cpp seq_test.cpp par_example.cpp"'
# 'seq_test.cpp' has no sample runs
'"dpg"
"DPG miniapps:"
"miniapps/dpg"
"{,p}{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
'"gslib"
"GSLIB miniapps:"
"miniapps/gslib"
"field-diff.cpp field-interp.cpp findpts.cpp schwarz_ex1.cpp pfindpts.cpp
schwarz_ex1p.cpp"'
'"hdiv-linear-solver"
"H(div) linear solver miniapps:"
"miniapps/hdiv-linear-solver"
"grad_div.cpp darcy.cpp"'
# 'miniapps/hooke/hooke.cpp' has no sample runs
# todo: miniapps/mtop
# todo: miniapps/multidomain
'"navier"
"Navier miniapps:"
"miniapps/navier"
"navier_cht.cpp"'
# todo: add other navier miniapps
'"nurbs"
"NURBS miniapps:"
"miniapps/nurbs"
"nurbs_ex1.cpp nurbs_ex1p.cpp nurbs_ex11p.cpp"'
# todo: add other nurbs miniapps
'"shifted"
"Shifted miniapps:"
"miniapps/shifted"
"distance.cpp"'
# todo: add other shifted miniapps
'"solvers"
"Solvers miniapps:"
"miniapps/solvers"
"block-solvers.cpp"'
# todo: add other solvers miniapps
# todo: miniapps/spde
'"tools"
"Tools miniapps:"
"miniapps/tools"
"convert-dc.cpp display-basis.cpp get-values.cpp load-dc.cpp
lor-transfer.cpp"'
# todo: add other tools miniapps
'"toys"
"Toys miniapps:"
"miniapps/toys"
@@ -386,7 +456,7 @@ function help_message()
mfem_config [${mfem_config}]
Set MFEM configuration options
make [${make}], mpiexec [${mpiexec}], mpiexec_np [${mpiexec_np}]
Their values can also set using the respective uppercase environment
Their values can also be set using the respective uppercase environment
variable
mfem_build_dir [${mfem_build_dir}]
Same as '-d': set this variable to something different from <mfem_dir>
+3 -3
View File
@@ -18,9 +18,9 @@ elements
boundary
4
1 1 0 1
1 1 2 3
1 1 3 0
1 1 1 2
2 1 2 3
3 1 3 0
4 1 1 2
edges
4
+3 -1
View File
@@ -980,6 +980,7 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/miniapps/mtop \
@MFEM_SOURCE_DIR@/miniapps/multidomain \
@MFEM_SOURCE_DIR@/miniapps/navier \
@MFEM_SOURCE_DIR@/miniapps/stabilized \
@MFEM_SOURCE_DIR@/miniapps/nurbs \
@MFEM_SOURCE_DIR@/miniapps/parelag \
@MFEM_SOURCE_DIR@/miniapps/performance \
@@ -1049,7 +1050,8 @@ RECURSIVE = NO
EXCLUDE = @MFEM_SOURCE_DIR@/config/_config.hpp \
@MFEM_SOURCE_DIR@/config/get_hypre_version.cpp \
@MFEM_SOURCE_DIR@/general/tinyxml2.h \
@MFEM_SOURCE_DIR@/general/tinyxml2.cpp
@MFEM_SOURCE_DIR@/general/tinyxml2.cpp \
@MFEM_SOURCE_DIR@/linalg/lapack.hpp
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
+18 -1
View File
@@ -114,7 +114,9 @@ namespace mfem {
* - <a class="el" href="ex37p_8cpp_source.html">Example 37p</a>: parallel topology optimization
* - <a class="el" href="ex38_8cpp_source.html">Example 38</a>: cut-surface and cut-volume integration
* - <a class="el" href="ex39_8cpp_source.html">Example 39</a>: named mesh attributes
* - <a class="el" href="ex39p_8cpp_source.html">Example 39</a>: parallel named mesh attributes
* - <a class="el" href="ex39p_8cpp_source.html">Example 39p</a>: parallel named mesh attributes
* - <a class="el" href="ex40_8cpp_source.html">Example 40</a>: eikonal equation
* - <a class="el" href="ex40p_8cpp_source.html">Example 40p</a>: parallel eikonal equation
*
* <H4>AmgX Examples</H4>
* - Variants of Examples
@@ -180,6 +182,21 @@ namespace mfem {
* <a class="el" href="examples_2superlu_2ex1p_8cpp_source.html">1p</a>,
* demonstrating the use of MFEM's \link superlu.hpp SuperLU integration\endlink.
*
* <H4>NURBS Examples</H4>
* - Variants of Examples
* <a class="el" href="nurbs__ex1_8cpp_source.html">1</a>,
* <a class="el" href="nurbs__ex1p_8cpp_source.html">1p</a>,
* <a class="el" href="nurbs__ex3_8cpp_source.html">3</a>,
* <a class="el" href="nurbs__ex5_8cpp_source.html">5</a>,
* <a class="el" href="nurbs__ex11p_8cpp_source.html">11p</a>, and
* <a class="el" href="nurbs__ex24_8cpp_source.html">24</a>,
* demonstrating howto perform NURBS-based Isogeometric Analysis.
* - Variant of Example <a class="el" href="nurbs__patch__ex1_8cpp_source.html">1</a>: demonstrates the use of patch integration
* - <a class="el" href="nurbs__solenoidal_8cpp_source.html">NURBS Divergence-free</a>: solve a solenoidal vector projection with NURBS-based H(div) elements
* - <a class="el" href="nurbs__curveint_8cpp_source.html">NURBS Interpolation</a>: NURBS interpolation of given geometry
* - <a class="el" href="nurbs__naca__cmesh_8cpp_source.html">NURBS NACA Mesher</a>: generate NURBS based mesh around a NACA foil
* - <a class="el" href="nurbs__printfunc_8cpp_source.html">NURBS Printer</a>: print the NURBS-basis
*
* <H3>Miniapps</H3>
* - <a class="el" href="volta_8cpp_source.html">Volta</a>: simple electrostatics simulation code
* - <a class="el" href="tesla_8cpp_source.html">Tesla</a>: simple magnetostatics simulation code
+10 -3
View File
@@ -45,6 +45,7 @@ list(APPEND ALL_EXE_SRCS
ex37.cpp
ex38.cpp
ex39.cpp
ex40.cpp
)
if (MFEM_USE_MPI)
@@ -87,6 +88,7 @@ if (MFEM_USE_MPI)
ex36p.cpp
ex37p.cpp
ex39p.cpp
ex40p.cpp
)
endif()
@@ -146,10 +148,10 @@ if (MFEM_ENABLE_TESTING)
# Add CUDA/HIP tests.
set(DEVICE_EXAMPLES
# serial examples with device support:
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
ex1 ex3 ex4 ex5 ex6 ex9 ex14 ex22 ex24 ex25 ex26 ex34
# parallel examples with device support:
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p
ex34p ex35p)
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex14p ex22p ex24p ex25p
ex26p ex34p ex35p)
set(MFEM_TEST_DEVICE)
if (MFEM_USE_CUDA)
set(MFEM_TEST_DEVICE "cuda")
@@ -159,6 +161,11 @@ if (MFEM_ENABLE_TESTING)
if (MFEM_TEST_DEVICE)
foreach(TEST_NAME ${DEVICE_EXAMPLES})
set(THIS_TEST_OPTIONS "-no-vis" "-d" "${MFEM_TEST_DEVICE}")
if (${TEST_NAME} MATCHES "ex14p")
list(APPEND THIS_TEST_OPTIONS "-rs" "2" "-rp" "0" "-pa")
elseif (${TEST_NAME} MATCHES "ex14")
list(APPEND THIS_TEST_OPTIONS "-r" "2" "-pa")
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
+16 -20
View File
@@ -44,7 +44,7 @@ protected:
BilinearForm *M;
BilinearForm *K;
SparseMatrix Mmat, Kmat, Kmat0;
SparseMatrix Mmat, Kmat;
SparseMatrix *T; // T = M + dt K
real_t current_dt;
@@ -83,25 +83,24 @@ WaveOperator::WaveOperator(FiniteElementSpace &f,
: SecondOrderTimeDependentOperator(f.GetTrueVSize(), (real_t) 0.0),
fespace(f), M(NULL), K(NULL), T(NULL), current_dt(0.0), z(height)
{
const real_t rel_tol = 1e-8;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
// Assemble Laplace matrix
c2 = new ConstantCoefficient(speed*speed);
K = new BilinearForm(&fespace);
K->AddDomainIntegrator(new DiffusionIntegrator(*c2));
K->Assemble();
Array<int> dummy;
K->FormSystemMatrix(dummy, Kmat0);
K->FormSystemMatrix(ess_tdof_list, Kmat);
// Assemble Mass matrix
M = new BilinearForm(&fespace);
M->AddDomainIntegrator(new MassIntegrator());
M->Assemble();
// Apply Bcs
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
K->FormSystemMatrix(ess_tdof_list, Kmat);
M->FormSystemMatrix(ess_tdof_list, Mmat);
// Configure preconditioner
const real_t rel_tol = 1e-8;
M_solver.iterative_mode = false;
M_solver.SetRelTol(rel_tol);
M_solver.SetAbsTol(0.0);
@@ -110,14 +109,13 @@ WaveOperator::WaveOperator(FiniteElementSpace &f,
M_solver.SetPreconditioner(M_prec);
M_solver.SetOperator(Mmat);
// Configure solver
T_solver.iterative_mode = false;
T_solver.SetRelTol(rel_tol);
T_solver.SetAbsTol(0.0);
T_solver.SetMaxIter(100);
T_solver.SetPrintLevel(0);
T_solver.SetPreconditioner(T_prec);
T = NULL;
}
void WaveOperator::Mult(const Vector &u, const Vector &du_dt,
@@ -126,9 +124,11 @@ void WaveOperator::Mult(const Vector &u, const Vector &du_dt,
// Compute:
// d2udt2 = M^{-1}*-K(u)
// for d2udt2
Kmat.Mult(u, z);
K->FullMult(u, z);
z.Neg(); // z = -z
z.SetSubVector(ess_tdof_list, 0.0);
M_solver.Mult(z, d2udt2);
d2udt2.SetSubVector(ess_tdof_list, 0.0);
}
void WaveOperator::ImplicitSolve(const real_t fac0, const real_t fac1,
@@ -142,14 +142,11 @@ void WaveOperator::ImplicitSolve(const real_t fac0, const real_t fac1,
T = Add(1.0, Mmat, fac0, Kmat);
T_solver.SetOperator(*T);
}
Kmat0.Mult(u, z);
K->FullMult(u, z);
z.Neg();
for (int i = 0; i < ess_tdof_list.Size(); i++)
{
z[ess_tdof_list[i]] = 0.0;
}
z.SetSubVector(ess_tdof_list, 0.0);
T_solver.Mult(z, d2udt2);
d2udt2.SetSubVector(ess_tdof_list, 0.0);
}
void WaveOperator::SetParameters(const Vector &u)
@@ -314,7 +311,6 @@ int main(int argc, char *argv[])
ess_bdr = 0;
}
}
WaveOperator oper(fespace, ess_bdr, speed);
u_gf.SetFromTrueDofs(u);
+374
View File
@@ -0,0 +1,374 @@
// MFEM Example 40
//
// Compile with: make ex40
//
// Sample runs: ex40 -step 10 -gr 2.0
// ex40 -step 10 -gr 2.0 -o 3 -r 1
// ex40 -step 10 -gr 2.0 -r 4 -m ../data/l-shape.mesh
// ex40 -step 10 -gr 2.0 -r 2 -m ../data/fichera.mesh
//
// Description: This example code demonstrates how to use MFEM to solve the
// eikonal equation,
//
// |∇𝑢| = 1 in Ω, 𝑢 = g on ∂Ω.
//
// The solution of this problem coincides with the unique optimum of
// the nonlinear program
//
// maximize ∫_Ω 𝑢 d𝑥 subject to |∇𝑢| ≤ 1, 𝑢 = g on Ω, (⋆)
//
// which is the foundation for method implemented below.
//
// Following the proximal Galerkin methodology [1] (see also Example
// 36), we construct a Legendre function for the unit ball
// 𝐵₁ := {𝑥 ∈ Rⁿ | |𝑥| < 1}. Our choice is the Hellinger entropy,
//
// h(𝑥) = ( 1 |𝑥|² )^{1/2},
//
// although other choices are possible, each leading to a slightly
// different algorithm. We then adaptively regularize the optimization
// problem (⋆) with the Bregman divergence of the Hellinger entropy,
//
// maximize ∫_Ω 𝑢 d𝑥 - αₖ⁻¹ Dₕ(∇𝑢,∇𝑢ₖ₋₁) subject to 𝑢 = g on Ω.
//
// This results in a sequence of functions ( 𝜓ₖ , 𝑢ₖ ),
//
// 𝑢ₖ → 𝑢, 𝜓ₖ/|𝜓ₖ| → ∇𝑢 as k → \infty,
//
// defined by the nonlinear saddle-point problems
//
// Find 𝜓ₖ ∈ H(div,Ω) and 𝑢ₖ ∈ L²(Ω) such that
// ( Zₖ(𝜓ₖ) , τ ) + ( 𝑢ₖ , ∇⋅τ ) = ⟨ g , τ⋅n ⟩ ∀ τ ∈ H(div,Ω)
// ( ∇⋅𝜓ₖ , v ) = ( ∇⋅𝜓ₖ₋₁ - 1 , v ) ∀ v ∈ L²(Ω)
//
// where Zₖ(𝜓) := ∇h⁻¹(αₖ 𝜓) = 𝜓 / ( αₖ⁻² + |𝜓|² )^{1/2} and step size
// αₖ > 0. These saddle-point problems are solved using a damped Newton's
// method. This example assumes that g = 0 and allows the step size to
// grow geometrically, αₖ = α₀rᵏ, where r ≥ 1 is the growth rate.
//
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
class ZCoefficient : public VectorCoefficient
{
protected:
GridFunction *psi;
real_t alpha;
public:
ZCoefficient(int vdim, GridFunction &psi_, real_t alpha_ = 1.0)
: VectorCoefficient(vdim), psi(&psi_), alpha(alpha_) { }
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
class DZCoefficient : public MatrixCoefficient
{
protected:
GridFunction *psi;
real_t alpha;
public:
DZCoefficient(int height, GridFunction &psi_, real_t alpha_ = 1.0)
: MatrixCoefficient(height), psi(&psi_), alpha(alpha_) { }
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
int max_it = 5;
int ref_levels = 3;
real_t alpha = 1.0;
real_t growth_rate = 1.0;
real_t newton_scaling = 0.9;
real_t tichonov = 1e-1;
real_t tol = 1e-4;
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&ref_levels, "-r", "--refs",
"Number of h-refinements.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of iterations");
args.AddOption(&tol, "-tol", "--tol",
"Stopping criteria based on the difference between"
"successive solution updates");
args.AddOption(&alpha, "-step", "--step",
"Initial size alpha");
args.AddOption(&growth_rate, "-gr", "--growth-rate",
"Growth rate of the step size alpha");
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 mesh from the mesh file.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
int sdim = mesh.SpaceDimension();
MFEM_ASSERT(mesh.bdr_attributes.Size(),
"This example does not currently support meshes"
" without boundary attributes."
)
// 3. Postprocess the mesh.
// 3A. Refine the mesh to increase the resolution.
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
// 3B. Interpolate the geometry after refinement to control geometry error.
// NOTE: Minimum second-order interpolation is used to improve the accuracy.
int curvature_order = max(order,2);
mesh.SetCurvature(curvature_order);
// 4. Define the necessary finite element spaces on the mesh.
RT_FECollection RTfec(order, dim);
FiniteElementSpace RTfes(&mesh, &RTfec);
L2_FECollection L2fec(order, dim);
FiniteElementSpace L2fes(&mesh, &L2fec);
cout << "Number of H(div) dofs: "
<< RTfes.GetTrueVSize() << endl;
cout << "Number of L² dofs: "
<< L2fes.GetTrueVSize() << endl;
// 5. Define the offsets for the block matrices
Array<int> offsets(3);
offsets[0] = 0;
offsets[1] = RTfes.GetVSize();
offsets[2] = L2fes.GetVSize();
offsets.PartialSum();
BlockVector x(offsets), rhs(offsets);
x = 0.0; rhs = 0.0;
// 6. Define the solution vectors as a finite element grid functions
// corresponding to the fespaces.
GridFunction u_gf, delta_psi_gf;
delta_psi_gf.MakeRef(&RTfes,x,offsets[0]);
u_gf.MakeRef(&L2fes,x,offsets[1]);
GridFunction psi_old_gf(&RTfes);
GridFunction psi_gf(&RTfes);
GridFunction u_old_gf(&L2fes);
// 7. Define initial guesses for the solution variables.
delta_psi_gf = 0.0;
psi_gf = 0.0;
u_gf = 0.0;
psi_old_gf = psi_gf;
u_old_gf = u_gf;
// 8. Prepare for glvis output.
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock;
if (visualization)
{
sol_sock.open(vishost,visport);
sol_sock.precision(8);
}
// 9. Coefficients to be used later.
ConstantCoefficient neg_one(-1.0);
ConstantCoefficient zero(0.0);
ConstantCoefficient tichonov_cf(tichonov);
ConstantCoefficient neg_tichonov_cf(-1.0*tichonov);
ZCoefficient Z(sdim, psi_gf, alpha);
DZCoefficient DZ(sdim, psi_gf, alpha);
ScalarVectorProductCoefficient neg_Z(-1.0, Z);
DivergenceGridFunctionCoefficient div_psi_cf(&psi_gf);
DivergenceGridFunctionCoefficient div_psi_old_cf(&psi_old_gf);
SumCoefficient psi_old_minus_psi(div_psi_old_cf, div_psi_cf, 1.0, -1.0);
// 10. Assemble constant matrices/vectors to avoid reassembly in the loop.
LinearForm b0, b1;
b0.MakeRef(&RTfes,rhs.GetBlock(0),0);
b1.MakeRef(&L2fes,rhs.GetBlock(1),0);
b0.AddDomainIntegrator(new VectorFEDomainLFIntegrator(neg_Z));
b1.AddDomainIntegrator(new DomainLFIntegrator(neg_one));
b1.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
BilinearForm a00(&RTfes);
a00.AddDomainIntegrator(new VectorFEMassIntegrator(DZ));
a00.AddDomainIntegrator(new VectorFEMassIntegrator(tichonov_cf));
MixedBilinearForm a10(&RTfes,&L2fes);
a10.AddDomainIntegrator(new VectorFEDivergenceIntegrator());
a10.Assemble();
a10.Finalize();
SparseMatrix &A10 = a10.SpMat();
SparseMatrix *A01 = Transpose(A10);
BilinearForm a11(&L2fes);
a11.AddDomainIntegrator(new MassIntegrator(neg_tichonov_cf));
a11.Assemble();
a11.Finalize();
SparseMatrix &A11 = a11.SpMat();
// 11. Iterate.
int k;
int total_iterations = 0;
real_t increment_u = 0.1;
GridFunction u_tmp(&L2fes);
for (k = 0; k < max_it; k++)
{
u_tmp = u_old_gf;
Z.SetAlpha(alpha);
DZ.SetAlpha(alpha);
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
int j;
for ( j = 0; j < 5; j++)
{
total_iterations++;
b0.Assemble();
b1.Assemble();
a00.Assemble(false);
a00.Finalize(false);
SparseMatrix &A00 = a00.SpMat();
// Construct Schur-complement preconditioner
Vector A00_diag(a00.Height());
A00.GetDiag(A00_diag);
A00_diag.Reciprocal();
SparseMatrix *S = Mult_AtDA(*A01, A00_diag);
BlockDiagonalPreconditioner prec(offsets);
prec.SetDiagonalBlock(0,new DSmoother(A00));
#ifndef MFEM_USE_SUITESPARSE
prec.SetDiagonalBlock(1,new GSSmoother(*S));
#else
prec.SetDiagonalBlock(1,new UMFPackSolver(*S));
#endif
prec.owns_blocks = 1;
BlockOperator A(offsets);
A.SetBlock(0,0,&A00);
A.SetBlock(1,0,&A10);
A.SetBlock(0,1,A01);
A.SetBlock(1,1,&A11);
GMRES(A,prec,rhs,x,0,2000,500,1e-12,0.0);
delete S;
u_tmp -= u_gf;
real_t Newton_update_size = u_tmp.ComputeL2Error(zero);
u_tmp = u_gf;
// Damped Newton update
psi_gf.Add(newton_scaling, delta_psi_gf);
a00.Update();
if (visualization)
{
sol_sock << "solution\n" << mesh << u_gf << "window_title 'Discrete solution'"
<< flush;
}
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
if (Newton_update_size < increment_u)
{
break;
}
}
u_tmp = u_gf;
u_tmp -= u_old_gf;
increment_u = u_tmp.ComputeL2Error(zero);
mfem::out << "Number of Newton iterations = " << j+1 << endl;
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
u_old_gf = u_gf;
psi_old_gf = psi_gf;
if (increment_u < tol || k == max_it-1)
{
break;
}
alpha *= max(growth_rate, 1_r);
}
mfem::out << "\n Outer iterations: " << k+1
<< "\n Total iterations: " << total_iterations
<< "\n Total dofs: " << RTfes.GetTrueVSize() + L2fes.GetTrueVSize()
<< endl;
delete A01;
return 0;
}
void ZCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(psi != NULL, "grid function is not set");
MFEM_ASSERT(alpha > 0, "alpha is not positive");
Vector psi_vals(vdim);
psi->GetVectorValue(T, ip, psi_vals);
real_t norm = psi_vals.Norml2();
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
V = psi_vals;
V *= phi;
}
void DZCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(psi != NULL, "grid function is not set");
MFEM_ASSERT(alpha > 0, "alpha is not positive");
Vector psi_vals(height);
psi->GetVectorValue(T, ip, psi_vals);
real_t norm = psi_vals.Norml2();
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
K = 0.0;
for (int i = 0; i < height; i++)
{
K(i,i) = phi;
for (int j = 0; j < height; j++)
{
K(i,j) -= psi_vals(i) * psi_vals(j) * pow(phi, 3);
}
}
}
+436
View File
@@ -0,0 +1,436 @@
// MFEM Example 40 - Parallel Version
//
// Compile with: make ex40p
//
// Sample runs: mpirun -np 4 ex40p -step 10 -gr 2.0
// mpirun -np 4 ex40p -step 10 -gr 2.0 -o 3 -r 1
// mpirun -np 4 ex40p -step 10 -gr 2.0 -r 4 -m ../data/l-shape.mesh
// mpirun -np 4 ex40p -step 10 -gr 2.0 -r 2 -m ../data/fichera.mesh
//
// Description: This example code demonstrates how to use MFEM to solve the
// eikonal equation,
//
// |∇𝑢| = 1 in Ω, 𝑢 = g on ∂Ω.
//
// The solution of this problem coincides with the unique optimum of
// the nonlinear program
//
// maximize ∫_Ω 𝑢 d𝑥 subject to |∇𝑢| ≤ 1, 𝑢 = g on Ω, (⋆)
//
// which is the foundation for method implemented below.
//
// Following the proximal Galerkin methodology [1] (see also Example
// 36), we construct a Legendre function for the unit ball
// 𝐵₁ := {𝑥 ∈ Rⁿ | |𝑥| < 1}. Our choice is the Hellinger entropy,
//
// h(𝑥) = ( 1 |𝑥|² )^{1/2},
//
// although other choices are possible, each leading to a slightly
// different algorithm. We then adaptively regularize the optimization
// problem (⋆) with the Bregman divergence of the Hellinger entropy,
//
// maximize ∫_Ω 𝑢 d𝑥 - αₖ⁻¹ Dₕ(∇𝑢,∇𝑢ₖ₋₁) subject to 𝑢 = g on Ω.
//
// This results in a sequence of functions ( 𝜓ₖ , 𝑢ₖ ),
//
// 𝑢ₖ → 𝑢, 𝜓ₖ/|𝜓ₖ| → ∇𝑢 as k → \infty,
//
// defined by the nonlinear saddle-point problems
//
// Find 𝜓ₖ ∈ H(div,Ω) and 𝑢ₖ ∈ L²(Ω) such that
// ( Zₖ(𝜓ₖ) , τ ) + ( 𝑢ₖ , ∇⋅τ ) = ⟨ g , τ⋅n ⟩ ∀ τ ∈ H(div,Ω)
// ( ∇⋅𝜓ₖ , v ) = ( ∇⋅𝜓ₖ₋₁ - 1 , v ) ∀ v ∈ L²(Ω)
//
// where Zₖ(𝜓) := ∇h⁻¹(αₖ 𝜓) = 𝜓 / ( αₖ⁻² + |𝜓|² )^{1/2} and step size
// αₖ > 0. These saddle-point problems are solved using a damped Newton's
// method. This example assumes that g = 0 and allows the step size to
// grow geometrically, αₖ = α₀rᵏ, where r ≥ 1 is the growth rate.
//
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
class ZCoefficient : public VectorCoefficient
{
protected:
ParGridFunction *psi;
real_t alpha;
public:
ZCoefficient(int vdim, ParGridFunction &psi_, real_t alpha_ = 1.0)
: VectorCoefficient(vdim), psi(&psi_), alpha(alpha_) { }
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
class DZCoefficient : public MatrixCoefficient
{
protected:
ParGridFunction *psi;
real_t alpha;
public:
DZCoefficient(int height, ParGridFunction &psi_, real_t alpha_ = 1.0)
: MatrixCoefficient(height), psi(&psi_), alpha(alpha_) { }
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
int main(int argc, char *argv[])
{
// 0. Initialize MPI and HYPRE.
Mpi::Init();
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
int max_it = 5;
int ref_levels = 3;
real_t alpha = 1.0;
real_t growth_rate = 1.0;
real_t newton_scaling = 0.9;
real_t tichonov = 1e-1;
real_t tol = 1e-4;
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&ref_levels, "-r", "--refs",
"Number of h-refinements.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of iterations");
args.AddOption(&tol, "-tol", "--tol",
"Stopping criteria based on the difference between"
"successive solution updates");
args.AddOption(&alpha, "-step", "--step",
"Initial size alpha");
args.AddOption(&growth_rate, "-gr", "--growth-rate",
"Growth rate of the step size alpha");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 2. Read the mesh from the mesh file.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
int sdim = mesh.SpaceDimension();
MFEM_ASSERT(mesh.bdr_attributes.Size(),
"This example does not currently support meshes"
" without boundary attributes."
)
// 3. Postprocess the mesh.
// 3A. Refine the mesh to increase the resolution.
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
// 3B. Interpolate the geometry after refinement to control geometry error.
// NOTE: Minimum second-order interpolation is used to improve the accuracy.
int curvature_order = max(order,2);
mesh.SetCurvature(curvature_order);
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
// 4. Define the necessary finite element spaces on the mesh.
RT_FECollection RTfec(order, dim);
ParFiniteElementSpace RTfes(&pmesh, &RTfec);
L2_FECollection L2fec(order, dim);
ParFiniteElementSpace L2fes(&pmesh, &L2fec);
int num_dofs_RT = RTfes.GlobalTrueVSize();
int num_dofs_L2 = L2fes.GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of H(div) dofs: "
<< num_dofs_RT << endl;
cout << "Number of L² dofs: "
<< num_dofs_L2 << endl;
}
// 5. Define the offsets for the block matrices
Array<int> offsets(3);
offsets[0] = 0;
offsets[1] = RTfes.GetVSize();
offsets[2] = L2fes.GetVSize();
offsets.PartialSum();
Array<int> toffsets(3);
toffsets[0] = 0;
toffsets[1] = RTfes.GetTrueVSize();
toffsets[2] = L2fes.GetTrueVSize();
toffsets.PartialSum();
BlockVector x(offsets), rhs(offsets);
x = 0.0; rhs = 0.0;
BlockVector tx(toffsets), trhs(toffsets);
tx = 0.0; trhs = 0.0;
// 6. Define the solution vectors as a finite element grid functions
// corresponding to the fespaces.
ParGridFunction u_gf, delta_psi_gf;
delta_psi_gf.MakeRef(&RTfes,x,offsets[0]);
u_gf.MakeRef(&L2fes,x,offsets[1]);
ParGridFunction psi_old_gf(&RTfes);
ParGridFunction psi_gf(&RTfes);
ParGridFunction u_old_gf(&L2fes);
// 7. Define initial guesses for the solution variables.
delta_psi_gf = 0.0;
psi_gf = 0.0;
u_gf = 0.0;
psi_old_gf = psi_gf;
u_old_gf = u_gf;
// 8. Prepare for glvis output.
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock;
if (visualization)
{
sol_sock.open(vishost,visport);
sol_sock.precision(8);
}
// 9. Coefficients to be used later.
ConstantCoefficient neg_one(-1.0);
ConstantCoefficient zero(0.0);
ConstantCoefficient tichonov_cf(tichonov);
ConstantCoefficient neg_tichonov_cf(-1.0*tichonov);
ZCoefficient Z(sdim, psi_gf, alpha);
DZCoefficient DZ(sdim, psi_gf, alpha);
ScalarVectorProductCoefficient neg_Z(-1.0, Z);
DivergenceGridFunctionCoefficient div_psi_cf(&psi_gf);
DivergenceGridFunctionCoefficient div_psi_old_cf(&psi_old_gf);
SumCoefficient psi_old_minus_psi(div_psi_old_cf, div_psi_cf, 1.0, -1.0);
// 10. Assemble constant matrices/vectors to avoid reassembly in the loop.
ParLinearForm b0, b1;
b0.MakeRef(&RTfes,rhs.GetBlock(0),0);
b1.MakeRef(&L2fes,rhs.GetBlock(1),0);
b0.AddDomainIntegrator(new VectorFEDomainLFIntegrator(neg_Z));
b1.AddDomainIntegrator(new DomainLFIntegrator(neg_one));
b1.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
ParBilinearForm a00(&RTfes);
a00.AddDomainIntegrator(new VectorFEMassIntegrator(DZ));
a00.AddDomainIntegrator(new VectorFEMassIntegrator(tichonov_cf));
ParMixedBilinearForm a10(&RTfes,&L2fes);
a10.AddDomainIntegrator(new VectorFEDivergenceIntegrator());
a10.Assemble();
a10.Finalize();
HypreParMatrix *A10 = a10.ParallelAssemble();
HypreParMatrix *A01 = A10->Transpose();
ParBilinearForm a11(&L2fes);
a11.AddDomainIntegrator(new MassIntegrator(neg_tichonov_cf));
a11.Assemble();
a11.Finalize();
HypreParMatrix *A11 = a11.ParallelAssemble();
// 11. Iterate.
int k;
int total_iterations = 0;
real_t increment_u = 0.1;
ParGridFunction u_tmp(&L2fes);
for (k = 0; k < max_it; k++)
{
u_tmp = u_old_gf;
Z.SetAlpha(alpha);
DZ.SetAlpha(alpha);
if (myid == 0)
{
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
}
int j;
for ( j = 0; j < 5; j++)
{
total_iterations++;
b0.Assemble();
b0.ParallelAssemble(trhs.GetBlock(0));
b1.Assemble();
b1.ParallelAssemble(trhs.GetBlock(1));
a00.Assemble(false);
a00.Finalize(false);
HypreParMatrix *A00 = a00.ParallelAssemble();
// Construct Schur-complement preconditioner
HypreParVector A00_diag(MPI_COMM_WORLD, A00->GetGlobalNumRows(),
A00->GetRowStarts());
A00->GetDiag(A00_diag);
HypreParMatrix S_tmp(*A01);
S_tmp.InvScaleRows(A00_diag);
HypreParMatrix *S = ParMult(A10, &S_tmp, true);
BlockDiagonalPreconditioner prec(toffsets);
HypreBoomerAMG P00(*A00);
P00.SetPrintLevel(0);
HypreBoomerAMG P11(*S);
P11.SetPrintLevel(0);
prec.SetDiagonalBlock(0,&P00);
prec.SetDiagonalBlock(1,&P11);
BlockOperator A(toffsets);
A.SetBlock(0,0,A00);
A.SetBlock(1,0,A10);
A.SetBlock(0,1,A01);
A.SetBlock(1,1,A11);
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetPrintLevel(-1);
gmres.SetRelTol(1e-8);
gmres.SetMaxIter(2000);
gmres.SetKDim(500);
gmres.SetOperator(A);
gmres.SetPreconditioner(prec);
gmres.Mult(trhs,tx);
delete S;
delete A00;
delta_psi_gf.SetFromTrueDofs(tx.GetBlock(0));
u_gf.SetFromTrueDofs(tx.GetBlock(1));
u_tmp -= u_gf;
real_t Newton_update_size = u_tmp.ComputeL2Error(zero);
u_tmp = u_gf;
// Damped Newton update
psi_gf.Add(newton_scaling, delta_psi_gf);
a00.Update();
if (visualization)
{
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock << "solution\n" << pmesh << u_gf << "window_title 'Discrete solution'"
<< flush;
}
if (myid == 0)
{
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
}
if (Newton_update_size < increment_u)
{
break;
}
}
u_tmp = u_gf;
u_tmp -= u_old_gf;
increment_u = u_tmp.ComputeL2Error(zero);
if (myid == 0)
{
mfem::out << "Number of Newton iterations = " << j+1 << endl;
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
}
u_old_gf = u_gf;
psi_old_gf = psi_gf;
if (increment_u < tol || k == max_it-1)
{
break;
}
alpha *= max(growth_rate, 1_r);
}
// 12. Print stats.
if (myid == 0)
{
mfem::out << "\n Outer iterations: " << k+1
<< "\n Total iterations: " << total_iterations
<< "\n Total dofs: " << RTfes.GetTrueVSize() + L2fes.GetTrueVSize()
<< endl;
}
// 13. Free the used memory.
delete A01;
delete A10;
delete A11;
return 0;
}
void ZCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(psi != NULL, "grid function is not set");
MFEM_ASSERT(alpha > 0, "alpha is not positive");
Vector psi_vals(vdim);
psi->GetVectorValue(T, ip, psi_vals);
real_t norm = psi_vals.Norml2();
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
V = psi_vals;
V *= phi;
}
void DZCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(psi != NULL, "grid function is not set");
MFEM_ASSERT(alpha > 0, "alpha is not positive");
Vector psi_vals(height);
psi->GetVectorValue(T, ip, psi_vals);
real_t norm = psi_vals.Norml2();
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
K = 0.0;
for (int i = 0; i < height; i++)
{
K(i,i) = phi;
for (int j = 0; j < height; j++)
{
K(i,j) -= psi_vals(i) * psi_vals(j) * pow(phi, 3);
}
}
}
+13 -5
View File
@@ -23,14 +23,14 @@ MFEM_LIB_FILE = mfem_is_not_built
SEQ_EXAMPLES = ex0 ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 \
ex17 ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex28 ex29 ex30 \
ex31 ex33 ex34 ex36 ex37 ex38 ex39
ex31 ex33 ex34 ex36 ex37 ex38 ex39 ex40
PAR_EXAMPLES = ex0p ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p \
ex12p ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p \
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p ex34p ex35p ex36p \
ex37p ex39p
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p \
ex24p ex25p ex26p ex34p ex35p
ex37p ex39p ex40p
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex14 ex22 ex24 ex25 ex26 ex34
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex14p \
ex22p ex24p ex25p ex26p ex34p ex35p
ifeq ($(MFEM_USE_LAPACK),YES)
SEQ_EXAMPLES += ex38
@@ -138,6 +138,14 @@ ex10-test-seq: ex10
@$(call mfem-test,$<,, Serial example,-tf 5)
ex10p-test-par: ex10p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-tf 5)
ex14-test-seq-cuda: ex14
@$(call mfem-test,$<,, Serial CUDA example,-r 2 -pa -d cuda)
ex14p-test-par-cuda: ex14p
@$(call mfem-test,$<, $(RUN_MPI), Parallel CUDA example,-rs 2 -rp 0 -pa -d cuda)
ex14-test-seq-hip: ex14
@$(call mfem-test,$<,, Serial HIP example,-r 2 -pa -d hip)
ex14p-test-par-hip: ex14p
@$(call mfem-test,$<, $(RUN_MPI), Parallel HIP example,-rs 2 -rp 0 -pa -d hip)
ex15-test-seq: ex15
@$(call mfem-test,$<,, Serial example,-e 1)
ex15p-test-par: ex15p
-1
View File
@@ -66,7 +66,6 @@ int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI) and HYPRE.
Mpi::Init(argc, argv);
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
-2
View File
@@ -80,8 +80,6 @@ int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI) and HYPRE.
Mpi::Init(argc, argv);
int num_proc = Mpi::WorldSize();
int myId = Mpi::WorldRank();
Hypre::Init();
// 2. Parse command-line options.
+345
View File
@@ -1539,6 +1539,351 @@ const IntegrationRule &ConvectionIntegrator::GetRule(
return GetRule(el,el,Trans);
}
void LaplaceIntegrator::AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat )
{
int nd = el.GetDof();
real_t w;
elmat.SetSize(nd);
shape.SetSize(nd);
laplace.SetSize(nd);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
el.CalcPhysShape(Trans, shape);
el.CalcPhysLaplacian(Trans, laplace);
w = Trans.Weight() * ip.weight * alpha;
if (Q)
{
w *= Q -> Eval(Trans, ip);
}
shape *= w;
AddMultVWt(shape, laplace, elmat);
}
}
void LaplaceIntegrator::AssembleElementMatrix2(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat)
{
int tr_nd = trial_fe.GetDof();
int te_nd = test_fe.GetDof();
elmat.SetSize(te_nd, tr_nd);
laplace.SetSize(tr_nd);
shape.SetSize(te_nd);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
Trans);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
test_fe.CalcPhysShape(Trans, shape);
trial_fe.CalcPhysLaplacian(Trans, laplace);
real_t w = Trans.Weight() * ip.weight * alpha;
if (Q)
{
w *= Q -> Eval(Trans, ip);
}
AddMult_a_VWt(w, shape, laplace, elmat);
}
}
const IntegrationRule &LaplaceIntegrator::GetRule(
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans)
{
int order = trial_fe.GetOrder() + test_fe.GetOrder();
return IntRules.Get(trial_fe.GetGeomType(), order);
}
void LaplaceGradIntegrator::AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat )
{
int nd = el.GetDof();
dim = el.GetDim();
elmat.SetSize(nd);
dshape.SetSize(nd,dim);
adjJ.SetSize(dim);
laplace.SetSize(nd);
vec2.SetSize(dim);
BdFidxT.SetSize(nd);
Vector vec1;
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
Q->Eval(Q_ir, Trans, *ir);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
el.CalcDShape(ip, dshape);
el.CalcPhysLaplacian(Trans, laplace);
Trans.SetIntPoint(&ip);
CalcAdjugate(Trans.Jacobian(), adjJ);
Q_ir.GetColumnReference(i, vec1);
vec1 *= alpha * ip.weight;
adjJ.Mult(vec1, vec2);
dshape.Mult(vec2, BdFidxT);
AddMultVWt(BdFidxT, laplace, elmat);
}
}
void LaplaceGradIntegrator::AssembleElementMatrix2(const FiniteElement
&trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat)
{
dim = trial_fe.GetDim();
int tr_nd = trial_fe.GetDof();
int te_nd = test_fe.GetDof();
elmat.SetSize(te_nd, tr_nd);
laplace.SetSize(tr_nd);
dshape.SetSize(te_nd,dim);
adjJ.SetSize(dim);
vec2.SetSize(dim);
BdFidxT.SetSize(te_nd);
Vector vec1;
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
Trans);
Q->Eval(Q_ir, Trans, *ir);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
test_fe.CalcDShape(ip, dshape);
trial_fe.CalcPhysLaplacian(Trans, laplace);
Trans.SetIntPoint(&ip);
CalcAdjugate(Trans.Jacobian(), adjJ);
Q_ir.GetColumnReference(i, vec1);
vec1 *= alpha * ip.weight;
adjJ.Mult(vec1, vec2);
dshape.Mult(vec2, BdFidxT);
AddMultVWt(BdFidxT, laplace,elmat);
}
}
const IntegrationRule &LaplaceGradIntegrator::GetRule(
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans)
{
int order = trial_fe.GetOrder() + test_fe.GetOrder();
return IntRules.Get(trial_fe.GetGeomType(), order);
}
void LaplaceLaplaceIntegrator::AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat )
{
int nd = el.GetDof();
real_t w;
elmat.SetSize(nd);
laplace.SetSize(nd);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
el.CalcPhysLaplacian(Trans, laplace);
w = Trans.Weight() * ip.weight * alpha;
if (Q)
{
w *= Q -> Eval(Trans, ip);
}
AddMult_a_VVt(w, laplace, elmat);
}
}
void LaplaceLaplaceIntegrator::AssembleElementMatrix2(const FiniteElement
&trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat)
{
int
dim = trial_fe.GetDim();
int tr_nd = trial_fe.GetDof();
int te_nd = test_fe.GetDof();
real_t w;
elmat.SetSize(te_nd, tr_nd);
laplace.SetSize(tr_nd);
te_laplace.SetSize(te_nd);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
Trans);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
trial_fe.CalcPhysLaplacian(Trans, laplace);
test_fe.CalcPhysLaplacian(Trans, te_laplace);
w = Trans.Weight() * ip.weight * alpha;
if (Q)
{
w *= Q -> Eval(Trans, ip);
}
AddMult_a_VWt(w, te_laplace, laplace, elmat);
}
}
const IntegrationRule &LaplaceLaplaceIntegrator::GetRule(
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans)
{
int order = trial_fe.GetOrder() + test_fe.GetOrder();
return IntRules.Get(trial_fe.GetGeomType(), order);
}
void InverseEstimateIntegrator::AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat )
{
elmat = 0.0;
int nd = el.GetDof();
int dim = el.GetDim();
shape.SetSize(nd);
dshape.SetSize(nd,dim);
laplace.SetSize(nd);
lapmat.SetSize(nd,nd);
bimat.SetSize(nd,nd);
ovec.SetSize(nd);
real_t w,q;
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
int order = Trans.OrderGrad(&el) + Trans.Order() + el.GetOrder();
ir = &IntRules.Get(el.GetGeomType(), order);
}
bimat = 0.0;
lapmat = 0.0;
ovec = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint(&ip);
w = Trans.Weight()*ip.weight;
if (Q)
{
q = Q->Eval(Trans, ip);
}
el.CalcPhysDShape(Trans, dshape);
AddMult_a_AAt(w*q, dshape, lapmat);
el.CalcPhysLaplacian(Trans, laplace);
AddMult_a_VVt(w*q*q, laplace, bimat);
el.CalcPhysShape(Trans, shape);
ovec.Add(w, shape);
}
// Power method
Vector x(nd);
x.Randomize(696383532);
// Correct nullspace + inverse
AddMult_a_VVt(1.0, ovec, lapmat);
DenseMatrixInverse L_inv(lapmat);
// DenseMatrix M_i, Q_i;
real_t alpha= 0.0, eval_i = 0.0, eval_prev = 0.0;
// Inverse power method
Vector x_tmp(nd);
int iter = 0;
const real_t rel_tol = 1e-4;
alpha = ovec*ovec;
ovec *= 1.0/sqrt(alpha);
do
{
// Othogonalize
alpha = x*ovec;
x.Add(-alpha, ovec);
// MatVec (2x)
bimat.Mult(x, x_tmp);
L_inv.Mult(x_tmp, x);
eval_prev = eval_i;
eval_i = x.Norml2();
x *= 1.0/eval_i;
++iter;
}
while ((iter < 10000) && (fabs(eval_i - eval_prev)/fabs(eval_i) > rel_tol));
MFEM_VERIFY(fabs(eval_i - eval_prev)/fabs(eval_i) <= rel_tol,
"Inverse power method did not converge."
<< "\n\t iter = " << iter
<< "\n\t eval_i = " << eval_i
<< "\n\t eval_prev = " << eval_prev
<< "\n\t fabs(eval_i - eval_prev)/fabs(eval_i) = "
<< fabs(eval_i - eval_prev)/fabs(eval_i));
cout<<"evev = "<<eval_i<<" "<<iter<<endl;
}
const IntegrationRule &InverseEstimateIntegrator::GetRule(
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans)
{
// int order = Trans.OrderGrad(&trial_fe) + Trans.Order() + test_fe.GetOrder() - 2;
int order = trial_fe.GetOrder() + test_fe.GetOrder();
return IntRules.Get(trial_fe.GetGeomType(), order);
}
void VectorMassIntegrator::AssembleElementMatrix
( const FiniteElement &el, ElementTransformation &Trans,
DenseMatrix &elmat )
+132 -3
View File
@@ -1741,7 +1741,7 @@ public:
{ vector_fe.CalcPhysDShape(Trans, shape); }
};
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \cdot \nabla \cdot u, \nabla \cdot v)$ in 2D
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \cdot \nabla u, \nabla \cdot v)$ in 2D
or 3D and where $\hat{V}$ is a vector coefficient, $u$ is in $H^1$ and $v$ is in $H(div)$. */
class MixedGradDivIntegrator : public MixedScalarVectorIntegrator
{
@@ -1780,7 +1780,7 @@ public:
{ scalar_fe.CalcPhysDivShape(Trans, shape); }
};
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \nabla \cdot u, \nabla \cdot v)$ in 2D
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \nabla \cdot u, \nabla v)$ in 2D
or 3D and where $\hat{V}$ is a vector coefficient, $u$ is in $H(div)$ and $v$ is in $H^1$. */
class MixedDivGradIntegrator : public MixedScalarVectorIntegrator
{
@@ -1820,7 +1820,7 @@ public:
{ scalar_fe.CalcPhysDivShape(Trans, shape); }
};
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} u, \nabla \cdot v)$ in 2D or 3D
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} u, \nabla v)$ in 2D or 3D
and where $\hat{V}$ is a vector coefficient, $u$ is in $H^1$ or $L_2$ and $v$ is in $H^1$. */
class MixedScalarWeakDivergenceIntegrator : public MixedScalarVectorIntegrator
{
@@ -2450,6 +2450,135 @@ public:
DenseMatrix &);
};
/// $\alpha (Q \Delta u, v)$
class LaplaceIntegrator : public BilinearFormIntegrator
{
protected:
Coefficient *Q;
real_t alpha;
private:
Vector laplace, shape;
public:
LaplaceIntegrator(Coefficient &q, real_t a = 1.0)
: Q(&q) { alpha = a; }
virtual void AssembleElementMatrix(const FiniteElement &,
ElementTransformation &,
DenseMatrix &);
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans);
};
/// $\alpha (u, Q \Delta v)$
class TransposeLaplaceIntegrator : public TransposeIntegrator
{
public:
TransposeLaplaceIntegrator (Coefficient &q, real_t a = 1.0)
: TransposeIntegrator(new LaplaceIntegrator(q, a)) { }
};
/// $\alpha (\Delta u, Q \cdot \nabla v)$
class LaplaceGradIntegrator : public BilinearFormIntegrator
{
protected:
VectorCoefficient *Q;
real_t alpha;
int dim;
private:
Vector laplace, vec2, BdFidxT;
DenseMatrix dshape, adjJ, Q_ir;
public:
LaplaceGradIntegrator(VectorCoefficient &q, real_t a = 1.0)
: Q(&q) { alpha = a; }
virtual void AssembleElementMatrix(const FiniteElement &,
ElementTransformation &,
DenseMatrix &);
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans);
};
/// $\alpha (Q \cdot \nabla u, \Delta v)$
class GradLaplaceIntegrator : public TransposeIntegrator
{
public:
GradLaplaceIntegrator(VectorCoefficient &q, real_t a = 1.0)
: TransposeIntegrator(new LaplaceGradIntegrator(q, a)) { }
};
/// $\alpha (Q \Delta u, \Delta v)$
class LaplaceLaplaceIntegrator : public BilinearFormIntegrator
{
protected:
Coefficient *Q;
real_t alpha;
private:
Vector laplace, te_laplace;
public:
LaplaceLaplaceIntegrator(Coefficient &q, real_t a = 1.0)
: Q(&q) { alpha = a; }
virtual void AssembleElementMatrix(const FiniteElement &,
ElementTransformation &,
DenseMatrix &);
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans);
};
// Alias for @LaplaceLaplaceIntegrator.
using BiHarmonicIntegrator = LaplaceLaplaceIntegrator;
/// Get the inverse estimate
class InverseEstimateIntegrator : public BilinearFormIntegrator
{
protected:
Coefficient *Q;
private:
Vector laplace, shape, ovec;//, vec2, BdFidxT;
DenseMatrix dshape, lapmat, bimat;//, adjJ, Q_ir;
public:
InverseEstimateIntegrator(Coefficient &q)
: Q(&q) { }
virtual void AssembleElementMatrix(const FiniteElement &,
ElementTransformation &,
DenseMatrix &);
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans);
};
/** Class for integrating the bilinear form $a(u,v) := (Q u, v)$,
where $u=(u_1,\dots,u_n)$ and $v=(v_1,\dots,v_n)$, $u_i$ and $v_i$ are defined
by scalar FE through standard transformation. */
+407 -4
View File
@@ -807,6 +807,7 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
QuadratureSpaceBase &qspace = *qf.GetSpace();
const int ne = qspace.GetNE();
qf.HostWrite();
DenseMatrix values;
DenseSymmetricMatrix matrix;
for (int iel = 0; iel < ne; ++iel)
@@ -818,7 +819,7 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
{
const IntegrationPoint &ip = ir[iq];
T.SetIntPoint(&ip);
matrix.UseExternalData(&values(0, iq), vdim);
matrix.UseExternalData(&values(0, iq), height);
Eval(matrix, T, ip);
}
}
@@ -828,13 +829,12 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
void SymmetricMatrixCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
mat.SetSize(height);
Eval(mat, T, ip);
Eval(mat_aux, T, ip);
for (int j = 0; j < width; ++j)
{
for (int i = 0; i < height; ++ i)
{
K(i, j) = mat(i, j);
K(i, j) = mat_aux(i, j);
}
}
}
@@ -924,6 +924,75 @@ void MatrixArrayCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
}
}
MatrixArrayVectorCoefficient::MatrixArrayVectorCoefficient (int dim)
: MatrixCoefficient (dim)
{
Coeff.SetSize(height);
ownCoeff.SetSize(height);
for (int i = 0; i < height; i++)
{
Coeff[i] = NULL;
ownCoeff[i] = true;
}
}
void MatrixArrayVectorCoefficient::SetTime(real_t t)
{
for (int i=0; i < height; i++)
{
if (Coeff[i]) { Coeff[i]->SetTime(t); }
}
this->MatrixCoefficient::SetTime(t);
}
void MatrixArrayVectorCoefficient::Set(int i, VectorCoefficient * c, bool own)
{
MFEM_ASSERT(i < height && i >= 0, "Row "
<< i << " does not exist. " <<
"Matrix height = " << height << ".");
if (ownCoeff[i]) { delete Coeff[i]; }
Coeff[i] = c;
ownCoeff[i] = own;
}
MatrixArrayVectorCoefficient::~MatrixArrayVectorCoefficient ()
{
for (int i=0; i < height; i++)
{
if (ownCoeff[i]) { delete Coeff[i]; }
}
}
void MatrixArrayVectorCoefficient::Eval(int i, Vector &V,
ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(i < height && i >= 0, "Row "
<< i << " does not exist. " <<
"Matrix height = " << height << ".");
if (Coeff[i])
{
Coeff[i] -> Eval(V, T, ip);
}
else
{
V = 0.0;
}
}
void MatrixArrayVectorCoefficient::Eval(DenseMatrix &K,
ElementTransformation &T,
const IntegrationPoint &ip)
{
K.SetSize(height, width);
Vector V(width);
for (int i = 0; i < height; i++)
{
this->Eval(i, V, T, ip);
K.SetRow(i, V);
}
}
void MatrixRestrictedCoefficient::SetTime(real_t t)
{
if (c) { c->SetTime(t); }
@@ -1041,6 +1110,27 @@ real_t DeterminantCoefficient::Eval(ElementTransformation &T,
return ma.Det();
}
TraceCoefficient::TraceCoefficient(MatrixCoefficient &A)
: a(&A), ma(A.GetHeight(), A.GetWidth())
{
MFEM_ASSERT(A.GetHeight() == A.GetWidth(),
"TraceCoefficient: "
"Argument must be a square matrix.");
}
void TraceCoefficient::SetTime(real_t t)
{
if (a) { a->SetTime(t); }
this->Coefficient::SetTime(t);
}
real_t TraceCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
a->Eval(ma, T, ip);
return ma.Trace();
}
VectorSumCoefficient::VectorSumCoefficient(int dim)
: VectorCoefficient(dim),
ACoef(NULL), BCoef(NULL),
@@ -1326,6 +1416,30 @@ void InverseMatrixCoefficient::Eval(DenseMatrix &M,
M.Invert();
}
ExponentialMatrixCoefficient::ExponentialMatrixCoefficient(MatrixCoefficient &A)
: MatrixCoefficient(A.GetHeight(), A.GetWidth()), a(&A)
{
MFEM_ASSERT(A.GetHeight() == A.GetWidth() && A.GetHeight() == 2,
"ExponentialMatrixCoefficient: "
<< "Argument must be a square 2x2 matrix."
<< " Height = " << A.GetHeight()
<< ", Width = " << A.GetWidth());
}
void ExponentialMatrixCoefficient::SetTime(real_t t)
{
if (a) { a->SetTime(t); }
this->MatrixCoefficient::SetTime(t);
}
void ExponentialMatrixCoefficient::Eval(DenseMatrix &M,
ElementTransformation &T,
const IntegrationPoint &ip)
{
a->Eval(M, T, ip);
M.Exponential();
}
OuterProductCoefficient::OuterProductCoefficient(VectorCoefficient &A,
VectorCoefficient &B)
: MatrixCoefficient(A.GetVDim(), B.GetVDim()), a(&A), b(&B),
@@ -1390,6 +1504,295 @@ void CrossCrossCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
M *= ((a == NULL ) ? aConst : a->Eval(T, ip) );
}
InverseEstimateCoefficient::InverseEstimateCoefficient(FiniteElementSpace *f)
: fes(f), Q(NULL), ir(NULL)
{
ComputeInverseEstimates();
}
InverseEstimateCoefficient::InverseEstimateCoefficient(FiniteElementSpace *f,
Coefficient &q)
: fes(f), Q(&q), ir(NULL)
{
ComputeInverseEstimates();
}
GridFunction *InverseEstimateCoefficient::GetGridFunction()
{
FiniteElementCollection* fec_ec = new L2_FECollection(0,
fes ->GetMesh()->Dimension());
FiniteElementSpace *fes_ec = new FiniteElementSpace(fes ->GetMesh(), fec_ec);
GridFunction *gf = new GridFunction(fes_ec, elemInvEst.GetData());
gf->MakeOwner(fec_ec);
return gf;
}
void InverseEstimateCoefficient::ComputeInverseEstimates()
{
elemInvEst.SetSize(fes -> GetNE());
SetIntRule(*fes->GetFE(0));
for (int i = 0; i < fes -> GetNE(); i++)
{
elemInvEst[i] = ElementInverseEstimate(*fes->GetFE(i),
*fes->GetElementTransformation(i));
}
}
void InverseEstimateCoefficient::SetIntRule(const FiniteElement &el)
{
ir = &IntRules.Get(el.GetGeomType(), 2*el.GetOrder());
}
real_t InverseEstimateCoefficient::ElementInverseEstimate(
const FiniteElement &el,
ElementTransformation &Trans)
{
if (el.GetOrder() < 2)
{
return std::numeric_limits<real_t>::min();
}
int nd = el.GetDof();
int dim = el.GetDim();
shape.SetSize(nd);
dshape.SetSize(nd,dim);
laplace.SetSize(nd);
lapmat.SetSize(nd,nd);
bimat.SetSize(nd,nd);
ovec.SetSize(nd);
real_t w,q = 1.0;
bimat = 0.0;
lapmat = 0.0;
ovec = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint(&ip);
w = Trans.Weight()*ip.weight;
if (Q)
{
q = Q->Eval(Trans, ip);
}
el.CalcPhysDShape(Trans, dshape);
AddMult_a_AAt(w*q, dshape, lapmat);
el.CalcPhysLaplacian(Trans, laplace);
AddMult_a_VVt(w*q*q, laplace, bimat);
el.CalcPhysShape(Trans, shape);
ovec.Add(w, shape);
}
ovec *= 1.0/ovec.Norml2();
// Correct nullspace
AddMultVVt(ovec, lapmat);
// Return largest eigenvalue
return bimat.Eigenvalue(lapmat);
}
ElasticInverseEstimateCoefficient
::ElasticInverseEstimateCoefficient(FiniteElementSpace *f)
: fes(f), Q(NULL), ir(NULL)
{
ComputeInverseEstimates();
}
ElasticInverseEstimateCoefficient
::ElasticInverseEstimateCoefficient(FiniteElementSpace *f,
Coefficient &q)
: fes(f), Q(&q), ir(NULL)
{
ComputeInverseEstimates();
}
GridFunction *ElasticInverseEstimateCoefficient::GetGridFunction()
{
FiniteElementCollection* fec_ec = new L2_FECollection(0,
fes ->GetMesh()->Dimension());
FiniteElementSpace *fes_ec = new FiniteElementSpace(fes ->GetMesh(), fec_ec);
GridFunction *gf = new GridFunction(fes_ec, elemInvEst.GetData());
gf->MakeOwner(fec_ec);
return gf;
}
void ElasticInverseEstimateCoefficient::ComputeInverseEstimates()
{
elemInvEst.SetSize(fes -> GetNE());
SetIntRule(*fes->GetFE(0));
int dim = fes->GetFE(0)->GetDim();
emat.SetSize(dim,dim);
divmat.SetSize(dim,dim);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
emat(i,j)= new DenseMatrix();
divmat(i,j)= new DenseMatrix();
}
}
hmap.SetSize(dim,dim);
if (dim == 2)
{
hmap(0,0) = 0;
hmap(0,1) = hmap(1,0) = 1;
hmap(1,1) = 2;
}
else if (dim == 2)
{
hmap(0,0) = 0;
hmap(0,1) = hmap(1,0) = 1;
hmap(0,2) = hmap(2,0) = 2;
hmap(1,1) = 3;
hmap(1,2) = hmap(2,1) = 4;
hmap(2,2) = 5;
}
else
{
mfem_error("Only implemented for 2D and 3D");
}
for (int i = 0; i < fes -> GetNE(); i++)
{
elemInvEst[i] = ElementInverseEstimate(*fes->GetFE(i),
*fes->GetElementTransformation(i));
}
}
void ElasticInverseEstimateCoefficient::SetIntRule(const FiniteElement &el)
{
ir = &IntRules.Get(el.GetGeomType(), 2*el.GetOrder());
}
real_t ElasticInverseEstimateCoefficient::ElementInverseEstimate(
const FiniteElement &el,
ElementTransformation &Trans)
{
// if (el.GetDerivType() != (int) FiniteElement::HESS)
// {
// return std::numeric_limits<real_t>::min();
// }
int nd = el.GetDof();
int dim = el.GetDim();
shape.SetSize(nd);
dshape.SetSize(nd,dim);
hshape.SetSize(nd,dim*(dim+1)/2);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
emat(i,j)->SetSize(nd,nd);
*emat(i,j) = 0.0;
divmat(i,j)->SetSize(nd,nd);
*divmat(i,j) = 0.0;
}
}
real_t w,q = 1.0;
for (int ii = 0; ii < ir->GetNPoints(); ii++)
{
const IntegrationPoint &ip = ir->IntPoint(ii);
Trans.SetIntPoint(&ip);
w = Trans.Weight()*ip.weight;
if (Q)
{
q = Q->Eval(Trans, ip);
}
el.CalcPhysDShape(Trans, dshape);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
AddMult_a_VVt(w*q, Vector(dshape.GetColumn(i),nd), *emat(j,j));
AddMult_a_VWt(w*q, Vector(dshape.GetColumn(i),nd),
Vector(dshape.GetColumn(j),nd), *emat(j,i));
AddMult_a_VWt(w*q, Vector(dshape.GetColumn(j),nd),
Vector(dshape.GetColumn(i),nd), *emat(i,j));
AddMult_a_VVt(w*q, Vector(dshape.GetColumn(j),nd), *emat(i,i));
}
}
el.CalcPhysHessian(Trans, hshape);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
for (int k = 0; k < dim; k++)
{
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,i)),nd),
Vector(hshape.GetColumn(hmap(k,k)),nd), *divmat(j,j));
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,i)),nd),
Vector(hshape.GetColumn(hmap(k,j)),nd), *divmat(j,k));
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,j)),nd),
Vector(hshape.GetColumn(hmap(k,k)),nd), *divmat(i,j));
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,j)),nd),
Vector(hshape.GetColumn(hmap(k,j)),nd), *divmat(i,k));
}
}
}
}
// Collect matrices
emat_tot.SetSize(nd*dim,nd*dim);
divmat_tot.SetSize(nd*dim,nd*dim);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
emat_tot .SetSubMatrix(i*nd, j*nd, *emat(i,j));
divmat_tot.SetSubMatrix(i*nd, j*nd, *divmat(i,j));
}
}
// Correct nullspace
DenseMatrix ns;
emat_tot.NullSpace(ns, 1e-10);
for (int i = 0; i < ns.Width(); i++)
{
AddMultVVt(Vector(ns.GetColumn(i),nd*dim), emat_tot);
}
// Return largest eigenvalue
return divmat_tot.Eigenvalue(emat_tot);
}
ElasticInverseEstimateCoefficient::~ElasticInverseEstimateCoefficient()
{
for (int i = 0; i < emat.NumRows(); i++)
{
for (int j = 0; j < emat.NumCols(); j++)
{
delete emat(i,j);
}
}
for (int i = 0; i < divmat.NumRows(); i++)
{
for (int j = 0; j < divmat.NumCols(); j++)
{
delete divmat(i,j);
}
}
}
real_t LpNormLoop(real_t p, Coefficient &coeff, Mesh &mesh,
const IntegrationRule *irs[])
{
+221 -6
View File
@@ -1334,6 +1334,46 @@ public:
virtual ~MatrixArrayCoefficient();
};
/** @brief Matrix coefficient defined row-wise by an array of vector
coefficients. Rows that are not set will evaluate to zero. The
matrix coefficient is stored as an array indexing the rows of
the matrix. */
class MatrixArrayVectorCoefficient : public MatrixCoefficient
{
private:
Array<VectorCoefficient *> Coeff;
Array<bool> ownCoeff;
public:
/** @brief Construct a coefficient matrix of dimensions @a dim * @a dim. The
actual coefficients still need to be added with Set(). */
explicit MatrixArrayVectorCoefficient (int dim);
/// Set the time for internally stored coefficients
void SetTime(real_t t) override;
/// Get the vector coefficient located at the i-th row of the matrix
VectorCoefficient* GetCoeff (int i) { return Coeff[i]; }
/** @brief Set the coefficient located at the i-th row of the matrix.
By this will take ownership of the Coefficient passed in, but this
can be overridden with the @a own parameter. */
void Set(int i, VectorCoefficient * c, bool own=true);
using MatrixCoefficient::Eval;
/// Evaluate coefficient located at the i-th row of the matrix using integration
/// point @a ip.
void Eval(int i, Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
/// Evaluate the matrix coefficient @a ip.
void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip) override;
virtual ~MatrixArrayVectorCoefficient();
};
/** @brief Derived matrix coefficient that has the value of the parent matrix
coefficient where it is active and is zero otherwise. */
@@ -1426,12 +1466,13 @@ public:
class SymmetricMatrixCoefficient : public MatrixCoefficient
{
protected:
/// Internal matrix used when evaluating this coefficient as a DenseMatrix.
DenseSymmetricMatrix mat;
mutable DenseSymmetricMatrix mat_aux;
public:
/// Construct a dim x dim matrix coefficient.
explicit SymmetricMatrixCoefficient(int dimension)
: MatrixCoefficient(dimension, true) { }
: MatrixCoefficient(dimension, true), mat_aux(height) { }
/// Get the size of the matrix.
int GetSize() const { return height; }
@@ -1464,8 +1505,9 @@ public:
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
/// Return a reference to the constant matrix.
const DenseSymmetricMatrix& GetMatrix() { return mat; }
/// @deprecated Return a reference to the internal matrix used when evaluating this coefficient as a DenseMatrix.
MFEM_DEPRECATED const DenseSymmetricMatrix& GetMatrix() { return mat_aux; }
virtual ~SymmetricMatrixCoefficient() { }
};
@@ -1485,6 +1527,10 @@ public:
/// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseSymmetricMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip) { M = mat; }
/// Return a reference to the constant matrix.
const DenseSymmetricMatrix& GetMatrix() { return mat; }
};
@@ -1761,6 +1807,31 @@ public:
const IntegrationPoint &ip);
};
/// Scalar coefficient defined as the trace of a matrix coefficient
class TraceCoefficient : public Coefficient
{
private:
MatrixCoefficient * a;
mutable DenseMatrix ma;
public:
/// Construct with the matrix.
TraceCoefficient(MatrixCoefficient &A);
/// Set the time for internally stored coefficients
void SetTime(real_t t);
/// Reset the matrix coefficient
void SetACoef(MatrixCoefficient &A) { a = &A; }
/// Return the matrix coefficient
MatrixCoefficient * GetACoef() const { return a; }
/// Evaluate the trace coefficient at @a ip.
virtual real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
/// Vector coefficient defined as the linear combination of two vectors
class VectorSumCoefficient : public VectorCoefficient
{
@@ -2112,7 +2183,7 @@ public:
const IntegrationPoint &ip);
};
/// Matrix coefficient defined as the transpose a matrix coefficient
/// Matrix coefficient defined as the transpose of a matrix coefficient
class TransposeMatrixCoefficient : public MatrixCoefficient
{
private:
@@ -2135,7 +2206,7 @@ public:
const IntegrationPoint &ip);
};
/// Matrix coefficient defined as the inverse a matrix coefficient.
/// Matrix coefficient defined as the inverse of a matrix coefficient.
class InverseMatrixCoefficient : public MatrixCoefficient
{
private:
@@ -2158,6 +2229,29 @@ public:
const IntegrationPoint &ip);
};
/// Matrix coefficient defined as the exponential of a matrix coefficient.
class ExponentialMatrixCoefficient : public MatrixCoefficient
{
private:
MatrixCoefficient * a;
public:
/// Construct the matrix coefficient. Result is $ \exp(A) $.
ExponentialMatrixCoefficient(MatrixCoefficient &A);
/// Set the time for internally stored coefficients
void SetTime(real_t t);
/// Reset the matrix coefficient
void SetACoef(MatrixCoefficient &A) { a = &A; }
/// Return the matrix coefficient
MatrixCoefficient * GetACoef() const { return a; }
/// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip);
};
/// Matrix coefficient defined as the outer product of two vector coefficients.
class OuterProductCoefficient : public MatrixCoefficient
{
@@ -2234,6 +2328,127 @@ public:
};
///@}
/** @brief
*/
class InverseEstimateCoefficient : public Coefficient
{
private:
///
Vector elemInvEst;
/// FE space on which the grid function lives. Owned if #fec is not NULL.
FiniteElementSpace *fes;
///
const IntegrationRule *ir;
///
Coefficient *Q;
Vector laplace, shape, ovec, evec;
DenseMatrix dshape, lapmat, bimat;
///
void SetIntRule(const FiniteElement &el);
///
void ComputeInverseEstimates();
real_t ElementInverseEstimate(const FiniteElement &el,
ElementTransformation &Trans);
public:
///
InverseEstimateCoefficient(FiniteElementSpace *f);
InverseEstimateCoefficient(FiniteElementSpace *f, Coefficient &q);
/// Caller gets owner ship of GridFunction and
GridFunction *GetGridFunction();
/// Reset the scalar factor
void SetDiffusion(Coefficient &q)
{
if (Q != &q)
{
Q = &q;
ComputeInverseEstimates();
}
}
/// Return the scalar factor
Coefficient * GetDiffusion() const { return Q; }
/// Evaluate the coefficient at @a ip.
virtual real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{ return elemInvEst[T.ElementNo]; }
};
class ElasticInverseEstimateCoefficient : public Coefficient
{
private:
///
Vector elemInvEst;
/// FE space on which the grid function lives. Owned if #fec is not NULL.
FiniteElementSpace *fes;
///
const IntegrationRule *ir;
///
Coefficient *Q;
Vector shape, ovec, evec;
DenseMatrix dshape, hshape, emat_tot, divmat_tot;
Array2D<DenseMatrix*> emat,divmat;
Array2D<int> hmap;
///
void SetIntRule(const FiniteElement &el);
///
void ComputeInverseEstimates();
///
real_t ElementInverseEstimate(const FiniteElement &el,
ElementTransformation &Trans);
public:
///
ElasticInverseEstimateCoefficient(FiniteElementSpace *f);
ElasticInverseEstimateCoefficient(FiniteElementSpace *f, Coefficient &q);
/// Caller gets owner ship of GridFunction and
GridFunction *GetGridFunction();
/// Reset the scalar factor
void SetDiffusion(Coefficient &q)
{
if (Q != &q)
{
Q = &q;
ComputeInverseEstimates();
}
}
void SetShearModulus(Coefficient &q) { SetDiffusion(q);}
/// Return the scalar factor
Coefficient * GetDiffusion() const { return Q; }
Coefficient * GetModulus() const { return GetDiffusion(); }
/// Evaluate the coefficient at @a ip.
virtual real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{ return elemInvEst[T.ElementNo]; }
// Destructor
~ElasticInverseEstimateCoefficient();
};
///@}
/** @brief Vector quadrature function coefficient which requires that the
quadrature rules used for this vector coefficient be the same as those that
live within the supplied QuadratureFunction. */
+17 -2
View File
@@ -52,6 +52,15 @@ protected:
const DenseMatrix &EvalTransAdjugateJ();
const DenseMatrix &EvalInverseJ();
/// @name Tolerance used for point comparisons
///@{
#ifdef MFEM_USE_DOUBLE
static constexpr real_t tol_0 = 1e-15;
#elif defined(MFEM_USE_SINGLE)
static constexpr real_t tol_0 = 1e-7;
#endif
///@}
public:
/** This enumeration declares the values stored in
@@ -176,7 +185,7 @@ public:
returned. This method is not 100 percent reliable for non-linear
transformations. */
virtual int TransformBack(const Vector &pt, IntegrationPoint &ip,
const real_t phys_tol = 1e-15) = 0;
const real_t phys_tol = tol_0) = 0;
virtual ~ElementTransformation() { }
};
@@ -281,9 +290,15 @@ public:
rel_qpts_order(-1),
solver_type(NewtonElementProject),
max_iter(16),
#ifdef MFEM_USE_DOUBLE
ref_tol(1e-15),
phys_rtol(1e-15),
ip_tol(1e-8),
#elif defined(MFEM_USE_SINGLE)
ref_tol(1e-7),
phys_rtol(1e-7),
ip_tol(1e-4),
#endif
print_level(-1)
{ }
@@ -449,7 +464,7 @@ public:
returned. This method is not 100 percent reliable for non-linear
transformations. */
virtual int TransformBack(const Vector & v, IntegrationPoint & ip,
const real_t phys_rel_tol = 1e-15)
const real_t phys_rel_tol = tol_0)
{
InverseElementTransformation inv_tr(this);
inv_tr.SetPhysicalRelTol(phys_rel_tol);
+8 -8
View File
@@ -221,7 +221,7 @@ void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans,
{
for (int nd = 0; nd < dof; nd++)
{
Laplacian[nd] = hess(nd,0) + hess(nd,4) + hess(nd,5);
Laplacian[nd] = hess(nd,0) + hess(nd,3) + hess(nd,5);
}
}
else if (dim == 2)
@@ -259,10 +259,10 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
scale[1] = 2*Gij(0,1);
scale[2] = 2*Gij(0,2);
scale[3] = 2*Gij(1,2);
scale[4] = Gij(2,2);
scale[3] = Gij(1,1);
scale[4] = 2*Gij(1,2);
scale[5] = Gij(1,1);
scale[5] = Gij(2,2);
}
else if (dim == 2)
{
@@ -299,12 +299,12 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
map[2] = 2;
map[3] = 1;
map[4] = 5;
map[5] = 3;
map[4] = 3;
map[5] = 4;
map[6] = 2;
map[7] = 3;
map[8] = 4;
map[7] = 4;
map[8] = 5;
}
else if (dim == 2)
{
+29 -27
View File
@@ -299,7 +299,8 @@ public:
NONE, ///< No derivatives implemented
GRAD, ///< Implements CalcDShape methods
DIV, ///< Implements CalcDivShape methods
CURL ///< Implements CalcCurlShape methods
CURL, ///< Implements CalcCurlShape methods
HESS ///< Implements CalcHessian & CalcDShape methods
};
/** @brief Construct FiniteElement with given
@@ -356,7 +357,7 @@ public:
/** @brief Returns the FiniteElement::DerivType of the element describing the
spatial derivative method implemented, one of {NONE, GRAD,
DIV, CURL}. */
DIV, CURL, HESS}. */
int GetDerivType() const { return deriv_type; }
/** @brief Returns the FiniteElement::DerivType of the element describing how
@@ -394,7 +395,32 @@ public:
/// Get a const reference to the nodes of the element
const IntegrationRule & GetNodes() const { return Nodes; }
// virtual functions for finite elements on vector spaces
/** @brief Evaluate the Hessians of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
part of the Hessian of one shape function.
The order in 2D is {u_xx, u_xy, u_yy}.
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
element in physical space at the given point @a ip. */
/** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
void CalcPhysHessian(ElementTransformation &Trans,
DenseMatrix& Hessian) const;
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
element in physical space at the given point @a ip. */
/** The size (#dof) of @a Laplacian must be set in advance. */
void CalcPhysLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
element in physical space at the given point @a ip. */
/** The size (#dof) of @a Laplacian must be set in advance. */
void CalcPhysLinLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in reference space at the given point @a ip. */
@@ -454,30 +480,6 @@ public:
*/
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
/** @brief Evaluate the Hessians of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
part of the Hessian of one shape function.
The order in 2D is {u_xx, u_xy, u_yy}.
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
virtual void CalcPhysHessian(ElementTransformation &Trans,
DenseMatrix& Hessian) const;
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** The size (#dof) of @a Laplacian must be set in advance. */
virtual void CalcPhysLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
virtual void CalcPhysLinLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
/** @brief Return the local interpolation matrix @a I (Dof x Dof) where the
fine element is the image of the base geometry under the given
transformation. */
+624 -11
View File
@@ -349,10 +349,10 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip,
d2sum[1] += ( hessian(o,1) = dsx*dsy*sz*weights(o) );
d2sum[2] += ( hessian(o,2) = dsx*sy*dsz*weights(o) );
d2sum[3] += ( hessian(o,3) = sx*dsy*dsz*weights(o) );
d2sum[3] += ( hessian(o,3) = sx*d2sy*sz*weights(o) );
d2sum[4] += ( hessian(o,4) = sx*dsy*dsz*weights(o) );
d2sum[4] += ( hessian(o,4) = sx*sy*d2sz*weights(o) );
d2sum[5] += ( hessian(o,5) = sx*d2sy*sz*weights(o) );
d2sum[5] += ( hessian(o,5) = sx*sy*d2sz*weights(o) );
}
}
}
@@ -387,19 +387,632 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip,
+ u[o]*sum*(2*dsum[0]*dsum[2] - d2sum[2]);
hessian(o,3) = hessian(o,3)*sum
- du(o,1)*sum*dsum[2]
- du(o,2)*sum*dsum[1]
+ u[o]*sum*(2*dsum[1]*dsum[2] - d2sum[3]);
- 2*du(o,1)*sum*dsum[1]
+ u[o]*sum*(2*dsum[1]*dsum[1] - d2sum[3]);
hessian(o,4) = hessian(o,4)*sum
- 2*du(o,2)*sum*dsum[2]
+ u[o]*sum*(2*dsum[2]*dsum[2] - d2sum[4]);
- du(o,1)*sum*dsum[2]
- du(o,2)*sum*dsum[1]
+ u[o]*sum*(2*dsum[1]*dsum[2] - d2sum[4]);
hessian(o,5) = hessian(o,5)*sum
- 2*du(o,1)*sum*dsum[1]
+ u[o]*sum*(2*dsum[1]*dsum[1] - d2sum[5]);
- 2*du(o,2)*sum*dsum[2]
+ u[o]*sum*(2*dsum[2]*dsum[2] - d2sum[5]);
}
}
void NURBS_HDiv2DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
order = max(orders[0]+1, orders[1]+1);
dof = (orders[0] + 2)*(orders[1] + 1)
+ (orders[1] + 1)*(orders[1] + 2);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HDiv2DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,0) = shape1_x(i)*sy;
shape(o,1) = 0.0;
}
}
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1 = shape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,0) = 0.0;
shape(o,1) = shape_x(i)*sy1;
}
}
}
void NURBS_HDiv2DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & J = Trans.Jacobian();
MFEM_ASSERT(J.Width() == 2 && J.Height() == 2,
"NURBS_HDiv2DFiniteElement cannot be embedded in "
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
shape(i, 0) = sx * J(0, 0) + sy * J(0, 1);
shape(i, 1) = sx * J(1, 0) + sy * J(1, 1);
}
shape *= (1.0 / Trans.Weight());
}
void NURBS_HDiv2DFiniteElement::CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
divshape(o) = dshape1_x(i)*sy;
}
}
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t dsy1 = dshape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
divshape(o) = shape_x(i)*dsy1;
}
}
}
NURBS_HDiv2DFiniteElement::~NURBS_HDiv2DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
}
void NURBS_HDiv3DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
orders[2] = kv[2]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
kv1[2] = kv[2]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
shape_z.SetSize(orders[2]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
dshape_z.SetSize(orders[2]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
d2shape_z.SetSize(orders[2]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
shape1_z.SetSize(orders[2]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
dshape1_z.SetSize(orders[2]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
d2shape1_z.SetSize(orders[2]+2);
order = max(orders[0]+1, max( orders[1]+1, orders[2]+1));
dof = (orders[0] + 2)*(orders[1] + 1)*(orders[2] + 1) +
(orders[0] + 1)*(orders[1] + 2)*(orders[2] + 1) +
(orders[0] + 1)*(orders[1] + 1)*(orders[2] + 2);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HDiv3DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv[2]->CalcShape(shape_z, ijk[2], ip.z);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
shape = 0.0;
int o = 0;
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz = shape_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,0) = shape1_x(i)*sy_sz;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz = shape1_y(j)*sz;
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,1) = shape_x(i)*sy1_sz;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz1 = shape_y(j)*sz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,2) = shape_x(i)*sy_sz1;
}
}
}
}
void NURBS_HDiv3DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & J = Trans.Jacobian();
MFEM_ASSERT(J.Width() == 3 && J.Height() == 3,
"RT_R2D_FiniteElement cannot be embedded in "
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
real_t sz = shape(i, 2);
shape(i, 0) = sx * J(0, 0) + sy * J(0, 1) + sz * J(0, 2);
shape(i, 1) = sx * J(1, 0) + sy * J(1, 1) + sz * J(1, 2);
shape(i, 2) = sx * J(2, 0) + sy * J(2, 1) + sz * J(2, 2);
}
shape *= (1.0 / Trans.Weight());
}
void NURBS_HDiv3DFiniteElement::CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv[2]->CalcShape ( shape_z, ijk[2], ip.z);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
kv1[2]->CalcDShape(dshape1_z, ijk[2], ip.z);
int o = 0;
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz = shape_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
divshape(o) = dshape1_x(i)*sy_sz;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t dy1_sz = dshape1_y(j)*sz;
for (int i = 0; i <= orders[0]; i++, o++)
{
divshape(o) = shape_x(i)*dy1_sz;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t dz1 = dshape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_dz1 = shape_y(j)*dz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
divshape(o) = shape_x(i)*sy_dz1;
}
}
}
}
NURBS_HDiv3DFiniteElement::~NURBS_HDiv3DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
}
void NURBS_HCurl2DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
order = max(orders[0]+1, orders[1]+1);
dof = (orders[0] + 1)*(orders[1] + 2)
+ (orders[1] + 2)*(orders[1] + 1);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HCurl2DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1 = shape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,0) = shape_x(i)*sy1;
shape(o,1) = 0.0;
}
}
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,0) = 0.0;
shape(o,1) = shape1_x(i)*sy;
}
}
}
void NURBS_HCurl2DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & JI = Trans.InverseJacobian();
MFEM_ASSERT(JI.Width() == 2 && JI.Height() == 2,
"NURBS_HCurl2DFiniteElement cannot be embedded in "
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
shape(i, 0) = sx * JI(0, 0) + sy * JI(1, 0);
shape(i, 1) = sx * JI(0, 1) + sy * JI(1, 1);
}
}
void NURBS_HCurl2DFiniteElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t dsy1 = dshape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
curl_shape(o,0) = -shape_x(i)*dsy1;
}
}
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
curl_shape(o,0) = dshape1_x(i)*sy;
}
}
}
NURBS_HCurl2DFiniteElement::~NURBS_HCurl2DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
}
void NURBS_HCurl3DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
orders[2] = kv[2]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
kv1[2] = kv[2]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
shape_z.SetSize(orders[2]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
dshape_z.SetSize(orders[2]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
d2shape_z.SetSize(orders[2]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
shape1_z.SetSize(orders[2]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
dshape1_z.SetSize(orders[2]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
d2shape1_z.SetSize(orders[2]+2);
order = max(orders[0]+1, max( orders[1]+1, orders[2]+1));
dof = (orders[0] + 1)*(orders[1] + 2)*(orders[2] + 2) +
(orders[0] + 2)*(orders[1] + 1)*(orders[2] + 2) +
(orders[0] + 2)*(orders[1] + 2)*(orders[2] + 1);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HCurl3DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv[2]->CalcShape(shape_z, ijk[2], ip.z);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
shape = 0.0;
int o = 0;
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz1 = shape1_y(j)*sz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,0) = shape_x(i)*sy1_sz1;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz1 = shape_y(j)*sz1;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,1) = shape1_x(i)*sy_sz1;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz = shape1_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,2) = shape1_x(i)*sy1_sz;
}
}
}
}
void NURBS_HCurl3DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & JI = Trans.InverseJacobian();
MFEM_ASSERT(JI.Width() == 3 && JI.Height() == 3,
"NURBS_HCurl3DFiniteElement must be in a"
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
real_t sz = shape(i, 2);
shape(i, 0) = sx * JI(0, 0) + sy * JI(1, 0) + sz * JI(2, 0);
shape(i, 1) = sx * JI(0, 1) + sy * JI(1, 1) + sz * JI(2, 1);
shape(i, 2) = sx * JI(0, 2) + sy * JI(1, 2) + sz * JI(2, 2);
}
}
void NURBS_HCurl3DFiniteElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv[2]->CalcShape ( shape_z, ijk[2], ip.z);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
kv1[2]->CalcDShape(dshape1_z, ijk[2], ip.z);
int o = 0;
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k), dsz1 = dshape1_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_dsz1 = shape1_y(j)*dsz1,
dsy1_sz1 = dshape1_y(j)*sz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
curl_shape(o,0) = 0.0;
curl_shape(o,1) = shape_x(i)*sy1_dsz1;
curl_shape(o,2) = -shape_x(i)*dsy1_sz1;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k), dsz1 = dshape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_dsz1 = shape_y(j)*dsz1,
sy_sz1 = shape_y(j)*sz1;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
curl_shape(o,0) = -shape1_x(i)*sy_dsz1;
curl_shape(o,1) = 0.0;
curl_shape(o,2) = dshape1_x(i)*sy_sz1;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz = shape1_y(j)*sz,
dsy1_sz = dshape1_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
curl_shape(o,0) = shape1_x(i)*dsy1_sz;
curl_shape(o,1) = -dshape1_x(i)*sy1_sz;
curl_shape(o,2) = 0.0;
}
}
}
}
NURBS_HCurl3DFiniteElement::~NURBS_HCurl3DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
}
}
+380 -23
View File
@@ -20,7 +20,7 @@ namespace mfem
class KnotVector;
/// An arbitrary order and dimension NURBS element
class NURBSFiniteElement : public ScalarFiniteElement
class NURBSFiniteElement
{
protected:
mutable Array <const KnotVector*> kv;
@@ -30,31 +30,34 @@ protected:
public:
/** @brief Construct NURBSFiniteElement with given
@param D Reference space dimension
@param G Geometry type (of type Geometry::Type)
@param Do Number of degrees of freedom in the FiniteElement
@param O Order/degree of the FiniteElement
@param F FunctionSpace type of the FiniteElement
@param dim Reference space dimension
*/
NURBSFiniteElement(int D, Geometry::Type G, int Do, int O, int F)
: ScalarFiniteElement(D, G, Do, O, F)
NURBSFiniteElement(int dim)
{
ijk = NULL;
patch = elem = -1;
kv.SetSize(dim);
weights.SetSize(dof);
weights = 1.0;
}
/// Resets the patch and element data stored in the element
void Reset () const { patch = elem = -1; }
/// Set which IJK in patch should be evaluated
void SetIJK (const int *IJK) const { ijk = IJK; }
/// Get which patch is currently considered
int GetPatch () const { return patch; }
/// Set which patch should be evaluated
void SetPatch (int p) const { patch = p; }
/// Set which elemenet should be evaluated
int GetElement () const { return elem; }
/// Get which element is currently considered
void SetElement (int e) const { elem = e; }
/// Get the KnotVectors
Array <const KnotVector*> &KnotVectors() const { return kv; }
/// Get the Weights
Vector &Weights () const { return weights; }
/// Update the NURBSFiniteElement according to the currently set knot vectors
/// Update the polynomial order according to the currently set knotvectors
/// Resizes all internal data members to have the correct size
/// related to the polynomial order
virtual void SetOrder () const { }
/// Returns the indices (i,j) in 2D or (i,j,k) in 3D of this element in the
@@ -64,7 +67,8 @@ public:
/// An arbitrary order 1D NURBS element on a segment
class NURBS1DFiniteElement : public NURBSFiniteElement
class NURBS1DFiniteElement : public ScalarFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x;
@@ -72,7 +76,8 @@ protected:
public:
/// Construct the NURBS1DFiniteElement of order @a p
NURBS1DFiniteElement(int p)
: NURBSFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk),
: ScalarFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk),
NURBSFiniteElement(1),
shape_x(p + 1) { }
virtual void SetOrder() const;
@@ -84,7 +89,8 @@ public:
};
/// An arbitrary order 2D NURBS element on a square
class NURBS2DFiniteElement : public NURBSFiniteElement
class NURBS2DFiniteElement : public ScalarFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector u, shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
@@ -93,16 +99,18 @@ protected:
public:
/// Construct the NURBS2DFiniteElement of order @a p
NURBS2DFiniteElement(int p)
: NURBSFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p,
FunctionSpace::Qk),
: ScalarFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p,
FunctionSpace::Qk),
NURBSFiniteElement(2),
u(dof), shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1), du(dof,2)
{ orders[0] = orders[1] = p; }
/// Construct the NURBS2DFiniteElement with x-order @a px and y-order @a py
NURBS2DFiniteElement(int px, int py)
: NURBSFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1),
std::max(px, py), FunctionSpace::Qk),
: ScalarFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1),
std::max(px, py), FunctionSpace::Qk),
NURBSFiniteElement(2),
u(dof), shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1), du(dof,2)
{ orders[0] = px; orders[1] = py; }
@@ -116,7 +124,8 @@ public:
};
/// An arbitrary order 3D NURBS element on a cube
class NURBS3DFiniteElement : public NURBSFiniteElement
class NURBS3DFiniteElement : public ScalarFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector u, shape_x, shape_y, shape_z;
@@ -127,8 +136,9 @@ protected:
public:
/// Construct the NURBS3DFiniteElement of order @a p
NURBS3DFiniteElement(int p)
: NURBSFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p,
FunctionSpace::Qk),
: ScalarFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p,
FunctionSpace::Qk),
NURBSFiniteElement(3),
u(dof), shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1), du(dof,3)
@@ -137,8 +147,9 @@ public:
/// Construct the NURBS3DFiniteElement with x-order @a px and y-order @a py
/// and z-order @a pz
NURBS3DFiniteElement(int px, int py, int pz)
: NURBSFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1),
std::max(std::max(px,py),pz), FunctionSpace::Qk),
: ScalarFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1),
std::max(std::max(px,py),pz), FunctionSpace::Qk),
NURBSFiniteElement(2),
u(dof), shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1), du(dof,3)
@@ -152,6 +163,352 @@ public:
DenseMatrix &hessian) const;
};
/** An arbitrary order H(div)-conforming 2D NURBS element on a square.
More details in the following papers:
[1] Annalisa Buffa, Carlo De Falco, Giancarlo Sangalli
"Isogeometric analysis: stable elements for the 2D Stokes equation."
International Journal for Numerical Methods in Fluids 65 (1112) 1407-1422
[2] John A Evans, Thomas JR Hughes
"Isogeometric divergence-conforming B-splines for the unsteady NavierStokes equations."
Journal of Computational Physics (241) 141-167
*/
class NURBS_HDiv2DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
mutable Vector shape1_x, shape1_y, dshape1_x, dshape1_y, d2shape1_x, d2shape1_y;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HDiv2DFiniteElement of order @a p
NURBS_HDiv2DFiniteElement(int p)
: VectorFiniteElement(2, Geometry::SQUARE, 2*(p + 1)*(p + 2), p,
H_DIV,FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1),
shape1_x(p + 2), shape1_y(p + 2), dshape1_x(p + 2),
dshape1_y(p + 2), d2shape1_x(p + 2), d2shape1_y(p + 2),
u(dof), du(dof,2)
{
orders[0] = orders[1] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
/// Construct the NURBS_HDiv2DFiniteElement with x-order @a px and y-order @a py
NURBS_HDiv2DFiniteElement(int px, int py)
: VectorFiniteElement(2, Geometry::SQUARE,
(px + 2)*(py + 1)+(px + 1)*(py + 2),
std::max(px, py), H_DIV, FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1),
shape1_x(px + 2), shape1_y(py + 2), dshape1_x(px + 2),
dshape1_y(py + 2), d2shape1_x(px + 2), d2shape1_y(py + 2),
u(dof), du(dof,2)
{
orders[0] = px; orders[1] = py;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the divergence of all shape functions of a *vector*
finite element in reference space at the given point @a ip. */
/** The size (#dof) of the result Vector @a divshape must be set in advance.
*/
virtual void CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const;
~NURBS_HDiv2DFiniteElement();
};
/** An arbitrary order H(div)-conforming 3D NURBS element on a cube
More details in the following papers:
[1] Annalisa Buffa, Carlo De Falco, Giancarlo Sangalli
"Isogeometric analysis: stable elements for the 2D Stokes equation."
International Journal for Numerical Methods in Fluids 65 (1112) 1407-1422
[2] John A Evans, Thomas JR Hughes
"Isogeometric divergence-conforming B-splines for the unsteady
NavierStokes equations."
Journal of Computational Physics (241) 141-167 */
class NURBS_HDiv3DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, shape_z;
mutable Vector dshape_x, dshape_y, dshape_z;
mutable Vector d2shape_x, d2shape_y, d2shape_z;
mutable Vector shape1_x, shape1_y, shape1_z;
mutable Vector dshape1_x, dshape1_y, dshape1_z;
mutable Vector d2shape1_x, d2shape1_y, d2shape1_z;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HDiv3DFiniteElement of order @a p
NURBS_HDiv3DFiniteElement(int p)
: VectorFiniteElement(3, Geometry::CUBE, 3*(p + 1)*(p + 1)*(p + 2),
p, H_DIV,FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1),
shape1_x(p + 2), shape1_y(p + 2), shape1_z(p + 2),
dshape1_x(p + 2), dshape1_y(p + 2),dshape1_z(p + 2),
d2shape1_x(p + 2), d2shape1_y(p + 2), d2shape1_z(p + 2),
u(dof), du(dof,3)
{
orders[0] = orders[1] = orders[2] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
/// Construct the NURBS_HDiv3DFiniteElement with x-order @a px, y-order @a py and z-order @a pz
NURBS_HDiv3DFiniteElement(int px, int py, int pz)
: VectorFiniteElement(3, Geometry::CUBE,
(px + 2)*(py + 1)*(pz + 1) +
(px + 1)*(py + 2)*(pz + 1) +
(px + 1)*(py + 1)*(pz + 2),
std::max(px, py), H_DIV, FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1),
shape1_x(px + 2), shape1_y(py + 2), shape1_z(pz + 2),
dshape1_x(px + 2), dshape1_y(py + 2),dshape1_z(pz + 2),
d2shape1_x(px + 2), d2shape1_y(py + 2), d2shape1_z(pz + 2),
u(dof), du(dof,3)
{
orders[0] = px; orders[1] = py; orders[2] = pz;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the divergence of all shape functions of a *vector*
finite element in reference space at the given point @a ip. */
/** The size (#dof) of the result Vector @a divshape must be set in advance.
*/
virtual void CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const;
~NURBS_HDiv3DFiniteElement();
};
/** An arbitrary order H(curl)-conforming 2D NURBS element on a square
More details in the following paper:
[1] Annalisa Buffa, Giancarlo Sangalli, Rafael Vázquez
"Isogeometric analysis in electromagnetics: B-splines approximation."
Computer Methods in Applied Mechanics and Engineering (199) 1143-1152 */
class NURBS_HCurl2DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
mutable Vector shape1_x, shape1_y, dshape1_x, dshape1_y, d2shape1_x, d2shape1_y;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HCurl2DFiniteElement of order @a p
NURBS_HCurl2DFiniteElement(int p)
: VectorFiniteElement(2, Geometry::SQUARE, 2*(p + 1)*(p + 2), p,
H_CURL,FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1),
shape1_x(p + 2), shape1_y(p + 2), dshape1_x(p + 2),
dshape1_y(p + 2), d2shape1_x(p + 2), d2shape1_y(p + 2),
u(dof), du(dof,2)
{
orders[0] = orders[1] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
/// Construct the NURBS_HCurl2DFiniteElement with x-order @a px and y-order @a py
NURBS_HCurl2DFiniteElement(int px, int py)
: VectorFiniteElement(2, Geometry::SQUARE,
(px + 1)*(py + 2)+(px + 2)*(py + 1),
std::max(px, py), H_CURL, FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1),
shape1_x(px + 2), shape1_y(py + 2), dshape1_x(px + 2),
dshape1_y(py + 2), d2shape1_x(px + 2), d2shape1_y(py + 2),
u(dof), du(dof,2)
{
orders[0] = px; orders[1] = py;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the curl of all shape functions of a *vector* finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a curl_shape contains the components
of the curl of one vector shape function. The size (#dof x CDim) of
@a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
CDim = 1 for #dim = 2. */
virtual void CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const;
~NURBS_HCurl2DFiniteElement();
};
/** An arbitrary order H(curl)-conforming 3D NURBS element on a cube
More details in the following paper:
[1] Annalisa Buffa, Giancarlo Sangalli, Rafael Vázquez
"Isogeometric analysis in electromagnetics: B-splines approximation."
Computer Methods in Applied Mechanics and Engineering (199) 1143-1152 */
class NURBS_HCurl3DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, shape_z;
mutable Vector dshape_x, dshape_y, dshape_z;
mutable Vector d2shape_x, d2shape_y, d2shape_z;
mutable Vector shape1_x, shape1_y, shape1_z;
mutable Vector dshape1_x, dshape1_y, dshape1_z;
mutable Vector d2shape1_x, d2shape1_y, d2shape1_z;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HCurl3DFiniteElement of order @a p
NURBS_HCurl3DFiniteElement(int p)
: VectorFiniteElement(3, Geometry::CUBE, 3*(p + 1)*(p + 2)*(p + 2), p,
H_CURL,FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1),
shape1_x(p + 2), shape1_y(p + 2), shape1_z(p + 2),
dshape1_x(p + 2), dshape1_y(p + 2),dshape1_z(p + 2),
d2shape1_x(p + 2), d2shape1_y(p + 2), d2shape1_z(p + 2),
u(dof), du(dof,3)
{
orders[0] = orders[1] = orders[2] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
/// Construct the NURBS_HCurl3DFiniteElement with x-order @a px, y-order @a py and z-order @a pz
NURBS_HCurl3DFiniteElement(int px, int py, int pz)
: VectorFiniteElement(3, Geometry::CUBE,
(px + 1)*(py + 2)*(pz + 2) +
(px + 2)*(py + 1)*(pz + 2) +
(px + 2)*(py + 2)*(pz + 1),
std::max(std::max(px, py), pz), H_CURL, FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1),
shape1_x(px + 2), shape1_y(py + 2), shape1_z(pz + 2),
dshape1_x(px + 2), dshape1_y(py + 2),dshape1_z(pz + 2),
d2shape1_x(px + 2), d2shape1_y(py + 2), d2shape1_z(pz + 2),
u(dof), du(dof,3)
{
orders[0] = px; orders[1] = py; orders[2] = pz;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the curl of all shape functions of a *vector* finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a curl_shape contains the components
of the curl of one vector shape function. The size (#dof x CDim) of
@a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
CDim = 1 for #dim = 2. */
virtual void CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const;
~NURBS_HCurl3DFiniteElement();
};
} // namespace mfem
#endif
+214
View File
@@ -344,6 +344,32 @@ FiniteElementCollection *FiniteElementCollection::New(const char *name)
{
fec = new Local_FECollection(name + 6);
}
else if (!strncmp(name, "NURBS_HDiv", 10))
{
if (name[10] != '\0')
{
// "NURBS" + "number" --> fixed order nurbs collection
fec = new NURBS_HDivFECollection(atoi(name + 10));
}
else
{
// "NURBS" --> variable order nurbs collection
fec = new NURBS_HDivFECollection();
}
}
else if (!strncmp(name, "NURBS_HCurl", 11))
{
if (name[11] != '\0')
{
// "NURBS" + "number" --> fixed order nurbs collection
fec = new NURBS_HCurlFECollection(atoi(name + 11));
}
else
{
// "NURBS" --> variable order nurbs collection
fec = new NURBS_HCurlFECollection();
}
}
else if (!strncmp(name, "NURBS", 5))
{
if (name[5] != '\0')
@@ -3533,4 +3559,192 @@ FiniteElementCollection *NURBSFECollection::GetTraceCollection() const
return NULL;
}
NURBS_HDivFECollection::NURBS_HDivFECollection(int Order, const int dim)
: NURBSFECollection((Order == VariableOrder) ? 1 : Order)
{
const int order = (Order == VariableOrder) ? 1 : Order;
SegmentFE = new NURBS1DFiniteElement(order);
QuadrilateralFE = new NURBS2DFiniteElement(order);
QuadrilateralVFE = new NURBS_HDiv2DFiniteElement(order);
ParallelepipedVFE = new NURBS_HDiv3DFiniteElement(order);
if (dim != -1) { SetDim(dim); }
SetOrder(Order);
}
void NURBS_HDivFECollection::SetDim(int dim)
{
if (dim == 2)
{
sFE = SegmentFE;
qFE = QuadrilateralVFE;
hFE = nullptr;
}
else if (dim == 3)
{
sFE = nullptr;
qFE = QuadrilateralFE;
hFE = ParallelepipedVFE;
}
else
{
mfem::err<<"Dimension = "<<dim<<endl;
mfem_error ("NURBS_HDivFECollection: wrong dimension!");
}
}
NURBS_HDivFECollection::~NURBS_HDivFECollection()
{
delete SegmentFE;
delete QuadrilateralFE;
delete QuadrilateralVFE;
delete ParallelepipedVFE;
}
const FiniteElement *
NURBS_HDivFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
switch (GeomType)
{
case Geometry::SEGMENT: return sFE;
case Geometry::SQUARE: return qFE;
case Geometry::CUBE: return hFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("NURBS_HDivFECollection: unknown geometry type.");
}
return QuadrilateralFE; // Make some compilers happy
}
void NURBS_HDivFECollection::SetOrder(int Order) const
{
mOrder = Order;
if (Order != VariableOrder)
{
snprintf(name, 16, "NURBS_HDiv%i", Order);
}
else
{
snprintf(name, 16, "NURBS_HDiv");
}
}
int NURBS_HDivFECollection::DofForGeometry(Geometry::Type GeomType) const
{
mfem_error("NURBS_HDivFECollection::DofForGeometry");
return 0; // Make some compilers happy
}
const int *NURBS_HDivFECollection::DofOrderForOrientation(
Geometry::Type GeomType,
int Or) const
{
mfem_error("NURBS_HDivFECollection::DofOrderForOrientation");
return NULL;
}
FiniteElementCollection *NURBS_HDivFECollection::GetTraceCollection() const
{
MFEM_ABORT("NURBS finite elements can not be statically condensed!");
return NULL;
}
NURBS_HCurlFECollection::NURBS_HCurlFECollection(int Order, const int dim)
: NURBSFECollection((Order == VariableOrder) ? 1 : Order)
{
const int order = (Order == VariableOrder) ? 1 : Order;
SegmentFE = new NURBS1DFiniteElement(order+1);
QuadrilateralFE = new NURBS2DFiniteElement(order+1);
QuadrilateralVFE = new NURBS_HCurl2DFiniteElement(order);
ParallelepipedVFE = new NURBS_HCurl3DFiniteElement(order);
if (dim != -1) { SetDim(dim); }
SetOrder(Order);
}
void NURBS_HCurlFECollection::SetDim(int dim)
{
if (dim == 2)
{
sFE = SegmentFE;
qFE = QuadrilateralVFE;
hFE = nullptr;
}
else if (dim == 3)
{
sFE = nullptr;
qFE = QuadrilateralFE;
hFE = ParallelepipedVFE;
}
else
{
mfem::err<<"Dimension = "<<dim<<endl;
mfem_error ("NURBS_HCurlFECollection: wrong dimension!");
}
}
NURBS_HCurlFECollection::~NURBS_HCurlFECollection()
{
delete SegmentFE;
delete QuadrilateralFE;
delete QuadrilateralVFE;
delete ParallelepipedVFE;
}
const FiniteElement *
NURBS_HCurlFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
switch (GeomType)
{
case Geometry::SEGMENT: return sFE;
case Geometry::SQUARE: return qFE;
case Geometry::CUBE: return hFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("NURBS_HCurlFECollection: unknown geometry type.");
}
return QuadrilateralFE; // Make some compilers happy
}
void NURBS_HCurlFECollection::SetOrder(int Order) const
{
mOrder = Order;
if (Order != VariableOrder)
{
snprintf(name, 16, "NURBS_HCurl%i", Order);
}
else
{
snprintf(name, 16, "NURBS_HCurl");
}
}
int NURBS_HCurlFECollection::DofForGeometry(Geometry::Type GeomType) const
{
mfem_error("NURBS_HCurlFECollection::DofForGeometry");
return 0; // Make some compilers happy
}
const int *NURBS_HCurlFECollection::DofOrderForOrientation(
Geometry::Type GeomType,
int Or) const
{
mfem_error("NURBS_HCurlFECollection::DofOrderForOrientation");
return NULL;
}
FiniteElementCollection *NURBS_HCurlFECollection::GetTraceCollection() const
{
MFEM_ABORT("NURBS finite elements can not be statically condensed!");
return NULL;
}
}
+109 -4
View File
@@ -680,8 +680,8 @@ public:
/// Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
class NURBSFECollection : public FiniteElementCollection
{
private:
PointFiniteElement *PointFE;
protected:
PointFiniteElement *PointFE;
NURBS1DFiniteElement *SegmentFE;
NURBS2DFiniteElement *QuadrilateralFE;
NURBS3DFiniteElement *ParallelepipedFE;
@@ -701,13 +701,15 @@ public:
order, or VariableOrder (default). */
explicit NURBSFECollection(int Order = VariableOrder);
void Reset() const
virtual void Reset() const
{
SegmentFE->Reset();
QuadrilateralFE->Reset();
ParallelepipedFE->Reset();
}
virtual void SetDim(const int dim) {};
/** @brief Get the order of the NURBS collection: either a positive number,
when using fixed order, or VariableOrder. */
/** @note Not to be confused with FiniteElementCollection::GetOrder(). */
@@ -715,7 +717,7 @@ public:
/** @brief Set the order and the name, based on the given @a Order: either a
positive number for fixed order, or VariableOrder. */
void SetOrder(int Order) const;
virtual void SetOrder(int Order) const;
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
@@ -734,6 +736,109 @@ public:
virtual ~NURBSFECollection();
};
/// Arbitrary order H(div) NURBS finite elements.
class NURBS_HDivFECollection : public NURBSFECollection
{
private:
NURBS1DFiniteElement *SegmentFE;
NURBS2DFiniteElement *QuadrilateralFE;
NURBS_HDiv2DFiniteElement *QuadrilateralVFE;
NURBS_HDiv3DFiniteElement *ParallelepipedVFE;
FiniteElement *sFE;
FiniteElement *qFE;
FiniteElement *hFE;
public:
/** @brief The parameter @a Order must be either a positive number, for fixed
order, or VariableOrder (default). */
explicit NURBS_HDivFECollection(int Order = VariableOrder, const int vdim = -1);
virtual void Reset() const override
{
SegmentFE->Reset();
QuadrilateralFE->Reset();
QuadrilateralVFE->Reset();
ParallelepipedVFE->Reset();
}
virtual void SetDim(const int dim) override;
/** @brief Set the order and the name, based on the given @a Order: either a
positive number for fixed order, or VariableOrder. */
virtual void SetOrder(int Order) const override;
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
int DofForGeometry(Geometry::Type GeomType) const override;
const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const override;
const char *Name() const override { return name; }
int GetContType() const override { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const override;
virtual ~NURBS_HDivFECollection();
};
/// Arbitrary order H(curl) NURBS finite elements.
class NURBS_HCurlFECollection : public NURBSFECollection
{
private:
NURBS1DFiniteElement *SegmentFE;
NURBS2DFiniteElement *QuadrilateralFE;
NURBS_HCurl2DFiniteElement *QuadrilateralVFE;
NURBS_HCurl3DFiniteElement *ParallelepipedVFE;
FiniteElement *sFE;
FiniteElement *qFE;
FiniteElement *hFE;
public:
/** @brief The parameter @a Order must be either a positive number, for fixed
order, or VariableOrder (default). */
explicit NURBS_HCurlFECollection(int Order = VariableOrder,
const int vdim = -1);
virtual void Reset() const override
{
SegmentFE->Reset();
QuadrilateralFE->Reset();
QuadrilateralVFE->Reset();
ParallelepipedVFE->Reset();
}
virtual void SetDim(const int dim) override;
/** @brief Set the order and the name, based on the given @a Order: either a
positive number for fixed order, or VariableOrder. */
virtual void SetOrder(int Order) const override;
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
int DofForGeometry(Geometry::Type GeomType) const override;
const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const override;
const char *Name() const override { return name; }
int GetContType() const override { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const override;
virtual ~NURBS_HCurlFECollection();
};
/// Piecewise-(bi/tri)linear continuous finite elements.
class LinearFECollection : public FiniteElementCollection
{
+263 -38
View File
@@ -1525,6 +1525,67 @@ SparseMatrix *FiniteElementSpace::RefinementMatrix_main(
return P;
}
SparseMatrix *FiniteElementSpace::VariableOrderRefinementMatrix(
const int coarse_ndofs, const Table &coarse_elem_dof) const
{
MFEM_VERIFY(mesh->GetLastOperation() == Mesh::REFINE, "");
Array<int> dofs, coarse_dofs, coarse_vdofs;
Vector row;
Mesh::GeometryList elem_geoms(*mesh);
SparseMatrix *P = new SparseMatrix(GetVSize(), coarse_ndofs*vdim);
Array<int> mark(P->Height());
mark = 0;
const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
DenseMatrix lP;
IsoparametricTransformation isotr;
for (int k = 0; k < mesh->GetNE(); k++)
{
const Embedding &emb = rtrans.embeddings[k];
const Geometry::Type geom = mesh->GetElementBaseGeometry(k);
const FiniteElement *fe = GetFE(k);
isotr.SetIdentityTransformation(geom);
const int ldof = fe->GetDof();
lP.SetSize(ldof, ldof);
const DenseTensor &pmats = rtrans.point_matrices[geom];
isotr.SetPointMat(pmats(emb.matrix));
fe->GetLocalInterpolation(isotr, lP);
const int fine_ldof = lP.Height();
elem_dof->GetRow(k, dofs);
coarse_elem_dof.GetRow(emb.parent, coarse_dofs);
for (int vd = 0; vd < vdim; vd++)
{
coarse_dofs.Copy(coarse_vdofs);
DofsToVDofs(vd, coarse_vdofs, coarse_ndofs);
for (int i = 0; i < fine_ldof; i++)
{
const int r = DofToVDof(dofs[i], vd);
int m = (r >= 0) ? r : (-1 - r);
if (!mark[m])
{
lP.GetRow(i, row);
P->SetRow(r, coarse_vdofs, row);
mark[m] = 1;
}
}
}
}
MFEM_VERIFY(mark.Sum() == P->Height(), "Not all rows of P set.");
P->Finalize();
return P;
}
void FiniteElementSpace::GetLocalRefinementMatrices(
Geometry::Type geom, DenseTensor &localP) const
{
@@ -1556,15 +1617,20 @@ SparseMatrix* FiniteElementSpace::RefinementMatrix(int old_ndofs,
"Previous mesh is not coarser.");
Mesh::GeometryList elem_geoms(*mesh);
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
if (!IsVariableOrder())
{
GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
{
GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
localP);
}
else
{
return VariableOrderRefinementMatrix(old_ndofs, *old_elem_dof);
}
return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
localP);
}
FiniteElementSpace::RefinementOperator::RefinementOperator(
@@ -1582,9 +1648,12 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
for (int i = 0; i < elem_geoms.Size(); i++)
if (!fespace->IsVariableOrder())
{
fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
for (int i = 0; i < elem_geoms.Size(); i++)
{
fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
}
ConstructDoFTransArray();
@@ -1597,10 +1666,13 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
{
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
for (int i = 0; i < elem_geoms.Size(); i++)
if (!fespace->IsVariableOrder())
{
fespace->GetLocalRefinementMatrices(*coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
for (int i = 0; i < elem_geoms.Size(); i++)
{
fespace->GetLocalRefinementMatrices(*coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
}
}
// Make a copy of the coarse elem_dof Table.
@@ -1676,11 +1748,25 @@ void FiniteElementSpace::RefinementOperator::Mult(const Vector &x,
Vector subY, subX;
DenseMatrix eP;
IsoparametricTransformation isotr;
for (int k = 0; k < mesh_ref->GetNE(); k++)
{
const Embedding &emb = trans_ref.embeddings[k];
const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
const DenseMatrix &lP = localP[geom](emb.matrix);
if (fespace->IsVariableOrder())
{
const FiniteElement *fe = fespace->GetFE(k);
isotr.SetIdentityTransformation(geom);
const int ldof = fe->GetDof();
eP.SetSize(ldof, ldof);
const DenseTensor &pmats = trans_ref.point_matrices[geom];
isotr.SetPointMat(pmats(emb.matrix));
fe->GetLocalInterpolation(isotr, eP);
}
const DenseMatrix &lP = (fespace->IsVariableOrder()) ? eP : localP[geom](
emb.matrix);
subY.SetSize(lP.Height());
@@ -1745,11 +1831,28 @@ void FiniteElementSpace::RefinementOperator::MultTranspose(const Vector &x,
Vector subY, subX, subYt;
DenseMatrix eP;
IsoparametricTransformation isotr;
const FiniteElement *fe = nullptr;
for (int k = 0; k < mesh_ref->GetNE(); k++)
{
const Embedding &emb = trans_ref.embeddings[k];
const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
const DenseMatrix &lP = localP[geom](emb.matrix);
if (fespace->IsVariableOrder())
{
fe = fespace->GetFE(k);
isotr.SetIdentityTransformation(geom);
const int ldof = fe->GetDof();
eP.SetSize(ldof);
const DenseTensor &pmats = trans_ref.point_matrices[geom];
isotr.SetPointMat(pmats(emb.matrix));
fe->GetLocalInterpolation(isotr, eP);
}
const DenseMatrix &lP = (fespace->IsVariableOrder()) ? eP : localP[geom](
emb.matrix);
DofTransformation *doftrans = fespace->GetElementDofs(k, f_dofs);
old_elem_dof->GetRow(emb.parent, c_dofs);
@@ -2108,9 +2211,12 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
Mesh::GeometryList elem_geoms(*mesh);
DenseTensor localR[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
if (!IsVariableOrder())
{
GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
for (int i = 0; i < elem_geoms.Size(); i++)
{
GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
}
}
SparseMatrix *R = new SparseMatrix(ndofs*vdim, old_ndofs*vdim);
@@ -2125,14 +2231,34 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
bool is_dg = FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS;
int num_marked = 0;
const FiniteElement *fe = nullptr;
DenseMatrix localRVO; //for variable order only
for (int k = 0; k < dtrans.embeddings.Size(); k++)
{
const Embedding &emb = dtrans.embeddings[k];
Geometry::Type geom = mesh->GetElementBaseGeometry(emb.parent);
DenseMatrix &lR = localR[geom](emb.matrix);
if (IsVariableOrder())
{
fe = GetFE(emb.parent);
const DenseTensor &pmats = dtrans.point_matrices[geom];
const int ldof = fe->GetDof();
IsoparametricTransformation isotr;
isotr.SetIdentityTransformation(geom);
localRVO.SetSize(ldof, ldof);
isotr.SetPointMat(pmats(emb.matrix));
// Local restriction is size ldofxldof assuming that the parent and
// child are of same polynomial order.
fe->GetLocalRestriction(isotr, localRVO);
}
DenseMatrix &lR = IsVariableOrder() ? localRVO : localR[geom](emb.matrix);
elem_dof->GetRow(emb.parent, dofs);
old_elem_dof->GetRow(k, old_dofs);
MFEM_VERIFY(old_dofs.Size() == dofs.Size(),
"Parent and child must have same #dofs.");
for (int vd = 0; vd < vdim; vd++)
{
@@ -2158,7 +2284,7 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
}
}
if (!is_dg)
if (!is_dg && !IsVariableOrder())
{
MFEM_VERIFY(num_marked == R->Height(),
"internal error: not all rows of R were set.");
@@ -2216,6 +2342,7 @@ void FiniteElementSpace::Constructor(Mesh *mesh_, NURBSExtension *NURBSext_,
const NURBSFECollection *nurbs_fec =
dynamic_cast<const NURBSFECollection *>(fec_);
if (nurbs_fec)
{
MFEM_VERIFY(mesh_->NURBSext, "NURBS FE space requires a NURBS mesh.");
@@ -2312,12 +2439,63 @@ void FiniteElementSpace::UpdateNURBS()
face_dof = NULL;
face_to_be.DeleteAll();
// Depending on the element type create the appropriate extensions
// for the individual components.
dynamic_cast<const NURBSFECollection *>(fec)->Reset();
ndofs = NURBSext->GetNDof();
elem_dof = NURBSext->GetElementDofTable();
bdr_elem_dof = NURBSext->GetBdrElementDofTable();
if (dynamic_cast<const NURBS_HDivFECollection *>(fec))
{
VNURBSext.SetSize(mesh->Dimension());
for (int d = 0; d < mesh->Dimension(); d++)
{
VNURBSext[d] = NURBSext->GetDivExtension(d);
}
}
if (dynamic_cast<const NURBS_HCurlFECollection *>(fec))
{
VNURBSext.SetSize(mesh->Dimension());
for (int d = 0; d < mesh->Dimension(); d++)
{
VNURBSext[d] = NURBSext->GetCurlExtension(d);
}
}
// If required: concatenate the dof tables of the individual components into
// one dof table for the vector fespace.
if (VNURBSext.Size() == 2)
{
int offset1 = VNURBSext[0]->GetNDof();
ndofs = VNURBSext[0]->GetNDof() + VNURBSext[1]->GetNDof();
// Merge Tables
elem_dof = new Table(*VNURBSext[0]->GetElementDofTable(),
*VNURBSext[1]->GetElementDofTable(),offset1 );
bdr_elem_dof = new Table(*VNURBSext[0]->GetBdrElementDofTable(),
*VNURBSext[1]->GetBdrElementDofTable(),offset1);
}
else if (VNURBSext.Size() == 3)
{
int offset1 = VNURBSext[0]->GetNDof();
int offset2 = offset1 + VNURBSext[1]->GetNDof();
ndofs = offset2 + VNURBSext[2]->GetNDof();
// Merge Tables
elem_dof = new Table(*VNURBSext[0]->GetElementDofTable(),
*VNURBSext[1]->GetElementDofTable(),offset1,
*VNURBSext[2]->GetElementDofTable(),offset2);
bdr_elem_dof = new Table(*VNURBSext[0]->GetBdrElementDofTable(),
*VNURBSext[1]->GetBdrElementDofTable(),offset1,
*VNURBSext[2]->GetBdrElementDofTable(),offset2);
}
else
{
ndofs = NURBSext->GetNDof();
elem_dof = NURBSext->GetElementDofTable();
bdr_elem_dof = NURBSext->GetBdrElementDofTable();
}
mesh_sequence = mesh->GetSequence();
sequence++;
}
@@ -3319,11 +3497,21 @@ void FiniteElementSpace::Destroy()
dof_elem_array.DeleteAll();
dof_ldof_array.DeleteAll();
for (int i = 0; i < VNURBSext.Size(); i++)
{
delete VNURBSext[i];
}
if (NURBSext)
{
if (own_ext) { delete NURBSext; }
delete face_dof;
face_to_be.DeleteAll();
if (VNURBSext.Size() > 0 )
{
delete elem_dof;
delete bdr_elem_dof;
}
}
else
{
@@ -3335,6 +3523,8 @@ void FiniteElementSpace::Destroy()
delete [] bdofs;
}
ceed::RemoveBasisAndRestriction(this);
}
void FiniteElementSpace::DestroyDoFTransArray()
@@ -3353,19 +3543,27 @@ void FiniteElementSpace::GetTransferOperator(
if (T.Type() == Operator::MFEM_SPARSEMAT)
{
Mesh::GeometryList elem_geoms(*mesh);
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
if (!IsVariableOrder())
{
GetLocalRefinementMatrices(coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
Mesh::GeometryList elem_geoms(*mesh);
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
{
GetLocalRefinementMatrices(coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
}
T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
coarse_fes.GetElementToDofTable(),
coarse_fes.
GetElementToFaceOrientationTable(),
localP));
}
else
{
T.Reset(VariableOrderRefinementMatrix(coarse_fes.GetNDofs(),
coarse_fes.GetElementToDofTable()));
}
T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
coarse_fes.GetElementToDofTable(),
coarse_fes.
GetElementToFaceOrientationTable(),
localP));
}
else
{
@@ -3416,19 +3614,33 @@ void FiniteElementSpace::GetTrueTransferOperator(
void FiniteElementSpace::UpdateElementOrders()
{
const CoarseFineTransformations &cf_tr = mesh->GetRefinementTransforms();
Array<char> new_order(mesh->GetNE());
switch (mesh->GetLastOperation())
{
case Mesh::REFINE:
{
const CoarseFineTransformations &cf_tr = mesh->GetRefinementTransforms();
for (int i = 0; i < mesh->GetNE(); i++)
{
new_order[i] = elem_order[cf_tr.embeddings[i].parent];
}
break;
}
case Mesh::DEREFINE:
{
const CoarseFineTransformations &cf_tr =
mesh->ncmesh->GetDerefinementTransforms();
Table coarse_to_fine;
cf_tr.MakeCoarseToFineTable(coarse_to_fine);
Array<int> tabrow;
for (int i = 0; i < coarse_to_fine.Size(); i++)
{
coarse_to_fine.GetRow(i, tabrow);
//For now we require that all children are of same polynomial order.
new_order[i] = elem_order[tabrow[0]];
}
break;
}
default:
MFEM_ABORT("not implemented yet");
}
@@ -3523,11 +3735,23 @@ void FiniteElementSpace::Update(bool want_transform)
{
BuildConformingInterpolation();
Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
if (cP && cR)
if (IsVariableOrder())
{
Th.SetOperatorOwner(false);
Th.Reset(new TripleProductOperator(cP.get(), cR.get(), Th.Ptr(),
false, false, true));
if (cP && cR_hp)
{
Th.SetOperatorOwner(false);
Th.Reset(new TripleProductOperator(cP.get(), cR_hp.get(), Th.Ptr(),
false, false, true));
}
}
else
{
if (cP && cR)
{
Th.SetOperatorOwner(false);
Th.Reset(new TripleProductOperator(cP.get(), cR.get(), Th.Ptr(),
false, false, true));
}
}
break;
}
@@ -3640,6 +3864,7 @@ FiniteElementCollection *FiniteElementSpace::Load(Mesh *m, std::istream &input)
input >> ord;
NURBSFECollection *nurbs_fec = dynamic_cast<NURBSFECollection*>(r_fec);
if (nurbs_fec) { nurbs_fec->SetDim(m->Dimension()); }
NURBSExtension *nurbs_ext = NULL;
if (fes_format == 90) // original format, v0.9
{
+11
View File
@@ -268,6 +268,10 @@ protected:
Array<int> dof_elem_array, dof_ldof_array;
NURBSExtension *NURBSext;
/** array of NURBS extension for H(div) and H(curl) vector elements.
For each direction an extension is created from the base NURBSext,
with an increase in order in the appropriate direction. */
Array<NURBSExtension*> VNURBSext;
int own_ext;
mutable Array<int> face_to_be; // NURBS FE space only
@@ -469,6 +473,11 @@ protected:
const Table *coarse_elem_fos,
const DenseTensor localP[]) const;
/* This method returns the Refinement matrix (i.e., the embedding)
from a coarse variable-order fes to a fine fes (after a geometric refinement) */
SparseMatrix *VariableOrderRefinementMatrix(const int coarse_ndofs,
const Table &coarse_elem_dof) const;
void GetLocalRefinementMatrices(Geometry::Type geom,
DenseTensor &localP) const;
void GetLocalDerefinementMatrices(Geometry::Type geom,
@@ -517,6 +526,8 @@ protected:
const Array<int> *perm);
public:
/** @brief Default constructor: the object is invalid until initialized using
the method Load(). */
FiniteElementSpace();
+210 -74
View File
@@ -12,6 +12,8 @@
// Implementation of GridFunction
#include "gridfunc.hpp"
#include "linearform.hpp"
#include "bilinearform.hpp"
#include "quadinterpolator.hpp"
#include "../mesh/nurbs.hpp"
#include "../general/text.hpp"
@@ -39,7 +41,7 @@ GridFunction::GridFunction(Mesh *m, std::istream &input)
UseDevice(true);
fes = new FiniteElementSpace;
fec = fes->Load(m, input);
fec_owned = fes->Load(m, input);
skip_comment_lines(input, '#');
istream::int_type next_char = input.peek();
@@ -81,10 +83,10 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
int vdim, ordering;
fes = gf_array[0]->FESpace();
fec = FiniteElementCollection::New(fes->FEColl()->Name());
fec_owned = FiniteElementCollection::New(fes->FEColl()->Name());
vdim = fes->GetVDim();
ordering = fes->GetOrdering();
fes = new FiniteElementSpace(m, fec, vdim, ordering);
fes = new FiniteElementSpace(m, fec_owned, vdim, ordering);
SetSize(fes->GetVSize());
if (m->NURBSext)
@@ -153,11 +155,11 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
void GridFunction::Destroy()
{
if (fec)
if (fec_owned)
{
delete fes;
delete fec;
fec = NULL;
delete fec_owned;
fec_owned = NULL;
}
}
@@ -325,10 +327,9 @@ int GridFunction::VectorDim() const
const FiniteElement *fe;
if (!fes->GetNE())
{
const FiniteElementCollection *fe_coll = fes->FEColl();
static const Geometry::Type geoms[3] =
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
fe = fe_coll->
fe = fes->FEColl()->
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
}
else
@@ -350,7 +351,8 @@ int GridFunction::CurlDim() const
{
static const Geometry::Type geoms[3] =
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
fe = fec->FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
fe = fes->FEColl()->
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
}
else
{
@@ -1321,9 +1323,9 @@ void GridFunction::ProjectVectorFieldOn(GridFunction &vec_field, int comp)
}
}
void GridFunction::AccumulateAndCountDerivativeValues(int comp, int der_comp,
GridFunction &der,
Array<int> &zones_per_dof)
void GridFunction::AccumulateAndCountDerivativeValues(
int comp, int der_comp, GridFunction &der,
Array<int> &zones_per_dof) const
{
FiniteElementSpace * der_fes = der.FESpace();
ElementTransformation * transf;
@@ -1374,7 +1376,8 @@ void GridFunction::AccumulateAndCountDerivativeValues(int comp, int der_comp,
}
}
void GridFunction::GetDerivative(int comp, int der_comp, GridFunction &der)
void GridFunction::GetDerivative(int comp, int der_comp,
GridFunction &der) const
{
Array<int> overlap;
AccumulateAndCountDerivativeValues(comp, der_comp, der, overlap);
@@ -2061,41 +2064,37 @@ void GridFunction::AccumulateAndCountBdrValues(
Coefficient *coeff[], VectorCoefficient *vcoeff, const Array<int> &attr,
Array<int> &values_counter)
{
int i, j, fdof, d, ind, vdim;
real_t val;
const FiniteElement *fe;
ElementTransformation *transf;
Array<int> vdofs;
Vector vc;
values_counter.SetSize(Size());
values_counter = 0;
vdim = fes->GetVDim();
const int vdim = fes->GetVDim();
HostReadWrite();
for (i = 0; i < fes->GetNBE(); i++)
for (int i = 0; i < fes->GetNBE(); i++)
{
if (attr[fes->GetBdrAttribute(i) - 1] == 0) { continue; }
fe = fes->GetBE(i);
fdof = fe->GetDof();
transf = fes->GetBdrElementTransformation(i);
const FiniteElement *fe = fes->GetBE(i);
const int fdof = fe->GetDof();
ElementTransformation *transf = fes->GetBdrElementTransformation(i);
const IntegrationRule &ir = fe->GetNodes();
fes->GetBdrElementVDofs(i, vdofs);
for (j = 0; j < fdof; j++)
for (int j = 0; j < fdof; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
transf->SetIntPoint(&ip);
if (vcoeff) { vcoeff->Eval(vc, *transf, ip); }
for (d = 0; d < vdim; d++)
for (int d = 0; d < vdim; d++)
{
if (!vcoeff && !coeff[d]) { continue; }
val = vcoeff ? vc(d) : coeff[d]->Eval(*transf, ip);
if ( (ind = vdofs[fdof*d+j]) < 0 )
real_t val = vcoeff ? vc(d) : coeff[d]->Eval(*transf, ip);
int ind = vdofs[fdof*d+j];
if ( ind < 0 )
{
val = -val, ind = -1-ind;
}
@@ -2117,10 +2116,11 @@ void GridFunction::AccumulateAndCountBdrValues(
// iff A_ij != 0. It is sufficient to resolve just the first level of
// dependency, since A is a projection matrix: A^n = A due to cR.cP = I.
// Cases like these arise in 3D when boundary edges are constrained by
// (depend on) internal faces/elements. We use the virtual method
// GetBoundaryClosure from NCMesh to resolve the dependencies.
if (fes->Nonconforming() && fes->GetMesh()->Dimension() == 3)
// (depend on) internal faces/elements, or for internal boundaries in 2 or
// 3D. We use the virtual method GetBoundaryClosure from NCMesh to resolve
// the dependencies.
if (fes->Nonconforming() && (fes->GetMesh()->Dimension() == 2 ||
fes->GetMesh()->Dimension() == 3))
{
Vector vals;
Mesh *mesh = fes->GetMesh();
@@ -2128,26 +2128,19 @@ void GridFunction::AccumulateAndCountBdrValues(
Array<int> bdr_edges, bdr_vertices, bdr_faces;
ncmesh->GetBoundaryClosure(attr, bdr_vertices, bdr_edges, bdr_faces);
for (i = 0; i < bdr_edges.Size(); i++)
auto mark_dofs = [&](ElementTransformation &transf, const FiniteElement &fe)
{
int edge = bdr_edges[i];
fes->GetEdgeVDofs(edge, vdofs);
if (vdofs.Size() == 0) { continue; }
transf = mesh->GetEdgeTransformation(edge);
transf->Attribute = -1; // TODO: set the boundary attribute
fe = fes->GetEdgeElement(edge);
if (!vcoeff)
{
vals.SetSize(fe->GetDof());
for (d = 0; d < vdim; d++)
vals.SetSize(fe.GetDof());
for (int d = 0; d < vdim; d++)
{
if (!coeff[d]) { continue; }
fe->Project(*coeff[d], *transf, vals);
fe.Project(*coeff[d], transf, vals);
for (int k = 0; k < vals.Size(); k++)
{
ind = vdofs[d*vals.Size()+k];
const int ind = vdofs[d*vals.Size()+k];
if (++values_counter[ind] == 1)
{
(*this)(ind) = vals(k);
@@ -2161,11 +2154,11 @@ void GridFunction::AccumulateAndCountBdrValues(
}
else // vcoeff != NULL
{
vals.SetSize(vdim*fe->GetDof());
fe->Project(*vcoeff, *transf, vals);
vals.SetSize(vdim*fe.GetDof());
fe.Project(*vcoeff, transf, vals);
for (int k = 0; k < vals.Size(); k++)
{
ind = vdofs[k];
const int ind = vdofs[k];
if (++values_counter[ind] == 1)
{
(*this)(ind) = vals(k);
@@ -2176,6 +2169,26 @@ void GridFunction::AccumulateAndCountBdrValues(
}
}
}
};
for (auto edge : bdr_edges)
{
fes->GetEdgeVDofs(edge, vdofs);
if (vdofs.Size() == 0) { continue; }
ElementTransformation *transf = mesh->GetEdgeTransformation(edge);
const FiniteElement *fe = fes->GetEdgeElement(edge);
mark_dofs(*transf, *fe);
}
for (auto face : bdr_faces)
{
fes->GetFaceVDofs(face, vdofs);
if (vdofs.Size() == 0) { continue; }
ElementTransformation *transf = mesh->GetFaceTransformation(face);
const FiniteElement *fe = fes->GetFaceElement(face);
mark_dofs(*transf, *fe);
}
}
}
@@ -2228,26 +2241,37 @@ void GridFunction::AccumulateAndCountBdrTangentValues(
accumulate_dofs(dofs, lvec, *this, values_counter);
}
if (fes->Nonconforming() && fes->GetMesh()->Dimension() == 3)
if (fes->Nonconforming() && (fes->GetMesh()->Dimension() == 2 ||
fes->GetMesh()->Dimension() == 3))
{
Mesh *mesh = fes->GetMesh();
NCMesh *ncmesh = mesh->ncmesh;
Array<int> bdr_edges, bdr_vertices, bdr_faces;
ncmesh->GetBoundaryClosure(bdr_attr, bdr_vertices, bdr_edges, bdr_faces);
for (int i = 0; i < bdr_edges.Size(); i++)
for (auto edge : bdr_edges)
{
int edge = bdr_edges[i];
fes->GetEdgeDofs(edge, dofs);
if (dofs.Size() == 0) { continue; }
T = mesh->GetEdgeTransformation(edge);
T->Attribute = -1; // TODO: set the boundary attribute
fe = fes->GetEdgeElement(edge);
lvec.SetSize(fe->GetDof());
fe->Project(vcoeff, *T, lvec);
accumulate_dofs(dofs, lvec, *this, values_counter);
}
for (auto face : bdr_faces)
{
fes->GetFaceDofs(face, dofs);
if (dofs.Size() == 0) { continue; }
T = mesh->GetFaceTransformation(face);
fe = fes->GetFaceElement(face);
lvec.SetSize(fe->GetDof());
fe->Project(vcoeff, *T, lvec);
accumulate_dofs(dofs, lvec, *this, values_counter);
}
}
}
@@ -2350,19 +2374,48 @@ void GridFunction::ProjectCoefficient(Coefficient &coeff)
if (delta_c == NULL)
{
Array<int> vdofs;
Vector vals;
for (int i = 0; i < fes->GetNE(); i++)
if (fes->GetNURBSext() == NULL)
{
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
Array<int> vdofs;
Vector vals;
for (int i = 0; i < fes->GetNE(); i++)
{
doftrans->TransformPrimal(vals);
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);
}
SetSubVector(vdofs, vals);
}
else
{
// Define and assemble linear form
LinearForm b(fes);
b.AddDomainIntegrator(new DomainLFIntegrator(coeff));
b.Assemble();
// Define and assemble bilinear form
BilinearForm a(fes);
a.AddDomainIntegrator(new MassIntegrator());
a.Assemble();
// Set solver and preconditioner
SparseMatrix A(a.SpMat());
GSSmoother prec(A);
CGSolver cg;
cg.SetOperator(A);
cg.SetPreconditioner(prec);
cg.SetRelTol(1e-12);
cg.SetMaxIter(1000);
cg.SetPrintLevel(0);
// Solve and get solution
*this = 0.0;
cg.Mult(b,*this);
}
}
else
@@ -2403,22 +2456,54 @@ void GridFunction::ProjectCoefficient(
void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff)
{
int i;
Array<int> vdofs;
Vector vals;
DofTransformation * doftrans = NULL;
for (i = 0; i < fes->GetNE(); i++)
if (fes->GetNURBSext() == NULL)
{
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
int i;
Array<int> vdofs;
Vector vals;
DofTransformation * doftrans = NULL;
for (i = 0; i < fes->GetNE(); i++)
{
doftrans->TransformPrimal(vals);
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);
}
SetSubVector(vdofs, vals);
}
else
{
// Define and assemble linear form
LinearForm b(fes);
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(vcoeff));
b.Assemble();
// Define and assemble bilinear form
BilinearForm a(fes);
a.AddDomainIntegrator(new VectorFEMassIntegrator());
a.Assemble();
// Set solver and preconditioner
SparseMatrix A(a.SpMat());
GSSmoother prec(A);
CGSolver cg;
cg.SetOperator(A);
cg.SetPreconditioner(prec);
cg.SetRelTol(1e-12);
cg.SetMaxIter(1000);
cg.SetPrintLevel(0);
// Solve and get solution
*this = 0.0;
cg.Mult(b,*this);
}
}
@@ -2966,6 +3051,57 @@ real_t GridFunction::ComputeDivError(
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
}
real_t GridFunction::ComputeLaplaceError(
Coefficient *exlap, const IntegrationRule *irs[]) const
{
real_t error = 0.0, a;
const FiniteElement *fe;
ElementTransformation *Tr;
Array<int> dofs;
int intorder, fdof;
Vector laplace;
for (int i = 0; i < fes->GetNE(); i++)
{
laplace.SetSize(fdof);
fe = fes->GetFE(i);
Tr = fes->GetElementTransformation(i);
intorder = 2*fe->GetOrder() + 3;
const IntegrationRule *ir;
if (irs)
{
ir = irs[fe->GetGeomType()];
}
else
{
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
fes->GetElementDofs(i, dofs);
fdof = fe->GetDof();
laplace.SetSize(fdof);
for (int j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
Tr->SetIntPoint(&ip);
fe->CalcPhysLaplacian(*Tr, laplace);
a = 0;
for (int k = 0; k < fdof; k++)
if (dofs[k] >= 0)
{
a += (*this)(dofs[k]) * laplace(k);
}
else
{
a -= (*this)(-1-dofs[k]) * laplace(k);
}
a -= exlap->Eval(*Tr, ip);
error += ip.weight * Tr->Weight() * a * a;
}
}
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
}
real_t GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
Coefficient *ell_coeff,
class JumpScaling jump_scaling,
@@ -3904,7 +4040,7 @@ void GridFunction::LegacyNCReorder()
mesh->GetEdgeVertices(i, ev);
if (old_vertex[ev[0]] > old_vertex[ev[1]])
{
const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, -1);
const int *ind = fes->FEColl()->DofOrderForOrientation(Geometry::SEGMENT, -1);
fes->GetEdgeInteriorDofs(i, dofs);
for (int k = 0; k < dofs.Size(); k++)
+21 -15
View File
@@ -30,14 +30,14 @@ namespace mfem
class GridFunction : public Vector
{
protected:
/// FE space on which the grid function lives. Owned if #fec is not NULL.
/// FE space on which the grid function lives. Owned if #fec_owned is not NULL.
FiniteElementSpace *fes;
/** @brief Used when the grid function is read from a file. It can also be
set explicitly, see MakeOwner().
If not NULL, this pointer is owned by the GridFunction. */
FiniteElementCollection *fec;
FiniteElementCollection *fec_owned;
long fes_sequence; // see FiniteElementSpace::sequence, Mesh::sequence
@@ -72,16 +72,16 @@ protected:
public:
GridFunction() { fes = NULL; fec = NULL; fes_sequence = 0; UseDevice(true); }
GridFunction() { fes = NULL; fec_owned = NULL; fes_sequence = 0; UseDevice(true); }
/// Copy constructor. The internal true-dof vector #t_vec is not copied.
GridFunction(const GridFunction &orig)
: Vector(orig), fes(orig.fes), fec(NULL), fes_sequence(orig.fes_sequence)
: Vector(orig), fes(orig.fes), fec_owned(NULL), fes_sequence(orig.fes_sequence)
{ UseDevice(true); }
/// Construct a GridFunction associated with the FiniteElementSpace @a *f.
GridFunction(FiniteElementSpace *f) : Vector(f->GetVSize())
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/// Construct a GridFunction using previously allocated array @a data.
/** The GridFunction does not assume ownership of @a data which is assumed to
@@ -91,13 +91,13 @@ public:
*/
GridFunction(FiniteElementSpace *f, real_t *data)
: Vector(data, f->GetVSize())
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
{ fes = f; fec_owned = 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); }
{ fes = f; fec_owned = 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
@@ -116,12 +116,12 @@ public:
GridFunction &operator=(const GridFunction &rhs)
{ return operator=((const Vector &)rhs); }
/// Make the GridFunction the owner of #fec and #fes.
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec
/// Make the GridFunction the owner of #fec_owned and #fes.
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec_owned
and #fes is taken away. */
void MakeOwner(FiniteElementCollection *fec_) { fec = fec_; }
void MakeOwner(FiniteElementCollection *fec_) { fec_owned = fec_; }
FiniteElementCollection *OwnFEC() { return fec; }
FiniteElementCollection *OwnFEC() { return fec_owned; }
int VectorDim() const;
int CurlDim() const;
@@ -321,7 +321,7 @@ public:
@param[out] der The resulting derivative (scalar function). The
FiniteElementSpace of this function must be set
before the call. */
void GetDerivative(int comp, int der_comp, GridFunction &der);
void GetDerivative(int comp, int der_comp, GridFunction &der) const;
real_t GetDivergence(ElementTransformation &tr) const;
@@ -387,7 +387,8 @@ public:
/** @brief Project @a coeff Coefficient to @a this GridFunction. The
projection computation depends on the choice of the FiniteElementSpace
#fes. Note that this is usually interpolation at the degrees of freedom
in each element (not L2 projection). */
in each element (not L2 projection). For NURBS spaces these degrees of
freedom are not available and L2 projection is resorted to as fallback. */
virtual void ProjectCoefficient(Coefficient &coeff);
/** @brief Project @a coeff Coefficient to @a this GridFunction, using one
@@ -398,7 +399,8 @@ public:
/** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction. The
projection computation depends on the choice of the FiniteElementSpace
#fes. Note that this is usually interpolation at the degrees of freedom
in each element (not L2 projection).*/
in each element (not L2 projection). For NURBS spaces these degrees of
freedom are not available and L2 projection is resorted to as fallback. */
void ProjectCoefficient(VectorCoefficient &vcoeff);
/** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction, using
@@ -443,7 +445,7 @@ protected:
GetDerivative() method; see its documentation. */
void AccumulateAndCountDerivativeValues(int comp, int der_comp,
GridFunction &der,
Array<int> &zones_per_dof);
Array<int> &zones_per_dof) const;
void AccumulateAndCountBdrValues(Coefficient *coeff[],
VectorCoefficient *vcoeff,
@@ -531,6 +533,10 @@ public:
virtual real_t ComputeDivError(Coefficient *exdiv,
const IntegrationRule *irs[] = NULL) const;
/// Returns ||lap u_ex - lap u_h||_L2 for H1 elements
virtual real_t ComputeLaplaceError(Coefficient *exlap,
const IntegrationRule *irs[] = NULL) const;
/// Returns the Face Jumps error for L2 elements. The error can be weighted
/// by a constant nu, by nu/h, or nu*p^2/h, depending on the value of
/// @a jump_scaling.
+2
View File
@@ -1393,8 +1393,10 @@ GSOPGSLIB::~GSOPGSLIB()
void GSOPGSLIB::UpdateIdentifiers(const Array<long long> &ids)
{
long long minval = ids.Min();
#ifdef MFEM_USE_MPI
MPI_Allreduce(MPI_IN_PLACE, &minval, 1, MPI_LONG_LONG_INT,
MPI_MIN, gsl_comm->c);
#endif
MFEM_VERIFY(minval >= 0, "Unique identifier cannot be negative.");
if (gsl_data != NULL) { gslib_gs_free(gsl_data); }
num_ids = ids.Size();
+44 -44
View File
@@ -220,8 +220,8 @@ void MomentFittingIntRules::ComputeSurfaceWeights1D(ElementTransformation& Tr)
{
IntegrationPoint ip2;
ip2.x = .5;
while (LvlSet->Eval(Tr, ip2) > 1e-12
|| LvlSet->Eval(Tr, ip2) < -1e-12)
while (LvlSet->Eval(Tr, ip2) > tol_1
|| LvlSet->Eval(Tr, ip2) < -tol_1)
{
if (LvlSet->Eval(Tr, ip0) * LvlSet->Eval(Tr, ip2) < 0.)
{
@@ -237,12 +237,12 @@ void MomentFittingIntRules::ComputeSurfaceWeights1D(ElementTransformation& Tr)
intp.x = ip2.x;
intp.weight = 1. / Tr.Weight();
}
else if (LvlSet->Eval(Tr, ip0) > 0. && LvlSet->Eval(Tr, ip1) <= 1e-12)
else if (LvlSet->Eval(Tr, ip0) > 0. && LvlSet->Eval(Tr, ip1) <= tol_1)
{
intp.x = 1.;
intp.weight = 1. / Tr.Weight();
}
else if (LvlSet->Eval(Tr, ip1) > 0. && LvlSet->Eval(Tr, ip0) <= 1e-12)
else if (LvlSet->Eval(Tr, ip1) > 0. && LvlSet->Eval(Tr, ip0) <= tol_1)
{
intp.x = 0.;
intp.weight = 1. / Tr.Weight();
@@ -290,8 +290,8 @@ void MomentFittingIntRules::ComputeVolumeWeights1D(ElementTransformation& Tr,
}
}
}
else if (LvlSet->Eval(Tr, ip0) <= -1e-12
|| LvlSet->Eval(Tr, ip1) <= -1e-12)
else if (LvlSet->Eval(Tr, ip0) <= -tol_1
|| LvlSet->Eval(Tr, ip1) <= -tol_1)
{
for (int ip = 0; ip < ir.GetNPoints(); ip++)
{
@@ -356,24 +356,24 @@ void MomentFittingIntRules::ComputeSurfaceWeights2D(ElementTransformation& Tr)
IntegrationPoint ipB;
Trafo.TransformBack(pointB, ipB);
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12)
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -1e-12
&& LvlSet->Eval(Trafo, ipB) > -1e-12)
if (LvlSet->Eval(Trafo, ipA) > -tol_1
&& LvlSet->Eval(Trafo, ipB) > -tol_1)
{
layout = Layout::inside;
}
else if (LvlSet->Eval(Trafo, ipA) > 1e-15
else if (LvlSet->Eval(Trafo, ipA) > tol_2
&& LvlSet->Eval(Trafo, ipB) <= 0.)
{
layout = Layout::intersected;
}
else if (LvlSet->Eval(Trafo, ipA) <= 0.
&& LvlSet->Eval(Trafo, ipB) > 1e-15)
&& LvlSet->Eval(Trafo, ipB) > tol_2)
{
layout = Layout::intersected;
Vector temp(pointA.Size());
@@ -399,10 +399,10 @@ void MomentFittingIntRules::ComputeSurfaceWeights2D(ElementTransformation& Tr)
IntegrationPoint ip;
Trafo.TransformBack(mid, ip);
while (LvlSet->Eval(Trafo, ip) > 1e-12
|| LvlSet->Eval(Trafo, ip) < -1e-12)
while (LvlSet->Eval(Trafo, ip) > tol_1
|| LvlSet->Eval(Trafo, ip) < -tol_1)
{
if (LvlSet->Eval(Trafo, ip) > 1e-12)
if (LvlSet->Eval(Trafo, ip) > tol_1)
{
pointC = mid;
}
@@ -539,7 +539,7 @@ void MomentFittingIntRules::ComputeSurfaceWeights2D(ElementTransformation& Tr)
temp2 = 0.;
for (int i = 0; i < nBasis; i++)
{
if (SVD.Singularvalue(i) > 1e-12)
if (SVD.Singularvalue(i) > tol_1)
{
temp2(i) = temp(i) / SVD.Singularvalue(i);
}
@@ -606,24 +606,24 @@ void MomentFittingIntRules::ComputeVolumeWeights2D(ElementTransformation& Tr,
IntegrationPoint ipB;
Trafo.TransformBack(pointB, ipB);
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12)
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -1e-12
&& LvlSet->Eval(Trafo, ipB) > -1e-12)
if (LvlSet->Eval(Trafo, ipA) > -tol_1
&& LvlSet->Eval(Trafo, ipB) > -tol_1)
{
layout = Layout::inside;
}
else if (LvlSet->Eval(Trafo, ipA) > 1e-15
else if (LvlSet->Eval(Trafo, ipA) > tol_2
&& LvlSet->Eval(Trafo, ipB) <= 0.)
{
layout = Layout::intersected;
}
else if (LvlSet->Eval(Trafo, ipA) <= 0.
&& LvlSet->Eval(Trafo, ipB) > 1e-15)
&& LvlSet->Eval(Trafo, ipB) > tol_2)
{
layout = Layout::intersected;
Vector temp(pointA.Size());
@@ -648,10 +648,10 @@ void MomentFittingIntRules::ComputeVolumeWeights2D(ElementTransformation& Tr,
IntegrationPoint ip;
Trafo.TransformBack(mid, ip);
while (LvlSet->Eval(Trafo, ip) > 1e-12
|| LvlSet->Eval(Trafo, ip) < -1e-12)
while (LvlSet->Eval(Trafo, ip) > tol_1
|| LvlSet->Eval(Trafo, ip) < -tol_1)
{
if (LvlSet->Eval(Trafo, ip) > 1e-12)
if (LvlSet->Eval(Trafo, ip) > tol_1)
{
pointC = mid;
}
@@ -786,7 +786,7 @@ void MomentFittingIntRules::ComputeVolumeWeights2D(ElementTransformation& Tr,
VolumeSVD->LeftSingularvectors().MultTranspose(RHS, temp);
for (int i = 0; i < nBasisVolume; i++)
{
if (VolumeSVD->Singularvalue(i) > 1e-12)
if (VolumeSVD->Singularvalue(i) > tol_1)
{
temp2(i) = temp(i) / VolumeSVD->Singularvalue(i);
}
@@ -865,18 +865,18 @@ void MomentFittingIntRules::ComputeSurfaceWeights3D(ElementTransformation& Tr)
IntegrationPoint ipD;
Trafo.TransformBack(pointD, ipD);
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12
|| LvlSet->Eval(Trafo, ipC) < -1e-12
|| LvlSet->Eval(Trafo, ipD) < -1e-12)
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1
|| LvlSet->Eval(Trafo, ipC) < -tol_1
|| LvlSet->Eval(Trafo, ipD) < -tol_1)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -1e-12
|| LvlSet->Eval(Trafo, ipB) > -1e-12
|| LvlSet->Eval(Trafo, ipC) > -1e-12
|| LvlSet->Eval(Trafo, ipD) > -1e-12)
if (LvlSet->Eval(Trafo, ipA) > -tol_1
|| LvlSet->Eval(Trafo, ipB) > -tol_1
|| LvlSet->Eval(Trafo, ipC) > -tol_1
|| LvlSet->Eval(Trafo, ipD) > -tol_1)
{
element_int = true;
}
@@ -978,7 +978,7 @@ void MomentFittingIntRules::ComputeSurfaceWeights3D(ElementTransformation& Tr)
temp2 = 0.;
for (int i = 0; i < nBasis; i++)
{
if (SVD.Singularvalue(i) > 1e-12)
if (SVD.Singularvalue(i) > tol_1)
{
temp2(i) = temp(i) / SVD.Singularvalue(i);
}
@@ -1047,18 +1047,18 @@ void MomentFittingIntRules::ComputeVolumeWeights3D(ElementTransformation& Tr,
IntegrationPoint ipD;
Trafo.TransformBack(pointD, ipD);
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12
|| LvlSet->Eval(Trafo, ipC) < -1e-12
|| LvlSet->Eval(Trafo, ipD) < -1e-12)
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1
|| LvlSet->Eval(Trafo, ipC) < -tol_1
|| LvlSet->Eval(Trafo, ipD) < -tol_1)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -1e-12
|| LvlSet->Eval(Trafo, ipB) > -1e-12
|| LvlSet->Eval(Trafo, ipC) > -1e-12
|| LvlSet->Eval(Trafo, ipD) > -1e-12)
if (LvlSet->Eval(Trafo, ipA) > -tol_1
|| LvlSet->Eval(Trafo, ipB) > -tol_1
|| LvlSet->Eval(Trafo, ipC) > -tol_1
|| LvlSet->Eval(Trafo, ipD) > -tol_1)
{
element_int = true;
}
@@ -1159,7 +1159,7 @@ void MomentFittingIntRules::ComputeVolumeWeights3D(ElementTransformation& Tr,
VolumeSVD->LeftSingularvectors().MultTranspose(RHS, temp);
temp2 = 0.;
for (int i = 0; i < nBasisVolume; i++)
if (VolumeSVD->Singularvalue(i) > 1e-12)
if (VolumeSVD->Singularvalue(i) > tol_1)
{
temp2(i) = temp(i) / VolumeSVD->Singularvalue(i);
}
+11
View File
@@ -36,6 +36,17 @@ protected:
/// Space order for the LS projection.
int lsOrder;
/// @name Tolerances used for point comparisons
///@{
#ifdef MFEM_USE_DOUBLE
static constexpr real_t tol_1 = 1e-12;
static constexpr real_t tol_2 = 1e-15;
#elif defined(MFEM_USE_SINGLE)
static constexpr real_t tol_1 = 1e-5;
static constexpr real_t tol_2 = 1e-7;
#endif
///@}
/** @brief Constructor to set up the generated cut IntegrationRules.
@param [in] order Order of the constructed IntegrationRule.
+29
View File
@@ -123,6 +123,35 @@ void DomainLFGradIntegrator::AssembleDeltaElementVect(
dshape.Mult(Qvec, elvect);
}
void DomainLFLaplaceIntegrator::AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect)
{
int dof = el.GetDof();
laplace.SetSize(dof); // vector of size dof
elvect.SetSize(dof);
elvect = 0.0;
const IntegrationRule *ir = NULL;//IntRule;
if (ir == NULL)
{
ir = &IntRules.Get(el.GetGeomType(), oa * el.GetOrder() + ob + 4);
}
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Tr.SetIntPoint (&ip);
real_t val = Tr.Weight() * Q.Eval(Tr, ip) * alpha;
el.CalcPhysLaplacian(Tr, laplace);
add(elvect, ip.weight * val, laplace, elvect);
}
}
void BoundaryLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
+23
View File
@@ -174,6 +174,29 @@ public:
using LinearFormIntegrator::AssembleRHSElementVect;
};
/// Class for domain integrator $ L(v) := (f, \Delta v) $
class DomainLFLaplaceIntegrator : public LinearFormIntegrator
{
private:
Vector laplace;
Coefficient &Q;
real_t alpha;
int oa, ob;
public:
/// Constructs the domain integrator $ (Q, \nabla v) $
DomainLFLaplaceIntegrator(Coefficient &QF, real_t alp = 1.0, int a = 2,
int b = 0)
: Q(QF), oa(a), ob(b) { alpha = alp; }
/** Given a particular Finite Element and a transformation (Tr)
computes the element right hand side element vector, elvect. */
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect);
using LinearFormIntegrator::AssembleRHSElementVect;
};
/// Class for boundary integration $ L(v) := (g, v) $
class BoundaryLFIntegrator : public LinearFormIntegrator
+5 -4
View File
@@ -39,9 +39,10 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, const GridFunction *gf,
{
const FiniteElementSpace *glob_fes = gf->FESpace();
// duplicate the FiniteElementCollection from 'gf'
fec = FiniteElementCollection::New(glob_fes->FEColl()->Name());
fec_owned = FiniteElementCollection::New(glob_fes->FEColl()->Name());
// create a local ParFiniteElementSpace from the global one:
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning, fec);
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning,
fec_owned);
SetSize(pfes->GetVSize());
if (partitioning)
@@ -81,7 +82,7 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, std::istream &input)
: GridFunction(pmesh, input)
{
// Convert the FiniteElementSpace, fes, to a ParFiniteElementSpace:
pfes = new ParFiniteElementSpace(pmesh, fec, fes->GetVDim(),
pfes = new ParFiniteElementSpace(pmesh, fec_owned, fes->GetVDim(),
fes->GetOrdering());
delete fes;
fes = pfes;
@@ -520,7 +521,7 @@ void ParGridFunction::CountElementsPerVDof(Array<int> &elem_per_vdof) const
}
void ParGridFunction::GetDerivative(int comp, int der_comp,
ParGridFunction &der)
ParGridFunction &der) const
{
Array<int> overlap;
AccumulateAndCountDerivativeValues(comp, der_comp, der, overlap);
+1 -1
View File
@@ -231,7 +231,7 @@ public:
void CountElementsPerVDof(Array<int> &elem_per_vdof) const override;
/// Parallel version of GridFunction::GetDerivative(); see its documentation.
void GetDerivative(int comp, int der_comp, ParGridFunction &der);
void GetDerivative(int comp, int der_comp, ParGridFunction &der) const;
/** Sets the output vector @a dof_vals to the values of the degrees of
freedom of element @a el. If @a el is greater than or equal to the number
+238 -124
View File
@@ -2949,6 +2949,15 @@ void TMOP_Integrator::EnableSurfaceFitting(const GridFunction &s0,
MFEM_VERIFY(surf_fit_pos == NULL,
"Using both fitting approaches is not supported.");
const int dim = s0.FESpace()->GetMesh()->Dimension();
Mesh *mesh = s0.FESpace()->GetMesh();
MFEM_VERIFY(mesh->GetNodes()->Size() == dim*s0.Size(),
"Mesh and level-set polynomial order must be the same.");
const H1_FECollection *fec = dynamic_cast<const H1_FECollection *>
(s0.FESpace()->FEColl());
MFEM_VERIFY(fec, "Only H1_FECollection is supported for the surface fitting "
"grid function.");
delete surf_fit_gf;
surf_fit_gf = new GridFunction(s0);
surf_fit_gf->CountElementsPerVDof(surf_fit_dof_count);
@@ -2987,12 +2996,24 @@ void TMOP_Integrator::EnableSurfaceFitting(const GridFunction &pos,
void TMOP_Integrator::EnableSurfaceFitting(const ParGridFunction &s0,
const Array<bool> &smarker,
Coefficient &coeff,
AdaptivityEvaluator &ae)
AdaptivityEvaluator &ae,
AdaptivityEvaluator *aegrad,
AdaptivityEvaluator *aehess)
{
// To have both we must duplicate the markers.
MFEM_VERIFY(surf_fit_pos == NULL,
"Using both fitting approaches is not supported.");
const int dim = s0.FESpace()->GetMesh()->Dimension();
ParMesh *pmesh = s0.ParFESpace()->GetParMesh();
MFEM_VERIFY(pmesh->GetNodes()->Size() == dim*s0.Size(),
"Mesh and level-set polynomial order must be the same.");
const H1_FECollection *fec = dynamic_cast<const H1_FECollection *>
(s0.FESpace()->FEColl());
MFEM_VERIFY(fec, "Only H1_FECollection is supported for the surface fitting "
"grid function.");
delete surf_fit_gf;
surf_fit_gf = new GridFunction(s0);
s0.CountElementsPerVDof(surf_fit_dof_count);
@@ -3000,11 +3021,80 @@ void TMOP_Integrator::EnableSurfaceFitting(const ParGridFunction &s0,
surf_fit_coeff = &coeff;
surf_fit_eval = &ae;
surf_fit_eval->SetParMetaInfo(*s0.ParFESpace()->GetParMesh(),
*s0.ParFESpace());
surf_fit_eval->SetParMetaInfo(*pmesh, *s0.ParFESpace());
surf_fit_eval->SetInitialField
(*surf_fit_gf->FESpace()->GetMesh()->GetNodes(), *surf_fit_gf);
surf_fit_gf_bg = false;
if (!aegrad) { return; }
MFEM_VERIFY(aehess, "AdaptivityEvaluator for Hessians must be provided too.");
ParFiniteElementSpace *fes = s0.ParFESpace();
// FE space for gradients.
delete surf_fit_grad;
H1_FECollection *fec_grad = new H1_FECollection(fec->GetOrder(), dim,
fec->GetBasisType());
ParFiniteElementSpace *fes_grad = new ParFiniteElementSpace(pmesh, fec_grad,
dim);
// Initial gradients.
surf_fit_grad = new GridFunction(fes_grad);
surf_fit_grad->MakeOwner(fec_grad);
for (int d = 0; d < dim; d++)
{
ParGridFunction surf_fit_grad_comp(fes, surf_fit_grad->GetData()+d*s0.Size());
s0.GetDerivative(1, d, surf_fit_grad_comp);
}
surf_fit_eval_grad = aegrad;
surf_fit_eval_grad->SetParMetaInfo(*pmesh, *fes_grad);
surf_fit_eval_grad->SetInitialField(*pmesh->GetNodes(), *surf_fit_grad);
// FE space for Hessians.
delete surf_fit_hess;
H1_FECollection *fec_hess = new H1_FECollection(fec->GetOrder(), dim,
fec->GetBasisType());
ParFiniteElementSpace *fes_hess = new ParFiniteElementSpace(pmesh, fec_hess,
dim*dim);
// Initial Hessians.
surf_fit_hess = new GridFunction(fes_hess);
surf_fit_hess->MakeOwner(fec_hess);
int id = 0;
for (int d = 0; d < dim; d++)
{
for (int idir = 0; idir < dim; idir++)
{
ParGridFunction surf_fit_grad_comp(fes,
surf_fit_grad->GetData()+d*s0.Size());
ParGridFunction surf_fit_hess_comp(fes,
surf_fit_hess->GetData()+id*s0.Size());
surf_fit_grad_comp.GetDerivative(1, idir, surf_fit_hess_comp);
id++;
}
}
surf_fit_eval_hess = aehess;
surf_fit_eval_hess->SetParMetaInfo(*pmesh, *fes_hess);
surf_fit_eval_hess->SetInitialField(*pmesh->GetNodes(), *surf_fit_hess);
// Store DOF indices that are marked for fitting. Used to reduce work for
// transferring information between source/background and current mesh.
surf_fit_marker_dof_index.SetSize(0);
#ifdef MFEM_USE_GSLIB
if (dynamic_cast<InterpolatorFP *>(surf_fit_eval) &&
dynamic_cast<InterpolatorFP *>(surf_fit_eval_grad) &&
dynamic_cast<InterpolatorFP *>(surf_fit_eval_hess))
{
for (int i = 0; i < surf_fit_marker->Size(); i++)
{
if ((*surf_fit_marker)[i] == true)
{
surf_fit_marker_dof_index.Append(i);
}
}
}
#endif
*surf_fit_grad = 0.0;
*surf_fit_hess = 0.0;
}
void TMOP_Integrator::EnableSurfaceFittingFromSource(
@@ -3022,16 +3112,17 @@ void TMOP_Integrator::EnableSurfaceFittingFromSource(
// Setup for level set function
delete surf_fit_gf;
surf_fit_gf = new GridFunction(s0);
*surf_fit_gf = 0.0;
surf_fit_marker = &smarker;
surf_fit_coeff = &coeff;
surf_fit_eval = &ae;
surf_fit_gf_bg = true;
surf_fit_eval->SetParMetaInfo(*s_bg.ParFESpace()->GetParMesh(),
*s_bg.ParFESpace());
surf_fit_eval->SetInitialField
(*s_bg.FESpace()->GetMesh()->GetNodes(), s_bg);
GridFunction *nodes = s0.FESpace()->GetMesh()->GetNodes();
surf_fit_eval->ComputeAtNewPosition(*nodes, *surf_fit_gf,
nodes->FESpace()->GetOrdering());
// Setup for gradient on background mesh
MFEM_VERIFY(s_bg_grad.ParFESpace()->GetOrdering() ==
@@ -3041,11 +3132,11 @@ void TMOP_Integrator::EnableSurfaceFittingFromSource(
delete surf_fit_grad;
surf_fit_grad = new GridFunction(s0_grad);
*surf_fit_grad = 0.0;
surf_fit_eval_bg_grad = &age;
surf_fit_eval_bg_hess = &ahe;
surf_fit_eval_bg_grad->SetParMetaInfo(*s_bg_grad.ParFESpace()->GetParMesh(),
*s_bg_grad.ParFESpace());
surf_fit_eval_bg_grad->SetInitialField
surf_fit_eval_grad = &age;
surf_fit_eval_hess = &ahe;
surf_fit_eval_grad->SetParMetaInfo(*s_bg_grad.ParFESpace()->GetParMesh(),
*s_bg_grad.ParFESpace());
surf_fit_eval_grad->SetInitialField
(*s_bg_grad.FESpace()->GetMesh()->GetNodes(), s_bg_grad);
// Setup for Hessian on background mesh
@@ -3056,9 +3147,9 @@ void TMOP_Integrator::EnableSurfaceFittingFromSource(
delete surf_fit_hess;
surf_fit_hess = new GridFunction(s0_hess);
*surf_fit_hess = 0.0;
surf_fit_eval_bg_hess->SetParMetaInfo(*s_bg_hess.ParFESpace()->GetParMesh(),
*s_bg_hess.ParFESpace());
surf_fit_eval_bg_hess->SetInitialField
surf_fit_eval_hess->SetParMetaInfo(*s_bg_hess.ParFESpace()->GetParMesh(),
*s_bg_hess.ParFESpace());
surf_fit_eval_hess->SetInitialField
(*s_bg_hess.FESpace()->GetMesh()->GetNodes(), s_bg_hess);
// Count number of zones that share each of the DOFs
@@ -3863,7 +3954,7 @@ void TMOP_Integrator::AssembleElemVecSurfFit(const FiniteElement &el_x,
Vector sigma_e(dof_s);
DenseMatrix surf_fit_grad_e(dof_s, dim);
if (surf_fit_gf || surf_fit_gf_bg)
if (surf_fit_gf)
{
surf_fit_gf->GetSubVector(vdofs, sigma_e);
@@ -3871,7 +3962,7 @@ void TMOP_Integrator::AssembleElemVecSurfFit(const FiniteElement &el_x,
// The FE coefficients of the gradient go in surf_fit_grad_e.
Vector grad_ptr(surf_fit_grad_e.GetData(), dof_s * dim);
DenseMatrix grad_phys; // This will be (dof x dim, dof).
if (surf_fit_gf_bg)
if (surf_fit_grad)
{
surf_fit_grad->FESpace()->GetElementVDofs(el_id, dofs);
surf_fit_grad->GetSubVector(dofs, grad_ptr);
@@ -3945,7 +4036,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
Vector sigma_e(dof_s);
DenseMatrix surf_fit_grad_e(dof_s, dim);
DenseMatrix surf_fit_hess_e(dof_s, dim*dim);
if (surf_fit_gf || surf_fit_gf_bg)
if (surf_fit_gf)
{
surf_fit_gf->GetSubVector(vdofs, sigma_e);
@@ -3953,7 +4044,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
// The FE coefficients of the gradient go in surf_fit_grad_e.
Vector grad_ptr(surf_fit_grad_e.GetData(), dof_s * dim);
DenseMatrix grad_phys; // This will be (dof x dim, dof).
if (surf_fit_gf_bg)
if (surf_fit_grad)
{
surf_fit_grad->FESpace()->GetElementVDofs(el_id, dofs);
surf_fit_grad->GetSubVector(dofs, grad_ptr);
@@ -3967,7 +4058,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
// Project the Hessian of sigma in the same space.
// The FE coefficients of the Hessian go in surf_fit_hess_e.
Vector hess_ptr(surf_fit_hess_e.GetData(), dof_s*dim*dim);
if (surf_fit_gf_bg)
if (surf_fit_hess)
{
surf_fit_hess->FESpace()->GetElementVDofs(el_id, dofs);
surf_fit_hess->GetSubVector(dofs, hess_ptr);
@@ -3994,7 +4085,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
Tpr.SetIntPoint(&ip);
real_t w = surf_fit_normal * surf_fit_coeff->Eval(Tpr, ip);
if (surf_fit_gf || surf_fit_gf_bg)
if (surf_fit_gf)
{
Vector gg_ptr(surf_fit_hess_s.GetData(), dim * dim);
surf_fit_hess_e.GetRow(s, gg_ptr);
@@ -4376,6 +4467,130 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x,
dx = detv_avg_min / dxscale;
}
void TMOP_Integrator::RemapSurfaceFittingLevelSetAtNodes(const Vector &new_x,
int new_x_ordering)
{
if (!surf_fit_gf) { return; }
if (surf_fit_marker_dof_index.Size())
{
// Interpolate information only at DOFs marked for fitting.
const int dim = surf_fit_gf->FESpace()->GetMesh()->Dimension();
const int cnt = surf_fit_marker_dof_index.Size();
const int total_cnt = new_x.Size()/dim;
Vector new_x_sorted(cnt*dim);
if (new_x_ordering == 0)
{
for (int d = 0; d < dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
new_x_sorted(i + d*cnt) = new_x(dof_index + d*total_cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < dim; d++)
{
new_x_sorted(d + i*dim) = new_x(d + dof_index*dim);
}
}
}
// Interpolate values of the LS.
Vector surf_fit_gf_int, surf_fit_grad_int, surf_fit_hess_int;
surf_fit_eval->ComputeAtNewPosition(new_x_sorted, surf_fit_gf_int,
new_x_ordering);
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_gf)[dof_index] = surf_fit_gf_int(i);
}
// Interpolate gradients of the LS.
surf_fit_eval_grad->ComputeAtNewPosition(new_x_sorted, surf_fit_grad_int,
new_x_ordering);
// Assumes surf_fit_grad and surf_fit_gf share the same space
const int grad_dim = surf_fit_grad->VectorDim();
const int grad_cnt = surf_fit_grad->Size()/grad_dim;
if (surf_fit_grad->FESpace()->GetOrdering() == Ordering::byNODES)
{
for (int d = 0; d < grad_dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_grad)[dof_index + d*grad_cnt] =
surf_fit_grad_int(i + d*cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < grad_dim; d++)
{
(*surf_fit_grad)[dof_index*grad_dim + d] =
surf_fit_grad_int(i*grad_dim + d);
}
}
}
// Interpolate Hessians of the LS.
surf_fit_eval_hess->ComputeAtNewPosition(new_x_sorted, surf_fit_hess_int,
new_x_ordering);
// Assumes surf_fit_hess and surf_fit_gf share the same space
const int hess_dim = surf_fit_hess->VectorDim();
const int hess_cnt = surf_fit_hess->Size()/hess_dim;
if (surf_fit_hess->FESpace()->GetOrdering() == Ordering::byNODES)
{
for (int d = 0; d < hess_dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_hess)[dof_index + d*hess_cnt] =
surf_fit_hess_int(i + d*cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < hess_dim; d++)
{
(*surf_fit_hess)[dof_index*hess_dim + d] =
surf_fit_hess_int(i*hess_dim + d);
}
}
}
}
else
{
surf_fit_eval->ComputeAtNewPosition(new_x, *surf_fit_gf, new_x_ordering);
if (surf_fit_eval_grad)
{
surf_fit_eval_grad->ComputeAtNewPosition(new_x, *surf_fit_grad,
new_x_ordering);
}
if (surf_fit_eval_hess)
{
surf_fit_eval_hess->ComputeAtNewPosition(new_x, *surf_fit_hess,
new_x_ordering);
}
}
}
void TMOP_Integrator::
UpdateAfterMeshPositionChange(const Vector &x_new,
const FiniteElementSpace &x_fes)
@@ -4406,112 +4621,11 @@ UpdateAfterMeshPositionChange(const Vector &x_new,
adapt_lim_eval->ComputeAtNewPosition(x_new, *adapt_lim_gf, ordering);
}
// Update surf_fit_gf if surface fitting is enabled.
// Update surf_fit_gf (and optionally its gradients) if surface
// fitting is enabled.
if (surf_fit_gf)
{
if (surf_fit_gf_bg)
{
// Interpolate information for only DOFs marked for fitting.
const int dim = surf_fit_gf->FESpace()->GetMesh()->Dimension();
const int cnt = surf_fit_marker_dof_index.Size();
const int total_cnt = x_new.Size()/dim;
Vector new_x_sorted(cnt*dim);
if (ordering == 0)
{
for (int d = 0; d < dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
new_x_sorted(i + d*cnt) = x_new(dof_index + d*total_cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < dim; d++)
{
new_x_sorted(d + i*dim) = x_new(d + dof_index*dim);
}
}
}
Vector surf_fit_gf_int, surf_fit_grad_int, surf_fit_hess_int;
surf_fit_eval->ComputeAtNewPosition(
new_x_sorted, surf_fit_gf_int, ordering);
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_gf)[dof_index] = surf_fit_gf_int(i);
}
surf_fit_eval_bg_grad->ComputeAtNewPosition(
new_x_sorted, surf_fit_grad_int, ordering);
// Assumes surf_fit_grad and surf_fit_gf share the same space
const int grad_dim = surf_fit_grad->VectorDim();
const int grad_cnt = surf_fit_grad->Size()/grad_dim;
if (surf_fit_grad->FESpace()->GetOrdering() == Ordering::byNODES)
{
for (int d = 0; d < grad_dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_grad)[dof_index + d*grad_cnt] =
surf_fit_grad_int(i + d*cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < grad_dim; d++)
{
(*surf_fit_grad)[dof_index*dim + d] =
surf_fit_grad_int(i*dim + d);
}
}
}
surf_fit_eval_bg_hess->ComputeAtNewPosition(
new_x_sorted, surf_fit_hess_int, ordering);
// Assumes surf_fit_hess and surf_fit_gf share the same space
const int hess_dim = surf_fit_hess->VectorDim();
const int hess_cnt = surf_fit_hess->Size()/hess_dim;
if (surf_fit_hess->FESpace()->GetOrdering() == Ordering::byNODES)
{
for (int d = 0; d < hess_dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_hess)[dof_index + d*hess_cnt] =
surf_fit_hess_int(i + d*cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < hess_dim; d++)
{
(*surf_fit_hess)[dof_index*dim + d] =
surf_fit_hess_int(i*dim + d);
}
}
}
}
else
{
surf_fit_eval->ComputeAtNewPosition(x_new, *surf_fit_gf, ordering);
}
RemapSurfaceFittingLevelSetAtNodes(x_new, ordering);
}
}
+18 -10
View File
@@ -1784,12 +1784,11 @@ protected:
// Fitting to given physical positions.
TMOP_QuadraticLimiter *surf_fit_limiter; // Owned. Created internally.
const GridFunction *surf_fit_pos; // Not owned. Positions to fit.
real_t surf_fit_normal;
bool surf_fit_gf_bg;
GridFunction *surf_fit_grad, *surf_fit_hess;
AdaptivityEvaluator *surf_fit_eval_bg_grad, *surf_fit_eval_bg_hess;
Array<int> surf_fit_dof_count;
Array<int> surf_fit_marker_dof_index;
real_t surf_fit_normal; // Normalization factor.
GridFunction *surf_fit_grad, *surf_fit_hess; // Owned. Created internally.
AdaptivityEvaluator *surf_fit_eval_grad, *surf_fit_eval_hess; // Not owned.
Array<int> surf_fit_dof_count; // Number of dofs per node.
Array<int> surf_fit_marker_dof_index; // Indices of nodes to fit.
DiscreteAdaptTC *discr_tc;
@@ -1985,6 +1984,10 @@ protected:
real_t ComputeUntanglerMaxMuBarrier(const Vector &x,
const FiniteElementSpace &fes);
// Remaps the internal surface fitting gridfunction object at provided
// locations.
void RemapSurfaceFittingLevelSetAtNodes(const Vector &new_x,
int new_x_ordering);
public:
/** @param[in] m TMOP_QualityMetric for r-adaptivity (not owned).
@param[in] tc Target-matrix construction algorithm to use (not owned).
@@ -2000,9 +2003,8 @@ public:
surf_fit_marker(NULL), surf_fit_coeff(NULL),
surf_fit_gf(NULL), surf_fit_eval(NULL),
surf_fit_limiter(NULL), surf_fit_pos(NULL),
surf_fit_normal(1.0),
surf_fit_gf_bg(false), surf_fit_grad(NULL), surf_fit_hess(NULL),
surf_fit_eval_bg_grad(NULL), surf_fit_eval_bg_hess(NULL),
surf_fit_normal(1.0), surf_fit_grad(NULL), surf_fit_hess(NULL),
surf_fit_eval_grad(NULL), surf_fit_eval_hess(NULL),
discr_tc(dynamic_cast<DiscreteAdaptTC *>(tc)),
fdflag(false), dxscale(1.0e3), fd_call_flag(false), exact_action(false)
{ PA.enabled = false; }
@@ -2103,9 +2105,15 @@ public:
#ifdef MFEM_USE_MPI
/// Parallel support for surface fitting to the zero level set of a function.
/// Here, we add two optional inputs: @a aegrad and @a aehess. When provided,
/// the first and second derivative of the input level set are computed on
/// the initial mesh, and @a aegrad and @a aehess are used to remap grad_s(x)
/// from grad_s0(x0) and hess_s(x) from hess_s0(x0), respectively.
void EnableSurfaceFitting(const ParGridFunction &s0,
const Array<bool> &smarker, Coefficient &coeff,
AdaptivityEvaluator &ae);
AdaptivityEvaluator &ae,
AdaptivityEvaluator *aegrad = NULL,
AdaptivityEvaluator *aehess = NULL);
/** @brief Fitting of certain DOFs in the current mesh to the zero level set
of a function defined on another (finer) source mesh.
+88 -36
View File
@@ -429,11 +429,13 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
#endif
real_t scale = 1.0;
real_t avg_surf_fit_err, max_surf_fit_err = 0.0;
if (surf_fit_max_threshold > 0.0)
bool fitting = IsSurfaceFittingEnabled();
real_t init_fit_avg_err, init_fit_max_err = 0.0;
if (fitting && surf_fit_converge_error)
{
GetSurfaceFittingError(x_out_loc, avg_surf_fit_err, max_surf_fit_err);
if (max_surf_fit_err < surf_fit_max_threshold)
GetSurfaceFittingError(x_out_loc, init_fit_avg_err, init_fit_max_err);
// Check for convergence
if (init_fit_max_err < surf_fit_max_err_limit)
{
if (print_options.iterations)
{
@@ -444,11 +446,12 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
return scale;
}
}
if (adapt_inc_count >= max_adapt_inc_count)
if (surf_fit_adapt_count >= surf_fit_adapt_count_limit)
{
if (print_options.iterations)
{
mfem::out << "TMOPNewtonSolver converged "
mfem::out << "TMOPNewtonSolver terminated "
"based on max number of times surface fitting weight can"
"be increased. \n";
}
@@ -467,7 +470,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
// reference to detect deteriorations.
MFEM_VERIFY(min_det_ptr != NULL, " Initial mesh was valid, but"
" intermediate mesh is invalid. Contact TMOP Developers.");
MFEM_VERIFY(min_detJ_threshold == 0.0,
MFEM_VERIFY(min_detJ_limit == 0.0,
"This setup is not supported. Contact TMOP Developers.");
*min_det_ptr = untangle_factor * min_detT_in;
}
@@ -478,6 +481,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
bool x_out_ok = false;
real_t energy_out = 0.0, min_detT_out;
const real_t norm_in = Norm(r);
real_t avg_fit_err, max_fit_err = 0.0;
const real_t detJ_factor = (solver_type == 1) ? 0.25 : 0.5;
compute_metric_quantile_flag = false;
@@ -488,6 +492,9 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
// Perform the line search.
for (int i = 0; i < 12; i++)
{
avg_fit_err = 0.0;
max_fit_err = 0.0;
// Update the mesh and get the L-vector in x_out_loc.
add(x, -scale, c, x_out);
if (serial)
@@ -502,7 +509,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
// Check the changes in detJ.
min_detT_out = ComputeMinDet(x_out_loc, *fes);
if (untangling == false && min_detT_out <= min_detJ_threshold)
if (untangling == false && min_detT_out <= min_detJ_limit)
{
// No untangling, and detJ got negative (or small) -- no good.
if (print_options.iterations)
@@ -529,18 +536,19 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
// Check the changes in total energy.
ProcessNewState(x_out);
real_t avg_fit_err, max_fit_err = 0.0;
if (surf_fit_max_threshold > 0.0)
// Ensure sufficient decrease in fitting error if we are trying to
// converge based on error.
if (fitting && surf_fit_converge_error)
{
GetSurfaceFittingError(x_out_loc, avg_fit_err, max_fit_err);
}
if (surf_fit_max_threshold > 0.0 && max_fit_err >= 1.2*max_surf_fit_err)
{
if (print_options.iterations)
if (max_fit_err >= 1.2*init_fit_max_err)
{
mfem::out << "Scale = " << scale << " Surf fit err increased.\n";
if (print_options.iterations)
{
mfem::out << "Scale = " << scale << " Surf fit err increased.\n";
}
scale *= 0.5; continue;
}
scale *= 0.5; continue;
}
if (serial)
@@ -614,7 +622,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
if (x_out_ok == false) { scale = 0.0; }
if (surf_fit_scale_factor > 0.0) { update_surf_fit_coeff = true; }
if (surf_fit_scale_factor > 0.0) { surf_fit_coeff_update = true; }
compute_metric_quantile_flag = true;
return scale;
@@ -657,7 +665,7 @@ void TMOPNewtonSolver::GetSurfaceFittingWeight(Array<real_t> &weights) const
for (int i = 0; i < integs.Size(); i++)
{
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
if (ti)
if (ti && ti->IsSurfaceFittingEnabled())
{
weight = ti->GetSurfaceFittingWeight();
weights.Append(weight);
@@ -668,8 +676,11 @@ void TMOPNewtonSolver::GetSurfaceFittingWeight(Array<real_t> &weights) const
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
for (int j = 0; j < ati.Size(); j++)
{
weight = ati[j]->GetSurfaceFittingWeight();
weights.Append(weight);
if (ati[j]->IsSurfaceFittingEnabled())
{
weight = ati[j]->GetSurfaceFittingWeight();
weights.Append(weight);
}
}
}
}
@@ -716,6 +727,39 @@ void TMOPNewtonSolver::GetSurfaceFittingError(const Vector &x_loc,
}
}
bool TMOPNewtonSolver::IsSurfaceFittingEnabled() const
{
const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
const 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)
{
if (ti->IsSurfaceFittingEnabled())
{
return true;
}
}
co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
if (co)
{
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
for (int j = 0; j < ati.Size(); j++)
{
if (ati[j]->IsSurfaceFittingEnabled())
{
return true;
}
}
}
}
return false;
}
void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
{
const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
@@ -801,38 +845,46 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
// adaptive surface fitting is enabled. The idea is to increase the
// coefficient if the surface fitting error does not sufficiently
// decrease between subsequent TMOPNewtonSolver iterations.
if (update_surf_fit_coeff)
if (surf_fit_coeff_update)
{
// Get surface fitting errors.
GetSurfaceFittingError(x_loc, surf_fit_err_avg, surf_fit_err_max);
GetSurfaceFittingError(x_loc, surf_fit_avg_err, surf_fit_max_err);
// Get array with surface fitting weights.
Array<real_t> weights;
GetSurfaceFittingWeight(weights);
Array<real_t> fitweights;
GetSurfaceFittingWeight(fitweights);
if (print_options.iterations)
{
mfem::out << "Avg/Max surface fitting error: " <<
surf_fit_err_avg << " " <<
surf_fit_err_max << "\n";
surf_fit_avg_err << " " <<
surf_fit_max_err << "\n";
mfem::out << "Min/Max surface fitting weight: " <<
weights.Min() << " " << weights.Max() << "\n";
fitweights.Min() << " " << fitweights.Max() << "\n";
}
real_t change_surf_fit_err = surf_fit_err_avg_prvs-surf_fit_err_avg;
real_t rel_change_surf_fit_err = change_surf_fit_err/surf_fit_err_avg_prvs;
real_t change_surf_fit_err = surf_fit_avg_err_prvs-surf_fit_avg_err;
real_t rel_change_surf_fit_err = change_surf_fit_err/surf_fit_avg_err_prvs;
// Increase the surface fitting coefficient if the surface fitting error
// does not decrease sufficiently.
if (rel_change_surf_fit_err < surf_fit_rel_change_threshold)
// does not decrease sufficiently. If we are converging based on residual,
// also make sure we have not reached the maximum fitting weight and
// error threshold.
if (rel_change_surf_fit_err < surf_fit_err_rel_change_limit &&
(surf_fit_converge_error ||
(fitweights.Max() < surf_fit_weight_limit &&
surf_fit_max_err > surf_fit_max_err_limit)))
{
UpdateSurfaceFittingWeight(surf_fit_scale_factor);
adapt_inc_count += 1;
real_t scale_factor = std::min(surf_fit_scale_factor,
surf_fit_weight_limit/fitweights.Max());
UpdateSurfaceFittingWeight(scale_factor);
surf_fit_adapt_count += 1;
}
else
{
adapt_inc_count = 0;
surf_fit_adapt_count = 0;
}
surf_fit_err_avg_prvs = surf_fit_err_avg;
update_surf_fit_coeff = false;
surf_fit_avg_err_prvs = surf_fit_avg_err;
surf_fit_coeff_update = false;
}
}
+87 -26
View File
@@ -134,18 +134,20 @@ protected:
int solver_type;
bool parallel;
// Line search step is rejected if min(detJ) <= min_detJ_threshold.
real_t min_detJ_threshold = 0.0;
// Line search step is rejected if min(detJ) <= min_detJ_limit.
real_t min_detJ_limit = 0.0;
// Surface fitting variables.
mutable real_t surf_fit_err_avg_prvs = 10000.0;
mutable real_t surf_fit_err_avg, surf_fit_err_max;
mutable bool update_surf_fit_coeff = false;
real_t surf_fit_max_threshold = -1.0;
real_t surf_fit_rel_change_threshold = 0.001;
mutable real_t surf_fit_avg_err_prvs = 10000.0;
mutable real_t surf_fit_avg_err, surf_fit_max_err;
mutable bool surf_fit_coeff_update = false;
real_t surf_fit_max_err_limit = -1.0;
real_t surf_fit_err_rel_change_limit = 0.001;
real_t surf_fit_scale_factor = 0.0;
mutable int adapt_inc_count = 0;
mutable int max_adapt_inc_count = 10;
mutable int surf_fit_adapt_count = 0;
mutable int surf_fit_adapt_count_limit = 10;
mutable real_t surf_fit_weight_limit = 1e10;
bool surf_fit_converge_error = false;
// Minimum determinant over the whole mesh. Used for mesh untangling.
real_t *min_det_ptr = nullptr;
@@ -191,6 +193,9 @@ protected:
void GetSurfaceFittingWeight(Array<real_t> &weights) const;
///@}
/// Check if surface fitting is enabled.
bool IsSurfaceFittingEnabled() const;
public:
#ifdef MFEM_USE_MPI
TMOPNewtonSolver(MPI_Comm comm, const IntegrationRule &irule, int type = 0)
@@ -224,38 +229,94 @@ public:
/// (ii) surface fitting weight.
virtual void ProcessNewState(const Vector &x) const;
/** @name Methods for adaptive surface fitting weight. (Experimental) */
/// Enable/Disable adaptive surface fitting weight.
/// The weight is modified after each TMOPNewtonSolver iteration as:
/// w_{k+1} = w_{k} * @a surf_fit_scale_factor if relative change in
/// max surface fitting error < @a surf_fit_rel_change_threshold.
/// The solver terminates if the maximum surface fitting error does
/// not sufficiently decrease for @a max_adapt_inc_count consecutive
/// solver iterations or if the max error falls below @a surf_fit_max_threshold.
void EnableAdaptiveSurfaceFitting()
{
surf_fit_scale_factor = 10.0;
surf_fit_rel_change_threshold = 0.001;
}
/** @name Methods for adaptive surface fitting.
\brief These methods control the behavior of the weight and the
termination of the solver. (Experimental)
Adaptive fitting weight: The weight is modified after each
TMOPNewtonSolver iteration as:
w_{k+1} = w_{k} * \ref surf_fit_scale_factor if the relative
change in average fitting error < \ref surf_fit_err_rel_change_limit.
When converging based on the residual, we enforce the fitting weight
to be at-most \ref surf_fit_weight_limit, and increase it only if the
fitting error is below user prescribed threshold
(\ref surf_fit_max_err_limit).
See \ref SetAdaptiveSurfaceFittingScalingFactor and
\ref SetAdaptiveSurfaceFittingRelativeChangeThreshold.
Note that the solver stops if the maximum surface fitting error
does not sufficiently decrease for \ref surf_fit_adapt_count_limit (default 10)
consecutive increments of the fitting weight during weight adaptation.
This typically occurs when the mesh cannot align with the level-set
without degrading element quality.
See \ref SetMaxNumberofIncrementsForAdaptiveFitting.
Convergence criterion: There are two modes, residual- and error-based,
which can be toggled using \ref SetSurfaceFittingConvergenceBasedOnError.
(i) Residual based (default): Stop when the norm of the gradient of the
TMOP objective reaches the prescribed tolerance. This method is best used
with a reasonable value for \ref surf_fit_weight_limit when the
adaptive surface fitting scheme is used. See method
\ref SetSurfaceFittingWeightLimit.
(ii) Error based: Stop when the maximum fitting error
reaches the user-prescribed threshold, \ref surf_fit_max_err_limit.
In this case, \ref surf_fit_weight_limit is ignored during weight
adaptation.
*/
///@{
void SetAdaptiveSurfaceFittingScalingFactor(real_t factor)
{
MFEM_VERIFY(factor > 1.0, "Scaling factor must be greater than 1.");
surf_fit_scale_factor = factor;
}
void SetAdaptiveSurfaceFittingRelativeChangeThreshold(real_t threshold)
{
surf_fit_rel_change_threshold = threshold;
surf_fit_err_rel_change_limit = threshold;
}
/// Used for stopping based on the number of consecutive failed weight
/// adaptation iterations.
// TODO: Rename to SetMaxNumberofIncrementsForAdaptiveSurfaceFitting
// in future.
void SetMaxNumberofIncrementsForAdaptiveFitting(int count)
{
max_adapt_inc_count = count;
surf_fit_adapt_count_limit = count;
}
/// Used for error-based surface fitting termination.
void SetTerminationWithMaxSurfaceFittingError(real_t max_error)
{
surf_fit_max_threshold = max_error;
surf_fit_max_err_limit = max_error;
surf_fit_converge_error = true;
}
/// Could be used with both error-based or residual-based convergence.
void SetSurfaceFittingMaxErrorLimit(real_t max_error)
{
surf_fit_max_err_limit = max_error;
}
/// Used for residual-based surface fitting termination.
void SetSurfaceFittingWeightLimit(real_t weight)
{
surf_fit_weight_limit = weight;
}
/// Toggle convergence based on residual or error.
void SetSurfaceFittingConvergenceBasedOnError(bool mode)
{
surf_fit_converge_error = mode;
if (surf_fit_converge_error)
{
MFEM_VERIFY(surf_fit_max_err_limit >= 0,
"Fitting error based convergence requires the user to "
"first set the error threshold."
"See SetTerminationWithMaxSurfaceFittingError");
}
}
///@}
/// Set minimum determinant enforced during line-search.
void SetMinimumDeterminantThreshold(real_t threshold)
{
min_detJ_threshold = threshold;
min_detJ_limit = threshold;
}
virtual void Mult(const Vector &b, Vector &x) const
+2
View File
@@ -1233,6 +1233,8 @@ void PRefinementTransferOperator::Mult(const Vector& x, Vector& y) const
int vdim = lFESpace.GetVDim();
y = 0.0;
for (int i = 0; i < mesh->GetNE(); i++)
{
DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
+2 -2
View File
@@ -63,9 +63,9 @@
#define MFEM_FOREACH_THREAD(i,k,N) for(int i=0; i<N; i++)
#endif
// 'double' atomicAdd implementation for previous versions of CUDA
// 'double' and 'float' atomicAdd implementation for previous versions of CUDA
#if defined(MFEM_USE_CUDA) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600
MFEM_DEVICE inline real_t atomicAdd(real_t *add, real_t val)
MFEM_DEVICE inline mfem::real_t atomicAdd(mfem::real_t *add, mfem::real_t val)
{
unsigned long long int *ptr = (unsigned long long int *) add;
unsigned long long int old = *ptr, reg;
+1 -1
View File
@@ -51,7 +51,7 @@ int isockstream::establish()
{
// char myname[129];
char myname[] = "localhost";
int sfd;
int sfd = -1;
struct addrinfo hints, *res, *rp;
memset(&hints, 0, sizeof(hints));
+2 -2
View File
@@ -134,7 +134,7 @@ int socketbuf::open(const char hostname[], int port)
{
closesocket(socket_descriptor);
socket_descriptor = -2;
return -1;
continue;
}
#endif
@@ -148,7 +148,7 @@ int socketbuf::open(const char hostname[], int port)
}
freeaddrinfo(res);
return 0;
return (socket_descriptor < 0) ? -1 : 0;
}
int socketbuf::close()
+72
View File
@@ -37,6 +37,78 @@ Table::Table(const Table &table)
}
}
Table::Table(const Table &table1,
const Table &table2, int offset)
{
MFEM_ASSERT(table1.size == table2.size,
"Tables have different sizes can not merge.");
size = table1.size;
const int nnz = table1.I[size] + table2.I[size];
I.New(size+1, table1.I.GetMemoryType());
J.New(nnz, table1.J.GetMemoryType());
I[0] = 0;
Array<int> row;
for (int i = 0; i < size; i++)
{
I[i+1] = I[i];
table1.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = row[r];
}
table2.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset : row[r] + offset;
}
}
}
Table::Table(const Table &table1,
const Table &table2, int offset2,
const Table &table3, int offset3)
{
MFEM_ASSERT(table1.size == table2.size,
"Tables have different sizes can not merge.");
MFEM_ASSERT(table1.size == table3.size,
"Tables have different sizes can not merge.");
size = table1.size;
const int nnz = table1.I[size] + table2.I[size] + table3.I[size];
I.New(size+1, table1.I.GetMemoryType());
J.New(nnz, table1.J.GetMemoryType());
I[0] = 0;
Array<int> row;
for (int i = 0; i < size; i++)
{
I[i+1] = I[i];
table1.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = row[r];
}
table2.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset2 : row[r] + offset2;
}
table3.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset3 : row[r] + offset3;
}
}
}
Table& Table::operator=(const Table &rhs)
{
Clear();
+8
View File
@@ -58,6 +58,14 @@ public:
/// Copy constructor
Table(const Table &);
/** Merge constructors
This is used to combine two or three tables into one table.*/
Table(const Table &table1,
const Table &table2, int offset2);
Table(const Table &table1,
const Table &table2, int offset2,
const Table &table3, int offset3);
/// Assignment operator: deep copy
Table& operator=(const Table &rhs);
+1
View File
@@ -44,6 +44,7 @@ list(APPEND HDRS
handle.hpp
invariants.hpp
kernels.hpp
lapack.hpp
linalg.hpp
matrix.hpp
ode.hpp
+20 -138
View File
@@ -10,60 +10,9 @@
// CONTRIBUTING.md for details.
#include "complex_densemat.hpp"
#include "lapack.hpp"
#include <complex>
#ifdef MFEM_USE_LAPACK
#ifdef MFEM_USE_SINGLE
extern "C" void
cgetrf_(int *, int *, std::complex<float> *, int *, int *, int *);
extern "C" void
cgetrs_(char *, int *, int *, std::complex<float> *, int *, int *,
std::complex<float> *, int *, int *);
extern "C" void
cgetri_(int *, std::complex<float> *, int *, int *,
std::complex<float> *, int *, int *);
extern "C" void
ctrsm_(char *, char *, char *, char *, int *, int *, std::complex<float> *,
std::complex<float> *, int *, std::complex<float> *, int *);
extern "C" void
cpotrf_(char *, int *, std::complex<float> *, int *, int *);
extern "C" void
ctrtrs_(char *, char*, char *, int *, int *, std::complex<float> *, int *,
std::complex<float> *, int *, int *);
extern "C" void
cpotri_(char *, int *, std::complex<float> *, int*, int *);
extern "C" void
cpotrs_(char *, int *, int *, std::complex<float> *, int *,
std::complex<float> *, int *, int *);
#elif defined MFEM_USE_DOUBLE
extern "C" void
zgetrf_(int *, int *, std::complex<double> *, int *, int *, int *);
extern "C" void
zgetrs_(char *, int *, int *, std::complex<double> *, int *, int *,
std::complex<double> *, int *, int *);
extern "C" void
zgetri_(int *, std::complex<double> *, int *, int *,
std::complex<double> *, int *, int *);
extern "C" void
ztrsm_(char *, char *, char *, char *, int *, int *, std::complex<double> *,
std::complex<double> *, int *, std::complex<double> *, int *);
extern "C" void
zpotrf_(char *, int *, std::complex<double> *, int *, int *);
extern "C" void
ztrtrs_(char *, char*, char *, int *, int *, std::complex<double> *, int *,
std::complex<double> *, int *, int *);
extern "C" void
zpotri_(char *, int *, std::complex<double> *, int*, int *);
extern "C" void
zpotrs_(char *, int *, int *, std::complex<double> *, int *,
std::complex<double> *, int *, int *);
#endif
#endif
namespace mfem
{
@@ -175,35 +124,17 @@ ComplexDenseMatrix * ComplexDenseMatrix::ComputeInverse()
std::complex<real_t> qwork, *work;
int info;
#ifdef MFEM_USE_SINGLE
cgetrf_(&w, &w, data, &w, ipiv, &info);
#elif defined MFEM_USE_DOUBLE
zgetrf_(&w, &w, data, &w, ipiv, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_COMPLEX(getrf_)(&w, &w, data, &w, ipiv, &info);
if (info)
{
mfem_error("DenseMatrix::Invert() : Error in ZGETRF");
}
#ifdef MFEM_USE_SINGLE
cgetri_(&w, data, &w, ipiv, &qwork, &lwork, &info);
#elif defined MFEM_USE_DOUBLE
zgetri_(&w, data, &w, ipiv, &qwork, &lwork, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_COMPLEX(getri_)(&w, data, &w, ipiv, &qwork, &lwork, &info);
lwork = (int) qwork.real();
work = new std::complex<real_t>[lwork];
#ifdef MFEM_USE_SINGLE
cgetri_(&w, data, &w, ipiv, work, &lwork, &info);
#elif defined MFEM_USE_DOUBLE
zgetri_(&w, data, &w, ipiv, work, &lwork, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_COMPLEX(getri_)(&w, data, &w, ipiv, work, &lwork, &info);
if (info)
{
mfem_error("DenseMatrix::Invert() : Error in ZGETRI");
@@ -493,11 +424,7 @@ bool ComplexLUFactors::Factor(int m, real_t TOL)
#ifdef MFEM_USE_LAPACK
int info = 0;
MFEM_VERIFY(data, "Matrix data not set");
#ifdef MFEM_USE_SINGLE
if (m) { cgetrf_(&m, &m, data, &m, ipiv, &info); }
#elif defined MFEM_USE_DOUBLE
if (m) { zgetrf_(&m, &m, data, &m, ipiv, &info); }
#endif
if (m) { MFEM_LAPACK_COMPLEX(getrf_)(&m, &m, data, &m, ipiv, &info); }
return info == 0;
#else
// compiling without LAPACK
@@ -659,13 +586,10 @@ void ComplexLUFactors::Solve(int m, int n, real_t *X_r, real_t * X_i) const
std::complex<real_t> * x = ComplexFactors::RealToComplex(m*n,X_r,X_i);
char trans = 'N';
int info = 0;
#ifdef MFEM_USE_SINGLE
if (m > 0 && n > 0) { cgetrs_(&trans, &m, &n, data, &m, ipiv, x, &m, &info); }
#elif defined MFEM_USE_DOUBLE
if (m > 0 && n > 0) { zgetrs_(&trans, &m, &n, data, &m, ipiv, x, &m, &info); }
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (m > 0 && n > 0)
{
MFEM_LAPACK_COMPLEX(getrs_)(&trans, &m, &n, data, &m, ipiv, x, &m, &info);
}
MFEM_VERIFY(!info, "LAPACK: error in ZGETRS");
ComplexFactors::ComplexToReal(m*n,x,X_r,X_i);
delete [] x;
@@ -685,15 +609,8 @@ void ComplexLUFactors::RightSolve(int m, int n, real_t *X_r, real_t * X_i) const
if (m > 0 && n > 0)
{
std::complex<real_t> alpha(1.0,0.0);
#ifdef MFEM_USE_SINGLE
ctrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
ctrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#elif defined MFEM_USE_DOUBLE
ztrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
ztrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_COMPLEX(trsm_)(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
MFEM_LAPACK_COMPLEX(trsm_)(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
}
#else
// compiling without LAPACK
@@ -815,13 +732,7 @@ bool ComplexCholeskyFactors::Factor(int m, real_t TOL)
int info = 0;
char uplo = 'L';
MFEM_VERIFY(data, "Matrix data not set");
#ifdef MFEM_USE_SINGLE
if (m) {cpotrf_(&uplo, &m, data, &m, &info);}
#elif defined MFEM_USE_DOUBLE
if (m) {zpotrf_(&uplo, &m, data, &m, &info);}
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (m) { MFEM_LAPACK_COMPLEX(potrf_)(&uplo, &m, data, &m, &info); }
return info == 0;
#else
// CholeskyCrout algorithm
@@ -921,13 +832,8 @@ void ComplexCholeskyFactors::LSolve(int m, int n, real_t * X_r,
char diag = 'N';
int info = 0;
#ifdef MFEM_USE_SINGLE
ctrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#elif defined MFEM_USE_DOUBLE
ztrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_COMPLEX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, x, &m,
&info);
MFEM_VERIFY(!info, "ComplexCholeskyFactors:LSolve:: info");
#else
for (int k = 0; k < n; k++)
@@ -960,13 +866,8 @@ void ComplexCholeskyFactors::USolve(int m, int n, real_t * X_r,
char diag = 'N';
int info = 0;
#ifdef MFEM_USE_SINGLE
ctrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#elif defined MFEM_USE_DOUBLE
ztrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_COMPLEX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, x, &m,
&info);
MFEM_VERIFY(!info, "ComplexCholeskyFactors:USolve:: info");
#else
// X <- L^{-t} X
@@ -994,13 +895,7 @@ void ComplexCholeskyFactors::Solve(int m, int n, real_t * X_r,
char uplo = 'L';
int info = 0;
std::complex<real_t> *x = ComplexFactors::RealToComplex(m*n,X_r,X_i);
#ifdef MFEM_USE_SINGLE
cpotrs_(&uplo, &m, &n, data, &m, x, &m, &info);
#elif defined MFEM_USE_DOUBLE
zpotrs_(&uplo, &m, &n, data, &m, x, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_COMPLEX(potrs_)(&uplo, &m, &n, data, &m, x, &m, &info);
MFEM_VERIFY(!info, "ComplexCholeskyFactors:Solve:: info");
ComplexFactors::ComplexToReal(m*n,x,X_r,X_i);
delete x;
@@ -1026,15 +921,8 @@ void ComplexCholeskyFactors::RightSolve(int m, int n, real_t * X_r,
std::complex<real_t> alpha(1.0,0.0);
if (m > 0 && n > 0)
{
#ifdef MFEM_USE_SINGLE
ctrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
ctrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
#elif defined MFEM_USE_DOUBLE
ztrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
ztrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_COMPLEX(trsm_)(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
MFEM_LAPACK_COMPLEX(trsm_)(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
}
#else
// X <- X L^{-H}
@@ -1085,13 +973,7 @@ void ComplexCholeskyFactors::GetInverseMatrix(int m, real_t * X_r,
}
char uplo = 'L';
int info = 0;
#ifdef MFEM_USE_SINGLE
cpotri_(&uplo, &m, X, &m, &info);
#elif defined MFEM_USE_DOUBLE
zpotri_(&uplo, &m, X, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_COMPLEX(potri_)(&uplo, &m, X, &m, &info);
MFEM_VERIFY(!info, "ComplexCholeskyFactors:GetInverseMatrix:: info");
// fill in the upper triangular part
for (int i = 0; i<m; i++)
+538 -522
View File
File diff suppressed because it is too large Load Diff
+28 -8
View File
@@ -207,6 +207,10 @@ public:
/// Replaces the current matrix with its square root inverse
void SquareRootInverse();
/// Replaces the current matrix with its exponential
/// (currently only supports 2x2 matrices)
void Exponential();
/// Calculates the determinant of the matrix
/// (optimized for 2x2, 3x3, and 4x4 matrices)
real_t Det() const;
@@ -268,35 +272,51 @@ public:
/// Compute the square of the Frobenius norm of the matrix
real_t FNorm2() const { real_t s, n2; FNorm(s, n2); return s*s*n2; }
/// Compute eigenvalues of A x = ev x where A = *this
/** Compute eigenvalues of A x = ev x where A = *this
A is assumed to be symmetric. */
void Eigenvalues(Vector &ev)
{ Eigensystem(ev); }
/// Compute eigenvalues and eigenvectors of A x = ev x where A = *this
/** Compute ith eigenvalue of A x = ev x where A = *this
A is assumed to be symmetric. */
real_t Eigenvalue(int i = -1);
/** Compute eigenvalues and eigenvectors of A x = ev x where A = *this
A is assumed to be symmetric. */
void Eigenvalues(Vector &ev, DenseMatrix &evect)
{ Eigensystem(ev, &evect); }
/// Compute eigenvalues and eigenvectors of A x = ev x where A = *this
/** Compute eigenvalues and eigenvectors of A x = ev x where A = *this
A is assumed to be symmetric. */
void Eigensystem(Vector &ev, DenseMatrix &evect)
{ Eigensystem(ev, &evect); }
/** Compute generalized eigenvalues and eigenvectors of A x = ev B x,
where A = *this */
/** Compute generalized eigenvalues of A x = ev B x, where A = *this
A and B are assumed to be symmetric. */
void Eigenvalues(DenseMatrix &b, Vector &ev)
{ Eigensystem(b, ev); }
/// Compute generalized eigenvalues of A x = ev B x, where A = *this
/** Compute ith eigenvalue of A x = ev B x where A = *this
A and B are assumed to be symmetric. */
real_t Eigenvalue(DenseMatrix &b, int i = -1);
/** Compute generalized eigenvalues and eigenvectors of A x = ev B x,
where A = *this. A and B are assumed to be symmetric.*/
void Eigenvalues(DenseMatrix &b, Vector &ev, DenseMatrix &evect)
{ Eigensystem(b, ev, &evect); }
/** Compute generalized eigenvalues and eigenvectors of A x = ev B x,
where A = *this */
where A = *this. A and B are assumed to be symmetric.*/
void Eigensystem(DenseMatrix &b, Vector &ev, DenseMatrix &evect)
{ Eigensystem(b, ev, &evect); }
void SingularValues(Vector &sv) const;
int Rank(real_t tol) const;
/** Compute the Null Space of the matrix, such that A x = 0,
where A = *this* and x is a column of ns */
void NullSpace(DenseMatrix &ns, real_t tol);
/// Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
real_t CalcSingularvalue(const int i) const;
@@ -318,7 +338,6 @@ public:
void SetCol(int c, const real_t* col);
void SetCol(int c, const Vector &col);
/// Set all entries of a row to the specified value.
void SetRow(int row, real_t value);
/// Set all entries of a column to the specified value.
@@ -342,6 +361,7 @@ public:
void Transpose(const DenseMatrix &A);
/// (*this) = 1/2 ((*this) + (*this)^t)
void Symmetrize();
bool IsSymmetric(real_t tol = 1e-10);
void Lump();
+70 -66
View File
@@ -410,19 +410,19 @@ HYPRE_Int HypreParVector::Randomize(HYPRE_Int seed)
return hypre_ParVectorSetRandomValues(x,seed);
}
void HypreParVector::Print(const char *fname) const
void HypreParVector::Print(const std::string &fname) const
{
hypre_ParVectorPrint(x,fname);
hypre_ParVectorPrint(x, fname.c_str());
}
void HypreParVector::Read(MPI_Comm comm, const char *fname)
void HypreParVector::Read(MPI_Comm comm, const std::string &fname)
{
if (own_ParVector)
{
hypre_ParVectorDestroy(x);
}
data.Delete();
x = hypre_ParVectorRead(comm, fname);
x = hypre_ParVectorRead(comm, fname.c_str());
own_ParVector = true;
_SetDataAndSize_();
}
@@ -792,6 +792,44 @@ static void SyncBackBoolCSR(Table *bool_csr, MemoryIJData &mem_csr)
}
}
/// @brief Return the size of the partitioning arrays, see @ref
/// hypre_partitioning_descr.
static int GetPartitioningArraySize(MPI_Comm comm)
{
if (HYPRE_AssumedPartitionCheck())
{
return 2;
}
else
{
int comm_size;
MPI_Comm_size(comm, &comm_size);
return comm_size + 1;
}
}
/// @brief Returns true if the row and col arrays are equal (across all MPI
/// ranks).
///
/// Both @a row and @a col are partitioning arrays, whose length is returned by
/// GetPartitioningArraySize(), see @ref hypre_partitioning_descr.
static bool RowAndColStartsAreEqual(MPI_Comm comm, HYPRE_BigInt *rows,
HYPRE_BigInt *cols)
{
const int part_size = GetPartitioningArraySize(comm);
bool are_equal = true;
for (int i = 0; i < part_size; ++i)
{
if (rows[i] != cols[i])
{
are_equal = false;
break;
}
}
MPI_Allreduce(MPI_IN_PLACE, &are_equal, 1, MPI_C_BOOL, MPI_LAND, comm);
return are_equal;
}
// static method
signed char HypreParMatrix::HypreCsrToMem(hypre_CSRMatrix *h_mat,
MemoryType h_mat_mt,
@@ -924,7 +962,7 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
hypre_ParCSRMatrixSetNumNonzeros(A);
/* Make sure that the first entry in each row is the diagonal one. */
if (row_starts == col_starts)
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
{
HypreReadWrite();
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
@@ -974,11 +1012,12 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
hypre_ParCSRMatrixSetNumNonzeros(A);
/* Make sure that the first entry in each row is the diagonal one. */
if (row_starts == col_starts)
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
{
HypreReadWrite();
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
SyncBackCSR(diag, mem_diag); // update diag, if needed
// update diag, if needed
if (!own_diag_offd) { SyncBackCSR(diag, mem_diag); }
}
hypre_MatvecCommPkgCreate(A);
@@ -1031,7 +1070,7 @@ HypreParMatrix::HypreParMatrix(
hypre_ParCSRMatrixSetNumNonzeros(A);
/* Make sure that the first entry in each row is the diagonal one. */
if (row_starts == col_starts)
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
{
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
}
@@ -1093,7 +1132,7 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
hypre_CSRMatrixDestroy(csr_a);
/* Make sure that the first entry in each row is the diagonal one. */
if (row_starts == col_starts)
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
{
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(new_A));
}
@@ -1132,7 +1171,7 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
hypre_ParCSRMatrixSetNumNonzeros(A);
/* Make sure that the first entry in each row is the diagonal one. */
if (row_starts == col_starts)
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
{
HypreReadWrite();
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
@@ -1247,11 +1286,10 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
Init();
// Determine partitioning size, and my column start and end
int part_size;
const int part_size = GetPartitioningArraySize(comm);
HYPRE_BigInt my_col_start, my_col_end; // my range: [my_col_start, my_col_end)
if (HYPRE_AssumedPartitionCheck())
{
part_size = 2;
my_col_start = cols[0];
my_col_end = cols[1];
}
@@ -1259,15 +1297,14 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
{
int myid;
MPI_Comm_rank(comm, &myid);
MPI_Comm_size(comm, &part_size);
part_size++;
my_col_start = cols[myid];
my_col_end = cols[myid+1];
}
// Copy in the row and column partitionings
const bool rows_eq_cols = RowAndColStartsAreEqual(comm, rows, cols);
HYPRE_BigInt *row_starts, *col_starts;
if (rows == cols)
if (rows_eq_cols)
{
row_starts = col_starts = mfem_hypre_TAlloc_host(HYPRE_BigInt, part_size);
for (int i = 0; i < part_size; i++)
@@ -1360,14 +1397,14 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
}
hypre_ParCSRMatrixSetNumNonzeros(A);
/* Make sure that the first entry in each row is the diagonal one. */
if (row_starts == col_starts)
// Make sure that the first entry in each row is the diagonal one.
if (rows_eq_cols)
{
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
}
#if MFEM_HYPRE_VERSION > 22200
mfem_hypre_TFree_host(row_starts);
if (rows != cols)
if (!rows_eq_cols)
{
mfem_hypre_TFree_host(col_starts);
}
@@ -1480,16 +1517,7 @@ void HypreParMatrix::CopyRowStarts()
return;
}
int row_starts_size;
if (HYPRE_AssumedPartitionCheck())
{
row_starts_size = 2;
}
else
{
MPI_Comm_size(hypre_ParCSRMatrixComm(A), &row_starts_size);
row_starts_size++; // num_proc + 1
}
const int row_starts_size = GetPartitioningArraySize(hypre_ParCSRMatrixComm(A));
HYPRE_BigInt *old_row_starts = hypre_ParCSRMatrixRowStarts(A);
HYPRE_BigInt *new_row_starts = mfem_hypre_CTAlloc_host(HYPRE_BigInt,
@@ -1520,16 +1548,7 @@ void HypreParMatrix::CopyColStarts()
return;
}
int col_starts_size;
if (HYPRE_AssumedPartitionCheck())
{
col_starts_size = 2;
}
else
{
MPI_Comm_size(hypre_ParCSRMatrixComm(A), &col_starts_size);
col_starts_size++; // num_proc + 1
}
const int col_starts_size = GetPartitioningArraySize(hypre_ParCSRMatrixComm(A));
HYPRE_BigInt *old_col_starts = hypre_ParCSRMatrixColStarts(A);
HYPRE_BigInt *new_col_starts = mfem_hypre_CTAlloc_host(HYPRE_BigInt,
@@ -2291,13 +2310,8 @@ void HypreParMatrix::Threshold(real_t threshold)
A = parcsr_A_ptr;
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
// Make sure that the first entry in each row is the diagonal one.
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
{
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
}
@@ -2623,48 +2637,38 @@ void HypreParMatrix::EliminateBC(const Array<int> &ess_dofs,
mfem_hypre_TFree(eliminate_col);
}
void HypreParMatrix::Print(const char *fname, HYPRE_Int offi,
void HypreParMatrix::Print(const std::string &fname, HYPRE_Int offi,
HYPRE_Int offj) const
{
HostRead();
hypre_ParCSRMatrixPrintIJ(A,offi,offj,fname);
hypre_ParCSRMatrixPrintIJ(A, offi, offj, fname.c_str());
HypreRead();
}
void HypreParMatrix::Read(MPI_Comm comm, const char *fname)
void HypreParMatrix::Read(MPI_Comm comm, const std::string &fname)
{
Destroy();
Init();
HYPRE_ParCSRMatrix A_parcsr;
HYPRE_Int base_i, base_j;
hypre_ParCSRMatrixReadIJ(comm, fname, &base_i, &base_j, &A);
hypre_ParCSRMatrixReadIJ(comm, fname.c_str(), &base_i, &base_j, &A_parcsr);
WrapHypreParCSRMatrix(A_parcsr, true);
hypre_ParCSRMatrixSetNumNonzeros(A);
if (!hypre_ParCSRMatrixCommPkg(A)) { hypre_MatvecCommPkgCreate(A); }
height = GetNumRows();
width = GetNumCols();
}
void HypreParMatrix::Read_IJMatrix(MPI_Comm comm, const char *fname)
void HypreParMatrix::Read_IJMatrix(MPI_Comm comm, const std::string &fname)
{
Destroy();
Init();
HYPRE_IJMatrix A_ij;
HYPRE_IJMatrixRead(fname, comm, 5555, &A_ij); // HYPRE_PARCSR = 5555
HYPRE_IJMatrixRead(fname.c_str(), comm, 5555, &A_ij); // HYPRE_PARCSR = 5555
HYPRE_ParCSRMatrix A_parcsr;
HYPRE_IJMatrixGetObject(A_ij, (void**) &A_parcsr);
A = (hypre_ParCSRMatrix*)A_parcsr;
WrapHypreParCSRMatrix(A_parcsr, true);
hypre_ParCSRMatrixSetNumNonzeros(A);
if (!hypre_ParCSRMatrixCommPkg(A)) { hypre_MatvecCommPkgCreate(A); }
height = GetNumRows();
width = GetNumCols();
}
void HypreParMatrix::PrintCommPkg(std::ostream &os) const
+8 -6
View File
@@ -364,10 +364,10 @@ public:
HYPRE_Int Randomize(HYPRE_Int seed);
/// Prints the locally owned rows in parallel
void Print(const char *fname) const;
void Print(const std::string &fname) const;
/// Reads a HypreParVector from files saved with HypreParVector::Print
void Read(MPI_Comm comm, const char *fname);
void Read(MPI_Comm comm, const std::string &fname);
/// Calls hypre's destroy function
~HypreParVector();
@@ -919,12 +919,14 @@ public:
const Memory<HYPRE_Int> &GetDiagMemoryJ() const { return mem_diag.J; }
const Memory<real_t> &GetDiagMemoryData() const { return mem_diag.data; }
/// Prints the locally owned rows in parallel
void Print(const char *fname, HYPRE_Int offi = 0, HYPRE_Int offj = 0) const;
/// @brief Prints the locally owned rows in parallel. The resulting files can
/// be read with Read_IJMatrix().
void Print(const std::string &fname, HYPRE_Int offi = 0,
HYPRE_Int offj = 0) const;
/// Reads the matrix from a file
void Read(MPI_Comm comm, const char *fname);
void Read(MPI_Comm comm, const std::string &fname);
/// Read a matrix saved as a HYPRE_IJMatrix
void Read_IJMatrix(MPI_Comm comm, const char *fname);
void Read_IJMatrix(MPI_Comm comm, const std::string &fname);
/// Print information about the hypre_ParCSRCommPkg of the HypreParMatrix.
void PrintCommPkg(std::ostream &out = mfem::out) const;
+141
View File
@@ -0,0 +1,141 @@
// Copyright (c) 2010-2024, 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_LAPACK_HPP
#define MFEM_LAPACK_HPP
#include "../config/config.hpp"
#ifdef MFEM_USE_LAPACK
#ifdef MFEM_USE_SINGLE
#define MFEM_LAPACK_PREFIX(stub) s##stub
#define MFEM_LAPACK_COMPLEX(stub) c##stub
#elif defined(MFEM_USE_DOUBLE)
#define MFEM_LAPACK_PREFIX(stub) d##stub
#define MFEM_LAPACK_COMPLEX(stub) z##stub
#endif
namespace mfem
{
extern "C" void
MFEM_LAPACK_PREFIX(gemm_)(char *, char *, int *, int *, int *, real_t *,
real_t *, int *, real_t *, int *, real_t *, real_t *,
int *);
extern "C" void
MFEM_LAPACK_PREFIX(getrf_)(int *, int *, real_t *, int *, int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(getrs_)(char *, int *, int *, real_t *, int *, int *,
real_t *, int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(getri_)(int *N, real_t *A, int *LDA, int *IPIV, real_t *WORK,
int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(syevr_)(char *JOBZ, char *RANGE, char *UPLO, int *N,
real_t *A, int *LDA, real_t *VL, real_t *VU, int *IL,
int *IU, real_t *ABSTOL, int *M, real_t *W,
real_t *Z, int *LDZ, int *ISUPPZ, real_t *WORK,
int *LWORK, int *IWORK, int *LIWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(syev_)(char *JOBZ, char *UPLO, int *N, real_t *A, int *LDA,
real_t *W, real_t *WORK, int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(sygv_) (int *ITYPE, char *JOBZ, char *UPLO, int * N,
real_t *A, int *LDA, real_t *B, int *LDB, real_t *W,
real_t *WORK, int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(sygvx_)(int *ITYPE, char *JOBZ, char *RANGE, char *UPLO,
int *N, double *A, int *LDA, double *B, int *LDB,
double *VL, double *VU, int *IL, int *IU,
double *ABSTOL, int *M, double *W, double *Z,
int *LDZ, double *WORK, int *LWORK,int *IWORK,
int *IFAIL, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(gesvd_)(char *JOBU, char *JOBVT, int *M, int *N, real_t *A,
int *LDA, real_t *S, real_t *U, int *LDU, real_t *VT,
int *LDVT, real_t *WORK, int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(trsm_)(char *side, char *uplo, char *transa, char *diag,
int *m, int *n, real_t *alpha, real_t *a, int *lda,
real_t *b, int *ldb);
extern "C" void
MFEM_LAPACK_PREFIX(ggev_)(char *jobvl, char *jobvr, int *n, real_t *a, int *lda,
real_t *B, int *ldb, real_t *alphar, real_t *alphai,
real_t *beta, real_t *vl, int * ldvl, real_t * vr,
int * ldvr, real_t * work, int * lwork, int* info);
// Cholesky factorizations/solves
extern "C" void
MFEM_LAPACK_PREFIX(potrf_)(char *, int *, real_t *, int *, int *);
// Solve
extern "C" void
MFEM_LAPACK_PREFIX(potrs_)(char *, int *, int *, real_t *, int *, real_t *,
int *, int *);
// Triangular Solves
extern "C" void
MFEM_LAPACK_PREFIX(trtrs_)(char *, char*, char *, int *, int *, real_t *, int *,
real_t *, int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(potri_)(char *, int *, real_t *, int*, int *);
// LAPACK routines for NNLSSolver
extern "C" void
MFEM_LAPACK_PREFIX(ormqr_)(char *, char *, int *, int *, int *, real_t *, int*,
real_t *, real_t *, int *, real_t *, int*, int*);
extern "C" void
MFEM_LAPACK_PREFIX(geqrf_)(int *, int *, real_t *, int *, real_t *, real_t *,
int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(gemv_)(char *, int *, int *, real_t *, real_t *, int *,
real_t *, int *, real_t *, real_t *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(trsm_)(char *side, char *uplo, char *transa, char *diag,
int *m, int *n, real_t *alpha, real_t *a, int *lda,
real_t *b, int *ldb);
// Complex
extern "C" void
MFEM_LAPACK_COMPLEX(getrf_)(int *, int *, std::complex<real_t> *, int *, int *,
int *);
extern "C" void
MFEM_LAPACK_COMPLEX(getrs_)(char *, int *, int *, std::complex<real_t> *, int *,
int *, std::complex<real_t> *, int *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(getri_)(int *, std::complex<real_t> *, int *, int *,
std::complex<real_t> *, int *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(trsm_)(char *, char *, char *, char *, int *, int *,
std::complex<real_t> *, std::complex<real_t> *,
int *, std::complex<real_t> *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(potrf_)(char *, int *, std::complex<real_t> *, int *,
int *);
extern "C" void
MFEM_LAPACK_COMPLEX(trtrs_)(char *, char*, char *, int *, int *,
std::complex<real_t> *, int *,
std::complex<real_t> *, int *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(potri_)(char *, int *, std::complex<real_t> *, int*, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(potrs_)(char *, int *, int *, std::complex<real_t> *, int *,
std::complex<real_t> *, int *, int *);
}
#endif
#endif
+130 -52
View File
@@ -309,18 +309,51 @@ public:
/// Base abstract class for first order time dependent operators.
/** Operator of the form: (x,t) -> f(x,t), where k = f(x,t) generally solves the
algebraic equation F(x,k,t) = G(x,t). The functions F and G represent the
_implicit_ and _explicit_ parts of the operator, respectively. For explicit
operators, F(x,k,t) = k, so f(x,t) = G(x,t). */
/** Operator of the form: (u,t) -> k(u,t), where k generally solves the
algebraic equation F(u,k,t) = G(u,t). The functions F and G represent the
_implicit_ and _explicit_ parts of the operator, respectively.
A common use for this class is representing a differential algebraic
equation of the form $ F(y,\frac{dy}{dt},t) = G(y,t) $.
For example, consider an ordinary differential equation of the form
$ M \frac{dy}{dt} = g(y,t) $. There are various ways of expressing this ODE
as a TimeDependentOperator depending on the choices for F and G. Here are
some common choices:
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t),
2. F(u,k,t) = M k and G(u,t) = g(u,t),
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0.
Note that depending on the ODE solver, some of the above choices may be
preferable to the others.
*/
class TimeDependentOperator : public Operator
{
public:
/// Enum used to describe the form of the time-dependent operator.
/** The type should be set by classes derived from TimeDependentOperator to
describe the form, in terms of the functions F and G, used by the
specific derived class. This information can be queried by classes or
functions (like time stepping algorithms) to make choices about the
algorithm to use, or to ensure that the TimeDependentOperator uses the
form expected by the class/function.
For example, assume that a derived class is implementing the ODE
$M \frac{dy}{dt} = g(y,t)$ and chooses to define $F(u,k,t) = M k$ and
$G(u,t) = g(u,t)$. Then it cannot use type EXPLICIT, unless $M = I$, or
type HOMOGENEOUS, unless $g(u,t) = 0$. If, on the other hand, the derived
class chooses to define $F(u,k,t) = k$ and $G(u,t) = M^{-1} g(y,t)$, then
the natural choice is to set the type to EXPLICIT, even though setting it
to IMPLICIT is also not wrong -- doing so will simply fail to inform
methods that query this information that it uses a more specific
implementation, EXPLICIT, that may allow the use of algorithms that
support only the EXPLICIT type. */
enum Type
{
EXPLICIT, ///< This type assumes F(x,k,t) = k, i.e. k = f(x,t) = G(x,t).
EXPLICIT, ///< This type assumes F(u,k,t) = k.
IMPLICIT, ///< This is the most general type, no assumptions on F and G.
HOMOGENEOUS ///< This type assumes that G(x,t) = 0.
HOMOGENEOUS ///< This type assumes that G(u,t) = 0.
};
/// Evaluation mode. See SetEvalMode() for details.
@@ -328,29 +361,30 @@ public:
{
/** Normal evaluation. */
NORMAL,
/** Assuming additive split, f(x,t) = f1(x,t) + f2(x,t), evaluate the
first term, f1. */
/** Assuming additive split, k(u,t) = k1(u,t) + k2(u,t), evaluate the
first term, k1. */
ADDITIVE_TERM_1,
/** Assuming additive split, f(x,t) = f1(x,t) + f2(x,t), evaluate the
second term, f2. */
/** Assuming additive split, k(u,t) = k1(u,t) + k2(u,t), evaluate the
second term, k2. */
ADDITIVE_TERM_2
};
protected:
real_t t; ///< Current time.
Type type; ///< Describes the form of the TimeDependentOperator.
Type type; /**< @brief Describes the form of the TimeDependentOperator, see
the documentation of #Type. */
EvalMode eval_mode; ///< Current evaluation mode.
public:
/** @brief Construct a "square" TimeDependentOperator y = f(x,t), where x and
y have the same dimension @a n. */
/** @brief Construct a "square" TimeDependentOperator (u,t) -> k(u,t), where
u and k have the same dimension @a n. */
explicit TimeDependentOperator(int n = 0, real_t t_ = 0.0,
Type type_ = EXPLICIT)
: Operator(n) { t = t_; type = type_; eval_mode = NORMAL; }
/** @brief Construct a TimeDependentOperator y = f(x,t), where x and y have
dimensions @a w and @a h, respectively. */
TimeDependentOperator(int h, int w, real_t t_ = 0.0, Type type_ = EXPLICIT)
/** @brief Construct a TimeDependentOperator (u,t) -> k(u,t), where u and k
have dimensions @a w and @a h, respectively. */
TimeDependentOperator(int h, int w, double t_ = 0.0, Type type_ = EXPLICIT)
: Operator(h, w) { t = t_; type = type_; eval_mode = NORMAL; }
/// Read the currently set time.
@@ -373,7 +407,7 @@ public:
/** The evaluation mode is a switch that allows time-stepping methods to
request evaluation of separate components/terms of the time-dependent
operator. For example, IMEX methods typically assume additive split of
the operator: f(x,t) = f1(x,t) + f2(x,t) and they rely on the ability to
the operator: k(u,t) = k1(u,t) + k2(u,t) and they rely on the ability to
evaluate the two terms separately.
Generally, setting the evaluation mode should affect the behavior of all
@@ -384,62 +418,104 @@ public:
{ eval_mode = new_eval_mode; }
/** @brief Perform the action of the explicit part of the operator, G:
@a y = G(@a x, t) where t is the current time.
@a v = G(@a u, t) where t is the current time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual. */
virtual void ExplicitMult(const Vector &x, Vector &y) const;
virtual void ExplicitMult(const Vector &u, Vector &v) const;
/** @brief Perform the action of the implicit part of the operator, F:
@a y = F(@a x, @a k, t) where t is the current time.
@a v = F(@a u, @a k, t) where t is the current time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual.*/
virtual void ImplicitMult(const Vector &x, const Vector &k, Vector &y) const;
virtual void ImplicitMult(const Vector &u, const Vector &k, Vector &v) const;
/** @brief Perform the action of the operator: @a y = k = f(@a x, t), where
k solves the algebraic equation F(@a x, k, t) = G(@a x, t) and t is the
current time. */
virtual void Mult(const Vector &x, Vector &y) const;
/** @brief Perform the action of the operator (u,t) -> k(u,t) where t is the
current time set by SetTime() and @a k satisfies
F(@a u, @a k, t) = G(@a u, t).
/** @brief Solve the equation: @a k = f(@a x + @a dt @a k, t), for the
unknown @a k at the current time t.
For solving an ordinary differential equation of the form
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined in
various ways, e.g.:
For general F and G, the equation for @a k becomes:
F(@a x + @a dt @a k, @a k, t) = G(@a x + @a dt @a k, t).
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
2. F(u,k,t) = M k and G(u,t) = g(u,t)
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0.
The input vector @a x corresponds to time index (or cycle) n, while the
currently set time, #t, and the result vector @a k correspond to time
index n+1. The time step @a dt corresponds to the time interval between
cycles n and n+1.
Regardless of the choice of F and G, this function should always compute
@a k = inv(M) g(@a u, t). */
virtual void Mult(const Vector &u, Vector &v) const override;
This method allows for the abstract implementation of some time
integration methods, including diagonal implicit Runge-Kutta (DIRK)
methods and the backward Euler method in particular.
/** @brief Solve for the unknown @a k, at the current time t, the following
equation:
F(@a u + @a gamma @a k, @a k, t) = G(@a u + @a gamma @a k, t).
For solving an ordinary differential equation of the form
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined in
various ways, e.g.:
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
2. F(u,k,t) = M k and G(u,t) = g(u,t)
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
Regardless of the choice of F and G, this function should solve for @a k
in M @a k = g(@a u + @a gamma @a k, t).
To see how @a k can be useful, consider the backward Euler method defined
by $ y(t + \Delta t) = y(t) + \Delta t k_0 $ where
$ M k_0 = g \big( y(t) + \Delta t k_0, t + \Delta t \big) $. A backward
Euler integrator can use @a k from this function for $k_0$, with the call
using @a u set to $ y(t) $, @a gamma set to $ \Delta t$, and time set to
$t + \Delta t$. See class BackwardEulerSolver.
Generalizing further, consider a diagonally implicit Runge-Kutta (DIRK)
method defined by
$ y(t + \Delta t) = y(t) + \Delta t \sum_{i=1}^s b_i k_i $ where
$ M k_i = g \big( y(t) + \Delta t \sum_{j=1}^i a_{ij} k_j,
t + c_i \Delta t \big) $.
A DIRK integrator can use @a k from this function, with @a u set to
$ y(t) + \Delta t \sum_{j=1}^{i-1} a_{ij} k_j $ and @a gamma set to
$ a_{ii} \Delta t $, for $ k_i $. For example, see class SDIRK33Solver.
If not re-implemented, this method simply generates an error. */
virtual void ImplicitSolve(const real_t dt, const Vector &x, Vector &k);
virtual void ImplicitSolve(const real_t gamma, const Vector &u, Vector &k);
/** @brief Return an Operator representing (dF/dk @a shift + dF/dx) at the
given @a x, @a k, and the currently set time.
/** @brief Return an Operator representing (dF/dk @a shift + dF/du) at the
given @a u, @a k, and the currently set time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual. */
virtual Operator& GetImplicitGradient(const Vector &x, const Vector &k,
virtual Operator& GetImplicitGradient(const Vector &u, const Vector &k,
real_t shift) const;
/** @brief Return an Operator representing dG/dx at the given point @a x and
/** @brief Return an Operator representing dG/du at the given point @a u and
the currently set time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual. */
virtual Operator& GetExplicitGradient(const Vector &x) const;
virtual Operator& GetExplicitGradient(const Vector &u) const;
/** @brief Setup the ODE linear system $ A(x,t) = (I - gamma J) $ or
$ A = (M - gamma J) $, where $ J(x,t) = \frac{df}{dt(x,t)} $.
/** @brief Setup a linear system as needed by some SUNDIALS ODE solvers.
@param[in] x The state at which $A(x,t)$ should be evaluated.
@param[in] fx The current value of the ODE rhs function, $f(x,t)$.
For solving an ordinary differential equation of the form
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined as one
of the following:
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
2. F(u,k,t) = M k and G(u,t) = g(u,t)
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
This function performs setup to solve $ A x = b $ where A is either
1. A(@a y,t) = I - @a gamma inv(M) J(@a y,t)
2. A(@a y,t) = M - @a gamma J(@a y,t)
3. A(@a y,t) = M - @a gamma J(@a y,t)
with J = dg/dy (or a reasonable approximation thereof).
@param[in] y The state at which A(@a y,t) should be evaluated.
@param[in] v The value of inv(M) g(y,t) for 1 or g(y,t) for 2 & 3.
@param[in] jok Flag indicating if the Jacobian should be updated.
@param[out] jcur Flag to signal if the Jacobian was updated.
@param[in] gamma The scaled time step value.
@@ -448,10 +524,10 @@ public:
Presently, this method is used by SUNDIALS ODE solvers, for more
details, see the SUNDIALS User Guides. */
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
virtual int SUNImplicitSetup(const Vector &y, const Vector &v,
int jok, int *jcur, real_t gamma);
/** @brief Solve the ODE linear system $ A x = b $ as setup by
/** @brief Solve the ODE linear system A @a x = @a b, where A is defined by
the method SUNImplicitSetup().
@param[in] b The linear system right-hand side.
@@ -464,7 +540,8 @@ public:
details, see the SUNDIALS User Guides. */
virtual int SUNImplicitSolve(const Vector &b, Vector &x, real_t tol);
/** @brief Setup the mass matrix in the ODE system $ M y' = f(y,t) $ .
/** @brief Setup the mass matrix in the ODE system
$ M \frac{dy}{dt} = g(y,t) $ .
If not re-implemented, this method simply generates an error.
@@ -472,8 +549,8 @@ public:
details, see the ARKode User Guide. */
virtual int SUNMassSetup();
/** @brief Solve the mass matrix linear system $ M x = b $
as setup by the method SUNMassSetup().
/** @brief Solve the mass matrix linear system M @a x = @a b, where M is
defined by the method SUNMassSetup().
@param[in] b The linear system right-hand side.
@param[in,out] x On input, the initial guess. On output, the solution.
@@ -485,7 +562,8 @@ public:
details, see the ARKode User Guide. */
virtual int SUNMassSolve(const Vector &b, Vector &x, real_t tol);
/** @brief Compute the mass matrix-vector product $ v = M x $ .
/** @brief Compute the mass matrix-vector product @a v = M @a x, where M is
defined by the method SUNMassSetup().
@param[in] x The vector to multiply.
@param[out] v The result of the matrix-vector product.
+53 -138
View File
@@ -10,6 +10,7 @@
// CONTRIBUTING.md for details.
#include "linalg.hpp"
#include "lapack.hpp"
#include "../general/annotation.hpp"
#include "../general/forall.hpp"
#include "../general/globals.hpp"
@@ -3543,38 +3544,6 @@ void AuxSpaceSmoother::Mult(const Vector &x, Vector &y, bool transpose) const
#endif // MFEM_USE_MPI
#ifdef MFEM_USE_LAPACK
// LAPACK routines for NNLSSolver
#ifdef MFEM_USE_SINGLE
extern "C" void
sormqr_(char *, char *, int *, int *, int *, float *, int*, float *,
float *, int *, float *, int*, int*);
extern "C" void
sgeqrf_(int *, int *, float *, int *, float *, float *, int *, int *);
extern "C" void
sgemv_(char *, int *, int *, float *, float *, int *, float *, int *,
float *, float *, int *);
extern "C" void
strsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n,
float *alpha, float *a, int *lda, float *b, int *ldb);
#elif defined MFEM_USE_DOUBLE
extern "C" void
dormqr_(char *, char *, int *, int *, int *, double *, int*, double *,
double *, int *, double *, int*, int*);
extern "C" void
dgeqrf_(int *, int *, double *, int *, double *, double *, int *, int *);
extern "C" void
dgemv_(char *, int *, int *, double *, double *, int *, double *, int *,
double *, double *, int *);
extern "C" void
dtrsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n,
double *alpha, double *a, int *lda, double *b, int *ldb);
#endif
NNLSSolver::NNLSSolver()
: Solver(0), mat(nullptr), const_tol_(1.0e-14), min_nnz_(0),
@@ -3938,25 +3907,19 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
lwork = -1;
work.resize(10);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m), &m,
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &n_update,
&i_qr_start, mat_qr_data.GetData(), &m,
tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m),
&m, work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T A update work calculation failed
lwork = static_cast<int>(work[0]);
work.resize(lwork);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m), &m,
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &n_update,
&i_qr_start, mat_qr_data.GetData(), &m,
tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m),
&m, work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T A update failed
// Compute QR factorization of the submatrix
lwork = -1;
@@ -3977,24 +3940,16 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
sub_tau[j] = tau[i_qr_start + j];
}
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m_update, &n_update,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m_update, &n_update,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(geqrf_)(&m_update, &n_update, submat_data.GetData(),
&m_update, sub_tau.GetData(), work.data(),
&lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR update factorization work calc
lwork = static_cast<int>(work[0]);
if (lwork == 0) { lwork = 1; }
work.resize(lwork);
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m_update, &n_update,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m_update, &n_update,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(geqrf_)(&m_update, &n_update, submat_data.GetData(),
&m_update, sub_tau.GetData(), work.data(),
&lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR update factorization failed
// Copy result back
@@ -4023,23 +3978,13 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
// perform qr)
lwork = -1;
work.resize(10);
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m, &n_glob,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(geqrf_)(&m, &n_glob, mat_qr_data.GetData(), &m,
tau.GetData(), work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR factorization work calculation
lwork = static_cast<int>(work[0]);
work.resize(lwork);
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m, &n_glob,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(geqrf_)(&m, &n_glob, mat_qr_data.GetData(), &m,
tau.GetData(), work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR factorization failed
}
@@ -4067,25 +4012,17 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
sub_tau[0] = tau[i_qr_start];
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m_update, &ione, &ione,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m_update, &ione, &ione,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
sub_qt.GetData(), &m_update,
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m_update, &ione, &ione,
submat_data.GetData(), &m_update,
sub_tau.GetData(), sub_qt.GetData(),
&m_update, work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // H_last y work calculation failed
lwork = static_cast<int>(work[0]);
work.resize(lwork);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m_update, &ione, &ione,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m_update, &ione, &ione,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
sub_qt.GetData(), &m_update,
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m_update, &ione, &ione,
submat_data.GetData(), &m_update,
sub_tau.GetData(), sub_qt.GetData(),
&m_update, work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // H_last y failed
// Copy result back
for (int i=0; i<m_update; ++i)
@@ -4099,25 +4036,17 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
qt_rhs_glob = rhs_avg_glob;
lwork = -1;
work.resize(10);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &ione, &n_glob,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &ione, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T b work calculation failed
lwork = static_cast<int>(work[0]);
work.resize(lwork);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &ione, &n_glob,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &ione, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T b failed
}
@@ -4130,14 +4059,10 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
char upper = 'U';
char nounit = 'N';
vec1 = qt_rhs_glob;
#ifdef MFEM_USE_SINGLE
strsm_(&lside, &upper, &notrans, &nounit,
#elif defined MFEM_USE_DOUBLE
dtrsm_(&lside, &upper, &notrans, &nounit,
#endif
&n_glob, &ione, &fone,
mat_qr_data.GetData(), &m,
vec1.GetData(), &n_glob);
MFEM_LAPACK_PREFIX(trsm_)(&lside, &upper, &notrans, &nounit,
&n_glob, &ione, &fone,
mat_qr_data.GetData(), &m,
vec1.GetData(), &n_glob);
if (verbosity_ > 2)
{
@@ -4360,14 +4285,10 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
{
res_glob = rhs_avg_glob;
real_t fmone = -1.0;
#ifdef MFEM_USE_SINGLE
sgemv_(&notrans, &m, &n_glob, &fmone,
#elif defined MFEM_USE_DOUBLE
dgemv_(&notrans, &m, &n_glob, &fmone,
#endif
mat_0_data.GetData(), &m,
soln_nz_glob.GetData(), &ione, &fone,
res_glob.GetData(), &ione);
MFEM_LAPACK_PREFIX(gemv_)(&notrans, &m, &n_glob, &fmone,
mat_0_data.GetData(), &m,
soln_nz_glob.GetData(), &ione, &fone,
res_glob.GetData(), &ione);
}
else
{
@@ -4381,24 +4302,18 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
qqt_rhs_glob(i) = qt_rhs_glob(i);
}
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#endif
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &notrans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m,
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q Q^T b work calculation failed.
lwork = static_cast<int>(work[0]);
work.resize(lwork);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#endif
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &notrans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m,
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q Q^T b calculation failed.
res_glob = rhs_avg_glob;
res_glob -= qqt_rhs_glob;
+14 -5
View File
@@ -58,6 +58,20 @@ DenseSymmetricMatrix &DenseSymmetricMatrix::operator=(real_t c)
return *this;
}
DenseSymmetricMatrix &DenseSymmetricMatrix::operator=(const DenseSymmetricMatrix
&m)
{
SetSize(m.height);
const int hw = m.GetStoredSize();
for (int i = 0; i < hw; i++)
{
data[i] = m.data[i];
}
return *this;
}
real_t &DenseSymmetricMatrix::Elem(int i, int j)
{
return (*this)(i,j);
@@ -89,11 +103,6 @@ MatrixInverse *DenseSymmetricMatrix::Inverse() const
return nullptr;
}
void DenseSymmetricMatrix::Print (std::ostream & os, int width_) const
{
mfem_error("DenseSymmetricMatrix::Print() not implemented!");
}
DenseSymmetricMatrix::~DenseSymmetricMatrix()
{
data.Delete();
+3 -3
View File
@@ -102,6 +102,9 @@ public:
DenseSymmetricMatrix &operator*=(real_t c);
/// Sets the matrix size and elements equal to those of m
DenseSymmetricMatrix &operator=(const DenseSymmetricMatrix &m);
std::size_t MemoryUsage() const { return data.Capacity() * sizeof(real_t); }
/// Shortcut for mfem::Read( GetMemory(), TotalSize(), on_dev).
@@ -134,9 +137,6 @@ public:
/// Returns a pointer to (an approximation) of the matrix inverse.
virtual MatrixInverse *Inverse() const;
/// Prints matrix to stream out.
virtual void Print (std::ostream & out = mfem::out, int width_ = 4) const;
/// Destroys the symmetric matrix.
virtual ~DenseSymmetricMatrix();
};
+43 -11
View File
@@ -466,7 +466,8 @@ void Mesh::GetBdrElementTransformation(int i,
{
for (int j = 0; j < n; j++)
{
pm(k,j) = nodes(vdofs[n*k+j]);
int idx = vdofs[n*k+j];
pm(k,j) = nodes((idx<0)? -1-idx:idx);
}
}
ElTr->SetFE(bdr_el);
@@ -7131,17 +7132,15 @@ Table *Mesh::GetEdgeVertexTable() const
Table *Mesh::GetVertexToElementTable()
{
int i, j, nv, *v;
Table *vert_elem = new Table;
vert_elem->MakeI(NumOfVertices);
for (i = 0; i < NumOfElements; i++)
for (int i = 0; i < NumOfElements; i++)
{
nv = elements[i]->GetNVertices();
v = elements[i]->GetVertices();
for (j = 0; j < nv; j++)
const int nv = elements[i]->GetNVertices();
const int *v = elements[i]->GetVertices();
for (int j = 0; j < nv; j++)
{
vert_elem->AddAColumnInRow(v[j]);
}
@@ -7149,11 +7148,11 @@ Table *Mesh::GetVertexToElementTable()
vert_elem->MakeJ();
for (i = 0; i < NumOfElements; i++)
for (int i = 0; i < NumOfElements; i++)
{
nv = elements[i]->GetNVertices();
v = elements[i]->GetVertices();
for (j = 0; j < nv; j++)
const int nv = elements[i]->GetNVertices();
const int *v = elements[i]->GetVertices();
for (int j = 0; j < nv; j++)
{
vert_elem->AddConnection(v[j], i);
}
@@ -7164,6 +7163,39 @@ Table *Mesh::GetVertexToElementTable()
return vert_elem;
}
Table *Mesh::GetVertexToBdrElementTable()
{
Table *vert_bdr_elem = new Table;
vert_bdr_elem->MakeI(NumOfVertices);
for (int i = 0; i < NumOfBdrElements; i++)
{
const int nv = boundary[i]->GetNVertices();
const int *v = boundary[i]->GetVertices();
for (int j = 0; j < nv; j++)
{
vert_bdr_elem->AddAColumnInRow(v[j]);
}
}
vert_bdr_elem->MakeJ();
for (int i = 0; i < NumOfBdrElements; i++)
{
const int nv = boundary[i]->GetNVertices();
const int *v = boundary[i]->GetVertices();
for (int j = 0; j < nv; j++)
{
vert_bdr_elem->AddConnection(v[j], i);
}
}
vert_bdr_elem->ShiftUpI();
return vert_bdr_elem;
}
Table *Mesh::GetFaceToElementTable() const
{
Table *face_elem = new Table;
+6 -1
View File
@@ -857,7 +857,9 @@ public:
vectors using Mesh::CreatePeriodicVertexMapping.
@note MFEM requires that each edge of the resulting mesh be uniquely
identifiable by a pair of distinct vertices. As a consequence, periodic
boundaries must be connected by at least three edges. */
boundaries must be separated by at least two interior vertices.
@note The resulting mesh uses a discontinuous nodal function, see
SetCurvature() for further details. */
static Mesh MakePeriodic(const Mesh &orig_mesh, const std::vector<int> &v2v);
///@}
@@ -1535,6 +1537,9 @@ public:
/// @note The returned Table should be deleted by the caller
Table *GetVertexToElementTable();
/// @note The returned Table should be deleted by the caller
Table *GetVertexToBdrElementTable();
/// Return the "face"-element Table. Here "face" refers to face (3D),
/// edge (2D), or vertex (1D).
///
+16 -4
View File
@@ -1151,15 +1151,24 @@ void Mesh::ReadXML_VTKMesh(std::istream &input, int &curved, int &read_gf,
}
if (cells_xml == NULL) { MFEM_ABORT(erstr); }
// Read the element attributes, which are stored as CellData named "material"
// Read the element attributes, which are stored as CellData named either
// "material" or "attribute". We prioritize "material" over "attribute" for
// backwards compatibility.
Array<int> cell_attributes;
bool found_attributes = false;
for (const XMLElement *cell_data_xml = piece->FirstChildElement();
cell_data_xml != NULL;
cell_data_xml = cell_data_xml->NextSiblingElement())
{
if (StringCompare(cell_data_xml->Name(), "CellData")
&& StringCompare(cell_data_xml->Attribute("Scalars"), "material"))
const bool is_cell_data =
StringCompare(cell_data_xml->Name(), "CellData");
const bool is_material =
StringCompare(cell_data_xml->Attribute("Scalars"), "material");
const bool is_attribute =
StringCompare(cell_data_xml->Attribute("Scalars"), "attribute");
if (is_cell_data && (is_material || (is_attribute && !found_attributes)))
{
found_attributes = true;
const XMLElement *data_xml = cell_data_xml->FirstChildElement();
if (data_xml != NULL && StringCompare(data_xml->Name(), "DataArray"))
{
@@ -1274,6 +1283,7 @@ void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf,
// Read the cell materials
// bool found_material = false;
Array<int> cell_attributes;
bool found_attributes = false;
while ((input.good()))
{
getline(input, buff);
@@ -1281,8 +1291,10 @@ void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf,
{
break; // We have entered the POINT_DATA block. Quit.
}
else if (buff.rfind("SCALARS material") == 0)
else if (buff.rfind("SCALARS material") == 0 ||
(buff.rfind("SCALARS attribute") == 0 && !found_attributes))
{
found_attributes = true;
getline(input, buff); // LOOKUP_TABLE default
if (buff.rfind("LOOKUP_TABLE default") != 0)
{
+103 -18
View File
@@ -1857,7 +1857,7 @@ NURBSPatch *Revolve3D(NURBSPatch &patch, real_t n[], real_t ang, int times)
{
if (patch.Dim != 4)
{
mfem_error("Revolve3D(NURBSPatch &, double [], double)");
mfem_error("Revolve3D(NURBSPatch &, real_t [], real_t)");
}
int size = 1, ns;
@@ -2008,23 +2008,23 @@ NURBSExtension::NURBSExtension(std::istream &input, bool spacing)
input >> numSpacing;
for (int j = 0; j < numSpacing; j++)
{
int ki, spacingType, numIntParam, numDoubleParam;
input >> ki >> spacingType >> numIntParam >> numDoubleParam;
int ki, spacingType, numIntParam, numRealParam;
input >> ki >> spacingType >> numIntParam >> numRealParam;
MFEM_VERIFY(0 <= ki && ki < NumOfKnotVectors,
"Invalid knotvector index");
MFEM_VERIFY(numIntParam >= 0 && numDoubleParam >= 0,
MFEM_VERIFY(numIntParam >= 0 && numRealParam >= 0,
"Invalid number of parameters in KnotVector");
Array<int> ipar(numIntParam);
Vector dpar(numDoubleParam);
Vector dpar(numRealParam);
for (int i=0; i<numIntParam; ++i)
{
input >> ipar[i];
}
for (int i=0; i<numDoubleParam; ++i)
for (int i=0; i<numRealParam; ++i)
{
input >> dpar[i];
}
@@ -2064,7 +2064,7 @@ NURBSExtension::NURBSExtension(std::istream &input, bool spacing)
new KnotVector(*patches[p]->GetKV(0));
}
}
if (Dimension() == 2)
else if (Dimension() == 2)
{
patchTopo->GetElementEdges(p, edges, oedge);
if (knotVectors[KnotInd(edges[0])] == NULL)
@@ -2230,7 +2230,8 @@ NURBSExtension::NURBSExtension(NURBSExtension *parent, int newOrder)
}
NURBSExtension::NURBSExtension(NURBSExtension *parent,
const Array<int> &newOrders)
const Array<int> &newOrders, Mode mode)
: mode(mode)
{
newOrders.Copy(mOrders);
SetOrderFromOrders();
@@ -3891,7 +3892,16 @@ void NURBSExtension::GenerateBdrElementDofTable()
int ndof = bel_dof->Size_of_connections();
for (int i = 0; i < ndof; i++)
{
dof[i] = activeDof[dof[i]] - 1;
int idx = dof[i];
if (idx < 0)
{
dof[i] = -1 - (activeDof[-1-idx] - 1);
dof[i] = -activeDof[-1-idx];
}
else
{
dof[i] = activeDof[idx] - 1;
}
}
}
@@ -3943,6 +3953,22 @@ void NURBSExtension::Generate2DBdrElementDofTable()
// Load dofs
const int nks0 = kv[0]->GetNKS();
const int ord0 = kv[0]->GetOrder();
bool add_dofs = true;
int s = 1;
if (mode == Mode::H_DIV)
{
int fn = patchTopo->GetBdrElementFaceIndex(b);
if (ord0 == mOrders.Max()) { add_dofs = false; }
if (fn == 0) { s = -1; }
if (fn == 2) { s = -1; }
}
else if (mode == Mode::H_CURL)
{
if (ord0 == mOrders.Max()) { add_dofs = false; }
}
for (int i = 0; i < nks0; i++)
{
if (kv[0]->isElement(i))
@@ -3950,10 +3976,14 @@ void NURBSExtension::Generate2DBdrElementDofTable()
if (activeBdrElem[gbe])
{
Connection conn(lbe,0);
for (int ii = 0; ii <= ord0; ii++)
if (add_dofs)
{
conn.to = DofMap(p2g[(okv[0] >= 0) ? (i+ii) : (nx-i-ii)]);
bel_dof_list.Append(conn);
for (int ii = 0; ii <= ord0; ii++)
{
conn.to = DofMap(p2g[(okv[0] >= 0) ? (i+ii) : (nx-i-ii)]);
if (s == -1) { conn.to = -1 -conn.to; }
bel_dof_list.Append(conn);
}
}
bel_to_patch[lbe] = b;
bel_to_IJK(lbe,0) = (okv[0] >= 0) ? i : (-1-i);
@@ -3990,6 +4020,25 @@ void NURBSExtension::Generate3DBdrElementDofTable()
const int ord0 = kv[0]->GetOrder();
const int nks1 = kv[1]->GetNKS();
const int ord1 = kv[1]->GetOrder();
// Check if dofs are actually defined on boundary
bool add_dofs = true;
int s = 1;
if (mode == Mode::H_DIV)
{
int fn = patchTopo->GetBdrElementFaceIndex(b);
if (ord0 != ord1) { add_dofs = false; }
if (fn == 4) { s = -1; }
if (fn == 1) { s = -1; }
if (fn == 0) { s = -1; }
}
else if (mode == Mode::H_CURL)
{
if (ord0 == ord1) { add_dofs = false; }
}
for (int j = 0; j < nks1; j++)
{
if (kv[1]->isElement(j))
@@ -4001,14 +4050,18 @@ void NURBSExtension::Generate3DBdrElementDofTable()
if (activeBdrElem[gbe])
{
Connection conn(lbe,0);
for (int jj = 0; jj <= ord1; jj++)
if (add_dofs)
{
const int jj_ = (okv[1] >= 0) ? (j+jj) : (ny-j-jj);
for (int ii = 0; ii <= ord0; ii++)
for (int jj = 0; jj <= ord1; jj++)
{
const int ii_ = (okv[0] >= 0) ? (i+ii) : (nx-i-ii);
conn.to = DofMap(p2g(ii_, jj_));
bel_dof_list.Append(conn);
const int jj_ = (okv[1] >= 0) ? (j+jj) : (ny-j-jj);
for (int ii = 0; ii <= ord0; ii++)
{
const int ii_ = (okv[0] >= 0) ? (i+ii) : (nx-i-ii);
conn.to = DofMap(p2g(ii_, jj_));
if (s == -1) { conn.to = -1 -conn.to; }
bel_dof_list.Append(conn);
}
}
}
bel_to_patch[lbe] = b;
@@ -4241,6 +4294,38 @@ void NURBSExtension::DegreeElevate(int rel_degree, int degree)
}
}
NURBSExtension* NURBSExtension::GetDivExtension(int component)
{
// Smarter routine
if (GetNP() > 1)
{
mfem_error("NURBSExtension::GetDivExtension currently "
"only works for single patch NURBS meshes ");
}
Array<int> newOrders = GetOrders();
newOrders[component] += 1;
return new NURBSExtension(this, newOrders, Mode::H_DIV);
}
NURBSExtension* NURBSExtension::GetCurlExtension(int component)
{
// Smarter routine
if (GetNP() > 1)
{
mfem_error("NURBSExtension::GetCurlExtension currently "
"only works for single patch NURBS meshes ");
}
Array<int> newOrders = GetOrders();
for (int c = 0; c < newOrders.Size(); c++) { newOrders[c]++; }
newOrders[component] -= 1;
return new NURBSExtension(this, newOrders, Mode::H_CURL);
}
void NURBSExtension::UniformRefinement(Array<int> const& rf)
{
for (int p = 0; p < patches.Size(); p++)
+24 -1
View File
@@ -426,6 +426,16 @@ class NURBSExtension
friend class NURBSPatchMap;
protected:
/// Flag for indicating what type of NURBS fespace this extension is used for.
enum class Mode
{
H_1, ///> Extension for a standard scalar-valued space
H_DIV, ///> Extension for a divergence conforming vector-valued space
H_CURL, ///> Extension for a curl conforming vector-valued space
};
Mode mode = Mode::H_1;
/// Order of KnotVectors, see GetOrder() for description.
int mOrder;
@@ -655,8 +665,10 @@ public:
/** @a note If a KnotVector in @a parent already has order greater than or
equal to the corresponding entry in @a newOrder, it will be used
unmodified. */
NURBSExtension(NURBSExtension *parent, const Array<int> &newOrders);
NURBSExtension(NURBSExtension *parent, const Array<int> &newOrders,
Mode mode = Mode::H_1);
/// Construct a NURBSExtension by merging a partitioned NURBS mesh.
NURBSExtension(Mesh *mesh_array[], int num_pieces);
/// Copy assignment not supported.
@@ -841,6 +853,16 @@ public:
void KnotInsert(Array<KnotVector *> &kv);
void KnotInsert(Array<Vector *> &kv);
/** Returns the NURBSExtension to be used for @a component of
an H(div) conforming NURBS space. Caller gets ownership of
the returned object, and is responsible for deletion.*/
NURBSExtension* GetDivExtension(int component);
/** Returns the NURBSExtension to be used for @a component of
an H(curl) conforming NURBS space. Caller gets ownership of
the returned object, and is responsible for deletion.*/
NURBSExtension* GetCurlExtension(int component);
void KnotRemove(Array<Vector *> &kv, real_t tol = 1.0e-12);
/** Calls GetCoarseningFactors for each patch and finds the minimum factor
@@ -848,6 +870,7 @@ public:
non-nested spacing functions. */
void GetCoarseningFactors(Array<int> & f) const;
/// Returns the index of the patch containing element @a elem.
int GetElementPatch(int elem) const { return el_to_patch[elem]; }
+3 -3
View File
@@ -819,7 +819,7 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh,
apf::Downward verts;
apf_mesh->getDownward(ent,0,verts);
int *v, nv = 0;
int *v = nullptr, nv = 0;
apf::Mesh::Type ftype = apf_mesh->getType(ent);
if (ftype == apf::Mesh::TRIANGLE)
{
@@ -890,9 +890,9 @@ GridFunctionPumi::GridFunctionPumi(Mesh* m, apf::Mesh2* PumiM,
{
int spDim = m->SpaceDimension();
// Note: default BasisType for 'fec' is GaussLobatto.
fec = new H1_FECollection(mesh_order, m->Dimension());
fec_owned = new H1_FECollection(mesh_order, m->Dimension());
int ordering = Ordering::byVDIM; // x1y1z1/x2y2z2/...
fes = new FiniteElementSpace(m, fec, spDim, ordering);
fes = new FiniteElementSpace(m, fec_owned, spDim, ordering);
int data_size = fes->GetVSize();
// Read PUMI mesh data
+1
View File
@@ -37,3 +37,4 @@ add_subdirectory(tribol)
add_subdirectory(hooke)
add_subdirectory(dpg)
add_subdirectory(hdiv-linear-solver)
add_subdirectory(stabilized)
+5 -5
View File
@@ -15,11 +15,11 @@
//
// Sample runs
//
// acoustics -ref 4 -o 1 -rnum 1.0
// acoustics -m ../../data/inline-tri.mesh -ref 4 -o 2 -sc -rnum 3.0
// acoustics -m ../../data/amr-quad.mesh -ref 3 -o 3 -sc -rnum 4.5 -prob 1
// acoustics -m ../../data/inline-quad.mesh -ref 2 -o 4 -sc -rnum 11.5 -prob 1
// acoustics -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
// acoustics -ref 4 -o 1 -rnum 1.0
// acoustics -m ../../data/inline-tri.mesh -ref 4 -o 2 -sc -rnum 3.0
// acoustics -m ../../data/amr-quad.mesh -ref 3 -o 3 -sc -rnum 4.5 -prob 1
// acoustics -m ../../data/inline-quad.mesh -ref 2 -o 4 -sc -rnum 11.5 -prob 1
// acoustics -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
// Description:
// This example code demonstrates the use of MFEM to define and solve
+6 -6
View File
@@ -14,14 +14,14 @@
// Compile with: make convection-diffusion
//
// sample runs
// convection-diffusion -m ../../data/star.mesh -o 2 -ref 2 -theta 0.0 -eps 1e-1 -beta '2 3'
// convection-diffusion -m ../../data/beam-hex.mesh -o 2 -ref 2 -theta 0.0 -eps 1e0 -beta '1 0 2'
// convection-diffusion -m ../../data/inline-tri.mesh -o 3 -ref 2 -theta 0.0 -eps 1e-2 -beta '4 2' -sc
// convection-diffusion -m ../../data/star.mesh -o 2 -ref 2 -theta 0.0 -eps 1e-1 -beta '2 3'
// convection-diffusion -m ../../data/beam-hex.mesh -o 2 -ref 2 -theta 0.0 -eps 1e0 -beta '1 0 2'
// convection-diffusion -m ../../data/inline-tri.mesh -o 3 -ref 2 -theta 0.0 -eps 1e-2 -beta '4 2' -sc
// AMR runs
// convection-diffusion -o 3 -ref 5 -prob 1 -eps 1e-1 -theta 0.75
// convection-diffusion -o 2 -ref 9 -prob 1 -eps 1e-2 -theta 0.75
// convection-diffusion -o 3 -ref 9 -prob 1 -eps 1e-3 -theta 0.75 -sc
// convection-diffusion -o 3 -ref 5 -prob 1 -eps 1e-1 -theta 0.75
// convection-diffusion -o 2 -ref 9 -prob 1 -eps 1e-2 -theta 0.75
// convection-diffusion -o 3 -ref 9 -prob 1 -eps 1e-3 -theta 0.75 -sc
// Description:
// This example code demonstrates the use of MFEM to define and solve
+4 -4
View File
@@ -14,10 +14,10 @@
// Compile with: make maxwell
//
// Sample runs
// maxwell -m ../../data/inline-tri.mesh -ref 4 -o 1 -rnum 1.0
// maxwell -m ../../data/amr-quad.mesh -ref 3 -o 2 -rnum 1.6 -sc
// maxwell -m ../../data/inline-quad.mesh -ref 2 -o 3 -rnum 4.2 -sc
// maxwell -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
// maxwell -m ../../data/inline-tri.mesh -ref 4 -o 1 -rnum 1.0
// maxwell -m ../../data/amr-quad.mesh -ref 3 -o 2 -rnum 1.6 -sc
// maxwell -m ../../data/inline-quad.mesh -ref 2 -o 3 -rnum 4.2 -sc
// maxwell -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
// Description:
// This example code demonstrates the use of MFEM to define and solve
+11 -11
View File
@@ -15,19 +15,19 @@
//
// sample runs
// mpirun -np 4 pacoustics -o 3 -m ../../data/star.mesh -sref 1 -pref 2 -rnum 1.9 -sc -prob 0
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 1 -pref 2 -rnum 5.2 -sc -prob 1
// mpirun -np 4 pacoustics -o 4 -m ../../data/inline-tri.mesh -sref 1 -pref 2 -rnum 7.1 -sc -prob 1
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 1.9 -sc -prob 0
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 2 -pref 1 -rnum 7.1 -sc -prob 2
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 4.1 -sc -prob 2
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 7.1 -sc -prob 3
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 10.1 -sc -prob 4
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 12.1 -sc -prob 5
// mpirun -np 4 pacoustics -o 3 -m ../../data/star.mesh -sref 1 -pref 2 -rnum 1.9 -sc -prob 0
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 1 -pref 2 -rnum 5.2 -sc -prob 1
// mpirun -np 4 pacoustics -o 4 -m ../../data/inline-tri.mesh -sref 1 -pref 2 -rnum 7.1 -sc -prob 1
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 1.9 -sc -prob 0
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 2 -pref 1 -rnum 7.1 -sc -prob 2
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 4.1 -sc -prob 2
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 7.1 -sc -prob 3
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 10.1 -sc -prob 4
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 12.1 -sc -prob 5
// AMR runs
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 7 -theta 0.75 -rnum 10.1 -sc -prob 3
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 12 -theta 0.75 -rnum 20.1 -sc -prob 3
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 7 -theta 0.75 -rnum 10.1 -sc -prob 3
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 12 -theta 0.75 -rnum 20.1 -sc -prob 3
// Description:
// This example code demonstrates the use of MFEM to define and solve
+7 -7
View File
@@ -11,17 +11,17 @@
//
// MFEM Ultraweak DPG parallel example for convection-diffusion
//
// Compile with: make pconvection-diffusion
// Compile with: make pconvection-diffusion
//
// sample runs
// mpirun -np 4 pconvection-diffusion -o 2 -ref 3 -prob 0 -eps 1e-1 -beta '4 2' -theta 0.0
// mpirun -np 4 pconvection-diffusion -o 3 -ref 3 -prob 0 -eps 1e-2 -beta '2 3' -theta 0.0
// mpirun -np 4 pconvection-diffusion -m ../../data/inline-hex.mesh -o 2 -ref 1 -prob 0 -sc -eps 1e-1 -theta 0.0
// mpirun -np 4 pconvection-diffusion -o 2 -ref 3 -prob 0 -eps 1e-1 -beta '4 2' -theta 0.0
// mpirun -np 4 pconvection-diffusion -o 3 -ref 3 -prob 0 -eps 1e-2 -beta '2 3' -theta 0.0
// mpirun -np 4 pconvection-diffusion -m ../../data/inline-hex.mesh -o 2 -ref 1 -prob 0 -sc -eps 1e-1 -theta 0.0
// AMR runs
// mpirun -np 4 pconvection-diffusion -o 3 -ref 10 -prob 1 -eps 1e-3 -beta '1 0' -theta 0.7 -sc
// mpirun -np 4 pconvection-diffusion -o 3 -ref 15 -prob 2 -eps 5e-3 -theta 0.7 -sc
// mpirun -np 4 pconvection-diffusion -o 2 -ref 12 -prob 3 -eps 1e-2 -beta '1 2' -theta 0.7 -sc
// mpirun -np 4 pconvection-diffusion -o 3 -ref 10 -prob 1 -eps 1e-3 -beta '1 0' -theta 0.7 -sc
// mpirun -np 4 pconvection-diffusion -o 3 -ref 15 -prob 2 -eps 5e-3 -theta 0.7 -sc
// mpirun -np 4 pconvection-diffusion -o 2 -ref 12 -prob 3 -eps 1e-2 -beta '1 2' -theta 0.7 -sc
// Description:
// This example code demonstrates the use of MFEM to define and solve a parallel
+7 -7
View File
@@ -14,18 +14,18 @@
// Compile with: make pdiffusion
//
// Sample runs
// mpirun -np 4 pdiffusion -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 2 -theta 0.0 -prob 0
// mpirun -np 4 pdiffusion -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -theta 0.0 -prob 0 -sc
// mpirun -np 4 pdiffusion -m ../../data/beam-tet.mesh -o 3 -sref 0 -pref 2 -theta 0.0 -prob 0 -sc
// mpirun -np 4 pdiffusion -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 2 -theta 0.0 -prob 0
// mpirun -np 4 pdiffusion -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -theta 0.0 -prob 0 -sc
// mpirun -np 4 pdiffusion -m ../../data/beam-tet.mesh -o 3 -sref 0 -pref 2 -theta 0.0 -prob 0 -sc
// L-shape runs
// Note: uniform ref are expected to give sub-optimal rate for the L-shape problem (rate = 2/3)
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 5 -theta 0.0 -prob 1
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 5 -theta 0.0 -prob 1
// L-shape AMR runs
// mpirun -np 4 pdiffusion -o 1 -sref 1 -pref 10 -theta 0.8 -prob 1
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 8 -theta 0.75 -prob 1 -sc
// mpirun -np 4 pdiffusion -o 3 -sref 1 -pref 6 -theta 0.75 -prob 1 -sc -do 2
// mpirun -np 4 pdiffusion -o 1 -sref 1 -pref 10 -theta 0.8 -prob 1
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 8 -theta 0.75 -prob 1 -sc
// mpirun -np 4 pdiffusion -o 3 -sref 1 -pref 6 -theta 0.75 -prob 1 -sc -do 2
// Description:
// This example code demonstrates the use of MFEM to define and solve
+7 -7
View File
@@ -14,16 +14,16 @@
// Compile with: make pmaxwell
//
// sample run
// mpirun -np 4 pmaxwell -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4
// mpirun -np 4 pmaxwell -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4
// AMR run. Note that this is a computationally intensive sample run.
// We recommend trying it on a large machine with more mpi ranks
// mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc
// mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc
// Description:
// This example code demonstrates the use of MFEM to define and solve
+1 -1
View File
@@ -206,7 +206,7 @@ int main (int argc, char *argv[])
solver.SetMaxIter(200);
solver.SetRelTol(1e-10);
solver.SetAbsTol(0.0);
solver.EnableAdaptiveSurfaceFitting();
solver.SetAdaptiveSurfaceFittingScalingFactor(10);
solver.SetTerminationWithMaxSurfaceFittingError(1e-3);
// Solve.
+16
View File
@@ -34,6 +34,22 @@ real_t circle_level_set(const Vector &x)
}
}
real_t squircle_level_set(const Vector &x)
{
const int dim = x.Size();
if (dim == 2)
{
const real_t xc = x(0) - 0.5, yc = x(1) - 0.5;
return std::pow(xc, 4.0) + std::pow(yc, 4.0) - std::pow(0.24, 4.0);
}
else
{
const real_t xc = x(0) - 0.5, yc = x(1) - 0.5, zc = x(2) - 0.5;
return std::pow(xc, 4.0) + std::pow(yc, 4.0) +
std::pow(zc, 4.0) - std::pow(0.24, 4.0);
}
}
real_t in_circle(const Vector &x, const Vector &x_center, real_t radius)
{
Vector x_current = x;
+102 -89
View File
@@ -33,13 +33,15 @@
// Compile with: make pmesh-fitting
//
// Sample runs:
// Interface fitting:
// mpirun -np 4 pmesh-fitting -o 3 -mid 58 -tid 1 -ni 200 -vl 1 -sfc 5e4 -rtol 1e-5
// mpirun -np 4 pmesh-fitting -m square01-tri.mesh -o 3 -rs 0 -mid 58 -tid 1 -ni 200 -vl 1 -sfc 1e4 -rtol 1e-5
// Surface fitting:
// mpirun -np 4 pmesh-fitting -o 3 -mid 58 -tid 1 -vl 1 -sfc 5e4 -rtol 1e-5
// mpirun -np 4 pmesh-fitting -m square01-tri.mesh -o 3 -rs 0 -mid 58 -tid 1 -vl 1 -sfc 1e4 -rtol 1e-5
// Surface fitting with weight adaptation and termination based on fitting error:
// mpirun -np 4 pmesh-fitting -o 2 -mid 2 -tid 1 -ni 100 -vl 2 -sfc 10 -rtol 1e-20 -st 0 -sfa 10.0 -sft 1e-5
// Fitting to Fischer-Tropsch reactor like domain (requires GSLIB):
// * mpirun -np 6 pmesh-fitting -m ../../data/inline-tri.mesh -o 2 -rs 4 -mid 2 -tid 1 -vl 2 -sfc 100 -rtol 1e-12 -ni 100 -li 40 -ae 1 -bnd -sbgmesh -slstype 2 -smtype 0 -sfa 10.0 -sft 1e-4 -amriter 5 -dist -mod-bndr-attr
// mpirun -np 4 pmesh-fitting -o 2 -mid 2 -tid 1 -vl 2 -sfc 10 -rtol 1e-20 -sfa 10.0 -sft 1e-5 -no-resid
// Surface fitting with weight adaptation, limit on max weight, and convergence based on residual.
// * mpirun -np 4 pmesh-fitting -m ../../data/inline-tri.mesh -o 2 -mid 2 -tid 4 -vl 2 -sfc 10 -rtol 1e-10 -sfa 10.0 -sft 1e-5 -bgamriter 3 -sbgmesh -ae 1 -marking -slstype 3 -resid -sfcmax 10000 -mod-bndr-attr
// Surface fitting to Fischer-Tropsch reactor like domain (requires GSLIB):
// * mpirun -np 6 pmesh-fitting -m ../../data/inline-tri.mesh -o 2 -rs 4 -mid 2 -tid 1 -vl 2 -sfc 100 -rtol 1e-12 -li 20 -ae 1 -bnd -sbgmesh -slstype 2 -smtype 0 -sfa 10.0 -sft 1e-4 -no-resid -bgamriter 5 -dist -mod-bndr-attr
#include "mesh-fitting.hpp"
@@ -48,12 +50,16 @@ using namespace std;
int main (int argc, char *argv[])
{
// 0. Initialize MPI and HYPRE.
#ifdef HYPRE_USING_GPU
cout << "\nThis miniapp is NOT supported with the GPU version of hypre.\n\n";
return MFEM_SKIP_RETURN_VALUE;
#endif
Mpi::Init(argc, argv);
int myid = Mpi::WorldRank();
Hypre::Init();
// 1. Set the method's default parameters.
// Set the method's default parameters.
const char *mesh_file = "square01.mesh";
int mesh_poly_deg = 1;
int rs_levels = 1;
@@ -61,7 +67,6 @@ int main (int argc, char *argv[])
int metric_id = 2;
int target_id = 1;
real_t surface_fit_const = 100.0;
int quad_type = 1;
int quad_order = 8;
int solver_type = 0;
int solver_iter = 20;
@@ -70,27 +75,28 @@ int main (int argc, char *argv[])
#else
real_t solver_rtol = 1e-10;
#endif
int solver_art_type = 0;
int lin_solver = 2;
int max_lin_iter = 100;
bool move_bnd = true;
bool visualization = true;
bool visualization = false;
int verbosity_level = 0;
int adapt_eval = 0;
const char *devopt = "cpu";
real_t surface_fit_adapt = 0.0;
real_t surface_fit_threshold = -10;
real_t surf_fit_const_max = 1e20;
bool adapt_marking = false;
bool surf_bg_mesh = false;
bool comp_dist = false;
int surf_ls_type = 1;
int marking_type = 0;
bool mod_bndr_attr = false;
bool material = false;
bool surf_bg_mesh = false;
bool comp_dist = false;
int surf_ls_type = 1;
int marking_type = 0;
bool mod_bndr_attr = false;
bool material = false;
int mesh_node_ordering = 0;
int amr_iters = 0;
int bg_amr_iters = 0;
bool conv_residual = true;
// 2. Parse command-line options.
// Parse command-line options.
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
@@ -111,11 +117,6 @@ int main (int argc, char *argv[])
"5: Ideal shape, given size (in physical space)");
args.AddOption(&surface_fit_const, "-sfc", "--surface-fit-const",
"Surface preservation constant.");
args.AddOption(&quad_type, "-qt", "--quad-type",
"Quadrature rule type:\n\t"
"1: Gauss-Lobatto\n\t"
"2: Gauss-Legendre\n\t"
"3: Closed uniform points");
args.AddOption(&quad_order, "-qo", "--quad_order",
"Order of the quadrature rule.");
args.AddOption(&solver_type, "-st", "--solver-type",
@@ -124,11 +125,6 @@ int main (int argc, char *argv[])
"Maximum number of Newton iterations.");
args.AddOption(&solver_rtol, "-rtol", "--newton-rel-tolerance",
"Relative tolerance for the Newton solver.");
args.AddOption(&solver_art_type, "-art", "--adaptive-rel-tol",
"Type of adaptive relative linear solver tolerance:\n\t"
"0: None (default)\n\t"
"1: Eisenstat-Walker type 1\n\t"
"2: Eisenstat-Walker type 2");
args.AddOption(&lin_solver, "-ls", "--lin-solver",
"Linear solver:\n\t"
"0: l1-Jacobi\n\t"
@@ -151,10 +147,12 @@ int main (int argc, char *argv[])
args.AddOption(&devopt, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&surface_fit_adapt, "-sfa", "--adaptive-surface-fit",
"Enable or disable adaptive surface fitting.");
"Scaling factor for surface fitting weight.");
args.AddOption(&surface_fit_threshold, "-sft", "--surf-fit-threshold",
"Set threshold for surface fitting. TMOP solver will"
"terminate when max surface fitting error is below this limit");
args.AddOption(&surf_fit_const_max, "-sfcmax", "--surf-fit-const-max",
"Max surface fitting weight allowed");
args.AddOption(&adapt_marking, "-marking", "--adaptive-marking", "-no-amarking",
"--no-adaptive-marking",
"Enable or disable adaptive marking surface fitting.");
@@ -165,9 +163,9 @@ int main (int argc, char *argv[])
"-no-dist","--no-comp-dist",
"Compute distance from 0 level set or not.");
args.AddOption(&surf_ls_type, "-slstype", "--surf-ls-type",
"1 - Circle (DEFAULT), 2 - Squircle, 3 - Butterfly.");
"1 - Circle (DEFAULT), 2 - reactor level-set, 3 - squircle.");
args.AddOption(&marking_type, "-smtype", "--surf-marking-type",
"1 - Interface (DEFAULT), 2 - Boundary attribute.");
"0 - Interface (DEFAULT), otherwise Boundary attribute.");
args.AddOption(&mod_bndr_attr, "-mod-bndr-attr", "--modify-boundary-attribute",
"-fix-bndr-attr", "--fix-boundary-attribute",
"Change boundary attribute based on alignment with Cartesian axes.");
@@ -176,8 +174,11 @@ int main (int argc, char *argv[])
args.AddOption(&mesh_node_ordering, "-mno", "--mesh_node_ordering",
"Ordering of mesh nodes."
"0 (default): byNodes, 1: byVDIM");
args.AddOption(&amr_iters, "-amriter", "--amr-iter",
args.AddOption(&bg_amr_iters, "-bgamriter", "--amr-iter",
"Number of amr iterations on background mesh");
args.AddOption(&conv_residual, "-resid", "--resid", "-no-resid",
"--no-resid",
"Enable residual based convergence.");
args.Parse();
if (!args.Good())
{
@@ -189,7 +190,11 @@ int main (int argc, char *argv[])
Device device(devopt);
if (myid == 0) { device.Print();}
// 3. Initialize and refine the starting mesh.
MFEM_VERIFY(surface_fit_const > 0.0,
"This miniapp is for surface fitting only. See (p)mesh-optimizer"
"miniapps for general high-order mesh optimization.");
// Initialize and refine the starting mesh.
Mesh *mesh = new Mesh(mesh_file, 1, 1, false);
for (int lev = 0; lev < rs_levels; lev++)
{
@@ -207,6 +212,10 @@ int main (int argc, char *argv[])
{
ls_coeff = new FunctionCoefficient(reactor);
}
else if (surf_ls_type == 3) //squircle
{
ls_coeff = new FunctionCoefficient(squircle_level_set);
}
else if (surf_ls_type == 6) // 3D shape
{
ls_coeff = new FunctionCoefficient(csg_cubecylsph);
@@ -220,7 +229,7 @@ int main (int argc, char *argv[])
delete mesh;
for (int lev = 0; lev < rp_levels; lev++) { pmesh->UniformRefinement(); }
// 4. Setup background mesh for surface fitting
// Setup background mesh for surface fitting
ParMesh *pmesh_surf_fit_bg = NULL;
if (surf_bg_mesh)
{
@@ -240,10 +249,10 @@ int main (int argc, char *argv[])
delete mesh_surf_fit_bg;
}
// 5. Define a finite element space on the mesh. Here we use vector finite
// elements which are tensor products of quadratic finite elements. The
// number of components in the vector finite element space is specified by
// the last parameter of the FiniteElementSpace constructor.
// Define a finite element space on the mesh. Here we use vector finite
// elements which are tensor products of quadratic finite elements. The
// number of components in the vector finite element space is specified by
// the last parameter of the FiniteElementSpace constructor.
FiniteElementCollection *fec;
if (mesh_poly_deg <= 0)
{
@@ -254,21 +263,21 @@ int main (int argc, char *argv[])
ParFiniteElementSpace *pfespace =
new ParFiniteElementSpace(pmesh, fec, dim, mesh_node_ordering);
// 6. Make the mesh curved based on the above finite element space. This
// means that we define the mesh elements through a fespace-based
// transformation of the reference element.
// Make the mesh curved based on the above finite element space. This
// means that we define the mesh elements through a fespace-based
// transformation of the reference element.
pmesh->SetNodalFESpace(pfespace);
// 7. Get the mesh nodes (vertices and other degrees of freedom in the finite
// element space) as a finite element grid function in fespace. Note that
// changing x automatically changes the shapes of the mesh elements.
// Get the mesh nodes (vertices and other degrees of freedom in the finite
// element space) as a finite element grid function in fespace. Note that
// changing x automatically changes the shapes of the mesh elements.
ParGridFunction x(pfespace);
pmesh->SetNodalGridFunction(&x);
x.SetTrueVector();
// 10. Save the starting (prior to the optimization) mesh to a file. This
// output can be viewed later using GLVis: "glvis -m perturbed -np
// num_mpi_tasks".
// Save the starting (prior to the optimization) mesh to a file. This
// output can be viewed later using GLVis: "glvis -m perturbed -np
// num_mpi_tasks".
{
ostringstream mesh_name;
mesh_name << "perturbed.mesh";
@@ -326,16 +335,7 @@ int main (int argc, char *argv[])
TMOP_Integrator *tmop_integ = new TMOP_Integrator(metric, target_c);
// Setup the quadrature rules for the TMOP integrator.
IntegrationRules *irules = NULL;
switch (quad_type)
{
case 1: irules = &IntRulesLo; break;
case 2: irules = &IntRules; break;
case 3: irules = &IntRulesCU; break;
default:
if (myid == 0) { cout << "Unknown quad_type: " << quad_type << endl; }
return 3;
}
IntegrationRules *irules = &IntRulesLo;
tmop_integ->SetIntegrationRules(*irules, quad_order);
if (myid == 0 && dim == 2)
{
@@ -423,7 +423,7 @@ int main (int argc, char *argv[])
if (surf_bg_mesh)
{
OptimizeMeshWithAMRAroundZeroLevelSet(*pmesh_surf_fit_bg, *ls_coeff,
amr_iters, *surf_fit_bg_gf0);
bg_amr_iters, *surf_fit_bg_gf0);
pmesh_surf_fit_bg->Rebalance();
surf_fit_bg_fes->Update();
surf_fit_bg_gf0->Update();
@@ -505,6 +505,7 @@ int main (int argc, char *argv[])
ModifyAttributeForMarkingDOFS(pmesh, mat, 0);
ModifyAttributeForMarkingDOFS(pmesh, mat, 1);
}
pmesh->SetAttributes();
GridFunctionCoefficient coeff_mat(&mat);
surf_fit_mat_gf.ProjectDiscCoefficient(coeff_mat,
@@ -579,6 +580,22 @@ int main (int argc, char *argv[])
}
}
// Unify marker across processor boundary
surf_fit_mat_gf.ExchangeFaceNbrData();
{
GroupCommunicator &gcomm = surf_fit_mat_gf.ParFESpace()->GroupComm();
Array<real_t> gf_array(surf_fit_mat_gf.GetData(),
surf_fit_mat_gf.Size());
gcomm.Reduce<real_t>(gf_array, GroupCommunicator::Max);
gcomm.Bcast(gf_array);
}
surf_fit_mat_gf.ExchangeFaceNbrData();
for (int i = 0; i < surf_fit_mat_gf.Size(); i++)
{
surf_fit_marker[i] = surf_fit_mat_gf(i) == 1.0;
}
// Set AdaptivityEvaluators for transferring information from initial
// mesh to current mesh as it moves during adaptivity.
if (adapt_eval == 0)
@@ -590,11 +607,8 @@ int main (int argc, char *argv[])
{
#ifdef MFEM_USE_GSLIB
adapt_surface = new InterpolatorFP;
if (surf_bg_mesh)
{
adapt_grad_surface = new InterpolatorFP;
adapt_hess_surface = new InterpolatorFP;
}
adapt_grad_surface = new InterpolatorFP;
adapt_hess_surface = new InterpolatorFP;
#else
MFEM_ABORT("MFEM is not built with GSLIB support!");
#endif
@@ -604,7 +618,9 @@ int main (int argc, char *argv[])
if (!surf_bg_mesh)
{
tmop_integ->EnableSurfaceFitting(surf_fit_gf0, surf_fit_marker,
surf_fit_coeff, *adapt_surface);
surf_fit_coeff, *adapt_surface,
adapt_grad_surface,
adapt_hess_surface);
}
else
{
@@ -632,16 +648,9 @@ int main (int argc, char *argv[])
}
}
}
pmesh->SetAttributes();
// 13. Setup the final NonlinearForm (which defines the integral of interest,
// its first and second derivatives). Here we can use a combination of
// metrics, i.e., optimize the sum of two integrals, where both are
// scaled by used-defined space-dependent weights. Note that there are
// no command-line options for the weights and the type of the second
// metric; one should update those in the code.
// Setup the final NonlinearForm.
ParNonlinearForm a(pfespace);
ConstantCoefficient *metric_coeff1 = NULL;
a.AddDomainIntegrator(tmop_integ);
// Compute the minimum det(J) of the starting mesh.
@@ -674,10 +683,10 @@ int main (int argc, char *argv[])
surf_fit_coeff.constant = surface_fit_const;
}
// 14. Fix all boundary nodes, or fix only a given component depending on the
// boundary attributes of the given mesh. Attributes 1/2/3 correspond to
// fixed x/y/z components of the node. Attribute dim+1 corresponds to
// an entirely fixed node.
// Fix all boundary nodes, or fix only a given component depending on the
// boundary attributes of the given mesh. Attributes 1/2/3 correspond to
// fixed x/y/z components of the node. Attribute dim+1 corresponds to
// an entirely fixed node.
if (move_bnd == false)
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
@@ -733,8 +742,7 @@ int main (int argc, char *argv[])
a.SetEssentialVDofs(ess_vdofs);
}
// 15. As we use the Newton method to solve the resulting nonlinear system,
// here we setup the linear solver for the system's Jacobian.
// Setup the linear solver for the system's Jacobian.
Solver *S = NULL, *S_prec = NULL;
#ifdef MFEM_USE_SINGLE
const real_t linsol_rtol = 1e-5;
@@ -784,8 +792,14 @@ int main (int argc, char *argv[])
}
if (surface_fit_threshold > 0)
{
solver.SetTerminationWithMaxSurfaceFittingError(surface_fit_threshold);
solver.SetSurfaceFittingMaxErrorLimit(surface_fit_threshold);
}
solver.SetSurfaceFittingConvergenceBasedOnError(!conv_residual);
if (conv_residual)
{
solver.SetSurfaceFittingWeightLimit(surf_fit_const_max);
}
// Provide all integration rules in case of a mixed mesh.
solver.SetIntegrationRules(*irules, quad_order);
if (solver_type == 0)
@@ -797,18 +811,14 @@ int main (int argc, char *argv[])
solver.SetRelTol(solver_rtol);
solver.SetAbsTol(0.0);
solver.SetMinimumDeterminantThreshold(0.001*min_detJ);
if (solver_art_type > 0)
{
solver.SetAdaptiveLinRtol(solver_art_type, 0.5, 0.9);
}
solver.SetPrintLevel(verbosity_level >= 1 ? 1 : -1);
solver.SetOperator(a);
Vector b(0);
solver.Mult(b, x.GetTrueVector());
x.SetFromTrueVector();
// 16. Save the optimized mesh to a file. This output can be viewed later
// using GLVis: "glvis -m optimized -np num_mpi_tasks".
// Save the optimized mesh to a file. This output can be viewed later
// using GLVis: "glvis -m optimized -np num_mpi_tasks".
{
ostringstream mesh_name;
mesh_name << "optimized.mesh";
@@ -842,9 +852,13 @@ int main (int argc, char *argv[])
if (surface_fit_const > 0.0)
{
adapt_surface->ComputeAtNewPosition(x, surf_fit_gf0,
x.FESpace()->GetOrdering());
if (visualization)
{
socketstream vis2, vis3;
socketstream vis1, vis2, vis3;
common::VisualizeField(vis1, "localhost", 19916, surf_fit_gf0,
"Level Set", 000, 400, 300, 300);
common::VisualizeField(vis2, "localhost", 19916, mat,
"Materials", 300, 400, 300, 300);
common::VisualizeField(vis3, "localhost", 19916, surf_fit_mat_gf,
@@ -859,7 +873,7 @@ int main (int argc, char *argv[])
}
}
// 18. Visualize the mesh displacement.
// Visualize the mesh displacement.
if (visualization)
{
x0 -= x;
@@ -870,7 +884,6 @@ int main (int argc, char *argv[])
delete S;
delete S_prec;
delete metric_coeff1;
delete adapt_surface;
delete adapt_grad_surface;
delete adapt_hess_surface;
+3
View File
@@ -55,6 +55,9 @@ MESH_FILES = $(notdir $(wildcard $(SRC)*.mesh))
$(MESH_FILES): %: $(SRC)%
ln -sf $(<) .
multidomain: | $(MESH_FILES)
# The target 'copy-data' is used by the makefile in ../../tests/unit
.PHONY: copy-data
copy-data: | $(MESH_FILES)
endif
MFEM_TESTS = MINIAPPS
+84 -7
View File
@@ -13,6 +13,18 @@ add_mfem_miniapp(nurbs_ex1
MAIN nurbs_ex1.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_ex3
MAIN nurbs_ex3.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_ex5
MAIN nurbs_ex5.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_ex24
MAIN nurbs_ex24.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_curveint
MAIN nurbs_curveint.cpp
LIBRARIES mfem)
@@ -29,6 +41,14 @@ add_mfem_miniapp(nurbs_patch_ex1
MAIN nurbs_patch_ex1.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_solenoidal
MAIN nurbs_solenoidal.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_biharm
MAIN nurbs_biharm.cpp
LIBRARIES mfem)
if (MFEM_ENABLE_TESTING)
add_test(NAME nurbs_ex1_1d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
@@ -64,6 +84,10 @@ if (MFEM_ENABLE_TESTING)
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 2)
add_test(NAME nurbs_ex1_neu_r2_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -r 2 --neu "3")
add_test(NAME nurbs_ex1_weak_mp_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/ball-nurbs.mesh -o 2 --weak-bc -r 0)
@@ -125,9 +149,64 @@ if (MFEM_ENABLE_TESTING)
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/two-cubes-nurbs-autoedge.mesh -o 1 -r 3 -rf ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/two-cubes.ref)
add_test(NAME nurbs_ex1_periodic_2d
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -r 2 --master "3" --slave "4")
add_test(NAME nurbs_ex1_periodic_3d
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube-nurbs.mesh -pm "1" -ps "2" -rf ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube.ref)
-m ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube-nurbs.mesh
-rf ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube.ref
--master "1" --slave "2")
add_test(NAME nurbs_ex3_2d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_ex3> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
add_test(NAME nurbs_ex3_3d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_ex3> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2)
add_test(NAME nurbs_ex5_2d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_ex5> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
add_test(NAME nurbs_ex5_3d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_ex5> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2)
add_test(NAME nurbs_ex24_2d_r1_o2_p0_ser
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 0)
add_test(NAME nurbs_ex24_2d_r1_o2_p2_ser
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 2)
add_test(NAME nurbs_ex24_3d_r1_o2_p0_ser
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2 -p 0)
add_test(NAME nurbs_ex24_3d_r1_o2_p1_ser
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2 -p 1)
add_test(NAME nurbs_ex24_3d_r1_o2_p2_ser
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2 -p 2)
add_test(NAME nurbs_solenoidal_2d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_solenoidal> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -r 1 -o 2)
add_test(NAME nurbs_solenoidal_3d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_solenoidal> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2)
add_test(NAME nurbs_biharm_ser
COMMAND $<TARGET_FILE:nurbs_biharm> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
endif()
if (MFEM_USE_MPI)
@@ -135,6 +214,10 @@ if (MFEM_USE_MPI)
MAIN nurbs_ex1p.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_ex11p
MAIN nurbs_ex11p.cpp
LIBRARIES mfem)
if (MFEM_ENABLE_TESTING)
add_test(NAME nurbs_ex1p_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
@@ -169,13 +252,7 @@ if (MFEM_USE_MPI)
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1)
endif()
add_mfem_miniapp(nurbs_ex11p
MAIN nurbs_ex11p.cpp
LIBRARIES mfem)
if (MFEM_ENABLE_TESTING)
add_test(NAME nurbs_ex11p_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex11p> -no-vis
+33 -4
View File
@@ -21,8 +21,7 @@ CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_MINIAPPS = nurbs_ex1 nurbs_patch_ex1 nurbs_curveint nurbs_printfunc nurbs_naca_cmesh
SEQ_MINIAPPS = nurbs_ex1 nurbs_patch_ex1 nurbs_ex3 nurbs_ex5 nurbs_ex24 nurbs_curveint nurbs_printfunc nurbs_solenoidal nurbs_naca_cmesh
PAR_MINIAPPS = nurbs_ex1p nurbs_ex11p
ifeq ($(MFEM_USE_MPI),NO)
MINIAPPS = $(SEQ_MINIAPPS)
@@ -103,6 +102,36 @@ endif
@$(call mfem-test,$<,, NURBS miniapp,$(EX1PATCH_ARGS_2))
@$(call mfem-test,$<,, NURBS miniapp,$(EX1PATCH_ARGS_3))
EX3_ARGS_1 := -m $(MFEM_DIR)/data/square-nurbs.mesh -r 1 -o 2
EX3_ARGS_2 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2
nurbs_ex3-test-seq: nurbs_ex3
@$(call mfem-test,$<,, NURBS miniapp,$(EX3_ARGS_1))
@$(call mfem-test,$<,, NURBS miniapp,$(EX3_ARGS_2))
EX5_ARGS_1 := -m $(MFEM_DIR)/data/square-nurbs.mesh -r 1 -o 2
EX5_ARGS_2 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2
nurbs_ex5-test-seq: nurbs_ex5
@$(call mfem-test,$<,, NURBS miniapp,$(EX5_ARGS_1))
@$(call mfem-test,$<,, NURBS miniapp,$(EX5_ARGS_2))
EX24_ARGS_1 := -m $(MFEM_DIR)/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 0
EX24_ARGS_2 := -m $(MFEM_DIR)/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 2
EX24_ARGS_3 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2 -p 0
EX24_ARGS_4 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2 -p 1
EX24_ARGS_5 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2 -p 2
nurbs_ex24-test-seq: nurbs_ex24
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_1))
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_2))
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_3))
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_4))
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_5))
SOL_ARGS_1 := -m $(MFEM_DIR)/data/pipe-nurbs-2d.mesh -r 1 -o 2
SOL_ARGS_1 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2
nurbs_sol-test-seq: nurbs_solenoidal
@$(call mfem-test,$<,, NURBS miniapp,$(SOL_ARGS_1))
@$(call mfem-test,$<,, NURBS miniapp,$(SOl_ARGS_2))
CI_ARGS_1 := -uw -n 9 -no-visit
CI_ARGS_2 := -nw -n 9 -no-visit
@@ -151,6 +180,6 @@ clean-build:
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -f refined.mesh sin-fit.mesh mesh.* sol.* mode_* naca-cmesh.mesh
@rm -rf Example1*
@rm -f refined.mesh sin-fit.mesh ex5.mesh exsol.mesh mesh.* sol.* mode_* naca-cmesh.mesh sol_?.gf
@rm -rf Example1* Example3* Example5* Solenoidal_* ParaView
@rm -rf CurveInt Naca_cmesh glvis_naca-cmesh.mesh
+408
View File
@@ -0,0 +1,408 @@
// Copyright (c) 2010-2024, 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.
//
// Stabilized Convection-Diffusion
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <list>
using namespace std;
using namespace mfem;
real_t kappa_param = 1.0;
real_t dif_fun(const Vector & x)
{
return kappa_param;
}
real_t force_fun(const Vector & x)
{
int d = x.Size();
real_t kappa = dif_fun(x);
real_t pi = (real_t)(M_PI);
real_t sx = sin(pi*x[0]);
real_t sy = 1.0;
real_t sz = 1.0;
if (d >= 2)
{
sy = sin(pi*x[1]);
}
if (d >= 3)
{
sz = sin(pi*x[2]);
}
return d*d*kappa*pi*pi*pi*pi*sx*sy*sz;
}
real_t sol_fun(const Vector & x)
{
real_t pi = (real_t)(M_PI);
real_t sx = sin(pi*x[0]);
real_t sy = 1.0;
real_t sz = 1.0;
int d = x.Size();
if (d >= 2)
{
sy = sin(pi*x[1]);
}
if (d >= 3)
{
sz = sin(pi*x[2]);
}
return sx*sy*sz;
}
void grad_fun(const Vector & x, Vector & a)
{
real_t pi = (real_t)(M_PI);
real_t sx = sin(pi*x[0]);
real_t cx = cos(pi*x[0]);
real_t sy = 1.0;
real_t cy = 1.0;
real_t sz = 1.0;
real_t cz = 1.0;
int d = x.Size();
if (d >= 2)
{
sy = sin(pi*x[1]);
cy = cos(pi*x[1]);
}
if (d >= 3)
{
sz = sin(pi*x[2]);
cz = cos(pi*x[2]);
}
a[0] = pi*cx*sy;
a[1] = pi*sx*cy;
}
//----------------------------------------------------------
real_t lap_fun(const Vector & x)
{
real_t pi = (real_t)(M_PI);
real_t sx = sin(pi*x[0]);
real_t cx = cos(pi*x[0]);
real_t sy = 1.0;
real_t cy = 1.0;
real_t sz = 1.0;
real_t cz = 1.0;
int d = x.Size();
if (d >= 2)
{
sy = sin(pi*x[1]);
cy = cos(pi*x[1]);
}
if (d >= 3)
{
sz = sin(pi*x[2]);
cz = cos(pi*x[2]);
}
return -d*pi*pi*sx*sy*sz;
}
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/square-nurbs.mesh";
const char *per_file = "none";
const char *ref_file = "";
int ref_levels = 0;
Array<int> master(0);
Array<int> slave(0);
bool static_cond = false;
bool visualization = false;
real_t penalty = -1;
Array<int> order(1);
order[0] = 2;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&per_file, "-p", "--per",
"Periodic BCS file.");
args.AddOption(&ref_file, "-rf", "--ref-file",
"File with refinement data");
args.AddOption(&master, "-pm", "--master",
"Master boundaries for periodic BCs");
args.AddOption(&slave, "-ps", "--slave",
"Slave boundaries for periodic BCs");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&kappa_param, "-k", "--kappa",
"Sets the diffusion parameters, should be positive."
" Negative values are replaced with function defined in source.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(mfem::out);
return 1;
}
args.PrintOptions(mfem::out);
if (order.Min()< 2)
{
mfem_error("Wrong order.");
}
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement and knot insertion of knots defined
// in a refinement file. We choose 'ref_levels' to be the largest number
// that gives a final mesh with no more than 50,000 elements.
{
// Mesh refinement as defined in refinement file
if (mesh->NURBSext && (strlen(ref_file) != 0))
{
mesh->RefineNURBSFromFile(ref_file);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
mesh->PrintInfo();
}
// 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;
NURBSExtension *NURBSext = NULL;
int own_fec = 0;
if (mesh->NURBSext)
{
fec = new NURBSFECollection(order[0]);
own_fec = 1;
int nkv = mesh->NURBSext->GetNKV();
if (order.Size() == 1)
{
int tmp = order[0];
order.SetSize(nkv);
order = tmp;
}
if (order.Size() != nkv ) { mfem_error("Wrong number of orders set."); }
NURBSext = new NURBSExtension(mesh->NURBSext, order);
// Read periodic BCs from file
std::ifstream in;
in.open(per_file, std::ifstream::in);
if (in.is_open())
{
int psize;
in >> psize;
master.SetSize(psize);
slave.SetSize(psize);
master.Load(in, psize);
slave.Load(in, psize);
in.close();
}
master.Print();
slave.Print();
NURBSext->ConnectBoundaries(master,slave);
}
else if (order[0] == -1) // Isoparametric
{
if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
own_fec = 0;
mfem::out << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
mfem::out <<"Mesh does not have FEs --> Assume order 1.\n";
fec = new H1_FECollection(1, dim);
own_fec = 1;
}
}
else
{
if (order.Size() > 1) { cout <<"Wrong number of orders set, needs one.\n"; }
fec = new H1_FECollection(abs(order[0]), dim);
own_fec = 1;
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, NURBSext, fec);
mfem::out << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
// Remove periodic BCs
for (int i = 0; i < master.Size(); i++)
{
ess_bdr[master[i]-1] = 0;
ess_bdr[slave[i]-1] = 0;
}
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
ConstantCoefficient u_dir(0.0);
Coefficient *kappa_tmp;
if (kappa_param < 0.0)
{
kappa_tmp = new FunctionCoefficient(dif_fun);
}
else
{
kappa_tmp = new ConstantCoefficient(kappa_param);
}
Coefficient& kappa = *kappa_tmp;
FunctionCoefficient force(force_fun);
LinearForm *b = new LinearForm(fespace);
b->AddDomainIntegrator(new DomainLFIntegrator(force));
b->Assemble();
// 7. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
GridFunction x(fespace);
x = 0.0;
// 8. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new LaplaceLaplaceIntegrator(kappa));
// 9. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
mfem::out << "Size of linear system: " << A.Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 10. Define a simple Jacobi preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
GMRES(A, M, B, X, 1, 2000, 2000, 1e-16, 0.0);
#else
// 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
#endif
// 11. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 12. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
{
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
sol_ofs.close();
}
// 13. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 14. Error computation
Vector norm(3);
int order_quad = 3*order.Max() + 4;
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
FunctionCoefficient sol_cf(sol_fun);
VectorFunctionCoefficient grad_cf(mesh->Dimension(), grad_fun);
FunctionCoefficient lap_cf(lap_fun);
norm[0]= x.ComputeL2Error(sol_cf,irs);
norm[1]= x.ComputeGradError(&grad_cf, irs);
norm[2] = x.ComputeLaplaceError(&lap_cf, irs);
mfem::out << "|| x_h - x_ex || = " << norm[0] << "\n";
mfem::out << "|| grad x_h - grad x_ex || = " << norm[1] << "\n";
mfem::out << "|| lap x_h - lap x_ex || = " << norm[2] << "\n";
// 15. Save data in the VisIt format
VisItDataCollection visit_dc("Biharm", mesh);
visit_dc.RegisterField("solution", &x);
visit_dc.Save();
// 16. Free the used memory.
delete fespace;
if (own_fec) { delete fec; }
delete mesh;
return 0;
}
+71 -103
View File
@@ -6,6 +6,7 @@
// nurbs_ex1 -m ../../data/square-nurbs.mesh -o 2 --weak-bc
// nurbs_ex1 -m ../../data/cube-nurbs.mesh -o 2 -no-ibp
// nurbs_ex1 -m ../../data/pipe-nurbs-2d.mesh -o 2 -no-ibp
// nurbs_ex1 -m ../../data/pipe-nurbs-2d.mesh -o 2 -r 2 --neu "3"
// nurbs_ex1 -m ../../data/square-disc-nurbs.mesh -o -1
// nurbs_ex1 -m ../../data/disc-nurbs.mesh -o -1
// nurbs_ex1 -m ../../data/pipe-nurbs.mesh -o -1
@@ -52,101 +53,17 @@ public:
inline bool operator==(const Data& d1,const Data& d2) { return (d1.x == d2.x); }
inline bool operator <(const Data& d1,const Data& d2) { return (d1.x < d2.x); }
/** Class for integrating the bilinear form a(u,v) := (Q Laplace u, v) where Q
can be a scalar coefficient. */
class Diffusion2Integrator: public BilinearFormIntegrator
{
private:
#ifndef MFEM_THREAD_SAFE
Vector shape,laplace;
#endif
Coefficient *Q;
public:
/// Construct a diffusion integrator with coefficient Q = 1
Diffusion2Integrator() { Q = NULL; }
/// Construct a diffusion integrator with a scalar coefficient q
Diffusion2Integrator (Coefficient &q) : Q(&q) { }
/** Given a particular Finite Element
computes the element stiffness matrix elmat. */
virtual void AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat)
{
int nd = el.GetDof();
int dim = el.GetDim();
real_t w;
#ifdef MFEM_THREAD_SAFE
Vector shape(nd);
Vector laplace(nd);
#else
shape.SetSize(nd);
laplace.SetSize(nd);
#endif
elmat.SetSize(nd);
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
int order;
if (el.Space() == FunctionSpace::Pk)
{
order = 2*el.GetOrder() - 2;
}
else
{
order = 2*el.GetOrder() + dim - 1;
}
if (el.Space() == FunctionSpace::rQk)
{
ir = &RefinedIntRules.Get(el.GetGeomType(),order);
}
else
{
ir = &IntRules.Get(el.GetGeomType(),order);
}
}
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint(&ip);
w = -ip.weight * Trans.Weight();
el.CalcShape(ip, shape);
el.CalcPhysLaplacian(Trans, laplace);
if (Q)
{
w *= Q->Eval(Trans, ip);
}
for (int jj = 0; jj < nd; jj++)
{
for (int ii = 0; ii < nd; ii++)
{
elmat(ii, jj) += w*shape(ii)*laplace(jj);
}
}
}
}
};
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/star.mesh";
const char *mesh_file = "../../data/square-nurbs.mesh";
const char *per_file = "none";
const char *ref_file = "";
int ref_levels = -1;
Array<int> master(0);
Array<int> slave(0);
Array<int> neu(0);
bool static_cond = false;
bool visualization = 1;
int lod = 0;
@@ -169,6 +86,8 @@ int main(int argc, char *argv[])
"Master boundaries for periodic BCs");
args.AddOption(&slave, "-ps", "--slave",
"Slave boundaries for periodic BCs");
args.AddOption(&neu, "-n", "--neu",
"Boundaries with Neumann BCs");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
@@ -266,8 +185,6 @@ int main(int argc, char *argv[])
slave.Load(in, psize);
in.close();
}
master.Print();
slave.Print();
NURBSext->ConnectBoundaries(master,slave);
}
else if (order[0] == -1) // Isoparametric
@@ -323,39 +240,84 @@ int main(int argc, char *argv[])
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
Array<int> ess_bdr(0);
Array<int> neu_bdr(0);
Array<int> per_bdr(0);
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
if (strongBC)
ess_bdr.SetSize(mesh->bdr_attributes.Max());
neu_bdr.SetSize(mesh->bdr_attributes.Max());
per_bdr.SetSize(mesh->bdr_attributes.Max());
ess_bdr = 1;
neu_bdr = 0;
per_bdr = 0;
// Apply Neumann BCs
for (int i = 0; i < neu.Size(); i++)
{
ess_bdr = 1;
}
else
{
ess_bdr = 0;
if ( neu[i]-1 >= 0 &&
neu[i]-1 < mesh->bdr_attributes.Max())
{
ess_bdr[neu[i]-1] = 0;
neu_bdr[neu[i]-1] = 1;
}
else
{
cout <<"Neumann boundary "<<neu[i]<<" out of range -- discarded"<< endl;
}
}
// Remove periodic BCs
// Correct for periodic BCs
for (int i = 0; i < master.Size(); i++)
{
ess_bdr[master[i]-1] = 0;
ess_bdr[slave[i]-1] = 0;
if ( master[i]-1 >= 0 &&
master[i]-1 < mesh->bdr_attributes.Max())
{
ess_bdr[master[i]-1] = 0;
neu_bdr[master[i]-1] = 0;
per_bdr[master[i]-1] = 1;
}
else
{
cout <<"Master boundary "<<master[i]<<" out of range -- discarded"<< endl;
}
}
for (int i = 0; i < slave.Size(); i++)
{
if ( slave[i]-1 >= 0 &&
slave[i]-1 < mesh->bdr_attributes.Max())
{
ess_bdr[slave[i]-1] = 0;
neu_bdr[slave[i]-1] = 0;
per_bdr[slave[i]-1] = 1;
}
else
{
cout <<"Slave boundary "<<slave[i]<<" out of range -- discarded"<< endl;
}
}
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
cout <<"Boundary conditions:"<< endl;
cout <<" - Periodic : "; per_bdr.Print();
cout <<" - Essential : "; ess_bdr.Print();
cout <<" - Neumann : "; neu_bdr.Print();
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
ConstantCoefficient one(1.0);
ConstantCoefficient mone(-1.0);
ConstantCoefficient zero(0.0);
LinearForm *b = new LinearForm(fespace);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->AddBoundaryIntegrator( new BoundaryLFIntegrator(one),neu_bdr);
if (!strongBC)
b->AddBdrFaceIntegrator(
new DGDirichletLFIntegrator(zero, one, -1.0, kappa));
new DGDirichletLFIntegrator(zero, one, -1.0, kappa), ess_bdr);
b->Assemble();
// 7. Define the solution vector x as a finite element grid function
@@ -374,12 +336,13 @@ int main(int argc, char *argv[])
}
else
{
a->AddDomainIntegrator(new Diffusion2Integrator(one));
a->AddDomainIntegrator(new LaplaceIntegrator(one, -1.0));
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(mone, 0.0, 0.0), neu_bdr);
}
if (!strongBC)
{
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, -1.0, kappa));
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, -1.0, kappa), ess_bdr);
}
// 9. Assemble the bilinear form and the corresponding linear system,
@@ -391,6 +354,11 @@ int main(int argc, char *argv[])
SparseMatrix A;
Vector B, X;
Array<int> ess_tdof_list(0);
if (strongBC)
{
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A.Height() << endl;
+459
View File
@@ -0,0 +1,459 @@
// MFEM Example 24 -- modified for NURBS FE
//
// Compile with: make nurbs_ex24
//
// Sample runs: nurbs_ex24 -m ../../data/pipe-nurbs-2d.mesh -o 2
// nurbs_ex24 -m ../../data/pipe-nurbs-2d.mesh -p 2
// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2
// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2 -p 1
// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2 -p 2
// nurbs_ex24 -m ../../data/escher.mesh
// nurbs_ex24 -m ../../data/escher.mesh -o 2
// nurbs_ex24 -m ../../data/fichera.mesh
// nurbs_ex24 -m ../../data/fichera-q2.vtk
// nurbs_ex24 -m ../../data/fichera-q3.mesh
// nurbs_ex24 -m ../../data/amr-quad.mesh -o 2
// nurbs_ex24 -m ../../data/amr-hex.mesh
//
// Device sample runs -- do not work for NURBS:
// nurbs_ex24 -m ../../data/escher.mesh -pa -d cuda
// nurbs_ex24 -m ../../data/escher.mesh -pa -d raja-cuda
// nurbs_ex24 -m ../../data/escher.mesh -pa -d raja-omp
//
// Description: This example code illustrates usage of mixed finite element
// spaces, with three variants:
//
// 0) (grad p, u) for p in H^1 tested against u in H(curl)
// 1) (curl v, u) for v in H(curl) tested against u in H(div), 3D
// 2) (div v, q) for v in H(div) tested against q in L_2
//
// Using different approaches, we project the gradient, curl, or
// divergence to the appropriate space.
//
// NURBS-based H(curl) and H(div) spaces only implemented
// for meshes consisting of a single patch.
//
// We recommend viewing examples 1, 3, and 5 before viewing this
// example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
real_t p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
real_t div_gradp_exact(const Vector &x);
void v_exact(const Vector &x, Vector &v);
void curlv_exact(const Vector &x, Vector &cv);
int dim;
real_t freq = 1.0, kappa;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/cube-nurbs.mesh";
int ref_levels = -1;
int order = 1;
bool NURBS = true;
int prob = 0;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&NURBS, "-n", "--nurbs", "-nn","--no-nurbs",
"NURBS.");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: grad, 1: curl, 2: div");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
kappa = freq * M_PI;
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
if ((prob == 1) &&(dim != 3))
{
MFEM_ABORT("The curl problem is only defined in 3D.");
}
int sdim = mesh->SpaceDimension();
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 50,000
// elements.
{
if (ref_levels < 0)
{
ref_levels = (int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a finite element space on the mesh. Here we use Nedelec or
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *trial_fec = nullptr;
FiniteElementCollection *test_fec = nullptr;
NURBSExtension *NURBSext = nullptr;
if (mesh->NURBSext && NURBS)
{
NURBSext = new NURBSExtension(mesh->NURBSext, order);
if (prob == 0)
{
trial_fec = new NURBSFECollection(order);
test_fec = new NURBS_HCurlFECollection(order, dim);
}
else if (prob == 1)
{
trial_fec = new NURBS_HCurlFECollection(order, dim);
test_fec = new NURBS_HDivFECollection(order, dim);
}
else
{
trial_fec = new NURBS_HDivFECollection(order, dim);
test_fec = new NURBSFECollection(order);
}
mfem::out<<"Create NURBS fec and ext"<<std::endl;
}
else
{
if (prob == 0)
{
trial_fec = new H1_FECollection(order, dim);
test_fec = new ND_FECollection(order, dim);
}
else if (prob == 1)
{
trial_fec = new ND_FECollection(order, dim);
test_fec = new RT_FECollection(order-1, dim);
}
else
{
trial_fec = new RT_FECollection(order-1, dim);
test_fec = new L2_FECollection(order-1, dim);
}
}
FiniteElementSpace trial_fes(mesh, NURBSext, trial_fec);
FiniteElementSpace test_fes(mesh,trial_fes.StealNURBSext(), test_fec);
int trial_size = trial_fes.GetTrueVSize();
int test_size = test_fes.GetTrueVSize();
if (prob == 0)
{
cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
cout << "Number of H1 finite element unknowns: " << trial_size << endl;
}
else if (prob == 1)
{
cout << "Number of Nedelec finite element unknowns: " << trial_size << endl;
cout << "Number of Raviart-Thomas finite element unknowns: " << test_size <<
endl;
}
else
{
cout << "Number of Raviart-Thomas finite element unknowns: "
<< trial_size << endl;
cout << "Number of L2 finite element unknowns: " << test_size << endl;
}
// 6. Define the solution vector as a finite element grid function
// corresponding to the trial fespace.
GridFunction gftest(&test_fes);
GridFunction gftrial(&trial_fes);
GridFunction x(&test_fes);
FunctionCoefficient p_coef(p_exact);
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
VectorFunctionCoefficient v_coef(sdim, v_exact);
VectorFunctionCoefficient curlv_coef(sdim, curlv_exact);
FunctionCoefficient divgradp_coef(div_gradp_exact);
if (prob == 0)
{
gftrial.ProjectCoefficient(p_coef);
}
else if (prob == 1)
{
gftrial.ProjectCoefficient(v_coef);
}
else
{
gftrial.ProjectCoefficient(gradp_coef);
}
gftrial.SetTrueVector();
gftrial.SetFromTrueVector();
// 7. Set up the bilinear forms for L2 projection.
ConstantCoefficient one(1.0);
BilinearForm a(&test_fes);
MixedBilinearForm a_mixed(&trial_fes, &test_fes);
if (pa)
{
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_mixed.SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
if (prob == 0)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorGradientIntegrator(one));
}
else if (prob == 1)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorCurlIntegrator(one));
}
else
{
a.AddDomainIntegrator(new MassIntegrator(one));
a_mixed.AddDomainIntegrator(new VectorFEDivergenceIntegrator(one));
}
// 8. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a.EnableStaticCondensation(); }
a.Assemble();
if (!pa) { a.Finalize(); }
a_mixed.Assemble();
if (!pa) { a_mixed.Finalize(); }
if (pa)
{
a_mixed.Mult(gftrial, x);
}
else
{
SparseMatrix& mixed = a_mixed.SpMat();
mixed.Mult(gftrial, x);
}
// 9. Define and apply a PCG solver for Ax = b with Jacobi preconditioner.
{
GridFunction rhs(&test_fes);
rhs = x;
x = 0.0;
CGSolver cg;
cg.SetRelTol(1e-12);
cg.SetMaxIter(1000);
cg.SetPrintLevel(1);
if (pa)
{
Array<int> ess_tdof_list; // empty
OperatorJacobiSmoother Jacobi(a, ess_tdof_list);
cg.SetOperator(a);
cg.SetPreconditioner(Jacobi);
cg.Mult(rhs, x);
}
else
{
SparseMatrix& Amat = a.SpMat();
DSmoother Jacobi(Amat);
cg.SetOperator(Amat);
cg.SetPreconditioner(Jacobi);
cg.Mult(rhs, x);
}
}
// 10. Compute the projection of the exact field.
GridFunction exact_proj(&test_fes);
if (prob == 0)
{
exact_proj.ProjectCoefficient(gradp_coef);
}
else if (prob == 1)
{
exact_proj.ProjectCoefficient(curlv_coef);
}
else
{
exact_proj.ProjectCoefficient(divgradp_coef);
}
exact_proj.SetTrueVector();
exact_proj.SetFromTrueVector();
// 11. Compute and print the L_2 norm of the error.
if (prob == 0)
{
real_t errSol = x.ComputeL2Error(gradp_coef);
real_t errProj = exact_proj.ComputeL2Error(gradp_coef);
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in H(curl): "
"|| E_h - grad p ||_{L_2} = " << errSol << '\n' << endl;
cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
"||_{L_2} = " << errProj << '\n' << endl;
}
else if (prob == 1)
{
real_t errSol = x.ComputeL2Error(curlv_coef);
real_t errProj = exact_proj.ComputeL2Error(curlv_coef);
cout << "\n Solution of (E_h,w) = (curl v_h,w) for E_h and w in H(div): "
"|| E_h - curl v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Projection E_h of exact curl v in H(div): || E_h - curl v "
"||_{L_2} = " << errProj << '\n' << endl;
}
else
{
int order_quad = max(3, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t errSol = x.ComputeL2Error(divgradp_coef, irs);
real_t errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
cout << "\n Solution of (f_h,q) = (div v_h,q) for f_h and q in L_2: "
"|| f_h - div v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Projection f_h of exact div v in L_2: || f_h - div v "
"||_{L_2} = " << errProj << '\n' << endl;
}
// 12. Save the refined mesh and the solution. This output can be viewed
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
// 13. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 14. Free the used memory.
delete trial_fec;
delete test_fec;
delete mesh;
return 0;
}
real_t p_exact(const Vector &x)
{
if (dim == 3)
{
return sin(x(0)) * sin(x(1)) * sin(x(2));
}
else if (dim == 2)
{
return sin(x(0)) * sin(x(1));
}
return 0.0;
}
void gradp_exact(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = cos(x(0)) * sin(x(1)) * sin(x(2));
f(1) = sin(x(0)) * cos(x(1)) * sin(x(2));
f(2) = sin(x(0)) * sin(x(1)) * cos(x(2));
}
else
{
f(0) = cos(x(0)) * sin(x(1));
f(1) = sin(x(0)) * cos(x(1));
if (x.Size() == 3) { f(2) = 0.0; }
}
}
real_t div_gradp_exact(const Vector &x)
{
if (dim == 3)
{
return -3.0 * sin(x(0)) * sin(x(1)) * sin(x(2));
}
else if (dim == 2)
{
return -2.0 * sin(x(0)) * sin(x(1));
}
return 0.0;
}
void v_exact(const Vector &x, Vector &v)
{
if (dim == 3)
{
v(0) = sin(kappa * x(1));
v(1) = sin(kappa * x(2));
v(2) = sin(kappa * x(0));
}
else
{
v(0) = sin(kappa * x(1));
v(1) = sin(kappa * x(0));
if (x.Size() == 3) { v(2) = 0.0; }
}
}
void curlv_exact(const Vector &x, Vector &cv)
{
if (dim == 3)
{
cv(0) = -kappa * cos(kappa * x(2));
cv(1) = -kappa * cos(kappa * x(0));
cv(2) = -kappa * cos(kappa * x(1));
}
else
{
cv = 0.0;
}
}
+284
View File
@@ -0,0 +1,284 @@
// MFEM Example 3 -- modified for NURBS FE
//
// Compile with: make nurbs_ex3
//
// Sample runs: nurbs_ex3 -m ../../data/square-nurbs.mesh
// nurbs_ex3 -m ../../data/square-nurbs.mesh -o 2
// nurbs_ex3 -m ../../data/cube-nurbs.mesh
//
// Description: This example code solves a simple electromagnetic diffusion
// problem corresponding to the second order definite Maxwell
// equation curl curl E + E = f with boundary condition
// E x n = <given tangential field>. Here, we use a given exact
// solution E and compute the corresponding r.h.s. f.
// We discretize with Nedelec finite elements in 2D or 3D.
//
// The example demonstrates the use of H(curl) finite element
// spaces with the curl-curl and the (vector finite element) mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Static condensation is
// also illustrated.
//
// NURBS-based H(curl) spaces only implemented for meshes
// consisting of a single patch.
//
// We recommend viewing examples 1-2 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Exact solution, E, and r.h.s., f. See below for implementation.
void E_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
real_t freq = 1.0, kappa;
int dim;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/square-nurbs.mesh";
int ref_levels = -1;
bool NURBS = true;
int order = 1;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&NURBS, "-n", "--nurbs", "-nn","--no-nurbs",
"NURBS.");
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
" solution.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
kappa = freq * M_PI;
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 50,000
// elements.
{
if (ref_levels < 0)
{
ref_levels =
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a finite element space on the mesh. Here we use the
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *fec = nullptr;
NURBSExtension *NURBSext = nullptr;
if (mesh->NURBSext && NURBS)
{
fec = new NURBS_HCurlFECollection(order,dim);
NURBSext = new NURBSExtension(mesh->NURBSext, order);
mfem::out<<"Create NURBS fec and ext"<<std::endl;
}
else
{
NURBS = false;
fec = new ND_FECollection(order, dim);
mfem::out<<"Create Normal fec"<<std::endl;
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, NURBSext, fec);
cout << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
cout << "Number of knowns in essential BCs: "
<< ess_tdof_list.Size() << endl;
// 7. Set up the linear form b(.) which corresponds to the right-hand side
// of the FEM linear system, which in this case is (f,phi_i) where f is
// given by the function f_exact and phi_i are the basis functions in the
// finite element fespace.
VectorFunctionCoefficient f(sdim, f_exact);
LinearForm *b = new LinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 8. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
GridFunction x(fespace);
VectorFunctionCoefficient E(sdim, E_exact);
x.ProjectCoefficient(E);
// 9. Set up the bilinear form corresponding to the EM diffusion operator
// curl muinv curl + sigma I, by adding the curl-curl and the mass domain
// integrators.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
BilinearForm *a = new BilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
// 10. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
OperatorPtr A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A->Height() << endl;
// 11. Solve the linear system A X = B.
if (pa) // Jacobi preconditioning in partial assembly mode
{
OperatorJacobiSmoother M(*a, ess_tdof_list);
PCG(*A, M, B, X, 1, 1000, 1e-12, 0.0);
}
else
{
#ifndef MFEM_USE_SUITESPARSE
// 11. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system Ax=b with PCG.
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 1, 500, 1e-12, 0.0);
#else
// 11. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the
// system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(*A);
umf_solver.Mult(B, X);
#endif
}
// 12. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 13. Compute and print the L^2 norm of the error.
cout << "\n|| E_h - E ||_{L^2} = " << x.ComputeL2Error(E) << '\n' << endl;
// 14. Save the refined mesh and the solution. This output can be viewed
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
{
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 15. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 16. Create output in visit format
VisItDataCollection visit_dc("Example3", mesh);
visit_dc.RegisterField("x", &x);
visit_dc.Save();
// 17. Free the used memory.
delete a;
delete sigma;
delete muinv;
delete b;
delete fespace;
delete fec;
delete mesh;
return 0;
}
void E_exact(const Vector &x, Vector &E)
{
if (dim == 3)
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(2));
E(2) = sin(kappa * x(0));
}
else
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(0));
if (x.Size() == 3) { E(2) = 0.0; }
}
}
void f_exact(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
}
else
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
if (x.Size() == 3) { f(2) = 0.0; }
}
}
+498
View File
@@ -0,0 +1,498 @@
// MFEM Example 5 -- modified for NURBS FE
//
// Compile with: make nurbs_ex5
//
// Sample runs: nurbs_ex5 -m ../../data/square-nurbs.mesh -o 3
// nurbs_ex5 -m ../../data/cube-nurbs.mesh -r 3
// nurbs_ex5 -m ../../data/pipe-nurbs-2d.mesh
// nurbs_ex5 -m ../../data/beam-tet.mesh
// nurbs_ex5 -m ../../data/beam-hex.mesh
// nurbs_ex5 -m ../../data/escher.mesh
// nurbs_ex5 -m ../../data/fichera.mesh
//
// Device sample runs -- do not work for NURBS:
// nurbs_ex5 -m ../../data/escher.mesh -pa -d cuda
// nurbs_ex5 -m ../../data/escher.mesh -pa -d raja-cuda
// nurbs_ex5 -m ../../data/escher.mesh -pa -d raja-omp
//
// Description: This example code solves a simple 2D/3D mixed Darcy problem
// corresponding to the saddle point system
//
// k*u + grad p = f
// - div u = g
//
// with natural boundary condition -p = <given pressure>.
// Here, we use a given exact solution (u,p) and compute the
// corresponding r.h.s. (f,g). We discretize with Raviart-Thomas
// finite elements (velocity u) and piecewise discontinuous
// polynomials (pressure p).
//
// NURBS-based H(div) spaces only implemented for meshes
// consisting of a single patch.
//
// The example demonstrates the use of the BlockOperator class, as
// well as the collective saving of several grid functions in
// VisIt (visit.llnl.gov) and ParaView (paraview.org) formats.
//
// We recommend viewing examples 1-4 before viewing this example.
// Sample runs: nurbs_ex3 -m ../../data/square-nurbs.mesh
// nurbs_ex3 -m ../../data/square-nurbs.mesh -o 2
// nurbs_ex3 -m ../../data/cube-nurbs.mesh
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace mfem;
// Define the analytical solution and forcing terms / boundary conditions
void uFun_ex(const Vector & x, Vector & u);
real_t pFun_ex(const Vector & x);
void fFun(const Vector & x, Vector & f);
real_t gFun(const Vector & x);
real_t f_natural(const Vector & x);
int main(int argc, char *argv[])
{
StopWatch chrono;
// 1. Parse command-line options.
const char *mesh_file = "../../data/square-nurbs.mesh";
int ref_levels = -1;
int order = 1;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
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. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 10,000
// elements.
{
if (ref_levels < 0)
{
ref_levels =
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a finite element space on the mesh. Here we use the
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *hdiv_coll = nullptr;
FiniteElementCollection *l2_coll = nullptr;
NURBSExtension *NURBSext = nullptr;
if (mesh->NURBSext && !pa)
{
hdiv_coll = new NURBS_HDivFECollection(order,dim);
l2_coll = new NURBSFECollection(order);
NURBSext = new NURBSExtension(mesh->NURBSext, order);
mfem::out<<"Create NURBS fec and ext"<<std::endl;
}
else
{
hdiv_coll = new RT_FECollection(order, dim);
l2_coll = new L2_FECollection(order, dim);
mfem::out<<"Create Normal fec"<<std::endl;
}
pa = false;
FiniteElementSpace *W_space = new FiniteElementSpace(mesh, NURBSext, l2_coll);
FiniteElementSpace *R_space = new FiniteElementSpace(mesh,
W_space->StealNURBSext(),
hdiv_coll);
// 6. Define the BlockStructure of the problem, i.e. define the array of
// offsets for each variable. The last component of the Array is the sum
// of the dimensions of each block.
Array<int> block_offsets(3); // number of variables + 1
block_offsets[0] = 0;
block_offsets[1] = R_space->GetVSize();
block_offsets[2] = W_space->GetVSize();
block_offsets.PartialSum();
std::cout << "***********************************************************\n";
std::cout << "dim(R) = " << block_offsets[1] - block_offsets[0] << "\n";
std::cout << "dim(W) = " << block_offsets[2] - block_offsets[1] << "\n";
std::cout << "dim(R+W) = " << block_offsets.Last() << "\n";
std::cout << "***********************************************************\n";
{
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
R_space->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
cout << "Number boundary dofs in H(div): "
<< ess_tdof_list.Size() << endl;
}
{
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
W_space->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
cout << "Number boundary dofs in H1: "
<< ess_tdof_list.Size() << endl;
}
// 7. Define the coefficients, analytical solution, and rhs of the PDE.
ConstantCoefficient k(1.0);
VectorFunctionCoefficient fcoeff(dim, fFun);
FunctionCoefficient fnatcoeff(f_natural);
FunctionCoefficient gcoeff(gFun);
VectorFunctionCoefficient ucoeff(dim, uFun_ex);
FunctionCoefficient pcoeff(pFun_ex);
// 8. Allocate memory (x, rhs) for the analytical solution and the right hand
// side. Define the GridFunction u,p for the finite element solution and
// linear forms fform and gform for the right hand side. The data
// allocated by x and rhs are passed as a reference to the grid functions
// (u,p) and the linear forms (fform, gform).
MemoryType mt = device.GetMemoryType();
BlockVector x(block_offsets, mt), rhs(block_offsets, mt);
LinearForm *fform(new LinearForm);
fform->Update(R_space, rhs.GetBlock(0), 0);
fform->AddDomainIntegrator(new VectorFEDomainLFIntegrator(fcoeff));
fform->AddBoundaryIntegrator(new VectorFEBoundaryFluxLFIntegrator(fnatcoeff));
fform->Assemble();
fform->SyncAliasMemory(rhs);
LinearForm *gform(new LinearForm);
gform->Update(W_space, rhs.GetBlock(1), 0);
gform->AddDomainIntegrator(new DomainLFIntegrator(gcoeff));
gform->Assemble();
gform->SyncAliasMemory(rhs);
// 9. Assemble the finite element matrices for the Darcy operator
//
// D = [ M B^T ]
// [ B 0 ]
// where:
//
// M = \int_\Omega k u_h \cdot v_h d\Omega u_h, v_h \in R_h
// B = -\int_\Omega \div u_h q_h d\Omega u_h \in R_h, q_h \in W_h
BilinearForm *mVarf(new BilinearForm(R_space));
MixedBilinearForm *bVarf(new MixedBilinearForm(R_space, W_space));
if (pa) { mVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(k));
mVarf->Assemble();
if (!pa) { mVarf->Finalize(); }
if (pa) { bVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
bVarf->Assemble();
if (!pa) { bVarf->Finalize(); }
BlockOperator darcyOp(block_offsets);
TransposeOperator *Bt = NULL;
if (pa)
{
Bt = new TransposeOperator(bVarf);
darcyOp.SetBlock(0,0, mVarf);
darcyOp.SetBlock(0,1, Bt, -1.0);
darcyOp.SetBlock(1,0, bVarf, -1.0);
}
else
{
SparseMatrix &M(mVarf->SpMat());
SparseMatrix &B(bVarf->SpMat());
B *= -1.;
Bt = new TransposeOperator(&B);
darcyOp.SetBlock(0,0, &M);
darcyOp.SetBlock(0,1, Bt);
darcyOp.SetBlock(1,0, &B);
}
// 10. Construct the operators for preconditioner
//
// P = [ diag(M) 0 ]
// [ 0 B diag(M)^-1 B^T ]
//
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
// pressure Schur Complement
SparseMatrix *MinvBt = NULL;
Vector Md(mVarf->Height());
BlockDiagonalPreconditioner darcyPrec(block_offsets);
Solver *invM, *invS;
SparseMatrix *S = NULL;
if (pa)
{
mVarf->AssembleDiagonal(Md);
auto Md_host = Md.HostRead();
Vector invMd(mVarf->Height());
for (int i=0; i<mVarf->Height(); ++i)
{
invMd(i) = 1.0 / Md_host[i];
}
Vector BMBt_diag(bVarf->Height());
bVarf->AssembleDiagonal_ADAt(invMd, BMBt_diag);
Array<int> ess_tdof_list; // empty
invM = new OperatorJacobiSmoother(Md, ess_tdof_list);
invS = new OperatorJacobiSmoother(BMBt_diag, ess_tdof_list);
}
else
{
SparseMatrix &M(mVarf->SpMat());
M.GetDiag(Md);
Md.HostReadWrite();
SparseMatrix &B(bVarf->SpMat());
MinvBt = Transpose(B);
for (int i = 0; i < Md.Size(); i++)
{
MinvBt->ScaleRow(i, 1./Md(i));
}
S = Mult(B, *MinvBt);
invM = new DSmoother(M);
#ifndef MFEM_USE_SUITESPARSE
invS = new GSSmoother(*S);
#else
invS = new UMFPackSolver(*S);
#endif
}
invM->iterative_mode = false;
invS->iterative_mode = false;
darcyPrec.SetDiagonalBlock(0, invM);
darcyPrec.SetDiagonalBlock(1, invS);
// 11. Solve the linear system with MINRES.
// Check the norm of the unpreconditioned residual.
int maxIter(10000);
real_t rtol(1.e-10);
real_t atol(1.e-10);
chrono.Clear();
chrono.Start();
MINRESSolver solver;
solver.SetAbsTol(atol);
solver.SetRelTol(rtol);
solver.SetMaxIter(maxIter);
solver.SetOperator(darcyOp);
solver.SetPreconditioner(darcyPrec);
solver.SetPrintLevel(1);
x = 0.0;
solver.Mult(rhs, x);
if (device.IsEnabled()) { x.HostRead(); }
chrono.Stop();
if (solver.GetConverged())
{
std::cout << "MINRES converged in " << solver.GetNumIterations()
<< " iterations with a residual norm of "
<< solver.GetFinalNorm() << ".\n";
}
else
{
std::cout << "MINRES did not converge in " << solver.GetNumIterations()
<< " iterations. Residual norm is " << solver.GetFinalNorm()
<< ".\n";
}
std::cout << "MINRES solver took " << chrono.RealTime() << "s.\n";
// 12. Create the grid functions u and p. Compute the L2 error norms.
GridFunction u, p;
u.MakeRef(R_space, x.GetBlock(0), 0);
p.MakeRef(W_space, x.GetBlock(1), 0);
int order_quad = max(2, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t err_u = u.ComputeL2Error(ucoeff, irs);
real_t norm_u = ComputeLpNorm(2., ucoeff, *mesh, irs);
real_t err_p = p.ComputeL2Error(pcoeff, irs);
real_t norm_p = ComputeLpNorm(2., pcoeff, *mesh, irs);
std::cout << "|| u_h - u_ex || / || u_ex || = " << err_u / norm_u << "\n";
std::cout << "|| p_h - p_ex || / || p_ex || = " << err_p / norm_p << "\n";
// 13. Save the mesh and the solution. This output can be viewed later using
// GLVis: "glvis -m ex5.mesh -g sol_u.gf" or "glvis -m ex5.mesh -g
// sol_p.gf".
{
ofstream mesh_ofs("ex5.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream u_ofs("sol_u.gf");
u_ofs.precision(8);
u.Save(u_ofs);
ofstream p_ofs("sol_p.gf");
p_ofs.precision(8);
p.Save(p_ofs);
}
// 14. Save data in the VisIt format
VisItDataCollection visit_dc("Example5", mesh);
visit_dc.RegisterField("velocity", &u);
visit_dc.RegisterField("pressure", &p);
visit_dc.Save();
// 15. Save data in the ParaView format
ParaViewDataCollection paraview_dc("Example5", mesh);
paraview_dc.SetPrefixPath("ParaView");
paraview_dc.SetLevelsOfDetail(order);
paraview_dc.SetCycle(0);
paraview_dc.SetDataFormat(VTKFormat::BINARY);
paraview_dc.SetHighOrderOutput(true);
paraview_dc.SetTime(0.0); // set the time
paraview_dc.RegisterField("velocity",&u);
paraview_dc.RegisterField("pressure",&p);
paraview_dc.Save();
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream u_sock(vishost, visport);
u_sock.precision(8);
u_sock << "solution\n" << *mesh << u << "window_title 'Velocity'" << endl;
socketstream p_sock(vishost, visport);
p_sock.precision(8);
p_sock << "solution\n" << *mesh << p << "window_title 'Pressure'" << endl;
}
// 17. Free the used memory.
delete fform;
delete gform;
delete invM;
delete invS;
delete S;
delete Bt;
delete MinvBt;
delete mVarf;
delete bVarf;
delete W_space;
delete R_space;
delete l2_coll;
delete hdiv_coll;
delete mesh;
return 0;
}
void uFun_ex(const Vector & x, Vector & u)
{
real_t xi(x(0));
real_t yi(x(1));
real_t zi(0.0);
if (x.Size() == 3)
{
zi = x(2);
}
u(0) = - exp(xi)*sin(yi)*cos(zi);
u(1) = - exp(xi)*cos(yi)*cos(zi);
if (x.Size() == 3)
{
u(2) = exp(xi)*sin(yi)*sin(zi);
}
}
// Change if needed
real_t pFun_ex(const Vector & x)
{
real_t xi(x(0));
real_t yi(x(1));
real_t zi(0.0);
if (x.Size() == 3)
{
zi = x(2);
}
return exp(xi)*sin(yi)*cos(zi);
}
void fFun(const Vector & x, Vector & f)
{
f = 0.0;
}
real_t gFun(const Vector & x)
{
if (x.Size() == 3)
{
return -pFun_ex(x);
}
else
{
return 0;
}
}
real_t f_natural(const Vector & x)
{
return (-pFun_ex(x));
}
+2 -1
View File
@@ -153,7 +153,8 @@ int main(int argc, char *argv[])
if (patchAssembly && reducedIntegration && !pa)
{
#ifdef MFEM_USE_SINGLE
MFEM_ABORT("Reduced integration is not supported in single precision.");
cout << "Reduced integration is not supported in single precision.\n";
return MFEM_SKIP_RETURN_VALUE;
#endif
di->SetIntegrationMode(NonlinearFormIntegrator::Mode::PATCHWISE_REDUCED);
+401
View File
@@ -0,0 +1,401 @@
// Copyright (c) 2010-2024, 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.
//
// ------------------------------------------------------------
// NURBS Solenoidal Miniapp: Project solenoidal velocity
// ------------------------------------------------------------
//
//
// Compile with: make nurbs_solenoidal
//
// Sample runs: nurbs_solenoidal -m ../../data/square-nurbs.mesh -o 2
// nurbs_solenoidal -m ../../data/cube-nurbs.mesh -o 2
//
// Description: This code projects a velocity field, and forces this field
// to be solenoidal, viz. the divergence is zero. If the correct
// discrete spaces are chosen the divergence is pointwise zero.
//
// This is achieved by solving a simple 2D/3D mixed Darcy problem
// corresponding to the saddle point system (similar to ex5)
//
// u + grad p = u_ex
// - div u = 0
//
// NURBS-based H(div) spaces only implemented for meshes
// consisting of a single patch.
//
// Here, u_ex is the specified velocity field. If u_ex is
// divergence free, we expect the pressure to converge to zero.
// We discretize with H(div) and L2/H1 conforming elements.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace mfem;
void u_2d(const Vector & x, Vector & u)
{
real_t xi(x(0));
real_t yi(x(1));
int p = 4;
u(0) = pow(xi,p + 1)*pow(yi,p );
u(1) = -pow(xi,p )*pow(yi,p + 1);
}
void u_3d(const Vector & x, Vector & u)
{
real_t xi(x(0));
real_t yi(x(1));
real_t zi(x(2));
int p = 4;
real_t cx = 3.0/4.0;
real_t cy = 2.0/3.0;
real_t cz = -cx - cy;
u(0) = cx*pow(xi,p + 1)*pow(yi,p )*pow(zi,p );
u(1) = cy*pow(xi,p )*pow(yi,p + 1)*pow(zi,p );
u(2) = cz*pow(xi,p )*pow(yi,p )*pow(zi,p + 1);
}
// Define the analytical solution and forcing terms / boundary conditions
void u_ex(const Vector & x, Vector & u)
{
if (x.Size() == 2)
{
u_2d(x, u);
}
else if (x.Size() == 3)
{
u_3d(x, u);
}
}
int main(int argc, char *argv[])
{
StopWatch chrono;
// 1. Parse command-line options.
const char *mesh_file = "../../data/square-nurbs.mesh";
int ref_levels = -1;
int order = 1;
const char *device_config = "cpu";
bool visualization = 1;
bool NURBS = true;
bool div_free = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&div_free, "-df", "--div-free", "-p","--proj",
"Div-free or standard projection.");
args.AddOption(&NURBS, "-n", "--nurbs", "-nn","--no-nurbs",
"NURBS.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(mfem::out);
return 1;
}
args.PrintOptions(mfem::out);
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 10,000
// elements.
{
if (ref_levels < 0)
{
ref_levels =
(int)floor(log(5000./mesh->GetNE())/log(2.)/dim);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a finite element space on the mesh. Here we use the
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *hdiv_coll = nullptr;
FiniteElementCollection *l2_coll = nullptr;
NURBSExtension *NURBSext = nullptr;
if (mesh->NURBSext&& NURBS)
{
hdiv_coll = new NURBS_HDivFECollection(order, dim);
l2_coll = new NURBSFECollection(order);
NURBSext = new NURBSExtension(mesh->NURBSext, order);
mfem::out<<"Create NURBS fec and ext"<<std::endl;
}
else
{
NURBS = false;
hdiv_coll = new RT_FECollection(order, dim);
l2_coll = new L2_FECollection(order, dim);
mfem::out<<"Create Normal fec"<<std::endl;
}
FiniteElementSpace *W_space = new FiniteElementSpace(mesh, NURBSext, l2_coll);
FiniteElementSpace *R_space = new FiniteElementSpace(mesh,
W_space->StealNURBSext(),
hdiv_coll);
// 6. Define the BlockStructure of the problem, i.e. define the array of
// offsets for each variable. The last component of the Array is the sum
// of the dimensions of each block.
Array<int> block_offsets(3); // number of variables + 1
block_offsets[0] = 0;
block_offsets[1] = R_space->GetVSize();
block_offsets[2] = W_space->GetVSize();
block_offsets.PartialSum();
mfem::out << "***********************************************************\n";
mfem::out << "dim(R) = " << block_offsets[1] - block_offsets[0] << "\n";
mfem::out << "dim(W) = " << block_offsets[2] - block_offsets[1] << "\n";
mfem::out << "dim(R+W) = " << block_offsets.Last() << "\n";
mfem::out << "***********************************************************\n";
// 7. Define the coefficients, analytical solution, and rhs of the PDE.
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
VectorFunctionCoefficient ucoeff(dim, u_ex);
// 8. Allocate memory (x, rhs) for the analytical solution and the right hand
// side. Define the GridFunction u,p for the finite element solution and
// linear forms fform and gform for the right hand side. The data
// allocated by x and rhs are passed as a reference to the grid functions
// (u,p) and the linear forms (fform, gform).
MemoryType mt = device.GetMemoryType();
BlockVector x(block_offsets, mt), rhs(block_offsets, mt);
rhs = 0.0;
LinearForm *fform(new LinearForm);
fform->Update(R_space, rhs.GetBlock(0), 0);
fform->AddDomainIntegrator(new VectorFEDomainLFIntegrator(ucoeff));
fform->Assemble();
fform->SyncAliasMemory(rhs);
// 9. Assemble the finite element matrices for the Darcy operator
//
// D = [ M B^T ]
// [ B 0 ]
// where:
//
// M = \int_\Omega k u_h \cdot v_h d\Omega u_h, v_h \in R_h
// B = -\int_\Omega \div u_h q_h d\Omega u_h \in R_h, q_h \in W_h
BilinearForm *mVarf(new BilinearForm(R_space));
MixedBilinearForm *bVarf(new MixedBilinearForm(R_space, W_space));
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(one));
mVarf->Assemble();
mVarf->Finalize();
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
bVarf->Assemble();
bVarf->Finalize();
SparseMatrix &M(mVarf->SpMat());
SparseMatrix &B(bVarf->SpMat());
B *= -1.;
TransposeOperator *Bt = new TransposeOperator(&B);
BlockOperator darcyOp(block_offsets);
darcyOp.SetBlock(0,0, &M);
if (div_free) { darcyOp.SetBlock(0,1, Bt); }
if (div_free) { darcyOp.SetBlock(1,0, &B); }
// 10. Construct the operators for preconditioner
//
// P = [ diag(M) 0 ]
// [ 0 B diag(M)^-1 B^T ]
//
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
// pressure Schur Complement
Vector Md(mVarf->Height());
M.GetDiag(Md);
Md.HostReadWrite();
SparseMatrix *MinvBt = Transpose(B);
for (int i = 0; i < Md.Size(); i++)
{
MinvBt->ScaleRow(i, 1./Md(i));
}
SparseMatrix *S = Mult(B, *MinvBt);
Solver *invS;
#ifndef MFEM_USE_SUITESPARSE
invS = new GSSmoother(*S);
#else
invS = new UMFPackSolver(*S);
#endif
invS->iterative_mode = false;
Solver *invM = new GSSmoother(M);
invM->iterative_mode = false;
BlockDiagonalPreconditioner darcyPrec(block_offsets);
darcyPrec.SetDiagonalBlock(0, invM);
darcyPrec.SetDiagonalBlock(1, invS);
// 11. Solve the linear system with MINRES.
// Check the norm of the unpreconditioned residual.
int maxIter(10000);
real_t rtol(10*std::numeric_limits<real_t>::epsilon());
real_t atol(10*std::numeric_limits<real_t>::epsilon());
chrono.Clear();
chrono.Start();
MINRESSolver solver;
solver.SetAbsTol(atol);
solver.SetRelTol(rtol);
solver.SetMaxIter(maxIter);
solver.SetOperator(darcyOp);
solver.SetPreconditioner(darcyPrec);
solver.SetPrintLevel(2);
x = 0.0;
solver.Mult(rhs, x);
if (device.IsEnabled()) { x.HostRead(); }
chrono.Stop();
if (solver.GetConverged())
{
mfem::out << "MINRES converged in " << solver.GetNumIterations()
<< " iterations with a residual norm of "
<< solver.GetFinalNorm() << ".\n";
}
else
{
mfem::out << "MINRES did not converge in " << solver.GetNumIterations()
<< " iterations. Residual norm is " << solver.GetFinalNorm()
<< ".\n";
}
mfem::out << "MINRES solver took " << chrono.RealTime() << "s.\n";
// 12. Create the grid functions u and p
GridFunction u, p, uu, vv, ww;
u.MakeRef(R_space, x.GetBlock(0), 0);
p.MakeRef(W_space, x.GetBlock(1), 0);
// 13. Save the mesh and the solution. This output can be viewed later using
// GLVis: "glvis -m exsol.mesh -g sol_u.gf" or "glvis -m exsol.mesh -g
// sol_p.gf".
{
ofstream mesh_ofs("exsol.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream u_ofs("sol_u.gf");
u_ofs.precision(8);
u.Save(u_ofs);
ofstream p_ofs("sol_p.gf");
p_ofs.precision(8);
p.Save(p_ofs);
}
// 14. Save data in the VisIt format
VisItDataCollection visit_dc("Solenoidal", mesh);
visit_dc.RegisterField("velocity", &u);
visit_dc.RegisterField("pressure", &p);
visit_dc.Save();
// 15. Save data in the ParaView format
ParaViewDataCollection paraview_dc("Solenoidal", mesh);
paraview_dc.SetPrefixPath("ParaView");
paraview_dc.SetLevelsOfDetail(order);
paraview_dc.SetCycle(0);
paraview_dc.SetDataFormat(VTKFormat::BINARY);
paraview_dc.SetHighOrderOutput(true);
paraview_dc.SetTime(0.0); // set the time
paraview_dc.RegisterField("velocity",&u);
paraview_dc.RegisterField("pressure",&p);
paraview_dc.Save();
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream u_sock(vishost, visport);
u_sock.precision(8);
u_sock << "solution\n" << *mesh << u << "window_title 'Velocity'" << endl;
socketstream p_sock(vishost, visport);
p_sock.precision(8);
p_sock << "solution\n" << *mesh << p << "window_title 'Pressure'" << endl;
}
// 17. Compute errors
int order_quad = 2*order+2;
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t err_u = u.ComputeL2Error(ucoeff, irs);
real_t err_p = p.ComputeL2Error(zero, irs);
real_t err_div = u.ComputeDivError(&zero, irs);
mfem::out << "|| u_h - u_ex || = " << err_u << "\n";
mfem::out << "|| div u_h - div u_ex || = " << err_div << "\n";
mfem::out << "|| p_h - p_ex || = " << err_p << "\n";
// 18. Free the used memory.
delete fform;
delete invM;
delete invS;
delete S;
delete Bt;
delete MinvBt;
delete mVarf;
delete bVarf;
delete W_space;
delete R_space;
delete l2_coll;
delete hdiv_coll;
delete mesh;
if (err_div > 1e4*std::numeric_limits<real_t>::epsilon() )
{
mfem::out << "std::numeric_limits<real_t>::epsilon() = "
<< std::numeric_limits<real_t>::epsilon() << "\n";
mfem_error("Divergence error larger than expected");
}
return 0;
}
+51
View File
@@ -0,0 +1,51 @@
# Copyright (c) 2010-2024, 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.
list(APPEND STAB_COMMON_SOURCES
stab_tau.cpp stab_condif.cpp stab_navsto.cpp)
list(APPEND STAB_COMMON_HEADERS
stab_tau.hpp stab_condif.hpp stab_navsto.hpp manu.hpp skew.hpp)
set(STAB_COMMON_FILES
EXTRA_SOURCES ${STAB_COMMON_SOURCES}
EXTRA_HEADERS ${STAB_COMMON_HEADERS})
add_mfem_miniapp(condif
MAIN condif.cpp
${STAB_COMMON_FILES}
LIBRARIES mfem)
add_mfem_miniapp(navsto
MAIN navsto.cpp
${STAB_COMMON_FILES}
LIBRARIES mfem)
if (MFEM_ENABLE_TESTING)
add_test(NAME ex_condif
COMMAND $<TARGET_FILE:condif> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
endif()
if (MFEM_USE_MPI)
add_mfem_miniapp(navsto_p
MAIN navsto_p.cpp
${STAB_COMMON_FILES}
LIBRARIES mfem)
if (MFEM_ENABLE_TESTING)
add_test(NAME navsto_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:navsto> -no-vis
${MPIEXEC_POSTFLAGS}
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
endif()
endif()
+405
View File
@@ -0,0 +1,405 @@
// Copyright (c) 2010-2024, 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.
//
// Stabilized Convection-Diffusion
#include "stab_condif.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <list>
using namespace std;
using namespace mfem;
real_t att_param = 1.0;
real_t kappa_param = 1.0;
real_t pi = (real_t)(M_PI);
using VectorFun = std::function<void(const Vector & x, Vector & a)>;
using ScalarFun = std::function<real_t(const Vector & x)>;
#include "skew.hpp"
#include "manu.hpp"
void evaluate1D(Vector &x, Vector &f, GridFunction *gf, int lod)
{
// Get Mesh and Nodes gridfunction
Mesh *mesh = gf->FESpace()->GetMesh();
GridFunction *nodes = mesh->GetNodes();
if (!nodes)
{
nodes = new GridFunction(gf->FESpace());
mesh->GetNodes(*nodes);
}
// Evaluate
std::list<pair<real_t,real_t>> sol;
Vector vals,coords;
for (int i = 0; i < mesh->GetNE(); i++)
{
int geom = mesh->GetElementBaseGeometry(i);
RefinedGeometry *refined_geo = GlobGeometryRefiner.Refine(( Geometry::Type)geom, 1, lod);
gf->GetValues(i, refined_geo->RefPts, vals);
nodes->GetValues(i, refined_geo->RefPts, coords);
for (int j = 0; j < vals.Size(); j++)
{
sol.push_back(std::make_pair(coords[j],vals[j]));
}
}
// Sort and make unique
sol.sort();
sol.unique();
// Convert to Vectors
x.SetSize(sol.size());
f.SetSize(sol.size());
int i = 0;
for (std::list<pair<real_t,real_t>>::iterator d = sol.begin() ; d != sol.end(); ++d, i++)
{
x[i] = d->first;
f[i] = d->second;
}
}
StabType GetStabilisationType(int stype)
{
switch (stype)
{
case GALERKIN:
mfem::out<<"Galerkin formulation"<<std::endl;
break;
case SUPG:
mfem::out<<"SUPG formulation"<<std::endl;
break;
case GLS:
mfem::out<<"GLS formulation"<<std::endl;
break;
case VMS:
mfem::out<<"VMS formulation"<<std::endl;
break;
default:
mfem::out<<"GAL"<<"\t"<<"SUPG"<<"\t"<<"GLS"<<"\t"<<"VMS"<<std::endl;
mfem::out<<GALERKIN<<"\t"<<SUPG<<"\t"<<GLS<<"\t"<<VMS<<std::endl;
mfem_error("Wrong formulation");
}
return (StabType) stype;
}
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/inline-quad.mesh";
const char *ref_file = "";
int problem = 0;
int sstype = -2;
bool static_cond = false;
bool visualization = false;
int lod = 0;
real_t penalty = -1;
Array<int> order(1);
order[0] = 2;
int ref_levels = 0;
bool mono = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_file, "-rf", "--ref-file",
"File with refinement data");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh.");
args.AddOption(&kappa_param , "-k", "--kappa",
"Sets the diffusion parameters, should be positive.");
args.AddOption(&att_param , "-a", "--att",
"Sets the velocity direction");
args.AddOption(&problem, "-p", "--problem",
"Select the problem to solve:\n\t"
" 0 = convection skew-to-the mesh\n\t"
" 1 = manufactured solution\n");
args.AddOption(&sstype, "-s", "--stab", " Stabilization type:\n\t"
" -2 = Galerkin\n\t"
" -1 = GLS\n\t"
" 0 = SUPG\n\t"
" 1 = VMS\n");
args.AddOption(&mono, "-mo", "--mono", "-co",
"--comp",
"Use a monolithic integrator or a composed one.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&lod, "-lod", "--level-of-detail",
"Refinement level for 1D solution output (0 means no output).");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
}
args.PrintOptions(mfem::out);
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement and knot insertion of knots defined
// in a refinement file. We choose 'ref_levels' to be the largest number
// that gives a final mesh with no more than 50,000 elements.
{
// Mesh refinement as defined in refinement file
if (mesh->NURBSext && (strlen(ref_file) != 0))
{
mesh->RefineNURBSFromFile(ref_file);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
mesh->PrintInfo();
}
// 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;
NURBSExtension *NURBSext = nullptr;
int own_fec = 1;
if (mesh->NURBSext)
{
fec = new NURBSFECollection(order[0]);
int nkv = mesh->NURBSext->GetNKV();
if (order.Size() == 1)
{
int tmp = order[0];
order.SetSize(nkv);
order = tmp;
}
if (order.Size() != nkv ) { mfem_error("Wrong number of orders set."); }
NURBSext = new NURBSExtension(mesh->NURBSext, order);
}
else if (order[0] == -1) // Isoparametric
{
if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
own_fec = 0;
mfem::out << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
mfem::out <<"Mesh does not have FEs --> Assume order 1.\n";
fec = new H1_FECollection(1, dim);
}
}
else
{
if (order.Size() > 1) { cout <<"Wrong number of orders set, needs one.\n"; }
fec = new H1_FECollection(abs(order[0]), dim);
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, NURBSext, fec);
mfem::out << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
VectorFunctionCoefficient *adv, *grad;
FunctionCoefficient *kappa,*force, *sol, *lap;
if (problem == 0)
{
if (mesh->Dimension() != 2) mfem_error("Advection skew to the mesh needs a 2D mesh!");
adv = new VectorFunctionCoefficient(mesh->Dimension(), skew::adv);
kappa= new FunctionCoefficient(skew::kappa);
force = new FunctionCoefficient(skew::force);
sol = new FunctionCoefficient(skew::sol);
grad = new VectorFunctionCoefficient(mesh->Dimension(), skew::grad);
lap = new FunctionCoefficient(skew::laplace);
}
else if (problem == 1)
{
adv = new VectorFunctionCoefficient(mesh->Dimension(), manufactured::adv);
kappa= new FunctionCoefficient(manufactured::kappa);
force = new FunctionCoefficient(manufactured::force);
sol = new FunctionCoefficient(manufactured::sol);
grad = new VectorFunctionCoefficient(mesh->Dimension(), manufactured::grad);
lap = new FunctionCoefficient(manufactured::laplace);
}
else
{
mfem_error("Incorrect problem!");
}
// 7. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
GridFunction x(fespace);
x.ProjectCoefficient(*sol);
if (problem == 1)
{
Vector norm(3);
norm[0] = x.ComputeL2Error(*sol);
norm[1] = x.ComputeGradError(grad);
norm[2] = x.ComputeLaplaceError(lap);
mfem::out << "|| x_h - x_ex || = " << norm[0] << "\n";
mfem::out << "|| grad x_h - grad x_ex || = " << norm[1] << "\n";
mfem::out << "|| lap x_h - lap x_ex || = " << norm[2] << "\n";
}
// 9. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
StabType stype = GetStabilisationType(sstype);
FFH92Tau tau (adv, kappa, fespace);
StabConDifComposition stab_condif_comp(adv, kappa, force, &tau);
BilinearForm a(fespace);
LinearForm b(fespace);
if (mono)
{
a.AddDomainIntegrator(new StabConDifIntegrator(adv, kappa, force, &tau, stype));
b.AddDomainIntegrator(new StabConDifIntegrator(adv, kappa, force, &tau, stype));
}
else
{
stab_condif_comp.SetBilinearIntegrators(&a, stype);
stab_condif_comp.SetLinearIntegrators(&b, stype);
}
a.Assemble();
b.Assemble();
if (static_cond) { a.EnableStaticCondensation(); }
SparseMatrix A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
mfem::out << "Size of linear system: " << A.Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 10. Define a simple Jacobi preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
GMRES(A, M, B, X, 1, 2000, 2000, 1e-16, 0.0);
#else
// 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
#endif
// 11. Recover the solution as a finite element grid function.
a.RecoverFEMSolution(X, b, x);
// 12. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
{
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
sol_ofs.close();
}
// 13. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
if (mesh->Dimension() == 1 && lod > 0)
{
Vector coord, val;
evaluate1D(coord, val, &x, lod);
ofstream sol_ofs("solution.dat");
for (int i = 0; i < x.Size();i++)
{
sol_ofs<<coord[i] <<"\t"<<val[i]<<endl;
}
sol_ofs.close();
}
// 14. Error computation
if (problem == 1)
{
Vector norm(3);
norm[0] = x.ComputeL2Error(*sol);
norm[1] = x.ComputeGradError(grad);
norm[2] = x.ComputeLaplaceError(lap);
mfem::out << "|| x_h - x_ex || = " << norm[0] << "\n";
mfem::out << "|| grad x_h - grad x_ex || = " << norm[1] << "\n";
mfem::out << "|| lap x_h - lap x_ex || = " << norm[2] << "\n";
}
// 15. Save data in the VisIt format
VisItDataCollection visit_dc("condif", mesh);
visit_dc.RegisterField("solution", &x);
visit_dc.Save();
// 16. Free the used memory.
delete fespace;
if (own_fec) { delete fec; }
delete mesh;
delete adv, grad;
delete kappa, force, sol, lap;
return 0;
}
+114
View File
@@ -0,0 +1,114 @@
namespace manufactured
{
//----------------------------------------------------------
void adv(const Vector & x, Vector & a)
{
a[1] = 1.0/(1.0 + att_param*att_param);
a[0] = sqrt(1.0 - a[1]*a[1]);
}
//----------------------------------------------------------
real_t kappa(const Vector & x)
{
return kappa_param;
}
//----------------------------------------------------------
real_t force(const Vector & x)
{
int d = x.Size();
Vector a(d);
adv(x, a);
real_t ax = a[0];
real_t ay = 0.0;
real_t az = 0.0;
real_t k = kappa(x);
real_t sx = sin(pi*x[0]);
real_t cx = cos(pi*x[0]);
real_t sy = 1.0;
real_t cy = 1.0;
real_t sz = 1.0;
real_t cz = 1.0;
if (d >= 2)
{
sy = sin(pi*x[1]);
cy = cos(pi*x[1]);
ay = a[1];
}
if (d >= 3)
{
sz = sin(pi*x[2]);
cz = cos(pi*x[2]);
az = a[2];
}
return ax*pi*cx*sy*sz
+ ay*pi*sx*cy*sz
+ az*pi*sx*sy*cz + d*k*pi*pi*sx*sy*sz;
}
//----------------------------------------------------------
real_t sol(const Vector & x)
{
real_t sx = sin(pi*x[0]);
real_t sy = 1.0;
real_t sz = 1.0;
int d = x.Size();
if (d >= 2)
{
sy = sin(pi*x[1]);
}
if (d >= 3)
{
sz = sin(pi*x[2]);
}
return sx*sy*sz;
}
//----------------------------------------------------------
void grad(const Vector & x, Vector &grad)
{
real_t sx = sin(pi*x[0]);
real_t sy = 1.0;
real_t sz = 1.0;
real_t gx = pi*cos(pi*x[0]);
real_t gy = 0.0;
real_t gz = 0.0;
grad[0] = gx;
int d = x.Size();
if (d >= 2)
{
sy = sin(pi*x[1]);
gy = pi*cos(pi*x[1]);
grad[0] = gx*sy;
grad[1] = sx*gy;
}
if (d >= 3)
{
sz = sin(pi*x[2]);
gz = pi*cos(pi*x[2]);
grad[0] = gx*sy*sz;
grad[1] = sx*gy*sz;
grad[2] = sx*sy*gz;
}
}
//----------------------------------------------------------
real_t laplace(const Vector & x)
{
return -x.Size()*pi*pi*sol(x);
}
}
+282
View File
@@ -0,0 +1,282 @@
// Copyright (c) 2010-2024, 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.
//
// Stabilized Navier-Stokes
#include "stab_navsto.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <list>
using namespace std;
using namespace mfem;
real_t kappa_param = 1.0;
real_t pi = (real_t)(M_PI);
using VectorFun = std::function<void(const Vector & x, Vector & a)>;
using ScalarFun = std::function<real_t(const Vector & x)>;
void sol_fun(const Vector & x, Vector &sol)
{
sol = 0.0;
if ((x[1] - 0.99 > 0.0) &&
(fabs(x[0] - 0.5) < 0.49) )
{
sol[0] = 1.0;
}
}
real_t kappa_fun(const Vector & x)
{
return kappa_param;
}
void force_fun(const Vector & x, Vector &f)
{
f = 0.0;
// f[0] = x[1]*(1.0-x[1])*x[0]*(1.0-x[0]);
}
StabType GetStabilisationType(int stype)
{
switch (stype)
{
case GALERKIN:
mfem::out<<"Galerkin formulation"<<std::endl;
break;
case SUPG:
mfem::out<<"SUPG formulation"<<std::endl;
break;
case GLS:
mfem::out<<"GLS formulation"<<std::endl;
break;
case VMS:
mfem::out<<"VMS formulation"<<std::endl;
break;
default:
mfem::out<<"GAL"<<"\t"<<"SUPG"<<"\t"<<"GLS"<<"\t"<<"VMS"<<std::endl;
mfem::out<<GALERKIN<<"\t"<<SUPG<<"\t"<<GLS<<"\t"<<VMS<<std::endl;
mfem_error("Wrong formulation");
}
return (StabType) stype;
}
int main(int argc, char *argv[])
{
// Parse command-line options.
const char *mesh_file = "../../data/inline-quad.mesh";
const char *ref_file = "";
int problem = 0;
int sstype = -2;
bool static_cond = false;
bool visualization = false;
real_t penalty = -1;
int order = 1;
int ref_levels = 0;
bool mono = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_file, "-rf", "--ref-file",
"File with refinement data");
args.AddOption(&order, "-o", "--order",
"Finite element order isoparametric space.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh.");
args.AddOption(&kappa_param , "-k", "--kappa",
"Sets the diffusion parameters, should be positive.");
args.AddOption(&problem, "-p", "--problem",
"Select the problem to solve:\n\t"
" 0 = convection skew-to-the mesh\n\t"
" 1 = manufactured solution\n");
args.AddOption(&sstype, "-s", "--stab", " Stabilization type:\n\t"
" -2 = Galerkin\n\t"
" -1 = GLS\n\t"
" 0 = SUPG\n\t"
" 1 = VMS\n");
args.AddOption(&mono, "-mo", "--mono", "-co",
"--comp",
"Use a monolithic integrator or a composed one.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
}
args.PrintOptions(mfem::out);
// Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
// Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement and knot insertion of knots defined
// in a refinement file. We choose 'ref_levels' to be the largest number
// that gives a final mesh with no more than 50,000 elements.
{
// Mesh refinement as defined in refinement file
if (mesh.NURBSext && (strlen(ref_file) != 0))
{
mesh.RefineNURBSFromFile(ref_file);
}
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
mesh.PrintInfo();
}
// 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.
Array<FiniteElementCollection *> fecs(2);
fecs[0] = new H1_FECollection(order, dim);
fecs[1] = new H1_FECollection(order, dim);
Array<FiniteElementSpace *> spaces(2);
spaces[0] = new FiniteElementSpace(&mesh, fecs[0], dim);
spaces[1] = new FiniteElementSpace(&mesh, fecs[1]);
mfem::out << "Number of finite element unknowns:\n"
<< "\tVelocity = "<<spaces[0]->GetTrueVSize() << endl
<< "\tPressure = "<<spaces[1]->GetTrueVSize() << endl;
// Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<Array<int> *> ess_bdr(2);
Array<int> ess_tdof_list;
Array<int> ess_bdr_u(spaces[0]->GetMesh()->bdr_attributes.Max());
Array<int> ess_bdr_p(spaces[1]->GetMesh()->bdr_attributes.Max());
ess_bdr_p = 0;
ess_bdr_u = 1;
ess_bdr[0] = &ess_bdr_u;
ess_bdr[1] = &ess_bdr_p;
// Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
// Define the solution vector xp as a finite element grid function
Array<int> bOffsets(3);
bOffsets[0] = 0;
bOffsets[1] = spaces[0]->GetTrueVSize();
bOffsets[2] = spaces[1]->GetTrueVSize();
bOffsets.PartialSum();
BlockVector xp(bOffsets);
GridFunction x_u(spaces[0]);
GridFunction x_p(spaces[1]);
x_u.MakeTRef(spaces[0], xp.GetBlock(0), 0);
x_p.MakeTRef(spaces[1], xp.GetBlock(1), 0);
VectorFunctionCoefficient sol(dim, sol_fun);
x_u.ProjectCoefficient(sol);
x_p = 0.0;
x_u.SetTrueVector();
x_p.SetTrueVector();
// Define the output
VisItDataCollection visit_dc("navsto", &mesh);
visit_dc.RegisterField("u", &x_u);
visit_dc.RegisterField("p", &x_p);
visit_dc.SetCycle(0);
visit_dc.Save();
// Define the problem parameters
FunctionCoefficient kappa(kappa_fun);
VectorFunctionCoefficient force(dim, force_fun);
// Define the stabilisation parameters
VectorGridFunctionCoefficient adv(&x_u);
ElasticInverseEstimateCoefficient invEst(spaces[0]);
FFH92Tau tau(&adv, &kappa, &invEst, 4.0);
FF91Delta delta(&adv, &kappa, &invEst);
tau.print = delta.print = true;
// Define the block nonlinear form
BlockNonlinearForm Hform(spaces);
Hform.AddDomainIntegrator(new StabInNavStoIntegrator(kappa, force, tau, delta));
Array<Vector *> rhs(2);
rhs = nullptr; // Set all entries in the array
Hform.SetEssentialBC(ess_bdr, rhs);
// Set up the preconditioner
JacobianPreconditioner jac_prec(bOffsets,
Array<Solver *>({new GSSmoother(0,5),
new GSSmoother(0,5)}));
// Set up the Jacobian solver
GeneralResidualMonitor j_monitor("\t\t\t\tFGMRES", 25);
FGMRESSolver j_gmres;
j_gmres.iterative_mode = false;
j_gmres.SetRelTol(1e-2);
j_gmres.SetAbsTol(1e-12);
j_gmres.SetMaxIter(300);
j_gmres.SetPrintLevel(-1);
j_gmres.SetMonitor(j_monitor);
j_gmres.SetPreconditioner(jac_prec);
// Set up the newton solver
SystemResidualMonitor newton_monitor("Newton", 1, bOffsets, &visit_dc);
NewtonSolver newton_solver;
newton_solver.iterative_mode = true;
newton_solver.SetPrintLevel(-1);
newton_solver.SetMonitor(newton_monitor);
newton_solver.SetRelTol(1e-4);
newton_solver.SetAbsTol(1e-8);
newton_solver.SetMaxIter(25);
newton_solver.SetSolver(j_gmres);
newton_solver.SetOperator(Hform);
// Solve the Newton system
Vector zero;
newton_solver.Mult(zero, xp);
// Save data in the VisIt format
visit_dc.SetCycle(999999);
visit_dc.Save();
// Free the used memory.
for (int i = 0; i < fecs.Size(); ++i)
{
delete fecs[i];
}
for (int i = 0; i < spaces.Size(); ++i)
{
delete spaces[i];
}
return 0;
}
+297
View File
@@ -0,0 +1,297 @@
// Copyright (c) 2010-2024, 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.
//
// Stabilized Navier-Stokes
#include "stab_navsto.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <list>
using namespace std;
using namespace mfem;
real_t kappa_param = 1.0;
real_t pi = (real_t)(M_PI);
using VectorFun = std::function<void(const Vector & x, Vector & a)>;
using ScalarFun = std::function<real_t(const Vector & x)>;
void sol_fun(const Vector & x, Vector &sol)
{
sol = 0.0;
if ((x[1] - 0.99 > 0.0) &&
(fabs(x[0] - 0.5) < 0.49) )
{
sol[0] = 1.0;
}
}
real_t kappa_fun(const Vector & x)
{
return kappa_param;
}
void force_fun(const Vector & x, Vector &f)
{
f = 0.0;
// f[0] = x[1]*(1.0-x[1])*x[0]*(1.0-x[0]);
}
StabType GetStabilisationType(int stype)
{
switch (stype)
{
case GALERKIN:
mfem::out<<"Galerkin formulation"<<std::endl;
break;
case SUPG:
mfem::out<<"SUPG formulation"<<std::endl;
break;
case GLS:
mfem::out<<"GLS formulation"<<std::endl;
break;
case VMS:
mfem::out<<"VMS formulation"<<std::endl;
break;
default:
mfem::out<<"GAL"<<"\t"<<"SUPG"<<"\t"<<"GLS"<<"\t"<<"VMS"<<std::endl;
mfem::out<<GALERKIN<<"\t"<<SUPG<<"\t"<<GLS<<"\t"<<VMS<<std::endl;
mfem_error("Wrong formulation");
}
return (StabType) stype;
}
int main(int argc, char *argv[])
{
// Initialize MPI and HYPRE.
Mpi::Init(argc, argv);
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
// Parse command-line options.
const char *mesh_file = "../../data/inline-quad.mesh";
const char *ref_file = "";
int problem = 0;
int sstype = -2;
bool static_cond = false;
bool visualization = false;
real_t penalty = -1;
int order = 1;
int ref_levels = 0;
bool mono = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_file, "-rf", "--ref-file",
"File with refinement data");
args.AddOption(&order, "-o", "--order",
"Finite element order isoparametric space.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh.");
args.AddOption(&kappa_param , "-k", "--kappa",
"Sets the diffusion parameters, should be positive.");
args.AddOption(&problem, "-p", "--problem",
"Select the problem to solve:\n\t"
" 0 = convection skew-to-the mesh\n\t"
" 1 = manufactured solution\n");
args.AddOption(&sstype, "-s", "--stab", " Stabilization type:\n\t"
" -2 = Galerkin\n\t"
" -1 = GLS\n\t"
" 0 = SUPG\n\t"
" 1 = VMS\n");
args.AddOption(&mono, "-mo", "--mono", "-co",
"--comp",
"Use a monolithic integrator or a composed one.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0) args.PrintUsage(cout);
return 1;
}
if (myid == 0) args.PrintOptions(cout);
// Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
// Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement and knot insertion of knots defined
// in a refinement file. We choose 'ref_levels' to be the largest number
// that gives a final mesh with no more than 50,000 elements.
{
// Mesh refinement as defined in refinement file
if (mesh.NURBSext && (strlen(ref_file) != 0))
{
mesh.RefineNURBSFromFile(ref_file);
}
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
if (myid == 0) mesh.PrintInfo();
}
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
// 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.
Array<FiniteElementCollection *> fecs(2);
fecs[0] = new H1_FECollection(order, dim);
fecs[1] = new H1_FECollection(order, dim);
Array<ParFiniteElementSpace *> spaces(2);
spaces[0] = new ParFiniteElementSpace(&pmesh, fecs[0], dim);//, Ordering::byVDIM);
spaces[1] = new ParFiniteElementSpace(&pmesh, fecs[1]);
Array<int> tdof(num_procs),udof(num_procs),pdof(num_procs);
tdof = 0;
tdof[myid] = spaces[0]->TrueVSize();
MPI_Reduce(tdof.GetData(), udof.GetData(), num_procs, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
tdof = 0;
tdof[myid] = spaces[1]->TrueVSize();
MPI_Reduce(tdof.GetData(), pdof.GetData(), num_procs, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
if (myid == 0)
{
mfem::out << "Number of finite element unknowns:\n";
mfem::out << "\tVelocity = "<<spaces[0]->GlobalTrueVSize() << endl;
mfem::out << "\tPressure = "<<spaces[1]->GlobalTrueVSize() << endl;
mfem::out << "Number of finite element unknowns per partition:\n";
mfem::out << "\tVelocity = ";udof.Print(mfem::out, num_procs);
mfem::out << "\tPressure = ";pdof.Print(mfem::out, num_procs);
}
// Mark all velocity boundary dofs as essential
Array<Array<int> *> ess_bdr(2);
// Array<int> ess_tdof_list;
Array<int> ess_bdr_u(spaces[0]->GetMesh()->bdr_attributes.Max());
Array<int> ess_bdr_p(spaces[1]->GetMesh()->bdr_attributes.Max());
ess_bdr_p = 0;
ess_bdr_u = 1;
ess_bdr[0] = &ess_bdr_u;
ess_bdr[1] = &ess_bdr_p;
// Define the solution vector xp as a finite element grid function
Array<int> bOffsets(3);
bOffsets[0] = 0;
bOffsets[1] = spaces[0]->TrueVSize();
bOffsets[2] = spaces[1]->TrueVSize();
bOffsets.PartialSum();
BlockVector xp(bOffsets);
ParGridFunction x_u(spaces[0]);
ParGridFunction x_p(spaces[1]);
VectorFunctionCoefficient sol(dim, sol_fun);
x_u.ProjectCoefficient(sol);
x_p = 0.0;
x_u.GetTrueDofs(xp.GetBlock(0));
x_p.GetTrueDofs(xp.GetBlock(1));
VisItDataCollection visit_dc("navsto", &pmesh);
visit_dc.RegisterField("u", &x_u);
visit_dc.RegisterField("p", &x_p);
visit_dc.SetCycle(0);
visit_dc.Save();
// Define the problem parameters
FunctionCoefficient kappa(kappa_fun);
VectorFunctionCoefficient force(dim, force_fun);
// Define the stabilisation parameters
VectorGridFunctionCoefficient adv(&x_u);
ElasticInverseEstimateCoefficient invEst(spaces[0]);
FFH92Tau tau(&adv, &kappa, &invEst, 4.0);
FF91Delta delta(&adv, &kappa, &invEst);
tau.print = delta.print = (myid == 0);
// Define the block nonlinear form
ParBlockNonlinearForm Hform(spaces);
Hform.AddDomainIntegrator(new StabInNavStoIntegrator(kappa, force, tau, delta));
Array<Vector *> rhs(2);
rhs = nullptr; // Set all entries in the array
Hform.SetEssentialBC(ess_bdr, rhs);
// Set up the preconditioner
JacobianPreconditioner jac_prec(bOffsets,
Array<Solver *>({new HypreSmoother(),
new HypreSmoother()}));
// Set up the Jacobian solver
GeneralResidualMonitor j_monitor(MPI_COMM_WORLD,"\t\t\t\tFGMRES", 25);
FGMRESSolver j_gmres(MPI_COMM_WORLD);
j_gmres.iterative_mode = false;
j_gmres.SetRelTol(1e-2);
j_gmres.SetAbsTol(1e-12);
j_gmres.SetMaxIter(300);
j_gmres.SetPrintLevel(-1);
j_gmres.SetMonitor(j_monitor);
j_gmres.SetPreconditioner(jac_prec);
// Set up the newton solver
SystemResidualMonitor newton_monitor(MPI_COMM_WORLD,"Newton", 1, bOffsets, &visit_dc, &xp,
Array<ParGridFunction *>({&x_u, &x_p}));
NewtonSolver newton_solver(MPI_COMM_WORLD);
newton_solver.iterative_mode = true;
newton_solver.SetPrintLevel(-1);
newton_solver.SetMonitor(newton_monitor);
newton_solver.SetRelTol(1e-4);
newton_solver.SetAbsTol(1e-8);
newton_solver.SetMaxIter(25);
newton_solver.SetSolver(j_gmres);
newton_solver.SetOperator(Hform);
// Solve the Newton system
Vector zero;
newton_solver.Mult(zero, xp);
// Save data in the VisIt format
// Define the output
// Save data in the VisIt format
visit_dc.SetCycle(999999);
visit_dc.Save();
// Free the used memory.
for (int i = 0; i < fecs.Size(); ++i)
{
delete fecs[i];
}
for (int i = 0; i < spaces.Size(); ++i)
{
delete spaces[i];
}
return 0;
}
+46
View File
@@ -0,0 +1,46 @@
namespace skew
{
//----------------------------------------------------------
void adv(const Vector & x, Vector & a)
{
a[1] = 1.0/(1.0 + att_param*att_param);
a[0] = sqrt(1.0 - a[1]*a[1]);
}
//----------------------------------------------------------
real_t kappa(const Vector & x)
{
return kappa_param;
}
//----------------------------------------------------------
real_t force(const Vector & x)
{
return 0.0;
}
//----------------------------------------------------------
real_t sol(const Vector & x)
{
if ((x[1] - x[0] - 0.2 < 0.0)
&(x[0] + x[1] -0.99 < 0.0))
{
return 1.0;
}
return 0.0;
}
//----------------------------------------------------------
void grad(const Vector & x, Vector &grad)
{
grad = 0.0;
}
//----------------------------------------------------------
real_t laplace(const Vector & x)
{
return 0.0;
}
}
+234
View File
@@ -0,0 +1,234 @@
// Copyright (c) 2010-2024, 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 "stab_condif.hpp"
using namespace mfem;
StabConDifIntegrator::StabConDifIntegrator(VectorCoefficient *a,
Coefficient *k,
Coefficient *f,
Tau *t, StabType s)
: adv(a), kappa(k), force(f), tau(t), stab(s), own_tau(false)
{
if (tau == nullptr)
{
tau = new FFH92Tau(adv, kappa, 12.0);
own_tau = true;
}
else
{
tau->SetConvection(adv);
tau->SetDiffusion(kappa);
}
}
StabConDifIntegrator::~StabConDifIntegrator()
{
if (own_tau) { delete tau; }
}
const IntegrationRule &StabConDifIntegrator::GetRule(
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans)
{
int order = trial_fe.GetOrder() + test_fe.GetOrder();
return IntRules.Get(trial_fe.GetGeomType(), order);
}
void StabConDifIntegrator::AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat )
{
int nd = el.GetDof();
int dim = el.GetDim();
real_t w,k,t = 0;
Vector a(dim);
elmat.SetSize(nd);
shape.SetSize(nd);
dshape.SetSize(nd,dim);
adshape.SetSize(nd);
laplace.SetSize(nd);
trail.SetSize(nd);
test.SetSize(nd);
const IntegrationRule *ir = NonlinearFormIntegrator::IntRule ? NonlinearFormIntegrator::IntRule : &GetRule(el, el, Trans);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
w = Trans.Weight() * ip.weight;
// Calculate shapes
el.CalcPhysShape(Trans, shape);
el.CalcPhysDShape(Trans, dshape);
// Evaluate coefficients
k = kappa->Eval(Trans, ip);
adv->Eval(a, Trans, ip);
// Galerkin convection term
dshape.Mult(a, adshape);
AddMult_a_VWt(w, shape, adshape, elmat);
// Galerkin diffusion term
AddMult_a_AAt(w*k, dshape, elmat);
if (stab != GALERKIN)
{
// Calculate shapes
el.CalcPhysLaplacian(Trans, laplace);
// Evaluate coefficients
t = tau->Eval(Trans, ip);
// Stablization term
// - GLS: stab = -1
// - SUPG: stab = 0
// - VMS: stab = +1
add(adshape, stab*k, laplace, test);
add(adshape, -k, laplace, trail);
AddMult_a_VWt(w*t, test, trail, elmat);
}
}
}
void StabConDifIntegrator::AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Trans,
Vector &elvect)
{
int nd = el.GetDof();
int dim = el.GetDim();
real_t w,k,t,f;
Vector a(dim);
elvect.SetSize(nd);
shape.SetSize(nd);
dshape.SetSize(nd,dim);
adshape.SetSize(nd);
laplace.SetSize(nd);
test.SetSize(nd);
const IntegrationRule *ir = LinearFormIntegrator::IntRule ? LinearFormIntegrator::IntRule : &GetRule(el, el, Trans);
elvect = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
w = Trans.Weight() * ip.weight;
// Calculate shapes
el.CalcPhysShape(Trans, shape);
// Evaluate coefficients
f = force->Eval(Trans, ip);
// Galerkin term
elvect.Add(w*f, shape);
if (stab != GALERKIN)
{
// Calculate shapes
el.CalcPhysDShape(Trans, dshape);
el.CalcPhysLaplacian(Trans, laplace);
// Evaluate coefficients
k = kappa->Eval(Trans, ip);
adv->Eval(a, Trans, ip);
t = tau->Eval(Trans, ip);
// Advective derivative
dshape.Mult(a, adshape);
// Stablization term
// - GLS: stab = -1
// - SUPG: stab = 0
// - VMS: stab = +1
add(adshape, stab*k, laplace, test);
elvect.Add(w*f*t, test);
}
}
}
StabConDifComposition::StabConDifComposition(VectorCoefficient *a,
Coefficient *k,
Coefficient *f,
Tau *t)
: adv(a), kappa(k), force(f), tau(t), own_tau(false)
{
if (tau == nullptr)
{
tau = new FFH92Tau(adv, kappa, 12.0);
own_tau = true;
}
else
{
tau->SetConvection(adv);
tau->SetDiffusion(kappa);
}
// SUPG coefficients
adv_tau = new ScalarVectorProductCoefficient(*tau, *adv);
adv_tau_force = new ScalarVectorProductCoefficient(*force, *adv_tau);
adv_tau_kappa = new ScalarVectorProductCoefficient(*kappa, *adv_tau);
adv_tau_adv = new OuterProductCoefficient(*adv_tau, *adv);
// GLS/VMS coefficients
kappa_tau = new ProductCoefficient(*kappa, *tau);
kappa_tau_kappa = new ProductCoefficient(*kappa_tau, *kappa);
kappa_tau_force = new ProductCoefficient(*kappa_tau, *force);
}
StabConDifComposition::~StabConDifComposition()
{
if (own_tau) { delete tau; }
delete adv_tau, adv_tau_kappa, adv_tau_adv, adv_tau_force,
kappa_tau, kappa_tau_kappa,kappa_tau_force;
}
void StabConDifComposition::SetBilinearIntegrators(BilinearForm *a, StabType stype)
{
a->AddDomainIntegrator(new ConservativeConvectionIntegrator(*adv));
a->AddDomainIntegrator(new DiffusionIntegrator(*kappa));
if (stype == GALERKIN) return;
// Add SUPG terms
a->AddDomainIntegrator(new DiffusionIntegrator(*adv_tau_adv));
a->AddDomainIntegrator(new GradLaplaceIntegrator(*adv_tau_kappa, 1.0));
if (stype == SUPG) return;
// Add VMS/GLS terms
real_t s = (stype == GLS)? -1.0: 1.0;
a->AddDomainIntegrator(new LaplaceGradIntegrator(*adv_tau_kappa,-s));
a->AddDomainIntegrator(new LaplaceLaplaceIntegrator(*kappa_tau_kappa,-s));
}
void StabConDifComposition::SetLinearIntegrators(LinearForm *b, StabType stype)
{
b->AddDomainIntegrator(new DomainLFIntegrator(*force));
if (stype == GALERKIN) return;
// Add SUPG terms
b->AddDomainIntegrator(new DomainLFGradIntegrator(*adv_tau_force));
if (stype == SUPG) return;
// Add VMS/GLS terms
real_t s = (stype == GLS)? -1.0: 1.0;
b->AddDomainIntegrator(new DomainLFLaplaceIntegrator(*kappa_tau_force,-s));
}
+130
View File
@@ -0,0 +1,130 @@
// Copyright (c) 2010-2024, 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_STAB_CONDIF_HPP
#define MFEM_STAB_CONDIF_HPP
#include "mfem.hpp"
#include "stab_tau.hpp"
namespace mfem
{
/** This Class defines a monolithic integrator for stabilized multi-dimensional
convection-diffusion.
$(a \cdot \nabla u, v) + (\kappa \nabla u, \nabla v)
+ \sum (a \cdot \nabla u - \kappa \Delta u, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
$(f, \nabla v)
+ \sum (f, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
*/
class StabConDifIntegrator : public BilinearFormIntegrator,
public LinearFormIntegrator
{
protected:
/// The advection field
VectorCoefficient *adv;
/// The diffusion parameter and force fields
Coefficient *kappa, *force;
/// The stabilization parameter
Tau *tau;
bool own_tau;
StabType stab;
private:
Vector laplace, shape, adshape, trail, test;
DenseMatrix dshape;
public:
StabConDifIntegrator(VectorCoefficient *a,
Coefficient *k,
Coefficient *f,
Tau *t = nullptr, StabType s = GALERKIN);
~StabConDifIntegrator();
virtual void AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Tr,
DenseMatrix &elmat);
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans);
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect);
using LinearFormIntegrator::AssembleRHSElementVect;
};
/** This Class composes standard integrators to obtain a stabilized formulation for
multi-dimensional convection-diffusion.
$(a \cdot \nabla u, v) + (\kappa \nabla u, \nabla v)
+ \sum (a \cdot \nabla u - \kappa \Delta u, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
$(f, \nabla v)
+ \sum (f, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
*/
class StabConDifComposition
{
private:
/// The advection field
VectorCoefficient *adv;
/// The diffusion parameter and force fields
Coefficient *kappa, *force;
/// The stabilization parameter
Tau *tau;
bool own_tau;
//// Helper coefficients for defining the weak forms
VectorCoefficient *adv_tau;
Coefficient *kappa_tau;
/// SUPG coefficients
VectorCoefficient *adv_tau_force;
VectorCoefficient *adv_tau_kappa;
MatrixCoefficient *adv_tau_adv;
/// GLS/VMS coefficients
Coefficient *kappa_tau_kappa;
Coefficient *kappa_tau_force;
public:
/** Constructor
@a a: is the advection velocity field.
@a k: is the diffusion param field.
@a f: is the force field. */
StabConDifComposition(VectorCoefficient *a,
Coefficient *k,
Coefficient *f,
Tau *t = nullptr);
/// Destructor
~StabConDifComposition();
/// This method sets the integrators for the bilinearform
void SetBilinearIntegrators(BilinearForm *a, StabType s);
/// This method sets the integrators for the linearform
void SetLinearIntegrators(LinearForm *b, StabType s);
};
} // namespace mfem
#endif
+394
View File
@@ -0,0 +1,394 @@
// Copyright (c) 2010-2024, 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 "stab_navsto.hpp"
using namespace mfem;
StabInNavStoIntegrator::StabInNavStoIntegrator(Coefficient &mu_,
VectorCoefficient &force_,
Tau &t, Tau &d, StabType s)
: c_mu(&mu_), c_force(&force_), tau(&t), delta(&d), stab(s)
{ }
void StabInNavStoIntegrator::SetDim(int dim_)
{
if (dim_ != dim)
{
dim = dim_;
u.SetSize(dim);
f.SetSize(dim);
res.SetSize(dim);
up.SetSize(dim);
grad_u.SetSize(dim);
hess_u.SetSize(dim, (dim*(dim+1))/2);
grad_p.SetSize(dim);
hmap.SetSize(dim,dim);
if (dim == 2)
{
hmap(0,0) = 0;
hmap(0,1) = hmap(1,0) = 1;
hmap(1,1) = 2;
}
else if (dim == 2)
{
hmap(0,0) = 0;
hmap(0,1) = hmap(1,0) = 1;
hmap(0,2) = hmap(2,0) = 2;
hmap(1,1) = 3;
hmap(1,2) = hmap(2,1) = 4;
hmap(2,2) = 5;
}
else
{
mfem_error("Only implemented for 2D and 3D");
}
}
}
real_t StabInNavStoIntegrator::GetElementEnergy(
const Array<const FiniteElement *>&el,
ElementTransformation &Tr,
const Array<const Vector *>&elfun)
{
if (el.Size() != 2)
{
mfem_error("StabInNavStoIntegrator::GetElementEnergy"
" has incorrect block finite element space size!");
}
SetDim(el[0]->GetDim());
int dof_u = el[0]->GetDof();
sh_u.SetSize(dof_u);
elf_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
int intorder = 2*el[0]->GetOrder();
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
real_t energy = 0.0;
for (int i = 0; i < ir.GetNPoints(); ++i)
{
const IntegrationPoint &ip = ir.IntPoint(i);
Tr.SetIntPoint(&ip);
real_t w = ip.weight * Tr.Weight();
el[0]->CalcPhysShape(Tr, sh_u);
elf_u.MultTranspose(sh_u, u);
energy += w*(u*u)/2;
}
return energy;
}
void StabInNavStoIntegrator::AssembleElementVector(
const Array<const FiniteElement *> &el,
ElementTransformation &Tr,
const Array<const Vector *> &elfun,
const Array<Vector *> &elvec)
{
if (el.Size() != 2)
{
mfem_error("StabInNavStoIntegrator::AssembleElementVector"
" has finite element space of incorrect block number");
}
int dof_u = el[0]->GetDof();
int dof_p = el[1]->GetDof();
SetDim(el[0]->GetDim());
int spaceDim = Tr.GetSpaceDim();
bool hess = (el[0]->GetDerivType() == (int) FiniteElement::HESS);
if (dim != spaceDim)
{
mfem_error("StabInNavStoIntegrator::AssembleElementVector"
" is not defined on manifold meshes");
}
elvec[0]->SetSize(dof_u*dim);
elvec[1]->SetSize(dof_p);
*elvec[0] = 0.0;
*elvec[1] = 0.0;
elf_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
elv_u.UseExternalData(elvec[0]->GetData(), dof_u, dim);
sh_u.SetSize(dof_u);
shg_u.SetSize(dof_u, dim);
ushg_u.SetSize(dof_u);
shh_u.SetSize(dof_u, (dim*(dim+1))/2);
sh_p.SetSize(dof_p);
shg_p.SetSize(dof_p, dim);
int intorder = 2*el[0]->GetOrder();
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
for (int i = 0; i < ir.GetNPoints(); ++i)
{
const IntegrationPoint &ip = ir.IntPoint(i);
Tr.SetIntPoint(&ip);
real_t w = ip.weight * Tr.Weight();
real_t mu = c_mu->Eval(Tr, ip);
c_force->Eval(f, Tr, ip);
// Compute shape and interpolate
el[0]->CalcPhysShape(Tr, sh_u);
elf_u.MultTranspose(sh_u, u);
el[0]->CalcPhysDShape(Tr, shg_u);
shg_u.Mult(u, ushg_u);
MultAtB(elf_u, shg_u, grad_u);
if (hess)
{
el[0]->CalcPhysHessian(Tr,shh_u);
MultAtB(elf_u, shh_u, hess_u);
}
else
{
shh_u = 0.0;
hess_u = 0.0;
}
el[1]->CalcPhysShape(Tr, sh_p);
real_t p = sh_p*(*elfun[1]);
el[1]->CalcPhysDShape(Tr, shg_p);
shg_p.MultTranspose(*elfun[1], grad_p);
// Compute strong residual
grad_u.Mult(u,res); // Add convection
res += grad_p; // Add pressure
res -= f; // Subtract force
for (int i = 0; i < dim; ++i)
{
for (int j = 0; j < dim; ++j)
{
res[j] -= mu*(hess_u(j,hmap(i,i)) +
hess_u(i,hmap(j,i))); // Add diffusion
}
}
// Compute stability params
real_t t = tau->Eval(Tr, ip);
real_t d = delta->Eval(Tr, ip);
// Compute momentum weak residual
flux.Diag(-p + d*grad_u.Trace(),dim); // Add pressure & LSIC to flux
grad_u.Symmetrize(); // Grad to strain
flux.Add(2*mu,grad_u); // Add stress to flux
AddMult_a_VVt(-1.0, u, flux); // Add convection to flux
AddMult_a_VWt(t, res, u, flux); // Add SUPG to flux --> check order u and res
AddMult_a_ABt(w, shg_u, flux, elv_u); // Add flux term to rhs
AddMult_a_VWt(-w, sh_u, f, elv_u); // Add force term to rhs
// Compute momentum weak residual
elvec[1]->Add(w*grad_u.Trace(), sh_p); // Add Galerkin term
shg_p.Mult(res, sh_p); // PSPG help term
elvec[1]->Add(w*t, sh_p); // Add PSPG term - sign looks worng?
}
}
void StabInNavStoIntegrator::AssembleElementGrad(
const Array<const FiniteElement*> &el,
ElementTransformation &Tr,
const Array<const Vector *> &elfun,
const Array2D<DenseMatrix *> &elmats)
{
int dof_u = el[0]->GetDof();
int dof_p = el[1]->GetDof();
SetDim(el[0]->GetDim());
bool hess = (el[0]->GetDerivType() == (int) FiniteElement::HESS);
elf_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
elmats(0,0)->SetSize(dof_u*dim, dof_u*dim);
elmats(0,1)->SetSize(dof_u*dim, dof_p);
elmats(1,0)->SetSize(dof_p, dof_u*dim);
elmats(1,1)->SetSize(dof_p, dof_p);
*elmats(0,0) = 0.0;
*elmats(0,1) = 0.0;
*elmats(1,0) = 0.0;
*elmats(1,1) = 0.0;
sh_u.SetSize(dof_u);
shg_u.SetSize(dof_u, dim);
ushg_u.SetSize(dof_u);
sh_p.SetSize(dof_p);
shg_p.SetSize(dof_p, dim);
int intorder = 2*el[0]->GetOrder();
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
for (int i = 0; i < ir.GetNPoints(); ++i)
{
const IntegrationPoint &ip = ir.IntPoint(i);
Tr.SetIntPoint(&ip);
real_t w = ip.weight * Tr.Weight();
real_t mu = c_mu->Eval(Tr, ip);
real_t t = tau->Eval(Tr, ip);
real_t d = delta->Eval(Tr, ip);
el[0]->CalcPhysShape(Tr, sh_u);
elf_u.MultTranspose(sh_u, u);
el[0]->CalcPhysDShape(Tr, shg_u);
MultAtB(elf_u, shg_u, grad_u);
shg_u.Mult(u, ushg_u);
el[1]->CalcPhysShape(Tr, sh_p);
real_t p = sh_p*(*elfun[1]);
el[1]->CalcPhysDShape(Tr, shg_p);
shg_p.MultTranspose(*elfun[1], grad_p);
// u,u block
for (int i_u = 0; i_u < dof_u; ++i_u)
{
for (int j_u = 0; j_u < dof_u; ++j_u)
{
// Diffusion
real_t mat = 0.0;
for (int dim_u = 0; dim_u < dim; ++dim_u)
{
mat += shg_u(i_u,dim_u)*shg_u(j_u,dim_u);
}
mat *= mu;
// Convection
mat -= ushg_u(i_u)*sh_u(j_u); // Galerkin
mat += t*ushg_u(i_u)*ushg_u(j_u); // SUPG
mat *= w;
for (int dim_u = 0; dim_u < dim; ++dim_u)
{
(*elmats(0,0))(i_u + dim_u*dof_u, j_u + dim_u*dof_u) += mat;
}
for (int i_dim = 0; i_dim < dim; ++i_dim)
{
for (int j_dim = 0; j_dim < dim; ++j_dim)
{
(*elmats(0,0))(i_u + i_dim*dof_u, j_u + j_dim*dof_u) +=
(mu + d)*shg_u(i_u,j_dim)*shg_u(j_u,i_dim)*w;
}
}
}
}
// u,p and p,u blocks
for (int i_p = 0; i_p < dof_p; ++i_p)
{
for (int j_u = 0; j_u < dof_u; ++j_u)
{
for (int dim_u = 0; dim_u < dim; ++dim_u)
{
(*elmats(0,1))(j_u + dof_u * dim_u, i_p) += (shg_p(i_p, dim_u)*t*ushg_u(j_u)
-shg_u(j_u,dim_u)*sh_p(i_p))*w;
(*elmats(1,0))(i_p, j_u + dof_u * dim_u) += shg_u(j_u,dim_u)*sh_p(i_p)*w;
}
}
}
// p,p block
AddMult_a_AAt(w*t, shg_p, *elmats(1,1));
}
}
void GeneralResidualMonitor::MonitorResidual(int it, real_t norm,
const Vector &r, bool final)
{
if (it == 0)
{
norm0 = norm;
}
if ((print_level > 0 && it%print_level == 0) || final)
{
mfem::out << prefix << " iteration " << std::setw(2) << it
<< " : ||r|| = " << norm
<< ", ||r||/||r_0|| = " << 100*norm/norm0<<" % \n";
}
}
void SystemResidualMonitor::MonitorResidual(int it, real_t norm,
const Vector &r, bool final)
{
if (dc && (it > 0))
{
if (rank > 1)
{
for (int i = 0; i < nvar; ++i)
{
pgf[i]->Distribute(xp->GetBlock(i));
}
}
dc->SetCycle(it);
dc->Save();
}
Vector vnorm(nvar);
for (int i = 0; i < nvar; ++i)
{
Vector r_i(r.GetData() + bOffsets[i], bOffsets[i+1] - bOffsets[i]);
if ( rank == 1 )
{
vnorm[i] = r_i.Norml2();
}
else
{
vnorm[i] = sqrt(InnerProduct(MPI_COMM_WORLD, r_i, r_i));
}
if (it == 0) norm0[i] = vnorm[i];
}
bool print = (print_level > 0 && it%print_level == 0) || final;
if (print)
{
mfem::out << prefix << " iteration " << std::setw(3) << it <<"\n"
<< " ||r|| \t"<< "||r||/||r_0|| \n";
for (int i = 0; i < nvar; ++i)
{
mfem::out <<vnorm[i]<<"\t"<< 100*vnorm[i]/norm0[i]<<" % \n";
}
}
}
void JacobianPreconditioner::SetOperator(const Operator &op)
{
BlockOperator *jacobian = (BlockOperator *) &op;
for (int i = 0; i < prec.Size(); ++i)
{
prec[i]->SetOperator(jacobian->GetBlock(i,i));
SetDiagonalBlock(i, prec[i]);
}
SetBlock(1,0, const_cast<Operator*>(&jacobian->GetBlock(1,0)));
}
JacobianPreconditioner::~JacobianPreconditioner()
{
for (int i = 0; i < prec.Size(); ++i)
{
delete prec[i];
}
}
+242
View File
@@ -0,0 +1,242 @@
// Copyright (c) 2010-2024, 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_STAB_NAVSTO_HPP
#define MFEM_STAB_NAVSTO_HPP
#include "mfem.hpp"
#include "stab_tau.hpp"
namespace mfem
{
/** Stabilized incompressible Navier-Stokes integrator
Start with Galerkin for stokes - done
Add convection - done
Modify diffusion - done
Add difussion to residual - done
CHECK NUMBERING HESSIAN -> NURBS = WRONG?? 2D = ok --> 3D??? --> DONE NEEDS CHECKING???
Inverse estimate check order -> done
Add force -> done
Parallel --> done
Add supg - rhs done, jac conv + press --> ignore diffusion for now
Add pspg - rhs done, jac conv + press --> ignore diffusion for now
Add lsic - rhs done, jac conv + press --> ignore diffusion for now
Add correct inverse estimate -> done?? number does not coincide with H&C
Add VMS/GLS
Add selection option of different stab modes
Add Hessian check to inverse estimate
Check
- Hessian numbering in 3D
- Power method --> Laplack / null-space
- Elastic Inverse estimate
Leopoldo P. Franca, Sérgio L. Frey
Stabilized finite element methods:
II. The incompressible Navier-Stokes equations.
Computer Methods in Applied Mechanics and Engineering, 99(2-3), 209-233.
https://doi.org/10.1016/0045-7825(92)90041-H
https://www.sciencedirect.com/science/article/pii/004578259290041H
*/
class StabInNavStoIntegrator : public BlockNonlinearFormIntegrator
{
private:
Coefficient *c_mu;
VectorCoefficient *c_force;
Vector u, f, grad_p;
DenseMatrix flux;
DenseMatrix elf_u, elv_u;
// Vector elf_u, elv_u;//
DenseMatrix elf_p, elv_p;
Vector sh_u, ushg_u, sh_p;
DenseMatrix shg_u, shh_u, shg_p, grad_u, hess_u;
Array2D<int> hmap;
/// The stabilization parameters
StabType stab;
Tau *tau = nullptr;
Tau *delta = nullptr;
Vector res, up;
/// The advection field
VectorCoefficient *adv = nullptr; // tbd???
int dim = -1;
void SetDim(int dim);
public:
StabInNavStoIntegrator(Coefficient &mu_,
VectorCoefficient &force_,
Tau &t, Tau &d,
StabType s = GALERKIN);
virtual real_t GetElementEnergy(const Array<const FiniteElement *>&el,
ElementTransformation &Tr,
const Array<const Vector *> &elfun);
/// Perform the local action of the NonlinearFormIntegrator
virtual void AssembleElementVector(const Array<const FiniteElement *> &el,
ElementTransformation &Tr,
const Array<const Vector *> &elfun,
const Array<Vector *> &elvec);
/// Assemble the local gradient matrix
virtual void AssembleElementGrad(const Array<const FiniteElement*> &el,
ElementTransformation &Tr,
const Array<const Vector *> &elfun,
const Array2D<DenseMatrix *> &elmats);
};
class GeneralResidualMonitor : public IterativeSolverMonitor
{
public:
GeneralResidualMonitor(const std::string& prefix_, int print_lvl)
: prefix(prefix_)
{
print_level = print_lvl;
rank = 1;
}
GeneralResidualMonitor(MPI_Comm comm,
const std::string& prefix_, int print_lvl)
: prefix(prefix_)
{
#ifndef MFEM_USE_MPI
print_level = print_lvl;
#else
MPI_Comm_rank(comm, &rank);
if (rank == 0)
{
print_level = print_lvl;
}
else
{
print_level = -1;
}
#endif
}
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final);
private:
const std::string prefix;
int rank, print_level;
mutable real_t norm0;
};
class SystemResidualMonitor : public IterativeSolverMonitor
{
public:
SystemResidualMonitor(const std::string& prefix_,
int print_lvl,
Array<int> &offsets,
DataCollection *dc_ = nullptr)
: prefix(prefix_), bOffsets(offsets), dc(dc_)
{
print_level = print_lvl;
nvar = bOffsets.Size()-1;
norm0.SetSize(nvar);
rank = 1;
}
SystemResidualMonitor(MPI_Comm comm,
const std::string& prefix_,
int print_lvl,
Array<int> &offsets)
: prefix(prefix_), bOffsets(offsets), dc(nullptr), xp(nullptr)
{
#ifndef MFEM_USE_MPI
print_level = print_lvl;
rank = 1;
#else
MPI_Comm_rank(comm, &rank);
if (rank == 0)
{
print_level = print_lvl;
}
else
{
print_level = -1;
}
#endif
nvar = bOffsets.Size()-1;
norm0.SetSize(nvar);
}
SystemResidualMonitor(MPI_Comm comm,
const std::string& prefix_,
int print_lvl,
Array<int> &offsets,
DataCollection *dc_,
BlockVector *x,
Array<ParGridFunction *> pgf_)
: prefix(prefix_), bOffsets(offsets), dc(dc_), xp(x), pgf(pgf_)
{
#ifndef MFEM_USE_MPI
print_level = print_lvl;
rank = 1;
#else
MPI_Comm_rank(comm, &rank);
if (rank == 0)
{
print_level = print_lvl;
}
else
{
print_level = -1;
}
#endif
nvar = bOffsets.Size()-1;
norm0.SetSize(nvar);
}
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final);
private:
const std::string prefix;
int print_level, nvar, rank;
mutable Vector norm0;
// Offsets for extracting block vector segments
Array<int> &bOffsets;
DataCollection *dc;
BlockVector *xp;
Array<ParGridFunction *> pgf;
};
// Custom block preconditioner for the Jacobian
class JacobianPreconditioner : public BlockLowerTriangularPreconditioner //BlockDiagonalPreconditioner
{
protected:
Array<Solver *> prec;
public:
JacobianPreconditioner(Array<int> &offsets, Array<Solver *> p)
: BlockLowerTriangularPreconditioner (offsets), prec(p)
{ MFEM_VERIFY(offsets.Size()-1 == p.Size(), ""); };
virtual void SetOperator(const Operator &op);
virtual ~JacobianPreconditioner();
};
} // namespace mfem
#endif
+124
View File
@@ -0,0 +1,124 @@
// Copyright (c) 2010-2024, 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 "stab_tau.hpp"
using namespace mfem;
real_t FFH92Tau::GetElementSize(ElementTransformation &T)
{
const DenseMatrix &dxdxi = T.Jacobian();
row.SetSize(dim);
h.SetSize(dim);
for (int i = 0; i < dim; i++)
{
dxdxi.GetRow(i, row);
h[i] = row.Norml2();
}
switch (dim)
{
case 1:
return h[0];
case 2:
return h[0]*h[1]*sqrt(2.0/(h[0]*h[0] + h[1]*h[1]));
case 3:
return h[0]*h[1]*h[2]*(3.0/(h[0]*h[0] + h[1]*h[1] + h[2]*h[2]));
}
mfem_error("Wrong dim!");
return -1.0;
}
real_t FFH92Tau::GetInverseEstimate(ElementTransformation &T,
const IntegrationPoint &ip, real_t scale)
{
if (Ci>0.0)
{
return 1.0/Ci;
}
else
{
return 1.0/(invEst_cf->Eval(T,ip)*scale);
}
}
real_t FFH92Tau::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
real_t k = kappa->Eval(T, ip);
adv->Eval(a, T, ip);
real_t hk = GetElementSize(T);
real_t ci = GetInverseEstimate(T, ip, hk*hk);
real_t mk = std::min(1.0/3.0, 2*ci);
real_t ap = a.Normlp(p);
// Prevent division by zero
ap = std::max(ap,std::numeric_limits<real_t>::min());
real_t pe = mk*ap*hk/(k_fac*k); // k_fac = 2 for CD and k_fac = 4 for NS
real_t xi = std::min(pe,1.0);
real_t tau = hk*xi/(2*ap);
if (print)
{
std::cout<<"\n==========================\n";
std::cout<<" kappa = "<<k <<std::endl;
std::cout<<" adv = "; a.Print(std::cout);
std::cout<<" h = "<<hk <<std::endl;
std::cout<<" Ci = "<<ci<<" "
<<( (Ci<0) ? "(Computed)" :"(Specified)")<<std::endl;
std::cout<<" 1/Ci = "<<1.0/ci<<std::endl;
std::cout<<" mk = "<<mk <<std::endl;
std::cout<<" |a|_p = "<<ap <<std::endl;
std::cout<<" Pe = "<<pe <<std::endl;
std::cout<<" xi = "<<xi <<std::endl;
std::cout<<" tau = "<<tau<<std::endl;
std::cout<<" tau = "<<mk*hk*hk/(8*k)<<std::endl;
std::cout<<"==========================\n\n";
print = false;
}
return tau;
}
real_t FF91Delta::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
real_t k = kappa->Eval(T, ip);
adv->Eval(a, T, ip);
real_t hk = GetElementSize(T);
real_t ci = GetInverseEstimate(T, ip, hk*hk);
real_t mk = std::min(1.0/3.0, 2*ci);
real_t ap = a.Normlp(p); // Preventing division by zero not necessary
real_t pe = mk*ap*hk/(k_fac*k);
real_t xi = std::min(pe,1.0);
real_t delta = lambda*ap*hk*xi;
if (print)
{
std::cout<<"\n==========================\n";
std::cout<<" kappa = "<<k <<std::endl;
std::cout<<" adv = "; a.Print(std::cout);
std::cout<<" h = "<<hk <<std::endl;
std::cout<<" Ci = "<<ci<<" "
<<( (Ci<0) ? "(Computed)" :"(Specified)")<<std::endl;
std::cout<<" 1/Ci = "<<1.0/ci<<std::endl;
std::cout<<" mk = "<<mk <<std::endl;
std::cout<<" |a|_p = "<<ap <<std::endl;
std::cout<<" Pe = "<<pe <<std::endl;
std::cout<<" xi = "<<xi <<std::endl;
std::cout<<" lambda = "<<lambda <<std::endl;
std::cout<<" delta = "<<delta<<std::endl;
std::cout<<"==========================\n\n";
print = false;
}
return delta;
}

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