Compare commits
351
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffce41001e | ||
|
|
5724e4f274 | ||
|
|
e189b0b0f0 | ||
|
|
11badb5d2f | ||
|
|
39e3854585 | ||
|
|
c271ac1eda | ||
|
|
ed8ce36e96 | ||
|
|
66c71dd4f2 | ||
|
|
635c487665 | ||
|
|
90c995f0e6 | ||
|
|
9d3ce2c394 | ||
|
|
185b2bba58 | ||
|
|
93e6be67d3 | ||
|
|
7a4ab004c2 | ||
|
|
467cc941f3 | ||
|
|
5a5d9cfe77 | ||
|
|
998b531fe5 | ||
|
|
c33327f234 | ||
|
|
e60145110d | ||
|
|
5f04684f17 | ||
|
|
a3065a05dc | ||
|
|
ede448d783 | ||
|
|
2e0df87cd6 | ||
|
|
5ec854e9e4 | ||
|
|
842c68b0b5 | ||
|
|
c3806304d4 | ||
|
|
a092f9cad0 | ||
|
|
17eb65d619 | ||
|
|
75567ae1ef | ||
|
|
c18e27aeac | ||
|
|
3d84777b69 | ||
|
|
c240df5fbe | ||
|
|
950198a3f2 | ||
|
|
d808463114 | ||
|
|
5447bcf8a9 | ||
|
|
7ace2dedf1 | ||
|
|
cb6d48f499 | ||
|
|
36dea0cf38 | ||
|
|
01dfecd67e | ||
|
|
94ca7d26e8 | ||
|
|
46e35d0bce | ||
|
|
d582c31370 | ||
|
|
f387244e57 | ||
|
|
8876a84dd4 | ||
|
|
8153d11274 | ||
|
|
827ed64113 | ||
|
|
ef9f02ba53 | ||
|
|
e9a0b0620a | ||
|
|
4d9d444248 | ||
|
|
6e2badecca | ||
|
|
99b45fcb02 | ||
|
|
003dc46a84 | ||
|
|
7fac0fbd07 | ||
|
|
9a327eeca6 | ||
|
|
086f6c9847 | ||
|
|
480e90b41b | ||
|
|
bc6ba0252a | ||
|
|
262fa6173d | ||
|
|
e4b8584a16 | ||
|
|
7912d6915d | ||
|
|
293d9009ae | ||
|
|
51bde67bb1 | ||
|
|
9caa48d5c8 | ||
|
|
f4d286b4b7 | ||
|
|
45e2636921 | ||
|
|
57876fbfb0 | ||
|
|
c3eb769a2a | ||
|
|
9286d89b0e | ||
|
|
47b519047a | ||
|
|
35225e045e | ||
|
|
22c1087503 | ||
|
|
cd5d2f7c04 | ||
|
|
7fc2ce350d | ||
|
|
cbae29ad06 | ||
|
|
4c1d842c72 | ||
|
|
4aa0ed52af | ||
|
|
fca4c314d4 | ||
|
|
8712d02570 | ||
|
|
e5fec6279b | ||
|
|
e90e96f9a5 | ||
|
|
459def6d79 | ||
|
|
cc00ef7d90 | ||
|
|
7b84f6ddc6 | ||
|
|
2c0346bc36 | ||
|
|
56186d8770 | ||
|
|
1645b854a4 | ||
|
|
69fd2f9051 | ||
|
|
a5d230f199 | ||
|
|
ba4b627e68 | ||
|
|
62c535d0ee | ||
|
|
17829d1c38 | ||
|
|
dd198ce3f9 | ||
|
|
b9f36468ba | ||
|
|
76bcd044d0 | ||
|
|
84ce403ffb | ||
|
|
df09aea4da | ||
|
|
d2840464ba | ||
|
|
0dff351b2e | ||
|
|
55a914321d | ||
|
|
1410aef639 | ||
|
|
e1ac8ca08c | ||
|
|
28916b23a4 | ||
|
|
7476c00f2b | ||
|
|
7a0137c496 | ||
|
|
4267b2af05 | ||
|
|
e37daad5eb | ||
|
|
20b4b72071 | ||
|
|
ddf80492c5 | ||
|
|
712ae82026 | ||
|
|
53dd97e0d8 | ||
|
|
0c413570c4 | ||
|
|
f8d18cd4be | ||
|
|
994d83dd80 | ||
|
|
f218efae09 | ||
|
|
43bb865c26 | ||
|
|
dd9b723cfd | ||
|
|
87362ca1ca | ||
|
|
a6afefc6a5 | ||
|
|
e1dc4680d3 | ||
|
|
44985dacc0 | ||
|
|
9c77f6b407 | ||
|
|
8df0341e11 | ||
|
|
af24eaea27 | ||
|
|
7338e797bb | ||
|
|
31d931a99c | ||
|
|
3ae930c93b | ||
|
|
36f882257e | ||
|
|
8adb7461b0 | ||
|
|
716e370d35 | ||
|
|
37c0768fe3 | ||
|
|
217b77d5f0 | ||
|
|
bb67d6cb98 | ||
|
|
696cbd05e8 | ||
|
|
6c8a4188a1 | ||
|
|
829b123641 | ||
|
|
bd52201add | ||
|
|
812ecce84a | ||
|
|
172c38b675 | ||
|
|
875b5f3f52 | ||
|
|
be1f36a523 | ||
|
|
d4c7dd3490 | ||
|
|
1bac61ad1c | ||
|
|
c7451115d8 | ||
|
|
72ae003a00 | ||
|
|
d67098b8f8 | ||
|
|
0e6dbaf050 | ||
|
|
32afc8565c | ||
|
|
48ace60875 | ||
|
|
9b6ee6fcad | ||
|
|
1a1639b87e | ||
|
|
3735aa504b | ||
|
|
367dda6794 | ||
|
|
e4a85f79cd | ||
|
|
678101938b | ||
|
|
9a3aa18c62 | ||
|
|
5a3ba1424a | ||
|
|
3bb8419a96 | ||
|
|
ce29282f63 | ||
|
|
9575299ae3 | ||
|
|
995ceca6c2 | ||
|
|
012aa50cd3 | ||
|
|
d0193919c4 | ||
|
|
422ca290b5 | ||
|
|
59e1d7bf27 | ||
|
|
09dd9656c8 | ||
|
|
e9afca2cd6 | ||
|
|
6abd0e6002 | ||
|
|
656e3062b4 | ||
|
|
5f083cea48 | ||
|
|
80e29c8950 | ||
|
|
7264091c6f | ||
|
|
33c0df349d | ||
|
|
d3015edb40 | ||
|
|
927c7f82be | ||
|
|
008dda250b | ||
|
|
9c9c519175 | ||
|
|
8300809562 | ||
|
|
cce7296ffe | ||
|
|
a445ad00da | ||
|
|
4db7e1a107 | ||
|
|
c51a1c4aa9 | ||
|
|
d489908e50 | ||
|
|
c4eda188d5 | ||
|
|
677eb4c876 | ||
|
|
69a4aa70b9 | ||
|
|
f07c2f460d | ||
|
|
09c557bdd7 | ||
|
|
e487da01c5 | ||
|
|
a6b00aacbf | ||
|
|
504ae95915 | ||
|
|
b6b6843ad2 | ||
|
|
5d28b67295 | ||
|
|
b19800f1a7 | ||
|
|
66a1379947 | ||
|
|
546ba6c11e | ||
|
|
67ba63c2f4 | ||
|
|
99c2967920 | ||
|
|
e96dc7e4aa | ||
|
|
3a113dcdd6 | ||
|
|
6a6d7eb83c | ||
|
|
8a0e295691 | ||
|
|
2dc419f1ae | ||
|
|
450d6cea6d | ||
|
|
3386418737 | ||
|
|
2f09777b17 | ||
|
|
75df4ad3e6 | ||
|
|
4048d46443 | ||
|
|
12842aa9e1 | ||
|
|
b07ff3f5db | ||
|
|
b86fdfb46c | ||
|
|
50905e0dcb | ||
|
|
9702811d72 | ||
|
|
955fe9f9df | ||
|
|
97e4f45be3 | ||
|
|
60242d41bd | ||
|
|
1fb47dab6b | ||
|
|
cd671cae3e | ||
|
|
c2154f95fe | ||
|
|
bbd4edce83 | ||
|
|
1742616cac | ||
|
|
2c64bbab79 | ||
|
|
785fa7adc2 | ||
|
|
0248c58591 | ||
|
|
160e783638 | ||
|
|
ddd2500a9c | ||
|
|
2b5dee2b95 | ||
|
|
26393f230f | ||
|
|
8e9948d729 | ||
|
|
9bbbd8c324 | ||
|
|
a19e7cb38e | ||
|
|
3a2912bc0b | ||
|
|
5cfd284cb8 | ||
|
|
eeae538115 | ||
|
|
8a98c0332f | ||
|
|
84d44db3a7 | ||
|
|
c97af2f3dc | ||
|
|
c4ca3bfc5f | ||
|
|
b03cf507be | ||
|
|
066dc9b078 | ||
|
|
70854254e7 | ||
|
|
646df28ac8 | ||
|
|
73d4f987e4 | ||
|
|
c59d519c89 | ||
|
|
1ec2cba9e8 | ||
|
|
26cc1f8387 | ||
|
|
85fe35bec2 | ||
|
|
b57fa2b127 | ||
|
|
596909138a | ||
|
|
c11a76f2c1 | ||
|
|
51d32ad293 | ||
|
|
a433e9e0b4 | ||
|
|
abac61f5b5 | ||
|
|
a121a9d186 | ||
|
|
58ecbf6150 | ||
|
|
bad5ae41d1 | ||
|
|
e773e07373 | ||
|
|
c3ded3c003 | ||
|
|
76e04c4606 | ||
|
|
83ccf77d2f | ||
|
|
a0d53975d8 | ||
|
|
1252c0fbb9 | ||
|
|
04acf613ae | ||
|
|
c8bddb8035 | ||
|
|
467e83da31 | ||
|
|
8b29ef1335 | ||
|
|
1076700714 | ||
|
|
978f1155c5 | ||
|
|
3096d9d9cb | ||
|
|
ffea75abb2 | ||
|
|
a44a8b8789 | ||
|
|
05106096c3 | ||
|
|
ba7fd7a9a9 | ||
|
|
9b0e4e0085 | ||
|
|
3cb64f7f7e | ||
|
|
6642857437 | ||
|
|
91f00d643a | ||
|
|
ce8b62cfe7 | ||
|
|
4064bda60d | ||
|
|
4a21554986 | ||
|
|
165968dc26 | ||
|
|
9eb70f7be0 | ||
|
|
8797a9cb00 | ||
|
|
8366a5a6d6 | ||
|
|
63a9d5749b | ||
|
|
0e6aa41245 | ||
|
|
bbcb054814 | ||
|
|
2e5a86db7a | ||
|
|
057b15cefb | ||
|
|
7c06741f36 | ||
|
|
3a0c42aea5 | ||
|
|
75d5555a5f | ||
|
|
10c1ac9a66 | ||
|
|
692e15c088 | ||
|
|
6be9665bfb | ||
|
|
9be617d754 | ||
|
|
ec4f37fe25 | ||
|
|
6bb4ae9d50 | ||
|
|
c7a3f188c0 | ||
|
|
8e44509585 | ||
|
|
787954715b | ||
|
|
9f03260dd2 | ||
|
|
5c3a3f7fdf | ||
|
|
6693b22c83 | ||
|
|
49c7f60a57 | ||
|
|
ace4608f10 | ||
|
|
3899dfcc64 | ||
|
|
2dc98e9153 | ||
|
|
90f8a2409f | ||
|
|
92dc0db889 | ||
|
|
d8fc48e608 | ||
|
|
611802f990 | ||
|
|
606df86b0a | ||
|
|
2f7d38e6f6 | ||
|
|
b90d665ced | ||
|
|
50dd77ffd4 | ||
|
|
5e5b79783c | ||
|
|
c815114661 | ||
|
|
93f6a53201 | ||
|
|
a3ee0cfe79 | ||
|
|
95b0178514 | ||
|
|
afacf3db45 | ||
|
|
4a80321420 | ||
|
|
9295c69249 | ||
|
|
893f04967c | ||
|
|
fa410a6e02 | ||
|
|
aed2687743 | ||
|
|
978c0d10bc | ||
|
|
25b540e804 | ||
|
|
9aa58cd5c2 | ||
|
|
691be01bcc | ||
|
|
402ed45ee4 | ||
|
|
07dfcd83b9 | ||
|
|
9845dfda2c | ||
|
|
da5ee77e61 | ||
|
|
e1d2966e42 | ||
|
|
17428ce198 | ||
|
|
e87e790215 | ||
|
|
f907191e58 | ||
|
|
62a00562de | ||
|
|
3316d89c63 | ||
|
|
6bf590c3ee | ||
|
|
78bf9951e3 | ||
|
|
532060a646 | ||
|
|
59f76ced6a | ||
|
|
0c2766ee76 | ||
|
|
a90df38643 | ||
|
|
407741b8e3 | ||
|
|
3859678772 | ||
|
|
a6d4e17911 | ||
|
|
bde7846b5a | ||
|
|
01283767a6 |
+14
@@ -15,6 +15,9 @@
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
|
||||
# Clangd server cache
|
||||
*.cache*
|
||||
|
||||
# Backup files
|
||||
*~
|
||||
|
||||
@@ -272,16 +275,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
|
||||
|
||||
@@ -11,9 +11,28 @@
|
||||
Version 4.7.1 (development)
|
||||
===========================
|
||||
|
||||
- Refactored the `ARKStepSolver` class (ARKODE interface) to use
|
||||
`TimeDependentOperator::Mult` only when the associated ODE operator is
|
||||
expressed in explicit form (i.e., `TimeDependentOperator::isExplicit()`),
|
||||
otherwise `TimeDependentOperator::ExplicitMult` is used. A check has been
|
||||
added to `ARKStepSolver` to verify that the associated ODE operator is not in
|
||||
explicit form when a mass matrix solver is enabled via a call to either the
|
||||
`UseMFEMMassLinearSolver` or `UseSundialsMassLinearSolver` methods. This is
|
||||
because enabling a mass matrix solver assumes that F(u,k,t) = M k in the
|
||||
associated ODE operator.
|
||||
|
||||
- Added support for custom interpolation procedure in FindPointsGSLIB.
|
||||
|
||||
- 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
|
||||
====================================
|
||||
@@ -38,6 +57,9 @@ Meshing improvements
|
||||
|
||||
- Added support for internal boundary elements in nonconforming meshes.
|
||||
|
||||
- Added ExodusII output capability. The writer can handle first-order (Pyramid5,
|
||||
Wedge6, Hex8, Tet4) and second-order FE types (Pyramid14, Wedge18, Hex27, Tet10).
|
||||
|
||||
- The ReadCubit Genesis mesh importer has been rewritten to improve readability.
|
||||
|
||||
Discretization improvements
|
||||
|
||||
+83
-13
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -96,6 +96,7 @@ public:
|
||||
{
|
||||
Vector w_glob(width);
|
||||
pfes.Dof_TrueDof_Matrix()->MultTranspose(w, w_glob);
|
||||
w_glob.HostReadWrite(); // read+write -> can use w_glob(i) (non-const)
|
||||
for (int i = 0; i < width; i++) { grad(0, i) = w_glob(i); }
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -31,11 +31,21 @@ include_directories(BEFORE ${PROJECT_BINARY_DIR})
|
||||
add_custom_target(test_sundials
|
||||
${CMAKE_CTEST_COMMAND} -R sundials USES_TERMINAL)
|
||||
|
||||
# Add one executable per cpp file, adding "sundials_" as prefix. Sets
|
||||
# "test_sundials" as a target that depends on the given examples.
|
||||
# Add one executable per cpp file, adding "sundials_" as prefix so the CMake
|
||||
# target is unique from those in the non-SUNDIALS examples. Also sets
|
||||
# "test_sundials" as a target that depends on the given SUNDIALS examples.
|
||||
set(PFX sundials_)
|
||||
add_mfem_examples(SUNDIALS_EXAMPLES_SRCS ${PFX} "" test_sundials)
|
||||
|
||||
# Remove "sundials_" prefix from exectuable name for consistency with GNU build
|
||||
# system.
|
||||
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
|
||||
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
|
||||
string(REPLACE ".cpp" "" TARGET_NAME "${PFX}${SRC_FILENAME}")
|
||||
string(REPLACE ${PFX} "" EXE_NAME ${TARGET_NAME})
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${EXE_NAME})
|
||||
endforeach()
|
||||
|
||||
# Testing.
|
||||
# The SUNDIALS tests can be run separately using the target "test_sundials"
|
||||
# which builds the examples and runs:
|
||||
@@ -51,7 +61,10 @@ if (MFEM_ENABLE_TESTING)
|
||||
set(EX10_COMMON_OPTS -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -tf 6 -vs 10)
|
||||
set(EX10_TEST_OPTS ${EX10_COMMON_OPTS} -r 2)
|
||||
set(EX10P_TEST_OPTS ${EX10_COMMON_OPTS} -rp 1)
|
||||
# Example 16: use the default options
|
||||
# Example 16: test ARKODE with implicit time stepping using mass form
|
||||
set(EX16_COMMON_OPTS -s 15)
|
||||
set(EX16_TEST_OPTS ${EX16_COMMON_OPTS})
|
||||
set(EX16P_TEST_OPTS ${EX16_COMMON_OPTS})
|
||||
|
||||
# Add the tests: one test per source file.
|
||||
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// MFEM Example 10
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex10
|
||||
// Compile with:
|
||||
// make ex10 (GNU make)
|
||||
// make sundials_ex10 (CMake)
|
||||
//
|
||||
// Sample runs:
|
||||
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 12 -dt 0.15 -vs 10
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// MFEM Example 10 - Parallel Version
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex10p
|
||||
// Compile with:
|
||||
// make ex10p (GNU make)
|
||||
// make sundials_ex10p (CMake)
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 12 -dt 0.15 -vs 10
|
||||
|
||||
+256
-163
@@ -1,15 +1,21 @@
|
||||
// MFEM Example 16
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex16
|
||||
// Compile with:
|
||||
// make ex16 (GNU make)
|
||||
// make sundials_ex16 (CMake)
|
||||
//
|
||||
// Sample runs: ex16
|
||||
// ex16 -m ../../data/inline-tri.mesh
|
||||
// ex16 -m ../../data/disc-nurbs.mesh -tf 2
|
||||
// ex16 -s 12 -a 0.0 -k 1.0
|
||||
// ex16 -s 15 -a 0.0 -k 1.0
|
||||
// ex16 -s 8 -a 1.0 -k 0.0 -dt 1e-4 -tf 5e-2 -vs 25
|
||||
// ex16 -s 11 -a 1.0 -k 0.0 -dt 1e-4 -tf 5e-2 -vs 25
|
||||
// ex16 -s 9 -a 0.5 -k 0.5 -o 4 -dt 1e-4 -tf 2e-2 -vs 25
|
||||
// ex16 -s 12 -a 0.5 -k 0.5 -o 4 -dt 1e-4 -tf 2e-2 -vs 25
|
||||
// ex16 -s 10 -dt 1.0e-4 -tf 4.0e-2 -vs 40
|
||||
// ex16 -s 13 -dt 1.0e-4 -tf 4.0e-2 -vs 40
|
||||
// ex16 -m ../../data/fichera-q2.mesh
|
||||
// ex16 -m ../../data/escher.mesh
|
||||
// ex16 -m ../../data/beam-tet.mesh -tf 10 -dt 0.1
|
||||
@@ -37,75 +43,102 @@
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
/** After spatial discretization, the conduction model can be written as:
|
||||
/** After spatial discretization, the conduction model is expressed as
|
||||
*
|
||||
* du/dt = M^{-1}(-Ku)
|
||||
* M du/dt = - K(u) u
|
||||
*
|
||||
* where u is the vector representing the temperature, M is the mass matrix,
|
||||
* and K is the diffusion operator with diffusivity depending on u:
|
||||
* and K(u) is the diffusion operator with diffusivity depending on u:
|
||||
* (\kappa + \alpha u).
|
||||
*
|
||||
* Class ConductionOperator represents the right-hand side of the above ODE.
|
||||
* Class ConductionOperatorOperator represents the above ODE operator in the
|
||||
* general form F(u, k, t) = G(u, t) where
|
||||
*
|
||||
* 1. F(u, du/dt, t) = du/dt (ODE is expressed in EXPLICIT form)
|
||||
* G(u, t) = - inv(M) K(u) u
|
||||
* 2. F(u, du/dt, t) = M du/dt (ODE is expressed in IMPLICIT form)
|
||||
* G(u, t) = - K(u) u
|
||||
*/
|
||||
class ConductionOperator : public TimeDependentOperator
|
||||
{
|
||||
protected:
|
||||
FiniteElementSpace &fespace;
|
||||
Array<int> ess_tdof_list; // this list remains empty for pure Neumann b.c.
|
||||
|
||||
BilinearForm *M;
|
||||
BilinearForm *K;
|
||||
BilinearForm M;
|
||||
SparseMatrix Mmat;
|
||||
|
||||
SparseMatrix Mmat, Kmat;
|
||||
SparseMatrix *T; // T = M + dt K
|
||||
const real_t alpha, kappa;
|
||||
std::unique_ptr<BilinearForm> K;
|
||||
SparseMatrix Kmat;
|
||||
|
||||
std::unique_ptr<SparseMatrix> T; // T = M + gam K(u)
|
||||
|
||||
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
|
||||
DSmoother M_prec; // Preconditioner for the mass matrix M
|
||||
|
||||
CGSolver T_solver; // Implicit solver for T = M + dt K
|
||||
CGSolver T_solver; // Implicit solver for T = M + gam K(u)
|
||||
DSmoother T_prec; // Preconditioner for the implicit solver
|
||||
|
||||
double alpha, kappa;
|
||||
|
||||
mutable Vector z; // auxiliary vector
|
||||
|
||||
public:
|
||||
ConductionOperator(FiniteElementSpace &f, double alpha, double kappa,
|
||||
const Vector &u);
|
||||
|
||||
virtual void Mult(const Vector &u, Vector &du_dt) const;
|
||||
ConductionOperator(FiniteElementSpace &f, const real_t alpha,
|
||||
const real_t kappa, const Vector &u,
|
||||
const Type &ode_expression_type);
|
||||
|
||||
/** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
|
||||
This is the only requirement for high-order SDIRK implicit integration.*/
|
||||
virtual void ImplicitSolve(const double dt, const Vector &u, Vector &k);
|
||||
// Compute K(u_n) for use as an approximation in - K(u) u
|
||||
void SetConductionTensor(const Vector &u);
|
||||
|
||||
/// Custom Jacobian system solver for the SUNDIALS time integrators.
|
||||
/** For the ODE system represented by ConductionOperator
|
||||
/** Compute G(u, t) as defined in the IMPLICIT expression form of the ODE
|
||||
operator, i.e., @a v = - K(u_n) @a u. Note that K(u_n) is an
|
||||
approximation to K(u). */
|
||||
void ExplicitMult(const Vector &u, Vector &v) const override;
|
||||
|
||||
M du/dt = -K(u),
|
||||
/** Solve for k in F(u, k, t) = G(u, t) for either EXPLICIT or IMPLICIT
|
||||
expression forms of the ODE operator, i.e., @a k = - inv(M) K(u_n) @a u.
|
||||
Note that K(u_n) is an approximation to K(u). */
|
||||
void Mult(const Vector &u, Vector &k) const override;
|
||||
|
||||
this class facilitates the solution of linear systems of the form
|
||||
/** Solve for k in F(u + gam*k, k, t) = G(u + gam*k, t) for either EXPLICIT
|
||||
or IMPLICIT expression forms of the ODE operator, i.e.,
|
||||
[ M + @a gam K(u_n) ] @a k = - K(u_n) @a u . Note that K(u_n) is an
|
||||
approximation to K(u). */
|
||||
void ImplicitSolve(const real_t gam, const Vector &u, Vector &k) override;
|
||||
|
||||
(M + γK) y = M b,
|
||||
/** Setup to solve for dk in [dF/dk + gam*dF/du - gam*dG/du] dk = G - F for
|
||||
either EXPLICIT or IMPLICIT expression forms of the ODE operator, i.e.,
|
||||
[M - @a gam Jf(u)] dk = G - F, where Jf(u) is an approximation of the
|
||||
Jacobian of -K(u) u. The approximation chosen here is Jf(u) = -K(u_n). */
|
||||
int SUNImplicitSetup(const Vector &u, const Vector &fu, int jok, int *jcur,
|
||||
real_t gam) override;
|
||||
|
||||
for given b, u (not used), and γ = GetTimeStep(). */
|
||||
/** Solve for @a dk in the system in SUNImplicitSetup to the given tolerance,
|
||||
with the residual @a r providing either
|
||||
1. @a r = G - F = inv(M) f(u) - k (EXPLICIT expression form)
|
||||
1. @a r = G - F = f(u) - M k (IMPLICIT expression form)
|
||||
*/
|
||||
int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol) override;
|
||||
|
||||
/** Setup the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
|
||||
int jok, int *jcur, double gamma);
|
||||
int SUNMassSetup() override;
|
||||
|
||||
/** Solve the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSolve(const Vector &b, Vector &x, double tol);
|
||||
int SUNMassSolve(const Vector &b, Vector &x, real_t tol) override;
|
||||
|
||||
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
|
||||
void SetParameters(const Vector &u);
|
||||
|
||||
virtual ~ConductionOperator();
|
||||
int SUNMassMult(const Vector &x, Vector &v) override;
|
||||
};
|
||||
|
||||
double InitialTemperature(const Vector &x);
|
||||
real_t InitialTemperature(const Vector &x)
|
||||
{
|
||||
if (x.Norml2() < 0.5)
|
||||
{
|
||||
return 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -117,16 +150,16 @@ int main(int argc, char *argv[])
|
||||
int ref_levels = 2;
|
||||
int order = 2;
|
||||
int ode_solver_type = 9; // CVODE implicit BDF
|
||||
double t_final = 0.5;
|
||||
double dt = 1.0e-2;
|
||||
double alpha = 1.0e-2;
|
||||
double kappa = 0.5;
|
||||
real_t t_final = 0.5;
|
||||
real_t dt = 1.0e-2;
|
||||
real_t alpha = 1.0e-2;
|
||||
real_t kappa = 0.5;
|
||||
bool visualization = true;
|
||||
bool visit = false;
|
||||
int vis_steps = 5;
|
||||
|
||||
// Relative and absolute tolerances for CVODE and ARKODE.
|
||||
const double reltol = 1e-4, abstol = 1e-4;
|
||||
const real_t reltol = 1e-4, abstol = 1e-4;
|
||||
|
||||
int precision = 8;
|
||||
cout.precision(precision);
|
||||
@@ -151,7 +184,10 @@ int main(int argc, char *argv[])
|
||||
"9 - CVODE (implicit BDF),\n\t"
|
||||
"10 - ARKODE (default explicit),\n\t"
|
||||
"11 - ARKODE (explicit Fehlberg-6-4-5),\n\t"
|
||||
"12 - ARKODE (default impicit).");
|
||||
"12 - ARKODE (default implicit),\n\t"
|
||||
"13 - ARKODE (default explicit with MFEM mass solve),\n\t"
|
||||
"14 - ARKODE (explicit Fehlberg-6-4-5 with MFEM mass solve),\n\t"
|
||||
"15 - ARKODE (default implicit with MFEM mass solve).");
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -174,16 +210,13 @@ int main(int argc, char *argv[])
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
if (ode_solver_type < 1 || ode_solver_type > 12)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 3;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
bool use_mass_solver = ode_solver_type >= 13;
|
||||
|
||||
// 2. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral and hexahedral meshes with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
std::unique_ptr<Mesh> mesh(new Mesh(mesh_file, 1, 1));
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 3. Refine the mesh to increase the resolution. In this example we do
|
||||
@@ -197,7 +230,7 @@ int main(int argc, char *argv[])
|
||||
// 4. Define the vector finite element space representing the current and the
|
||||
// initial temperature, u_ref.
|
||||
H1_FECollection fe_coll(order, dim);
|
||||
FiniteElementSpace fespace(mesh, &fe_coll);
|
||||
FiniteElementSpace fespace(mesh.get(), &fe_coll);
|
||||
|
||||
int fe_size = fespace.GetTrueVSize();
|
||||
cout << "Number of temperature unknowns: " << fe_size << endl;
|
||||
@@ -211,8 +244,17 @@ int main(int argc, char *argv[])
|
||||
Vector u;
|
||||
u_gf.GetTrueDofs(u);
|
||||
|
||||
// 6. Initialize the conduction operator and the visualization.
|
||||
ConductionOperator oper(fespace, alpha, kappa, u);
|
||||
// 6. Initialize the conduction ODE operator and the visualization.
|
||||
ConductionOperator::Type ode_expression_type;
|
||||
if (use_mass_solver)
|
||||
{
|
||||
ode_expression_type = ConductionOperator::Type::IMPLICIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ode_expression_type = ConductionOperator::Type::EXPLICIT;
|
||||
}
|
||||
ConductionOperator oper(fespace, alpha, kappa, u, ode_expression_type);
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
{
|
||||
@@ -224,7 +266,7 @@ int main(int argc, char *argv[])
|
||||
u_gf.Save(osol);
|
||||
}
|
||||
|
||||
VisItDataCollection visit_dc("Example16", mesh);
|
||||
VisItDataCollection visit_dc("Example16", mesh.get());
|
||||
visit_dc.RegisterField("temperature", &u_gf);
|
||||
if (visit)
|
||||
{
|
||||
@@ -258,52 +300,75 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// 7. Define the ODE solver used for time integration.
|
||||
double t = 0.0;
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKStepSolver *arkode = NULL;
|
||||
real_t t = 0.0;
|
||||
std::unique_ptr<ODESolver> ode_solver;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// MFEM explicit methods
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 1: ode_solver = std::make_unique<ForwardEulerSolver>(); break;
|
||||
case 2: ode_solver = std::make_unique<RK2Solver>(0.5); break; // midpoint method
|
||||
case 3: ode_solver = std::make_unique<RK3SSPSolver>(); break;
|
||||
case 4: ode_solver = std::make_unique<RK4Solver>(); break;
|
||||
// MFEM implicit L-stable methods
|
||||
case 5: ode_solver = new BackwardEulerSolver; break;
|
||||
case 6: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 7: ode_solver = new SDIRK33Solver; break;
|
||||
case 5: ode_solver = std::make_unique<BackwardEulerSolver>(); break;
|
||||
case 6: ode_solver = std::make_unique<SDIRK23Solver>(2); break;
|
||||
case 7: ode_solver = std::make_unique<SDIRK33Solver>(); break;
|
||||
// CVODE
|
||||
case 8:
|
||||
cvode = new CVODESolver(CV_ADAMS);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 9:
|
||||
cvode = new CVODESolver(CV_BDF);
|
||||
{
|
||||
int cvode_solver_type;
|
||||
if (ode_solver_type == 8)
|
||||
{
|
||||
cvode_solver_type = CV_ADAMS;
|
||||
}
|
||||
else
|
||||
{
|
||||
cvode_solver_type = CV_BDF;
|
||||
}
|
||||
std::unique_ptr<CVODESolver> cvode(new CVODESolver(cvode_solver_type));
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
ode_solver = std::move(cvode);
|
||||
break;
|
||||
}
|
||||
// ARKODE
|
||||
case 10:
|
||||
case 11:
|
||||
arkode = new ARKStepSolver(ARKStepSolver::EXPLICIT);
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
{
|
||||
ARKStepSolver::Type arkode_solver_type;
|
||||
if (ode_solver_type == 12 || ode_solver_type == 15)
|
||||
{
|
||||
arkode_solver_type = ARKStepSolver::IMPLICIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
arkode_solver_type = ARKStepSolver::EXPLICIT;
|
||||
}
|
||||
std::unique_ptr<ARKStepSolver> arkode(
|
||||
new ARKStepSolver(arkode_solver_type));
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 11)
|
||||
if (ode_solver_type == 11 || ode_solver_type == 14)
|
||||
{
|
||||
arkode->SetERKTableNum(ARKODE_FEHLBERG_13_7_8);
|
||||
}
|
||||
ode_solver = arkode; break;
|
||||
case 12:
|
||||
arkode = new ARKStepSolver(ARKStepSolver::IMPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
if (use_mass_solver)
|
||||
{
|
||||
arkode->UseMFEMMassLinearSolver(SUNFALSE);
|
||||
}
|
||||
ode_solver = std::move(arkode);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
|
||||
@@ -311,8 +376,14 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Since we want to update the diffusion coefficient after every time step,
|
||||
// we need to use the "one-step" mode of the SUNDIALS solvers.
|
||||
if (cvode) { cvode->SetStepMode(CV_ONE_STEP); }
|
||||
if (arkode) { arkode->SetStepMode(ARK_ONE_STEP); }
|
||||
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
|
||||
{
|
||||
cvode->SetStepMode(CV_ONE_STEP);
|
||||
}
|
||||
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
|
||||
{
|
||||
arkode->SetStepMode(ARK_ONE_STEP);
|
||||
}
|
||||
|
||||
// 8. Perform time-integration (looping over the time iterations, ti, with a
|
||||
// time-step dt).
|
||||
@@ -323,7 +394,7 @@ int main(int argc, char *argv[])
|
||||
bool last_step = false;
|
||||
for (int ti = 1; !last_step; ti++)
|
||||
{
|
||||
double dt_real = min(dt, t_final - t);
|
||||
real_t dt_real = min(dt, t_final - t);
|
||||
|
||||
// Note that since we are using the "one-step" mode of the SUNDIALS
|
||||
// solvers, they will, generally, step over the final time and will not
|
||||
@@ -337,8 +408,14 @@ int main(int argc, char *argv[])
|
||||
if (last_step || (ti % vis_steps) == 0)
|
||||
{
|
||||
cout << "step " << ti << ", t = " << t << endl;
|
||||
if (cvode) { cvode->PrintInfo(); }
|
||||
if (arkode) { arkode->PrintInfo(); }
|
||||
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
|
||||
{
|
||||
cvode->PrintInfo();
|
||||
}
|
||||
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
|
||||
{
|
||||
arkode->PrintInfo();
|
||||
}
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
if (visualization)
|
||||
@@ -353,137 +430,153 @@ int main(int argc, char *argv[])
|
||||
visit_dc.Save();
|
||||
}
|
||||
}
|
||||
oper.SetParameters(u);
|
||||
oper.SetConductionTensor(u);
|
||||
}
|
||||
tic_toc.Stop();
|
||||
cout << "Done, " << tic_toc.RealTime() << "s." << endl;
|
||||
|
||||
// 9. Save the final solution. This output can be viewed later using GLVis:
|
||||
// "glvis -m ex16.mesh -g ex16-final.gf".
|
||||
{
|
||||
ofstream osol("ex16-final.gf");
|
||||
osol.precision(precision);
|
||||
u_gf.Save(osol);
|
||||
}
|
||||
|
||||
// 10. Free the used memory.
|
||||
delete ode_solver;
|
||||
delete mesh;
|
||||
u_gf.Save("ex16-final.gf", precision);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConductionOperator::ConductionOperator(FiniteElementSpace &f, double al,
|
||||
double kap, const Vector &u)
|
||||
: TimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL), K(NULL),
|
||||
T(NULL), z(height)
|
||||
ConductionOperator::ConductionOperator(FiniteElementSpace &fes,
|
||||
const real_t alpha, const real_t kappa,
|
||||
const Vector &u,
|
||||
const Type &ode_expression_type)
|
||||
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
|
||||
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace), z(height)
|
||||
{
|
||||
const double rel_tol = 1e-8;
|
||||
// specify a relative tolerance for all solves with MFEM integrators
|
||||
const real_t rel_tol = 1e-8;
|
||||
|
||||
M = new BilinearForm(&fespace);
|
||||
M->AddDomainIntegrator(new MassIntegrator());
|
||||
M->Assemble();
|
||||
M->FormSystemMatrix(ess_tdof_list, Mmat);
|
||||
M.AddDomainIntegrator(new MassIntegrator());
|
||||
M.Assemble();
|
||||
M.FormSystemMatrix(ess_tdof_list, Mmat);
|
||||
|
||||
M_solver.iterative_mode = false;
|
||||
M_solver.SetRelTol(rel_tol);
|
||||
M_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
|
||||
M_solver.SetAbsTol(0.0);
|
||||
M_solver.SetMaxIter(50);
|
||||
M_solver.SetPrintLevel(0);
|
||||
M_solver.SetPreconditioner(M_prec);
|
||||
M_solver.SetOperator(Mmat);
|
||||
|
||||
alpha = al;
|
||||
kappa = kap;
|
||||
|
||||
T_solver.iterative_mode = false;
|
||||
T_solver.SetRelTol(rel_tol);
|
||||
T_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
|
||||
T_solver.SetAbsTol(0.0);
|
||||
T_solver.SetMaxIter(100);
|
||||
T_solver.SetPrintLevel(0);
|
||||
T_solver.SetPreconditioner(T_prec);
|
||||
|
||||
SetParameters(u);
|
||||
SetConductionTensor(u);
|
||||
}
|
||||
|
||||
void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
|
||||
{
|
||||
// Compute:
|
||||
// du_dt = M^{-1}*-K(u)
|
||||
// for du_dt
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg(); // z = -z
|
||||
M_solver.Mult(z, du_dt);
|
||||
}
|
||||
|
||||
void ConductionOperator::ImplicitSolve(const double dt,
|
||||
const Vector &u, Vector &du_dt)
|
||||
{
|
||||
// Solve the equation:
|
||||
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
|
||||
// for du_dt
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
T_solver.SetOperator(*T);
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg();
|
||||
T_solver.Mult(z, du_dt);
|
||||
}
|
||||
|
||||
void ConductionOperator::SetParameters(const Vector &u)
|
||||
void ConductionOperator::SetConductionTensor(const Vector &u)
|
||||
{
|
||||
// Compute K(u_n).
|
||||
GridFunction u_alpha_gf(&fespace);
|
||||
u_alpha_gf.SetFromTrueDofs(u);
|
||||
for (int i = 0; i < u_alpha_gf.Size(); i++)
|
||||
{
|
||||
u_alpha_gf(i) = kappa + alpha*u_alpha_gf(i);
|
||||
}
|
||||
|
||||
delete K;
|
||||
K = new BilinearForm(&fespace);
|
||||
|
||||
GridFunctionCoefficient u_coeff(&u_alpha_gf);
|
||||
|
||||
K = std::make_unique<BilinearForm>(&fespace);
|
||||
K->AddDomainIntegrator(new DiffusionIntegrator(u_coeff));
|
||||
K->Assemble();
|
||||
K->FormSystemMatrix(ess_tdof_list, Kmat);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSetup(const Vector &x,
|
||||
const Vector &fx, int jok, int *jcur,
|
||||
double gamma)
|
||||
void ConductionOperator::ExplicitMult(const Vector &u, Vector &v) const
|
||||
{
|
||||
// Setup the ODE Jacobian T = M + gamma K.
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, gamma, Kmat);
|
||||
// Compute - K(u_n) u.
|
||||
Kmat.Mult(u, v);
|
||||
v.Neg();
|
||||
}
|
||||
|
||||
void ConductionOperator::Mult(const Vector &u, Vector &k) const
|
||||
{
|
||||
// Compute - inv(M) K(u_n) u.
|
||||
ExplicitMult(u, z);
|
||||
M_solver.Mult(z, k);
|
||||
}
|
||||
|
||||
void ConductionOperator::ImplicitSolve(const real_t gam, const Vector &u,
|
||||
Vector &k)
|
||||
{
|
||||
// Solve for k in M k = - K(u_n) [u + gam*k].
|
||||
ExplicitMult(u, z);
|
||||
T = std::unique_ptr<SparseMatrix>(Add(1.0, Mmat, gam, Kmat));
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = 1;
|
||||
return (0);
|
||||
T_solver.Mult(z, k);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &b, Vector &x, double tol)
|
||||
int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
|
||||
int jok, int *jcur, real_t gam)
|
||||
{
|
||||
// Solve the system A x = z => (M - gamma K) x = M b.
|
||||
Mmat.Mult(b, z);
|
||||
T_solver.Mult(z, x);
|
||||
return (0);
|
||||
// Compute T = M + gamma K(u_n).
|
||||
T = std::unique_ptr<SparseMatrix>(Add(1.0, Mmat, gam, Kmat));
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
ConductionOperator::~ConductionOperator()
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
|
||||
real_t tol)
|
||||
{
|
||||
delete T;
|
||||
delete M;
|
||||
delete K;
|
||||
}
|
||||
|
||||
double InitialTemperature(const Vector &x)
|
||||
{
|
||||
if (x.Norml2() < 0.5)
|
||||
// Solve the system [M + gamma K(u_n)] dk = - K(u_n) u - M k.
|
||||
// What value r is providing depends on the ODE expression form:
|
||||
// EXPLICIT form: r = -inv(M) K(u_n) u - k
|
||||
// IMPLICIT form: r = -K(u_n) u - M k
|
||||
T_solver.SetRelTol(tol);
|
||||
if (isExplicit())
|
||||
{
|
||||
return 2.0;
|
||||
Mmat.Mult(r, z);
|
||||
T_solver.Mult(z, dk);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0;
|
||||
T_solver.Mult(r, dk);
|
||||
}
|
||||
if (T_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SUNLS_CONV_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassSetup()
|
||||
{
|
||||
// Do nothing b/c mass solver was setup in constructor.
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
|
||||
{
|
||||
// Solve the system M x = b.
|
||||
M_solver.SetRelTol(tol);
|
||||
M_solver.Mult(b, x);
|
||||
if (M_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SUNLS_CONV_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
|
||||
{
|
||||
// Compute M x.
|
||||
Mmat.Mult(x, v);
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
+285
-188
@@ -1,16 +1,22 @@
|
||||
// MFEM Example 16 - Parallel Version
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex16p
|
||||
// Compile with:
|
||||
// make ex16p (GNU make)
|
||||
// make sundials_ex16p (CMake)
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 4 ex16p
|
||||
// mpirun -np 4 ex16p -m ../../data/inline-tri.mesh
|
||||
// mpirun -np 4 ex16p -m ../../data/disc-nurbs.mesh -tf 2
|
||||
// mpirun -np 4 ex16p -s 12 -a 0.0 -k 1.0
|
||||
// mpirun -np 4 ex16p -s 15 -a 0.0 -k 1.0
|
||||
// mpirun -np 4 ex16p -s 8 -a 1.0 -k 0.0 -dt 4e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 4 ex16p -s 11 -a 1.0 -k 0.0 -dt 4e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 8 ex16p -s 9 -a 0.5 -k 0.5 -o 4 -dt 8e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 8 ex16p -s 12 -a 0.5 -k 0.5 -o 4 -dt 8e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 4 ex16p -s 10 -dt 2.0e-4 -tf 4.0e-2
|
||||
// mpirun -np 4 ex16p -s 13 -dt 2.0e-4 -tf 4.0e-2
|
||||
// mpirun -np 16 ex16p -m ../../data/fichera-q2.mesh
|
||||
// mpirun -np 16 ex16p -m ../../data/escher-p2.mesh
|
||||
// mpirun -np 8 ex16p -m ../../data/beam-tet.mesh -tf 10 -dt 0.1
|
||||
@@ -38,66 +44,102 @@
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
/** After spatial discretization, the conduction model can be written as:
|
||||
/** After spatial discretization, the conduction model is expressed as
|
||||
*
|
||||
* du/dt = M^{-1}(-Ku)
|
||||
* M du/dt = - K(u) u
|
||||
*
|
||||
* where u is the vector representing the temperature, M is the mass matrix,
|
||||
* and K is the diffusion operator with diffusivity depending on u:
|
||||
* and K(u) is the diffusion operator with diffusivity depending on u:
|
||||
* (\kappa + \alpha u).
|
||||
*
|
||||
* Class ConductionOperator represents the right-hand side of the above ODE.
|
||||
* Class ConductionOperatorOperator represents the above ODE operator in the
|
||||
* general form F(u, k, t) = G(u, t) where either
|
||||
*
|
||||
* 1. F(u, du/dt, t) = du/dt (ODE is expressed in EXPLICIT form)
|
||||
* G(u, t) = - inv(M) K(u) u
|
||||
* 2. F(u, du/dt, t) = M du/dt (ODE is expressed in IMPLICIT form)
|
||||
* G(u, t) = - K(u) u
|
||||
*/
|
||||
class ConductionOperator : public TimeDependentOperator
|
||||
{
|
||||
protected:
|
||||
ParFiniteElementSpace &fespace;
|
||||
Array<int> ess_tdof_list; // this list remains empty for pure Neumann b.c.
|
||||
|
||||
ParBilinearForm *M;
|
||||
ParBilinearForm *K;
|
||||
|
||||
ParBilinearForm M;
|
||||
HypreParMatrix Mmat;
|
||||
|
||||
const real_t alpha, kappa;
|
||||
std::unique_ptr<BilinearForm> K;
|
||||
HypreParMatrix Kmat;
|
||||
HypreParMatrix *T; // T = M + dt K
|
||||
double current_dt;
|
||||
|
||||
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
|
||||
HypreSmoother M_prec; // Preconditioner for the mass matrix M
|
||||
std::unique_ptr<HypreParMatrix> T; // T = M + gam K(u)
|
||||
|
||||
CGSolver T_solver; // Implicit solver for T = M + dt K
|
||||
HypreSmoother T_prec; // Preconditioner for the implicit solver
|
||||
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
|
||||
HypreSmoother M_prec; // Preconditioner for the mass matrix M
|
||||
|
||||
double alpha, kappa;
|
||||
CGSolver T_solver; // Implicit solver for T = M + gam K(u)
|
||||
HypreSmoother T_prec; // Preconditioner for the implicit solver
|
||||
|
||||
mutable Vector z; // auxiliary vector
|
||||
|
||||
public:
|
||||
ConductionOperator(ParFiniteElementSpace &f, double alpha, double kappa,
|
||||
const Vector &u);
|
||||
|
||||
virtual void Mult(const Vector &u, Vector &du_dt) const;
|
||||
ConductionOperator(ParFiniteElementSpace &f, const real_t alpha,
|
||||
const real_t kappa, const Vector &u,
|
||||
const Type &ode_expression_type);
|
||||
|
||||
/** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
|
||||
This is the only requirement for high-order SDIRK implicit integration.*/
|
||||
virtual void ImplicitSolve(const double dt, const Vector &u, Vector &k);
|
||||
// Compute K(u_n) for use as an approximation in - K(u) u
|
||||
void SetConductionTensor(const Vector &u);
|
||||
|
||||
/** Setup the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
|
||||
int jok, int *jcur, double gamma);
|
||||
/** Compute G(u, t) as defined in the IMPLICIT expression form of the ODE
|
||||
operator, i.e., @a v = - K(u_n) @a u. Note that K(u_n) is an
|
||||
approximation to K(u). */
|
||||
void ExplicitMult(const Vector &u, Vector &v) const override;
|
||||
|
||||
/** Solve the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSolve(const Vector &b, Vector &x, double tol);
|
||||
/** Solve for k in F(u, k, t) = G(u, t) for either EXPLICIT or IMPLICIT
|
||||
expression forms of the ODE operator, i.e., @a k = - inv(M) K(u_n) @a u.
|
||||
Note that K(u_n) is an approximation to K(u). */
|
||||
void Mult(const Vector &u, Vector &k) const override;
|
||||
|
||||
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
|
||||
void SetParameters(const Vector &u);
|
||||
/** Solve for k in F(u + gam*k, k, t) = G(u + gam*k, t) for either EXPLICIT
|
||||
or IMPLICIT expression forms of the ODE operator, i.e.,
|
||||
[ M + @a gam K(u_n) ] @a k = - K(u_n) @a u . Note that K(u_n) is an
|
||||
approximation to K(u). */
|
||||
void ImplicitSolve(const real_t gam, const Vector &u, Vector &k) override;
|
||||
|
||||
virtual ~ConductionOperator();
|
||||
/** Setup to solve for dk in [dF/dk + gam*dF/du - gam*dG/du] dk = G - F for
|
||||
either EXPLICIT or IMPLICIT expression forms of the ODE operator, i.e.,
|
||||
[M - @a gam Jf(u)] dk = G - F, where Jf(u) is an approximation of the
|
||||
Jacobian of -K(u) u. The approximation chosen here is Jf(u) = -K(u_n). */
|
||||
int SUNImplicitSetup(const Vector &u, const Vector &fu, int jok, int *jcur,
|
||||
real_t gam) override;
|
||||
|
||||
/** Solve for @a dk in the system in SUNImplicitSetup to the given tolerance,
|
||||
with the residual @a r providing either
|
||||
1. @a r = G - F = inv(M) f(u) - k (EXPLICIT expression form)
|
||||
1. @a r = G - F = f(u) - M k (IMPLICIT expression form)
|
||||
*/
|
||||
int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol) override;
|
||||
|
||||
int SUNMassSetup() override;
|
||||
|
||||
int SUNMassSolve(const Vector &b, Vector &x, real_t tol) override;
|
||||
|
||||
int SUNMassMult(const Vector &x, Vector &v) override;
|
||||
};
|
||||
|
||||
double InitialTemperature(const Vector &x);
|
||||
real_t InitialTemperature(const Vector &x)
|
||||
{
|
||||
if (x.Norml2() < 0.5)
|
||||
{
|
||||
return 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -114,16 +156,16 @@ int main(int argc, char *argv[])
|
||||
int par_ref_levels = 1;
|
||||
int order = 2;
|
||||
int ode_solver_type = 9; // CVODE implicit BDF
|
||||
double t_final = 0.5;
|
||||
double dt = 1.0e-2;
|
||||
double alpha = 1.0e-2;
|
||||
double kappa = 0.5;
|
||||
real_t t_final = 0.5;
|
||||
real_t dt = 1.0e-2;
|
||||
real_t alpha = 1.0e-2;
|
||||
real_t kappa = 0.5;
|
||||
bool visualization = true;
|
||||
bool visit = false;
|
||||
int vis_steps = 5;
|
||||
|
||||
// Relative and absolute tolerances for CVODE and ARKODE.
|
||||
const double reltol = 1e-4, abstol = 1e-4;
|
||||
const real_t reltol = 1e-4, abstol = 1e-4;
|
||||
|
||||
int precision = 8;
|
||||
cout.precision(precision);
|
||||
@@ -150,7 +192,10 @@ int main(int argc, char *argv[])
|
||||
"9 - CVODE (implicit BDF),\n\t"
|
||||
"10 - ARKODE (default explicit),\n\t"
|
||||
"11 - ARKODE (explicit Fehlberg-6-4-5),\n\t"
|
||||
"12 - ARKODE (default impicit).");
|
||||
"12 - ARKODE (default implicit),\n\t"
|
||||
"13 - ARKODE (default explicit with MFEM mass solve),\n\t"
|
||||
"14 - ARKODE (explicit Fehlberg-6-4-5 with MFEM mass solve),\n\t"
|
||||
"15 - ARKODE (default implicit with MFEM mass solve).");
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -174,40 +219,33 @@ int main(int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (myid == 0)
|
||||
if (Mpi::Root())
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
// check for valid ODE solver option
|
||||
if (ode_solver_type < 1 || ode_solver_type > 12)
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
bool use_mass_solver = ode_solver_type >= 13;
|
||||
|
||||
// 3. Read the serial mesh from the given mesh file on all processors. We can
|
||||
// 3. Define a parallel mesh by a partitioning of a serial mesh. Read the
|
||||
// serial mesh from the given mesh file on all processors. We can
|
||||
// handle triangular, quadrilateral, tetrahedral and hexahedral meshes
|
||||
// with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 4. Refine the mesh in serial to increase the resolution. In this example
|
||||
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
|
||||
// a command-line parameter.
|
||||
for (int lev = 0; lev < ser_ref_levels; lev++)
|
||||
std::unique_ptr<ParMesh> pmesh;
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
std::unique_ptr<Mesh> mesh(new Mesh(mesh_file, 1, 1));
|
||||
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
// 4. Refine the mesh in serial to increase the resolution. In this example
|
||||
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
|
||||
// a command-line parameter.
|
||||
for (int lev = 0; lev < ser_ref_levels; lev++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 5. Refine this mesh further in parallel to increase the resolution.
|
||||
// Once the parallel mesh is defined, the serial mesh can be deleted.
|
||||
pmesh = std::make_unique<ParMesh>(MPI_COMM_WORLD, *mesh);
|
||||
}
|
||||
for (int lev = 0; lev < par_ref_levels; lev++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
@@ -215,8 +253,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 6. Define the vector finite element space representing the current and the
|
||||
// initial temperature, u_ref.
|
||||
int dim = pmesh->Dimension();
|
||||
H1_FECollection fe_coll(order, dim);
|
||||
ParFiniteElementSpace fespace(pmesh, &fe_coll);
|
||||
ParFiniteElementSpace fespace(pmesh.get(), &fe_coll);
|
||||
|
||||
int fe_size = fespace.GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
@@ -233,8 +272,17 @@ int main(int argc, char *argv[])
|
||||
Vector u;
|
||||
u_gf.GetTrueDofs(u);
|
||||
|
||||
// 8. Initialize the conduction operator and the VisIt visualization.
|
||||
ConductionOperator oper(fespace, alpha, kappa, u);
|
||||
// 8. Initialize the conduction ODE operator and the visualization.
|
||||
ConductionOperator::Type ode_expression_type;
|
||||
if (use_mass_solver)
|
||||
{
|
||||
ode_expression_type = ConductionOperator::Type::IMPLICIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ode_expression_type = ConductionOperator::Type::EXPLICIT;
|
||||
}
|
||||
ConductionOperator oper(fespace, alpha, kappa, u, ode_expression_type);
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
{
|
||||
@@ -249,7 +297,7 @@ int main(int argc, char *argv[])
|
||||
u_gf.Save(osol);
|
||||
}
|
||||
|
||||
VisItDataCollection visit_dc("Example16-Parallel", pmesh);
|
||||
VisItDataCollection visit_dc("Example16-Parallel", pmesh.get());
|
||||
visit_dc.RegisterField("temperature", &u_gf);
|
||||
if (visit)
|
||||
{
|
||||
@@ -293,52 +341,76 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// 9. Define the ODE solver used for time integration.
|
||||
double t = 0.0;
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKStepSolver *arkode = NULL;
|
||||
real_t t = 0.0;
|
||||
std::unique_ptr<ODESolver> ode_solver;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// MFEM explicit methods
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 1: ode_solver = std::make_unique<ForwardEulerSolver>(); break;
|
||||
case 2: ode_solver = std::make_unique<RK2Solver>(0.5); break; // midpoint method
|
||||
case 3: ode_solver = std::make_unique<RK3SSPSolver>(); break;
|
||||
case 4: ode_solver = std::make_unique<RK4Solver>(); break;
|
||||
// MFEM implicit L-stable methods
|
||||
case 5: ode_solver = new BackwardEulerSolver; break;
|
||||
case 6: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 7: ode_solver = new SDIRK33Solver; break;
|
||||
case 5: ode_solver = std::make_unique<BackwardEulerSolver>(); break;
|
||||
case 6: ode_solver = std::make_unique<SDIRK23Solver>(2); break;
|
||||
case 7: ode_solver = std::make_unique<SDIRK33Solver>(); break;
|
||||
// CVODE
|
||||
case 8:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_ADAMS);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 9:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_BDF);
|
||||
{
|
||||
int cvode_solver_type;
|
||||
if (ode_solver_type == 8)
|
||||
{
|
||||
cvode_solver_type = CV_ADAMS;
|
||||
}
|
||||
else
|
||||
{
|
||||
cvode_solver_type = CV_BDF;
|
||||
}
|
||||
std::unique_ptr<CVODESolver> cvode(
|
||||
new CVODESolver(MPI_COMM_WORLD, cvode_solver_type));
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
ode_solver = std::move(cvode);
|
||||
break;
|
||||
}
|
||||
// ARKODE
|
||||
case 10:
|
||||
case 11:
|
||||
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::EXPLICIT);
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
{
|
||||
ARKStepSolver::Type arkode_solver_type;
|
||||
if (ode_solver_type == 12 || ode_solver_type == 15)
|
||||
{
|
||||
arkode_solver_type = ARKStepSolver::IMPLICIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
arkode_solver_type = ARKStepSolver::EXPLICIT;
|
||||
}
|
||||
std::unique_ptr<ARKStepSolver> arkode(
|
||||
new ARKStepSolver(MPI_COMM_WORLD, arkode_solver_type));
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 11)
|
||||
if (ode_solver_type == 11 || ode_solver_type == 14)
|
||||
{
|
||||
arkode->SetERKTableNum(ARKODE_FEHLBERG_13_7_8);
|
||||
}
|
||||
ode_solver = arkode; break;
|
||||
case 12:
|
||||
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::IMPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
if (use_mass_solver)
|
||||
{
|
||||
arkode->UseMFEMMassLinearSolver(SUNFALSE);
|
||||
}
|
||||
ode_solver = std::move(arkode);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
|
||||
@@ -346,12 +418,18 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Since we want to update the diffusion coefficient after every time step,
|
||||
// we need to use the "one-step" mode of the SUNDIALS solvers.
|
||||
if (cvode) { cvode->SetStepMode(CV_ONE_STEP); }
|
||||
if (arkode) { arkode->SetStepMode(ARK_ONE_STEP); }
|
||||
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
|
||||
{
|
||||
cvode->SetStepMode(CV_ONE_STEP);
|
||||
}
|
||||
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
|
||||
{
|
||||
arkode->SetStepMode(ARK_ONE_STEP);
|
||||
}
|
||||
|
||||
// 10. Perform time-integration (looping over the time iterations, ti, with a
|
||||
// time-step dt).
|
||||
if (myid == 0)
|
||||
if (Mpi::Root())
|
||||
{
|
||||
cout << "Integrating the ODE ..." << endl;
|
||||
}
|
||||
@@ -361,7 +439,7 @@ int main(int argc, char *argv[])
|
||||
bool last_step = false;
|
||||
for (int ti = 1; !last_step; ti++)
|
||||
{
|
||||
double dt_real = min(dt, t_final - t);
|
||||
real_t dt_real = min(dt, t_final - t);
|
||||
|
||||
// Note that since we are using the "one-step" mode of the SUNDIALS
|
||||
// solvers, they will, generally, step over the final time and will not
|
||||
@@ -377,8 +455,14 @@ int main(int argc, char *argv[])
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "step " << ti << ", t = " << t << endl;
|
||||
if (cvode) { cvode->PrintInfo(); }
|
||||
if (arkode) { arkode->PrintInfo(); }
|
||||
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
|
||||
{
|
||||
cvode->PrintInfo();
|
||||
}
|
||||
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
|
||||
{
|
||||
arkode->PrintInfo();
|
||||
}
|
||||
}
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
@@ -395,46 +479,38 @@ int main(int argc, char *argv[])
|
||||
visit_dc.Save();
|
||||
}
|
||||
}
|
||||
oper.SetParameters(u);
|
||||
oper.SetConductionTensor(u);
|
||||
}
|
||||
tic_toc.Stop();
|
||||
if (myid == 0)
|
||||
if (Mpi::Root())
|
||||
{
|
||||
cout << "Done, " << tic_toc.RealTime() << "s." << endl;
|
||||
}
|
||||
|
||||
// 11. Save the final solution in parallel. This output can be viewed later
|
||||
// using GLVis: "glvis -np <np> -m ex16-mesh -g ex16-final".
|
||||
{
|
||||
ostringstream sol_name;
|
||||
sol_name << "ex16-final." << setfill('0') << setw(6) << myid;
|
||||
ofstream osol(sol_name.str().c_str());
|
||||
osol.precision(precision);
|
||||
u_gf.Save(osol);
|
||||
}
|
||||
|
||||
// 12. Free the used memory.
|
||||
delete ode_solver;
|
||||
delete pmesh;
|
||||
u_gf.Save("ex16-final", precision);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConductionOperator::ConductionOperator(ParFiniteElementSpace &f, double al,
|
||||
double kap, const Vector &u)
|
||||
: TimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL), K(NULL),
|
||||
T(NULL),
|
||||
M_solver(f.GetComm()), T_solver(f.GetComm()), z(height)
|
||||
ConductionOperator::ConductionOperator(ParFiniteElementSpace &fes,
|
||||
const real_t alpha, const real_t kappa,
|
||||
const Vector &u,
|
||||
const Type &ode_expression_type)
|
||||
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
|
||||
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace),
|
||||
M_solver(fes.GetComm()), T_solver(fes.GetComm()), z(height)
|
||||
{
|
||||
const double rel_tol = 1e-8;
|
||||
// specify a relative tolerance for all solves with MFEM integrators
|
||||
const real_t rel_tol = 1e-8;
|
||||
|
||||
M = new ParBilinearForm(&fespace);
|
||||
M->AddDomainIntegrator(new MassIntegrator());
|
||||
M->Assemble(0); // keep sparsity pattern of M and K the same
|
||||
M->FormSystemMatrix(ess_tdof_list, Mmat);
|
||||
M.AddDomainIntegrator(new MassIntegrator());
|
||||
M.Assemble(0); // keep zeros to keep sparsity pattern of M and K the same
|
||||
M.FormSystemMatrix(ess_tdof_list, Mmat);
|
||||
|
||||
M_solver.iterative_mode = false;
|
||||
M_solver.SetRelTol(rel_tol);
|
||||
M_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
|
||||
M_solver.SetAbsTol(0.0);
|
||||
M_solver.SetMaxIter(100);
|
||||
M_solver.SetPrintLevel(0);
|
||||
@@ -442,97 +518,118 @@ ConductionOperator::ConductionOperator(ParFiniteElementSpace &f, double al,
|
||||
M_solver.SetPreconditioner(M_prec);
|
||||
M_solver.SetOperator(Mmat);
|
||||
|
||||
alpha = al;
|
||||
kappa = kap;
|
||||
|
||||
T_solver.iterative_mode = false;
|
||||
T_solver.SetRelTol(rel_tol);
|
||||
T_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
|
||||
T_solver.SetAbsTol(0.0);
|
||||
T_solver.SetMaxIter(100);
|
||||
T_solver.SetPrintLevel(0);
|
||||
T_solver.SetPreconditioner(T_prec);
|
||||
|
||||
SetParameters(u);
|
||||
SetConductionTensor(u);
|
||||
}
|
||||
|
||||
void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
|
||||
{
|
||||
// Compute:
|
||||
// du_dt = M^{-1}*-K(u)
|
||||
// for du_dt
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg(); // z = -z
|
||||
M_solver.Mult(z, du_dt);
|
||||
}
|
||||
|
||||
void ConductionOperator::ImplicitSolve(const double dt,
|
||||
const Vector &u, Vector &du_dt)
|
||||
{
|
||||
// Solve the equation:
|
||||
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
|
||||
// for du_dt
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
T_solver.SetOperator(*T);
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg();
|
||||
T_solver.Mult(z, du_dt);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSetup(const Vector &x,
|
||||
const Vector &fx, int jok, int *jcur,
|
||||
double gamma)
|
||||
{
|
||||
// Setup the ODE Jacobian T = M + gamma K.
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, gamma, Kmat);
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &b, Vector &x, double tol)
|
||||
{
|
||||
// Solve the system A x = z => (M - gamma K) x = M b.
|
||||
Mmat.Mult(b, z);
|
||||
T_solver.Mult(z, x);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void ConductionOperator::SetParameters(const Vector &u)
|
||||
void ConductionOperator::SetConductionTensor(const Vector &u)
|
||||
{
|
||||
// Compute K(u_n).
|
||||
ParGridFunction u_alpha_gf(&fespace);
|
||||
u_alpha_gf.SetFromTrueDofs(u);
|
||||
for (int i = 0; i < u_alpha_gf.Size(); i++)
|
||||
{
|
||||
u_alpha_gf(i) = kappa + alpha*u_alpha_gf(i);
|
||||
}
|
||||
|
||||
delete K;
|
||||
K = new ParBilinearForm(&fespace);
|
||||
|
||||
GridFunctionCoefficient u_coeff(&u_alpha_gf);
|
||||
|
||||
K = std::make_unique<ParBilinearForm>(&fespace);
|
||||
K->AddDomainIntegrator(new DiffusionIntegrator(u_coeff));
|
||||
K->Assemble(0); // keep sparsity pattern of M and K the same
|
||||
K->Assemble(0); // keep zeros to keep sparsity pattern of M and K the same
|
||||
K->FormSystemMatrix(ess_tdof_list, Kmat);
|
||||
}
|
||||
|
||||
ConductionOperator::~ConductionOperator()
|
||||
void ConductionOperator::ExplicitMult(const Vector &u, Vector &v) const
|
||||
{
|
||||
delete T;
|
||||
delete M;
|
||||
delete K;
|
||||
// Compute - K(u_n) u.
|
||||
Kmat.Mult(u, v);
|
||||
v.Neg();
|
||||
}
|
||||
|
||||
double InitialTemperature(const Vector &x)
|
||||
void ConductionOperator::Mult(const Vector &u, Vector &k) const
|
||||
{
|
||||
if (x.Norml2() < 0.5)
|
||||
// Compute - inv(M) K(u_n) u.
|
||||
ExplicitMult(u, z);
|
||||
M_solver.Mult(z, k);
|
||||
}
|
||||
|
||||
void ConductionOperator::ImplicitSolve(const real_t gam, const Vector &u,
|
||||
Vector &k)
|
||||
{
|
||||
// Solve for k in M k = - K(u_n) [u + gam*k].
|
||||
ExplicitMult(u, z);
|
||||
T = std::unique_ptr<HypreParMatrix>(Add(1.0, Mmat, gam, Kmat));
|
||||
T_solver.SetOperator(*T);
|
||||
T_solver.Mult(z, k);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
|
||||
int jok, int *jcur, real_t gam)
|
||||
{
|
||||
// Compute T = M + gamma K(u_n).
|
||||
T = std::unique_ptr<HypreParMatrix>(Add(1.0, Mmat, gam, Kmat));
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
|
||||
real_t tol)
|
||||
{
|
||||
// Solve the system [M + gamma K(u_n)] dk = - K(u_n) u - M k.
|
||||
// What value r is providing depends on the ODE expression form:
|
||||
// EXPLICIT form: r = -inv(M) K(u_n) u - k
|
||||
// IMPLICIT form: r = -K(u_n) u - M k
|
||||
T_solver.SetRelTol(tol);
|
||||
if (isExplicit())
|
||||
{
|
||||
return 2.0;
|
||||
Mmat.Mult(r, z);
|
||||
T_solver.Mult(z, dk);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0;
|
||||
T_solver.Mult(r, dk);
|
||||
}
|
||||
if (T_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SUNLS_CONV_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassSetup()
|
||||
{
|
||||
// Do nothing b/c mass solver was setup in constructor.
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
|
||||
{
|
||||
// Solve the system M x = b.
|
||||
M_solver.SetRelTol(tol);
|
||||
M_solver.Mult(b, x);
|
||||
if (M_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SUNLS_CONV_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
|
||||
{
|
||||
// Compute M x.
|
||||
Mmat.Mult(x, v);
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// MFEM Example 9
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex9
|
||||
// Compile with:
|
||||
// make ex9 (GNU make)
|
||||
// make sundials_ex9 (CMake)
|
||||
//
|
||||
// Sample runs:
|
||||
// ex9 -m ../../data/periodic-segment.mesh -p 0 -r 2 -s 7 -dt 0.005
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// MFEM Example 9 - Parallel Version
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex9p
|
||||
// Compile with:
|
||||
// make ex9p (GNU make)
|
||||
// make sundials_ex9p (CMake)
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-segment.mesh -p 1 -rp 1 -s 7 -dt 0.0025
|
||||
|
||||
@@ -100,6 +100,12 @@ ex10-test-seq: ex10
|
||||
@$(call mfem-test,$<,, $(SERIAL_NAME),$(EX10_ARGS))
|
||||
ex10p-test-par: ex10p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME),$(EX10P_ARGS))
|
||||
# Example 16: test ARKODE with implicit time stepping using mass form
|
||||
EX16_COMMON_ARGS := -s 15
|
||||
ex16-test-seq: ex16
|
||||
@$(call mfem-test,$<,, $(SERIAL_NAME),$(EX16_COMMON_ARGS))
|
||||
ex16p-test-par: ex16p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME),$(EX16_COMMON_ARGS))
|
||||
|
||||
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
|
||||
|
||||
|
||||
+3
-3
@@ -112,8 +112,6 @@ set(SRCS
|
||||
qinterp/eval_by_vdim.cpp
|
||||
qinterp/grad_by_nodes.cpp
|
||||
qinterp/grad_by_vdim.cpp
|
||||
qinterp/grad_phys_by_nodes.cpp
|
||||
qinterp/grad_phys_by_vdim.cpp
|
||||
qspace.cpp
|
||||
quadinterpolator.cpp
|
||||
quadinterpolator_face.cpp
|
||||
@@ -192,6 +190,9 @@ set(HDRS
|
||||
hybridization.hpp
|
||||
intrules.hpp
|
||||
intrules_cut.hpp
|
||||
kernel_dispatch.hpp
|
||||
kernel_reporter.hpp
|
||||
kernels.hpp
|
||||
ceed/interface/basis.hpp
|
||||
ceed/interface/integrator.hpp
|
||||
ceed/interface/interface.hpp
|
||||
@@ -223,7 +224,6 @@ set(HDRS
|
||||
nonlinearform_ext.hpp
|
||||
nonlininteg.hpp
|
||||
qfunction.hpp
|
||||
qinterp/dispatch.hpp
|
||||
qinterp/eval.hpp
|
||||
qinterp/grad.hpp
|
||||
qspace.hpp
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "qfunction.hpp"
|
||||
#include <memory>
|
||||
|
||||
#include "kernel_dispatch.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
@@ -2127,6 +2129,22 @@ public:
|
||||
can be a scalar or a matrix coefficient. */
|
||||
class DiffusionIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
public:
|
||||
|
||||
using ApplyKernelType = void(*)(const int, const bool, const Array<real_t>&,
|
||||
const Array<real_t>&, const Array<real_t>&,
|
||||
const Array<real_t>&,
|
||||
const Vector&, const Vector&,
|
||||
Vector&, const int, const int);
|
||||
|
||||
using DiagonalKernelType = void(*)(const int, const bool, const Array<real_t>&,
|
||||
const Array<real_t>&, const Vector&, Vector&,
|
||||
const int, const int);
|
||||
|
||||
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
|
||||
MFEM_REGISTER_KERNELS(DiagonalPAKernels, DiagonalKernelType, (int, int, int));
|
||||
static struct Kernels { Kernels(); } kernels;
|
||||
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
VectorCoefficient *VQ;
|
||||
@@ -2287,6 +2305,13 @@ public:
|
||||
bool SupportsCeed() const { return DeviceCanUseCeed(); }
|
||||
|
||||
Coefficient *GetCoefficient() const { return Q; }
|
||||
|
||||
template <int DIM, int D1D, int Q1D>
|
||||
static void AddSpecialization()
|
||||
{
|
||||
ApplyPAKernels::Specialization<DIM,D1D,Q1D>::Add();
|
||||
DiagonalPAKernels::Specialization<DIM,D1D,Q1D>::Add();
|
||||
}
|
||||
};
|
||||
|
||||
/** Class for local mass matrix assembling $a(u,v) := (Q u, v)$ */
|
||||
@@ -2306,6 +2331,20 @@ protected:
|
||||
const FaceGeometricFactors *face_geom; ///< Not owned
|
||||
int dim, ne, nq, dofs1D, quad1D;
|
||||
|
||||
public:
|
||||
|
||||
using ApplyKernelType = void(*)(const int, const Array<real_t>&,
|
||||
const Array<real_t>&, const Vector&,
|
||||
const Vector&, Vector&, const int, const int);
|
||||
|
||||
using DiagonalKernelType = void(*)(const int, const Array<real_t>&,
|
||||
const Vector&, Vector&, const int,
|
||||
const int);
|
||||
|
||||
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
|
||||
MFEM_REGISTER_KERNELS(DiagonalPAKernels, DiagonalKernelType, (int, int, int));
|
||||
static struct Kernels { Kernels(); } kernels;
|
||||
|
||||
public:
|
||||
MassIntegrator(const IntegrationRule *ir = NULL)
|
||||
: BilinearFormIntegrator(ir), Q(NULL), maps(NULL), geom(NULL) { }
|
||||
@@ -2351,6 +2390,13 @@ public:
|
||||
bool SupportsCeed() const { return DeviceCanUseCeed(); }
|
||||
|
||||
const Coefficient *GetCoefficient() const { return Q; }
|
||||
|
||||
template <int DIM, int D1D, int Q1D>
|
||||
static void AddSpecialization()
|
||||
{
|
||||
ApplyPAKernels::Specialization<DIM,D1D,Q1D>::Add();
|
||||
DiagonalPAKernels::Specialization<DIM,D1D,Q1D>::Add();
|
||||
}
|
||||
};
|
||||
|
||||
/** Mass integrator $(u, v)$ restricted to the boundary of a domain */
|
||||
|
||||
+17
-2
@@ -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
@@ -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
@@ -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
@@ -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 (11‐12) 1407-1422
|
||||
|
||||
[2] John A Evans, Thomas JR Hughes
|
||||
"Isogeometric divergence-conforming B-splines for the unsteady Navier–Stokes 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 (11‐12) 1407-1422
|
||||
|
||||
[2] John A Evans, Thomas JR Hughes
|
||||
"Isogeometric divergence-conforming B-splines for the unsteady
|
||||
Navier–Stokes 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
@@ -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
@@ -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
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
+114
@@ -1168,6 +1168,120 @@ void FindPointsGSLIB::InterpolateGeneral(const GridFunction &field_in,
|
||||
} // parallel
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::DistributePointInfoToOwningMPIRanks(
|
||||
Array<unsigned int> &recv_elem, Vector &recv_ref,
|
||||
Array<unsigned int> &recv_code)
|
||||
{
|
||||
MFEM_VERIFY(points_cnt,
|
||||
"Invalid size. Please make sure to call FindPoints method "
|
||||
"before calling this function.");
|
||||
|
||||
// Pack data to send via crystal router
|
||||
struct gslib::array *outpt = new gslib::array;
|
||||
|
||||
struct out_pt { double rst[3]; uint index, elem, proc, code; };
|
||||
struct out_pt *pt;
|
||||
array_init(struct out_pt, outpt, points_cnt);
|
||||
outpt->n=points_cnt;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
|
||||
for (int index = 0; index < points_cnt; index++)
|
||||
{
|
||||
pt->index = index;
|
||||
pt->elem = gsl_mfem_elem[index];
|
||||
pt->proc = gsl_proc[index];
|
||||
pt->code = gsl_code[index];
|
||||
for (int d = 0; d < dim; ++d)
|
||||
{
|
||||
pt->rst[d]= gsl_mfem_ref(index*dim + d);
|
||||
}
|
||||
++pt;
|
||||
}
|
||||
|
||||
// Transfer data to target MPI ranks
|
||||
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
|
||||
|
||||
// Store received data
|
||||
const int points_recv = outpt->n;
|
||||
recv_proc.SetSize(points_recv);
|
||||
recv_elem.SetSize(points_recv);
|
||||
recv_index.SetSize(points_recv);
|
||||
recv_code.SetSize(points_recv);
|
||||
recv_ref.SetSize(points_recv*dim);
|
||||
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < points_recv; index++)
|
||||
{
|
||||
recv_index[index] = pt->index;
|
||||
recv_elem[index] = pt->elem;
|
||||
recv_proc[index] = pt->proc;
|
||||
recv_code[index] = pt->code;
|
||||
for (int d = 0; d < dim; ++d)
|
||||
{
|
||||
recv_ref(index*dim + d)= pt->rst[d];
|
||||
}
|
||||
++pt;
|
||||
}
|
||||
|
||||
array_free(outpt);
|
||||
delete outpt;
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::DistributeInterpolatedValues(const Vector &int_vals,
|
||||
const int vdim,
|
||||
const int ordering,
|
||||
Vector &field_out) const
|
||||
{
|
||||
const int points_recv = recv_index.Size();;
|
||||
MFEM_VERIFY(points_recv == 0 ||
|
||||
int_vals.Size() % points_recv == 0,
|
||||
"Incompatible size. Please return interpolated values"
|
||||
"corresponding to points received using"
|
||||
"SendCoordinatesToOwningProcessors.");
|
||||
field_out.SetSize(points_cnt*vdim);
|
||||
|
||||
for (int v = 0; v < vdim; v++)
|
||||
{
|
||||
// Pack data to send via crystal router
|
||||
struct gslib::array *outpt = new gslib::array;
|
||||
struct out_pt { double val; uint index, proc; };
|
||||
struct out_pt *pt;
|
||||
array_init(struct out_pt, outpt, points_recv);
|
||||
outpt->n=points_recv;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < points_recv; index++)
|
||||
{
|
||||
pt->index = recv_index[index];
|
||||
pt->proc = recv_proc[index];
|
||||
pt->val = ordering == Ordering::byNODES ?
|
||||
int_vals(index + v*points_recv) :
|
||||
int_vals(index*vdim + v);
|
||||
++pt;
|
||||
}
|
||||
|
||||
// Transfer data to target MPI ranks
|
||||
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
|
||||
|
||||
// Store received data
|
||||
MFEM_VERIFY(outpt->n == points_cnt, "Incompatible size. Number of points "
|
||||
"received does not match the number of points originally "
|
||||
"found using FindPoints.");
|
||||
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < points_cnt; index++)
|
||||
{
|
||||
int idx = ordering == Ordering::byNODES ?
|
||||
pt->index + v*points_cnt :
|
||||
pt->index*vdim + v;
|
||||
field_out(idx) = pt->val;
|
||||
++pt;
|
||||
}
|
||||
|
||||
array_free(outpt);
|
||||
delete outpt;
|
||||
}
|
||||
}
|
||||
|
||||
void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
|
||||
GridFunction *gfmax,
|
||||
const double bb_t, const double newt_tol,
|
||||
|
||||
+66
-19
@@ -34,7 +34,7 @@ namespace mfem
|
||||
*
|
||||
* There are three key functions in FindPointsGSLIB:
|
||||
*
|
||||
* 1. Setup - constructs the internal data structures of gslib.
|
||||
* 1. Setup - constructs the internal data structures of gslib. See \ref Setup.
|
||||
*
|
||||
* 2. FindPoints - for any given arbitrary set of points in physical space,
|
||||
* gslib finds the element number, MPI rank, and the reference space
|
||||
@@ -45,12 +45,23 @@ namespace mfem
|
||||
* on an element edge/face or near the domain boundary, and gslib also
|
||||
* returns a distance to the border. Points near (but outside) the domain
|
||||
* boundary must then be marked as not found using the distance returned
|
||||
* by gslib.
|
||||
* by gslib. See \ref FindPoints.
|
||||
*
|
||||
* 3. Interpolate - Interpolates any grid function at the points found using 2.
|
||||
* For functions in L2 finite element space, use \ref SetL2AvgType to
|
||||
* specify how to interpolate values at points located at element boundaries
|
||||
* where the function might be multi-valued. See \ref Interpolate.
|
||||
*
|
||||
* FindPointsGSLIB provides interface to use these functions individually or
|
||||
* using a single call.
|
||||
* FindPointsGSLIB also provides interface to use these functions through a
|
||||
* single call.
|
||||
*
|
||||
* For custom interpolation (e.g., evaluating strain rate tensor), we provide
|
||||
* functions that use gslib to send element index and corresponding
|
||||
* reference-space coordinates for each point to the mpi rank that the element
|
||||
* is located on. Then, custom interpolation can be defined locally by the user
|
||||
* before sending the values back to mpi ranks where the query originated from.
|
||||
* See \ref DistributePointInfoToOwningMPIRanks and
|
||||
* \ref DistributeInterpolatedValues.
|
||||
*/
|
||||
class FindPointsGSLIB
|
||||
{
|
||||
@@ -74,7 +85,8 @@ protected:
|
||||
int dim, points_cnt;
|
||||
Array<unsigned int> gsl_code, gsl_proc, gsl_elem, gsl_mfem_elem;
|
||||
Vector gsl_mesh, gsl_ref, gsl_dist, gsl_mfem_ref;
|
||||
bool setupflag; // flag to indicate whether gslib data has been setup
|
||||
Array<unsigned int> recv_proc, recv_index; // data for custom interpolation
|
||||
bool setupflag; // flag to indicate if gslib data has been setup
|
||||
double default_interp_value; // used for points that are not found in the mesh
|
||||
AvgType avgtype; // average type used for L2 functions
|
||||
Array<int> split_element_map;
|
||||
@@ -118,9 +130,9 @@ public:
|
||||
virtual ~FindPointsGSLIB();
|
||||
|
||||
/** Initializes the internal mesh in gslib, by sending the positions of the
|
||||
Gauss-Lobatto nodes of the input Mesh object @a m.
|
||||
Gauss-Lobatto nodes of the input Mesh object \p m.
|
||||
Note: not tested with periodic (L2).
|
||||
Note: the input mesh @a m must have Nodes set.
|
||||
Note: the input mesh \p m must have Nodes set.
|
||||
|
||||
@param[in] m Input mesh.
|
||||
@param[in] bb_t (Optional) Relative size of bounding box around
|
||||
@@ -133,9 +145,9 @@ public:
|
||||
void Setup(Mesh &m, const double bb_t = 0.1,
|
||||
const double newt_tol = 1.0e-12,
|
||||
const int npt_max = 256);
|
||||
/** Searches positions given in physical space by @a point_pos.
|
||||
/** Searches positions given in physical space by \p point_pos.
|
||||
These positions can be ordered byNodes: (XXX...,YYY...,ZZZ) or
|
||||
byVDim: (XYZ,XYZ,....XYZ) specified by @a point_pos_ordering.
|
||||
byVDim: (XYZ,XYZ,....XYZ) specified by \p point_pos_ordering.
|
||||
This function populates the following member variables:
|
||||
#gsl_code Return codes for each point: inside element (0),
|
||||
element boundary (1), not found (2).
|
||||
@@ -164,20 +176,20 @@ public:
|
||||
/** Interpolation of field values at prescribed reference space positions.
|
||||
@param[in] field_in Function values that will be interpolated on the
|
||||
reference positions. Note: it is assumed that
|
||||
@a field_in is in H1 and in the same space as the
|
||||
\p field_in is in H1 and in the same space as the
|
||||
mesh that was given to Setup().
|
||||
@param[out] field_out Interpolated values. For points that are not found
|
||||
the value is set to #default_interp_value. */
|
||||
virtual void Interpolate(const GridFunction &field_in, Vector &field_out);
|
||||
/** Search positions and interpolate. The ordering (byNODES or byVDIM) of
|
||||
the output values in @a field_out corresponds to the ordering used
|
||||
in the input GridFunction @a field_in. */
|
||||
the output values in \p field_out corresponds to the ordering used
|
||||
in the input GridFunction \p field_in. */
|
||||
void Interpolate(const Vector &point_pos, const GridFunction &field_in,
|
||||
Vector &field_out,
|
||||
int point_pos_ordering = Ordering::byNODES);
|
||||
/** Setup FindPoints, search positions and interpolate. The ordering (byNODES
|
||||
or byVDIM) of the output values in @a field_out corresponds to the
|
||||
ordering used in the input GridFunction @a field_in. */
|
||||
or byVDIM) of the output values in \p field_out corresponds to the
|
||||
ordering used in the input GridFunction \p field_in. */
|
||||
void Interpolate(Mesh &m, const Vector &point_pos,
|
||||
const GridFunction &field_in, Vector &field_out,
|
||||
int point_pos_ordering = Ordering::byNODES);
|
||||
@@ -225,6 +237,41 @@ public:
|
||||
/// Return reference coordinates in [-1,1] (internal range in GSLIB) for each
|
||||
/// point found by FindPoints.
|
||||
virtual const Vector &GetGSLIBReferencePosition() const { return gsl_ref; }
|
||||
|
||||
/** @name Methods to support a custom interpolation procedure.
|
||||
\brief The physical-space point that the user seeks to interpolate at
|
||||
could be located inside an element on another mpi rank.
|
||||
To enable a custom interpolation procedure (e.g., strain tensor computation)
|
||||
we need a mechanism to first send element indices and reference-space
|
||||
coordinates to the mpi-ranks where each point is found. Then the custom
|
||||
interpolation can be done locally by the user before sending the
|
||||
interpolated values back to the mpi-ranks that the query originated from.
|
||||
Example usage looks something like this:
|
||||
|
||||
FindPoints() -> DistributePointInfoToOwningMPIRanks() -> Computation by
|
||||
user -> DistributeInterpolatedValues().
|
||||
*/
|
||||
///@{
|
||||
/// Distribute element indices in #gsl_mfem_elem, the reference coordinates
|
||||
/// #gsl_mfem_ref, and the code #gsl_code to the corresponding mpi-rank
|
||||
/// #gsl_proc for each point. The received information is provided locally
|
||||
/// in \p recv_elem, \p recv_ref (ordered by vdim), and \p recv_code.
|
||||
/// Note: The user can send empty Array/Vectors to the method as they are
|
||||
/// appropriately sized and filled internally.
|
||||
virtual void DistributePointInfoToOwningMPIRanks(
|
||||
Array<unsigned int> &recv_elem, Vector &recv_ref,
|
||||
Array<unsigned int> &recv_code);
|
||||
/// Return interpolated values back to the mpi-ranks #recv_proc that had
|
||||
/// sent the element indices and corresponding reference-space coordinates.
|
||||
/// Specify \p vdim and \p ordering (by nodes or by vdim) based on how the
|
||||
/// \p int_vals are structured. The received values are filled in
|
||||
/// \p field_out consistent with the original ordering of the points that
|
||||
/// were used in \ref FindPoints.
|
||||
virtual void DistributeInterpolatedValues(const Vector &int_vals,
|
||||
const int vdim,
|
||||
const int ordering,
|
||||
Vector &field_out) const;
|
||||
///@}
|
||||
};
|
||||
|
||||
/** \brief OversetFindPointsGSLIB enables use of findpts for arbitrary number of
|
||||
@@ -249,9 +296,9 @@ public:
|
||||
#endif
|
||||
|
||||
/** Initializes the internal mesh in gslib, by sending the positions of the
|
||||
Gauss-Lobatto nodes of the input Mesh object @a m.
|
||||
Gauss-Lobatto nodes of the input Mesh object \p m.
|
||||
Note: not tested with periodic meshes (L2).
|
||||
Note: the input mesh @a m must have Nodes set.
|
||||
Note: the input mesh \p m must have Nodes set.
|
||||
|
||||
@param[in] m Input mesh.
|
||||
@param[in] meshid A unique # for each overlapping mesh. This id is
|
||||
@@ -274,12 +321,12 @@ public:
|
||||
const double bb_t = 0.1, const double newt_tol = 1.0e-12,
|
||||
const int npt_max = 256);
|
||||
|
||||
/** Searches positions given in physical space by @a point_pos. All output
|
||||
/** Searches positions given in physical space by \p point_pos. All output
|
||||
Arrays and Vectors are expected to have the correct size.
|
||||
|
||||
@param[in] point_pos Positions to be found.
|
||||
@param[in] point_id Index of the mesh that the point belongs
|
||||
to (corresponding to @a meshid in Setup).
|
||||
to (corresponding to \p meshid in Setup).
|
||||
@param[in] point_pos_ordering Ordering of the points:
|
||||
byNodes: (XXX...,YYY...,ZZZ) or
|
||||
byVDim: (XYZ,XYZ,....XYZ) */
|
||||
@@ -342,7 +389,7 @@ public:
|
||||
enum GSOp {ADD, MUL, MIN, MAX};
|
||||
|
||||
/// Update the identifiers used for the gather-scatter operator.
|
||||
/// Same @a ids get grouped together and id == 0 does not participate.
|
||||
/// Same \p ids get grouped together and id == 0 does not participate.
|
||||
/// See class description.
|
||||
void UpdateIdentifiers(const Array<long long> &ids);
|
||||
|
||||
|
||||
@@ -14,6 +14,33 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// PA Diffusion Integrator
|
||||
|
||||
DiffusionIntegrator::Kernels DiffusionIntegrator::kernels;
|
||||
DiffusionIntegrator::Kernels::Kernels()
|
||||
{
|
||||
// 2D
|
||||
DiffusionIntegrator::AddSpecialization<2,2,2>();
|
||||
DiffusionIntegrator::AddSpecialization<2,3,3>();
|
||||
DiffusionIntegrator::AddSpecialization<2,4,4>();
|
||||
DiffusionIntegrator::AddSpecialization<2,5,5>();
|
||||
DiffusionIntegrator::AddSpecialization<2,6,6>();
|
||||
DiffusionIntegrator::AddSpecialization<2,7,7>();
|
||||
DiffusionIntegrator::AddSpecialization<2,8,8>();
|
||||
DiffusionIntegrator::AddSpecialization<2,9,9>();
|
||||
// 3D
|
||||
DiffusionIntegrator::AddSpecialization<3,2,2>();
|
||||
DiffusionIntegrator::AddSpecialization<3,2,3>();
|
||||
DiffusionIntegrator::AddSpecialization<3,3,4>();
|
||||
DiffusionIntegrator::AddSpecialization<3,4,5>();
|
||||
DiffusionIntegrator::AddSpecialization<3,4,6>();
|
||||
DiffusionIntegrator::AddSpecialization<3,5,6>();
|
||||
DiffusionIntegrator::AddSpecialization<3,5,8>();
|
||||
DiffusionIntegrator::AddSpecialization<3,6,7>();
|
||||
DiffusionIntegrator::AddSpecialization<3,7,8>();
|
||||
DiffusionIntegrator::AddSpecialization<3,8,9>();
|
||||
}
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
@@ -363,118 +390,6 @@ void OccaPADiffusionSetup3D(const int D1D,
|
||||
}
|
||||
#endif // MFEM_USE_OCCA
|
||||
|
||||
void PADiffusionAssembleDiagonal(const int dim,
|
||||
const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symm,
|
||||
const Array<real_t> &B,
|
||||
const Array<real_t> &G,
|
||||
const Vector &D,
|
||||
Vector &Y)
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
switch ((D1D << 4 ) | Q1D)
|
||||
{
|
||||
case 0x22: return SmemPADiffusionDiagonal2D<2,2,8>(NE,symm,B,G,D,Y);
|
||||
case 0x33: return SmemPADiffusionDiagonal2D<3,3,8>(NE,symm,B,G,D,Y);
|
||||
case 0x44: return SmemPADiffusionDiagonal2D<4,4,4>(NE,symm,B,G,D,Y);
|
||||
case 0x55: return SmemPADiffusionDiagonal2D<5,5,4>(NE,symm,B,G,D,Y);
|
||||
case 0x66: return SmemPADiffusionDiagonal2D<6,6,2>(NE,symm,B,G,D,Y);
|
||||
case 0x77: return SmemPADiffusionDiagonal2D<7,7,2>(NE,symm,B,G,D,Y);
|
||||
case 0x88: return SmemPADiffusionDiagonal2D<8,8,1>(NE,symm,B,G,D,Y);
|
||||
case 0x99: return SmemPADiffusionDiagonal2D<9,9,1>(NE,symm,B,G,D,Y);
|
||||
default: return PADiffusionDiagonal2D(NE,symm,B,G,D,Y,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch ((D1D << 4 ) | Q1D)
|
||||
{
|
||||
case 0x22: return SmemPADiffusionDiagonal3D<2,2>(NE,symm,B,G,D,Y);
|
||||
case 0x23: return SmemPADiffusionDiagonal3D<2,3>(NE,symm,B,G,D,Y);
|
||||
case 0x34: return SmemPADiffusionDiagonal3D<3,4>(NE,symm,B,G,D,Y);
|
||||
case 0x45: return SmemPADiffusionDiagonal3D<4,5>(NE,symm,B,G,D,Y);
|
||||
case 0x46: return SmemPADiffusionDiagonal3D<4,6>(NE,symm,B,G,D,Y);
|
||||
case 0x56: return SmemPADiffusionDiagonal3D<5,6>(NE,symm,B,G,D,Y);
|
||||
case 0x67: return SmemPADiffusionDiagonal3D<6,7>(NE,symm,B,G,D,Y);
|
||||
case 0x78: return SmemPADiffusionDiagonal3D<7,8>(NE,symm,B,G,D,Y);
|
||||
case 0x89: return SmemPADiffusionDiagonal3D<8,9>(NE,symm,B,G,D,Y);
|
||||
case 0x9A: return SmemPADiffusionDiagonal3D<9,10>(NE,symm,B,G,D,Y);
|
||||
default: return PADiffusionDiagonal3D(NE,symm,B,G,D,Y,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
}
|
||||
|
||||
void PADiffusionApply(const int dim,
|
||||
const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symm,
|
||||
const Array<real_t> &B,
|
||||
const Array<real_t> &G,
|
||||
const Array<real_t> &Bt,
|
||||
const Array<real_t> &Gt,
|
||||
const Vector &D,
|
||||
const Vector &X,
|
||||
Vector &Y)
|
||||
{
|
||||
#ifdef MFEM_USE_OCCA
|
||||
if (DeviceCanUseOcca())
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
OccaPADiffusionApply2D(D1D,Q1D,NE,B,G,Bt,Gt,D,X,Y);
|
||||
return;
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
OccaPADiffusionApply3D(D1D,Q1D,NE,B,G,Bt,Gt,D,X,Y);
|
||||
return;
|
||||
}
|
||||
MFEM_ABORT("OCCA PADiffusionApply unknown kernel!");
|
||||
}
|
||||
#endif // MFEM_USE_OCCA
|
||||
const int id = (D1D << 4) | Q1D;
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x22: return SmemPADiffusionApply2D<2,2,16>(NE,symm,B,G,D,X,Y);
|
||||
case 0x33: return SmemPADiffusionApply2D<3,3,16>(NE,symm,B,G,D,X,Y);
|
||||
case 0x44: return SmemPADiffusionApply2D<4,4,8>(NE,symm,B,G,D,X,Y);
|
||||
case 0x55: return SmemPADiffusionApply2D<5,5,8>(NE,symm,B,G,D,X,Y);
|
||||
case 0x66: return SmemPADiffusionApply2D<6,6,4>(NE,symm,B,G,D,X,Y);
|
||||
case 0x77: return SmemPADiffusionApply2D<7,7,4>(NE,symm,B,G,D,X,Y);
|
||||
case 0x88: return SmemPADiffusionApply2D<8,8,2>(NE,symm,B,G,D,X,Y);
|
||||
case 0x99: return SmemPADiffusionApply2D<9,9,2>(NE,symm,B,G,D,X,Y);
|
||||
default: return PADiffusionApply2D(NE,symm,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x22: return SmemPADiffusionApply3D<2,2>(NE,symm,B,G,D,X,Y);
|
||||
case 0x23: return SmemPADiffusionApply3D<2,3>(NE,symm,B,G,D,X,Y);
|
||||
case 0x34: return SmemPADiffusionApply3D<3,4>(NE,symm,B,G,D,X,Y);
|
||||
case 0x45: return SmemPADiffusionApply3D<4,5>(NE,symm,B,G,D,X,Y);
|
||||
case 0x46: return SmemPADiffusionApply3D<4,6>(NE,symm,B,G,D,X,Y);
|
||||
case 0x56: return SmemPADiffusionApply3D<5,6>(NE,symm,B,G,D,X,Y);
|
||||
case 0x58: return SmemPADiffusionApply3D<5,8>(NE,symm,B,G,D,X,Y);
|
||||
case 0x67: return SmemPADiffusionApply3D<6,7>(NE,symm,B,G,D,X,Y);
|
||||
case 0x78: return SmemPADiffusionApply3D<7,8>(NE,symm,B,G,D,X,Y);
|
||||
case 0x89: return SmemPADiffusionApply3D<8,9>(NE,symm,B,G,D,X,Y);
|
||||
default: return PADiffusionApply3D(NE,symm,B,G,Bt,Gt,D,X,Y,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel: 0x"<<std::hex << id << std::dec);
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_OCCA
|
||||
void OccaPADiffusionApply2D(const int D1D,
|
||||
const int Q1D,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#ifndef MFEM_BILININTEG_DIFFUSION_KERNELS_HPP
|
||||
#define MFEM_BILININTEG_DIFFUSION_KERNELS_HPP
|
||||
|
||||
#include "../kernel_dispatch.hpp"
|
||||
#include "../../config/config.hpp"
|
||||
#include "../../general/array.hpp"
|
||||
#include "../../general/forall.hpp"
|
||||
@@ -36,7 +37,7 @@ void PADiffusionSetup(const int dim,
|
||||
const Vector &C,
|
||||
Vector &D);
|
||||
|
||||
// PA Diffusion Assemble 2D kernel
|
||||
// PA Diffusion Assemble 2D f
|
||||
template<int T_SDIM>
|
||||
void PADiffusionSetup2D(const int Q1D,
|
||||
const int coeffDim,
|
||||
@@ -151,8 +152,23 @@ inline void PADiffusionDiagonal2D(const int NE,
|
||||
});
|
||||
}
|
||||
|
||||
namespace diffusion
|
||||
{
|
||||
constexpr int ipow(int x, int p) { return p == 0 ? 1 : x*ipow(x, p-1); }
|
||||
constexpr int D11(int x) { return (11 - x)/2; }
|
||||
constexpr int D10(int x) { return (10 - x)/2; }
|
||||
constexpr int NBZApply(int D1D)
|
||||
{
|
||||
return ipow(2, D11(D1D) >= 0 ? D11(D1D) : 0);
|
||||
}
|
||||
constexpr int NBZDiagonal(int D1D)
|
||||
{
|
||||
return ipow(2, D10(D1D) >= 0 ? D10(D1D) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Shared memory PA Diffusion Diagonal 2D kernel
|
||||
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
|
||||
template<int T_D1D = 0, int T_Q1D = 0>
|
||||
inline void SmemPADiffusionDiagonal2D(const int NE,
|
||||
const bool symmetric,
|
||||
const Array<real_t> &b_,
|
||||
@@ -162,9 +178,10 @@ inline void SmemPADiffusionDiagonal2D(const int NE,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
static constexpr int T_NBZ = diffusion::NBZDiagonal(T_D1D);
|
||||
static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
@@ -178,7 +195,6 @@ inline void SmemPADiffusionDiagonal2D(const int NE,
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
MFEM_SHARED real_t BG[2][MQ1*MD1];
|
||||
@@ -628,20 +644,23 @@ inline void PADiffusionApply2D(const int NE,
|
||||
}
|
||||
|
||||
// Shared memory PA Diffusion Apply 2D kernel
|
||||
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
|
||||
template<int T_D1D = 0, int T_Q1D = 0>
|
||||
inline void SmemPADiffusionApply2D(const int NE,
|
||||
const bool symmetric,
|
||||
const Array<real_t> &b_,
|
||||
const Array<real_t> &g_,
|
||||
const Array<real_t> &bt_,
|
||||
const Array<real_t> >_,
|
||||
const Vector &d_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
static constexpr int T_NBZ = diffusion::NBZApply(T_D1D);
|
||||
static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
@@ -656,7 +675,6 @@ inline void SmemPADiffusionApply2D(const int NE,
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
MFEM_SHARED real_t sBG[2][MQ1*MD1];
|
||||
@@ -984,6 +1002,8 @@ inline void SmemPADiffusionApply3D(const int NE,
|
||||
const bool symmetric,
|
||||
const Array<real_t> &b_,
|
||||
const Array<real_t> &g_,
|
||||
const Array<real_t> &,
|
||||
const Array<real_t> &,
|
||||
const Vector &d_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
@@ -1203,6 +1223,44 @@ inline void SmemPADiffusionApply3D(const int NE,
|
||||
|
||||
} // namespace internal
|
||||
|
||||
namespace
|
||||
{
|
||||
using ApplyKernelType = DiffusionIntegrator::ApplyKernelType;
|
||||
using DiagonalKernelType = DiffusionIntegrator::DiagonalKernelType;
|
||||
}
|
||||
|
||||
template<int DIM, int T_D1D, int T_Q1D>
|
||||
ApplyKernelType DiffusionIntegrator::ApplyPAKernels::Kernel()
|
||||
{
|
||||
if (DIM == 2) { return internal::SmemPADiffusionApply2D<T_D1D,T_Q1D>; }
|
||||
else if (DIM == 3) { return internal::SmemPADiffusionApply3D<T_D1D, T_Q1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
inline
|
||||
ApplyKernelType DiffusionIntegrator::ApplyPAKernels::Fallback(int DIM, int, int)
|
||||
{
|
||||
if (DIM == 2) { return internal::PADiffusionApply2D; }
|
||||
else if (DIM == 3) { return internal::PADiffusionApply3D; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
template<int DIM, int D1D, int Q1D>
|
||||
DiagonalKernelType DiffusionIntegrator::DiagonalPAKernels::Kernel()
|
||||
{
|
||||
if (DIM == 2) { return internal::SmemPADiffusionDiagonal2D<D1D,Q1D>; }
|
||||
else if (DIM == 3) { return internal::SmemPADiffusionDiagonal3D<D1D, Q1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
inline DiagonalKernelType
|
||||
DiffusionIntegrator::DiagonalPAKernels::Fallback(int DIM, int, int)
|
||||
{
|
||||
if (DIM == 2) { return internal::PADiffusionDiagonal2D; }
|
||||
else if (DIM == 3) { return internal::PADiffusionDiagonal3D; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,73 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
void DiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
|
||||
{
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
ceedOp->GetDiagonal(diag);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pa_data.Size() == 0) { AssemblePA(*fespace); }
|
||||
const Array<real_t> &B = maps->B;
|
||||
const Array<real_t> &G = maps->G;
|
||||
const Vector &Dv = pa_data;
|
||||
DiagonalPAKernels::Run(dim, dofs1D, quad1D, ne, symmetric, B, G, Dv,
|
||||
diag, dofs1D, quad1D);
|
||||
}
|
||||
}
|
||||
|
||||
// PA Diffusion Apply kernel
|
||||
void DiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
|
||||
{
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
ceedOp->AddMult(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
const Array<real_t> &B = maps->B;
|
||||
const Array<real_t> &G = maps->G;
|
||||
const Array<real_t> &Bt = maps->Bt;
|
||||
const Array<real_t> &Gt = maps->Gt;
|
||||
const Vector &Dv = pa_data;
|
||||
|
||||
#ifdef MFEM_USE_OCCA
|
||||
if (DeviceCanUseOcca())
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
OccaPADiffusionApply2D(dofs1D,quad1D,ne,B,G,Bt,Gt,Dv,x,y);
|
||||
return;
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
OccaPADiffusionApply3D(dofs1D,quad1D,ne,B,G,Bt,Gt,Dv,x,y);
|
||||
return;
|
||||
}
|
||||
MFEM_ABORT("OCCA PADiffusionApply unknown kernel!");
|
||||
}
|
||||
#endif // MFEM_USE_OCCA
|
||||
|
||||
ApplyPAKernels::Run(dim, dofs1D, quad1D, ne, symmetric, B, G, Bt,
|
||||
Gt, Dv, x, y, dofs1D, quad1D);
|
||||
}
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const
|
||||
{
|
||||
if (symmetric)
|
||||
{
|
||||
AddMultPA(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("DiffusionIntegrator::AddMultTransposePA only implemented in "
|
||||
"the symmetric case.")
|
||||
}
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
|
||||
@@ -98,47 +165,6 @@ void DiffusionIntegrator::AssemblePatchPA(const int patch,
|
||||
SetupPatchPA(patch, mesh); // For full quadrature, unitWeights = false
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
|
||||
{
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
ceedOp->GetDiagonal(diag);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pa_data.Size()==0) { AssemblePA(*fespace); }
|
||||
internal::PADiffusionAssembleDiagonal(dim, dofs1D, quad1D, ne, symmetric,
|
||||
maps->B, maps->G, pa_data, diag);
|
||||
}
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
|
||||
{
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
ceedOp->AddMult(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
internal::PADiffusionApply(dim, dofs1D, quad1D, ne, symmetric,
|
||||
maps->B, maps->G, maps->Bt, maps->Gt,
|
||||
pa_data, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const
|
||||
{
|
||||
if (symmetric)
|
||||
{
|
||||
AddMultPA(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("DiffusionIntegrator::AddMultTransposePA only implemented in "
|
||||
"the symmetric case.")
|
||||
}
|
||||
}
|
||||
|
||||
// This version uses full 1D quadrature rules, taking into account the
|
||||
// minimum interaction between basis functions and integration points.
|
||||
void DiffusionIntegrator::AddMultPatchPA(const int patch, const Vector &x,
|
||||
|
||||
@@ -14,78 +14,34 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MassIntegrator::Kernels MassIntegrator::kernels;
|
||||
MassIntegrator::Kernels::Kernels()
|
||||
{
|
||||
// 2D
|
||||
MassIntegrator::AddSpecialization<2,2,2>();
|
||||
MassIntegrator::AddSpecialization<2,3,3>();
|
||||
MassIntegrator::AddSpecialization<2,4,4>();
|
||||
MassIntegrator::AddSpecialization<2,5,5>();
|
||||
MassIntegrator::AddSpecialization<2,6,6>();
|
||||
MassIntegrator::AddSpecialization<2,7,7>();
|
||||
MassIntegrator::AddSpecialization<2,8,8>();
|
||||
MassIntegrator::AddSpecialization<2,9,9>();
|
||||
// 3D
|
||||
MassIntegrator::AddSpecialization<3,2,2>();
|
||||
MassIntegrator::AddSpecialization<3,2,3>();
|
||||
MassIntegrator::AddSpecialization<3,3,4>();
|
||||
MassIntegrator::AddSpecialization<3,4,5>();
|
||||
MassIntegrator::AddSpecialization<3,4,6>();
|
||||
MassIntegrator::AddSpecialization<3,5,6>();
|
||||
MassIntegrator::AddSpecialization<3,5,8>();
|
||||
MassIntegrator::AddSpecialization<3,6,7>();
|
||||
MassIntegrator::AddSpecialization<3,7,8>();
|
||||
MassIntegrator::AddSpecialization<3,8,9>();
|
||||
}
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
// PA Mass Diagonal 1D kernel
|
||||
static void PAMassAssembleDiagonal1D(const int NE,
|
||||
const Array<real_t> &b,
|
||||
const Vector &d,
|
||||
Vector &y,
|
||||
const int D1D,
|
||||
const int Q1D)
|
||||
{
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto D = Reshape(d.Read(), Q1D, NE);
|
||||
auto Y = Reshape(y.ReadWrite(), D1D, NE);
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
Y(dx, e) += B(qx, dx) * B(qx, dx) * D(qx, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PAMassAssembleDiagonal(const int dim, const int D1D,
|
||||
const int Q1D, const int NE,
|
||||
const Array<real_t> &B,
|
||||
const Vector &D,
|
||||
Vector &Y)
|
||||
{
|
||||
if (dim == 1)
|
||||
{
|
||||
return PAMassAssembleDiagonal1D(NE,B,D,Y,D1D,Q1D);
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
switch ((D1D << 4 ) | Q1D)
|
||||
{
|
||||
case 0x22: return SmemPAMassAssembleDiagonal2D<2,2,16>(NE,B,D,Y);
|
||||
case 0x33: return SmemPAMassAssembleDiagonal2D<3,3,16>(NE,B,D,Y);
|
||||
case 0x44: return SmemPAMassAssembleDiagonal2D<4,4,8>(NE,B,D,Y);
|
||||
case 0x55: return SmemPAMassAssembleDiagonal2D<5,5,8>(NE,B,D,Y);
|
||||
case 0x66: return SmemPAMassAssembleDiagonal2D<6,6,4>(NE,B,D,Y);
|
||||
case 0x77: return SmemPAMassAssembleDiagonal2D<7,7,4>(NE,B,D,Y);
|
||||
case 0x88: return SmemPAMassAssembleDiagonal2D<8,8,2>(NE,B,D,Y);
|
||||
case 0x99: return SmemPAMassAssembleDiagonal2D<9,9,2>(NE,B,D,Y);
|
||||
default: return PAMassAssembleDiagonal2D(NE,B,D,Y,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch ((D1D << 4 ) | Q1D)
|
||||
{
|
||||
case 0x23: return SmemPAMassAssembleDiagonal3D<2,3>(NE,B,D,Y);
|
||||
case 0x24: return SmemPAMassAssembleDiagonal3D<2,4>(NE,B,D,Y);
|
||||
case 0x26: return SmemPAMassAssembleDiagonal3D<2,6>(NE,B,D,Y);
|
||||
case 0x34: return SmemPAMassAssembleDiagonal3D<3,4>(NE,B,D,Y);
|
||||
case 0x35: return SmemPAMassAssembleDiagonal3D<3,5>(NE,B,D,Y);
|
||||
case 0x45: return SmemPAMassAssembleDiagonal3D<4,5>(NE,B,D,Y);
|
||||
case 0x48: return SmemPAMassAssembleDiagonal3D<4,8>(NE,B,D,Y);
|
||||
case 0x56: return SmemPAMassAssembleDiagonal3D<5,6>(NE,B,D,Y);
|
||||
case 0x67: return SmemPAMassAssembleDiagonal3D<6,7>(NE,B,D,Y);
|
||||
case 0x78: return SmemPAMassAssembleDiagonal3D<7,8>(NE,B,D,Y);
|
||||
case 0x89: return SmemPAMassAssembleDiagonal3D<8,9>(NE,B,D,Y);
|
||||
default: return PAMassAssembleDiagonal3D(NE,B,D,Y,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_OCCA
|
||||
void OccaPAMassApply2D(const int D1D,
|
||||
const int Q1D,
|
||||
@@ -176,154 +132,6 @@ void OccaPAMassApply3D(const int D1D,
|
||||
}
|
||||
#endif // MFEM_USE_OCCA
|
||||
|
||||
MFEM_HOST_DEVICE inline
|
||||
void PAMassApply1D_Element(const int e,
|
||||
const int NE,
|
||||
const real_t *b_,
|
||||
const real_t *bt_,
|
||||
const real_t *d_,
|
||||
const real_t *x_,
|
||||
real_t *y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = d1d;
|
||||
const int Q1D = q1d;
|
||||
auto B = ConstDeviceMatrix(b_, Q1D, D1D);
|
||||
auto Bt = ConstDeviceMatrix(bt_, D1D, Q1D);
|
||||
auto D = ConstDeviceMatrix(d_, Q1D, NE);
|
||||
auto X = ConstDeviceMatrix(x_, D1D, NE);
|
||||
auto Y = DeviceMatrix(y_, D1D, NE);
|
||||
|
||||
real_t XQ[DofQuadLimits::MAX_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
XQ[qx] = 0.0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const real_t s = X(dx,e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
XQ[qx] += B(qx,dx)*s;
|
||||
}
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const real_t q = XQ[qx]*D(qx,e);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
Y(dx,e) += Bt(dx,qx) * q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PA Mass Apply 1D kernel
|
||||
static void PAMassApply1D(const int NE,
|
||||
const Array<real_t> &b_,
|
||||
const Array<real_t> &bt_,
|
||||
const Vector &d_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
|
||||
const auto B = b_.Read();
|
||||
const auto Bt = bt_.Read();
|
||||
const auto D = d_.Read();
|
||||
const auto X = x_.Read();
|
||||
auto Y = y_.ReadWrite();
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
internal::PAMassApply1D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
|
||||
});
|
||||
}
|
||||
|
||||
void PAMassApply(const int dim,
|
||||
const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const Array<real_t> &B,
|
||||
const Array<real_t> &Bt,
|
||||
const Vector &D,
|
||||
const Vector &X,
|
||||
Vector &Y)
|
||||
{
|
||||
#ifdef MFEM_USE_OCCA
|
||||
if (DeviceCanUseOcca())
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
return OccaPAMassApply2D(D1D,Q1D,NE,B,Bt,D,X,Y);
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
return OccaPAMassApply3D(D1D,Q1D,NE,B,Bt,D,X,Y);
|
||||
}
|
||||
MFEM_ABORT("OCCA PA Mass Apply unknown kernel!");
|
||||
}
|
||||
#endif // MFEM_USE_OCCA
|
||||
const int id = (D1D << 4) | Q1D;
|
||||
|
||||
if (dim == 1)
|
||||
{
|
||||
return PAMassApply1D(NE,B,Bt,D,X,Y,D1D,Q1D);
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x22: return SmemPAMassApply2D<2,2,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x24: return SmemPAMassApply2D<2,4,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x33: return SmemPAMassApply2D<3,3,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x34: return SmemPAMassApply2D<3,4,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x35: return SmemPAMassApply2D<3,5,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x36: return SmemPAMassApply2D<3,6,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x44: return SmemPAMassApply2D<4,4,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x46: return SmemPAMassApply2D<4,6,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x48: return SmemPAMassApply2D<4,8,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x55: return SmemPAMassApply2D<5,5,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x57: return SmemPAMassApply2D<5,7,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x58: return SmemPAMassApply2D<5,8,2>(NE,B,Bt,D,X,Y);
|
||||
case 0x66: return SmemPAMassApply2D<6,6,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x77: return SmemPAMassApply2D<7,7,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x88: return SmemPAMassApply2D<8,8,2>(NE,B,Bt,D,X,Y);
|
||||
case 0x99: return SmemPAMassApply2D<9,9,2>(NE,B,Bt,D,X,Y);
|
||||
default: return PAMassApply2D(NE,B,Bt,D,X,Y,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x22: return SmemPAMassApply3D<2,2>(NE,B,Bt,D,X,Y);
|
||||
case 0x23: return SmemPAMassApply3D<2,3>(NE,B,Bt,D,X,Y);
|
||||
case 0x24: return SmemPAMassApply3D<2,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x26: return SmemPAMassApply3D<2,6>(NE,B,Bt,D,X,Y);
|
||||
case 0x34: return SmemPAMassApply3D<3,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x35: return SmemPAMassApply3D<3,5>(NE,B,Bt,D,X,Y);
|
||||
case 0x36: return SmemPAMassApply3D<3,6>(NE,B,Bt,D,X,Y);
|
||||
case 0x37: return SmemPAMassApply3D<3,7>(NE,B,Bt,D,X,Y);
|
||||
case 0x45: return SmemPAMassApply3D<4,5>(NE,B,Bt,D,X,Y);
|
||||
case 0x46: return SmemPAMassApply3D<4,6>(NE,B,Bt,D,X,Y);
|
||||
case 0x48: return SmemPAMassApply3D<4,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x56: return SmemPAMassApply3D<5,6>(NE,B,Bt,D,X,Y);
|
||||
case 0x58: return SmemPAMassApply3D<5,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x67: return SmemPAMassApply3D<6,7>(NE,B,Bt,D,X,Y);
|
||||
case 0x78: return SmemPAMassApply3D<7,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x89: return SmemPAMassApply3D<8,9>(NE,B,Bt,D,X,Y);
|
||||
case 0x9A: return SmemPAMassApply3D<9,10>(NE,B,Bt,D,X,Y);
|
||||
default: return PAMassApply3D(NE,B,Bt,D,X,Y,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -25,11 +25,95 @@ namespace mfem
|
||||
namespace internal
|
||||
{
|
||||
|
||||
void PAMassAssembleDiagonal(const int dim, const int D1D,
|
||||
const int Q1D, const int NE,
|
||||
const Array<real_t> &B,
|
||||
const Vector &D,
|
||||
Vector &Y);
|
||||
// PA Mass Diagonal 1D kernel
|
||||
static void PAMassAssembleDiagonal1D(const int NE,
|
||||
const Array<real_t> &b,
|
||||
const Vector &d,
|
||||
Vector &y,
|
||||
const int D1D,
|
||||
const int Q1D)
|
||||
{
|
||||
auto B = Reshape(b.Read(), Q1D, D1D);
|
||||
auto D = Reshape(d.Read(), Q1D, NE);
|
||||
auto Y = Reshape(y.ReadWrite(), D1D, NE);
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
Y(dx, e) += B(qx, dx) * B(qx, dx) * D(qx, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
MFEM_HOST_DEVICE inline
|
||||
void PAMassApply1D_Element(const int e,
|
||||
const int NE,
|
||||
const real_t *b_,
|
||||
const real_t *bt_,
|
||||
const real_t *d_,
|
||||
const real_t *x_,
|
||||
real_t *y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = d1d;
|
||||
const int Q1D = q1d;
|
||||
auto B = ConstDeviceMatrix(b_, Q1D, D1D);
|
||||
auto Bt = ConstDeviceMatrix(bt_, D1D, Q1D);
|
||||
auto D = ConstDeviceMatrix(d_, Q1D, NE);
|
||||
auto X = ConstDeviceMatrix(x_, D1D, NE);
|
||||
auto Y = DeviceMatrix(y_, D1D, NE);
|
||||
|
||||
real_t XQ[DofQuadLimits::MAX_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
XQ[qx] = 0.0;
|
||||
}
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const real_t s = X(dx,e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
XQ[qx] += B(qx,dx)*s;
|
||||
}
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double q = XQ[qx]*D(qx,e);
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
Y(dx,e) += Bt(dx,qx) * q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PA Mass Apply 1D kernel
|
||||
static void PAMassApply1D(const int NE,
|
||||
const Array<real_t> &b_,
|
||||
const Array<real_t> &bt_,
|
||||
const Vector &d_,
|
||||
const Vector &x_,
|
||||
Vector &y_,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
|
||||
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
|
||||
|
||||
const auto B = b_.Read();
|
||||
const auto Bt = bt_.Read();
|
||||
const auto D = d_.Read();
|
||||
const auto X = x_.Read();
|
||||
auto Y = y_.ReadWrite();
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
internal::PAMassApply1D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
|
||||
});
|
||||
}
|
||||
|
||||
// PA Mass Diagonal 2D kernel
|
||||
template<int T_D1D = 0, int T_Q1D = 0>
|
||||
@@ -78,8 +162,18 @@ inline void PAMassAssembleDiagonal2D(const int NE,
|
||||
});
|
||||
}
|
||||
|
||||
namespace mass
|
||||
{
|
||||
constexpr int ipow(int x, int p) { return p == 0 ? 1 : x*ipow(x, p-1); }
|
||||
constexpr int D(int D1D) { return (11 - D1D) / 2; }
|
||||
constexpr int NBZ(int D1D)
|
||||
{
|
||||
return ipow(2, D(D1D) >= 0 ? D(D1D) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Shared memory PA Mass Diagonal 2D kernel
|
||||
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
|
||||
template<int T_D1D = 0, int T_Q1D = 0>
|
||||
inline void SmemPAMassAssembleDiagonal2D(const int NE,
|
||||
const Array<real_t> &b_,
|
||||
const Vector &d_,
|
||||
@@ -87,9 +181,10 @@ inline void SmemPAMassAssembleDiagonal2D(const int NE,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
static constexpr int T_NBZ = mass::NBZ(T_D1D);
|
||||
static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
@@ -102,7 +197,6 @@ inline void SmemPAMassAssembleDiagonal2D(const int NE,
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
MFEM_SHARED real_t B[MQ1][MD1];
|
||||
@@ -302,16 +396,6 @@ inline void SmemPAMassAssembleDiagonal3D(const int NE,
|
||||
});
|
||||
}
|
||||
|
||||
void PAMassApply(const int dim,
|
||||
const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const Array<real_t> &B,
|
||||
const Array<real_t> &Bt,
|
||||
const Vector &D,
|
||||
const Vector &X,
|
||||
Vector &Y);
|
||||
|
||||
#ifdef MFEM_USE_OCCA
|
||||
// OCCA PA Mass Apply 2D kernel
|
||||
void OccaPAMassApply2D(const int D1D,
|
||||
@@ -964,7 +1048,7 @@ inline void PAMassApply2D(const int NE,
|
||||
}
|
||||
|
||||
// Shared memory PA Mass Apply 2D kernel
|
||||
template<int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
|
||||
template<int T_D1D = 0, int T_Q1D = 0>
|
||||
inline void SmemPAMassApply2D(const int NE,
|
||||
const Array<real_t> &b_,
|
||||
const Array<real_t> &bt_,
|
||||
@@ -975,9 +1059,10 @@ inline void SmemPAMassApply2D(const int NE,
|
||||
const int q1d = 0)
|
||||
{
|
||||
MFEM_CONTRACT_VAR(bt_);
|
||||
static constexpr int T_NBZ = mass::NBZ(T_D1D);
|
||||
static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int max_q1d = T_Q1D ? T_Q1D : DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
const int max_d1d = T_D1D ? T_D1D : DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
MFEM_VERIFY(D1D <= max_d1d, "");
|
||||
@@ -988,8 +1073,8 @@ inline void SmemPAMassApply2D(const int NE,
|
||||
auto Y = y_.ReadWrite();
|
||||
mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
internal::SmemPAMassApply2D_Element<T_D1D,T_Q1D,T_NBZ>(e, NE, b, D, x, Y, d1d,
|
||||
q1d);
|
||||
internal::SmemPAMassApply2D_Element<T_D1D,T_Q1D,T_NBZ>(
|
||||
e, NE, b, D, x, Y, d1d, q1d);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1049,6 +1134,48 @@ inline void SmemPAMassApply3D(const int NE,
|
||||
|
||||
} // namespace internal
|
||||
|
||||
namespace
|
||||
{
|
||||
using ApplyKernelType = MassIntegrator::ApplyKernelType;
|
||||
using DiagonalKernelType = MassIntegrator::DiagonalKernelType;
|
||||
}
|
||||
|
||||
template<int DIM, int T_D1D, int T_Q1D>
|
||||
ApplyKernelType MassIntegrator::ApplyPAKernels::Kernel()
|
||||
{
|
||||
if (DIM == 1) { return internal::PAMassApply1D; }
|
||||
else if (DIM == 2) { return internal::SmemPAMassApply2D<T_D1D,T_Q1D>; }
|
||||
else if (DIM == 3) { return internal::SmemPAMassApply3D<T_D1D, T_Q1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
inline ApplyKernelType MassIntegrator::ApplyPAKernels::Fallback(
|
||||
int DIM, int, int)
|
||||
{
|
||||
if (DIM == 1) { return internal::PAMassApply1D; }
|
||||
else if (DIM == 2) { return internal::PAMassApply2D; }
|
||||
else if (DIM == 3) { return internal::PAMassApply3D; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
template<int DIM, int T_D1D, int T_Q1D>
|
||||
DiagonalKernelType MassIntegrator::DiagonalPAKernels::Kernel()
|
||||
{
|
||||
if (DIM == 1) { return internal::PAMassAssembleDiagonal1D; }
|
||||
else if (DIM == 2) { return internal::SmemPAMassAssembleDiagonal2D<T_D1D,T_Q1D>; }
|
||||
else if (DIM == 3) { return internal::SmemPAMassAssembleDiagonal3D<T_D1D, T_Q1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
inline DiagonalKernelType MassIntegrator::DiagonalPAKernels::Fallback(
|
||||
int DIM, int, int)
|
||||
{
|
||||
if (DIM == 1) { return internal::PAMassAssembleDiagonal1D; }
|
||||
else if (DIM == 2) { return internal::PAMassAssembleDiagonal2D; }
|
||||
else if (DIM == 3) { return internal::PAMassAssembleDiagonal3D; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// PA Mass Integrator
|
||||
|
||||
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
|
||||
@@ -195,8 +197,8 @@ void MassIntegrator::AssembleDiagonalPA(Vector &diag)
|
||||
}
|
||||
else
|
||||
{
|
||||
internal::PAMassAssembleDiagonal(dim, dofs1D, quad1D, ne, maps->B, pa_data,
|
||||
diag);
|
||||
DiagonalPAKernels::Run(dim, dofs1D, quad1D, ne, maps->B, pa_data,
|
||||
diag, dofs1D, quad1D);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,8 +210,26 @@ void MassIntegrator::AddMultPA(const Vector &x, Vector &y) const
|
||||
}
|
||||
else
|
||||
{
|
||||
internal::PAMassApply(dim, dofs1D, quad1D, ne, maps->B, maps->Bt, pa_data, x,
|
||||
y);
|
||||
const int D1D = dofs1D;
|
||||
const int Q1D = quad1D;
|
||||
const Array<real_t> &B = maps->B;
|
||||
const Array<real_t> &Bt = maps->Bt;
|
||||
const Vector &D = pa_data;
|
||||
#ifdef MFEM_USE_OCCA
|
||||
if (DeviceCanUseOcca())
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
return OccaPAMassApply2D(D1D,Q1D,ne,B,Bt,D,x,y);
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
return OccaPAMassApply3D(D1D,Q1D,ne,B,Bt,D,x,y);
|
||||
}
|
||||
MFEM_ABORT("OCCA PA Mass Apply unknown kernel!");
|
||||
}
|
||||
#endif // MFEM_USE_OCCA
|
||||
ApplyPAKernels::Run(dim, D1D, Q1D, ne, B, Bt, D, x, y, D1D, Q1D);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+44
-44
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
// 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_KERNEL_DISPATCH_HPP
|
||||
#define MFEM_KERNEL_DISPATCH_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "kernel_reporter.hpp"
|
||||
#include <unordered_map>
|
||||
#include <tuple>
|
||||
#include <cstddef>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// The MFEM_REGISTER_KERNELS macro registers kernels for runtime dispatch using
|
||||
// a dispatch map.
|
||||
//
|
||||
// This creates a dispatch table (a static member variable) named @a KernelName
|
||||
// containing function points of type @a KernelType. These are followed by one
|
||||
// or two sets of parenthesized argument types.
|
||||
//
|
||||
// The first set of argument types contains the types that are used to dispatch
|
||||
// to either specialized or fallback kernels. The second set of argument types
|
||||
// can be used to further specialize the kernel without participating in
|
||||
// dispatch (a canonical example is NBZ, determining the size of the thread
|
||||
// blocks; this is required to specialize kernels for optimal performance, but
|
||||
// is not relevant for dispatch).
|
||||
//
|
||||
// After calling this macro, the user must implement the Kernel and Fallback
|
||||
// static member functions, which return pointers to the appropriate kernel
|
||||
// functions depending on the parameters.
|
||||
//
|
||||
// Specialized functions can be registered using the static AddSpecialization
|
||||
// member function.
|
||||
|
||||
#define MFEM_EXPAND(X) X // Workaround needed for MSVC compiler
|
||||
|
||||
#define MFEM_REGISTER_KERNELS(KernelName, KernelType, ...) \
|
||||
MFEM_EXPAND(MFEM_EXPAND(MFEM_REGISTER_KERNELS_N(__VA_ARGS__,2,1,)) \
|
||||
(KernelName,KernelType,__VA_ARGS__))
|
||||
|
||||
#define MFEM_REGISTER_KERNELS_N(_1, _2, N, ...) MFEM_REGISTER_KERNELS_##N
|
||||
|
||||
// Expands a variable length macro parameter so that multiple variable length
|
||||
// parameters can be passed to the same macro.
|
||||
#define MFEM_PARAM_LIST(...) __VA_ARGS__
|
||||
|
||||
// Version of MFEM_REGISTER_KERNELS without any "optional" (non-dispatch)
|
||||
// parameters.
|
||||
#define MFEM_REGISTER_KERNELS_1(KernelName, KernelType, Params) \
|
||||
MFEM_REGISTER_KERNELS_(KernelName, KernelType, Params, (), Params)
|
||||
|
||||
// Version of MFEM_REGISTER_KERNELS without any optional (non-dispatch)
|
||||
// parameters (e.g. NBZ).
|
||||
#define MFEM_REGISTER_KERNELS_2(KernelName, KernelType, Params, OptParams) \
|
||||
MFEM_REGISTER_KERNELS_(KernelName, KernelType, Params, OptParams, \
|
||||
(MFEM_PARAM_LIST Params, MFEM_PARAM_LIST OptParams))
|
||||
|
||||
// P1 are the parameters, P2 are the optional (non-dispatch parameters), and P3
|
||||
// is the concatenation of P1 and P2. We need to pass it as a separate argument
|
||||
// to avoid a trailing comma in the case that P2 is empty.
|
||||
#define MFEM_REGISTER_KERNELS_(KernelName, KernelType, P1, P2, P3) \
|
||||
class KernelName : public \
|
||||
KernelDispatchTable<KernelName, KernelType, \
|
||||
internal::KernelTypeList<MFEM_PARAM_LIST P1>, \
|
||||
internal::KernelTypeList<MFEM_PARAM_LIST P2>> \
|
||||
{ \
|
||||
public: \
|
||||
const char *kernel_name = MFEM_KERNEL_NAME(KernelName); \
|
||||
using KernelSignature = KernelType; \
|
||||
template <MFEM_PARAM_LIST P3> \
|
||||
static KernelSignature Kernel(); \
|
||||
static KernelSignature Fallback(MFEM_PARAM_LIST P1); \
|
||||
static KernelName &Get() \
|
||||
{ static KernelName table; return table;} \
|
||||
}
|
||||
|
||||
/// @brief Hashes variadic packs for which each type contained in the variadic
|
||||
/// pack has a specialization of `std::hash` available.
|
||||
///
|
||||
/// For example, packs containing int, bool, enum values, etc.
|
||||
template<typename ...KernelParameters>
|
||||
struct KernelDispatchKeyHash
|
||||
{
|
||||
private:
|
||||
template<int N>
|
||||
size_t operator()(std::tuple<KernelParameters...> value) const { return 0; }
|
||||
|
||||
// The hashing formula here is taken directly from the Boost library, with
|
||||
// the magic number 0x9e3779b9 chosen to minimize hashing collisions.
|
||||
template<std::size_t N, typename THead, typename... TTail>
|
||||
size_t operator()(std::tuple<KernelParameters...> value) const
|
||||
{
|
||||
constexpr int Index = N - sizeof...(TTail) - 1;
|
||||
auto lhs_hash = std::hash<THead>()(std::get<Index>(value));
|
||||
auto rhs_hash = operator()<N, TTail...>(value);
|
||||
return lhs_hash^(rhs_hash + 0x9e3779b9 + (lhs_hash<<6) + (lhs_hash>>2));
|
||||
}
|
||||
public:
|
||||
/// Returns the hash of the given @a value.
|
||||
size_t operator()(std::tuple<KernelParameters...> value) const
|
||||
{
|
||||
return operator()<sizeof...(KernelParameters),KernelParameters...>(value);
|
||||
}
|
||||
};
|
||||
|
||||
namespace internal { template<typename... Types> struct KernelTypeList { }; }
|
||||
|
||||
template<typename... T> class KernelDispatchTable { };
|
||||
|
||||
template <typename Kernels,
|
||||
typename Signature,
|
||||
typename... Params,
|
||||
typename... OptParams>
|
||||
class KernelDispatchTable<Kernels,
|
||||
Signature,
|
||||
internal::KernelTypeList<Params...>,
|
||||
internal::KernelTypeList<OptParams...>>
|
||||
{
|
||||
std::unordered_map<std::tuple<Params...>,
|
||||
Signature,
|
||||
KernelDispatchKeyHash<Params...>> table;
|
||||
|
||||
public:
|
||||
/// @brief Run the kernel with the given dispatch parameters and arguments.
|
||||
///
|
||||
/// If a compile-time specialized version of the kernel with the given
|
||||
/// parameters has been registered, it will be called. Otherwise, the
|
||||
/// fallback kernel will be called.
|
||||
template<typename... Args>
|
||||
static void Run(Params... params, Args&&... args)
|
||||
{
|
||||
const auto &table = Kernels::Get().table;
|
||||
const std::tuple<Params...> key = std::make_tuple(params...);
|
||||
const auto it = table.find(key);
|
||||
if (it != table.end())
|
||||
{
|
||||
it->second(std::forward<Args>(args)...);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReportFallback(Kernels::Get().kernel_name, params...);
|
||||
Kernels::Fallback(params...)(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a specialized kernel for dispatch.
|
||||
template <Params... PARAMS>
|
||||
struct Specialization
|
||||
{
|
||||
// Version without optional parameters
|
||||
static void Add()
|
||||
{
|
||||
std::tuple<Params...> param_tuple(PARAMS...);
|
||||
Kernels::Get().table[param_tuple] =
|
||||
Kernels:: template Kernel<PARAMS...>();
|
||||
};
|
||||
// Version with optional parameters
|
||||
template <OptParams... OPT_PARAMS>
|
||||
struct Opt
|
||||
{
|
||||
static void Add()
|
||||
{
|
||||
std::tuple<Params...> param_tuple(PARAMS...);
|
||||
Kernels::Get().table[param_tuple] =
|
||||
Kernels:: template Kernel<PARAMS..., OPT_PARAMS...>();
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
// 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_KERNEL_REPORTER_HPP
|
||||
#define MFEM_KERNEL_REPORTER_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
|
||||
#ifdef MFEM_REPORT_KERNELS
|
||||
|
||||
#include "../general/globals.hpp"
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#define MFEM_STR_(X) #X
|
||||
#define MFEM_STR(X) MFEM_STR_(X)
|
||||
#define MFEM_KERNEL_NAME(KernelName) \
|
||||
__FILE__ ":" MFEM_STR(__LINE__) " : " #KernelName
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename Last>
|
||||
static void Stringify_(std::ostream &o, Last &&arg)
|
||||
{
|
||||
o << arg;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename... Rest>
|
||||
static void Stringify_(std::ostream &o, T1 &&a1, T2 &&a2, Rest&&... rest)
|
||||
{
|
||||
o << int(a1) << ",";
|
||||
Stringify_(o, a2, rest...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static std::string Stringify(Args&&... args)
|
||||
{
|
||||
std::stringstream o;
|
||||
Stringify_(o, args...);
|
||||
return o.str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename... Params>
|
||||
void ReportFallback(const std::string &kernel_name, Params&&... params)
|
||||
{
|
||||
static std::set<std::string> reported_fallbacks;
|
||||
const std::string requested_kernel =
|
||||
kernel_name + "<" + Stringify(params...) + ">";
|
||||
if (reported_fallbacks.find(requested_kernel) == reported_fallbacks.end())
|
||||
{
|
||||
reported_fallbacks.insert(requested_kernel);
|
||||
mfem::err << "Fallback kernel. Requested "
|
||||
<< requested_kernel << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#else // #ifdef MFEM_REPORT_KERNELS
|
||||
|
||||
// No-op
|
||||
#define MFEM_KERNEL_NAME(KernelName) ""
|
||||
template <typename... T> void ReportFallback(T&&...) { }
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+4
-3
@@ -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;
|
||||
|
||||
+64
-83
@@ -27,12 +27,16 @@ namespace quadrature_interpolator
|
||||
{
|
||||
|
||||
static void Det1D(const int NE,
|
||||
const real_t *b,
|
||||
const real_t *g,
|
||||
const real_t *x,
|
||||
real_t *y,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
const int q1d,
|
||||
Vector *d_buff = nullptr)
|
||||
{
|
||||
MFEM_CONTRACT_VAR(b);
|
||||
MFEM_CONTRACT_VAR(d_buff);
|
||||
const auto G = Reshape(g, q1d, d1d);
|
||||
const auto X = Reshape(x, d1d, NE);
|
||||
|
||||
@@ -59,8 +63,10 @@ static void Det2D(const int NE,
|
||||
const real_t *x,
|
||||
real_t *y,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
const int q1d = 0,
|
||||
Vector *d_buff = nullptr)
|
||||
{
|
||||
MFEM_CONTRACT_VAR(d_buff);
|
||||
static constexpr int SDIM = 2;
|
||||
static constexpr int NBZ = 1;
|
||||
|
||||
@@ -109,8 +115,11 @@ static void Det2DSurface(const int NE,
|
||||
const real_t *x,
|
||||
real_t *y,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
const int q1d = 0,
|
||||
Vector *d_buff = nullptr)
|
||||
{
|
||||
MFEM_CONTRACT_VAR(d_buff);
|
||||
|
||||
static constexpr int SDIM = 3;
|
||||
static constexpr int NBZ = 1;
|
||||
|
||||
@@ -272,91 +281,63 @@ static void Det3D(const int NE,
|
||||
});
|
||||
}
|
||||
|
||||
// Tensor-product evaluation of quadrature point determinants: dispatch
|
||||
// function.
|
||||
void TensorDeterminants(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_det,
|
||||
Vector &d_buff)
|
||||
void InitDetKernels()
|
||||
{
|
||||
if (NE == 0) { return; }
|
||||
const int dim = maps.FE->GetDim();
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const real_t *B = maps.B.Read();
|
||||
const real_t *G = maps.G.Read();
|
||||
const real_t *X = e_vec.Read();
|
||||
real_t *Y = q_det.Write();
|
||||
|
||||
const int id = (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
if (dim == 1)
|
||||
{
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D,
|
||||
"Orders higher than " << DeviceDofQuadLimits::Get().MAX_D1D-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D,
|
||||
"Quadrature rules with more than "
|
||||
<< DeviceDofQuadLimits::Get().MAX_Q1D << " 1D points are not supported!");
|
||||
Det1D(NE, G, X, Y, D1D, Q1D);
|
||||
return;
|
||||
}
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x222: return Det2D<2,2>(NE,B,G,X,Y);
|
||||
case 0x223: return Det2D<2,3>(NE,B,G,X,Y);
|
||||
case 0x224: return Det2D<2,4>(NE,B,G,X,Y);
|
||||
case 0x226: return Det2D<2,6>(NE,B,G,X,Y);
|
||||
case 0x234: return Det2D<3,4>(NE,B,G,X,Y);
|
||||
case 0x236: return Det2D<3,6>(NE,B,G,X,Y);
|
||||
case 0x244: return Det2D<4,4>(NE,B,G,X,Y);
|
||||
case 0x246: return Det2D<4,6>(NE,B,G,X,Y);
|
||||
case 0x256: return Det2D<5,6>(NE,B,G,X,Y);
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
if (vdim == 2) { Det2D(NE,B,G,X,Y,D1D,Q1D); }
|
||||
else if (vdim == 3) { Det2DSurface(NE,B,G,X,Y,D1D,Q1D); }
|
||||
else { MFEM_ABORT("Invalid space dimension."); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x324: return Det3D<2,4>(NE,B,G,X,Y);
|
||||
case 0x333: return Det3D<3,3>(NE,B,G,X,Y);
|
||||
case 0x335: return Det3D<3,5>(NE,B,G,X,Y);
|
||||
case 0x336: return Det3D<3,6>(NE,B,G,X,Y);
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_DET_1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_DET_1D;
|
||||
// Highest orders that fit in shared memory
|
||||
if (D1D <= MD && Q1D <= MQ)
|
||||
{ return Det3D<0,0,true>(NE,B,G,X,Y,D1D,Q1D); }
|
||||
// Last fall-back will use global memory
|
||||
return Det3D<0,0,false>(
|
||||
NE,B,G,X,Y,D1D,Q1D,&d_buff);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Kernel " << std::hex << id << std::dec << " not supported yet");
|
||||
using k = QuadratureInterpolator::DetKernels;
|
||||
// 2D
|
||||
k::Specialization<2,2,2,2>::Add();
|
||||
k::Specialization<2,2,2,3>::Add();
|
||||
k::Specialization<2,2,2,4>::Add();
|
||||
k::Specialization<2,2,2,6>::Add();
|
||||
k::Specialization<2,2,3,4>::Add();
|
||||
k::Specialization<2,2,3,6>::Add();
|
||||
k::Specialization<2,2,4,4>::Add();
|
||||
k::Specialization<2,2,4,6>::Add();
|
||||
k::Specialization<2,2,5,6>::Add();
|
||||
// 3D
|
||||
k::Specialization<3,3,2,4>::Add();
|
||||
k::Specialization<3,3,3,3>::Add();
|
||||
k::Specialization<3,3,3,5>::Add();
|
||||
k::Specialization<3,3,3,6>::Add();
|
||||
}
|
||||
|
||||
} // namespace quadrature_interpolator
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// @cond Suppress_Doxygen_warnings
|
||||
|
||||
namespace
|
||||
{
|
||||
using DetKernel = QuadratureInterpolator::DetKernelType;
|
||||
}
|
||||
|
||||
template<int DIM, int SDIM, int D1D, int Q1D>
|
||||
DetKernel QuadratureInterpolator::DetKernels::Kernel()
|
||||
{
|
||||
if (DIM == 1) { return internal::quadrature_interpolator::Det1D; }
|
||||
else if (DIM == 2 && SDIM == 2) { return internal::quadrature_interpolator::Det2D<D1D, Q1D>; }
|
||||
else if (DIM == 2 && SDIM == 3) { return internal::quadrature_interpolator::Det2DSurface<D1D, Q1D>; }
|
||||
else if (DIM == 3) { return internal::quadrature_interpolator::Det3D<D1D, Q1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
DetKernel QuadratureInterpolator::DetKernels::Fallback(
|
||||
int DIM, int SDIM, int D1D, int Q1D)
|
||||
{
|
||||
if (DIM == 1) { return internal::quadrature_interpolator::Det1D; }
|
||||
else if (DIM == 2 && SDIM == 2) { return internal::quadrature_interpolator::Det2D; }
|
||||
else if (DIM == 2 && SDIM == 3) { return internal::quadrature_interpolator::Det2DSurface; }
|
||||
else if (DIM == 3)
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_DET_1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_DET_1D;
|
||||
if (D1D <= MD && Q1D <= MQ) { return internal::quadrature_interpolator::Det3D<0,0,true>; }
|
||||
else { return internal::quadrature_interpolator::Det3D<0,0,false>; }
|
||||
}
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// Internal header, included only by .cpp files
|
||||
|
||||
#include "../quadinterpolator.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
namespace quadrature_interpolator
|
||||
{
|
||||
|
||||
// Tensor-product evaluation of quadrature point values: dispatch function.
|
||||
template<QVectorLayout VL>
|
||||
void TensorValues(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val);
|
||||
|
||||
// Tensor-product evaluation of quadrature point derivatives: dispatch function.
|
||||
template<QVectorLayout VL>
|
||||
void TensorDerivatives(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_der);
|
||||
|
||||
// Tensor-product evaluation of quadrature point physical derivatives: dispatch
|
||||
// function.
|
||||
template<QVectorLayout VL>
|
||||
void TensorPhysDerivatives(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const GeometricFactors &geom,
|
||||
const Vector &e_vec,
|
||||
Vector &q_der);
|
||||
|
||||
// Tensor-product evaluation of quadrature point determinants: dispatch
|
||||
// function.
|
||||
void TensorDeterminants(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_det,
|
||||
Vector &d_buff);
|
||||
|
||||
} // namespace quadrature_interpolator
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
+21
-1
@@ -12,6 +12,9 @@
|
||||
// Internal header, included only by .cpp files.
|
||||
// Template function implementations.
|
||||
|
||||
#ifndef MFEM_QUADINTERP_EVAL
|
||||
#define MFEM_QUADINTERP_EVAL
|
||||
|
||||
#include "../quadinterpolator.hpp"
|
||||
#include "../../general/forall.hpp"
|
||||
#include "../../linalg/dtensor.hpp"
|
||||
@@ -63,7 +66,7 @@ static void Values1D(const int NE,
|
||||
// Template compute kernel for Values in 2D: tensor product version.
|
||||
template<QVectorLayout Q_LAYOUT,
|
||||
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
|
||||
int T_NBZ = 1, int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
int T_NBZ = 1>
|
||||
static void Values2D(const int NE,
|
||||
const real_t *b_,
|
||||
const real_t *x_,
|
||||
@@ -193,4 +196,21 @@ static void Values3D(const int NE,
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// @cond Suppress_Doxygen_warnings
|
||||
|
||||
template<int DIM, QVectorLayout Q_LAYOUT,
|
||||
int VDIM, int D1D, int Q1D, int NBZ>
|
||||
QuadratureInterpolator::TensorEvalKernelType
|
||||
QuadratureInterpolator::TensorEvalKernels::Kernel()
|
||||
{
|
||||
if (DIM == 1) { return internal::quadrature_interpolator::Values1D<Q_LAYOUT>; }
|
||||
else if (DIM == 2) { return internal::quadrature_interpolator::Values2D<Q_LAYOUT, VDIM, D1D, Q1D, NBZ>; }
|
||||
else if (DIM == 3) { return internal::quadrature_interpolator::Values3D<Q_LAYOUT, VDIM, D1D, Q1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
+47
-115
@@ -10,143 +10,75 @@
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "../quadinterpolator.hpp"
|
||||
#include "dispatch.hpp"
|
||||
#include "eval.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
namespace quadrature_interpolator
|
||||
{
|
||||
|
||||
// Tensor-product evaluation of quadrature point values: dispatch function.
|
||||
// Instantiation for the case QVectorLayout::byNODES.
|
||||
template<>
|
||||
void TensorValues<QVectorLayout::byNODES>(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val)
|
||||
void InitEvalByNodesKernels()
|
||||
{
|
||||
if (NE == 0) { return; }
|
||||
const int dim = maps.FE->GetDim();
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const real_t *B = maps.B.Read();
|
||||
const real_t *X = e_vec.Read();
|
||||
real_t *Y = q_val.Write();
|
||||
using k = QuadratureInterpolator::TensorEvalKernels;
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byNODES;
|
||||
// 2D
|
||||
k::Specialization<2,QVectorLayout::byNODES,1,3,3>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,1,2,4>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,1,3,2>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,1,3,4>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,1,4,3>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,1,4,4>::Opt<1>::Add();
|
||||
|
||||
const int id = (vdim<<8) | (D1D<<4) | Q1D;
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,2,2>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,2,3>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,2,4>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,2,5>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,2,6>::Opt<1>::Add();
|
||||
|
||||
if (dim == 1)
|
||||
{
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D,
|
||||
"Orders higher than " << DeviceDofQuadLimits::Get().MAX_D1D-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D,
|
||||
"Quadrature rules with more than "
|
||||
<< DeviceDofQuadLimits::Get().MAX_Q1D << " 1D points are not supported!");
|
||||
Values1D<L>(NE, B, X, Y, vdim, D1D, Q1D);
|
||||
return;
|
||||
}
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x133: return Values2D<L,1,3,3>(NE,B,X,Y);
|
||||
case 0x124: return Values2D<L,1,2,4>(NE,B,X,Y);
|
||||
case 0x132: return Values2D<L,1,3,2>(NE,B,X,Y);
|
||||
case 0x134: return Values2D<L,1,3,4>(NE,B,X,Y);
|
||||
case 0x143: return Values2D<L,1,4,3>(NE,B,X,Y);
|
||||
case 0x144: return Values2D<L,1,4,4>(NE,B,X,Y);
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,3,3>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,3,4>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,3,6>::Opt<1>::Add();
|
||||
|
||||
case 0x222: return Values2D<L,2,2,2>(NE,B,X,Y);
|
||||
case 0x223: return Values2D<L,2,2,3>(NE,B,X,Y);
|
||||
case 0x224: return Values2D<L,2,2,4>(NE,B,X,Y);
|
||||
case 0x225: return Values2D<L,2,2,5>(NE,B,X,Y);
|
||||
case 0x226: return Values2D<L,2,2,6>(NE,B,X,Y);
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,4,3>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,4,4>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,4,5>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,4,6>::Opt<1>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,4,7>::Opt<1>::Add();
|
||||
|
||||
case 0x233: return Values2D<L,2,3,3>(NE,B,X,Y);
|
||||
case 0x234: return Values2D<L,2,3,4>(NE,B,X,Y);
|
||||
case 0x236: return Values2D<L,2,3,6>(NE,B,X,Y);
|
||||
k::Specialization<2,QVectorLayout::byNODES,2,5,6>::Opt<1>::Add();
|
||||
|
||||
case 0x243: return Values2D<L,2,4,3>(NE,B,X,Y);
|
||||
case 0x244: return Values2D<L,2,4,4>(NE,B,X,Y);
|
||||
case 0x245: return Values2D<L,2,4,5>(NE,B,X,Y);
|
||||
case 0x246: return Values2D<L,2,4,6>(NE,B,X,Y);
|
||||
case 0x247: return Values2D<L,2,4,7>(NE,B,X,Y);
|
||||
// 3D
|
||||
k::Specialization<3,QVectorLayout::byNODES,1,2,4>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,1,3,3>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,1,3,4>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,1,3,6>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,1,4,3>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,1,4,4>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,1,4,8>::Opt<1>::Add();
|
||||
|
||||
case 0x256: return Values2D<L,2,5,6>(NE,B,X,Y);
|
||||
k::Specialization<3,QVectorLayout::byNODES,2,2,2>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,2,2,3>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,2,3,4>::Opt<1>::Add();
|
||||
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
Values2D<L>(NE,B,X,Y,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x124: return Values3D<L,1,2,4>(NE,B,X,Y);
|
||||
case 0x133: return Values3D<L,1,3,3>(NE,B,X,Y);
|
||||
case 0x134: return Values3D<L,1,3,4>(NE,B,X,Y);
|
||||
case 0x136: return Values3D<L,1,3,6>(NE,B,X,Y);
|
||||
case 0x143: return Values3D<L,1,4,3>(NE,B,X,Y);
|
||||
case 0x144: return Values3D<L,1,4,4>(NE,B,X,Y);
|
||||
case 0x148: return Values3D<L,1,4,8>(NE,B,X,Y);
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,2,3>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,2,4>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,2,5>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,2,6>::Opt<1>::Add();
|
||||
|
||||
case 0x222: return Values3D<L,2,2,2>(NE,B,X,Y);
|
||||
case 0x223: return Values3D<L,2,2,3>(NE,B,X,Y);
|
||||
case 0x234: return Values3D<L,2,3,4>(NE,B,X,Y);
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,3,3>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,3,4>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,3,5>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,3,6>::Opt<1>::Add();
|
||||
|
||||
case 0x323: return Values3D<L,3,2,3>(NE,B,X,Y);
|
||||
case 0x324: return Values3D<L,3,2,4>(NE,B,X,Y);
|
||||
case 0x325: return Values3D<L,3,2,5>(NE,B,X,Y);
|
||||
case 0x326: return Values3D<L,3,2,6>(NE,B,X,Y);
|
||||
|
||||
case 0x333: return Values3D<L,3,3,3>(NE,B,X,Y);
|
||||
case 0x334: return Values3D<L,3,3,4>(NE,B,X,Y);
|
||||
case 0x335: return Values3D<L,3,3,5>(NE,B,X,Y);
|
||||
case 0x336: return Values3D<L,3,3,6>(NE,B,X,Y);
|
||||
|
||||
case 0x343: return Values3D<L,3,4,3>(NE,B,X,Y);
|
||||
case 0x344: return Values3D<L,3,4,4>(NE,B,X,Y);
|
||||
case 0x346: return Values3D<L,3,4,6>(NE,B,X,Y);
|
||||
case 0x347: return Values3D<L,3,4,7>(NE,B,X,Y);
|
||||
case 0x348: return Values3D<L,3,4,8>(NE,B,X,Y);
|
||||
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
Values3D<L>(NE,B,X,Y,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,4,3>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,4,4>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,4,6>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,4,7>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,3,4,8>::Opt<1>::Add();
|
||||
}
|
||||
|
||||
} // namespace quadrature_interpolator
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -10,117 +10,45 @@
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "../quadinterpolator.hpp"
|
||||
#include "dispatch.hpp"
|
||||
#include "eval.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
namespace quadrature_interpolator
|
||||
{
|
||||
|
||||
// Tensor-product evaluation of quadrature point values: dispatch function.
|
||||
// Instantiation for the case QVectorLayout::byVDIM.
|
||||
template<>
|
||||
void TensorValues<QVectorLayout::byVDIM>(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val)
|
||||
void InitEvalByVDimKernels()
|
||||
{
|
||||
if (NE == 0) { return; }
|
||||
const int dim = maps.FE->GetDim();
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const real_t *B = maps.B.Read();
|
||||
const real_t *X = e_vec.Read();
|
||||
real_t *Y = q_val.Write();
|
||||
using k = QuadratureInterpolator::TensorEvalKernels;
|
||||
// 2D
|
||||
k::Specialization<2,QVectorLayout::byVDIM,1,2,4>::Opt<8>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,1,3,6>::Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,1,4,8>::Opt<2>::Add();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byVDIM;
|
||||
k::Specialization<2,QVectorLayout::byVDIM,2,2,4>::Opt<8>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,2,3,4>::Opt<8>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,2,3,6>::Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,2,4,8>::Opt<2>::Add();
|
||||
// 3D
|
||||
k::Specialization<3,QVectorLayout::byVDIM,1,2,4>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,1,3,6>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,1,4,8>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,3,2,4>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,3,3,6>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,3,4,8>::Opt<1>::Add();
|
||||
|
||||
const int id = (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
if (dim == 1)
|
||||
{
|
||||
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D,
|
||||
"Orders higher than " << DeviceDofQuadLimits::Get().MAX_D1D-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D,
|
||||
"Quadrature rules with more than "
|
||||
<< DeviceDofQuadLimits::Get().MAX_Q1D << " 1D points are not supported!");
|
||||
Values1D<L>(NE, B, X, Y, vdim, D1D, Q1D);
|
||||
return;
|
||||
}
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x124: return Values2D<L,1,2,4,8>(NE,B,X,Y);
|
||||
case 0x136: return Values2D<L,1,3,6,4>(NE,B,X,Y);
|
||||
case 0x148: return Values2D<L,1,4,8,2>(NE,B,X,Y);
|
||||
|
||||
case 0x224: return Values2D<L,2,2,4,8>(NE,B,X,Y);
|
||||
case 0x234: return Values2D<L,2,3,4,8>(NE,B,X,Y);
|
||||
case 0x236: return Values2D<L,2,3,6,4>(NE,B,X,Y);
|
||||
case 0x248: return Values2D<L,2,4,8,2>(NE,B,X,Y);
|
||||
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
Values2D<L>(NE,B,X,Y,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x124: return Values3D<L,1,2,4>(NE,B,X,Y);
|
||||
case 0x136: return Values3D<L,1,3,6>(NE,B,X,Y);
|
||||
case 0x148: return Values3D<L,1,4,8>(NE,B,X,Y);
|
||||
|
||||
case 0x324: return Values3D<L,3,2,4>(NE,B,X,Y);
|
||||
case 0x336: return Values3D<L,3,3,6>(NE,B,X,Y);
|
||||
case 0x348: return Values3D<L,3,4,8>(NE,B,X,Y);
|
||||
|
||||
// Used for LOR batched assembly
|
||||
case 0x322: return Values3D<L,3,2,2>(NE,B,X,Y);
|
||||
case 0x333: return Values3D<L,3,3,3>(NE,B,X,Y);
|
||||
case 0x344: return Values3D<L,3,4,4>(NE,B,X,Y);
|
||||
case 0x355: return Values3D<L,3,5,5>(NE,B,X,Y);
|
||||
case 0x366: return Values3D<L,3,6,6>(NE,B,X,Y);
|
||||
case 0x377: return Values3D<L,3,7,7>(NE,B,X,Y);
|
||||
case 0x388: return Values3D<L,3,8,8>(NE,B,X,Y);
|
||||
case 0x399: return Values3D<L,3,9,9>(NE,B,X,Y);
|
||||
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
Values3D<L>(NE,B,X,Y,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
k::Specialization<3,QVectorLayout::byVDIM,3,2,2>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,3,3,3>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,3,4,4>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,3,5,5>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,3,6,6>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,3,7,7>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,3,8,8>::Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,3,9,9>::Opt<1>::Add();
|
||||
}
|
||||
|
||||
} // namespace quadrature_interpolator
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
// Internal header, included only by .cpp files.
|
||||
// Template function implementations.
|
||||
|
||||
#ifndef MFEM_QUADINTERP_GRAD
|
||||
#define MFEM_QUADINTERP_GRAD
|
||||
|
||||
#include "../quadinterpolator.hpp"
|
||||
#include "../../general/forall.hpp"
|
||||
#include "../../linalg/dtensor.hpp"
|
||||
@@ -29,6 +32,7 @@ namespace quadrature_interpolator
|
||||
|
||||
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
|
||||
static void Derivatives1D(const int NE,
|
||||
const real_t *b_,
|
||||
const real_t *g_,
|
||||
const real_t *j_,
|
||||
const real_t *x_,
|
||||
@@ -38,6 +42,7 @@ static void Derivatives1D(const int NE,
|
||||
const int d1d,
|
||||
const int q1d)
|
||||
{
|
||||
MFEM_CONTRACT_VAR(b_);
|
||||
const auto g = Reshape(g_, q1d, d1d);
|
||||
const auto j = Reshape(j_, q1d, sdim, NE);
|
||||
const auto x = Reshape(x_, d1d, vdim, NE);
|
||||
@@ -232,6 +237,7 @@ static void Derivatives3D(const int NE,
|
||||
const real_t *j_,
|
||||
const real_t *x_,
|
||||
real_t *y_,
|
||||
const int sdim = 3,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
@@ -370,4 +376,21 @@ static void Derivatives3D(const int NE,
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// @cond Suppress_Doxygen_warnings
|
||||
|
||||
template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS,
|
||||
int VDIM, int D1D, int Q1D, int NBZ>
|
||||
QuadratureInterpolator::GradKernelType
|
||||
QuadratureInterpolator::GradKernels::Kernel()
|
||||
{
|
||||
if (DIM == 1) { return internal::quadrature_interpolator::Derivatives1D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else if (DIM == 2) { return internal::quadrature_interpolator::Derivatives2D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, Q1D, NBZ>; }
|
||||
else if (DIM == 3) { return internal::quadrature_interpolator::Derivatives3D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, Q1D>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
+45
-104
@@ -9,128 +9,69 @@
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "dispatch.hpp"
|
||||
#include "../quadinterpolator.hpp"
|
||||
#include "grad.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
namespace quadrature_interpolator
|
||||
{
|
||||
|
||||
// Tensor-product evaluation of quadrature point derivatives: dispatch function.
|
||||
// Instantiation for the case QVectorLayout::byNODES.
|
||||
template<>
|
||||
void TensorDerivatives<QVectorLayout::byNODES>(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_der)
|
||||
template <bool P>
|
||||
void InitGradByNodesKernels()
|
||||
{
|
||||
if (NE == 0) { return; }
|
||||
const int dim = maps.FE->GetDim();
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const real_t *B = maps.B.Read();
|
||||
const real_t *G = maps.G.Read();
|
||||
const real_t *J = nullptr; // not used in DERIVATIVES (non-GRAD_PHYS) mode
|
||||
const real_t *X = e_vec.Read();
|
||||
real_t *Y = q_der.Write();
|
||||
using k = QuadratureInterpolator::GradKernels;
|
||||
// 2D
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,1,3,3>::template Opt<16>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,1,3,4>::template Opt<16>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,1,4,3>::template Opt<16>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,1,4,4>::template Opt<16>::Add();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byNODES;
|
||||
constexpr bool P = false; // GRAD_PHYS
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,2,2>::template Opt<16>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,2,3>::template Opt<8>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,2,4>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,2,5>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,2,6>::template Opt<2>::Add();
|
||||
|
||||
const int id = (vdim<<8) | (D1D<<4) | Q1D;
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,3,3>::template Opt<2>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,3,4>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,4,3>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,3,6>::template Opt<2>::Add();
|
||||
|
||||
if (dim == 1)
|
||||
{
|
||||
return Derivatives1D<L,P>(NE,G,J,X,Y,dim,vdim,D1D,Q1D);
|
||||
}
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x133: return Derivatives2D<L,P,1,3,3,16>(NE,B,G,J,X,Y);
|
||||
case 0x134: return Derivatives2D<L,P,1,3,4,16>(NE,B,G,J,X,Y);
|
||||
case 0x143: return Derivatives2D<L,P,1,4,3,16>(NE,B,G,J,X,Y);
|
||||
case 0x144: return Derivatives2D<L,P,1,4,4,16>(NE,B,G,J,X,Y);
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,4,4>::template Opt<2>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,4,5>::template Opt<2>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,4,6>::template Opt<2>::Add();
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,4,7>::template Opt<2>::Add();
|
||||
|
||||
case 0x222: return Derivatives2D<L,P,2,2,2,16>(NE,B,G,J,X,Y);
|
||||
case 0x223: return Derivatives2D<L,P,2,2,3,8>(NE,B,G,J,X,Y);
|
||||
case 0x224: return Derivatives2D<L,P,2,2,4,4>(NE,B,G,J,X,Y);
|
||||
case 0x225: return Derivatives2D<L,P,2,2,5,4>(NE,B,G,J,X,Y);
|
||||
case 0x226: return Derivatives2D<L,P,2,2,6,2>(NE,B,G,J,X,Y);
|
||||
k::Specialization<2,QVectorLayout::byNODES,P,2,5,6>::template Opt<2>::Add();
|
||||
// 3D
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,2,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,3,3>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,3,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,3,6>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,4,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,1,4,8>::template Opt<1>::Add();
|
||||
|
||||
case 0x233: return Derivatives2D<L,P,2,3,3,2>(NE,B,G,J,X,Y);
|
||||
case 0x234: return Derivatives2D<L,P,2,3,4,4>(NE,B,G,J,X,Y);
|
||||
case 0x243: return Derivatives2D<L,P,2,4,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x236: return Derivatives2D<L,P,2,3,6,2>(NE,B,G,J,X,Y);
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,2,3>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,2,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,2,5>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,2,6>::template Opt<1>::Add();
|
||||
|
||||
case 0x244: return Derivatives2D<L,P,2,4,4,2>(NE,B,G,J,X,Y);
|
||||
case 0x245: return Derivatives2D<L,P,2,4,5,2>(NE,B,G,J,X,Y);
|
||||
case 0x246: return Derivatives2D<L,P,2,4,6,2>(NE,B,G,J,X,Y);
|
||||
case 0x247: return Derivatives2D<L,P,2,4,7,2>(NE,B,G,J,X,Y);
|
||||
|
||||
case 0x256: return Derivatives2D<L,P,2,5,6,2>(NE,B,G,J,X,Y);
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
if (D1D > MD || Q1D > MQ)
|
||||
{
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
Derivatives2D<L,P>(NE,B,G,J,X,Y,dim,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x124: return Derivatives3D<L,P,1,2,4>(NE,B,G,J,X,Y);
|
||||
case 0x133: return Derivatives3D<L,P,1,3,3>(NE,B,G,J,X,Y);
|
||||
case 0x134: return Derivatives3D<L,P,1,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x136: return Derivatives3D<L,P,1,3,6>(NE,B,G,J,X,Y);
|
||||
case 0x144: return Derivatives3D<L,P,1,4,4>(NE,B,G,J,X,Y);
|
||||
case 0x148: return Derivatives3D<L,P,1,4,8>(NE,B,G,J,X,Y);
|
||||
|
||||
case 0x323: return Derivatives3D<L,P,3,2,3>(NE,B,G,J,X,Y);
|
||||
case 0x324: return Derivatives3D<L,P,3,2,4>(NE,B,G,J,X,Y);
|
||||
case 0x325: return Derivatives3D<L,P,3,2,5>(NE,B,G,J,X,Y);
|
||||
case 0x326: return Derivatives3D<L,P,3,2,6>(NE,B,G,J,X,Y);
|
||||
|
||||
case 0x333: return Derivatives3D<L,P,3,3,3>(NE,B,G,J,X,Y);
|
||||
case 0x334: return Derivatives3D<L,P,3,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x335: return Derivatives3D<L,P,3,3,5>(NE,B,G,J,X,Y);
|
||||
case 0x336: return Derivatives3D<L,P,3,3,6>(NE,B,G,J,X,Y);
|
||||
case 0x344: return Derivatives3D<L,P,3,4,4>(NE,B,G,J,X,Y);
|
||||
case 0x346: return Derivatives3D<L,P,3,4,6>(NE,B,G,J,X,Y);
|
||||
case 0x347: return Derivatives3D<L,P,3,4,7>(NE,B,G,J,X,Y);
|
||||
case 0x348: return Derivatives3D<L,P,3,4,8>(NE,B,G,J,X,Y);
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
Derivatives3D<L,P>(NE,B,G,J,X,Y,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,3,3>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,3,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,3,5>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,3,6>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,4,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,4,6>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,4,7>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byNODES,P,3,4,8>::template Opt<1>::Add();
|
||||
}
|
||||
|
||||
template void InitGradByNodesKernels<true>();
|
||||
template void InitGradByNodesKernels<false>();
|
||||
|
||||
} // namespace quadrature_interpolator
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -9,100 +9,41 @@
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "dispatch.hpp"
|
||||
#include "../quadinterpolator.hpp"
|
||||
#include "grad.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
namespace quadrature_interpolator
|
||||
{
|
||||
|
||||
// Tensor-product evaluation of quadrature point derivatives: dispatch function.
|
||||
// Instantiation for the case QVectorLayout::byVDIM.
|
||||
template<>
|
||||
void TensorDerivatives<QVectorLayout::byVDIM>(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_der)
|
||||
template <bool P>
|
||||
void InitGradByVDimKernels()
|
||||
{
|
||||
if (NE == 0) { return; }
|
||||
const int dim = maps.FE->GetDim();
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const real_t *B = maps.B.Read();
|
||||
const real_t *G = maps.G.Read();
|
||||
const real_t *J = nullptr; // not used in DERIVATIVES (non-GRAD_PHYS) mode
|
||||
const real_t *X = e_vec.Read();
|
||||
real_t *Y = q_der.Write();
|
||||
using k = QuadratureInterpolator::GradKernels;
|
||||
// 2D
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,1,3,4>::template Opt<8>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,1,4,6>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,1,5,8>::template Opt<2>::Add();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byVDIM;
|
||||
constexpr bool P = false; // GRAD_PHYS
|
||||
|
||||
const int id = (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
if (dim == 1)
|
||||
{
|
||||
return Derivatives1D<L,P>(NE,G,J,X,Y,dim,vdim,D1D,Q1D);
|
||||
}
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x134: return Derivatives2D<L,P,1,3,4,8>(NE,B,G,J,X,Y);
|
||||
case 0x146: return Derivatives2D<L,P,1,4,6,4>(NE,B,G,J,X,Y);
|
||||
case 0x158: return Derivatives2D<L,P,1,5,8,2>(NE,B,G,J,X,Y);
|
||||
|
||||
case 0x234: return Derivatives2D<L,P,2,3,4,8>(NE,B,G,J,X,Y);
|
||||
case 0x246: return Derivatives2D<L,P,2,4,6,4>(NE,B,G,J,X,Y);
|
||||
case 0x258: return Derivatives2D<L,P,2,5,8,2>(NE,B,G,J,X,Y);
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
Derivatives2D<L,P>(NE,B,G,J,X,Y,dim,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x134: return Derivatives3D<L,P,1,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x146: return Derivatives3D<L,P,1,4,6>(NE,B,G,J,X,Y);
|
||||
case 0x158: return Derivatives3D<L,P,1,5,8>(NE,B,G,J,X,Y);
|
||||
|
||||
case 0x334: return Derivatives3D<L,P,3,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x346: return Derivatives3D<L,P,3,4,6>(NE,B,G,J,X,Y);
|
||||
case 0x358: return Derivatives3D<L,P,3,5,8>(NE,B,G,J,X,Y);
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
Derivatives3D<L,P>(NE,B,G,J,X,Y,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,2,3,3>::template Opt<8>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,2,3,4>::template Opt<8>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,2,4,6>::template Opt<4>::Add();
|
||||
k::Specialization<2,QVectorLayout::byVDIM,P,2,5,8>::template Opt<2>::Add();
|
||||
// 3D
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,1,3,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,1,4,6>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,1,5,8>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,3,3,4>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,3,4,6>::template Opt<1>::Add();
|
||||
k::Specialization<3,QVectorLayout::byVDIM,P,3,5,8>::template Opt<1>::Add();
|
||||
}
|
||||
|
||||
template void InitGradByVDimKernels<true>();
|
||||
template void InitGradByVDimKernels<false>();
|
||||
|
||||
} // namespace quadrature_interpolator
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
// 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 "dispatch.hpp"
|
||||
#include "grad.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
namespace quadrature_interpolator
|
||||
{
|
||||
|
||||
// Tensor-product evaluation of quadrature point physical derivatives: dispatch
|
||||
// function.
|
||||
// Instantiation for the case QVectorLayout::byNODES.
|
||||
template<>
|
||||
void TensorPhysDerivatives<QVectorLayout::byNODES>(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const GeometricFactors &geom,
|
||||
const Vector &e_vec,
|
||||
Vector &q_der)
|
||||
{
|
||||
if (NE == 0) { return; }
|
||||
const int dim = maps.FE->GetDim();
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
|
||||
const int sdim = geom.mesh->SpaceDimension();
|
||||
|
||||
const real_t *B = maps.B.Read();
|
||||
const real_t *G = maps.G.Read();
|
||||
const real_t *J = geom.J.Read();
|
||||
const real_t *X = e_vec.Read();
|
||||
real_t *Y = q_der.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byNODES;
|
||||
constexpr bool P = true; // GRAD_PHYS
|
||||
|
||||
const int id = (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
if (dim == 1)
|
||||
{
|
||||
return Derivatives1D<L,P>(NE,G,J,X,Y,sdim,vdim,D1D,Q1D);
|
||||
}
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x133: return Derivatives2D<L,P,1,3,3,8>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x134: return Derivatives2D<L,P,1,3,4,8>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x143: return Derivatives2D<L,P,1,4,3,4>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x144: return Derivatives2D<L,P,1,4,4,4>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x146: return Derivatives2D<L,P,1,4,6,4>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x158: return Derivatives2D<L,P,1,5,8,2>(NE,B,G,J,X,Y,sdim);
|
||||
|
||||
case 0x233: return Derivatives2D<L,P,2,3,3,8>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x234: return Derivatives2D<L,P,2,3,4,8>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x243: return Derivatives2D<L,P,2,4,3,4>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x244: return Derivatives2D<L,P,2,4,4,4>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x246: return Derivatives2D<L,P,2,4,6,4>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x258: return Derivatives2D<L,P,2,5,8,2>(NE,B,G,J,X,Y,sdim);
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
Derivatives2D<L,P>(NE,B,G,J,X,Y,sdim,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x133: return Derivatives3D<L,P,1,3,3>(NE,B,G,J,X,Y);
|
||||
case 0x134: return Derivatives3D<L,P,1,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x144: return Derivatives3D<L,P,1,4,4>(NE,B,G,J,X,Y);
|
||||
case 0x146: return Derivatives3D<L,P,1,4,6>(NE,B,G,J,X,Y);
|
||||
case 0x158: return Derivatives3D<L,P,1,5,8>(NE,B,G,J,X,Y);
|
||||
|
||||
case 0x333: return Derivatives3D<L,P,3,3,3>(NE,B,G,J,X,Y);
|
||||
case 0x334: return Derivatives3D<L,P,3,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x344: return Derivatives3D<L,P,3,4,4>(NE,B,G,J,X,Y);
|
||||
case 0x346: return Derivatives3D<L,P,3,4,6>(NE,B,G,J,X,Y);
|
||||
case 0x358: return Derivatives3D<L,P,3,5,8>(NE,B,G,J,X,Y);
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
Derivatives3D<L,P>(NE,B,G,J,X,Y,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Unknown kernel");
|
||||
}
|
||||
|
||||
} // namespace quadrature_interpolator
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,114 +0,0 @@
|
||||
// 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 "dispatch.hpp"
|
||||
#include "grad.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
namespace quadrature_interpolator
|
||||
{
|
||||
|
||||
// Tensor-product evaluation of quadrature point physical derivatives: dispatch
|
||||
// function.
|
||||
// Instantiation for the case QVectorLayout::byVDIM.
|
||||
template<>
|
||||
void TensorPhysDerivatives<QVectorLayout::byVDIM>(const int NE,
|
||||
const int vdim,
|
||||
const DofToQuad &maps,
|
||||
const GeometricFactors &geom,
|
||||
const Vector &e_vec,
|
||||
Vector &q_der)
|
||||
{
|
||||
if (NE == 0) { return; }
|
||||
const int dim = maps.FE->GetDim();
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
|
||||
const int sdim = geom.mesh->SpaceDimension();
|
||||
|
||||
const real_t *B = maps.B.Read();
|
||||
const real_t *G = maps.G.Read();
|
||||
const real_t *J = geom.J.Read();
|
||||
const real_t *X = e_vec.Read();
|
||||
real_t *Y = q_der.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byVDIM;
|
||||
constexpr bool P = true; // GRAD_PHYS
|
||||
|
||||
const int id = (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
if (dim == 1)
|
||||
{
|
||||
return Derivatives1D<L,P>(NE,G,J,X,Y,sdim,vdim,D1D,Q1D);
|
||||
}
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x134: return Derivatives2D<L,P,1,3,4,8>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x146: return Derivatives2D<L,P,1,4,6,4>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x158: return Derivatives2D<L,P,1,5,8,2>(NE,B,G,J,X,Y,sdim);
|
||||
|
||||
case 0x233: return Derivatives2D<L,P,2,3,3,8>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x234: return Derivatives2D<L,P,2,3,4,8>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x246: return Derivatives2D<L,P,2,4,6,4>(NE,B,G,J,X,Y,sdim);
|
||||
case 0x258: return Derivatives2D<L,P,2,5,8,2>(NE,B,G,J,X,Y,sdim);
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_D1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_Q1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
Derivatives2D<L,P>(NE,B,G,J,X,Y,sdim,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x134: return Derivatives3D<L,P,1,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x146: return Derivatives3D<L,P,1,4,6>(NE,B,G,J,X,Y);
|
||||
case 0x158: return Derivatives3D<L,P,1,5,8>(NE,B,G,J,X,Y);
|
||||
|
||||
case 0x334: return Derivatives3D<L,P,3,3,4>(NE,B,G,J,X,Y);
|
||||
case 0x346: return Derivatives3D<L,P,3,4,6>(NE,B,G,J,X,Y);
|
||||
case 0x358: return Derivatives3D<L,P,3,5,8>(NE,B,G,J,X,Y);
|
||||
default:
|
||||
{
|
||||
const int MD = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
const int MQ = DeviceDofQuadLimits::Get().MAX_INTERP_1D;
|
||||
MFEM_VERIFY(D1D <= MD, "Orders higher than " << MD-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ, "Quadrature rules with more than "
|
||||
<< MQ << " 1D points are not supported!");
|
||||
Derivatives3D<L,P>(NE,B,G,J,X,Y,vdim,D1D,Q1D);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Unknown kernel");
|
||||
}
|
||||
|
||||
} // namespace quadrature_interpolator
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
+234
-187
@@ -10,7 +10,8 @@
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "qinterp/dispatch.hpp"
|
||||
#include "qinterp/grad.hpp"
|
||||
#include "qinterp/eval.hpp"
|
||||
#include "qspace.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
@@ -19,6 +20,38 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
namespace quadrature_interpolator
|
||||
{
|
||||
void InitEvalByNodesKernels();
|
||||
void InitEvalByVDimKernels();
|
||||
void InitEvalKernels();
|
||||
void InitDetKernels();
|
||||
template <bool P> void InitGradByNodesKernels();
|
||||
template <bool P> void InitGradByVDimKernels();
|
||||
}
|
||||
}
|
||||
|
||||
QuadratureInterpolator::Kernels QuadratureInterpolator::kernels;
|
||||
QuadratureInterpolator::Kernels::Kernels()
|
||||
{
|
||||
using namespace internal::quadrature_interpolator;
|
||||
|
||||
InitEvalByNodesKernels();
|
||||
InitEvalByVDimKernels();
|
||||
// Non-phys grad kernels
|
||||
InitGradByNodesKernels<false>();
|
||||
InitGradByVDimKernels<false>();
|
||||
// Phys grad kernels
|
||||
InitGradByNodesKernels<true>();
|
||||
InitGradByVDimKernels<true>();
|
||||
// Determinants
|
||||
InitDetKernels();
|
||||
// Non-tensor
|
||||
InitEvalKernels();
|
||||
}
|
||||
|
||||
QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir):
|
||||
|
||||
@@ -467,6 +500,7 @@ void QuadratureInterpolator::Mult(const Vector &e_vec,
|
||||
const int ne = fespace->GetNE();
|
||||
if (ne == 0) { return; }
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int sdim = fespace->GetMesh()->SpaceDimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const bool use_tensor_eval =
|
||||
use_tensor_products &&
|
||||
@@ -477,6 +511,8 @@ void QuadratureInterpolator::Mult(const Vector &e_vec,
|
||||
use_tensor_eval ? DofToQuad::TENSOR : DofToQuad::FULL;
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, mode);
|
||||
const int dim = maps.FE->GetDim();
|
||||
const int nd = maps.ndof;
|
||||
const int nq = maps.nqpt;
|
||||
const GeometricFactors *geom = nullptr;
|
||||
if (eval_flags & PHYSICAL_DERIVATIVES)
|
||||
{
|
||||
@@ -492,202 +528,31 @@ void QuadratureInterpolator::Mult(const Vector &e_vec,
|
||||
|
||||
if (use_tensor_eval)
|
||||
{
|
||||
// TODO: use fused kernels
|
||||
if (q_layout == QVectorLayout::byNODES)
|
||||
if (eval_flags & VALUES)
|
||||
{
|
||||
if (eval_flags & VALUES)
|
||||
{
|
||||
TensorValues<QVectorLayout::byNODES>(ne, vdim, maps, e_vec, q_val);
|
||||
}
|
||||
if (eval_flags & DERIVATIVES)
|
||||
{
|
||||
TensorDerivatives<QVectorLayout::byNODES>(
|
||||
ne, vdim, maps, e_vec, q_der);
|
||||
}
|
||||
if (eval_flags & PHYSICAL_DERIVATIVES)
|
||||
{
|
||||
TensorPhysDerivatives<QVectorLayout::byNODES>(
|
||||
ne, vdim, maps, *geom, e_vec, q_der);
|
||||
}
|
||||
TensorEvalKernels::Run(dim, q_layout, vdim, nd, nq, ne, maps.B.Read(),
|
||||
e_vec.Read(), q_val.Write(), vdim, nd, nq);
|
||||
}
|
||||
|
||||
if (q_layout == QVectorLayout::byVDIM)
|
||||
if (eval_flags & (DERIVATIVES | PHYSICAL_DERIVATIVES))
|
||||
{
|
||||
if (eval_flags & VALUES)
|
||||
{
|
||||
TensorValues<QVectorLayout::byVDIM>(ne, vdim, maps, e_vec, q_val);
|
||||
}
|
||||
if (eval_flags & DERIVATIVES)
|
||||
{
|
||||
TensorDerivatives<QVectorLayout::byVDIM>(
|
||||
ne, vdim, maps, e_vec, q_der);
|
||||
}
|
||||
if (eval_flags & PHYSICAL_DERIVATIVES)
|
||||
{
|
||||
TensorPhysDerivatives<QVectorLayout::byVDIM>(
|
||||
ne, vdim, maps, *geom, e_vec, q_der);
|
||||
}
|
||||
const bool phys = (eval_flags & PHYSICAL_DERIVATIVES);
|
||||
const real_t *J = phys ? geom->J.Read() : nullptr;
|
||||
const int s_dim = phys ? sdim : dim;
|
||||
GradKernels::Run(dim, q_layout, phys, vdim, nd, nq, ne,
|
||||
maps.B.Read(), maps.G.Read(), J, e_vec.Read(),
|
||||
q_der.Write(), s_dim, vdim, nd, nq);
|
||||
}
|
||||
if (eval_flags & DETERMINANTS)
|
||||
{
|
||||
TensorDeterminants(ne, vdim, maps, e_vec, q_det, d_buffer);
|
||||
DetKernels::Run(dim, vdim, nd, nq, ne, maps.B.Read(),
|
||||
maps.G.Read(), e_vec.Read(), q_det.Write(), nd,
|
||||
nq, &d_buffer);
|
||||
}
|
||||
}
|
||||
else // use_tensor_eval == false
|
||||
{
|
||||
const int nd = maps.ndof;
|
||||
const int nq = maps.nqpt;
|
||||
|
||||
void (*mult)(const int NE,
|
||||
const int vdim,
|
||||
const QVectorLayout q_layout,
|
||||
const GeometricFactors *geom,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val,
|
||||
Vector &q_der,
|
||||
Vector &q_det,
|
||||
const int eval_flags) = NULL;
|
||||
|
||||
if (dim == 1)
|
||||
{
|
||||
mult = &Eval1D;
|
||||
}
|
||||
else if (vdim == 1) // dim == 2 || dim == 3
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (100*nd + nq)
|
||||
{
|
||||
// Q0
|
||||
case 101: mult = &Eval2D<1,1,1>; break;
|
||||
case 104: mult = &Eval2D<1,1,4>; break;
|
||||
// Q1
|
||||
case 404: mult = &Eval2D<1,4,4>; break;
|
||||
case 409: mult = &Eval2D<1,4,9>; break;
|
||||
// Q2
|
||||
case 909: mult = &Eval2D<1,9,9>; break;
|
||||
case 916: mult = &Eval2D<1,9,16>; break;
|
||||
// Q3
|
||||
case 1616: mult = &Eval2D<1,16,16>; break;
|
||||
case 1625: mult = &Eval2D<1,16,25>; break;
|
||||
case 1636: mult = &Eval2D<1,16,36>; break;
|
||||
// Q4
|
||||
case 2525: mult = &Eval2D<1,25,25>; break;
|
||||
case 2536: mult = &Eval2D<1,25,36>; break;
|
||||
case 2549: mult = &Eval2D<1,25,49>; break;
|
||||
case 2564: mult = &Eval2D<1,25,64>; break;
|
||||
}
|
||||
if (nq >= 100 || !mult)
|
||||
{
|
||||
mult = &Eval2D<1,0,0>;
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch (1000*nd + nq)
|
||||
{
|
||||
// Q0
|
||||
case 1001: mult = &Eval3D<1,1,1>; break;
|
||||
case 1008: mult = &Eval3D<1,1,8>; break;
|
||||
// Q1
|
||||
case 8008: mult = &Eval3D<1,8,8>; break;
|
||||
case 8027: mult = &Eval3D<1,8,27>; break;
|
||||
// Q2
|
||||
case 27027: mult = &Eval3D<1,27,27>; break;
|
||||
case 27064: mult = &Eval3D<1,27,64>; break;
|
||||
// Q3
|
||||
case 64064: mult = &Eval3D<1,64,64>; break;
|
||||
case 64125: mult = &Eval3D<1,64,125>; break;
|
||||
case 64216: mult = &Eval3D<1,64,216>; break;
|
||||
// Q4
|
||||
case 125125: mult = &Eval3D<1,125,125>; break;
|
||||
case 125216: mult = &Eval3D<1,125,216>; break;
|
||||
}
|
||||
if (nq >= 1000 || !mult)
|
||||
{
|
||||
mult = &Eval3D<1,0,0>;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (vdim == 3 && dim == 2)
|
||||
{
|
||||
switch (100*nd + nq)
|
||||
{
|
||||
// Q0
|
||||
case 101: mult = &Eval2D<3,1,1>; break;
|
||||
case 104: mult = &Eval2D<3,1,4>; break;
|
||||
// Q1
|
||||
case 404: mult = &Eval2D<3,4,4>; break;
|
||||
case 409: mult = &Eval2D<3,4,9>; break;
|
||||
// Q2
|
||||
case 904: mult = &Eval2D<3,9,4>; break;
|
||||
case 909: mult = &Eval2D<3,9,9>; break;
|
||||
case 916: mult = &Eval2D<3,9,16>; break;
|
||||
case 925: mult = &Eval2D<3,9,25>; break;
|
||||
// Q3
|
||||
case 1616: mult = &Eval2D<3,16,16>; break;
|
||||
case 1625: mult = &Eval2D<3,16,25>; break;
|
||||
case 1636: mult = &Eval2D<3,16,36>; break;
|
||||
// Q4
|
||||
case 2525: mult = &Eval2D<3,25,25>; break;
|
||||
case 2536: mult = &Eval2D<3,25,36>; break;
|
||||
case 2549: mult = &Eval2D<3,25,49>; break;
|
||||
case 2564: mult = &Eval2D<3,25,64>; break;
|
||||
default: mult = &Eval2D<3,0,0>;
|
||||
}
|
||||
}
|
||||
else if (vdim == dim)
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (100*nd + nq)
|
||||
{
|
||||
// Q1
|
||||
case 404: mult = &Eval2D<2,4,4>; break;
|
||||
case 409: mult = &Eval2D<2,4,9>; break;
|
||||
// Q2
|
||||
case 909: mult = &Eval2D<2,9,9>; break;
|
||||
case 916: mult = &Eval2D<2,9,16>; break;
|
||||
// Q3
|
||||
case 1616: mult = &Eval2D<2,16,16>; break;
|
||||
case 1625: mult = &Eval2D<2,16,25>; break;
|
||||
case 1636: mult = &Eval2D<2,16,36>; break;
|
||||
// Q4
|
||||
case 2525: mult = &Eval2D<2,25,25>; break;
|
||||
case 2536: mult = &Eval2D<2,25,36>; break;
|
||||
case 2549: mult = &Eval2D<2,25,49>; break;
|
||||
case 2564: mult = &Eval2D<2,25,64>; break;
|
||||
}
|
||||
if (nq >= 100 || !mult) { mult = &Eval2D<2,0,0>; }
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch (1000*nd + nq)
|
||||
{
|
||||
// Q1
|
||||
case 8008: mult = &Eval3D<3,8,8>; break;
|
||||
case 8027: mult = &Eval3D<3,8,27>; break;
|
||||
// Q2
|
||||
case 27027: mult = &Eval3D<3,27,27>; break;
|
||||
case 27064: mult = &Eval3D<3,27,64>; break;
|
||||
case 27125: mult = &Eval3D<3,27,125>; break;
|
||||
// Q3
|
||||
case 64064: mult = &Eval3D<3,64,64>; break;
|
||||
case 64125: mult = &Eval3D<3,64,125>; break;
|
||||
case 64216: mult = &Eval3D<3,64,216>; break;
|
||||
// Q4
|
||||
case 125125: mult = &Eval3D<3,125,125>; break;
|
||||
case 125216: mult = &Eval3D<3,125,216>; break;
|
||||
}
|
||||
if (nq >= 1000 || !mult) { mult = &Eval3D<3,0,0>; }
|
||||
}
|
||||
}
|
||||
if (mult)
|
||||
{
|
||||
mult(ne,vdim,q_layout,geom,maps,e_vec,q_val,q_der,q_det,eval_flags);
|
||||
}
|
||||
else { MFEM_ABORT("case not supported yet"); }
|
||||
EvalKernels::Run(dim, vdim, maps.ndof, maps.nqpt, ne,vdim,q_layout,
|
||||
geom, maps,e_vec, q_val,q_der,q_det,eval_flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,4 +596,186 @@ void QuadratureInterpolator::Determinants(const Vector &e_vec,
|
||||
Mult(e_vec, DETERMINANTS, empty, empty, q_det);
|
||||
}
|
||||
|
||||
/// @cond Suppress_Doxygen_warnings
|
||||
|
||||
namespace
|
||||
{
|
||||
using EvalKernel = QuadratureInterpolator::EvalKernelType;
|
||||
using TensorEvalKernel = QuadratureInterpolator::TensorEvalKernelType;
|
||||
using GradKernel = QuadratureInterpolator::GradKernelType;
|
||||
|
||||
template <QVectorLayout Q_LAYOUT>
|
||||
TensorEvalKernel FallbackTensorEvalKernel(int DIM)
|
||||
{
|
||||
if (DIM == 1) { return internal::quadrature_interpolator::Values1D<Q_LAYOUT>; }
|
||||
else if (DIM == 2) { return internal::quadrature_interpolator::Values2D<Q_LAYOUT>; }
|
||||
else if (DIM == 3) { return internal::quadrature_interpolator::Values3D<Q_LAYOUT>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
|
||||
GradKernel GetGradKernel(int DIM)
|
||||
{
|
||||
if (DIM == 1) { return internal::quadrature_interpolator::Derivatives1D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else if (DIM == 2) { return internal::quadrature_interpolator::Derivatives2D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else if (DIM == 3) { return internal::quadrature_interpolator::Derivatives3D<Q_LAYOUT, GRAD_PHYS>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
template<QVectorLayout Q_LAYOUT>
|
||||
GradKernel GetGradKernel(int DIM, bool GRAD_PHYS)
|
||||
{
|
||||
if (GRAD_PHYS) { return GetGradKernel<Q_LAYOUT, true>(DIM); }
|
||||
else { return GetGradKernel<Q_LAYOUT, false>(DIM); }
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <int DIM, int VDIM, int ND, int NQ>
|
||||
EvalKernel QuadratureInterpolator::EvalKernels::Kernel()
|
||||
{
|
||||
using namespace internal::quadrature_interpolator;
|
||||
if (DIM == 1) { return Eval1D; }
|
||||
else if (DIM == 2) { return Eval2D<VDIM,ND,NQ>; }
|
||||
else if (DIM == 3) { return Eval3D<VDIM,ND,NQ>; }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
template <int DIM>
|
||||
EvalKernel GetEvalKernelVDimFallback(int VDIM)
|
||||
{
|
||||
using EvalKernels = QuadratureInterpolator::EvalKernels;
|
||||
if (VDIM == 1) { return EvalKernels::Kernel<DIM,1,0,0>(); }
|
||||
else if (VDIM == 2) { return EvalKernels::Kernel<DIM,2,0,0>(); }
|
||||
else if (VDIM == 3) { return EvalKernels::Kernel<DIM,3,0,0>(); }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
EvalKernel QuadratureInterpolator::EvalKernels::Fallback(
|
||||
int DIM, int VDIM, int ND, int NQ)
|
||||
{
|
||||
if (DIM == 1) { return GetEvalKernelVDimFallback<1>(VDIM); }
|
||||
else if (DIM == 2) { return GetEvalKernelVDimFallback<2>(VDIM); }
|
||||
else if (DIM == 3) { return GetEvalKernelVDimFallback<3>(VDIM); }
|
||||
else { MFEM_ABORT(""); }
|
||||
}
|
||||
|
||||
TensorEvalKernel QuadratureInterpolator::TensorEvalKernels::Fallback(
|
||||
int DIM, QVectorLayout Q_LAYOUT, int, int, int)
|
||||
{
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES) { return FallbackTensorEvalKernel<QVectorLayout::byNODES>(DIM); }
|
||||
else { return FallbackTensorEvalKernel<QVectorLayout::byVDIM>(DIM); }
|
||||
}
|
||||
|
||||
GradKernel QuadratureInterpolator::GradKernels::Fallback(
|
||||
int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int, int, int)
|
||||
{
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES) { return GetGradKernel<QVectorLayout::byNODES>(DIM, GRAD_PHYS); }
|
||||
else { return GetGradKernel<QVectorLayout::byVDIM>(DIM, GRAD_PHYS); }
|
||||
}
|
||||
|
||||
/// @endcond
|
||||
|
||||
namespace internal
|
||||
{
|
||||
namespace quadrature_interpolator
|
||||
{
|
||||
void InitEvalKernels()
|
||||
{
|
||||
using k = QuadratureInterpolator::EvalKernels;
|
||||
// 2D, VDIM = 1
|
||||
k::Specialization<2,1,1,1>::Add();
|
||||
k::Specialization<2,1,1,4>::Add();
|
||||
// Q1
|
||||
k::Specialization<2,1,4,4>::Add();
|
||||
k::Specialization<2,1,4,9>::Add();
|
||||
// Q2
|
||||
k::Specialization<2,1,9,9>::Add();
|
||||
k::Specialization<2,1,9,16>::Add();
|
||||
// Q3
|
||||
k::Specialization<2,1,16,16>::Add();
|
||||
k::Specialization<2,1,16,25>::Add();
|
||||
k::Specialization<2,1,16,36>::Add();
|
||||
// Q4
|
||||
k::Specialization<2,1,25,25>::Add();
|
||||
k::Specialization<2,1,25,36>::Add();
|
||||
k::Specialization<2,1,25,49>::Add();
|
||||
k::Specialization<2,1,25,64>::Add();
|
||||
|
||||
// 3D, VDIM = 1
|
||||
// Q0
|
||||
k::Specialization<3,1,1,1>::Add();
|
||||
k::Specialization<3,1,1,8>::Add();
|
||||
// Q1
|
||||
k::Specialization<3,1,8,8>::Add();
|
||||
k::Specialization<3,1,8,27>::Add();
|
||||
// Q2
|
||||
k::Specialization<3,1,27,27>::Add();
|
||||
k::Specialization<3,1,27,64>::Add();
|
||||
// Q3
|
||||
k::Specialization<3,1,64,64>::Add();
|
||||
k::Specialization<3,1,64,125>::Add();
|
||||
k::Specialization<3,1,64,216>::Add();
|
||||
// Q4
|
||||
k::Specialization<3,1,125,125>::Add();
|
||||
k::Specialization<3,1,125,216>::Add();
|
||||
|
||||
// 2D, VDIM = 3
|
||||
// Q0
|
||||
k::Specialization<2,3,1,1>::Add();
|
||||
k::Specialization<2,3,1,4>::Add();
|
||||
// Q1
|
||||
k::Specialization<2,3,4,4>::Add();
|
||||
k::Specialization<2,3,4,9>::Add();
|
||||
// Q2
|
||||
k::Specialization<2,3,9,4>::Add();
|
||||
k::Specialization<2,3,9,9>::Add();
|
||||
k::Specialization<2,3,9,16>::Add();
|
||||
k::Specialization<2,3,9,25>::Add();
|
||||
// Q3
|
||||
k::Specialization<2,3,16,16>::Add();
|
||||
k::Specialization<2,3,16,25>::Add();
|
||||
k::Specialization<2,3,16,36>::Add();
|
||||
// Q4
|
||||
k::Specialization<2,3,25,25>::Add();
|
||||
k::Specialization<2,3,25,36>::Add();
|
||||
k::Specialization<2,3,25,49>::Add();
|
||||
k::Specialization<2,3,25,64>::Add();
|
||||
|
||||
// 2D, VDIM = 2
|
||||
// Q1
|
||||
k::Specialization<2,2,4,4>::Add();
|
||||
k::Specialization<2,2,4,9>::Add();
|
||||
// Q2
|
||||
k::Specialization<2,2,9,9>::Add();
|
||||
k::Specialization<2,2,9,16>::Add();
|
||||
// Q3
|
||||
k::Specialization<2,2,16,16>::Add();
|
||||
k::Specialization<2,2,16,25>::Add();
|
||||
k::Specialization<2,2,16,36>::Add();
|
||||
// Q4
|
||||
k::Specialization<2,2,25,25>::Add();
|
||||
k::Specialization<2,2,25,36>::Add();
|
||||
k::Specialization<2,2,25,49>::Add();
|
||||
k::Specialization<2,2,25,64>::Add();
|
||||
|
||||
// 3D, VDIM = 3
|
||||
// Q1
|
||||
k::Specialization<3,3,8,8>::Add();
|
||||
k::Specialization<3,3,8,27>::Add();
|
||||
// Q2
|
||||
k::Specialization<3,3,27,27>::Add();
|
||||
k::Specialization<3,3,27,64>::Add();
|
||||
k::Specialization<3,3,27,125>::Add();
|
||||
// Q3
|
||||
k::Specialization<3,3,64,64>::Add();
|
||||
k::Specialization<3,3,64,125>::Add();
|
||||
k::Specialization<3,3,64,216>::Add();
|
||||
// Q4
|
||||
k::Specialization<3,3,125,125>::Add();
|
||||
k::Specialization<3,3,125,216>::Add();
|
||||
}
|
||||
|
||||
} // namespace quadrature_Interpolator
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define MFEM_QUADINTERP
|
||||
|
||||
#include "fespace.hpp"
|
||||
#include "kernel_dispatch.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -130,6 +131,29 @@ public:
|
||||
/// Perform the transpose operation of Mult(). (TODO)
|
||||
void MultTranspose(unsigned eval_flags, const Vector &q_val,
|
||||
const Vector &q_der, Vector &e_vec) const;
|
||||
|
||||
|
||||
using TensorEvalKernelType = void(*)(const int, const real_t *, const real_t *,
|
||||
real_t *, const int, const int, const int);
|
||||
using GradKernelType = void(*)(const int, const real_t *, const real_t *,
|
||||
const real_t *, const real_t *, real_t *,
|
||||
const int, const int, const int, const int);
|
||||
using DetKernelType = void(*)(const int NE, const real_t *, const real_t *,
|
||||
const real_t *, real_t *, const int, const int,
|
||||
Vector *);
|
||||
using EvalKernelType = void(*)(const int, const int, const QVectorLayout,
|
||||
const GeometricFactors *, const DofToQuad &,
|
||||
const Vector &, Vector &, Vector &, Vector &,
|
||||
const int);
|
||||
|
||||
MFEM_REGISTER_KERNELS(TensorEvalKernels, TensorEvalKernelType,
|
||||
(int, QVectorLayout, int, int, int), (int));
|
||||
MFEM_REGISTER_KERNELS(GradKernels, GradKernelType,
|
||||
(int, QVectorLayout, bool, int, int, int), (int));
|
||||
MFEM_REGISTER_KERNELS(DetKernels, DetKernelType, (int, int, int, int));
|
||||
MFEM_REGISTER_KERNELS(EvalKernels, EvalKernelType, (int, int, int, int));
|
||||
|
||||
static struct Kernels { Kernels(); } kernels;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+4
-2
@@ -855,7 +855,8 @@ void ConformingFaceRestriction::SetFaceDofsScatterIndices(
|
||||
"This method should not be used on nonconforming coarse faces.");
|
||||
MFEM_ASSERT(face.element[0].orientation==0,
|
||||
"FaceRestriction used on degenerated mesh.");
|
||||
MFEM_CONTRACT_VAR(f_ordering); // not supported yet
|
||||
MFEM_VERIFY(f_ordering == ElementDofOrdering::LEXICOGRAPHIC,
|
||||
"NATIVE ordering is not supported yet");
|
||||
|
||||
fes.GetFE(0)->GetFaceMap(face.element[0].local_face_id, face_map);
|
||||
|
||||
@@ -883,7 +884,8 @@ void ConformingFaceRestriction::SetFaceDofsGatherIndices(
|
||||
{
|
||||
MFEM_ASSERT(!(face.IsNonconformingCoarse()),
|
||||
"This method should not be used on nonconforming coarse faces.");
|
||||
MFEM_CONTRACT_VAR(f_ordering); // not supported yet
|
||||
MFEM_VERIFY(f_ordering == ElementDofOrdering::LEXICOGRAPHIC,
|
||||
"NATIVE ordering is not supported yet");
|
||||
|
||||
fes.GetFE(0)->GetFaceMap(face.element[0].local_face_id, face_map);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ list(APPEND HDRS
|
||||
handle.hpp
|
||||
invariants.hpp
|
||||
kernels.hpp
|
||||
lapack.hpp
|
||||
linalg.hpp
|
||||
matrix.hpp
|
||||
ode.hpp
|
||||
|
||||
+20
-138
@@ -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
|
||||
// Cholesky–Crout 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
@@ -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
|
||||
// Cholesky–Crout 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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
+29
-10
@@ -420,8 +420,9 @@ public:
|
||||
/** @brief Perform the action of the explicit part of the operator, G:
|
||||
@a v = G(@a u, t) where t is the current time.
|
||||
|
||||
Presently, this method is used by some PETSc ODE solvers, for more
|
||||
details, see the PETSc Manual. */
|
||||
Presently, this method is used by some PETSc ODE solvers and the
|
||||
SUNDIALS ARKStep integrator, for more details, see either the PETSc
|
||||
Manual or the ARKode User Guide, respectively. */
|
||||
virtual void ExplicitMult(const Vector &u, Vector &v) const;
|
||||
|
||||
/** @brief Perform the action of the implicit part of the operator, F:
|
||||
@@ -445,7 +446,7 @@ public:
|
||||
|
||||
Regardless of the choice of F and G, this function should always compute
|
||||
@a k = inv(M) g(@a u, t). */
|
||||
virtual void Mult(const Vector &u, Vector &v) const override;
|
||||
virtual void Mult(const Vector &u, Vector &k) const override;
|
||||
|
||||
/** @brief Solve for the unknown @a k, at the current time t, the following
|
||||
equation:
|
||||
@@ -496,7 +497,17 @@ public:
|
||||
details, see the PETSc Manual. */
|
||||
virtual Operator& GetExplicitGradient(const Vector &u) const;
|
||||
|
||||
/** @brief Setup a linear system as needed by some SUNDIALS ODE solvers.
|
||||
/** @brief Setup a linear system as needed by some SUNDIALS ODE solvers to
|
||||
perform a similar action to ImplicitSolve, i.e., solve for k, at the
|
||||
current time t, in F(u + gamma k, k, t) = G(u + gamma k, t).
|
||||
|
||||
The SUNDIALS ODE solvers iteratively solve for k, as knew = kold + dk.
|
||||
The linear system here is for dk, obtained by linearizing the nonlinear
|
||||
system F(u + gamma knew, knew, t) = G(u + gamma knew, t) about dk = 0:
|
||||
F(u + gamma (kold + dk), kold + dk, t) = G(u + gamma (kold + dk), t)
|
||||
=> [dF/dk + gamma (dF/du - dG/du)] dk = G - F + O(dk^2)
|
||||
In other words, the linear system to be setup here is A dk = r, where
|
||||
A = [dF/dk + gamma (dF/du - dG/du)] and r = G - F.
|
||||
|
||||
For solving an ordinary differential equation of the form
|
||||
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined as one
|
||||
@@ -506,7 +517,7 @@ public:
|
||||
2. F(u,k,t) = M k and G(u,t) = g(u,t)
|
||||
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
|
||||
|
||||
This function performs setup to solve $ A x = b $ where A is either
|
||||
This function performs setup to solve $ A dk = r $ where A is either
|
||||
|
||||
1. A(@a y,t) = I - @a gamma inv(M) J(@a y,t)
|
||||
2. A(@a y,t) = M - @a gamma J(@a y,t)
|
||||
@@ -527,18 +538,26 @@ public:
|
||||
virtual int SUNImplicitSetup(const Vector &y, const Vector &v,
|
||||
int jok, int *jcur, real_t gamma);
|
||||
|
||||
/** @brief Solve the ODE linear system A @a x = @a b, where A is defined by
|
||||
the method SUNImplicitSetup().
|
||||
/** @brief Solve the ODE linear system A @a dk = @a r , where A and r are
|
||||
defined by the method SUNImplicitSetup().
|
||||
|
||||
@param[in] b The linear system right-hand side.
|
||||
@param[in,out] x On input, the initial guess. On output, the solution.
|
||||
For solving an ordinary differential equation of the form
|
||||
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined as one
|
||||
of the following:
|
||||
|
||||
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
|
||||
2. F(u,k,t) = M k and G(u,t) = g(u,t)
|
||||
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
|
||||
|
||||
@param[in] r inv(M) g(y,t) - k for 1 or g(y,t) - M k for 2 & 3.
|
||||
@param[in,out] dk On input, the initial guess. On output, the solution.
|
||||
@param[in] tol Linear solve tolerance.
|
||||
|
||||
If not re-implemented, this method simply generates an error.
|
||||
|
||||
Presently, this method is used by SUNDIALS ODE solvers, for more
|
||||
details, see the SUNDIALS User Guides. */
|
||||
virtual int SUNImplicitSolve(const Vector &b, Vector &x, real_t tol);
|
||||
virtual int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol);
|
||||
|
||||
/** @brief Setup the mass matrix in the ODE system
|
||||
$ M \frac{dy}{dt} = g(y,t) $ .
|
||||
|
||||
+53
-138
@@ -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, ¬rans, &nounit,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dtrsm_(&lside, &upper, ¬rans, &nounit,
|
||||
#endif
|
||||
&n_glob, &ione, &fone,
|
||||
mat_qr_data.GetData(), &m,
|
||||
vec1.GetData(), &n_glob);
|
||||
MFEM_LAPACK_PREFIX(trsm_)(&lside, &upper, ¬rans, &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_(¬rans, &m, &n_glob, &fmone,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgemv_(¬rans, &m, &n_glob, &fmone,
|
||||
#endif
|
||||
mat_0_data.GetData(), &m,
|
||||
soln_nz_glob.GetData(), &ione, &fone,
|
||||
res_glob.GetData(), &ione);
|
||||
MFEM_LAPACK_PREFIX(gemv_)(¬rans, &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, ¬rans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dormqr_(&lside, ¬rans, &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, ¬rans, &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, ¬rans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dormqr_(&lside, ¬rans, &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, ¬rans, &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;
|
||||
|
||||
+19
-11
@@ -1267,24 +1267,32 @@ real_t SparseMatrix::InnerProduct(const Vector &x, const Vector &y) const
|
||||
|
||||
void SparseMatrix::GetRowSums(Vector &x) const
|
||||
{
|
||||
for (int i = 0; i < height; i++)
|
||||
if (Finalized())
|
||||
{
|
||||
real_t a = 0.0;
|
||||
if (A)
|
||||
auto d_I = ReadI();
|
||||
auto d_A = ReadData();
|
||||
auto d_x = x.Write();
|
||||
mfem::forall(height, [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
for (int j = I[i], end = I[i+1]; j < end; j++)
|
||||
real_t sum = 0.0;
|
||||
for (int j = d_I[i], end = d_I[i+1]; j < end; j++)
|
||||
{
|
||||
a += A[j];
|
||||
sum += d_A[j];
|
||||
}
|
||||
}
|
||||
else
|
||||
d_x[i] = sum;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
real_t a = 0.0;
|
||||
for (RowNode *np = Rows[i]; np != NULL; np = np->Prev)
|
||||
{
|
||||
a += np->Value;
|
||||
}
|
||||
x(i) = a;
|
||||
}
|
||||
x(i) = a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3300,7 +3308,7 @@ void SparseMatrix::Print(std::ostream & os, int width_) const
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (A == NULL)
|
||||
if (A.Empty())
|
||||
{
|
||||
RowNode *nd;
|
||||
for (i = 0; i < height; i++)
|
||||
@@ -3354,7 +3362,7 @@ void SparseMatrix::PrintMatlab(std::ostream & os) const
|
||||
os.setf(ios::scientific);
|
||||
std::streamsize old_prec = os.precision(14);
|
||||
|
||||
if (A == NULL)
|
||||
if (A.Empty())
|
||||
{
|
||||
RowNode *nd;
|
||||
for (i = 0; i < height; i++)
|
||||
@@ -3397,7 +3405,7 @@ void SparseMatrix::PrintMM(std::ostream & os) const
|
||||
|
||||
os << height << " " << width << " " << NumNonZeroElems() << '\n';
|
||||
|
||||
if (A == NULL)
|
||||
if (A.Empty())
|
||||
{
|
||||
RowNode *nd;
|
||||
for (i = 0; i < height; i++)
|
||||
|
||||
@@ -216,7 +216,7 @@ public:
|
||||
void ClearCuSparse() { ClearGPUSparse(); }
|
||||
|
||||
/// Check if the SparseMatrix is empty.
|
||||
bool Empty() const { return (A == NULL) && (Rows == NULL); }
|
||||
bool Empty() const { return A.Empty() && (Rows == NULL); }
|
||||
|
||||
/// Return the array #I.
|
||||
inline int *GetI() { return I; }
|
||||
|
||||
+37
-10
@@ -1341,38 +1341,59 @@ CVODESSolver::~CVODESSolver()
|
||||
// ARKStep interface
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int ARKStepSolver::RHS1(realtype t, const N_Vector y, N_Vector ydot,
|
||||
int ARKStepSolver::RHS1(realtype t, const N_Vector y, N_Vector result,
|
||||
void *user_data)
|
||||
{
|
||||
// Get data from N_Vectors
|
||||
const SundialsNVector mfem_y(y);
|
||||
SundialsNVector mfem_ydot(ydot);
|
||||
SundialsNVector mfem_result(result);
|
||||
ARKStepSolver *self = static_cast<ARKStepSolver*>(user_data);
|
||||
|
||||
// Compute f(t, y) in y' = f(t, y) or fe(t, y) in y' = fe(t, y) + fi(t, y)
|
||||
// Compute either f(t, y) in one of
|
||||
// 1. y' = f(t, y)
|
||||
// 2. M y' = f(t, y)
|
||||
// or fe(t, y) in one of
|
||||
// 1. y' = fe(t, y) + fi(t, y)
|
||||
// 2. M y' = fe(t, y) + fi(t, y)
|
||||
self->f->SetTime(t);
|
||||
if (self->rk_type == IMEX)
|
||||
{
|
||||
self->f->SetEvalMode(TimeDependentOperator::ADDITIVE_TERM_1);
|
||||
}
|
||||
self->f->Mult(mfem_y, mfem_ydot);
|
||||
if (self->f->isExplicit()) // ODE is in form 1
|
||||
{
|
||||
self->f->Mult(mfem_y, mfem_result);
|
||||
}
|
||||
else // ODE is in form 2
|
||||
{
|
||||
self->f->ExplicitMult(mfem_y, mfem_result);
|
||||
}
|
||||
|
||||
// Return success
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ARKStepSolver::RHS2(realtype t, const N_Vector y, N_Vector ydot,
|
||||
int ARKStepSolver::RHS2(realtype t, const N_Vector y, N_Vector result,
|
||||
void *user_data)
|
||||
{
|
||||
// Get data from N_Vectors
|
||||
const SundialsNVector mfem_y(y);
|
||||
SundialsNVector mfem_ydot(ydot);
|
||||
SundialsNVector mfem_result(result);
|
||||
ARKStepSolver *self = static_cast<ARKStepSolver*>(user_data);
|
||||
|
||||
// Compute fi(t, y) in y' = fe(t, y) + fi(t, y)
|
||||
// Compute fi(t, y) in one of
|
||||
// 1. y' = fe(t, y) + fi(t, y) (ODE is expressed in EXPLICIT form)
|
||||
// 2. M y' = fe(t, y) + fi(y, t) (ODE is expressed in IMPLICIT form)
|
||||
self->f->SetTime(t);
|
||||
self->f->SetEvalMode(TimeDependentOperator::ADDITIVE_TERM_2);
|
||||
self->f->Mult(mfem_y, mfem_ydot);
|
||||
if (self->f->isExplicit())
|
||||
{
|
||||
self->f->Mult(mfem_y, mfem_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->f->ExplicitMult(mfem_y, mfem_result);
|
||||
}
|
||||
|
||||
// Return success
|
||||
return (0);
|
||||
@@ -1567,7 +1588,7 @@ void ARKStepSolver::Init(TimeDependentOperator &f_)
|
||||
reinit = true;
|
||||
}
|
||||
|
||||
void ARKStepSolver::Step(Vector &x, double &t, double &dt)
|
||||
void ARKStepSolver::Step(Vector &x, real_t &t, real_t &dt)
|
||||
{
|
||||
Y->MakeRef(x, 0, x.Size());
|
||||
MFEM_VERIFY(Y->Size() == x.Size(), "size mismatch");
|
||||
@@ -1666,7 +1687,7 @@ void ARKStepSolver::UseMFEMMassLinearSolver(int tdep)
|
||||
LSM->content = this;
|
||||
LSM->ops->gettype = LSGetType;
|
||||
LSM->ops->solve = ARKStepSolver::MassSysSolve;
|
||||
LSA->ops->free = LSFree;
|
||||
LSM->ops->free = LSFree;
|
||||
|
||||
M = SUNMatNewEmpty(Sundials::GetContext());
|
||||
MFEM_VERIFY(M, "error in SUNMatNewEmpty()");
|
||||
@@ -1683,6 +1704,9 @@ void ARKStepSolver::UseMFEMMassLinearSolver(int tdep)
|
||||
// Set the linear system function
|
||||
flag = ARKStepSetMassFn(sundials_mem, ARKStepSolver::MassSysSetup);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassFn()");
|
||||
|
||||
// Check that the ODE is not expressed in EXPLICIT form
|
||||
MFEM_VERIFY(!f->isExplicit(), "ODE operator is expressed in EXPLICIT form")
|
||||
}
|
||||
|
||||
void ARKStepSolver::UseSundialsMassLinearSolver(int tdep)
|
||||
@@ -1703,6 +1727,9 @@ void ARKStepSolver::UseSundialsMassLinearSolver(int tdep)
|
||||
flag = ARKStepSetMassTimes(sundials_mem, NULL, ARKStepSolver::MassMult2,
|
||||
this);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassTimes()");
|
||||
|
||||
// Check that the ODE is not expressed in EXPLICIT form
|
||||
MFEM_VERIFY(!f->isExplicit(), "ODE operator is expressed in EXPLICIT form")
|
||||
}
|
||||
|
||||
void ARKStepSolver::SetStepMode(int itask)
|
||||
|
||||
+1
-1
@@ -763,7 +763,7 @@ public:
|
||||
@note On input, the values of @a t and @a dt are used to compute desired
|
||||
output time for the integration, tout = @a t + @a dt.
|
||||
*/
|
||||
virtual void Step(Vector &x, double &t, double &dt);
|
||||
virtual void Step(Vector &x, real_t &t, real_t &dt) override;
|
||||
|
||||
/** @brief Attach the linear system setup and solve methods from the
|
||||
TimeDependentOperator i.e., SUNImplicitSetup() and SUNImplicitSolve() to
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
set(SRCS
|
||||
attribute_sets.cpp
|
||||
element.cpp
|
||||
exodus_writer.cpp
|
||||
face_nbr_geom.cpp
|
||||
gmsh.cpp
|
||||
hexahedron.cpp
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+43
-11
@@ -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;
|
||||
|
||||
@@ -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).
|
||||
///
|
||||
@@ -2331,6 +2334,11 @@ public:
|
||||
bool high_order_output=false,
|
||||
int compression_level=0);
|
||||
|
||||
#ifdef MFEM_USE_NETCDF
|
||||
/// @brief Export a mesh to an Exodus II file.
|
||||
void PrintExodusII(const std::string fpath);
|
||||
#endif
|
||||
|
||||
/** @brief Prints the mesh with boundary elements given by the boundary of
|
||||
the subdomains, so that the boundary of subdomain i has boundary
|
||||
attribute i+1. */
|
||||
|
||||
+103
-18
@@ -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
@@ -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
@@ -819,7 +819,7 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh,
|
||||
apf::Downward verts;
|
||||
apf_mesh->getDownward(ent,0,verts);
|
||||
|
||||
int *v, nv = 0;
|
||||
int *v = nullptr, nv = 0;
|
||||
apf::Mesh::Type ftype = apf_mesh->getType(ent);
|
||||
if (ftype == apf::Mesh::TRIANGLE)
|
||||
{
|
||||
@@ -890,9 +890,9 @@ GridFunctionPumi::GridFunctionPumi(Mesh* m, apf::Mesh2* PumiM,
|
||||
{
|
||||
int spDim = m->SpaceDimension();
|
||||
// Note: default BasisType for 'fec' is GaussLobatto.
|
||||
fec = new H1_FECollection(mesh_order, m->Dimension());
|
||||
fec_owned = new H1_FECollection(mesh_order, m->Dimension());
|
||||
int ordering = Ordering::byVDIM; // x1y1z1/x2y2z2/...
|
||||
fes = new FiniteElementSpace(m, fec, spDim, ordering);
|
||||
fes = new FiniteElementSpace(m, fec_owned, spDim, ordering);
|
||||
int data_size = fes->GetVSize();
|
||||
|
||||
// Read PUMI mesh data
|
||||
|
||||
@@ -1,637 +0,0 @@
|
||||
// Parallel contact example
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 1 -testno 4
|
||||
// CG iteration numbers = 105 114 116 115 113 109 113 108 107 114 206 236 268 435 987
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 5
|
||||
// CG iteration numbers = 106 116 116 116 115 113 107 107 128 131 531 1437 1318
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 6
|
||||
// CG iteration numbers = 18 18 18 18 18 17 17 21 22 46 52 53
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "ipsolver/ParIPsolver.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
double GetBdrElementVolume(int i, Mesh & mesh)
|
||||
{
|
||||
ElementTransformation *et = mesh.GetBdrElementTransformation(i);
|
||||
const IntegrationRule &ir = IntRules.Get(mesh.GetBdrElementGeometry(i),
|
||||
et->OrderJ());
|
||||
double volume = 0.0;
|
||||
for (int j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(j);
|
||||
et->SetIntPoint(&ip);
|
||||
volume += ip.weight * et->Weight();
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
|
||||
double GetBdrArea(int bdrattr, Mesh&mesh)
|
||||
{
|
||||
double area = 0.0;
|
||||
for (int i = 0; i<mesh.GetNBE(); i++)
|
||||
{
|
||||
if (mesh.GetBdrAttribute(i) == bdrattr)
|
||||
{
|
||||
area += GetBdrElementVolume(i,mesh);
|
||||
}
|
||||
}
|
||||
|
||||
MPI_Allreduce(MPI_IN_PLACE,&area,1, MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
|
||||
return area;
|
||||
}
|
||||
|
||||
void OutputData(ostringstream & file_name, double E0, double Ef, int dofs, int constr, int optit, const Array<int> & iters)
|
||||
{
|
||||
file_name << ".csv";
|
||||
std::ofstream outputfile(file_name.str().c_str());
|
||||
//if (!outputfile.is_open())
|
||||
//{
|
||||
// MFEM_ABORT("Failed to open file for writing.\n");
|
||||
//}
|
||||
outputfile << "Initial Energy objective = " << E0 << endl;
|
||||
outputfile << "Final Energy objective = " << Ef << endl;
|
||||
outputfile << "Global number of dofs = " << dofs << endl;
|
||||
outputfile << "Global number of constraints = " << constr << endl;
|
||||
outputfile << "Optimizer number of iterations = " << optit << endl;
|
||||
outputfile << "CG iteration numbers = "; iters.Print(outputfile, iters.Size());
|
||||
outputfile << "OptimizerIteration,CGIterations" << endl;
|
||||
for (int i = 0; i< iters.Size(); i++)
|
||||
{
|
||||
outputfile << i+1 <<","<< iters[i] << endl;
|
||||
}
|
||||
outputfile.close();
|
||||
std::cout << " Data has been written to " << file_name.str().c_str() << endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Mpi::Init();
|
||||
int myid = Mpi::WorldRank();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
Hypre::Init();
|
||||
|
||||
int order = 1;
|
||||
int sref = 1;
|
||||
int pref = 0;
|
||||
Array<int> attr;
|
||||
Array<int> m_attr;
|
||||
bool visualization = true;
|
||||
bool paraview = false;
|
||||
int paraview_plot_every = 1;
|
||||
int SQPrepeat = 1;
|
||||
double linsolverrtol = 1e-10;
|
||||
double linsolveratol = 1e-12;
|
||||
int relax_type = 8;
|
||||
double optimizer_tol = 1e-6;
|
||||
int optimizer_maxit = 20;
|
||||
int linsolver = 2; // PCG - AMG
|
||||
bool elast = false;
|
||||
bool nocontact = false;
|
||||
int testNo = -1; // 0-6
|
||||
int nsteps = 1;
|
||||
bool outputfiles = false;
|
||||
bool doublepass = false;
|
||||
// 1. Parse command-line options.
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&testNo, "-testno", "--test-number",
|
||||
"Choice of test problem:"
|
||||
"-1: default (original 2 block problem)"
|
||||
"0: not implemented yet"
|
||||
"1: not implemented yet"
|
||||
"2: not implemented yet"
|
||||
"3: not implemented yet"
|
||||
"4: two block problem - diablo"
|
||||
"41: two block problem - twisted"
|
||||
"5: ironing problem"
|
||||
"51: ironing problem extended"
|
||||
"6: nested spheres problem");
|
||||
args.AddOption(&attr, "-at", "--attributes-surf",
|
||||
"Attributes of boundary faces on contact surface for mesh 2.");
|
||||
args.AddOption(&sref, "-sr", "--serial-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&nsteps, "-nsteps", "--nsteps",
|
||||
"Number of steps.");
|
||||
args.AddOption(&pref, "-pr", "--parallel-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&linsolverrtol, "-srtol", "--solver-rel-tol",
|
||||
"Linear Solver Relative Tolerance.");
|
||||
args.AddOption(&linsolveratol, "-satol", "--solver-abs-tol",
|
||||
"Linear Solver Abs Tolerance.");
|
||||
args.AddOption(&elast, "-elast", "--elast", "-no-elast",
|
||||
"--no-elast",
|
||||
"Enable or disable AMG Elasticity options.");
|
||||
args.AddOption(&nocontact, "-nocontact", "--nocontact", "-no-nocontact",
|
||||
"--no-nocontact",
|
||||
"Enable or disable AMG solve with no contact for testing.");
|
||||
args.AddOption(&doublepass, "-doublepass", "--double-pass", "-singlepass",
|
||||
"--single-pass",
|
||||
"Enable or disable double pass for contact constraints.");
|
||||
args.AddOption(&optimizer_tol, "-otol", "--optimizer-tol",
|
||||
"Interior Point Solver Tolerance.");
|
||||
args.AddOption(&optimizer_maxit, "-omaxit", "--optimizer-maxit",
|
||||
"Interior Point Solver maximum number of iterations.");
|
||||
args.AddOption(&relax_type, "-rt", "--relax-type",
|
||||
"Selection of Smoother for AMG");
|
||||
args.AddOption(&linsolver, "-ls", "--linear-solver",
|
||||
"Selection of inner linear solver:"
|
||||
"0: mumps,"
|
||||
"1: mumps-reduced,"
|
||||
"2: PCG-AMG-reduced,"
|
||||
"3: PCG- with block-diag(AMG,direct solver)"
|
||||
"4: with static cond of contact dofs");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(¶view, "-paraview", "--paraview", "-no-paraview",
|
||||
"--no-paraview",
|
||||
"Enable or disable ParaView visualization.");
|
||||
args.AddOption(¶view_plot_every, "-plot_every", "--plot-every",
|
||||
"Output every plot_every pseudotimesteps as a paraview file");
|
||||
args.AddOption(&SQPrepeat, "-nSQPrepeat", "--nSQP-repeats", "Number of times to relinearize and resolve the SQP before incremenetally updating forcing and boundary terms");
|
||||
args.AddOption(&outputfiles, "-out", "--output", "-no-out",
|
||||
"--no-ouput",
|
||||
"Enable or disable ouput to files.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
if (Mpi::Root())
|
||||
{
|
||||
mfem::out << "Solving test problem number: " << testNo << endl;
|
||||
}
|
||||
|
||||
const char *mesh_file = nullptr;
|
||||
|
||||
switch (testNo)
|
||||
{
|
||||
case -1:
|
||||
mesh_file = "meshes/two-block.mesh";
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
MFEM_ABORT("Problem not implemented yet");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
mesh_file = "meshes/Test4.mesh";
|
||||
break;
|
||||
case 40:
|
||||
mesh_file = "meshes/Test40.mesh";
|
||||
break;
|
||||
case 41:
|
||||
mesh_file = "meshes/Test41.mesh";
|
||||
break;
|
||||
case 42:
|
||||
mesh_file = "meshes/Test42.mesh";
|
||||
break;
|
||||
case 5:
|
||||
mesh_file = "meshes/Test5.mesh";
|
||||
break;
|
||||
case 51:
|
||||
mesh_file = "meshes/Test51.mesh";
|
||||
break;
|
||||
case 6:
|
||||
mesh_file = "meshes/Test6.mesh";
|
||||
break;
|
||||
case 61:
|
||||
// Something wrong with this mesh
|
||||
mesh_file = "meshes/Test61.mesh";
|
||||
break;
|
||||
case 62:
|
||||
mesh_file = "meshes/Test62.mesh";
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Should be unreachable");
|
||||
break;
|
||||
}
|
||||
|
||||
Mesh * mesh = new Mesh(mesh_file,1);
|
||||
for (int i = 0; i<sref; i++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
ParMesh * pmesh = new ParMesh(MPI_COMM_WORLD,*mesh);
|
||||
|
||||
for (int i = 0; i<pref; i++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
Array<int> ess_bdr_attr;
|
||||
Array<int> ess_bdr_attr_comp;
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(1);
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(2);
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 62)
|
||||
{
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 40)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(10); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(6); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
ParElasticityProblem * prob = new ParElasticityProblem(pmesh,
|
||||
ess_bdr_attr,ess_bdr_attr_comp,
|
||||
order);
|
||||
Vector lambda(prob->GetMesh()->attributes.Max());
|
||||
Vector mu(prob->GetMesh()->attributes.Max());
|
||||
|
||||
if (testNo == -1 )
|
||||
{
|
||||
lambda = 57.6923076923;
|
||||
mu = 38.4615384615;
|
||||
}
|
||||
else if (testNo == 6 || testNo == 61 || testNo == 62)
|
||||
{
|
||||
lambda = (1000*0.3)/(1.3*0.4);
|
||||
mu = 500/(1.3);
|
||||
}
|
||||
else
|
||||
{
|
||||
//lambda = 57.6923076923;
|
||||
//mu = 38.4615384615;
|
||||
//lambda = 0.499 / (1.499 * 0.002);
|
||||
//mu = 1. / (2. * 1.499);
|
||||
lambda[0] = 0.499/(1.499*0.002);
|
||||
lambda[1] = 0.0;
|
||||
mu[0] = 1. / (2. * 1.499);
|
||||
mu[1] = 500.;
|
||||
}
|
||||
|
||||
prob->SetLambda(lambda); prob->SetMu(mu);
|
||||
|
||||
int dim = pmesh->Dimension();
|
||||
Vector ess_values(dim);
|
||||
int essbdr_attr;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
|
||||
ess_values = 0.0;
|
||||
|
||||
|
||||
double area = GetBdrArea(3,*mesh);
|
||||
|
||||
// ConstantCoefficient one(-area);
|
||||
ConstantCoefficient one(-1.0);
|
||||
|
||||
std::set<int> mortar_attr;
|
||||
std::set<int> nonmortar_attr;
|
||||
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[0] = 1;
|
||||
ess_bdr[1] = 1;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else if(testNo == 62)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
prob->SetNeumanData(0,3,-2.0);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (testNo == -1 || testNo == 41)
|
||||
{
|
||||
ess_values[0] = 0.1/nsteps;
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_values[2] = 1.0 / 1.4 / nsteps;
|
||||
//ess_values[2] = 0.25 / nsteps;//1.0/1.4/nsteps;
|
||||
// ess_values[0] = -2.0/nsteps;
|
||||
}
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = (testNo == 40) ? 10 : 6;
|
||||
ess_values = 0.0; ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
if (testNo == 40)
|
||||
{
|
||||
mortar_attr.insert(4);
|
||||
nonmortar_attr.insert(7);
|
||||
}
|
||||
else
|
||||
{
|
||||
mortar_attr.insert(3);
|
||||
nonmortar_attr.insert(4);
|
||||
}
|
||||
}
|
||||
|
||||
ParFiniteElementSpace * fes = prob->GetFESpace();
|
||||
ParGridFunction x_gf(fes); x_gf = 0.0;
|
||||
ParGridFunction xnew(fes); xnew = 0.0;
|
||||
ParaViewDataCollection * paraview_dc = nullptr;
|
||||
ParMesh pmesh_copy(*pmesh);
|
||||
ParFiniteElementSpace fes_copy(*fes,pmesh_copy);
|
||||
ParGridFunction xcopy_gf(&fes_copy); xcopy_gf = 0.0;
|
||||
|
||||
if (paraview)
|
||||
{
|
||||
std::ostringstream paraview_file_name;
|
||||
paraview_file_name << "QPContact-Test_" << testNo
|
||||
<< "_par_ref_" << pref
|
||||
<< "_ser_ref_" << sref;
|
||||
paraview_dc = new ParaViewDataCollection(paraview_file_name.str(), &pmesh_copy);
|
||||
paraview_dc->SetPrefixPath("ParaView");
|
||||
paraview_dc->SetLevelsOfDetail(1);
|
||||
paraview_dc->SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc->SetHighOrderOutput(true);
|
||||
// paraview_dc->RegisterField("u", &x_gf);
|
||||
paraview_dc->RegisterField("u", &xcopy_gf);
|
||||
paraview_dc->SetCycle(0);
|
||||
paraview_dc->SetTime(double(0));
|
||||
paraview_dc->Save();
|
||||
}
|
||||
socketstream sol_sock;
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
sol_sock.open(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
}
|
||||
// ParGridFunction coords(prob->GetFESpace());
|
||||
ParGridFunction ref_coords(prob->GetFESpace());
|
||||
ParGridFunction new_coords(prob->GetFESpace());
|
||||
pmesh->GetNodes(new_coords);
|
||||
pmesh->GetNodes(ref_coords);
|
||||
|
||||
Vector xref(x_gf.GetTrueVector().Size());
|
||||
|
||||
HypreParMatrix *dgdu;
|
||||
double p = 1;
|
||||
ConstantCoefficient f(p);
|
||||
|
||||
// SQPrepeat solves on same problem (forcing/boundary conditions)
|
||||
int Nsteps = nsteps * SQPrepeat;
|
||||
|
||||
double pseudotime = 0.0;
|
||||
double pseudotimestep = 1.0 / ((double) nsteps);
|
||||
double paraview_time = 0.0;
|
||||
double paraview_subtimestep = pseudotimestep / ((double) SQPrepeat);
|
||||
int paraview_cycle = 1;
|
||||
|
||||
bool QPConverged;
|
||||
|
||||
std::ofstream numConstraintsStream;
|
||||
std::ostringstream numConstraints_file_name;
|
||||
numConstraints_file_name << "data/numConstraints_ref" << sref << ".dat";
|
||||
if (Mpi::Root)
|
||||
{
|
||||
numConstraintsStream.open(numConstraints_file_name.str(), ios::out | ios::trunc);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nsteps; i++)
|
||||
{
|
||||
pseudotime = ((double) (i + 1)) / ((double) nsteps);
|
||||
for (int j = 0; j < SQPrepeat; j++)
|
||||
{
|
||||
paraview_time = pseudotime + j * paraview_subtimestep;
|
||||
if (testNo == 6)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
f.constant = -p * pseudotime;
|
||||
prob->SetNeumanPressureData(f,ess_bdr);
|
||||
// prob->SetNeumanData(0,3,-p*(i+1)/nsteps);
|
||||
}
|
||||
else if (testNo == 4 || testNo == 40 || testNo == 5 || testNo == 51)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
ess_values = 0.0;
|
||||
//ess_values[2] = 4.0 / 7.0 * pseudotime;
|
||||
//ess_values[2] = 0.25 * pseudotime; //1.0/1.4 * pseudotime;
|
||||
ess_values[2] = 1.0 / 1.4 * pseudotime;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
else if (testNo == 41)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_values[0] = 0.5 * pseudotime; //0.5/nsteps*(i+1);
|
||||
// ess_values[0] = 0.0;
|
||||
essbdr_attr = 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = 6;
|
||||
ess_values = 0.0;
|
||||
// ess_values[0] = -0.5/nsteps*(i+1);
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "ess_values[0] = " << ess_values[0] << endl;
|
||||
}
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
|
||||
//xref.Set(1.0, x_gf.GetTrueVector());
|
||||
xref = 0.0;
|
||||
ParContactProblem contact(prob, mortar_attr, nonmortar_attr, &new_coords, doublepass);
|
||||
QPOptParContactProblem qpopt(&contact, xref);
|
||||
int numconstr = contact.GetGlobalNumConstraints();
|
||||
ParInteriorPointSolver optimizer(&qpopt);
|
||||
optimizer.SetTol(optimizer_tol);
|
||||
optimizer.SetMaxIter(optimizer_maxit);
|
||||
optimizer.SetLinearSolver(linsolver);
|
||||
optimizer.SetLinearSolveRelTol(linsolverrtol);
|
||||
optimizer.SetLinearSolveAbsTol(linsolveratol);
|
||||
optimizer.SetLinearSolveRelaxType(relax_type);
|
||||
if (nocontact)
|
||||
{
|
||||
optimizer.EnableNoContactSolve();
|
||||
}
|
||||
if (elast)
|
||||
{
|
||||
optimizer.SetElasticityOptions(prob->GetFESpace());
|
||||
}
|
||||
// ParGridFunction x = prob->GetDisplacementGridFunction();
|
||||
// x.SetTrueVector();
|
||||
// Vector x0 = x.GetTrueVector();
|
||||
|
||||
x_gf.SetTrueVector();
|
||||
|
||||
|
||||
Vector x0 = x_gf.GetTrueVector();
|
||||
int ndofs = x0.Size();
|
||||
Vector xf(ndofs); xf = 0.0;
|
||||
optimizer.Mult(x0, xf);
|
||||
QPConverged = optimizer.GetConverged();
|
||||
|
||||
/* exit if not converged */
|
||||
MFEM_VERIFY(QPConverged, "IPM not converged on QP contact problem");
|
||||
|
||||
|
||||
double Einitial = contact.E(x0);
|
||||
double Efinal = contact.E(xf);
|
||||
Array<int> & CGiterations = optimizer.GetCGIterNumbers();
|
||||
int gndofs = prob->GetGlobalNumDofs();
|
||||
int gnconstraints = contact.GetGlobalNumConstraints();
|
||||
|
||||
//std::ofstream xfStream;
|
||||
//std::ostringstream xf_file_name;
|
||||
//xf_file_name << "data/xf_" << i << ".dat";
|
||||
//if (Mpi::Root())
|
||||
//{
|
||||
// xfStream.open(xf_file_name.str(), ios::out | ios::trunc);
|
||||
// for (int ii = 0; ii < xf.Size(); ii++)
|
||||
// {
|
||||
// xfStream << xf(ii) << "\n";
|
||||
// }
|
||||
// xfStream.close();
|
||||
//}
|
||||
//if (Mpi::Root)
|
||||
//{
|
||||
// numConstraintsStream.open(numConstraints_file_name.str(), ios::out | ios::trunc);
|
||||
//}
|
||||
|
||||
|
||||
if (Mpi::Root())
|
||||
{
|
||||
|
||||
mfem::out << endl;
|
||||
mfem::out << " Initial Energy objective = " << Einitial << endl;
|
||||
mfem::out << " Final Energy objective = " << Efinal << endl;
|
||||
mfem::out << " Global number of dofs = " << gndofs << endl;
|
||||
mfem::out << " Global number of constraints = " << numconstr << endl;
|
||||
mfem::out << " Optimizer number of iterations = " <<
|
||||
optimizer.GetNumIterations() << endl;
|
||||
if (linsolver == 2 || linsolver == 3 || linsolver == 4)
|
||||
{
|
||||
mfem::out << " CG iteration numbers = " ;
|
||||
CGiterations.Print(mfem::out, CGiterations.Size());
|
||||
}
|
||||
if (nocontact)
|
||||
{
|
||||
Array<int> & CGNoContactIterations = optimizer.GetCGNoContactIterNumbers();
|
||||
mfem::out << " CG no Contact iteration numbers = " ;
|
||||
CGNoContactIterations.Print(mfem::out, CGNoContactIterations.Size());
|
||||
}
|
||||
if (outputfiles)
|
||||
{
|
||||
ostringstream file_name;
|
||||
file_name << "output/Testno-"<<testNo<<"-ref-"<<sref+pref << "-step-" << i;
|
||||
OutputData(file_name, Einitial, Efinal, gndofs,numconstr, optimizer.GetNumIterations(), CGiterations);
|
||||
}
|
||||
numConstraintsStream << gnconstraints << endl;
|
||||
}
|
||||
|
||||
// Vector X_new(xf.GetData(),fes->GetTrueVSize());
|
||||
// xnew.SetFromTrueDofs(X_new);
|
||||
// x_gf = xnew;
|
||||
x_gf.SetFromTrueDofs(xf);
|
||||
// mfem::out << "x_gf norm = " << x_gf.Norml2() << endl;
|
||||
// cin.get();
|
||||
// pmesh->MoveNodes(xnew);
|
||||
// pmesh_copy.MoveNodes(xnew);
|
||||
// pmesh_copy.MoveNodes(xnew);
|
||||
add(ref_coords,x_gf,new_coords);
|
||||
// mfem::out << " ref_coords norm " << ref_coords.Norml2() << endl;
|
||||
// mfem::out << " x_gf norm " << x_gf.Norml2() << endl;
|
||||
// mfem::out << " new_coords norm " << new_coords.Norml2() << endl;
|
||||
// pmesh_copy.SetNodes(new_coords);
|
||||
pmesh_copy.SetNodes(new_coords);
|
||||
xcopy_gf = x_gf;
|
||||
// pmesh_copy.MoveNodes(x_gf);
|
||||
// pmesh_copy.SetNodes(x_gf);
|
||||
if (paraview && ((i+1) % paraview_plot_every == 0 ))
|
||||
{
|
||||
paraview_cycle += 1;
|
||||
paraview_dc->SetCycle(paraview_cycle) ;
|
||||
paraview_dc->SetTime(paraview_time);
|
||||
paraview_dc->Save();
|
||||
}
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n"
|
||||
<< "solution\n" << pmesh_copy << x_gf << flush;
|
||||
|
||||
if (i == nsteps - 1 && j == SQPrepeat - 1)
|
||||
{
|
||||
pmesh->MoveNodes(x_gf);
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock1(vishost, visport);
|
||||
sol_sock1 << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock1.precision(8);
|
||||
sol_sock1 << "solution\n" << *pmesh << x_gf << flush;
|
||||
}
|
||||
}
|
||||
if (i == nsteps - 1 && j == SQPrepeat) break;
|
||||
|
||||
prob->UpdateStep();
|
||||
if (testNo == 6 )
|
||||
{
|
||||
double area_new = GetBdrArea(3,*pmesh);
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "New area = " << area_new << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Mpi::Root)
|
||||
{
|
||||
numConstraintsStream.close();
|
||||
}
|
||||
delete prob;
|
||||
delete pmesh;
|
||||
delete mesh;
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,114 +0,0 @@
|
||||
#include "mfem.hpp"
|
||||
#include "../problems/parproblems.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
|
||||
#ifndef PARIPSOLVER
|
||||
#define PARIPSOLVER
|
||||
|
||||
class ParInteriorPointSolver
|
||||
{
|
||||
protected:
|
||||
QPOptParContactProblem* problem = nullptr;
|
||||
double OptTol;
|
||||
int max_iter;
|
||||
int iter=0;
|
||||
double mu_k; // \mu_k
|
||||
Vector lk, zlk;
|
||||
|
||||
double sMax, kSig, tauMin, eta, thetaMin, delta, sTheta, sPhi, kMu, thetaMu;
|
||||
double thetaMax, kSoc, gTheta, gPhi, kEps;
|
||||
|
||||
// filter
|
||||
Array<double> F1, F2;
|
||||
|
||||
// quantities computed in lineSearch
|
||||
double alpha, alphaz;
|
||||
double thx0, thxtrial;
|
||||
double phx0, phxtrial;
|
||||
bool descentDirection, switchCondition, sufficientDecrease, lineSearchSuccess, inFilterRegion;
|
||||
double Dxphi0_xhat;
|
||||
|
||||
int dimU, dimM, dimC;
|
||||
int gdimU, gdimM, gdimC;
|
||||
Array<int> block_offsetsumlz, block_offsetsuml, block_offsetsx;
|
||||
Vector ml;
|
||||
|
||||
Vector ckSoc;
|
||||
HypreParMatrix * Huu = nullptr;
|
||||
HypreParMatrix * Hum = nullptr;
|
||||
HypreParMatrix * Hmu = nullptr;
|
||||
HypreParMatrix * Hmm = nullptr;
|
||||
HypreParMatrix * Wmm = nullptr;
|
||||
HypreParMatrix * Ju = nullptr;
|
||||
HypreParMatrix * Jm = nullptr;
|
||||
HypreParMatrix * JuT = nullptr;
|
||||
HypreParMatrix * JmT = nullptr;
|
||||
|
||||
Array<int> cgnum_iterations;
|
||||
Array<int> cgnum_iterations_nocontact;
|
||||
ParFiniteElementSpace *pfes = nullptr;
|
||||
|
||||
int jOpt;
|
||||
bool converged;
|
||||
|
||||
int MyRank;
|
||||
bool iAmRoot;
|
||||
|
||||
bool saveLogBarrierIterates = false;
|
||||
|
||||
int linSolver=0;
|
||||
double linSolveAbsTol = 1e-12;
|
||||
double linSolveRelTol = 1e-6;
|
||||
int relax_type = 8;
|
||||
bool nocontact = false;
|
||||
public:
|
||||
ParInteriorPointSolver(QPOptParContactProblem*);
|
||||
double MaxStepSize(Vector& , Vector& , Vector& , double);
|
||||
double MaxStepSize(Vector& , Vector& , double);
|
||||
void Mult(const BlockVector& , BlockVector&);
|
||||
void Mult(const Vector&, Vector &);
|
||||
void FormIPNewtonMat(BlockVector& , Vector& , Vector& , BlockOperator &);
|
||||
void IPNewtonSolve(BlockVector& , Vector& , Vector& , Vector&, BlockVector& , double, bool);
|
||||
void lineSearch(BlockVector& , BlockVector& , double);
|
||||
void projectZ(const Vector & , Vector &, double);
|
||||
void filterCheck(double, double);
|
||||
double E(const BlockVector &, const Vector &, const Vector &, double, bool);
|
||||
double E(const BlockVector &, const Vector &, const Vector &, bool);
|
||||
bool GetConverged() const;
|
||||
Array<int> & GetCGIterNumbers() {return cgnum_iterations;}
|
||||
Array<int> & GetCGNoContactIterNumbers() {return cgnum_iterations_nocontact;}
|
||||
int GetNumIterations() {return iter;}
|
||||
// TO DO: include Hessian of Lagrangian
|
||||
double theta(const BlockVector &);
|
||||
double phi(const BlockVector &, double);
|
||||
void Dxphi(const BlockVector &, double, BlockVector &);
|
||||
double L(const BlockVector &, const Vector &, const Vector &);
|
||||
void DxL(const BlockVector &, const Vector &, const Vector &, BlockVector &);
|
||||
void SetTol(double);
|
||||
void SetMaxIter(int);
|
||||
void SetBarrierParameter(double);
|
||||
void SaveLogBarrierHessianIterates(bool);
|
||||
void SaveLambda(int);
|
||||
void SaveZl(int);
|
||||
void SetLinearSolver(int);
|
||||
void SetLinearSolveAbsTol(double);
|
||||
void SetLinearSolveRelTol(double);
|
||||
void SetLinearSolveRelaxType(int);
|
||||
|
||||
void SetElasticityOptions(ParFiniteElementSpace * pfes_)
|
||||
{
|
||||
pfes = pfes_;
|
||||
}
|
||||
void EnableNoContactSolve()
|
||||
{
|
||||
nocontact = true;
|
||||
}
|
||||
virtual ~ParInteriorPointSolver();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,109 +0,0 @@
|
||||
# Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
|
||||
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
# LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
#
|
||||
# This file is part of the MFEM library. For more information and source code
|
||||
# availability visit https://mfem.org.
|
||||
#
|
||||
# MFEM is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/contact/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
|
||||
# Include defaults.mk to get XLINKER
|
||||
#DEFAULTS_MK = $(MFEM_DIR)/config/defaults.mk
|
||||
#include $(DEFAULTS_MK)
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
FRAMEWORK_SRC = ipsolver/ParIPsolver.cpp problems/parproblems.cpp problems/parproblems_util.cpp
|
||||
CONTACT_SRC = contact.cpp $(FRAMEWORK_SRC)
|
||||
CONTACT_OBJ = $(CONTACT_SRC:.cpp=.o)
|
||||
|
||||
CONTACT_FDCHECK_SRC = contactFDcheck.cpp $(FRAMEWORK_SRC)
|
||||
CONTACT_FDCHECK_OBJ = $(CONTACT_FDCHECK_SRC:.cpp=.o)
|
||||
|
||||
SCRATCH_SRC = scratch.cpp $(FRAMEWORK_SRC)
|
||||
SCRATCH_OBJ = $(SCRATCH_SRC:.cpp=.o)
|
||||
|
||||
|
||||
SEQ_MINIAPPS =
|
||||
PAR_MINIAPPS = scratch contact contactFDcheck
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
MINIAPPS = $(SEQ_MINIAPPS)
|
||||
else
|
||||
MINIAPPS = $(PAR_MINIAPPS) $(SEQ_MINIAPPS)
|
||||
endif
|
||||
|
||||
COMMON_LIB = -L$(MFEM_BUILD_DIR)/miniapps/common -lmfem-common
|
||||
|
||||
# If MFEM_SHARED is set, add the ../common rpath
|
||||
COMMON_LIB += $(if $(MFEM_SHARED:YES=),,\
|
||||
$(if $(MFEM_USE_CUDA:YES=),$(CXX_XLINKER),$(CUDA_XLINKER))-rpath,$(abspath\
|
||||
$(MFEM_BUILD_DIR)/miniapps/common))
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .cpp .mk
|
||||
.PHONY: all lib-common clean clean-build clean-exec
|
||||
|
||||
# Remove built-in rule
|
||||
%: %.cpp
|
||||
%.o: %.cpp
|
||||
|
||||
%.o: $(SRC)%.cpp $(wildcard $(SRC)%.hpp) $(MFEM_LIB_FILE)\
|
||||
$(CONFIG_MK) | lib-common
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@
|
||||
|
||||
problems/%.o: $(SRC)problems/%.cpp $(wildcard $(SRC)problems/%.hpp) $(MFEM_LIB_FILE)\
|
||||
$(CONFIG_MK) | lib-common
|
||||
mkdir -p $(@D)
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@
|
||||
|
||||
|
||||
all: $(MINIAPPS)
|
||||
|
||||
contact: $(CONTACT_OBJ)
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(CONTACT_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
|
||||
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
|
||||
|
||||
contactFDcheck: $(CONTACT_FDCHECK_OBJ)
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(CONTACT_FDCHECK_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
|
||||
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
|
||||
|
||||
scratch: $(SCRATCH_OBJ)
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(SCRATCH_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
|
||||
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
|
||||
|
||||
|
||||
# Rule for building lib-common
|
||||
lib-common:
|
||||
$(MAKE) -C $(MFEM_BUILD_DIR)/miniapps/common
|
||||
|
||||
MFEM_TESTS = MINIAPPS
|
||||
include $(MFEM_TEST_MK)
|
||||
|
||||
# Testing: Specific execution options
|
||||
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
|
||||
contact-test-par: contact
|
||||
@$(call mfem-test,$<, $(RUN_MPI), pcontact miniapp,)
|
||||
|
||||
# Generate an error message if the MFEM library is not built and exit
|
||||
$(MFEM_LIB_FILE):
|
||||
$(error The MFEM library is not built)
|
||||
|
||||
clean: clean-build clean-exec
|
||||
|
||||
clean-build:
|
||||
rm -f *.o *~ $(PAR_MINIAPPS) $(SEQ_MINIAPPS)
|
||||
rm -f $(CONTACT_OBJ)
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
clean-exec:
|
||||
@rm -rf ParaView
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,453 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
# PYRAMID = 7
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
89
|
||||
1 5 0 1 5 4 40 41 45 44
|
||||
1 5 40 41 45 44 80 81 85 84
|
||||
1 5 44 45 49 48 84 85 89 88
|
||||
1 5 4 5 9 8 44 45 49 48
|
||||
1 5 5 6 10 9 45 46 50 49
|
||||
1 5 45 46 50 49 85 86 90 89
|
||||
1 5 41 42 46 45 81 82 86 85
|
||||
1 5 1 2 6 5 41 42 46 45
|
||||
1 5 2 3 7 6 42 43 47 46
|
||||
1 5 42 43 47 46 82 83 87 86
|
||||
1 5 6 7 11 10 46 47 51 50
|
||||
1 5 46 47 51 50 86 87 91 90
|
||||
1 5 86 87 91 90 126 127 131 130
|
||||
1 5 82 83 87 86 122 123 127 126
|
||||
1 5 81 82 86 85 121 122 126 125
|
||||
1 5 80 81 85 84 120 121 125 124
|
||||
1 5 84 85 89 88 124 125 129 128
|
||||
1 5 85 86 90 89 125 126 130 129
|
||||
1 5 89 90 94 93 129 130 134 133
|
||||
1 5 88 89 93 92 128 129 133 132
|
||||
1 5 92 93 97 96 132 133 137 136
|
||||
1 5 93 94 98 97 133 134 138 137
|
||||
1 5 94 95 99 98 134 135 139 138
|
||||
1 5 54 55 59 58 94 95 99 98
|
||||
1 5 90 91 95 94 130 131 135 134
|
||||
1 5 50 51 55 54 90 91 95 94
|
||||
1 5 10 11 15 14 50 51 55 54
|
||||
1 5 14 15 19 18 54 55 59 58
|
||||
1 5 13 14 18 17 53 54 58 57
|
||||
1 5 53 54 58 57 93 94 98 97
|
||||
1 5 49 50 54 53 89 90 94 93
|
||||
1 5 9 10 14 13 49 50 54 53
|
||||
1 5 8 9 13 12 48 49 53 52
|
||||
1 5 48 49 53 52 88 89 93 92
|
||||
1 5 52 53 57 56 92 93 97 96
|
||||
1 5 12 13 17 16 52 53 57 56
|
||||
1 5 16 17 21 20 56 57 61 60
|
||||
1 5 56 57 61 60 96 97 101 100
|
||||
1 5 57 58 62 61 97 98 102 101
|
||||
1 5 17 18 22 21 57 58 62 61
|
||||
1 5 18 19 23 22 58 59 63 62
|
||||
1 5 58 59 63 62 98 99 103 102
|
||||
1 5 98 99 103 102 138 139 143 142
|
||||
1 5 97 98 102 101 137 138 142 141
|
||||
1 5 96 97 101 100 136 137 141 140
|
||||
1 5 100 101 105 104 140 141 145 144
|
||||
1 5 101 102 106 105 141 142 146 145
|
||||
1 5 102 103 107 106 142 143 147 146
|
||||
1 5 62 63 67 66 102 103 107 106
|
||||
1 5 22 23 27 26 62 63 67 66
|
||||
1 5 21 22 26 25 61 62 66 65
|
||||
1 5 61 62 66 65 101 102 106 105
|
||||
1 5 60 61 65 64 100 101 105 104
|
||||
1 5 20 21 25 24 60 61 65 64
|
||||
1 5 24 25 29 28 64 65 69 68
|
||||
1 5 64 65 69 68 104 105 109 108
|
||||
1 5 68 69 73 72 108 109 113 112
|
||||
1 5 28 29 33 32 68 69 73 72
|
||||
1 5 29 30 34 33 69 70 74 73
|
||||
1 5 69 70 74 73 109 110 114 113
|
||||
1 5 65 66 70 69 105 106 110 109
|
||||
1 5 25 26 30 29 65 66 70 69
|
||||
1 5 26 27 31 30 66 67 71 70
|
||||
1 5 66 67 71 70 106 107 111 110
|
||||
1 5 30 31 35 34 70 71 75 74
|
||||
1 5 70 71 75 74 110 111 115 114
|
||||
1 5 110 111 115 114 150 151 155 154
|
||||
1 5 106 107 111 110 146 147 151 150
|
||||
1 5 105 106 110 109 145 146 150 149
|
||||
1 5 109 110 114 113 149 150 154 153
|
||||
1 5 104 105 109 108 144 145 149 148
|
||||
1 5 108 109 113 112 148 149 153 152
|
||||
1 5 112 113 117 116 152 153 157 156
|
||||
1 5 113 114 118 117 153 154 158 157
|
||||
1 5 114 115 119 118 154 155 159 158
|
||||
1 5 74 75 79 78 114 115 119 118
|
||||
1 5 34 35 39 38 74 75 79 78
|
||||
1 5 33 34 38 37 73 74 78 77
|
||||
1 5 73 74 78 77 113 114 118 117
|
||||
1 5 72 73 77 76 112 113 117 116
|
||||
1 5 32 33 37 36 72 73 77 76
|
||||
2 5 160 161 164 163 169 170 173 172
|
||||
2 5 163 164 167 166 172 173 176 175
|
||||
2 5 172 173 176 175 181 182 185 184
|
||||
2 5 169 170 173 172 178 179 182 181
|
||||
2 5 170 171 174 173 179 180 183 182
|
||||
2 5 173 174 177 176 182 183 186 185
|
||||
2 5 164 165 168 167 173 174 177 176
|
||||
2 5 161 162 165 164 170 171 174 173
|
||||
|
||||
boundary
|
||||
150
|
||||
1 3 0 4 5 1
|
||||
1 3 1 5 6 2
|
||||
1 3 2 6 7 3
|
||||
1 3 4 8 9 5
|
||||
1 3 5 9 10 6
|
||||
1 3 6 10 11 7
|
||||
1 3 8 12 13 9
|
||||
1 3 9 13 14 10
|
||||
1 3 10 14 15 11
|
||||
1 3 12 16 17 13
|
||||
1 3 13 17 18 14
|
||||
1 3 14 18 19 15
|
||||
1 3 16 20 21 17
|
||||
1 3 17 21 22 18
|
||||
1 3 18 22 23 19
|
||||
1 3 20 24 25 21
|
||||
1 3 21 25 26 22
|
||||
1 3 22 26 27 23
|
||||
1 3 24 28 29 25
|
||||
1 3 25 29 30 26
|
||||
1 3 26 30 31 27
|
||||
1 3 28 32 33 29
|
||||
1 3 29 33 34 30
|
||||
1 3 30 34 35 31
|
||||
1 3 32 36 37 33
|
||||
1 3 33 37 38 34
|
||||
1 3 34 38 39 35
|
||||
1 3 120 121 125 124
|
||||
1 3 121 122 126 125
|
||||
1 3 122 123 127 126
|
||||
1 3 124 125 129 128
|
||||
1 3 125 126 130 129
|
||||
1 3 126 127 131 130
|
||||
1 3 128 129 133 132
|
||||
1 3 129 130 134 133
|
||||
1 3 130 131 135 134
|
||||
1 3 132 133 137 136
|
||||
1 3 133 134 138 137
|
||||
1 3 134 135 139 138
|
||||
1 3 136 137 141 140
|
||||
1 3 137 138 142 141
|
||||
1 3 138 139 143 142
|
||||
1 3 140 141 145 144
|
||||
1 3 141 142 146 145
|
||||
1 3 142 143 147 146
|
||||
1 3 144 145 149 148
|
||||
1 3 145 146 150 149
|
||||
1 3 146 147 151 150
|
||||
1 3 148 149 153 152
|
||||
1 3 149 150 154 153
|
||||
1 3 150 151 155 154
|
||||
1 3 152 153 157 156
|
||||
1 3 153 154 158 157
|
||||
1 3 154 155 159 158
|
||||
2 3 0 40 44 4
|
||||
2 3 4 44 48 8
|
||||
2 3 8 48 52 12
|
||||
2 3 12 52 56 16
|
||||
2 3 16 56 60 20
|
||||
2 3 20 60 64 24
|
||||
2 3 24 64 68 28
|
||||
2 3 28 68 72 32
|
||||
2 3 32 72 76 36
|
||||
2 3 40 80 84 44
|
||||
2 3 44 84 88 48
|
||||
2 3 48 88 92 52
|
||||
2 3 52 92 96 56
|
||||
2 3 56 96 100 60
|
||||
2 3 60 100 104 64
|
||||
2 3 64 104 108 68
|
||||
2 3 68 108 112 72
|
||||
2 3 72 112 116 76
|
||||
2 3 80 120 124 84
|
||||
2 3 84 124 128 88
|
||||
2 3 88 128 132 92
|
||||
2 3 92 132 136 96
|
||||
2 3 96 136 140 100
|
||||
2 3 100 140 144 104
|
||||
2 3 104 144 148 108
|
||||
2 3 108 148 152 112
|
||||
2 3 112 152 156 116
|
||||
3 3 3 7 47 43
|
||||
3 3 7 11 51 47
|
||||
3 3 11 15 55 51
|
||||
3 3 15 19 59 55
|
||||
3 3 19 23 63 59
|
||||
3 3 23 27 67 63
|
||||
3 3 27 31 71 67
|
||||
3 3 31 35 75 71
|
||||
3 3 35 39 79 75
|
||||
3 3 43 47 87 83
|
||||
3 3 47 51 91 87
|
||||
3 3 51 55 95 91
|
||||
3 3 55 59 99 95
|
||||
3 3 59 63 103 99
|
||||
3 3 63 67 107 103
|
||||
3 3 67 71 111 107
|
||||
3 3 71 75 115 111
|
||||
3 3 75 79 119 115
|
||||
3 3 83 87 127 123
|
||||
3 3 87 91 131 127
|
||||
3 3 91 95 135 131
|
||||
3 3 95 99 139 135
|
||||
3 3 99 103 143 139
|
||||
3 3 103 107 147 143
|
||||
3 3 107 111 151 147
|
||||
3 3 111 115 155 151
|
||||
3 3 115 119 159 155
|
||||
1 3 0 1 41 40
|
||||
1 3 40 41 81 80
|
||||
1 3 80 81 121 120
|
||||
1 3 1 2 42 41
|
||||
1 3 41 42 82 81
|
||||
1 3 81 82 122 121
|
||||
1 3 2 3 43 42
|
||||
1 3 42 43 83 82
|
||||
1 3 82 83 123 122
|
||||
1 3 36 76 77 37
|
||||
1 3 76 116 117 77
|
||||
1 3 116 156 157 117
|
||||
1 3 37 77 78 38
|
||||
1 3 77 117 118 78
|
||||
1 3 117 157 158 118
|
||||
1 3 38 78 79 39
|
||||
1 3 78 118 119 79
|
||||
1 3 118 158 159 119
|
||||
5 3 160 163 164 161
|
||||
5 3 161 164 165 162
|
||||
5 3 163 166 167 164
|
||||
5 3 164 167 168 165
|
||||
5 3 178 179 182 181
|
||||
5 3 179 180 183 182
|
||||
5 3 181 182 185 184
|
||||
5 3 182 183 186 185
|
||||
4 3 160 169 172 163
|
||||
4 3 163 172 175 166
|
||||
4 3 169 178 181 172
|
||||
4 3 172 181 184 175
|
||||
6 3 162 165 174 171
|
||||
6 3 165 168 177 174
|
||||
6 3 171 174 183 180
|
||||
6 3 174 177 186 183
|
||||
5 3 160 161 170 169
|
||||
5 3 169 170 179 178
|
||||
5 3 161 162 171 170
|
||||
5 3 170 171 180 179
|
||||
5 3 166 175 176 167
|
||||
5 3 175 184 185 176
|
||||
5 3 167 176 177 168
|
||||
5 3 176 185 186 177
|
||||
|
||||
vertices
|
||||
187
|
||||
3
|
||||
-1 0 0
|
||||
-0.66666667 0 0
|
||||
-0.33333333 0 0
|
||||
0 0 0
|
||||
-1 0.33333333 0
|
||||
-0.66666667 0.33333333 0
|
||||
-0.33333333 0.33333333 0
|
||||
0 0.33333333 0
|
||||
-1 0.66666667 0
|
||||
-0.66666667 0.66666667 0
|
||||
-0.33333333 0.66666667 0
|
||||
0 0.66666667 0
|
||||
-1 1 0
|
||||
-0.66666667 1 0
|
||||
-0.33333333 1 0
|
||||
0 1 0
|
||||
-1 1.3333333 0
|
||||
-0.66666667 1.3333333 0
|
||||
-0.33333333 1.3333333 0
|
||||
0 1.3333333 0
|
||||
-1 1.6666667 0
|
||||
-0.66666667 1.6666667 0
|
||||
-0.33333333 1.6666667 0
|
||||
0 1.6666667 0
|
||||
-1 2 0
|
||||
-0.66666667 2 0
|
||||
-0.33333333 2 0
|
||||
0 2 0
|
||||
-1 2.3333333 0
|
||||
-0.66666667 2.3333333 0
|
||||
-0.33333333 2.3333333 0
|
||||
0 2.3333333 0
|
||||
-1 2.6666667 0
|
||||
-0.66666667 2.6666667 0
|
||||
-0.33333333 2.6666667 0
|
||||
0 2.6666667 0
|
||||
-1 3 0
|
||||
-0.66666667 3 0
|
||||
-0.33333333 3 0
|
||||
0 3 0
|
||||
-1 0 0.33333333
|
||||
-0.66666667 0 0.33333333
|
||||
-0.33333333 0 0.33333333
|
||||
0 0 0.33333333
|
||||
-1 0.33333333 0.33333333
|
||||
-0.66666667 0.33333333 0.33333333
|
||||
-0.33333333 0.33333333 0.33333333
|
||||
0 0.33333333 0.33333333
|
||||
-1 0.66666667 0.33333333
|
||||
-0.66666667 0.66666667 0.33333333
|
||||
-0.33333333 0.66666667 0.33333333
|
||||
0 0.66666667 0.33333333
|
||||
-1 1 0.33333333
|
||||
-0.66666667 1 0.33333333
|
||||
-0.33333333 1 0.33333333
|
||||
0 1 0.33333333
|
||||
-1 1.3333333 0.33333333
|
||||
-0.66666667 1.3333333 0.33333333
|
||||
-0.33333333 1.3333333 0.33333333
|
||||
0 1.3333333 0.33333333
|
||||
-1 1.6666667 0.33333333
|
||||
-0.66666667 1.6666667 0.33333333
|
||||
-0.33333333 1.6666667 0.33333333
|
||||
0 1.6666667 0.33333333
|
||||
-1 2 0.33333333
|
||||
-0.66666667 2 0.33333333
|
||||
-0.33333333 2 0.33333333
|
||||
0 2 0.33333333
|
||||
-1 2.3333333 0.33333333
|
||||
-0.66666667 2.3333333 0.33333333
|
||||
-0.33333333 2.3333333 0.33333333
|
||||
0 2.3333333 0.33333333
|
||||
-1 2.6666667 0.33333333
|
||||
-0.66666667 2.6666667 0.33333333
|
||||
-0.33333333 2.6666667 0.33333333
|
||||
0 2.6666667 0.33333333
|
||||
-1 3 0.33333333
|
||||
-0.66666667 3 0.33333333
|
||||
-0.33333333 3 0.33333333
|
||||
0 3 0.33333333
|
||||
-1 0 0.66666667
|
||||
-0.66666667 0 0.66666667
|
||||
-0.33333333 0 0.66666667
|
||||
0 0 0.66666667
|
||||
-1 0.33333333 0.66666667
|
||||
-0.66666667 0.33333333 0.66666667
|
||||
-0.33333333 0.33333333 0.66666667
|
||||
0 0.33333333 0.66666667
|
||||
-1 0.66666667 0.66666667
|
||||
-0.66666667 0.66666667 0.66666667
|
||||
-0.33333333 0.66666667 0.66666667
|
||||
0 0.66666667 0.66666667
|
||||
-1 1 0.66666667
|
||||
-0.66666667 1 0.66666667
|
||||
-0.33333333 1 0.66666667
|
||||
0 1 0.66666667
|
||||
-1 1.3333333 0.66666667
|
||||
-0.66666667 1.3333333 0.66666667
|
||||
-0.33333333 1.3333333 0.66666667
|
||||
0 1.3333333 0.66666667
|
||||
-1 1.6666667 0.66666667
|
||||
-0.66666667 1.6666667 0.66666667
|
||||
-0.33333333 1.6666667 0.66666667
|
||||
0 1.6666667 0.66666667
|
||||
-1 2 0.66666667
|
||||
-0.66666667 2 0.66666667
|
||||
-0.33333333 2 0.66666667
|
||||
0 2 0.66666667
|
||||
-1 2.3333333 0.66666667
|
||||
-0.66666667 2.3333333 0.66666667
|
||||
-0.33333333 2.3333333 0.66666667
|
||||
0 2.3333333 0.66666667
|
||||
-1 2.6666667 0.66666667
|
||||
-0.66666667 2.6666667 0.66666667
|
||||
-0.33333333 2.6666667 0.66666667
|
||||
0 2.6666667 0.66666667
|
||||
-1 3 0.66666667
|
||||
-0.66666667 3 0.66666667
|
||||
-0.33333333 3 0.66666667
|
||||
0 3 0.66666667
|
||||
-1 0 1
|
||||
-0.66666667 0 1
|
||||
-0.33333333 0 1
|
||||
0 0 1
|
||||
-1 0.33333333 1
|
||||
-0.66666667 0.33333333 1
|
||||
-0.33333333 0.33333333 1
|
||||
0 0.33333333 1
|
||||
-1 0.66666667 1
|
||||
-0.66666667 0.66666667 1
|
||||
-0.33333333 0.66666667 1
|
||||
0 0.66666667 1
|
||||
-1 1 1
|
||||
-0.66666667 1 1
|
||||
-0.33333333 1 1
|
||||
0 1 1
|
||||
-1 1.3333333 1
|
||||
-0.66666667 1.3333333 1
|
||||
-0.33333333 1.3333333 1
|
||||
0 1.3333333 1
|
||||
-1 1.6666667 1
|
||||
-0.66666667 1.6666667 1
|
||||
-0.33333333 1.6666667 1
|
||||
0 1.6666667 1
|
||||
-1 2 1
|
||||
-0.66666667 2 1
|
||||
-0.33333333 2 1
|
||||
0 2 1
|
||||
-1 2.3333333 1
|
||||
-0.66666667 2.3333333 1
|
||||
-0.33333333 2.3333333 1
|
||||
0 2.3333333 1
|
||||
-1 2.6666667 1
|
||||
-0.66666667 2.6666667 1
|
||||
-0.33333333 2.6666667 1
|
||||
0 2.6666667 1
|
||||
-1 3 1
|
||||
-0.66666667 3 1
|
||||
-0.33333333 3 1
|
||||
0 3 1
|
||||
0 1.5 0.25251263
|
||||
0.175 1.5 0.25251263
|
||||
0.35 1.5 0.25251263
|
||||
0 1.6237437 0.37625631
|
||||
0.175 1.6237437 0.37625631
|
||||
0.35 1.6237437 0.37625631
|
||||
0 1.7474874 0.5
|
||||
0.175 1.7474874 0.5
|
||||
0.35 1.7474874 0.5
|
||||
0 1.3762563 0.37625631
|
||||
0.175 1.3762563 0.37625631
|
||||
0.35 1.3762563 0.37625631
|
||||
0 1.5 0.5
|
||||
0.175 1.5 0.5
|
||||
0.35 1.5 0.5
|
||||
0 1.6237437 0.62374369
|
||||
0.175 1.6237437 0.62374369
|
||||
0.35 1.6237437 0.62374369
|
||||
0 1.2525126 0.5
|
||||
0.175 1.2525126 0.5
|
||||
0.35 1.2525126 0.5
|
||||
0 1.3762563 0.62374369
|
||||
0.175 1.3762563 0.62374369
|
||||
0.35 1.3762563 0.62374369
|
||||
0 1.5 0.74748737
|
||||
0.175 1.5 0.74748737
|
||||
0.35 1.5 0.74748737
|
||||
@@ -1,453 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
# PYRAMID = 7
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
89
|
||||
1 5 0 1 5 4 40 41 45 44
|
||||
1 5 40 41 45 44 80 81 85 84
|
||||
1 5 44 45 49 48 84 85 89 88
|
||||
1 5 4 5 9 8 44 45 49 48
|
||||
1 5 5 6 10 9 45 46 50 49
|
||||
1 5 45 46 50 49 85 86 90 89
|
||||
1 5 41 42 46 45 81 82 86 85
|
||||
1 5 1 2 6 5 41 42 46 45
|
||||
1 5 2 3 7 6 42 43 47 46
|
||||
1 5 42 43 47 46 82 83 87 86
|
||||
1 5 6 7 11 10 46 47 51 50
|
||||
1 5 46 47 51 50 86 87 91 90
|
||||
1 5 86 87 91 90 126 127 131 130
|
||||
1 5 82 83 87 86 122 123 127 126
|
||||
1 5 81 82 86 85 121 122 126 125
|
||||
1 5 80 81 85 84 120 121 125 124
|
||||
1 5 84 85 89 88 124 125 129 128
|
||||
1 5 85 86 90 89 125 126 130 129
|
||||
1 5 89 90 94 93 129 130 134 133
|
||||
1 5 88 89 93 92 128 129 133 132
|
||||
1 5 92 93 97 96 132 133 137 136
|
||||
1 5 93 94 98 97 133 134 138 137
|
||||
1 5 94 95 99 98 134 135 139 138
|
||||
1 5 54 55 59 58 94 95 99 98
|
||||
1 5 90 91 95 94 130 131 135 134
|
||||
1 5 50 51 55 54 90 91 95 94
|
||||
1 5 10 11 15 14 50 51 55 54
|
||||
1 5 14 15 19 18 54 55 59 58
|
||||
1 5 13 14 18 17 53 54 58 57
|
||||
1 5 53 54 58 57 93 94 98 97
|
||||
1 5 49 50 54 53 89 90 94 93
|
||||
1 5 9 10 14 13 49 50 54 53
|
||||
1 5 8 9 13 12 48 49 53 52
|
||||
1 5 48 49 53 52 88 89 93 92
|
||||
1 5 52 53 57 56 92 93 97 96
|
||||
1 5 12 13 17 16 52 53 57 56
|
||||
1 5 16 17 21 20 56 57 61 60
|
||||
1 5 56 57 61 60 96 97 101 100
|
||||
1 5 57 58 62 61 97 98 102 101
|
||||
1 5 17 18 22 21 57 58 62 61
|
||||
1 5 18 19 23 22 58 59 63 62
|
||||
1 5 58 59 63 62 98 99 103 102
|
||||
1 5 98 99 103 102 138 139 143 142
|
||||
1 5 97 98 102 101 137 138 142 141
|
||||
1 5 96 97 101 100 136 137 141 140
|
||||
1 5 100 101 105 104 140 141 145 144
|
||||
1 5 101 102 106 105 141 142 146 145
|
||||
1 5 102 103 107 106 142 143 147 146
|
||||
1 5 62 63 67 66 102 103 107 106
|
||||
1 5 22 23 27 26 62 63 67 66
|
||||
1 5 21 22 26 25 61 62 66 65
|
||||
1 5 61 62 66 65 101 102 106 105
|
||||
1 5 60 61 65 64 100 101 105 104
|
||||
1 5 20 21 25 24 60 61 65 64
|
||||
1 5 24 25 29 28 64 65 69 68
|
||||
1 5 64 65 69 68 104 105 109 108
|
||||
1 5 68 69 73 72 108 109 113 112
|
||||
1 5 28 29 33 32 68 69 73 72
|
||||
1 5 29 30 34 33 69 70 74 73
|
||||
1 5 69 70 74 73 109 110 114 113
|
||||
1 5 65 66 70 69 105 106 110 109
|
||||
1 5 25 26 30 29 65 66 70 69
|
||||
1 5 26 27 31 30 66 67 71 70
|
||||
1 5 66 67 71 70 106 107 111 110
|
||||
1 5 30 31 35 34 70 71 75 74
|
||||
1 5 70 71 75 74 110 111 115 114
|
||||
1 5 110 111 115 114 150 151 155 154
|
||||
1 5 106 107 111 110 146 147 151 150
|
||||
1 5 105 106 110 109 145 146 150 149
|
||||
1 5 109 110 114 113 149 150 154 153
|
||||
1 5 104 105 109 108 144 145 149 148
|
||||
1 5 108 109 113 112 148 149 153 152
|
||||
1 5 112 113 117 116 152 153 157 156
|
||||
1 5 113 114 118 117 153 154 158 157
|
||||
1 5 114 115 119 118 154 155 159 158
|
||||
1 5 74 75 79 78 114 115 119 118
|
||||
1 5 34 35 39 38 74 75 79 78
|
||||
1 5 33 34 38 37 73 74 78 77
|
||||
1 5 73 74 78 77 113 114 118 117
|
||||
1 5 72 73 77 76 112 113 117 116
|
||||
1 5 32 33 37 36 72 73 77 76
|
||||
2 5 160 161 164 163 169 170 173 172
|
||||
2 5 163 164 167 166 172 173 176 175
|
||||
2 5 172 173 176 175 181 182 185 184
|
||||
2 5 169 170 173 172 178 179 182 181
|
||||
2 5 170 171 174 173 179 180 183 182
|
||||
2 5 173 174 177 176 182 183 186 185
|
||||
2 5 164 165 168 167 173 174 177 176
|
||||
2 5 161 162 165 164 170 171 174 173
|
||||
|
||||
boundary
|
||||
150
|
||||
1 3 0 4 5 1
|
||||
1 3 1 5 6 2
|
||||
1 3 2 6 7 3
|
||||
1 3 4 8 9 5
|
||||
1 3 5 9 10 6
|
||||
1 3 6 10 11 7
|
||||
1 3 8 12 13 9
|
||||
1 3 9 13 14 10
|
||||
1 3 10 14 15 11
|
||||
1 3 12 16 17 13
|
||||
1 3 13 17 18 14
|
||||
1 3 14 18 19 15
|
||||
1 3 16 20 21 17
|
||||
1 3 17 21 22 18
|
||||
1 3 18 22 23 19
|
||||
1 3 20 24 25 21
|
||||
1 3 21 25 26 22
|
||||
1 3 22 26 27 23
|
||||
1 3 24 28 29 25
|
||||
1 3 25 29 30 26
|
||||
1 3 26 30 31 27
|
||||
1 3 28 32 33 29
|
||||
1 3 29 33 34 30
|
||||
1 3 30 34 35 31
|
||||
1 3 32 36 37 33
|
||||
1 3 33 37 38 34
|
||||
1 3 34 38 39 35
|
||||
1 3 120 121 125 124
|
||||
1 3 121 122 126 125
|
||||
1 3 122 123 127 126
|
||||
1 3 124 125 129 128
|
||||
1 3 125 126 130 129
|
||||
1 3 126 127 131 130
|
||||
1 3 128 129 133 132
|
||||
1 3 129 130 134 133
|
||||
1 3 130 131 135 134
|
||||
1 3 132 133 137 136
|
||||
1 3 133 134 138 137
|
||||
1 3 134 135 139 138
|
||||
1 3 136 137 141 140
|
||||
1 3 137 138 142 141
|
||||
1 3 138 139 143 142
|
||||
1 3 140 141 145 144
|
||||
1 3 141 142 146 145
|
||||
1 3 142 143 147 146
|
||||
1 3 144 145 149 148
|
||||
1 3 145 146 150 149
|
||||
1 3 146 147 151 150
|
||||
1 3 148 149 153 152
|
||||
1 3 149 150 154 153
|
||||
1 3 150 151 155 154
|
||||
1 3 152 153 157 156
|
||||
1 3 153 154 158 157
|
||||
1 3 154 155 159 158
|
||||
2 3 0 40 44 4
|
||||
2 3 4 44 48 8
|
||||
2 3 8 48 52 12
|
||||
2 3 12 52 56 16
|
||||
2 3 16 56 60 20
|
||||
2 3 20 60 64 24
|
||||
2 3 24 64 68 28
|
||||
2 3 28 68 72 32
|
||||
2 3 32 72 76 36
|
||||
2 3 40 80 84 44
|
||||
2 3 44 84 88 48
|
||||
2 3 48 88 92 52
|
||||
2 3 52 92 96 56
|
||||
2 3 56 96 100 60
|
||||
2 3 60 100 104 64
|
||||
2 3 64 104 108 68
|
||||
2 3 68 108 112 72
|
||||
2 3 72 112 116 76
|
||||
2 3 80 120 124 84
|
||||
2 3 84 124 128 88
|
||||
2 3 88 128 132 92
|
||||
2 3 92 132 136 96
|
||||
2 3 96 136 140 100
|
||||
2 3 100 140 144 104
|
||||
2 3 104 144 148 108
|
||||
2 3 108 148 152 112
|
||||
2 3 112 152 156 116
|
||||
3 3 3 7 47 43
|
||||
3 3 7 11 51 47
|
||||
3 3 11 15 55 51
|
||||
3 3 15 19 59 55
|
||||
3 3 19 23 63 59
|
||||
3 3 23 27 67 63
|
||||
3 3 27 31 71 67
|
||||
3 3 31 35 75 71
|
||||
3 3 35 39 79 75
|
||||
3 3 43 47 87 83
|
||||
3 3 47 51 91 87
|
||||
3 3 51 55 95 91
|
||||
3 3 55 59 99 95
|
||||
3 3 59 63 103 99
|
||||
3 3 63 67 107 103
|
||||
3 3 67 71 111 107
|
||||
3 3 71 75 115 111
|
||||
3 3 75 79 119 115
|
||||
3 3 83 87 127 123
|
||||
3 3 87 91 131 127
|
||||
3 3 91 95 135 131
|
||||
3 3 95 99 139 135
|
||||
3 3 99 103 143 139
|
||||
3 3 103 107 147 143
|
||||
3 3 107 111 151 147
|
||||
3 3 111 115 155 151
|
||||
3 3 115 119 159 155
|
||||
1 3 0 1 41 40
|
||||
1 3 40 41 81 80
|
||||
1 3 80 81 121 120
|
||||
1 3 1 2 42 41
|
||||
1 3 41 42 82 81
|
||||
1 3 81 82 122 121
|
||||
1 3 2 3 43 42
|
||||
1 3 42 43 83 82
|
||||
1 3 82 83 123 122
|
||||
1 3 36 76 77 37
|
||||
1 3 76 116 117 77
|
||||
1 3 116 156 157 117
|
||||
1 3 37 77 78 38
|
||||
1 3 77 117 118 78
|
||||
1 3 117 157 158 118
|
||||
1 3 38 78 79 39
|
||||
1 3 78 118 119 79
|
||||
1 3 118 158 159 119
|
||||
5 3 160 163 164 161
|
||||
5 3 161 164 165 162
|
||||
5 3 163 166 167 164
|
||||
5 3 164 167 168 165
|
||||
5 3 178 179 182 181
|
||||
5 3 179 180 183 182
|
||||
5 3 181 182 185 184
|
||||
5 3 182 183 186 185
|
||||
4 3 160 169 172 163
|
||||
4 3 163 172 175 166
|
||||
4 3 169 178 181 172
|
||||
4 3 172 181 184 175
|
||||
6 3 162 165 174 171
|
||||
6 3 165 168 177 174
|
||||
6 3 171 174 183 180
|
||||
6 3 174 177 186 183
|
||||
5 3 160 161 170 169
|
||||
5 3 169 170 179 178
|
||||
5 3 161 162 171 170
|
||||
5 3 170 171 180 179
|
||||
5 3 166 175 176 167
|
||||
5 3 175 184 185 176
|
||||
5 3 167 176 177 168
|
||||
5 3 176 185 186 177
|
||||
|
||||
vertices
|
||||
187
|
||||
3
|
||||
-1 0 0
|
||||
-0.66666667 0 0
|
||||
-0.33333333 0 0
|
||||
0 0 0
|
||||
-1 0.33333333 0
|
||||
-0.66666667 0.33333333 0
|
||||
-0.33333333 0.33333333 0
|
||||
0 0.33333333 0
|
||||
-1 0.66666667 0
|
||||
-0.66666667 0.66666667 0
|
||||
-0.33333333 0.66666667 0
|
||||
0 0.66666667 0
|
||||
-1 1 0
|
||||
-0.66666667 1 0
|
||||
-0.33333333 1 0
|
||||
0 1 0
|
||||
-1 1.3333333 0
|
||||
-0.66666667 1.3333333 0
|
||||
-0.33333333 1.3333333 0
|
||||
0 1.3333333 0
|
||||
-1 1.6666667 0
|
||||
-0.66666667 1.6666667 0
|
||||
-0.33333333 1.6666667 0
|
||||
0 1.6666667 0
|
||||
-1 2 0
|
||||
-0.66666667 2 0
|
||||
-0.33333333 2 0
|
||||
0 2 0
|
||||
-1 2.3333333 0
|
||||
-0.66666667 2.3333333 0
|
||||
-0.33333333 2.3333333 0
|
||||
0 2.3333333 0
|
||||
-1 2.6666667 0
|
||||
-0.66666667 2.6666667 0
|
||||
-0.33333333 2.6666667 0
|
||||
0 2.6666667 0
|
||||
-1 3 0
|
||||
-0.66666667 3 0
|
||||
-0.33333333 3 0
|
||||
0 3 0
|
||||
-1 0 0.33333333
|
||||
-0.66666667 0 0.33333333
|
||||
-0.33333333 0 0.33333333
|
||||
0 0 0.33333333
|
||||
-1 0.33333333 0.33333333
|
||||
-0.66666667 0.33333333 0.33333333
|
||||
-0.33333333 0.33333333 0.33333333
|
||||
0 0.33333333 0.33333333
|
||||
-1 0.66666667 0.33333333
|
||||
-0.66666667 0.66666667 0.33333333
|
||||
-0.33333333 0.66666667 0.33333333
|
||||
0 0.66666667 0.33333333
|
||||
-1 1 0.33333333
|
||||
-0.66666667 1 0.33333333
|
||||
-0.33333333 1 0.33333333
|
||||
0 1 0.33333333
|
||||
-1 1.3333333 0.33333333
|
||||
-0.66666667 1.3333333 0.33333333
|
||||
-0.33333333 1.3333333 0.33333333
|
||||
0 1.3333333 0.33333333
|
||||
-1 1.6666667 0.33333333
|
||||
-0.66666667 1.6666667 0.33333333
|
||||
-0.33333333 1.6666667 0.33333333
|
||||
0 1.6666667 0.33333333
|
||||
-1 2 0.33333333
|
||||
-0.66666667 2 0.33333333
|
||||
-0.33333333 2 0.33333333
|
||||
0 2 0.33333333
|
||||
-1 2.3333333 0.33333333
|
||||
-0.66666667 2.3333333 0.33333333
|
||||
-0.33333333 2.3333333 0.33333333
|
||||
0 2.3333333 0.33333333
|
||||
-1 2.6666667 0.33333333
|
||||
-0.66666667 2.6666667 0.33333333
|
||||
-0.33333333 2.6666667 0.33333333
|
||||
0 2.6666667 0.33333333
|
||||
-1 3 0.33333333
|
||||
-0.66666667 3 0.33333333
|
||||
-0.33333333 3 0.33333333
|
||||
0 3 0.33333333
|
||||
-1 0 0.66666667
|
||||
-0.66666667 0 0.66666667
|
||||
-0.33333333 0 0.66666667
|
||||
0 0 0.66666667
|
||||
-1 0.33333333 0.66666667
|
||||
-0.66666667 0.33333333 0.66666667
|
||||
-0.33333333 0.33333333 0.66666667
|
||||
0 0.33333333 0.66666667
|
||||
-1 0.66666667 0.66666667
|
||||
-0.66666667 0.66666667 0.66666667
|
||||
-0.33333333 0.66666667 0.66666667
|
||||
0 0.66666667 0.66666667
|
||||
-1 1 0.66666667
|
||||
-0.66666667 1 0.66666667
|
||||
-0.33333333 1 0.66666667
|
||||
0 1 0.66666667
|
||||
-1 1.3333333 0.66666667
|
||||
-0.66666667 1.3333333 0.66666667
|
||||
-0.33333333 1.3333333 0.66666667
|
||||
0 1.3333333 0.66666667
|
||||
-1 1.6666667 0.66666667
|
||||
-0.66666667 1.6666667 0.66666667
|
||||
-0.33333333 1.6666667 0.66666667
|
||||
0 1.6666667 0.66666667
|
||||
-1 2 0.66666667
|
||||
-0.66666667 2 0.66666667
|
||||
-0.33333333 2 0.66666667
|
||||
0 2 0.66666667
|
||||
-1 2.3333333 0.66666667
|
||||
-0.66666667 2.3333333 0.66666667
|
||||
-0.33333333 2.3333333 0.66666667
|
||||
0 2.3333333 0.66666667
|
||||
-1 2.6666667 0.66666667
|
||||
-0.66666667 2.6666667 0.66666667
|
||||
-0.33333333 2.6666667 0.66666667
|
||||
0 2.6666667 0.66666667
|
||||
-1 3 0.66666667
|
||||
-0.66666667 3 0.66666667
|
||||
-0.33333333 3 0.66666667
|
||||
0 3 0.66666667
|
||||
-1 0 1
|
||||
-0.66666667 0 1
|
||||
-0.33333333 0 1
|
||||
0 0 1
|
||||
-1 0.33333333 1
|
||||
-0.66666667 0.33333333 1
|
||||
-0.33333333 0.33333333 1
|
||||
0 0.33333333 1
|
||||
-1 0.66666667 1
|
||||
-0.66666667 0.66666667 1
|
||||
-0.33333333 0.66666667 1
|
||||
0 0.66666667 1
|
||||
-1 1 1
|
||||
-0.66666667 1 1
|
||||
-0.33333333 1 1
|
||||
0 1 1
|
||||
-1 1.3333333 1
|
||||
-0.66666667 1.3333333 1
|
||||
-0.33333333 1.3333333 1
|
||||
0 1.3333333 1
|
||||
-1 1.6666667 1
|
||||
-0.66666667 1.6666667 1
|
||||
-0.33333333 1.6666667 1
|
||||
0 1.6666667 1
|
||||
-1 2 1
|
||||
-0.66666667 2 1
|
||||
-0.33333333 2 1
|
||||
0 2 1
|
||||
-1 2.3333333 1
|
||||
-0.66666667 2.3333333 1
|
||||
-0.33333333 2.3333333 1
|
||||
0 2.3333333 1
|
||||
-1 2.6666667 1
|
||||
-0.66666667 2.6666667 1
|
||||
-0.33333333 2.6666667 1
|
||||
0 2.6666667 1
|
||||
-1 3 1
|
||||
-0.66666667 3 1
|
||||
-0.33333333 3 1
|
||||
0 3 1
|
||||
0 0.83333333 0.25251263
|
||||
0.175 0.83333333 0.25251263
|
||||
0.35 0.83333333 0.25251263
|
||||
0 0.95707702 0.37625631
|
||||
0.175 0.95707702 0.37625631
|
||||
0.35 0.95707702 0.37625631
|
||||
0 1.0808207 0.5
|
||||
0.175 1.0808207 0.5
|
||||
0.35 1.0808207 0.5
|
||||
0 0.70958965 0.37625631
|
||||
0.175 0.70958965 0.37625631
|
||||
0.35 0.70958965 0.37625631
|
||||
0 0.83333333 0.5
|
||||
0.175 0.83333333 0.5
|
||||
0.35 0.83333333 0.5
|
||||
0 0.95707702 0.62374369
|
||||
0.175 0.95707702 0.62374369
|
||||
0.35 0.95707702 0.62374369
|
||||
0 0.58584596 0.5
|
||||
0.175 0.58584596 0.5
|
||||
0.35 0.58584596 0.5
|
||||
0 0.70958965 0.62374369
|
||||
0.175 0.70958965 0.62374369
|
||||
0.35 0.70958965 0.62374369
|
||||
0 0.83333333 0.74748737
|
||||
0.175 0.83333333 0.74748737
|
||||
0.35 0.83333333 0.74748737
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,231 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
# PYRAMID = 7
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
35
|
||||
1 5 0 1 5 4 16 17 21 20
|
||||
1 5 16 17 21 20 32 33 37 36
|
||||
1 5 17 18 22 21 33 34 38 37
|
||||
1 5 1 2 6 5 17 18 22 21
|
||||
1 5 5 6 10 9 21 22 26 25
|
||||
1 5 21 22 26 25 37 38 42 41
|
||||
1 5 20 21 25 24 36 37 41 40
|
||||
1 5 4 5 9 8 20 21 25 24
|
||||
1 5 8 9 13 12 24 25 29 28
|
||||
1 5 24 25 29 28 40 41 45 44
|
||||
1 5 9 10 14 13 25 26 30 29
|
||||
1 5 25 26 30 29 41 42 46 45
|
||||
1 5 41 42 46 45 57 58 62 61
|
||||
1 5 40 41 45 44 56 57 61 60
|
||||
1 5 36 37 41 40 52 53 57 56
|
||||
1 5 37 38 42 41 53 54 58 57
|
||||
1 5 32 33 37 36 48 49 53 52
|
||||
1 5 33 34 38 37 49 50 54 53
|
||||
1 5 34 35 39 38 50 51 55 54
|
||||
1 5 38 39 43 42 54 55 59 58
|
||||
1 5 42 43 47 46 58 59 63 62
|
||||
1 5 26 27 31 30 42 43 47 46
|
||||
1 5 10 11 15 14 26 27 31 30
|
||||
1 5 6 7 11 10 22 23 27 26
|
||||
1 5 22 23 27 26 38 39 43 42
|
||||
1 5 18 19 23 22 34 35 39 38
|
||||
1 5 2 3 7 6 18 19 23 22
|
||||
1 5 64 65 68 67 73 74 77 76
|
||||
1 5 67 68 71 70 76 77 80 79
|
||||
1 5 76 77 80 79 85 86 89 88
|
||||
1 5 73 74 77 76 82 83 86 85
|
||||
1 5 74 75 78 77 83 84 87 86
|
||||
1 5 77 78 81 80 86 87 90 89
|
||||
1 5 68 69 72 71 77 78 81 80
|
||||
1 5 65 66 69 68 74 75 78 77
|
||||
|
||||
boundary
|
||||
78
|
||||
1 3 0 4 5 1
|
||||
1 3 1 5 6 2
|
||||
1 3 2 6 7 3
|
||||
1 3 4 8 9 5
|
||||
1 3 5 9 10 6
|
||||
1 3 6 10 11 7
|
||||
1 3 8 12 13 9
|
||||
1 3 9 13 14 10
|
||||
1 3 10 14 15 11
|
||||
1 3 48 49 53 52
|
||||
1 3 49 50 54 53
|
||||
1 3 50 51 55 54
|
||||
1 3 52 53 57 56
|
||||
1 3 53 54 58 57
|
||||
1 3 54 55 59 58
|
||||
1 3 56 57 61 60
|
||||
1 3 57 58 62 61
|
||||
1 3 58 59 63 62
|
||||
2 3 0 16 20 4
|
||||
2 3 4 20 24 8
|
||||
2 3 8 24 28 12
|
||||
2 3 16 32 36 20
|
||||
2 3 20 36 40 24
|
||||
2 3 24 40 44 28
|
||||
2 3 32 48 52 36
|
||||
2 3 36 52 56 40
|
||||
2 3 40 56 60 44
|
||||
3 3 3 7 23 19
|
||||
3 3 7 11 27 23
|
||||
3 3 11 15 31 27
|
||||
3 3 19 23 39 35
|
||||
3 3 23 27 43 39
|
||||
3 3 27 31 47 43
|
||||
3 3 35 39 55 51
|
||||
3 3 39 43 59 55
|
||||
3 3 43 47 63 59
|
||||
1 3 0 1 17 16
|
||||
1 3 16 17 33 32
|
||||
1 3 32 33 49 48
|
||||
1 3 1 2 18 17
|
||||
1 3 17 18 34 33
|
||||
1 3 33 34 50 49
|
||||
1 3 2 3 19 18
|
||||
1 3 18 19 35 34
|
||||
1 3 34 35 51 50
|
||||
1 3 12 28 29 13
|
||||
1 3 28 44 45 29
|
||||
1 3 44 60 61 45
|
||||
1 3 13 29 30 14
|
||||
1 3 29 45 46 30
|
||||
1 3 45 61 62 46
|
||||
1 3 14 30 31 15
|
||||
1 3 30 46 47 31
|
||||
1 3 46 62 63 47
|
||||
5 3 64 67 68 65
|
||||
5 3 65 68 69 66
|
||||
5 3 67 70 71 68
|
||||
5 3 68 71 72 69
|
||||
5 3 82 83 86 85
|
||||
5 3 83 84 87 86
|
||||
5 3 85 86 89 88
|
||||
5 3 86 87 90 89
|
||||
4 3 64 73 76 67
|
||||
4 3 67 76 79 70
|
||||
4 3 73 82 85 76
|
||||
4 3 76 85 88 79
|
||||
6 3 66 69 78 75
|
||||
6 3 69 72 81 78
|
||||
6 3 75 78 87 84
|
||||
6 3 78 81 90 87
|
||||
5 3 64 65 74 73
|
||||
5 3 73 74 83 82
|
||||
5 3 65 66 75 74
|
||||
5 3 74 75 84 83
|
||||
5 3 70 79 80 71
|
||||
5 3 79 88 89 80
|
||||
5 3 71 80 81 72
|
||||
5 3 80 89 90 81
|
||||
|
||||
vertices
|
||||
91
|
||||
3
|
||||
-1 0 0
|
||||
-0.66666667 0 0
|
||||
-0.33333333 0 0
|
||||
0 0 0
|
||||
-1 0.33333333 0
|
||||
-0.66666667 0.33333333 0
|
||||
-0.33333333 0.33333333 0
|
||||
0 0.33333333 0
|
||||
-1 0.66666667 0
|
||||
-0.66666667 0.66666667 0
|
||||
-0.33333333 0.66666667 0
|
||||
0 0.66666667 0
|
||||
-1 1 0
|
||||
-0.66666667 1 0
|
||||
-0.33333333 1 0
|
||||
0 1 0
|
||||
-1 0 0.33333333
|
||||
-0.66666667 0 0.33333333
|
||||
-0.33333333 0 0.33333333
|
||||
0 0 0.33333333
|
||||
-1 0.33333333 0.33333333
|
||||
-0.66666667 0.33333333 0.33333333
|
||||
-0.33333333 0.33333333 0.33333333
|
||||
0 0.33333333 0.33333333
|
||||
-1 0.66666667 0.33333333
|
||||
-0.66666667 0.66666667 0.33333333
|
||||
-0.33333333 0.66666667 0.33333333
|
||||
0 0.66666667 0.33333333
|
||||
-1 1 0.33333333
|
||||
-0.66666667 1 0.33333333
|
||||
-0.33333333 1 0.33333333
|
||||
0 1 0.33333333
|
||||
-1 0 0.66666667
|
||||
-0.66666667 0 0.66666667
|
||||
-0.33333333 0 0.66666667
|
||||
0 0 0.66666667
|
||||
-1 0.33333333 0.66666667
|
||||
-0.66666667 0.33333333 0.66666667
|
||||
-0.33333333 0.33333333 0.66666667
|
||||
0 0.33333333 0.66666667
|
||||
-1 0.66666667 0.66666667
|
||||
-0.66666667 0.66666667 0.66666667
|
||||
-0.33333333 0.66666667 0.66666667
|
||||
0 0.66666667 0.66666667
|
||||
-1 1 0.66666667
|
||||
-0.66666667 1 0.66666667
|
||||
-0.33333333 1 0.66666667
|
||||
0 1 0.66666667
|
||||
-1 0 1
|
||||
-0.66666667 0 1
|
||||
-0.33333333 0 1
|
||||
0 0 1
|
||||
-1 0.33333333 1
|
||||
-0.66666667 0.33333333 1
|
||||
-0.33333333 0.33333333 1
|
||||
0 0.33333333 1
|
||||
-1 0.66666667 1
|
||||
-0.66666667 0.66666667 1
|
||||
-0.33333333 0.66666667 1
|
||||
0 0.66666667 1
|
||||
-1 1 1
|
||||
-0.66666667 1 1
|
||||
-0.33333333 1 1
|
||||
0 1 1
|
||||
0 0.5 0.14644661
|
||||
0.25 0.5 0.14644661
|
||||
0.5 0.5 0.14644661
|
||||
0 0.6767767 0.3232233
|
||||
0.25 0.6767767 0.3232233
|
||||
0.5 0.6767767 0.3232233
|
||||
0 0.85355339 0.5
|
||||
0.25 0.85355339 0.5
|
||||
0.5 0.85355339 0.5
|
||||
0 0.3232233 0.3232233
|
||||
0.25 0.3232233 0.3232233
|
||||
0.5 0.3232233 0.3232233
|
||||
0 0.5 0.5
|
||||
0.25 0.5 0.5
|
||||
0.5 0.5 0.5
|
||||
0 0.6767767 0.6767767
|
||||
0.25 0.6767767 0.6767767
|
||||
0.5 0.6767767 0.6767767
|
||||
0 0.14644661 0.5
|
||||
0.25 0.14644661 0.5
|
||||
0.5 0.14644661 0.5
|
||||
0 0.3232233 0.6767767
|
||||
0.25 0.3232233 0.6767767
|
||||
0.5 0.3232233 0.6767767
|
||||
0 0.5 0.85355339
|
||||
0.25 0.5 0.85355339
|
||||
0.5 0.5 0.85355339
|
||||
@@ -1,663 +0,0 @@
|
||||
#include "parproblems.hpp"
|
||||
|
||||
void ParElasticityProblem::Init()
|
||||
{
|
||||
int dim = pmesh->Dimension();
|
||||
fec = new H1_FECollection(order,dim);
|
||||
fes = new ParFiniteElementSpace(pmesh,fec,dim,Ordering::byVDIM);
|
||||
ndofs = fes->GetVSize();
|
||||
ntdofs = fes->GetTrueVSize();
|
||||
gndofs = fes->GlobalTrueVSize();
|
||||
pmesh->SetNodalFESpace(fes);
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(pmesh->bdr_attributes.Max());
|
||||
}
|
||||
ess_bdr = 0;
|
||||
Array<int> ess_tdof_list_temp;
|
||||
for (int i = 0; i < ess_bdr_attr.Size(); i++ )
|
||||
{
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 1;
|
||||
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list_temp,ess_bdr_attr_comp[i]);
|
||||
ess_tdof_list.Append(ess_tdof_list_temp);
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 0;
|
||||
}
|
||||
// Solution GridFunction
|
||||
x.SetSpace(fes); x = 0.0;
|
||||
// RHS
|
||||
b = new ParLinearForm(fes);
|
||||
|
||||
// Elasticity operator
|
||||
lambda.SetSize(pmesh->attributes.Max()); lambda = 57.6923076923;
|
||||
mu.SetSize(pmesh->attributes.Max()); mu = 38.4615384615;
|
||||
|
||||
lambda_cf.UpdateConstants(lambda);
|
||||
mu_cf.UpdateConstants(mu);
|
||||
|
||||
a = new ParBilinearForm(fes);
|
||||
a->AddDomainIntegrator(new ElasticityIntegrator(lambda_cf,mu_cf));
|
||||
}
|
||||
|
||||
void ParElasticityProblem::FormLinearSystem()
|
||||
{
|
||||
if (!formsystem)
|
||||
{
|
||||
formsystem = true;
|
||||
b->Assemble();
|
||||
a->Assemble();
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
}
|
||||
}
|
||||
|
||||
void ParElasticityProblem::UpdateLinearSystem()
|
||||
{
|
||||
UpdateStep();
|
||||
FormLinearSystem();
|
||||
}
|
||||
|
||||
// #ifdef MFEM_USE_TRIBOL
|
||||
|
||||
|
||||
|
||||
ParContactProblem::ParContactProblem(ParElasticityProblem * prob_,
|
||||
const std::set<int> & mortar_attrs_,
|
||||
const std::set<int> & nonmortar_attrs_,
|
||||
ParGridFunction * coords_,
|
||||
bool doublepass_)
|
||||
: prob(prob_), mortar_attrs(mortar_attrs_), nonmortar_attrs(nonmortar_attrs_), doublepass(doublepass_), coords(coords_)
|
||||
{
|
||||
ParMesh* pmesh = prob->GetMesh();
|
||||
comm = pmesh->GetComm();
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
MPI_Comm_size(comm, &numprocs);
|
||||
|
||||
dim = pmesh->Dimension();
|
||||
nodes0.SetSpace(pmesh->GetNodes()->FESpace());
|
||||
nodes0 = *pmesh->GetNodes();
|
||||
nodes1 = pmesh->GetNodes();
|
||||
|
||||
prob->FormLinearSystem();
|
||||
K = new HypreParMatrix(prob->GetOperator());
|
||||
B = new Vector(prob->GetRHS());
|
||||
if (doublepass)
|
||||
{
|
||||
SetupTribolDoublePass();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupTribol();
|
||||
}
|
||||
}
|
||||
|
||||
void ParContactProblem::SetupTribol()
|
||||
{
|
||||
axom::slic::SimpleLogger logger;
|
||||
axom::slic::setIsRoot(mfem::Mpi::Root());
|
||||
|
||||
// Initialize Tribol contact library
|
||||
tribol::initialize(3, MPI_COMM_WORLD);
|
||||
|
||||
int coupling_scheme_id = 0;
|
||||
int mesh1_id = 0;
|
||||
int mesh2_id = 1;
|
||||
vfes = prob->GetFESpace();
|
||||
ParMesh * pmesh = prob->GetMesh();
|
||||
tribol::registerMfemCouplingScheme(
|
||||
coupling_scheme_id, mesh1_id, mesh2_id,
|
||||
*pmesh, *coords, mortar_attrs, nonmortar_attrs,
|
||||
tribol::SURFACE_TO_SURFACE,
|
||||
tribol::NO_SLIDING,
|
||||
tribol::SINGLE_MORTAR,
|
||||
tribol::FRICTIONLESS,
|
||||
tribol::LAGRANGE_MULTIPLIER,
|
||||
tribol::BINNING_GRID
|
||||
);
|
||||
|
||||
// Access Tribol's pressure grid function (on the contact surface)
|
||||
auto& pressure = tribol::getMfemPressure(coupling_scheme_id);
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of pressure unknowns: " <<
|
||||
pressure.ParFESpace()->GlobalTrueVSize() << std::endl;
|
||||
}
|
||||
|
||||
// Set Tribol options for Lagrange multiplier enforcement
|
||||
tribol::setLagrangeMultiplierOptions(
|
||||
coupling_scheme_id,
|
||||
tribol::ImplicitEvalMode::MORTAR_RESIDUAL_JACOBIAN
|
||||
);
|
||||
|
||||
// Update contact mesh decomposition
|
||||
tribol::updateMfemParallelDecomposition();
|
||||
|
||||
// Update contact gaps, forces, and tangent stiffness
|
||||
int cycle = 1; // pseudo cycle
|
||||
double t = 1.0; // pseudo time
|
||||
double dt = 1.0; // pseudo dt
|
||||
tribol::update(cycle, t, dt);
|
||||
|
||||
// Return contact contribution to the tangent stiffness matrix
|
||||
auto A_blk = tribol::getMfemBlockJacobian(coupling_scheme_id);
|
||||
|
||||
HypreParMatrix * Mfull = (HypreParMatrix *)(&A_blk->GetBlock(1,0));
|
||||
Mfull->EliminateCols(prob->GetEssentialDofs());
|
||||
int h = Mfull->Height();
|
||||
SparseMatrix merged;
|
||||
Mfull->MergeDiagAndOffd(merged);
|
||||
Array<int> nonzero_rows;
|
||||
for (int i = 0; i<h; i++)
|
||||
{
|
||||
if (!merged.RowIsEmpty(i))
|
||||
{
|
||||
nonzero_rows.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hnew = nonzero_rows.Size();
|
||||
SparseMatrix P(hnew,h);
|
||||
|
||||
for (int i = 0; i<hnew; i++)
|
||||
{
|
||||
int col = nonzero_rows[i];
|
||||
P.Set(i,col,1.0);
|
||||
}
|
||||
P.Finalize();
|
||||
|
||||
SparseMatrix * reduced_merged = Mult(P,merged);
|
||||
|
||||
int rows[2];
|
||||
int cols[2];
|
||||
cols[0] = Mfull->ColPart()[0];
|
||||
cols[1] = Mfull->ColPart()[1];
|
||||
int nrows = reduced_merged->Height();
|
||||
|
||||
int row_offset;
|
||||
MPI_Scan(&nrows,&row_offset,1,MPI_INT,MPI_SUM,Mfull->GetComm());
|
||||
|
||||
row_offset-=nrows;
|
||||
rows[0] = row_offset;
|
||||
rows[1] = row_offset+nrows;
|
||||
int glob_nrows;
|
||||
MPI_Allreduce(&nrows, &glob_nrows,1,MPI_INT,MPI_SUM,Mfull->GetComm());
|
||||
|
||||
|
||||
int glob_ncols = reduced_merged->Width();
|
||||
M = new HypreParMatrix(Mfull->GetComm(), nrows, glob_nrows,
|
||||
glob_ncols, reduced_merged->GetI(), reduced_merged->GetJ(),
|
||||
reduced_merged->GetData(), rows,cols);
|
||||
|
||||
Vector gap;
|
||||
tribol::getMfemGap(coupling_scheme_id, gap);
|
||||
auto& P_submesh = *pressure.ParFESpace()->GetProlongationMatrix();
|
||||
Vector gap_true;
|
||||
gap_true.SetSize(P_submesh.Width());
|
||||
P_submesh.MultTranspose(gap,gap_true);
|
||||
|
||||
gapv.SetSize(nrows);
|
||||
for (int i = 0; i<nrows; i++)
|
||||
{
|
||||
gapv[i] = gap_true[nonzero_rows[i]];
|
||||
}
|
||||
|
||||
constraints_starts.SetSize(2);
|
||||
constraints_starts[0] = M->RowPart()[0];
|
||||
constraints_starts[1] = M->RowPart()[1];
|
||||
|
||||
// find elast dofs in contact;
|
||||
HypreParMatrix * Jt = (HypreParMatrix *)(&A_blk->GetBlock(0,1));
|
||||
Jt->EliminateRows(prob->GetEssentialDofs());
|
||||
|
||||
int hJt = Jt->Height();
|
||||
SparseMatrix mergedJt;
|
||||
Jt->MergeDiagAndOffd(mergedJt);
|
||||
|
||||
Array<int> nonzerorows;
|
||||
Array<int> zerorows;
|
||||
for (int i = 0; i<hJt; i++)
|
||||
{
|
||||
if (!mergedJt.RowIsEmpty(i))
|
||||
{
|
||||
nonzerorows.Append(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
zerorows.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hb = nonzerorows.Size();
|
||||
SparseMatrix Pbt(hb,K->GetGlobalNumCols());
|
||||
|
||||
for (int i = 0; i<hb; i++)
|
||||
{
|
||||
int col = nonzerorows[i]+prob->GetFESpace()->GetMyTDofOffset();
|
||||
Pbt.Set(i,col,1.0);
|
||||
}
|
||||
Pbt.Finalize();
|
||||
|
||||
int rows_b[2];
|
||||
int cols_b[2];
|
||||
int nrows_b = Pbt.Height();
|
||||
|
||||
int row_offset_b;
|
||||
MPI_Scan(&nrows_b,&row_offset_b,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
row_offset_b-=nrows_b;
|
||||
rows_b[0] = row_offset_b;
|
||||
rows_b[1] = row_offset_b+nrows_b;
|
||||
cols_b[0] = K->ColPart()[0];
|
||||
cols_b[1] = K->ColPart()[1];
|
||||
int glob_nrows_b;
|
||||
int glob_ncols_b = K->GetGlobalNumCols();
|
||||
MPI_Allreduce(&nrows_b, &glob_nrows_b,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
HypreParMatrix * P_bt = new HypreParMatrix(MPI_COMM_WORLD, nrows_b, glob_nrows_b,
|
||||
glob_ncols_b, Pbt.GetI(), Pbt.GetJ(),
|
||||
Pbt.GetData(), rows_b,cols_b);
|
||||
|
||||
Pb = P_bt->Transpose();
|
||||
delete P_bt;
|
||||
|
||||
int hi = zerorows.Size();
|
||||
SparseMatrix Pit(hi,K->GetGlobalNumCols());
|
||||
|
||||
for (int i = 0; i<hi; i++)
|
||||
{
|
||||
int col = zerorows[i]+prob->GetFESpace()->GetMyTDofOffset();
|
||||
Pit.Set(i,col,1.0);
|
||||
}
|
||||
Pit.Finalize();
|
||||
|
||||
int rows_i[2];
|
||||
int cols_i[2];
|
||||
int nrows_i = Pit.Height();
|
||||
|
||||
int row_offset_i;
|
||||
MPI_Scan(&nrows_i,&row_offset_i,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
row_offset_i-=nrows_i;
|
||||
rows_i[0] = row_offset_i;
|
||||
rows_i[1] = row_offset_i+nrows_i;
|
||||
cols_i[0] = K->ColPart()[0];
|
||||
cols_i[1] = K->ColPart()[1];
|
||||
int glob_nrows_i;
|
||||
int glob_ncols_i = K->GetGlobalNumCols();
|
||||
MPI_Allreduce(&nrows_i, &glob_nrows_i,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
HypreParMatrix * P_it = new HypreParMatrix(MPI_COMM_WORLD, nrows_i, glob_nrows_i,
|
||||
glob_ncols_i, Pit.GetI(), Pit.GetJ(),
|
||||
Pit.GetData(), rows_i,cols_i);
|
||||
|
||||
Pi = P_it->Transpose();
|
||||
delete P_it;
|
||||
}
|
||||
|
||||
void ParContactProblem::SetupTribolDoublePass()
|
||||
{
|
||||
axom::slic::SimpleLogger logger1;
|
||||
axom::slic::setIsRoot(mfem::Mpi::Root());
|
||||
|
||||
// Initialize Tribol contact library
|
||||
tribol::initialize(3, MPI_COMM_WORLD);
|
||||
|
||||
int coupling_scheme_id1 = 0;
|
||||
int mesh1_id1 = 0;
|
||||
int mesh2_id1 = 1;
|
||||
vfes = prob->GetFESpace();
|
||||
ParGridFunction * coords1 = new ParGridFunction(vfes);
|
||||
ParMesh * pmesh1 = prob->GetMesh();
|
||||
pmesh1->SetNodalGridFunction(coords1);
|
||||
tribol::registerMfemCouplingScheme(
|
||||
coupling_scheme_id1, mesh1_id1, mesh2_id1,
|
||||
*pmesh1, *coords1, mortar_attrs, nonmortar_attrs,
|
||||
tribol::SURFACE_TO_SURFACE,
|
||||
tribol::NO_SLIDING,
|
||||
tribol::SINGLE_MORTAR,
|
||||
tribol::FRICTIONLESS,
|
||||
tribol::LAGRANGE_MULTIPLIER,
|
||||
tribol::BINNING_GRID
|
||||
);
|
||||
|
||||
// Access Tribol's pressure grid function (on the contact surface)
|
||||
auto& pressure1 = tribol::getMfemPressure(coupling_scheme_id1);
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of pressure unknowns: " <<
|
||||
pressure1.ParFESpace()->GlobalTrueVSize() << std::endl;
|
||||
}
|
||||
|
||||
// Set Tribol options for Lagrange multiplier enforcement
|
||||
tribol::setLagrangeMultiplierOptions(
|
||||
coupling_scheme_id1,
|
||||
tribol::ImplicitEvalMode::MORTAR_RESIDUAL_JACOBIAN
|
||||
);
|
||||
|
||||
// Update contact mesh decomposition
|
||||
tribol::updateMfemParallelDecomposition();
|
||||
|
||||
// Update contact gaps, forces, and tangent stiffness
|
||||
int cycle1 = 1; // pseudo cycle
|
||||
double t1 = 1.0; // pseudo time
|
||||
double dt1 = 1.0; // pseudo dt
|
||||
tribol::update(cycle1, t1, dt1);
|
||||
|
||||
// Return contact contribution to the tangent stiffness matrix
|
||||
auto A_blk1 = tribol::getMfemBlockJacobian(coupling_scheme_id1);
|
||||
|
||||
HypreParMatrix * Mfull1 = (HypreParMatrix *)(&A_blk1->GetBlock(1,0));
|
||||
Mfull1->EliminateCols(prob->GetEssentialDofs());
|
||||
int h1 = Mfull1->Height();
|
||||
SparseMatrix merged1;
|
||||
Mfull1->MergeDiagAndOffd(merged1);
|
||||
Array<int> nonzero_rows1;
|
||||
for (int i = 0; i<h1; i++)
|
||||
{
|
||||
if (!merged1.RowIsEmpty(i))
|
||||
{
|
||||
nonzero_rows1.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hnew1 = nonzero_rows1.Size();
|
||||
SparseMatrix P1(hnew1,h1);
|
||||
|
||||
for (int i = 0; i<hnew1; i++)
|
||||
{
|
||||
int col = nonzero_rows1[i];
|
||||
P1.Set(i,col,1.0);
|
||||
}
|
||||
P1.Finalize();
|
||||
|
||||
SparseMatrix * reduced_merged1 = Mult(P1,merged1);
|
||||
|
||||
int rows1[2];
|
||||
int cols1[2];
|
||||
cols1[0] = Mfull1->ColPart()[0];
|
||||
cols1[1] = Mfull1->ColPart()[1];
|
||||
int nrows1 = reduced_merged1->Height();
|
||||
|
||||
int row_offset1;
|
||||
MPI_Scan(&nrows1,&row_offset1,1,MPI_INT,MPI_SUM,Mfull1->GetComm());
|
||||
|
||||
row_offset1-=nrows1;
|
||||
rows1[0] = row_offset1;
|
||||
rows1[1] = row_offset1+nrows1;
|
||||
int glob_nrows1;
|
||||
MPI_Allreduce(&nrows1, &glob_nrows1,1,MPI_INT,MPI_SUM,Mfull1->GetComm());
|
||||
|
||||
|
||||
int glob_ncols1 = reduced_merged1->Width();
|
||||
HypreParMatrix * M1 = new HypreParMatrix(Mfull1->GetComm(), nrows1, glob_nrows1,
|
||||
glob_ncols1, reduced_merged1->GetI(), reduced_merged1->GetJ(),
|
||||
reduced_merged1->GetData(), rows1,cols1);
|
||||
|
||||
Vector gap1;
|
||||
tribol::getMfemGap(coupling_scheme_id1, gap1);
|
||||
auto& P_submesh1 = *pressure1.ParFESpace()->GetProlongationMatrix();
|
||||
Vector gap_true1;
|
||||
gap_true1.SetSize(P_submesh1.Width());
|
||||
P_submesh1.MultTranspose(gap1,gap_true1);
|
||||
|
||||
tribol::finalize();
|
||||
|
||||
// ------------------------------
|
||||
// second pass
|
||||
// ------------------------------
|
||||
// Initialize Tribol contact library
|
||||
tribol::initialize(3, MPI_COMM_WORLD);
|
||||
|
||||
int coupling_scheme_id2 = 0;
|
||||
int mesh1_id2 = 0;
|
||||
int mesh2_id2 = 1;
|
||||
ParGridFunction * coords2 = new ParGridFunction(vfes);
|
||||
ParMesh * pmesh2 = prob->GetMesh();
|
||||
pmesh2->SetNodalGridFunction(coords2);
|
||||
tribol::registerMfemCouplingScheme(
|
||||
coupling_scheme_id2, mesh1_id2, mesh2_id2,
|
||||
*pmesh2, *coords2, nonmortar_attrs, mortar_attrs,
|
||||
tribol::SURFACE_TO_SURFACE,
|
||||
tribol::NO_SLIDING,
|
||||
tribol::SINGLE_MORTAR,
|
||||
tribol::FRICTIONLESS,
|
||||
tribol::LAGRANGE_MULTIPLIER,
|
||||
tribol::BINNING_GRID
|
||||
);
|
||||
|
||||
// Access Tribol's pressure grid function (on the contact surface)
|
||||
auto& pressure2 = tribol::getMfemPressure(coupling_scheme_id2);
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of pressure unknowns: " <<
|
||||
pressure2.ParFESpace()->GlobalTrueVSize() << std::endl;
|
||||
}
|
||||
|
||||
// Set Tribol options for Lagrange multiplier enforcement
|
||||
tribol::setLagrangeMultiplierOptions(
|
||||
coupling_scheme_id2,
|
||||
tribol::ImplicitEvalMode::MORTAR_RESIDUAL_JACOBIAN
|
||||
);
|
||||
|
||||
// Update contact mesh decomposition
|
||||
tribol::updateMfemParallelDecomposition();
|
||||
|
||||
// Update contact gaps, forces, and tangent stiffness
|
||||
int cycle2 = 1; // pseudo cycle
|
||||
double t2 = 1.0; // pseudo time
|
||||
double dt2 = 1.0; // pseudo dt
|
||||
tribol::update(cycle2, t2, dt2);
|
||||
|
||||
// Return contact contribution to the tangent stiffness matrix
|
||||
auto A_blk2 = tribol::getMfemBlockJacobian(coupling_scheme_id2);
|
||||
|
||||
HypreParMatrix * Mfull2 = (HypreParMatrix *)(&A_blk2->GetBlock(1,0));
|
||||
Mfull2->EliminateCols(prob->GetEssentialDofs());
|
||||
int h2 = Mfull2->Height();
|
||||
SparseMatrix merged2;
|
||||
Mfull2->MergeDiagAndOffd(merged2);
|
||||
Array<int> nonzero_rows2;
|
||||
for (int i = 0; i<h2; i++)
|
||||
{
|
||||
if (!merged2.RowIsEmpty(i))
|
||||
{
|
||||
nonzero_rows2.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hnew2 = nonzero_rows2.Size();
|
||||
SparseMatrix P2(hnew2,h2);
|
||||
|
||||
for (int i = 0; i<hnew2; i++)
|
||||
{
|
||||
int col = nonzero_rows2[i];
|
||||
P2.Set(i,col,1.0);
|
||||
}
|
||||
P2.Finalize();
|
||||
|
||||
SparseMatrix * reduced_merged2 = Mult(P2,merged2);
|
||||
|
||||
int rows2[2];
|
||||
int cols2[2];
|
||||
cols2[0] = Mfull2->ColPart()[0];
|
||||
cols2[1] = Mfull2->ColPart()[1];
|
||||
int nrows2 = reduced_merged2->Height();
|
||||
|
||||
int row_offset2;
|
||||
MPI_Scan(&nrows2,&row_offset2,1,MPI_INT,MPI_SUM,Mfull2->GetComm());
|
||||
|
||||
row_offset2-=nrows2;
|
||||
rows2[0] = row_offset2;
|
||||
rows2[1] = row_offset2+nrows2;
|
||||
int glob_nrows2;
|
||||
MPI_Allreduce(&nrows2, &glob_nrows2,1,MPI_INT,MPI_SUM,Mfull2->GetComm());
|
||||
|
||||
|
||||
int glob_ncols2 = reduced_merged2->Width();
|
||||
HypreParMatrix * M2 = new HypreParMatrix(Mfull2->GetComm(), nrows2, glob_nrows2,
|
||||
glob_ncols2, reduced_merged2->GetI(), reduced_merged2->GetJ(),
|
||||
reduced_merged2->GetData(), rows2,cols2);
|
||||
|
||||
Vector gap2;
|
||||
tribol::getMfemGap(coupling_scheme_id2, gap2);
|
||||
auto& P_submesh2 = *pressure2.ParFESpace()->GetProlongationMatrix();
|
||||
Vector gap_true2;
|
||||
gap_true2.SetSize(P_submesh2.Width());
|
||||
P_submesh2.MultTranspose(gap2,gap_true2);
|
||||
|
||||
tribol::finalize();
|
||||
|
||||
|
||||
gapv.SetSize(nrows1+nrows2);
|
||||
for (int i = 0; i<nrows1; i++)
|
||||
{
|
||||
gapv[i] = gap_true1[nonzero_rows1[i]];
|
||||
}
|
||||
for (int i = 0; i<nrows2; i++)
|
||||
{
|
||||
gapv[nrows1+i] = gap_true2[nonzero_rows2[i]];
|
||||
}
|
||||
|
||||
Array2D<HypreParMatrix *> A_array(2,1);
|
||||
A_array(0,0) = M1;
|
||||
A_array(1,0) = M2;
|
||||
|
||||
M = HypreParMatrixFromBlocks(A_array);
|
||||
|
||||
constraints_starts.SetSize(2);
|
||||
constraints_starts[0] = M->RowPart()[0];
|
||||
constraints_starts[1] = M->RowPart()[1];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
double ParContactProblem::E(const Vector & d)
|
||||
{
|
||||
Vector kd(K->Height());
|
||||
K->Mult(d,kd);
|
||||
return 0.5 * InnerProduct(comm,d, kd) - InnerProduct(comm,d, *B);
|
||||
}
|
||||
|
||||
void ParContactProblem::DdE(const Vector &d, Vector &gradE)
|
||||
{
|
||||
gradE.SetSize(K->Height());
|
||||
K->Mult(d, gradE);
|
||||
gradE.Add(-1.0, *B);
|
||||
}
|
||||
|
||||
HypreParMatrix* ParContactProblem::DddE(const Vector &d)
|
||||
{
|
||||
return K;
|
||||
}
|
||||
|
||||
void ParContactProblem::g(const Vector &d, Vector &gd)
|
||||
{
|
||||
gd = GetGapFunction();
|
||||
}
|
||||
|
||||
HypreParMatrix* ParContactProblem::Ddg(const Vector &d)
|
||||
{
|
||||
return GetJacobian();
|
||||
}
|
||||
|
||||
HypreParMatrix* ParContactProblem::lDddg(const Vector &d, const Vector &l)
|
||||
{
|
||||
return nullptr; // for now
|
||||
}
|
||||
|
||||
|
||||
QPOptParContactProblem::QPOptParContactProblem(ParContactProblem * problem_, Vector &xref_)
|
||||
: problem(problem_)
|
||||
{
|
||||
dimU = problem->GetNumDofs();
|
||||
dimM = problem->GetNumConstraints();
|
||||
dimC = problem->GetNumConstraints();
|
||||
ml.SetSize(dimM); ml = 0.0;
|
||||
Vector negone(dimM); negone = -1.0;
|
||||
SparseMatrix diag(negone);
|
||||
|
||||
xref.SetSize(xref_.Size());
|
||||
xref.Set(1.0, xref_);
|
||||
|
||||
int gsize = problem->GetGlobalNumConstraints();
|
||||
int * rows = problem->GetConstraintsStarts().GetData();
|
||||
|
||||
NegId = new HypreParMatrix(problem->GetComm(),gsize, rows,&diag);
|
||||
HypreStealOwnership(*NegId, diag);
|
||||
}
|
||||
|
||||
int QPOptParContactProblem::GetDimU() { return dimU; }
|
||||
|
||||
int QPOptParContactProblem::GetDimM() { return dimM; }
|
||||
|
||||
int QPOptParContactProblem::GetDimC() { return dimC; }
|
||||
|
||||
Vector & QPOptParContactProblem::Getml() { return ml; }
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Duuf(const BlockVector & x)
|
||||
{
|
||||
return problem->DddE(x.GetBlock(0));
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dumf(const BlockVector & x)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dmuf(const BlockVector & x)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dmmf(const BlockVector & x)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Duc(const BlockVector & x)
|
||||
{
|
||||
return problem->Ddg(x.GetBlock(0));
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dmc(const BlockVector & x)
|
||||
{
|
||||
return NegId;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::lDuuc(const BlockVector & x, const Vector & l)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void QPOptParContactProblem::c(const BlockVector &x, Vector & y)
|
||||
{
|
||||
Vector g0; // g(dref)
|
||||
problem->g(x.GetBlock(0), g0); // gap function
|
||||
|
||||
// temp = d - xref (expansion)
|
||||
Vector temp(x.GetBlock(0).Size()); temp = 0.0;
|
||||
temp.Set(1.0, x.GetBlock(0));
|
||||
temp.Add(-1.0, xref); // displacement at previous time step
|
||||
|
||||
problem->GetJacobian()->Mult(temp, y); // J * (d - xref)
|
||||
y.Add(1.0, g0); // J * (d - xref) + g0
|
||||
y.Add(-1.0, x.GetBlock(1)); // J * (d - xref) + g0 - s
|
||||
}
|
||||
|
||||
double QPOptParContactProblem::CalcObjective(const BlockVector & x)
|
||||
{
|
||||
return problem->E(x.GetBlock(0));
|
||||
}
|
||||
|
||||
void QPOptParContactProblem::CalcObjectiveGrad(const BlockVector & x, BlockVector & y)
|
||||
{
|
||||
problem->DdE(x.GetBlock(0), y.GetBlock(0));
|
||||
y.GetBlock(1) = 0.0;
|
||||
}
|
||||
|
||||
QPOptParContactProblem::~QPOptParContactProblem()
|
||||
{
|
||||
delete NegId;
|
||||
}
|
||||
|
||||
// #endif
|
||||
@@ -1,335 +0,0 @@
|
||||
|
||||
#include "parproblems_util.hpp"
|
||||
|
||||
class ParElasticityProblem
|
||||
{
|
||||
private:
|
||||
MPI_Comm comm;
|
||||
bool formsystem = false;
|
||||
ParMesh * pmesh = nullptr;
|
||||
Array<int> ess_bdr_attr, ess_bdr_attr_comp;
|
||||
int order;
|
||||
int ndofs;
|
||||
int ntdofs;
|
||||
int gndofs;
|
||||
FiniteElementCollection * fec = nullptr;
|
||||
ParFiniteElementSpace * fes = nullptr;
|
||||
Vector lambda, mu;
|
||||
PWConstCoefficient lambda_cf, mu_cf;
|
||||
Array<int> ess_bdr, ess_tdof_list;
|
||||
ParBilinearForm * a = nullptr;
|
||||
ParLinearForm * b = nullptr;
|
||||
ParGridFunction x;
|
||||
HypreParMatrix A;
|
||||
Vector B,X;
|
||||
ConstantCoefficient pressure_cf;
|
||||
VectorArrayCoefficient * bf = nullptr;
|
||||
void Init();
|
||||
bool own_mesh;
|
||||
public:
|
||||
ParElasticityProblem(MPI_Comm comm_, const char *mesh_file , int sref, int pref,
|
||||
Array<int> & ess_bdr_attr_, Array<int> & ess_bdr_attr_comp_,
|
||||
int order_ = 1 )
|
||||
: comm(comm_), ess_bdr_attr(ess_bdr_attr_),ess_bdr_attr_comp(ess_bdr_attr_comp_), order(order_)
|
||||
{
|
||||
own_mesh = true;
|
||||
Mesh * mesh = new Mesh(mesh_file,1,1);
|
||||
for (int i = 0; i<sref; i++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
pmesh = new ParMesh(comm,*mesh);
|
||||
MFEM_VERIFY(pmesh->GetNE(), "ParElasticityProblem::Empty partition");
|
||||
delete mesh;
|
||||
for (int i = 0; i<pref; i++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
Init();
|
||||
}
|
||||
|
||||
ParElasticityProblem(ParMesh * pmesh_, Array<int> & ess_bdr_attr_, Array<int> & ess_bdr_attr_comp_, int order_ = 1)
|
||||
: pmesh(pmesh_), ess_bdr_attr(ess_bdr_attr_), ess_bdr_attr_comp(ess_bdr_attr_comp_), order(order_)
|
||||
{
|
||||
own_mesh = false;
|
||||
comm = pmesh->GetComm();
|
||||
Init();
|
||||
}
|
||||
|
||||
ParMesh * GetMesh() { return pmesh; }
|
||||
ParFiniteElementSpace * GetFESpace() { return fes; }
|
||||
FiniteElementCollection * GetFECol() { return fec; }
|
||||
int GetNumDofs() { return ndofs; }
|
||||
int GetNumTDofs() { return ntdofs; }
|
||||
int GetGlobalNumDofs() { return gndofs; }
|
||||
HypreParMatrix & GetOperator()
|
||||
{
|
||||
MFEM_VERIFY(formsystem, "System not formed yet. Call FormLinearSystem()");
|
||||
return A;
|
||||
}
|
||||
Vector & GetRHS()
|
||||
{
|
||||
MFEM_VERIFY(formsystem, "System not formed yet. Call FormLinearSystem()");
|
||||
return B;
|
||||
}
|
||||
|
||||
void SetLambda(const Vector & lambda_)
|
||||
{
|
||||
lambda = lambda_;
|
||||
lambda_cf.UpdateConstants(lambda);
|
||||
}
|
||||
void SetMu(const Vector & mu_)
|
||||
{
|
||||
mu = mu_;
|
||||
mu_cf.UpdateConstants(mu);
|
||||
}
|
||||
|
||||
void SetNeumanPressureData(ConstantCoefficient &f, Array<int> & bdr_marker)
|
||||
{
|
||||
pressure_cf.constant = f.constant;
|
||||
b->AddBoundaryIntegrator(new VectorBoundaryFluxLFIntegrator(pressure_cf),bdr_marker);
|
||||
}
|
||||
|
||||
void SetNeumanData(int comp, int bdrattr, double value)
|
||||
{
|
||||
int dim = pmesh->Dimension();
|
||||
bf = new VectorArrayCoefficient(dim);
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
if (i == comp)
|
||||
{
|
||||
Vector pull_force(pmesh->bdr_attributes.Max());
|
||||
pull_force = 0.0;
|
||||
pull_force(bdrattr-1) = value;
|
||||
bf->Set(i, new PWConstCoefficient(pull_force));
|
||||
}
|
||||
else
|
||||
{
|
||||
bf->Set(i, new ConstantCoefficient(0.0));
|
||||
}
|
||||
}
|
||||
b->AddBoundaryIntegrator(new VectorBoundaryLFIntegrator(*bf));
|
||||
}
|
||||
|
||||
void UpdateEssentialBC(Array<int> & ess_bdr_attr_, Array<int> & ess_bdr_attr_comp_)
|
||||
{
|
||||
ess_bdr_attr = ess_bdr_attr_;
|
||||
ess_bdr_attr_comp = ess_bdr_attr_comp_;
|
||||
ess_tdof_list.SetSize(0);
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(pmesh->bdr_attributes.Max());
|
||||
}
|
||||
ess_bdr = 0;
|
||||
Array<int> ess_tdof_list_temp;
|
||||
for (int i = 0; i < ess_bdr_attr.Size(); i++ )
|
||||
{
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 1;
|
||||
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list_temp,ess_bdr_attr_comp[i]);
|
||||
ess_tdof_list.Append(ess_tdof_list_temp);
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateStep()
|
||||
{
|
||||
if (formsystem)
|
||||
{
|
||||
delete b;
|
||||
b = new ParLinearForm(fes);
|
||||
delete a;
|
||||
a = new ParBilinearForm(fes);
|
||||
a->AddDomainIntegrator(new ElasticityIntegrator(lambda_cf,mu_cf));
|
||||
|
||||
|
||||
// a->Update();
|
||||
formsystem = false;
|
||||
}
|
||||
}
|
||||
|
||||
void FormLinearSystem();
|
||||
void UpdateLinearSystem();
|
||||
|
||||
void SetDisplacementDirichletData(const Vector & delta)
|
||||
{
|
||||
VectorConstantCoefficient delta_cf(delta);
|
||||
x.ProjectBdrCoefficient(delta_cf,ess_bdr);
|
||||
bool vis = false;
|
||||
if (vis)
|
||||
{
|
||||
int myid, num_procs;
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *pmesh << x << std::flush;
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
};
|
||||
|
||||
void ResetDisplacementDirichletData()
|
||||
{
|
||||
x = 0.0;
|
||||
}
|
||||
|
||||
void SetDisplacementDirichletData(const Vector & delta, Array<int> essbdr)
|
||||
{
|
||||
VectorConstantCoefficient delta_cf(delta);
|
||||
x.ProjectBdrCoefficient(delta_cf,essbdr);
|
||||
bool vis = false;
|
||||
if (vis)
|
||||
{
|
||||
int myid, num_procs;
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *pmesh << x << std::flush;
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
};
|
||||
|
||||
ParGridFunction & GetDisplacementGridFunction() {return x;};
|
||||
Array<int> & GetEssentialDofs() {return ess_tdof_list;};
|
||||
|
||||
~ParElasticityProblem()
|
||||
{
|
||||
delete a;
|
||||
delete b;
|
||||
delete fes;
|
||||
delete fec;
|
||||
if (own_mesh)
|
||||
{
|
||||
delete pmesh;
|
||||
}
|
||||
delete bf;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #ifdef MFEM_USE_TRIBOL
|
||||
|
||||
class ParContactProblem
|
||||
{
|
||||
private:
|
||||
MPI_Comm comm;
|
||||
int numprocs;
|
||||
int myid;
|
||||
ParElasticityProblem * prob = nullptr;
|
||||
ParFiniteElementSpace * vfes = nullptr;
|
||||
int dim;
|
||||
GridFunction nodes0;
|
||||
GridFunction *nodes1 = nullptr;
|
||||
std::set<int> contact_vertices;
|
||||
std::vector<int> dof_offsets;
|
||||
std::vector<int> vertex_offsets;
|
||||
std::vector<int> constraints_offsets;
|
||||
Array<int> tdof_offsets;
|
||||
Array<int> constraints_starts;
|
||||
Array<int> globalvertices;
|
||||
Array<int> vertices;
|
||||
ParGridFunction * coords = nullptr;
|
||||
//ParGridFunction * xref = nullptr;
|
||||
|
||||
protected:
|
||||
int npoints=0;
|
||||
int gnpoints=0;
|
||||
int nv, gnv;
|
||||
HypreParMatrix * K = nullptr;
|
||||
HypreParMatrix * Pi = nullptr;
|
||||
HypreParMatrix * Pb = nullptr;
|
||||
Vector *B = nullptr;
|
||||
Vector gapv;
|
||||
HypreParMatrix * M=nullptr;
|
||||
void SetupTribol();
|
||||
void SetupTribolDoublePass();
|
||||
std::set<int> mortar_attrs;
|
||||
// plane of top block
|
||||
std::set<int> nonmortar_attrs;
|
||||
bool doublepass = false;
|
||||
|
||||
public:
|
||||
ParContactProblem(ParElasticityProblem * prob_,
|
||||
const std::set<int> & mortar_attrs_, const std::set<int> & nonmortar_attrs_,
|
||||
ParGridFunction * coords_,
|
||||
bool doublepass = false);
|
||||
|
||||
ParElasticityProblem * GetElasticityProblem() {return prob;}
|
||||
MPI_Comm GetComm() {return comm;}
|
||||
int GetNumDofs() {return K->Height();}
|
||||
int GetGlobalNumDofs() {return K->GetGlobalNumRows();}
|
||||
int GetNumConstraints() {return M->Height();}
|
||||
int GetGlobalNumConstraints() { return M->GetGlobalNumRows(); }
|
||||
|
||||
std::vector<int> & GetDofOffets() { return dof_offsets; }
|
||||
std::vector<int> & GetVertexOffsets() { return vertex_offsets; }
|
||||
std::vector<int> & GetConstraintsOffsets() { return constraints_offsets; }
|
||||
Array<int> & GetConstraintsStarts() { return constraints_starts; }
|
||||
|
||||
Vector & GetGapFunction() {return gapv;}
|
||||
|
||||
HypreParMatrix * GetJacobian() {return M;}
|
||||
|
||||
double E(const Vector & d);
|
||||
void DdE(const Vector &d, Vector &gradE);
|
||||
HypreParMatrix* DddE(const Vector &d);
|
||||
void g(const Vector &d, Vector &gd);
|
||||
HypreParMatrix* Ddg(const Vector &d);
|
||||
HypreParMatrix* lDddg(const Vector &d, const Vector &l);
|
||||
|
||||
HypreParMatrix * GetRestrictionToInteriorDofs() {return Pi;}
|
||||
HypreParMatrix * GetRestrictionToContactDofs() {return Pb;}
|
||||
|
||||
~ParContactProblem()
|
||||
{
|
||||
delete B;
|
||||
delete K;
|
||||
delete M;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class QPOptParContactProblem
|
||||
{
|
||||
private:
|
||||
ParContactProblem * problem = nullptr;
|
||||
int dimU, dimM, dimC;
|
||||
Vector ml;
|
||||
HypreParMatrix * NegId = nullptr;
|
||||
Vector xref;
|
||||
public:
|
||||
QPOptParContactProblem(ParContactProblem * problem_, Vector & xref_);
|
||||
int GetDimU();
|
||||
int GetDimM();
|
||||
int GetDimC();
|
||||
Vector & Getml();
|
||||
MPI_Comm GetComm() {return problem->GetComm();}
|
||||
int * GetConstraintsStarts() {return problem->GetConstraintsStarts().GetData();}
|
||||
int GetGlobalNumConstraints() {return problem->GetGlobalNumConstraints();}
|
||||
|
||||
ParElasticityProblem * GetElasticityProblem() {return problem->GetElasticityProblem();}
|
||||
|
||||
HypreParMatrix * Duuf(const BlockVector &);
|
||||
HypreParMatrix * Dumf(const BlockVector &);
|
||||
HypreParMatrix * Dmuf(const BlockVector &);
|
||||
HypreParMatrix * Dmmf(const BlockVector &);
|
||||
HypreParMatrix * Duc(const BlockVector &);
|
||||
HypreParMatrix * Dmc(const BlockVector &);
|
||||
HypreParMatrix * lDuuc(const BlockVector &, const Vector &);
|
||||
|
||||
HypreParMatrix * GetRestrictionToInteriorDofs() {return problem->GetRestrictionToInteriorDofs();}
|
||||
HypreParMatrix * GetRestrictionToContactDofs() {return problem->GetRestrictionToContactDofs();}
|
||||
|
||||
void c(const BlockVector &, Vector &);
|
||||
double CalcObjective(const BlockVector &);
|
||||
void CalcObjectiveGrad(const BlockVector &, BlockVector &);
|
||||
~QPOptParContactProblem();
|
||||
};
|
||||
|
||||
// #endif
|
||||
@@ -1,115 +0,0 @@
|
||||
#include "parproblems_util.hpp"
|
||||
|
||||
int get_rank(int tdof, std::vector<int> & tdof_offsets)
|
||||
{
|
||||
int size = tdof_offsets.size();
|
||||
if (size == 1) { return 0; }
|
||||
std::vector<int>::iterator up;
|
||||
up=std::upper_bound(tdof_offsets.begin(), tdof_offsets.end(),tdof); //
|
||||
return std::distance(tdof_offsets.begin(),up)-1;
|
||||
}
|
||||
|
||||
void ComputeTdofOffsets(const ParFiniteElementSpace * pfes,
|
||||
std::vector<int> & tdof_offsets)
|
||||
{
|
||||
MPI_Comm comm = pfes->GetComm();
|
||||
int num_procs;
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
tdof_offsets.resize(num_procs);
|
||||
int mytoffset = pfes->GetMyTDofOffset();
|
||||
MPI_Allgather(&mytoffset,1,MPI_INT,&tdof_offsets[0],1,MPI_INT,comm);
|
||||
}
|
||||
|
||||
void ComputeTdofOffsets(MPI_Comm comm, int mytoffset, std::vector<int> & tdof_offsets)
|
||||
{
|
||||
int num_procs;
|
||||
MPI_Comm_size(comm,&num_procs);
|
||||
tdof_offsets.resize(num_procs);
|
||||
MPI_Allgather(&mytoffset,1,MPI_INT,&tdof_offsets[0],1,MPI_INT,comm);
|
||||
}
|
||||
|
||||
void ComputeTdofs(MPI_Comm comm, int mytoffs, std::vector<int> & tdofs)
|
||||
{
|
||||
int num_procs;
|
||||
MPI_Comm_size(comm,&num_procs);
|
||||
tdofs.resize(num_procs);
|
||||
MPI_Allgather(&mytoffs,1,MPI_INT,&tdofs,1,MPI_INT,comm);
|
||||
}
|
||||
|
||||
|
||||
// Performs Pᵀ * A * P for BlockOperator P (with blocks as HypreParMatrices)
|
||||
// and A a HypreParMatrix, i.e., this handles the special case
|
||||
// where P = [P₁ P₂ ⋅⋅⋅ Pₙ]
|
||||
// C = Pᵀ * A * P
|
||||
void RAP(const HypreParMatrix & A, const BlockOperator & P,
|
||||
BlockOperator & C)
|
||||
{
|
||||
int nblocks = P.NumColBlocks();
|
||||
|
||||
const HypreParMatrix * Pi = nullptr;
|
||||
const HypreParMatrix * Pj = nullptr;
|
||||
HypreParMatrix * PitAPj = nullptr;
|
||||
|
||||
for (int i = 0; i< nblocks; i++)
|
||||
{
|
||||
if (P.IsZeroBlock(0,i)) continue;
|
||||
Pi = dynamic_cast<const HypreParMatrix*>(&P.GetBlock(0,i));
|
||||
for (int j = 0; j<nblocks; j++)
|
||||
{
|
||||
if (P.IsZeroBlock(0,j)) continue;
|
||||
Pj = dynamic_cast<const HypreParMatrix*>(&P.GetBlock(0,j));
|
||||
if (i == j)
|
||||
{
|
||||
PitAPj = RAP(&A, Pj);
|
||||
}
|
||||
else
|
||||
{
|
||||
PitAPj = RAP(Pi, &A, Pj);
|
||||
}
|
||||
C.SetBlock(i,j,PitAPj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParAdd(const BlockOperator & A, const BlockOperator & B, BlockOperator & C)
|
||||
{
|
||||
int n = A.NumRowBlocks();
|
||||
int m = A.NumColBlocks();
|
||||
MFEM_VERIFY(B.NumRowBlocks() == n, "Inconsistent number of row blocks");
|
||||
MFEM_VERIFY(B.NumColBlocks() == m, "Inconsistent number of column blocks");
|
||||
|
||||
const HypreParMatrix * a;
|
||||
const HypreParMatrix * b;
|
||||
for (int i = 0; i<n; i++)
|
||||
{
|
||||
for (int j = 0; j<m; j++)
|
||||
{
|
||||
a = nullptr;
|
||||
b = nullptr;
|
||||
if (!A.IsZeroBlock(i,j))
|
||||
{
|
||||
a = dynamic_cast<const HypreParMatrix*>(&A.GetBlock(i,j));
|
||||
}
|
||||
if (!B.IsZeroBlock(i,j))
|
||||
{
|
||||
b = dynamic_cast<const HypreParMatrix*>(&B.GetBlock(i,j));
|
||||
}
|
||||
if (a && b)
|
||||
{
|
||||
C.SetBlock(i,j,ParAdd(a,b));
|
||||
}
|
||||
else if (a)
|
||||
{
|
||||
C.SetBlock(i,j,new HypreParMatrix(*a));
|
||||
}
|
||||
else if (b)
|
||||
{
|
||||
C.SetBlock(i,j,new HypreParMatrix(*b));
|
||||
}
|
||||
else
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
#include "mfem.hpp"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
#include "axom/slic.hpp"
|
||||
|
||||
#include "tribol/interface/tribol.hpp"
|
||||
#include "tribol/interface/mfem_tribol.hpp"
|
||||
int get_rank(int tdof, std::vector<int> & tdof_offsets);
|
||||
void ComputeTdofOffsets(const ParFiniteElementSpace * pfes,
|
||||
std::vector<int> & tdof_offsets);
|
||||
void ComputeTdofOffsets(MPI_Comm comm, int mytoffset, std::vector<int> & tdof_offsets);
|
||||
void ComputeTdofs(MPI_Comm comm, int mytoffs, std::vector<int> & tdofs);
|
||||
|
||||
|
||||
// Performs Pᵀ * A * P for BlockOperator P (with blocks as HypreParMatrices)
|
||||
// and A a HypreParMatrix, i.e., this handles the special case
|
||||
// where P = [P₁ P₂ ⋅⋅⋅ Pₙ]
|
||||
void RAP(const HypreParMatrix & A, const BlockOperator & P, BlockOperator & C);
|
||||
void ParAdd(const BlockOperator & A, const BlockOperator & B, BlockOperator & C);
|
||||
@@ -1,564 +0,0 @@
|
||||
// Parallel contact example
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 1 -testno 4
|
||||
// CG iteration numbers = 105 114 116 115 113 109 113 108 107 114 206 236 268 435 987
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 5
|
||||
// CG iteration numbers = 106 116 116 116 115 113 107 107 128 131 531 1437 1318
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 6
|
||||
// CG iteration numbers = 18 18 18 18 18 17 17 21 22 46 52 53
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "ipsolver/ParIPsolver.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Mpi::Init();
|
||||
int myid = Mpi::WorldRank();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
Hypre::Init();
|
||||
|
||||
int order = 1;
|
||||
int sref = 1;
|
||||
int pref = 0;
|
||||
Array<int> attr;
|
||||
Array<int> m_attr;
|
||||
bool visualization = true;
|
||||
bool paraview = false;
|
||||
bool elast = false;
|
||||
bool nocontact = false;
|
||||
int testNo = -1; // 0-6
|
||||
// 1. Parse command-line options.
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&testNo, "-testno", "--test-number",
|
||||
"Choice of test problem:"
|
||||
"-1: default (original 2 block problem)"
|
||||
"0: not implemented yet"
|
||||
"1: not implemented yet"
|
||||
"2: not implemented yet"
|
||||
"3: not implemented yet"
|
||||
"4: two block problem - diablo"
|
||||
"41: two block problem - twisted"
|
||||
"5: ironing problem"
|
||||
"51: ironing problem extended"
|
||||
"6: nested spheres problem");
|
||||
args.AddOption(&attr, "-at", "--attributes-surf",
|
||||
"Attributes of boundary faces on contact surface for mesh 2.");
|
||||
args.AddOption(&sref, "-sr", "--serial-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&pref, "-pr", "--parallel-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&elast, "-elast", "--elast", "-no-elast",
|
||||
"--no-elast",
|
||||
"Enable or disable AMG Elasticity options.");
|
||||
args.AddOption(&nocontact, "-nocontact", "--nocontact", "-no-nocontact",
|
||||
"--no-nocontact",
|
||||
"Enable or disable AMG solve with no contact for testing.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(¶view, "-paraview", "--paraview", "-no-paraview",
|
||||
"--no-paraview",
|
||||
"Enable or disable ParaView visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
if (Mpi::Root())
|
||||
{
|
||||
mfem::out << "Solving test problem number: " << testNo << endl;
|
||||
}
|
||||
|
||||
const char *mesh_file = nullptr;
|
||||
|
||||
switch (testNo)
|
||||
{
|
||||
case -1:
|
||||
mesh_file = "meshes/two-block.mesh";
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
MFEM_ABORT("Problem not implemented yet");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
mesh_file = "meshes/Test4.mesh";
|
||||
break;
|
||||
case 40:
|
||||
mesh_file = "meshes/Test40.mesh";
|
||||
break;
|
||||
case 41:
|
||||
mesh_file = "meshes/Test41.mesh";
|
||||
break;
|
||||
case 42:
|
||||
mesh_file = "meshes/Test42.mesh";
|
||||
break;
|
||||
case 5:
|
||||
mesh_file = "meshes/Test5.mesh";
|
||||
break;
|
||||
case 51:
|
||||
mesh_file = "meshes/Test51.mesh";
|
||||
break;
|
||||
case 6:
|
||||
mesh_file = "meshes/Test6.mesh";
|
||||
break;
|
||||
case 61:
|
||||
// Something wrong with this mesh
|
||||
mesh_file = "meshes/Test61.mesh";
|
||||
break;
|
||||
case 62:
|
||||
mesh_file = "meshes/Test62.mesh";
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Should be unreachable");
|
||||
break;
|
||||
}
|
||||
|
||||
Mesh * mesh = new Mesh(mesh_file,1);
|
||||
for (int i = 0; i<sref; i++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
ParMesh * pmesh = new ParMesh(MPI_COMM_WORLD,*mesh);
|
||||
|
||||
for (int i = 0; i<pref; i++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
Array<int> ess_bdr_attr;
|
||||
Array<int> ess_bdr_attr_comp;
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(1);
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(2);
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 62)
|
||||
{
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 40)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(10); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(6); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
ParElasticityProblem * prob = new ParElasticityProblem(pmesh,
|
||||
ess_bdr_attr,ess_bdr_attr_comp,
|
||||
order);
|
||||
Vector lambda(prob->GetMesh()->attributes.Max());
|
||||
Vector mu(prob->GetMesh()->attributes.Max());
|
||||
|
||||
if (testNo == -1 )
|
||||
{
|
||||
lambda = 57.6923076923;
|
||||
mu = 38.4615384615;
|
||||
}
|
||||
else if (testNo == 6 || testNo == 61 || testNo == 62)
|
||||
{
|
||||
lambda = (1000*0.3)/(1.3*0.4);
|
||||
mu = 500/(1.3);
|
||||
}
|
||||
else
|
||||
{
|
||||
lambda[0] = 0.499/(1.499*0.002);
|
||||
lambda[1] = 0.0;
|
||||
mu[0] = 1./(2*1.499);
|
||||
mu[1] = 500;
|
||||
}
|
||||
|
||||
prob->SetLambda(lambda); prob->SetMu(mu);
|
||||
|
||||
int dim = pmesh->Dimension();
|
||||
Vector ess_values(dim);
|
||||
int essbdr_attr;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
|
||||
ess_values = 0.0;
|
||||
|
||||
|
||||
// ConstantCoefficient one(-area);
|
||||
ConstantCoefficient one(-1.0);
|
||||
|
||||
std::set<int> mortar_attr;
|
||||
std::set<int> nonmortar_attr;
|
||||
|
||||
int nsteps = 100;
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[0] = 1;
|
||||
ess_bdr[1] = 1;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else if(testNo == 62)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
prob->SetNeumanData(0,3,-2.0);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (testNo == -1 || testNo == 41)
|
||||
{
|
||||
ess_values[0] = 0.1/nsteps;
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_values[2] = 1.0/1.4/nsteps;
|
||||
// ess_values[0] = -2.0/nsteps;
|
||||
}
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = (testNo == 40) ? 10 : 6;
|
||||
ess_values = 0.0; ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
if (testNo == 40)
|
||||
{
|
||||
mortar_attr.insert(4);
|
||||
nonmortar_attr.insert(7);
|
||||
}
|
||||
else
|
||||
{
|
||||
mortar_attr.insert(3);
|
||||
nonmortar_attr.insert(4);
|
||||
}
|
||||
}
|
||||
|
||||
ParFiniteElementSpace * fes = prob->GetFESpace();
|
||||
ParGridFunction x_gf(fes); x_gf = 0.0;
|
||||
ParGridFunction xnew(fes); xnew = 0.0;
|
||||
ParaViewDataCollection * paraview_dc = nullptr;
|
||||
ParMesh pmesh_copy(*pmesh);
|
||||
ParFiniteElementSpace fes_copy(*fes,pmesh_copy);
|
||||
ParGridFunction xcopy_gf(&fes_copy); xcopy_gf = 0.0;
|
||||
|
||||
if (paraview)
|
||||
{
|
||||
std::ostringstream paraview_file_name;
|
||||
paraview_file_name << "QPContact-Test_" << testNo
|
||||
<< "_par_ref_" << pref
|
||||
<< "_ser_ref_" << sref;
|
||||
paraview_dc = new ParaViewDataCollection(paraview_file_name.str(), &pmesh_copy);
|
||||
paraview_dc->SetPrefixPath("ParaView");
|
||||
paraview_dc->SetLevelsOfDetail(1);
|
||||
paraview_dc->SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc->SetHighOrderOutput(true);
|
||||
// paraview_dc->RegisterField("u", &x_gf);
|
||||
paraview_dc->RegisterField("u", &xcopy_gf);
|
||||
paraview_dc->SetCycle(0);
|
||||
paraview_dc->SetTime(double(0));
|
||||
paraview_dc->Save();
|
||||
}
|
||||
socketstream sol_sock;
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
sol_sock.open(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
}
|
||||
|
||||
|
||||
ParGridFunction ref_coords(prob->GetFESpace());
|
||||
ParGridFunction new_coords(prob->GetFESpace());
|
||||
pmesh->GetNodes(new_coords);
|
||||
pmesh->GetNodes(ref_coords);
|
||||
|
||||
Vector xref(x_gf.GetTrueVector().Size());
|
||||
|
||||
double p = 1;
|
||||
ConstantCoefficient f(p);
|
||||
|
||||
double pseudotime = 1.0 / ((double) nsteps);
|
||||
if (testNo == 6)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
f.constant = -p * pseudotime;
|
||||
prob->SetNeumanPressureData(f,ess_bdr);
|
||||
// prob->SetNeumanData(0,3,-p*(i+1)/nsteps);
|
||||
}
|
||||
else if (testNo == 4 || testNo == 40 || testNo == 5 || testNo == 51)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
ess_values = 0.0;
|
||||
//ess_values[2] = 4.0 / 7.0 * pseudotime;
|
||||
ess_values[2] = 1.0/1.4 * pseudotime;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
else if (testNo == 41)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_values[0] = 0.5 * pseudotime; //0.5/nsteps*(i+1);
|
||||
// ess_values[0] = 0.0;
|
||||
essbdr_attr = 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = 6;
|
||||
ess_values = 0.0;
|
||||
// ess_values[0] = -0.5/nsteps*(i+1);
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "ess_values[0] = " << ess_values[0] << endl;
|
||||
}
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
|
||||
|
||||
/* ------- finite difference check -------- */
|
||||
Vector x0(fes->GetTrueVSize()); x0 = 0.0;
|
||||
//x0 = 2.0;
|
||||
//x0.Randomize(); x0 *= 1.e-2;
|
||||
Array<int> vdofs;
|
||||
for (int i = 0; i < pmesh->GetNE(); i++)
|
||||
{
|
||||
cout << "attribute = " << pmesh->GetAttribute(i) << endl;
|
||||
if (pmesh->GetAttribute(i) == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
for (int j = 0; j < vdofs.Size(); j++)
|
||||
{
|
||||
x0(vdofs[j]) = 0.01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
x_gf.SetFromTrueDofs(x0);
|
||||
add(ref_coords, x_gf, new_coords);
|
||||
|
||||
Vector x1(fes->GetTrueVSize()); x1 = 0.0;
|
||||
Vector xdir(fes->GetTrueVSize()); xdir.Randomize();
|
||||
Vector temp(fes->GetTrueVSize()); temp = 0.0;
|
||||
xdir *= 1.e-2; // scale so as to avoid mesh tangling
|
||||
double eps = 1.0;
|
||||
|
||||
ParContactProblem ref_contact(prob, mortar_attr, nonmortar_attr, &new_coords);
|
||||
int ndofs = ref_contact.GetNumDofs();
|
||||
int nconstraints = ref_contact.GetNumConstraints();
|
||||
Vector g0 = ref_contact.GetGapFunction();
|
||||
g0.Print();
|
||||
HypreParMatrix * J0 = ref_contact.GetJacobian();
|
||||
|
||||
//for (int i = 0; i < 30; i++)
|
||||
//{
|
||||
// x1.Set(1.0, x0); // x1 = x0 + eps * xdir
|
||||
// x1.Add(eps, xdir);
|
||||
// x_gf.SetFromTrueDofs(x1);
|
||||
// add(ref_coords, x_gf, new_coords);
|
||||
// ParContactProblem new_contact(prob, mortar_attr, nonmortar_attr, &new_coords);
|
||||
// Vector g1 = new_contact.GetGapFunction(); // g1 = g(x0 + eps * xdir)
|
||||
// Vector fd_err(g1.Size());
|
||||
|
||||
// // ||J0 * xdir - (g1 - g0) / eps||
|
||||
// J0->Mult(xdir, fd_err);
|
||||
// fd_err.Add(-1.0 / eps, g1);
|
||||
// fd_err.Add(1.0 / eps, g0);
|
||||
// cout << "fd err = " << fd_err.Norml2() << ", eps = " << eps << endl;
|
||||
// eps /= 2.0;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
//for (int i = 0; i < 30; i++)
|
||||
//{
|
||||
//// add(ref_coords,x_gf,new_coords);
|
||||
//
|
||||
//}
|
||||
|
||||
|
||||
//for (int i = 0; i < nsteps; i++)
|
||||
//{
|
||||
// //pseudotime = ((double) (i) / ((double) SQPrepeat) + 1.) / ((double) nsteps);
|
||||
// pseudotime = ((double) (i)) / ((double) nsteps);
|
||||
// for (int j = 0; j < SQPrepeat; j++)
|
||||
// {
|
||||
// paraview_time = pseudotime + j * paraview_subtimestep;
|
||||
|
||||
// //xref.Set(1.0, new_coords.GetTrueVector());
|
||||
// //xref.Add(-1.0, ref_coords.GetTrueVector());
|
||||
// xref.Set(1.0, x_gf.GetTrueVector());
|
||||
// ParContactProblem contact(prob, mortar_attr, nonmortar_attr, &new_coords, doublepass);
|
||||
// QPOptParContactProblem qpopt(&contact, xref);
|
||||
// int numconstr = contact.GetGlobalNumConstraints();
|
||||
// ParInteriorPointSolver optimizer(&qpopt);
|
||||
// optimizer.SetTol(optimizer_tol);
|
||||
// optimizer.SetMaxIter(optimizer_maxit);
|
||||
// optimizer.SetLinearSolver(linsolver);
|
||||
// optimizer.SetLinearSolveRelTol(linsolverrtol);
|
||||
// optimizer.SetLinearSolveAbsTol(linsolveratol);
|
||||
// optimizer.SetLinearSolveRelaxType(relax_type);
|
||||
// if (nocontact)
|
||||
// {
|
||||
// optimizer.EnableNoContactSolve();
|
||||
// }
|
||||
// if (elast)
|
||||
// {
|
||||
// optimizer.SetElasticityOptions(prob->GetFESpace());
|
||||
// }
|
||||
// // ParGridFunction x = prob->GetDisplacementGridFunction();
|
||||
// // x.SetTrueVector();
|
||||
// // Vector x0 = x.GetTrueVector();
|
||||
|
||||
// x_gf.SetTrueVector();
|
||||
// Vector x0 = x_gf.GetTrueVector();
|
||||
// int ndofs = x0.Size();
|
||||
// Vector xf(ndofs); xf = 0.0;
|
||||
// optimizer.Mult(x0, xf);
|
||||
// QPConverged = optimizer.GetConverged();
|
||||
// MFEM_VERIFY(QPConverged, "IPM not converged on QP contact problem");
|
||||
// //optimizer.SaveLambda(i);
|
||||
// //optimizer.SaveZl(i);
|
||||
// Vector xf_copy(xf);
|
||||
// xf_copy+=x0;
|
||||
// double Einitial = contact.E(x0);
|
||||
// // double Efinal = contact.E(xf);
|
||||
// double Efinal = contact.E(xf_copy);
|
||||
// Array<int> & CGiterations = optimizer.GetCGIterNumbers();
|
||||
// int gndofs = prob->GetGlobalNumDofs();
|
||||
// //dgdu = contact.Ddg(xf_copy);
|
||||
// //std::ostringstream dgdu_file_name;
|
||||
// //dgdu_file_name << "Jacobians/J" << i;
|
||||
// //dgdu->Print(dgdu_file_name.str().c_str());
|
||||
// if (Mpi::Root())
|
||||
// {
|
||||
// mfem::out << endl;
|
||||
// mfem::out << " Initial Energy objective = " << Einitial << endl;
|
||||
// mfem::out << " Final Energy objective = " << Efinal << endl;
|
||||
// mfem::out << " Global number of dofs = " << gndofs << endl;
|
||||
// mfem::out << " Global number of constraints = " << numconstr << endl;
|
||||
// mfem::out << " Optimizer number of iterations = " <<
|
||||
// optimizer.GetNumIterations() << endl;
|
||||
// if (linsolver == 2 || linsolver == 3 || linsolver == 4)
|
||||
// {
|
||||
// mfem::out << " CG iteration numbers = " ;
|
||||
// CGiterations.Print(mfem::out, CGiterations.Size());
|
||||
// }
|
||||
// if (nocontact)
|
||||
// {
|
||||
// Array<int> & CGNoContactIterations = optimizer.GetCGNoContactIterNumbers();
|
||||
// mfem::out << " CG no Contact iteration numbers = " ;
|
||||
// CGNoContactIterations.Print(mfem::out, CGNoContactIterations.Size());
|
||||
// }
|
||||
// if (outputfiles)
|
||||
// {
|
||||
// ostringstream file_name;
|
||||
// file_name << "output/Testno-"<<testNo<<"-ref-"<<sref+pref << "-step-" << i;
|
||||
// OutputData(file_name, Einitial, Efinal, gndofs,numconstr, optimizer.GetNumIterations(), CGiterations);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Vector X_new(xf.GetData(),fes->GetTrueVSize());
|
||||
// // xnew.SetFromTrueDofs(X_new);
|
||||
// // x_gf = xnew;
|
||||
// x_gf.SetFromTrueDofs(xf);
|
||||
// // mfem::out << "x_gf norm = " << x_gf.Norml2() << endl;
|
||||
// // cin.get();
|
||||
// // pmesh->MoveNodes(xnew);
|
||||
// // pmesh_copy.MoveNodes(xnew);
|
||||
// // pmesh_copy.MoveNodes(xnew);
|
||||
// add(ref_coords,x_gf,new_coords);
|
||||
// // mfem::out << " ref_coords norm " << ref_coords.Norml2() << endl;
|
||||
// // mfem::out << " x_gf norm " << x_gf.Norml2() << endl;
|
||||
// // mfem::out << " new_coords norm " << new_coords.Norml2() << endl;
|
||||
// // pmesh_copy.SetNodes(new_coords);
|
||||
// pmesh_copy.SetNodes(new_coords);
|
||||
// xcopy_gf = x_gf;
|
||||
// // pmesh_copy.MoveNodes(x_gf);
|
||||
// // pmesh_copy.SetNodes(x_gf);
|
||||
// if (paraview && ((i+1) % paraview_plot_every == 0 ))
|
||||
// {
|
||||
// paraview_cycle += 1;
|
||||
// paraview_dc->SetCycle(paraview_cycle) ;
|
||||
// paraview_dc->SetTime(paraview_time);
|
||||
// paraview_dc->Save();
|
||||
// }
|
||||
|
||||
// if (visualization)
|
||||
// {
|
||||
// sol_sock << "parallel " << num_procs << " " << myid << "\n"
|
||||
// << "solution\n" << pmesh_copy << x_gf << flush;
|
||||
//
|
||||
// if (i == nsteps - 1 && j == SQPrepeat - 1)
|
||||
// {
|
||||
// pmesh->MoveNodes(x_gf);
|
||||
// char vishost[] = "localhost";
|
||||
// int visport = 19916;
|
||||
// socketstream sol_sock1(vishost, visport);
|
||||
// sol_sock1 << "parallel " << num_procs << " " << myid << "\n";
|
||||
// sol_sock1.precision(8);
|
||||
// sol_sock1 << "solution\n" << *pmesh << x_gf << flush;
|
||||
// }
|
||||
// }
|
||||
// if (i == nsteps - 1 && j == SQPrepeat) break;
|
||||
|
||||
// prob->UpdateStep();
|
||||
// if (testNo == 6 )
|
||||
// {
|
||||
// double area_new = GetBdrArea(3,*pmesh);
|
||||
// if (myid == 0)
|
||||
// {
|
||||
// mfem::out << "New area = " << area_new << endl;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
delete prob;
|
||||
delete pmesh;
|
||||
delete mesh;
|
||||
return 0;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user