Compare commits

...
Author SHA1 Message Date
Patrick Zulian 8a6d972814 Merge branch 'moonolith_h1_bugfix' into moonolith_h1_vector_space 2024-06-12 11:30:30 +02:00
Patrick Zulian 5706c247a4 Merge branch 'master' into moonolith_h1_bugfix 2024-06-12 11:07:52 +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
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
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
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
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
Sebastian Grimberg cc00ef7d90 Fix compiler error for real_t and old CUDA architectures pre-6.0 2024-05-30 13:52:27 -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
Tzanio Kolev 76bcd044d0 Merge branch 'master' into hdiv-nurbs 2024-05-29 07:49:33 -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
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
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
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
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
IdoAkkerman f218efae09 Modify tolerance for single precision 2024-05-22 16:06:11 +02:00
Ido Akkerman af24eaea27 Merge branch 'master' into hdiv-nurbs 2024-05-21 10:57:13 +02:00
IdoAkkerman 8adb7461b0 Comment on array of NURBSexts 2024-05-15 10:38:14 +02: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
Patrick Zulian 278b33942a Merge branch 'moonolith_h1_bugfix' into moonolith_h1_vector_space 2024-05-06 16:48:00 +02:00
Patrick Zulian 080163deac Merge branch 'master' into moonolith_h1_bugfix 2024-05-06 10:05:43 +02: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
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
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
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
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
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
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
Patrick Zulian 42d0c95bc8 moonolith (new experimental feature): Added support for H1 vector space. ex1p can run examples with such spaces by passing the flag --use_vector_space 2024-03-14 10:36:54 +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
Patrick Zulian 947c8c9be9 Merge branch 'master' into moonolith_h1_bugfix 2024-03-12 11:24:00 +01:00
Patrick Zulian cf82f2830c bug fix: Switched to TrueDofs when assembling the coupling matrices. This change resolves the inconsistent dof numbering that led to wrong results when using H1 collections in parallel. ran make style. 2024-03-12 11:20:16 +01: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
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
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
57 changed files with 5664 additions and 1970 deletions
+11
View File
@@ -272,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
+7
View File
@@ -11,9 +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
+2 -1
View File
@@ -1049,7 +1049,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
+15
View File
@@ -182,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
+46 -13
View File
@@ -5,7 +5,8 @@
// Moonolith sample runs:
// mpirun -np 4 ex1p
// mpirun -np 4 ex1p --source_refinements 1 --dest_refinements 2
// mpirun -np 4 ex1p -s ../../data/inline-hex.mesh -d ../../data/inline-tet.mesh
// mpirun -np 4 ex1p -s ../../data/inline-hex.mesh -d
// ../../data/inline-tet.mesh
//
// Description: This example code demonstrates the use of MFEM for transferring
// discrete fields from one finite element mesh to another. The
@@ -50,6 +51,8 @@ int main(int argc, char *argv[])
int dest_fe_order = 1;
bool visualization = true;
bool use_vector_fe = false;
bool use_h1 = true;
bool use_vector_space = false;
bool verbose = false;
bool assemble_mass_and_coupling_together = true;
@@ -72,14 +75,27 @@ int main(int argc, char *argv[])
args.AddOption(&verbose, "-verb", "--verbose", "--no-verb", "--no-verbose",
"Enable/Disable verbose output");
args.AddOption(&use_vector_fe, "-vfe", "--use_vector_fe", "-no-vfe",
"--no-vector_fe", "Use vector finite elements (Experimental)");
"--no-vector_fe",
"Use RT|ND vector finite elements (Experimental)");
args.AddOption(&use_vector_space, "-vfs", "--use_vector_space", "-no-vfs",
"--no-vector_space",
"Use Lagrange vector finite elements (Experimental)");
args.AddOption(&use_h1, "-h1", "--use-h1", "-nh1", "--no-h1",
"Use H1 collection");
args.AddOption(&assemble_mass_and_coupling_together, "-act",
"--assemble_mass_and_coupling_together", "-no-act",
"--no-assemble_mass_and_coupling_together",
"Assemble mass and coupling operators together (better for non-affine elements)");
"Assemble mass and coupling operators together (better for "
"non-affine elements)");
args.Parse();
check_options(args);
if (use_vector_fe && use_vector_space)
{
mfem::err <<
"WARNING: use_vector_fe and use_vector_space options are both true, ignoring use_vector_fe\n";
}
shared_ptr<Mesh> src_mesh, dest_mesh;
ifstream imesh;
@@ -169,17 +185,30 @@ int main(int argc, char *argv[])
}
else
{
src_fe_coll =
make_shared<L2_FECollection>(source_fe_order, src_mesh->Dimension());
dest_fe_coll =
make_shared<L2_FECollection>(dest_fe_order, dest_mesh->Dimension());
if (use_h1)
{
src_fe_coll =
make_shared<H1_FECollection>(source_fe_order, src_mesh->Dimension());
dest_fe_coll =
make_shared<H1_FECollection>(dest_fe_order, dest_mesh->Dimension());
}
else
{
src_fe_coll =
make_shared<L2_FECollection>(source_fe_order, src_mesh->Dimension());
dest_fe_coll =
make_shared<L2_FECollection>(dest_fe_order, dest_mesh->Dimension());
}
}
auto src_fe =
make_shared<ParFiniteElementSpace>(p_src_mesh.get(), src_fe_coll.get());
auto src_fe = make_shared<ParFiniteElementSpace>(
p_src_mesh.get(), src_fe_coll.get(),
use_vector_space ? src_mesh->Dimension() : 1);
auto dest_fe =
make_shared<ParFiniteElementSpace>(p_dest_mesh.get(), dest_fe_coll.get());
auto dest_fe = make_shared<ParFiniteElementSpace>(
p_dest_mesh.get(), dest_fe_coll.get(),
use_vector_space ? dest_mesh->Dimension() : 1);
ParGridFunction src_fun(src_fe.get());
@@ -189,7 +218,7 @@ int main(int argc, char *argv[])
// To be used with vector fe
VectorFunctionCoefficient vector_coeff(dim, &vector_fun);
if (use_vector_fe)
if (use_vector_fe || use_vector_space)
{
src_fun.ProjectCoefficient(vector_coeff);
src_fun.Update();
@@ -209,7 +238,11 @@ int main(int argc, char *argv[])
assemble_mass_and_coupling_together);
assembler.SetVerbose(verbose);
if (use_vector_fe)
if (use_vector_space)
{
assembler.AddMortarIntegrator(make_shared<TPL2MortarIntegrator>());
}
else if (use_vector_fe)
{
assembler.AddMortarIntegrator(make_shared<VectorL2MortarIntegrator>());
}
-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.
+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);
+26 -25
View File
@@ -394,7 +394,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 +479,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. */
+614 -1
View File
@@ -398,8 +398,621 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip,
hessian(o,5) = hessian(o,5)*sum
- 2*du(o,1)*sum*dsum[1]
+ u[o]*sum*(2*dsum[1]*dsum[1] - 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();
+96 -33
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
{
@@ -2372,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
@@ -2425,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);
}
}
@@ -3926,7 +3989,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++)
+15 -13
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;
@@ -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
+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.
+5 -26
View File
@@ -40,31 +40,10 @@ public:
bool assemble_mass_and_coupling_together{true};
int max_solver_iterations{400};
bool is_vector_fe() const
BilinearFormIntegrator * newBFormIntegrator() const
{
bool is_vector_fe = false;
for (auto i_ptr : integrators)
{
if (i_ptr->is_vector_fe())
{
is_vector_fe = true;
break;
}
}
return is_vector_fe;
}
BilinearFormIntegrator * new_mass_integrator() const
{
if (is_vector_fe())
{
return new VectorFEMassIntegrator();
}
else
{
return new MassIntegrator();
}
assert(!integrators.empty());
return integrators[0]->newBFormIntegrator();
}
};
@@ -200,7 +179,7 @@ bool MortarAssembler::Assemble(std::shared_ptr<SparseMatrix> &B)
impl_->source->GetNDofs());
std::unique_ptr<BilinearFormIntegrator> mass_integr(impl_->new_mass_integrator());
std::unique_ptr<BilinearFormIntegrator> mass_integr(impl_->newBFormIntegrator());
if(impl_->assemble_mass_and_coupling_together) {
impl_->mass_matrix = make_shared<SparseMatrix>(impl_->destination->GetNDofs(), impl_->destination->GetNDofs());
@@ -389,7 +368,7 @@ bool MortarAssembler::Update()
if(!impl_->assemble_mass_and_coupling_together) {
BilinearForm b_form(impl_->destination.get());
b_form.AddDomainIntegrator(impl_->new_mass_integrator());
b_form.AddDomainIntegrator(impl_->newBFormIntegrator());
b_form.Assemble();
b_form.Finalize();
+90
View File
@@ -47,6 +47,8 @@ void L2MortarIntegrator::AssembleElementMatrix(
}
}
BilinearFormIntegrator * L2MortarIntegrator::newBFormIntegrator() const { return new MassIntegrator(); }
void VectorL2MortarIntegrator::AssembleElementMatrix(
const FiniteElement &trial, const IntegrationRule &trial_ir,
ElementTransformation &trial_Trans, const FiniteElement &test,
@@ -212,4 +214,92 @@ void VectorL2MortarIntegrator::AssembleElementMatrix(
}
}
BilinearFormIntegrator * VectorL2MortarIntegrator::newBFormIntegrator() const { return new VectorFEMassIntegrator(); }
void TPL2MortarIntegrator::AssembleElementMatrix(const FiniteElement &trial,
const IntegrationRule &trial_ir,
ElementTransformation &trial_Trans,
const FiniteElement &test,
const IntegrationRule &test_ir,
ElementTransformation &test_Trans,
DenseMatrix &elmat)
{
int tr_nd = trial.GetDof();
int te_nd = test.GetDof();
double norm;
// If vdim is not set, set it to the space dimension
vdim = (vdim == -1) ? test_Trans.GetSpaceDim() : vdim;
#ifdef MFEM_THREAD_SAFE
Vector D;
Vector vec;
DenseMatrix K;
Vector test_shape;
Vector trial_shape;
DenseMatrix partelmat;
DenseMatrix mcoeff;
#endif
elmat.SetSize(te_nd*vdim, tr_nd*vdim);
trial_shape.SetSize(tr_nd);
test_shape.SetSize(te_nd);
partelmat.SetSize(te_nd, tr_nd);
if (VQ)
{
vec.SetSize(vdim);
}
else if (MQ)
{
mcoeff.SetSize(vdim);
}
elmat = 0.0;
for (int s = 0; s < test_ir.GetNPoints(); s++)
{
trial.CalcShape(trial_ir.IntPoint(s), trial_shape);
test.CalcShape(test_ir.IntPoint(s), test_shape);
test_Trans.SetIntPoint(&test_ir.IntPoint(s));
norm = test_ir.IntPoint(s).weight * test_Trans.Weight();
MultVWt(test_shape, trial_shape, partelmat);
if (VQ)
{
VQ->Eval(vec, test_Trans, test_ir.IntPoint(s));
for (int k = 0; k < vdim; k++)
{
elmat.AddMatrix(norm*vec(k), partelmat, te_nd*k, tr_nd*k);
}
}
else if (MQ)
{
MQ->Eval(mcoeff, test_Trans, test_ir.IntPoint(s));
for (int i = 0; i < vdim; i++)
for (int j = 0; j < vdim; j++)
{
elmat.AddMatrix(norm*mcoeff(i,j), partelmat, te_nd*i, tr_nd*j);
}
}
else
{
if (Q)
{
norm *= Q->Eval(test_Trans, test_ir.IntPoint(s));
}
partelmat *= norm;
for (int k = 0; k < vdim; k++)
{
elmat.AddMatrix(partelmat, te_nd*k, tr_nd*k);
}
}
}
}
BilinearFormIntegrator * TPL2MortarIntegrator::newBFormIntegrator() const { return new VectorMassIntegrator(); }
} // namespace mfem
+53 -4
View File
@@ -60,9 +60,9 @@ public:
virtual ~MortarIntegrator() {}
/*!
* @return true if it uses vector fe and false otherwise
* @return an equivalent BilinearFormIntegrator
*/
virtual bool is_vector_fe() const = 0;
virtual BilinearFormIntegrator * newBFormIntegrator() const = 0;
};
/*!
@@ -81,7 +81,7 @@ public:
ElementTransformation &test_Trans,
DenseMatrix &elemmat) override;
inline bool is_vector_fe() const override { return false; }
BilinearFormIntegrator * newBFormIntegrator() const override;
};
/*!
@@ -101,6 +101,8 @@ public:
#endif
public:
BilinearFormIntegrator * newBFormIntegrator() const override;
VectorL2MortarIntegrator() { Init(NULL, NULL, NULL); }
VectorL2MortarIntegrator(Coefficient *_q) { Init(_q, NULL, NULL); }
VectorL2MortarIntegrator(VectorCoefficient *_vq) { Init(NULL, _vq, NULL); }
@@ -114,9 +116,56 @@ public:
ElementTransformation &test_Trans,
DenseMatrix &elemmat) override;
inline bool is_vector_fe() const override { return true; }
private:
Coefficient *Q;
VectorCoefficient *VQ;
MatrixCoefficient *MQ;
void Init(Coefficient *q, VectorCoefficient *vq, MatrixCoefficient *mq)
{
Q = q;
VQ = vq;
MQ = mq;
}
};
/*!
* @brief Integrator for Lagrange vector finite elements. Experimental.
* $$ (u, v)_{L^2(\mathcal{T}_m \cap \mathcal{T}_s)}, u \in U(\mathcal{T}_m )
* and v \in V(\mathcal{T}_s ) $$
*/
class TPL2MortarIntegrator : public MortarIntegrator
{
public:
#ifndef MFEM_THREAD_SAFE
Vector D;
Vector vec;
DenseMatrix K;
Vector test_shape;
Vector trial_shape;
DenseMatrix partelmat;
DenseMatrix mcoeff;
#endif
public:
BilinearFormIntegrator * newBFormIntegrator() const override;
TPL2MortarIntegrator() : vdim(-1) { Init(NULL, NULL, NULL); }
TPL2MortarIntegrator(Coefficient *_q) : vdim(-1) { Init(_q, NULL, NULL); }
TPL2MortarIntegrator(VectorCoefficient *_vq) : vdim(-1) { Init(NULL, _vq, NULL); }
TPL2MortarIntegrator(MatrixCoefficient *_mq) : vdim(-1) { Init(NULL, NULL, _mq); }
inline void SetVDim(const int _vdim) { vdim = _vdim; }
void AssembleElementMatrix(const FiniteElement &trial,
const IntegrationRule &trial_ir,
ElementTransformation &trial_Trans,
const FiniteElement &test,
const IntegrationRule &test_ir,
ElementTransformation &test_Trans,
DenseMatrix &elemmat) override;
private:
int vdim;
Coefficient *Q;
VectorCoefficient *VQ;
MatrixCoefficient *MQ;
File diff suppressed because it is too large Load Diff
+4 -3
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;
+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));
+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++)
+69 -355
View File
@@ -17,6 +17,7 @@
#include "vector.hpp"
#include "matrix.hpp"
#include "densemat.hpp"
#include "lapack.hpp"
#include "../general/forall.hpp"
#include "../general/table.hpp"
#include "../general/globals.hpp"
@@ -32,103 +33,6 @@
#endif
#ifdef MFEM_USE_LAPACK
#ifdef MFEM_USE_SINGLE
extern "C" void
sgemm_(char *, char *, int *, int *, int *, float *, float *,
int *, float *, int *, float *, float *, int *);
extern "C" void
sgetrf_(int *, int *, float *, int *, int *, int *);
extern "C" void
sgetrs_(char *, int *, int *, float *, int *, int *, float *, int *, int *);
extern "C" void
sgetri_(int *N, float *A, int *LDA, int *IPIV, float *WORK,
int *LWORK, int *INFO);
extern "C" void
ssyevr_(char *JOBZ, char *RANGE, char *UPLO, int *N, float *A, int *LDA,
float *VL, float *VU, int *IL, int *IU, float *ABSTOL, int *M,
float *W, float *Z, int *LDZ, int *ISUPPZ, float *WORK, int *LWORK,
int *IWORK, int *LIWORK, int *INFO);
extern "C" void
ssyev_(char *JOBZ, char *UPLO, int *N, float *A, int *LDA, float *W,
float *WORK, int *LWORK, int *INFO);
extern "C" void
ssygv_ (int *ITYPE, char *JOBZ, char *UPLO, int * N, float *A, int *LDA,
float *B, int *LDB, float *W, float *WORK, int *LWORK, int *INFO);
extern "C" void
sgesvd_(char *JOBU, char *JOBVT, int *M, int *N, float *A, int *LDA,
float *S, float *U, int *LDU, float *VT, int *LDVT, float *WORK,
int *LWORK, int *INFO);
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);
extern "C" void
sggev_(char *jobvl, char *jobvr, int *n, float *a, int *lda, float *B,
int *ldb, float *alphar, float *alphai, float *beta, float *vl,
int * ldvl, float * vr, int * ldvr, float * work, int * lwork, int* info);
// Cholesky factorizations/solves
extern "C" void
spotrf_(char *, int *, float *, int *, int *);
// Solve
extern "C" void
spotrs_(char *, int *, int *, float *, int *, float *, int *, int *);
// Triangular Solves
extern "C" void
strtrs_(char *, char*, char *, int *, int *, float *, int *, float *, int *,
int *);
extern "C" void
spotri_(char *, int *, float *, int*, int *);
#elif defined MFEM_USE_DOUBLE
extern "C" void
dgemm_(char *, char *, int *, int *, int *, double *, double *,
int *, double *, int *, double *, double *, int *);
extern "C" void
dgetrf_(int *, int *, double *, int *, int *, int *);
extern "C" void
dgetrs_(char *, int *, int *, double *, int *, int *, double *, int *, int *);
extern "C" void
dgetri_(int *N, double *A, int *LDA, int *IPIV, double *WORK,
int *LWORK, int *INFO);
extern "C" void
dsyevr_(char *JOBZ, char *RANGE, char *UPLO, int *N, double *A, int *LDA,
double *VL, double *VU, int *IL, int *IU, double *ABSTOL, int *M,
double *W, double *Z, int *LDZ, int *ISUPPZ, double *WORK, int *LWORK,
int *IWORK, int *LIWORK, int *INFO);
extern "C" void
dsyev_(char *JOBZ, char *UPLO, int *N, double *A, int *LDA, double *W,
double *WORK, int *LWORK, int *INFO);
extern "C" void
dsygv_ (int *ITYPE, char *JOBZ, char *UPLO, int * N, double *A, int *LDA,
double *B, int *LDB, double *W, double *WORK, int *LWORK, int *INFO);
extern "C" void
dgesvd_(char *JOBU, char *JOBVT, int *M, int *N, double *A, int *LDA,
double *S, double *U, int *LDU, double *VT, int *LDVT, double *WORK,
int *LWORK, int *INFO);
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);
extern "C" void
dggev_(char *jobvl, char *jobvr, int *n, double *a, int *lda, double *B,
int *ldb, double *alphar, double *alphai, double *beta, double *vl,
int * ldvl, double * vr, int * ldvr, double * work, int * lwork, int* info);
// Cholesky factorizations/solves
extern "C" void
dpotrf_(char *, int *, double *, int *, int *);
// Solve
extern "C" void
dpotrs_(char *, int *, int *, double *, int *, double *, int *, int *);
// Triangular Solves
extern "C" void
dtrtrs_(char *, char*, char *, int *, int *, double *, int *, double *, int *,
int *);
extern "C" void
dpotri_(char *, int *, double *, int*, int *);
#endif
#endif
namespace mfem
{
@@ -801,36 +705,19 @@ void DenseMatrix::Invert()
real_t qwork, *work;
int info;
#ifdef MFEM_USE_SINGLE
sgetrf_(&width, &width, data, &width, ipiv, &info);
#elif defined MFEM_USE_DOUBLE
dgetrf_(&width, &width, data, &width, ipiv, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(getrf_)(&width, &width, data, &width, ipiv, &info);
if (info)
{
mfem_error("DenseMatrix::Invert() : Error in DGETRF");
}
#ifdef MFEM_USE_SINGLE
sgetri_(&width, data, &width, ipiv, &qwork, &lwork, &info);
MFEM_LAPACK_PREFIX(getri_)(&width, data, &width, ipiv, &qwork, &lwork, &info);
lwork = (int) qwork;
work = new float[lwork];
work = new real_t[lwork];
sgetri_(&width, data, &width, ipiv, work, &lwork, &info);
#elif defined MFEM_USE_DOUBLE
dgetri_(&width, data, &width, ipiv, &qwork, &lwork, &info);
lwork = (int) qwork;
work = new double[lwork];
dgetri_(&width, data, &width, ipiv, work, &lwork, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(getri_)(&width, data, &width, ipiv, work, &lwork, &info);
if (info)
{
@@ -1066,15 +953,9 @@ void dsyevr_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect)
A[i] = data[i];
}
#ifdef MFEM_USE_SINGLE
ssyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
#elif defined MFEM_USE_DOUBLE
dsyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
#else
MFEM_ABORT("Floating point type undefined");
#endif
&ABSTOL, &M, W, Z, &LDZ, ISUPPZ, &QWORK, &LWORK,
&QIWORK, &LIWORK, &INFO );
MFEM_LAPACK_PREFIX(syevr_)(&JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL,
&IU, &ABSTOL, &M, W, Z, &LDZ, ISUPPZ, &QWORK,
&LWORK, &QIWORK, &LIWORK, &INFO);
LWORK = (int) QWORK;
LIWORK = QIWORK;
@@ -1082,15 +963,9 @@ void dsyevr_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect)
WORK = new real_t[LWORK];
IWORK = new int[LIWORK];
#ifdef MFEM_USE_SINGLE
ssyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
#elif defined MFEM_USE_DOUBLE
dsyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
#else
MFEM_ABORT("Floating point type undefined");
#endif
&ABSTOL, &M, W, Z, &LDZ, ISUPPZ, WORK, &LWORK,
IWORK, &LIWORK, &INFO );
MFEM_LAPACK_PREFIX(syevr_)(&JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL,
&IU, &ABSTOL, &M, W, Z, &LDZ, ISUPPZ, WORK,
&LWORK, IWORK, &LIWORK, &INFO);
if (INFO != 0)
{
@@ -1230,24 +1105,12 @@ void dsyev_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect)
A[i] = data[i];
}
#ifdef MFEM_USE_SINGLE
ssyev_(&JOBZ, &UPLO, &N, A, &LDA, W, &QWORK, &LWORK, &INFO);
#elif defined MFEM_USE_DOUBLE
dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, &QWORK, &LWORK, &INFO);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(syev_)(&JOBZ, &UPLO, &N, A, &LDA, W, &QWORK, &LWORK, &INFO);
LWORK = (int) QWORK;
WORK = new real_t[LWORK];
#ifdef MFEM_USE_SINGLE
ssyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO);
#elif defined MFEM_USE_DOUBLE
dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(syev_)(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO);
if (INFO != 0)
{
@@ -1322,24 +1185,14 @@ void dsygv_Eigensystem(DenseMatrix &a, DenseMatrix &b, Vector &ev,
B[i] = b_data[i];
}
#ifdef MFEM_USE_SINGLE
ssygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, &QWORK, &LWORK, &INFO);
#elif defined MFEM_USE_DOUBLE
dsygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, &QWORK, &LWORK, &INFO);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(sygv_)(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W,
&QWORK, &LWORK, &INFO);
LWORK = (int) QWORK;
WORK = new real_t[LWORK];
#ifdef MFEM_USE_SINGLE
ssygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, WORK, &LWORK, &INFO);
#elif defined MFEM_USE_DOUBLE
dsygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, WORK, &LWORK, &INFO);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(sygv_)(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, WORK,
&LWORK, &INFO);
if (INFO != 0)
{
@@ -1391,26 +1244,14 @@ void DenseMatrix::SingularValues(Vector &sv) const
int info;
real_t qwork;
#ifdef MFEM_USE_SINGLE
sgesvd_(&jobu, &jobvt, &m, &n, a, &m,
#elif defined MFEM_USE_DOUBLE
dgesvd_(&jobu, &jobvt, &m, &n, a, &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
s, u, &m, vt, &n, &qwork, &lwork, &info);
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, a, &m, s, u, &m, vt, &n,
&qwork, &lwork, &info);
lwork = (int) qwork;
work = new real_t[lwork];
#ifdef MFEM_USE_SINGLE
sgesvd_(&jobu, &jobvt, &m, &n, a, &m,
#elif defined MFEM_USE_DOUBLE
dgesvd_(&jobu, &jobvt, &m, &n, a, &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
s, u, &m, vt, &n, work, &lwork, &info);
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, a, &m, s, u, &m, vt, &n,
work, &lwork, &info);
delete [] work;
if (info)
@@ -2573,14 +2414,8 @@ void Mult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
static real_t alpha = 1.0, beta = 0.0;
int m = b.Height(), n = c.Width(), k = b.Width();
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
c.Data(), &k, &beta, a.Data(), &m);
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
c.Data(), &k, &beta, a.Data(), &m);
#else
const int ah = a.Height();
const int aw = a.Width();
@@ -2603,14 +2438,8 @@ void AddMult_a(real_t alpha, const DenseMatrix &b, const DenseMatrix &c,
static real_t beta = 1.0;
int m = b.Height(), n = c.Width(), k = b.Width();
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
c.Data(), &k, &beta, a.Data(), &m);
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
c.Data(), &k, &beta, a.Data(), &m);
#else
const int ah = a.Height();
const int aw = a.Width();
@@ -2641,12 +2470,8 @@ void AddMult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
static real_t alpha = 1.0, beta = 1.0;
int m = b.Height(), n = c.Width(), k = b.Width();
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
#endif
c.Data(), &k, &beta, a.Data(), &m);
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
c.Data(), &k, &beta, a.Data(), &m);
#else
const int ah = a.Height();
const int aw = a.Width();
@@ -2965,12 +2790,8 @@ void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
static real_t alpha = 1.0, beta = 0.0;
int m = A.Height(), n = B.Height(), k = A.Width();
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#endif
B.Data(), &n, &beta, ABt.Data(), &m);
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
B.Data(), &n, &beta, ABt.Data(), &m);
#elif 1
const int ah = A.Height();
const int bh = B.Height();
@@ -3074,12 +2895,8 @@ void AddMultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
static real_t alpha = 1.0, beta = 1.0;
int m = A.Height(), n = B.Height(), k = A.Width();
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#endif
B.Data(), &n, &beta, ABt.Data(), &m);
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
B.Data(), &n, &beta, ABt.Data(), &m);
#elif 1
const int ah = A.Height();
const int bh = B.Height();
@@ -3173,12 +2990,8 @@ void AddMult_a_ABt(real_t a, const DenseMatrix &A, const DenseMatrix &B,
static real_t beta = 1.0;
int m = A.Height(), n = B.Height(), k = A.Width();
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
#endif
B.Data(), &n, &beta, ABt.Data(), &m);
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
B.Data(), &n, &beta, ABt.Data(), &m);
#elif 1
const int ah = A.Height();
const int bh = B.Height();
@@ -3234,12 +3047,8 @@ void MultAtB(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &AtB)
static real_t alpha = 1.0, beta = 0.0;
int m = A.Width(), n = B.Width(), k = A.Height();
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#endif
B.Data(), &k, &beta, AtB.Data(), &m);
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
B.Data(), &k, &beta, AtB.Data(), &m);
#elif 1
const int ah = A.Height();
const int aw = A.Width();
@@ -3291,12 +3100,8 @@ void AddMultAtB(const DenseMatrix &A, const DenseMatrix &B,
static real_t alpha = 1.0, beta = 1.0;
int m = A.Width(), n = B.Width(), k = A.Height();
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#endif
B.Data(), &k, &beta, AtB.Data(), &m);
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
B.Data(), &k, &beta, AtB.Data(), &m);
#else
const int ah = A.Height();
const int aw = A.Width();
@@ -3335,12 +3140,8 @@ void AddMult_a_AtB(real_t a, const DenseMatrix &A, const DenseMatrix &B,
static real_t beta = 1.0;
int m = A.Width(), n = B.Width(), k = A.Height();
#ifdef MFEM_USE_SINGLE
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#elif defined MFEM_USE_DOUBLE
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
#endif
B.Data(), &k, &beta, AtB.Data(), &m);
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
B.Data(), &k, &beta, AtB.Data(), &m);
#else
const int ah = A.Height();
const int aw = A.Width();
@@ -3545,13 +3346,7 @@ bool LUFactors::Factor(int m, real_t TOL)
{
#ifdef MFEM_USE_LAPACK
int info = 0;
#ifdef MFEM_USE_SINGLE
if (m) { sgetrf_(&m, &m, data, &m, ipiv, &info); }
#elif defined MFEM_USE_DOUBLE
if (m) { dgetrf_(&m, &m, data, &m, ipiv, &info); }
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (m) { MFEM_LAPACK_PREFIX(getrf_)(&m, &m, data, &m, ipiv, &info); }
return info == 0;
#else
// compiling without LAPACK
@@ -3703,13 +3498,10 @@ void LUFactors::Solve(int m, int n, real_t *X) const
#ifdef MFEM_USE_LAPACK
char trans = 'N';
int info = 0;
#ifdef MFEM_USE_SINGLE
if (m > 0 && n > 0) { sgetrs_(&trans, &m, &n, data, &m, ipiv, X, &m, &info); }
#elif defined MFEM_USE_DOUBLE
if (m > 0 && n > 0) { dgetrs_(&trans, &m, &n, data, &m, ipiv, X, &m, &info); }
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (m > 0 && n > 0)
{
MFEM_LAPACK_PREFIX(getrs_)(&trans, &m, &n, data, &m, ipiv, X, &m, &info);
}
MFEM_VERIFY(!info, "LAPACK: error in DGETRS");
#else
// compiling without LAPACK
@@ -3726,15 +3518,8 @@ void LUFactors::RightSolve(int m, int n, real_t *X) const
real_t alpha = 1.0;
if (m > 0 && n > 0)
{
#ifdef MFEM_USE_SINGLE
strsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
strsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#elif defined MFEM_USE_DOUBLE
dtrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
dtrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(trsm_)(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
MFEM_LAPACK_PREFIX(trsm_)(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
}
#else
// compiling without LAPACK
@@ -3911,13 +3696,7 @@ bool CholeskyFactors::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) {spotrf_(&uplo, &m, data, &m, &info);}
#elif defined MFEM_USE_DOUBLE
if (m) {dpotrf_(&uplo, &m, data, &m, &info);}
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (m) { MFEM_LAPACK_PREFIX(potrf_)(&uplo, &m, data, &m, &info); }
return info == 0;
#else
// CholeskyCrout algorithm
@@ -4009,13 +3788,8 @@ void CholeskyFactors::LSolve(int m, int n, real_t * X) const
char diag = 'N';
int info = 0;
#ifdef MFEM_USE_SINGLE
strtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
#elif defined MFEM_USE_DOUBLE
dtrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, X, &m,
&info);
MFEM_VERIFY(!info, "CholeskyFactors:LSolve:: info");
#else
@@ -4045,13 +3819,8 @@ void CholeskyFactors::USolve(int m, int n, real_t * X) const
char diag = 'N';
int info = 0;
#ifdef MFEM_USE_SINGLE
strtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
#elif defined MFEM_USE_DOUBLE
dtrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, X, &m,
&info);
MFEM_VERIFY(!info, "CholeskyFactors:USolve:: info");
#else
@@ -4077,13 +3846,7 @@ void CholeskyFactors::Solve(int m, int n, real_t * X) const
#ifdef MFEM_USE_LAPACK
char uplo = 'L';
int info = 0;
#ifdef MFEM_USE_SINGLE
spotrs_(&uplo, &m, &n, data, &m, X, &m, &info);
#elif defined MFEM_USE_DOUBLE
dpotrs_(&uplo, &m, &n, data, &m, X, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(potrs_)(&uplo, &m, &n, data, &m, X, &m, &info);
MFEM_VERIFY(!info, "CholeskyFactors:Solve:: info");
#else
@@ -4104,15 +3867,8 @@ void CholeskyFactors::RightSolve(int m, int n, real_t * X) const
real_t alpha = 1.0;
if (m > 0 && n > 0)
{
#ifdef MFEM_USE_SINGLE
strsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,X,&n);
strsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,X,&n);
#elif defined MFEM_USE_DOUBLE
dtrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,X,&n);
dtrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,X,&n);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(trsm_)(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,X,&n);
MFEM_LAPACK_PREFIX(trsm_)(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,X,&n);
}
#else
// X <- X L^{-t}
@@ -4160,13 +3916,7 @@ void CholeskyFactors::GetInverseMatrix(int m, real_t * X) const
}
char uplo = 'L';
int info = 0;
#ifdef MFEM_USE_SINGLE
spotri_(&uplo, &m, X, &m, &info);
#elif defined MFEM_USE_DOUBLE
dpotri_(&uplo, &m, X, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_LAPACK_PREFIX(potri_)(&uplo, &m, X, &m, &info);
MFEM_VERIFY(!info, "CholeskyFactors:GetInverseMatrix:: info");
// fill in the upper triangular part
for (int i = 0; i<m; i++)
@@ -4350,14 +4100,8 @@ DenseMatrixEigensystem::DenseMatrixEigensystem(DenseMatrix &m)
uplo = 'U';
lwork = -1;
real_t qwork;
#ifdef MFEM_USE_SINGLE
ssyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
#elif defined MFEM_USE_DOUBLE
dsyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
#else
MFEM_ABORT("Floating point type undefined");
#endif
&qwork, &lwork, &info);
MFEM_LAPACK_PREFIX(syev_)(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
&qwork, &lwork, &info);
lwork = (int) qwork;
work = new real_t[lwork];
@@ -4385,14 +4129,8 @@ void DenseMatrixEigensystem::Eval()
#endif
EVect = mat;
#ifdef MFEM_USE_SINGLE
ssyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
#elif defined MFEM_USE_DOUBLE
dsyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
#else
MFEM_ABORT("Floating point type undefined");
#endif
work, &lwork, &info);
MFEM_LAPACK_PREFIX(syev_)(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
work, &lwork, &info);
if (info != 0)
{
@@ -4444,15 +4182,9 @@ DenseMatrixGeneralizedEigensystem::DenseMatrixGeneralizedEigensystem(
int nl = max(1,Vl.Height());
int nr = max(1,Vr.Height());
#ifdef MFEM_USE_SINGLE
sggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
#elif defined MFEM_USE_DOUBLE
dggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
#else
MFEM_ABORT("Floating point type undefined");
#endif
alphai, beta, Vl.Data(), &nl, Vr.Data(), &nr,
&qwork, &lwork, &info);
MFEM_LAPACK_PREFIX(ggev_)(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,
alphar, alphai, beta, Vl.Data(), &nl, Vr.Data(),
&nr, &qwork, &lwork, &info);
lwork = (int) qwork;
work = new real_t[lwork];
@@ -4465,15 +4197,9 @@ void DenseMatrixGeneralizedEigensystem::Eval()
A_copy = A;
B_copy = B;
#ifdef MFEM_USE_SINGLE
sggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
#elif defined MFEM_USE_DOUBLE
dggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
#else
MFEM_ABORT("Floating point type undefined");
#endif
alphai, beta, Vl.Data(), &nl, Vr.Data(), &nr,
work, &lwork, &info);
MFEM_LAPACK_PREFIX(ggev_)(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,
alphar, alphai, beta, Vl.Data(), &nl, Vr.Data(),
&nr, work, &lwork, &info);
if (info != 0)
{
mfem::err << "DenseMatrixGeneralizedEigensystem::Eval(): DGGEV error code: "
@@ -4554,14 +4280,8 @@ void DenseMatrixSVD::Init()
sv.SetSize(min(m, n));
real_t qwork;
lwork = -1;
#ifdef MFEM_USE_SINGLE
sgesvd_(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(), NULL, &m,
#elif defined MFEM_USE_DOUBLE
dgesvd_(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(), NULL, &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
NULL, &n, &qwork, &lwork, &info);
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(),
NULL, &m, NULL, &n, &qwork, &lwork, &info);
lwork = (int) qwork;
work = new real_t[lwork];
}
@@ -4597,14 +4317,8 @@ void DenseMatrixSVD::Eval(DenseMatrix &M)
datavt = Vt.Data();
}
Mc = M;
#ifdef MFEM_USE_SINGLE
sgesvd_(&jobu, &jobvt, &m, &n, Mc.Data(), &m, sv.GetData(), datau, &m,
#elif defined MFEM_USE_DOUBLE
dgesvd_(&jobu, &jobvt, &m, &n, Mc.Data(), &m, sv.GetData(), datau, &m,
#else
MFEM_ABORT("Floating point type undefined");
#endif
datavt, &n, work, &lwork, &info);
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, Mc.Data(), &m, sv.GetData(),
datau, &m, datavt, &n, work, &lwork, &info);
if (info)
{
+134
View File
@@ -0,0 +1,134 @@
// 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(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
+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;
+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;
+3
View File
@@ -1537,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).
///
+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
+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
+76 -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,10 @@ add_mfem_miniapp(nurbs_patch_ex1
MAIN nurbs_patch_ex1.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_solenoidal
MAIN nurbs_solenoidal.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 +80,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 +145,60 @@ 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)
endif()
if (MFEM_USE_MPI)
@@ -135,6 +206,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 +244,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
+69 -16
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
@@ -147,6 +148,7 @@ int main(int argc, char *argv[])
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 +171,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 +270,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 +325,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
@@ -375,11 +422,12 @@ int main(int argc, char *argv[])
else
{
a->AddDomainIntegrator(new Diffusion2Integrator(one));
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 +439,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;
}
+298
View File
@@ -0,0 +1,298 @@
// 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 "unit_tests.hpp"
#include "mfem.hpp"
using namespace mfem;
namespace hptransfer_test
{
int order=1;
double u(const Vector & x)
{
return pow(x.Sum(),order);
}
void vecu(const Vector & x, Vector & U)
{
for (int i = 0; i<x.Size(); i++)
{
U[i] = pow(x[i], order);
}
}
void RandomPRefinement(FiniteElementSpace & fes)
{
Mesh *mesh = fes.GetMesh();
for (int i = 0; i < mesh->GetNE(); i++)
{
if ((double) rand() / RAND_MAX < 0.5)
{
const int eorder = fes.GetElementOrder(i);
fes.SetElementOrder(i,eorder+1);
}
}
fes.Update(false);
}
/* This function randomly selects elements to be de-refined and sets the
order of the elements that share the same parent to their minimum */
void PreprocessRandomDerefinement(FiniteElementSpace & fes, Array<int> &drefs,
double prob=0.5)
{
Mesh * mesh = fes.GetMesh();
const Table & dereftable = mesh->ncmesh->GetDerefinementTable();
int dref = dereftable.Size();
for (int i = 0; i < dref; i++)
{
if ((double) rand() / RAND_MAX < prob)
{
drefs.Append(i);
}
}
// Go through the possible derefinements and set the orders to minimum
Array<int> row;
for (int i = 0; i<drefs.Size(); i++)
{
dereftable.GetRow(drefs[i], row);
int minorder = 100;
for (int j = 0; j<row.Size(); j++)
{
minorder = std::min(minorder, fes.GetElementOrder(row[j]));
}
// set the min order
for (int j = 0; j<row.Size(); j++)
{
fes.SetElementOrder(row[j],minorder);
}
}
fes.Update(false);
}
void Derefine(Mesh &mesh, const Array<int> &drefs)
{
const Table & dereftable = mesh.ncmesh->GetDerefinementTable();
Array<int> row;
Vector errors(mesh.GetNE()); errors = infinity();
for (int i = 0; i<drefs.Size(); i++)
{
dereftable.GetRow(drefs[i], row);
for (int j = 0; j<row.Size(); j++)
{
errors[row[j]] = 0.0;
}
}
mesh.DerefineByError(errors,1.0);
}
enum class Space {H1, L2, VectorH1, VectorL2};
TEST_CASE("hpTransfer", "[hpTransfer]")
{
auto space = GENERATE(Space::H1, Space::L2, Space::VectorH1, Space::VectorL2);
int dim = GENERATE(2,3);
auto simplex = GENERATE(false, true);
order = GENERATE(1,2);
auto relax_conformity = GENERATE(false, true);
/* No need to distinguish between relaxed and full conformity in the DG case*/
if ((space == Space::L2 || space == Space::VectorL2) && relax_conformity) { return; }
constexpr int ne = 3;
CAPTURE(space, dim, simplex, order, relax_conformity);
Mesh mesh;
if (dim == 2)
{
Element::Type type = simplex ? Element::TRIANGLE : Element::QUADRILATERAL;
mesh = Mesh::MakeCartesian2D(ne, ne, type, 1, 1.0, 1.0);
}
else
{
Element::Type type = simplex ? Element::TETRAHEDRON : Element::HEXAHEDRON;
mesh = Mesh::MakeCartesian3D(ne, ne, ne, type, 1.0, 1.0, 1.0);
}
mesh.EnsureNCMesh(true);
// 1. Set up initial state by randomly h- and p- refinement
mesh.RandomRefinement(0.5);
FiniteElementCollection * fec = nullptr;
if (space == Space::H1 || space == Space::VectorH1)
{
fec = new H1_FECollection(order, dim);
}
else
{
fec = new L2_FECollection(order, dim);
}
int dimc = (space<=Space::L2) ? 1 : dim;
FiniteElementSpace fes(&mesh, fec, dimc);
fes.SetRelaxedHpConformity(relax_conformity);
RandomPRefinement(fes);
// 2. Set up a GridFunction on the initial hp-mesh
FunctionCoefficient f(u);
VectorFunctionCoefficient vf(dim,vecu);
GridFunction gf(&fes); gf = 0.0;
if (space<=Space::L2)
{
gf.ProjectCoefficient(f);
}
else
{
gf.ProjectCoefficient(vf);
}
// 3. Randomly h-refine the mesh and transfer the GridFunction
mesh.RandomRefinement(0.5);
fes.Update();
gf.Update();
GridFunction err_gf(&fes);
if (space<=Space::L2)
{
err_gf.ProjectCoefficient(f);
}
else
{
err_gf.ProjectCoefficient(vf);
}
err_gf-= gf;
if (fes.GetHpRestrictionMatrix())
{
Vector tmp0(fes.GetHpRestrictionMatrix()->Height());
fes.GetHpRestrictionMatrix()->Mult(err_gf,tmp0);
fes.GetProlongationMatrix()->Mult(tmp0,err_gf);
}
// 3a. Check if the prolonged GridFunction to the h-refined
// mesh exactly reproduces the polynomial GridFunction
REQUIRE(err_gf.Norml2() < 1e-11);
// 4. Randomly p-refine the mesh and transfer the GridFunction
Mesh cmesh(mesh);
FiniteElementSpace cfes(&cmesh, fec, dimc);
cfes.SetRelaxedHpConformity(relax_conformity);
for (int i = 0; i<cmesh.GetNE(); i++)
{
cfes.SetElementOrder(i,fes.GetElementOrder(i));
}
cfes.Update(false);
RandomPRefinement(fes);
PRefinementTransferOperator T(cfes, fes);
GridFunction hpgf(&fes);
T.Mult(gf,hpgf);
err_gf.SetSpace(&fes);
if (space<=Space::L2)
{
err_gf.ProjectCoefficient(f);
}
else
{
err_gf.ProjectCoefficient(vf);
}
err_gf-= hpgf;
if (fes.GetHpRestrictionMatrix())
{
Vector tmp(fes.GetHpRestrictionMatrix()->Height());
fes.GetHpRestrictionMatrix()->Mult(err_gf,tmp);
fes.GetProlongationMatrix()->Mult(tmp,err_gf);
}
// 4a. Check if the prolonged GridFunction to the p-refined
// mesh exactly reproduces the polynomial GridFunction
REQUIRE(err_gf.Norml2() < 1e-11);
// 5. Before randomly de-refining the mesh ensure that the elements
// (of the same parent) that are going to be de-refined
// have the same order
Mesh fmesh(mesh);
FiniteElementSpace ffes(&fmesh, fec, dimc);
ffes.SetRelaxedHpConformity(relax_conformity);
for (int i = 0; i<fmesh.GetNE(); i++)
{
ffes.SetElementOrder(i,fes.GetElementOrder(i));
}
ffes.Update(false);
Array<int> drefs;
// lower the order of the children to their minimum
PreprocessRandomDerefinement(fes, drefs);
PRefinementTransferOperator T2(ffes, fes);
gf.SetSpace(&fes);
T2.Mult(hpgf, gf);
err_gf.SetSpace(&fes);
if (space<=Space::L2)
{
err_gf.ProjectCoefficient(f);
}
else
{
err_gf.ProjectCoefficient(vf);
}
err_gf-= gf;
if (fes.GetHpRestrictionMatrix())
{
Vector temp(fes.GetHpRestrictionMatrix()->Height());
fes.GetHpRestrictionMatrix()->Mult(err_gf,temp);
fes.GetProlongationMatrix()->Mult(temp,err_gf);
}
// 5a. Check if the restricted GridFunction to the p-derefined
// mesh exactly reproduces the polynomial GridFunction
REQUIRE(err_gf.Norml2() < 1e-11);
// 6. De-refine the mesh and transfer the GridFunction
Derefine(mesh,drefs);
fes.Update();
gf.Update();
err_gf.SetSpace(&fes); err_gf = 0.0;
if (space<=Space::L2)
{
err_gf.ProjectCoefficient(f);
}
else
{
err_gf.ProjectCoefficient(vf);
}
err_gf-= gf;
if (fes.GetHpRestrictionMatrix())
{
Vector temp(fes.GetHpRestrictionMatrix()->Height());
fes.GetHpRestrictionMatrix()->Mult(err_gf,temp);
fes.GetProlongationMatrix()->Mult(temp,err_gf);
}
// 6a. Check if the restricted GridFunction to the de-refined
// mesh exactly reproduces the polynomial GridFunction
REQUIRE(err_gf.Norml2() < 1e-11);
delete fec;
}
}