Compare commits
422
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b09b5dbab5 | ||
|
|
ece1b1fd3d | ||
|
|
86f72cd22e | ||
|
|
97c4aed444 | ||
|
|
03199fe1fd | ||
|
|
aed9945c40 | ||
|
|
25d65f4275 | ||
|
|
05989d5d29 | ||
|
|
5d762f7cb5 | ||
|
|
bf5c6ebd23 | ||
|
|
8153d11274 | ||
|
|
827ed64113 | ||
|
|
ef9f02ba53 | ||
|
|
e9a0b0620a | ||
|
|
4d9d444248 | ||
|
|
6e2badecca | ||
|
|
99b45fcb02 | ||
|
|
9a327eeca6 | ||
|
|
a1d003aec0 | ||
|
|
fa87595f9a | ||
|
|
c4697ba253 | ||
|
|
5e01a5433d | ||
|
|
4833b17636 | ||
|
|
34378ffc5b | ||
|
|
a6e3e8e695 | ||
|
|
8af34d985e | ||
|
|
0f55696c69 | ||
|
|
f4a6f33284 | ||
|
|
781efd2d50 | ||
|
|
9035279bcb | ||
|
|
262fa6173d | ||
|
|
e4b8584a16 | ||
|
|
7912d6915d | ||
|
|
293d9009ae | ||
|
|
51bde67bb1 | ||
|
|
45e2636921 | ||
|
|
c3eb769a2a | ||
|
|
9286d89b0e | ||
|
|
613a55d318 | ||
|
|
35225e045e | ||
|
|
22c1087503 | ||
|
|
732e3c33f4 | ||
|
|
0586c0feee | ||
|
|
7e1186afd2 | ||
|
|
ffd3088722 | ||
|
|
cd5d2f7c04 | ||
|
|
cbae29ad06 | ||
|
|
4c1d842c72 | ||
|
|
4aa0ed52af | ||
|
|
7e8fc14b25 | ||
|
|
fca4c314d4 | ||
|
|
8712d02570 | ||
|
|
e5fec6279b | ||
|
|
e90e96f9a5 | ||
|
|
459def6d79 | ||
|
|
f252efd40a | ||
|
|
cc00ef7d90 | ||
|
|
9f7cc58596 | ||
|
|
cf86062f95 | ||
|
|
a5d230f199 | ||
|
|
62c535d0ee | ||
|
|
17829d1c38 | ||
|
|
dd198ce3f9 | ||
|
|
b9f36468ba | ||
|
|
d5b127caff | ||
|
|
a210103209 | ||
|
|
76bcd044d0 | ||
|
|
0d1d69c337 | ||
|
|
84ce403ffb | ||
|
|
df09aea4da | ||
|
|
d2840464ba | ||
|
|
41a40ebf57 | ||
|
|
80f0f6cdb9 | ||
|
|
3a65277b24 | ||
|
|
a2132dac0c | ||
|
|
28916b23a4 | ||
|
|
7476c00f2b | ||
|
|
c7772c33dc | ||
|
|
770bcab911 | ||
|
|
ec519e1de4 | ||
|
|
582f6a2f6e | ||
|
|
712a3941cf | ||
|
|
7a0137c496 | ||
|
|
4267b2af05 | ||
|
|
e37daad5eb | ||
|
|
289a241f81 | ||
|
|
d0850268e3 | ||
|
|
133bf60546 | ||
|
|
9f13192930 | ||
|
|
20b4b72071 | ||
|
|
ddf80492c5 | ||
|
|
2636fffda9 | ||
|
|
2489c68047 | ||
|
|
60d70b7d3d | ||
|
|
7f946e0920 | ||
|
|
0456014a32 | ||
|
|
77d98d68c3 | ||
|
|
569bb11b93 | ||
|
|
cdd8128966 | ||
|
|
a4e2605681 | ||
|
|
f35451744f | ||
|
|
b16a179b62 | ||
|
|
12c096a256 | ||
|
|
d64b83e7fb | ||
|
|
77b081a4eb | ||
|
|
8c47291d30 | ||
|
|
0406101e29 | ||
|
|
15600451c0 | ||
|
|
1f9c75585e | ||
|
|
c07bce73af | ||
|
|
acf510594e | ||
|
|
f8d18cd4be | ||
|
|
994d83dd80 | ||
|
|
14db63647d | ||
|
|
f218efae09 | ||
|
|
9bea5c01b7 | ||
|
|
1bc5a0c5e4 | ||
|
|
be0d8751a4 | ||
|
|
4ee1bcd561 | ||
|
|
69a4a38053 | ||
|
|
e195a709ff | ||
|
|
a910f49710 | ||
|
|
6355d3f4c0 | ||
|
|
2392aac78e | ||
|
|
198ccef4c1 | ||
|
|
627ff3ee7e | ||
|
|
f393750bd6 | ||
|
|
9cfae52d1e | ||
|
|
9dbc125598 | ||
|
|
af24eaea27 | ||
|
|
a482722cda | ||
|
|
41d3b5dfb5 | ||
|
|
4d4d8c46a7 | ||
|
|
b946917551 | ||
|
|
e358c400ab | ||
|
|
cd6b864e9c | ||
|
|
792700d7b1 | ||
|
|
8ed6d6d2d2 | ||
|
|
800b17838a | ||
|
|
a17333cb19 | ||
|
|
e0982be906 | ||
|
|
c64f672dbf | ||
|
|
a7236656ad | ||
|
|
b4ccaa3a7b | ||
|
|
3e8379105e | ||
|
|
b8d7d71350 | ||
|
|
9145b88b31 | ||
|
|
271d3a74f5 | ||
|
|
13e1067cd1 | ||
|
|
14b1c27dc5 | ||
|
|
8da512d5cf | ||
|
|
8be0dee008 | ||
|
|
52d467de56 | ||
|
|
8fa1374178 | ||
|
|
a3ce26485f | ||
|
|
8342bc06f0 | ||
|
|
c742675da0 | ||
|
|
1dd2c75a33 | ||
|
|
71ad30fc01 | ||
|
|
75bffa67f5 | ||
|
|
98341269cc | ||
|
|
54dcdc720f | ||
|
|
8adb7461b0 | ||
|
|
89bb3348eb | ||
|
|
69ac6a0d1a | ||
|
|
2b6029a416 | ||
|
|
c54e92aff1 | ||
|
|
d89cceaaca | ||
|
|
59d40f14fc | ||
|
|
fbbc3bbad0 | ||
|
|
62a57c30bd | ||
|
|
8cc311191a | ||
|
|
716e370d35 | ||
|
|
37c0768fe3 | ||
|
|
4eaa2c6d67 | ||
|
|
28bc92c034 | ||
|
|
4e0bb41e58 | ||
|
|
36a4df0494 | ||
|
|
f2dfb6d83a | ||
|
|
f1af6fccd2 | ||
|
|
9290acab48 | ||
|
|
263eabc81a | ||
|
|
63804ab6cb | ||
|
|
98e0f325f9 | ||
|
|
6f3dc3e187 | ||
|
|
365b2a027b | ||
|
|
f037b23fb1 | ||
|
|
2dabf82a0d | ||
|
|
65fe610f57 | ||
|
|
032666afc9 | ||
|
|
51860e9192 | ||
|
|
e81ad14586 | ||
|
|
ef1d5f86bf | ||
|
|
84631a1688 | ||
|
|
4b00ad0b03 | ||
|
|
c29f70e220 | ||
|
|
739dfbace1 | ||
|
|
4cbe4358ef | ||
|
|
d254f771c8 | ||
|
|
f7dc6c7090 | ||
|
|
e1fc8bf3b2 | ||
|
|
8544e4ef9c | ||
|
|
9e744d1f22 | ||
|
|
c772b2eaca | ||
|
|
d910bac841 | ||
|
|
e8147b14cb | ||
|
|
0c6d8b8417 | ||
|
|
5bf66c6704 | ||
|
|
d51c62699c | ||
|
|
d17d8f2a45 | ||
|
|
4483b664c2 | ||
|
|
e7b2a09943 | ||
|
|
801cb497e1 | ||
|
|
d7542b843e | ||
|
|
4a5d81981b | ||
|
|
80c22eaae6 | ||
|
|
901a714fac | ||
|
|
dadbc18916 | ||
|
|
6c5cfbfc65 | ||
|
|
8acdb178c2 | ||
|
|
6baf95a686 | ||
|
|
2bd8bb4c3b | ||
|
|
1c38648d5f | ||
|
|
4ebbbc45ae | ||
|
|
77a3bb103c | ||
|
|
ae3b9e23e7 | ||
|
|
0494eb22e6 | ||
|
|
31a977ac5f | ||
|
|
821c41fba9 | ||
|
|
af5a7844a8 | ||
|
|
9bfa6c051e | ||
|
|
850f0f7e89 | ||
|
|
90ecbf2bfb | ||
|
|
b0a3350622 | ||
|
|
875b5f3f52 | ||
|
|
be1f36a523 | ||
|
|
d4c7dd3490 | ||
|
|
3f45c0a9d7 | ||
|
|
18bee592c4 | ||
|
|
637854fd90 | ||
|
|
bc0ab53d19 | ||
|
|
e55fb21538 | ||
|
|
a966b0502f | ||
|
|
1bac61ad1c | ||
|
|
c7451115d8 | ||
|
|
72ae003a00 | ||
|
|
99db13a3c2 | ||
|
|
4dcb5933a9 | ||
|
|
1f5f30c9c4 | ||
|
|
d453981d3c | ||
|
|
d67098b8f8 | ||
|
|
0e6dbaf050 | ||
|
|
00bf53ed90 | ||
|
|
32afc8565c | ||
|
|
48ace60875 | ||
|
|
b89dc7fe56 | ||
|
|
9b6ee6fcad | ||
|
|
1a1639b87e | ||
|
|
3735aa504b | ||
|
|
367dda6794 | ||
|
|
e4a85f79cd | ||
|
|
678101938b | ||
|
|
9a3aa18c62 | ||
|
|
5a3ba1424a | ||
|
|
3bb8419a96 | ||
|
|
ce29282f63 | ||
|
|
9575299ae3 | ||
|
|
995ceca6c2 | ||
|
|
71da95b411 | ||
|
|
6abd0e6002 | ||
|
|
656e3062b4 | ||
|
|
57cce6a74d | ||
|
|
0fba4035e3 | ||
|
|
0ee0132e7c | ||
|
|
691c328d38 | ||
|
|
f45d15149a | ||
|
|
c32e986926 | ||
|
|
9c9c519175 | ||
|
|
8300809562 | ||
|
|
cce7296ffe | ||
|
|
a445ad00da | ||
|
|
4db7e1a107 | ||
|
|
c51a1c4aa9 | ||
|
|
d489908e50 | ||
|
|
c4eda188d5 | ||
|
|
677eb4c876 | ||
|
|
69a4aa70b9 | ||
|
|
f07c2f460d | ||
|
|
09c557bdd7 | ||
|
|
e487da01c5 | ||
|
|
b6b6843ad2 | ||
|
|
66a1379947 | ||
|
|
546ba6c11e | ||
|
|
67ba63c2f4 | ||
|
|
99c2967920 | ||
|
|
2dc419f1ae | ||
|
|
450d6cea6d | ||
|
|
17a24c71cd | ||
|
|
8a6f50f6cc | ||
|
|
5e856a6464 | ||
|
|
78aa8d60a8 | ||
|
|
f02247439b | ||
|
|
70c6f713d5 | ||
|
|
ca94342c04 | ||
|
|
59a2657f06 | ||
|
|
35a328c342 | ||
|
|
bcba29c6a2 | ||
|
|
2cc23787ab | ||
|
|
711df0e4fd | ||
|
|
75df4ad3e6 | ||
|
|
4048d46443 | ||
|
|
1ddcc6d421 | ||
|
|
e7da202037 | ||
|
|
dc9e6c5ffb | ||
|
|
0e74524f6d | ||
|
|
8fb59b8251 | ||
|
|
2012a9131b | ||
|
|
56d6841372 | ||
|
|
37a140c0e2 | ||
|
|
4f3a64d834 | ||
|
|
b03cf507be | ||
|
|
066dc9b078 | ||
|
|
70854254e7 | ||
|
|
646df28ac8 | ||
|
|
73d4f987e4 | ||
|
|
c59d519c89 | ||
|
|
1ec2cba9e8 | ||
|
|
26cc1f8387 | ||
|
|
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 | ||
|
|
a6d4e17911 | ||
|
|
bde7846b5a | ||
|
|
01283767a6 |
+13
@@ -57,6 +57,8 @@ examples/ex2[0-9]
|
||||
examples/ex2[0-9]p
|
||||
examples/ex3[0-9]
|
||||
examples/ex3[0-9]p
|
||||
examples/ex4[0-9]
|
||||
examples/ex4[0-9]p
|
||||
|
||||
examples/refined.mesh
|
||||
examples/displaced.mesh
|
||||
@@ -270,16 +272,27 @@ miniapps/navier/*_output
|
||||
|
||||
miniapps/nurbs/nurbs_ex1
|
||||
miniapps/nurbs/nurbs_ex1p
|
||||
miniapps/nurbs/nurbs_ex3
|
||||
miniapps/nurbs/nurbs_ex5
|
||||
miniapps/nurbs/nurbs_ex11p
|
||||
miniapps/nurbs/nurbs_ex24
|
||||
miniapps/nurbs/nurbs_solenoidal
|
||||
miniapps/nurbs/nurbs_printfunc
|
||||
miniapps/nurbs/nurbs_patch_ex1
|
||||
miniapps/nurbs/nurbs_curveint
|
||||
miniapps/nurbs/refined.mesh
|
||||
miniapps/nurbs/mesh.*
|
||||
miniapps/nurbs/sol_?.gf
|
||||
miniapps/nurbs/sol.*
|
||||
miniapps/nurbs/mode_*
|
||||
miniapps/nurbs/Example1*
|
||||
miniapps/nurbs/Example3*
|
||||
miniapps/nurbs/Example5*
|
||||
miniapps/nurbs/Solenoidal*
|
||||
miniapps/nurbs/ParaView
|
||||
miniapps/nurbs/sin-fit.mesh
|
||||
miniapps/nurbs/ex5.mesh
|
||||
miniapps/nurbs/exsol.mesh
|
||||
miniapps/nurbs/CurveInt
|
||||
miniapps/nurbs/nurbs_naca_cmesh
|
||||
miniapps/nurbs/naca-cmesh.mesh
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
# at Lawrence Livermore National Laboratory (LLNL). This entire pipeline is
|
||||
# LLNL-specific!
|
||||
|
||||
include:
|
||||
- project: 'lc-templates/id_tokens'
|
||||
file: 'id_tokens.yml'
|
||||
|
||||
# The pipeline is divided into stages. Usually, jobs in a given stage wait for
|
||||
# the preceding stages to complete before to start. However, we sometimes use
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
include:
|
||||
- project: 'lc-templates/id_tokens'
|
||||
file: 'id_tokens.yml'
|
||||
|
||||
# We define the following GitLab pipeline variables:
|
||||
variables:
|
||||
|
||||
|
||||
@@ -35,9 +35,8 @@ variables:
|
||||
- when: on_success
|
||||
|
||||
# Lassen uses a different job scheduler (spectrum lsf) that does not allow
|
||||
# pre-allocation the same way slurm does. We use pdebug queue on lassen
|
||||
# to speed-up the allocation. However this would not be scalable to
|
||||
# multiple builds.
|
||||
# pre-allocation the same way slurm does. We use the pci queue on lassen
|
||||
# to speed-up the allocation.
|
||||
.build_and_test_on_lassen:
|
||||
extends: [.on_lassen]
|
||||
stage: build_and_test
|
||||
@@ -45,5 +44,5 @@ variables:
|
||||
- echo ${MFEM_DATA_DIR}
|
||||
- echo ${SPEC}
|
||||
# Next script uses 'THREADS': leaving it empty --> it uses 'make all -j'
|
||||
- lalloc 1 -W 45 -q pdebug --atsdisable tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
|
||||
- lalloc 1 -W 45 -q pci --atsdisable tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
|
||||
needs: [setup]
|
||||
|
||||
@@ -52,4 +52,4 @@ variables:
|
||||
- echo ${JOBID}
|
||||
- echo ${MFEM_DATA_DIR}
|
||||
- echo ${SPEC}
|
||||
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 45 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
|
||||
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) --reservation=ci -t 45 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
|
||||
|
||||
@@ -14,14 +14,14 @@ stages:
|
||||
- build_and_test
|
||||
- report
|
||||
|
||||
opt_mpi_cuda_xl_16_1_1_12:
|
||||
opt_mpi_cuda_gcc:
|
||||
variables:
|
||||
SPEC: "%xl@16.1.1.12 +mpi +cuda cuda_arch=70"
|
||||
SPEC: "%gcc@8.3.1 +mpi +cuda cuda_arch=70"
|
||||
extends: .build_and_test_on_lassen
|
||||
|
||||
opt_mpi_cuda_hypre_cuda_xl:
|
||||
opt_mpi_cuda_hypre_cuda_gcc:
|
||||
variables:
|
||||
SPEC: "%xl@16.1.1.12 +mpi +cuda cuda_arch=70 ^hypre+cuda~shared cuda_arch=70"
|
||||
SPEC: "%gcc@8.3.1 +mpi +cuda cuda_arch=70 ^hypre+cuda~shared cuda_arch=70"
|
||||
extends: .build_and_test_on_lassen
|
||||
|
||||
# Jobs report
|
||||
|
||||
@@ -32,11 +32,11 @@ mkdir _${BASELINE_TEST} && cd _${BASELINE_TEST}
|
||||
|
||||
# run
|
||||
if [[ "${MACHINE_NAME}" == "quartz" || "${MACHINE_NAME}" == "ruby" ]]; then
|
||||
salloc --nodes=1 -p pdebug ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
salloc --nodes=1 --reservation=ci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
elif [[ ${MACHINE_NAME} == "corona" ]]; then
|
||||
salloc --nodes=1 -t 60 -p pbatch ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
elif [[ ${MACHINE_NAME} == "lassen" ]]; then
|
||||
lalloc 1 -q pdebug ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
lalloc 1 -q pci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
else
|
||||
echo "Unknown machine: MACHINE_NAME=$MACHINE_NAME"
|
||||
exit 1
|
||||
|
||||
@@ -11,6 +11,16 @@
|
||||
Version 4.7.1 (development)
|
||||
===========================
|
||||
|
||||
- Added NURBS-based H(div) and H(curl) elements in 2D and 3D. Only on single
|
||||
patch meshes. Only implemented for serial computations.
|
||||
|
||||
- Added miniapps to demonstrate the H(div) and H(curl) NURBS elements.
|
||||
|
||||
- Added an MFEM example for the eikonal equation. This new solver is based on
|
||||
the proximal Galerkin method introduced by Keith and Surowiec.
|
||||
|
||||
- API change: in class GridFunction, 'fec' was renamed to 'fec_owned'.
|
||||
|
||||
|
||||
Version 4.7, released on May 7, 2024
|
||||
====================================
|
||||
|
||||
+83
-13
@@ -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
|
||||
|
||||
@@ -980,6 +980,7 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
|
||||
@MFEM_SOURCE_DIR@/miniapps/mtop \
|
||||
@MFEM_SOURCE_DIR@/miniapps/multidomain \
|
||||
@MFEM_SOURCE_DIR@/miniapps/navier \
|
||||
@MFEM_SOURCE_DIR@/miniapps/stabilized \
|
||||
@MFEM_SOURCE_DIR@/miniapps/nurbs \
|
||||
@MFEM_SOURCE_DIR@/miniapps/parelag \
|
||||
@MFEM_SOURCE_DIR@/miniapps/performance \
|
||||
@@ -1049,7 +1050,8 @@ RECURSIVE = NO
|
||||
EXCLUDE = @MFEM_SOURCE_DIR@/config/_config.hpp \
|
||||
@MFEM_SOURCE_DIR@/config/get_hypre_version.cpp \
|
||||
@MFEM_SOURCE_DIR@/general/tinyxml2.h \
|
||||
@MFEM_SOURCE_DIR@/general/tinyxml2.cpp
|
||||
@MFEM_SOURCE_DIR@/general/tinyxml2.cpp \
|
||||
@MFEM_SOURCE_DIR@/linalg/lapack.hpp
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||
|
||||
@@ -114,7 +114,9 @@ namespace mfem {
|
||||
* - <a class="el" href="ex37p_8cpp_source.html">Example 37p</a>: parallel topology optimization
|
||||
* - <a class="el" href="ex38_8cpp_source.html">Example 38</a>: cut-surface and cut-volume integration
|
||||
* - <a class="el" href="ex39_8cpp_source.html">Example 39</a>: named mesh attributes
|
||||
* - <a class="el" href="ex39p_8cpp_source.html">Example 39</a>: parallel named mesh attributes
|
||||
* - <a class="el" href="ex39p_8cpp_source.html">Example 39p</a>: parallel named mesh attributes
|
||||
* - <a class="el" href="ex40_8cpp_source.html">Example 40</a>: eikonal equation
|
||||
* - <a class="el" href="ex40p_8cpp_source.html">Example 40p</a>: parallel eikonal equation
|
||||
*
|
||||
* <H4>AmgX Examples</H4>
|
||||
* - Variants of Examples
|
||||
@@ -180,6 +182,21 @@ namespace mfem {
|
||||
* <a class="el" href="examples_2superlu_2ex1p_8cpp_source.html">1p</a>,
|
||||
* demonstrating the use of MFEM's \link superlu.hpp SuperLU integration\endlink.
|
||||
*
|
||||
* <H4>NURBS Examples</H4>
|
||||
* - Variants of Examples
|
||||
* <a class="el" href="nurbs__ex1_8cpp_source.html">1</a>,
|
||||
* <a class="el" href="nurbs__ex1p_8cpp_source.html">1p</a>,
|
||||
* <a class="el" href="nurbs__ex3_8cpp_source.html">3</a>,
|
||||
* <a class="el" href="nurbs__ex5_8cpp_source.html">5</a>,
|
||||
* <a class="el" href="nurbs__ex11p_8cpp_source.html">11p</a>, and
|
||||
* <a class="el" href="nurbs__ex24_8cpp_source.html">24</a>,
|
||||
* demonstrating howto perform NURBS-based Isogeometric Analysis.
|
||||
* - Variant of Example <a class="el" href="nurbs__patch__ex1_8cpp_source.html">1</a>: demonstrates the use of patch integration
|
||||
* - <a class="el" href="nurbs__solenoidal_8cpp_source.html">NURBS Divergence-free</a>: solve a solenoidal vector projection with NURBS-based H(div) elements
|
||||
* - <a class="el" href="nurbs__curveint_8cpp_source.html">NURBS Interpolation</a>: NURBS interpolation of given geometry
|
||||
* - <a class="el" href="nurbs__naca__cmesh_8cpp_source.html">NURBS NACA Mesher</a>: generate NURBS based mesh around a NACA foil
|
||||
* - <a class="el" href="nurbs__printfunc_8cpp_source.html">NURBS Printer</a>: print the NURBS-basis
|
||||
*
|
||||
* <H3>Miniapps</H3>
|
||||
* - <a class="el" href="volta_8cpp_source.html">Volta</a>: simple electrostatics simulation code
|
||||
* - <a class="el" href="tesla_8cpp_source.html">Tesla</a>: simple magnetostatics simulation code
|
||||
|
||||
+10
-3
@@ -45,6 +45,7 @@ list(APPEND ALL_EXE_SRCS
|
||||
ex37.cpp
|
||||
ex38.cpp
|
||||
ex39.cpp
|
||||
ex40.cpp
|
||||
)
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
@@ -87,6 +88,7 @@ if (MFEM_USE_MPI)
|
||||
ex36p.cpp
|
||||
ex37p.cpp
|
||||
ex39p.cpp
|
||||
ex40p.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -146,10 +148,10 @@ if (MFEM_ENABLE_TESTING)
|
||||
# Add CUDA/HIP tests.
|
||||
set(DEVICE_EXAMPLES
|
||||
# serial examples with device support:
|
||||
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
|
||||
ex1 ex3 ex4 ex5 ex6 ex9 ex14 ex22 ex24 ex25 ex26 ex34
|
||||
# parallel examples with device support:
|
||||
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p
|
||||
ex34p ex35p)
|
||||
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex14p ex22p ex24p ex25p
|
||||
ex26p ex34p ex35p)
|
||||
set(MFEM_TEST_DEVICE)
|
||||
if (MFEM_USE_CUDA)
|
||||
set(MFEM_TEST_DEVICE "cuda")
|
||||
@@ -159,6 +161,11 @@ if (MFEM_ENABLE_TESTING)
|
||||
if (MFEM_TEST_DEVICE)
|
||||
foreach(TEST_NAME ${DEVICE_EXAMPLES})
|
||||
set(THIS_TEST_OPTIONS "-no-vis" "-d" "${MFEM_TEST_DEVICE}")
|
||||
if (${TEST_NAME} MATCHES "ex14p")
|
||||
list(APPEND THIS_TEST_OPTIONS "-rs" "2" "-rp" "0" "-pa")
|
||||
elseif (${TEST_NAME} MATCHES "ex14")
|
||||
list(APPEND THIS_TEST_OPTIONS "-r" "2" "-pa")
|
||||
endif()
|
||||
if (NOT (${TEST_NAME} MATCHES ".*p$"))
|
||||
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_ser
|
||||
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
|
||||
|
||||
+16
-20
@@ -44,7 +44,7 @@ protected:
|
||||
BilinearForm *M;
|
||||
BilinearForm *K;
|
||||
|
||||
SparseMatrix Mmat, Kmat, Kmat0;
|
||||
SparseMatrix Mmat, Kmat;
|
||||
SparseMatrix *T; // T = M + dt K
|
||||
real_t current_dt;
|
||||
|
||||
@@ -83,25 +83,24 @@ WaveOperator::WaveOperator(FiniteElementSpace &f,
|
||||
: SecondOrderTimeDependentOperator(f.GetTrueVSize(), (real_t) 0.0),
|
||||
fespace(f), M(NULL), K(NULL), T(NULL), current_dt(0.0), z(height)
|
||||
{
|
||||
const real_t rel_tol = 1e-8;
|
||||
|
||||
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
|
||||
// Assemble Laplace matrix
|
||||
c2 = new ConstantCoefficient(speed*speed);
|
||||
|
||||
K = new BilinearForm(&fespace);
|
||||
K->AddDomainIntegrator(new DiffusionIntegrator(*c2));
|
||||
K->Assemble();
|
||||
|
||||
Array<int> dummy;
|
||||
K->FormSystemMatrix(dummy, Kmat0);
|
||||
K->FormSystemMatrix(ess_tdof_list, Kmat);
|
||||
|
||||
// Assemble Mass matrix
|
||||
M = new BilinearForm(&fespace);
|
||||
M->AddDomainIntegrator(new MassIntegrator());
|
||||
M->Assemble();
|
||||
|
||||
// Apply Bcs
|
||||
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
K->FormSystemMatrix(ess_tdof_list, Kmat);
|
||||
M->FormSystemMatrix(ess_tdof_list, Mmat);
|
||||
|
||||
// Configure preconditioner
|
||||
const real_t rel_tol = 1e-8;
|
||||
M_solver.iterative_mode = false;
|
||||
M_solver.SetRelTol(rel_tol);
|
||||
M_solver.SetAbsTol(0.0);
|
||||
@@ -110,14 +109,13 @@ WaveOperator::WaveOperator(FiniteElementSpace &f,
|
||||
M_solver.SetPreconditioner(M_prec);
|
||||
M_solver.SetOperator(Mmat);
|
||||
|
||||
// Configure solver
|
||||
T_solver.iterative_mode = false;
|
||||
T_solver.SetRelTol(rel_tol);
|
||||
T_solver.SetAbsTol(0.0);
|
||||
T_solver.SetMaxIter(100);
|
||||
T_solver.SetPrintLevel(0);
|
||||
T_solver.SetPreconditioner(T_prec);
|
||||
|
||||
T = NULL;
|
||||
}
|
||||
|
||||
void WaveOperator::Mult(const Vector &u, const Vector &du_dt,
|
||||
@@ -126,9 +124,11 @@ void WaveOperator::Mult(const Vector &u, const Vector &du_dt,
|
||||
// Compute:
|
||||
// d2udt2 = M^{-1}*-K(u)
|
||||
// for d2udt2
|
||||
Kmat.Mult(u, z);
|
||||
K->FullMult(u, z);
|
||||
z.Neg(); // z = -z
|
||||
z.SetSubVector(ess_tdof_list, 0.0);
|
||||
M_solver.Mult(z, d2udt2);
|
||||
d2udt2.SetSubVector(ess_tdof_list, 0.0);
|
||||
}
|
||||
|
||||
void WaveOperator::ImplicitSolve(const real_t fac0, const real_t fac1,
|
||||
@@ -142,14 +142,11 @@ void WaveOperator::ImplicitSolve(const real_t fac0, const real_t fac1,
|
||||
T = Add(1.0, Mmat, fac0, Kmat);
|
||||
T_solver.SetOperator(*T);
|
||||
}
|
||||
Kmat0.Mult(u, z);
|
||||
K->FullMult(u, z);
|
||||
z.Neg();
|
||||
|
||||
for (int i = 0; i < ess_tdof_list.Size(); i++)
|
||||
{
|
||||
z[ess_tdof_list[i]] = 0.0;
|
||||
}
|
||||
z.SetSubVector(ess_tdof_list, 0.0);
|
||||
T_solver.Mult(z, d2udt2);
|
||||
d2udt2.SetSubVector(ess_tdof_list, 0.0);
|
||||
}
|
||||
|
||||
void WaveOperator::SetParameters(const Vector &u)
|
||||
@@ -314,7 +311,6 @@ int main(int argc, char *argv[])
|
||||
ess_bdr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
WaveOperator oper(fespace, ess_bdr, speed);
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
// MFEM Example 40
|
||||
//
|
||||
// Compile with: make ex40
|
||||
//
|
||||
// Sample runs: ex40 -step 10 -gr 2.0
|
||||
// ex40 -step 10 -gr 2.0 -o 3 -r 1
|
||||
// ex40 -step 10 -gr 2.0 -r 4 -m ../data/l-shape.mesh
|
||||
// ex40 -step 10 -gr 2.0 -r 2 -m ../data/fichera.mesh
|
||||
//
|
||||
// Description: This example code demonstrates how to use MFEM to solve the
|
||||
// eikonal equation,
|
||||
//
|
||||
// |∇𝑢| = 1 in Ω, 𝑢 = g on ∂Ω.
|
||||
//
|
||||
// The solution of this problem coincides with the unique optimum of
|
||||
// the nonlinear program
|
||||
//
|
||||
// maximize ∫_Ω 𝑢 d𝑥 subject to |∇𝑢| ≤ 1, 𝑢 = g on Ω, (⋆)
|
||||
//
|
||||
// which is the foundation for method implemented below.
|
||||
//
|
||||
// Following the proximal Galerkin methodology [1] (see also Example
|
||||
// 36), we construct a Legendre function for the unit ball
|
||||
// 𝐵₁ := {𝑥 ∈ Rⁿ | |𝑥| < 1}. Our choice is the Hellinger entropy,
|
||||
//
|
||||
// h(𝑥) = −( 1 − |𝑥|² )^{1/2},
|
||||
//
|
||||
// although other choices are possible, each leading to a slightly
|
||||
// different algorithm. We then adaptively regularize the optimization
|
||||
// problem (⋆) with the Bregman divergence of the Hellinger entropy,
|
||||
//
|
||||
// maximize ∫_Ω 𝑢 d𝑥 - αₖ⁻¹ Dₕ(∇𝑢,∇𝑢ₖ₋₁) subject to 𝑢 = g on Ω.
|
||||
//
|
||||
// This results in a sequence of functions ( 𝜓ₖ , 𝑢ₖ ),
|
||||
//
|
||||
// 𝑢ₖ → 𝑢, 𝜓ₖ/|𝜓ₖ| → ∇𝑢 as k → \infty,
|
||||
//
|
||||
// defined by the nonlinear saddle-point problems
|
||||
//
|
||||
// Find 𝜓ₖ ∈ H(div,Ω) and 𝑢ₖ ∈ L²(Ω) such that
|
||||
// ( Zₖ(𝜓ₖ) , τ ) + ( 𝑢ₖ , ∇⋅τ ) = ⟨ g , τ⋅n ⟩ ∀ τ ∈ H(div,Ω)
|
||||
// ( ∇⋅𝜓ₖ , v ) = ( ∇⋅𝜓ₖ₋₁ - 1 , v ) ∀ v ∈ L²(Ω)
|
||||
//
|
||||
// where Zₖ(𝜓) := ∇h⁻¹(αₖ 𝜓) = 𝜓 / ( αₖ⁻² + |𝜓|² )^{1/2} and step size
|
||||
// αₖ > 0. These saddle-point problems are solved using a damped Newton's
|
||||
// method. This example assumes that g = 0 and allows the step size to
|
||||
// grow geometrically, αₖ = α₀rᵏ, where r ≥ 1 is the growth rate.
|
||||
//
|
||||
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
|
||||
// preserving finite element method for pointwise bound constraints.
|
||||
// arXiv:2307.12444 [math.NA]
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
class ZCoefficient : public VectorCoefficient
|
||||
{
|
||||
protected:
|
||||
GridFunction *psi;
|
||||
real_t alpha;
|
||||
|
||||
public:
|
||||
ZCoefficient(int vdim, GridFunction &psi_, real_t alpha_ = 1.0)
|
||||
: VectorCoefficient(vdim), psi(&psi_), alpha(alpha_) { }
|
||||
|
||||
virtual void Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
void SetAlpha(real_t alpha_) { alpha = alpha_; }
|
||||
};
|
||||
|
||||
class DZCoefficient : public MatrixCoefficient
|
||||
{
|
||||
protected:
|
||||
GridFunction *psi;
|
||||
real_t alpha;
|
||||
|
||||
public:
|
||||
DZCoefficient(int height, GridFunction &psi_, real_t alpha_ = 1.0)
|
||||
: MatrixCoefficient(height), psi(&psi_), alpha(alpha_) { }
|
||||
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
void SetAlpha(real_t alpha_) { alpha = alpha_; }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
int order = 1;
|
||||
int max_it = 5;
|
||||
int ref_levels = 3;
|
||||
real_t alpha = 1.0;
|
||||
real_t growth_rate = 1.0;
|
||||
real_t newton_scaling = 0.9;
|
||||
real_t tichonov = 1e-1;
|
||||
real_t tol = 1e-4;
|
||||
bool visualization = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&ref_levels, "-r", "--refs",
|
||||
"Number of h-refinements.");
|
||||
args.AddOption(&max_it, "-mi", "--max-it",
|
||||
"Maximum number of iterations");
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"Stopping criteria based on the difference between"
|
||||
"successive solution updates");
|
||||
args.AddOption(&alpha, "-step", "--step",
|
||||
"Initial size alpha");
|
||||
args.AddOption(&growth_rate, "-gr", "--growth-rate",
|
||||
"Growth rate of the step size alpha");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
// 2. Read the mesh from the mesh file.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
int sdim = mesh.SpaceDimension();
|
||||
|
||||
MFEM_ASSERT(mesh.bdr_attributes.Size(),
|
||||
"This example does not currently support meshes"
|
||||
" without boundary attributes."
|
||||
)
|
||||
|
||||
// 3. Postprocess the mesh.
|
||||
// 3A. Refine the mesh to increase the resolution.
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
|
||||
// 3B. Interpolate the geometry after refinement to control geometry error.
|
||||
// NOTE: Minimum second-order interpolation is used to improve the accuracy.
|
||||
int curvature_order = max(order,2);
|
||||
mesh.SetCurvature(curvature_order);
|
||||
|
||||
// 4. Define the necessary finite element spaces on the mesh.
|
||||
RT_FECollection RTfec(order, dim);
|
||||
FiniteElementSpace RTfes(&mesh, &RTfec);
|
||||
|
||||
L2_FECollection L2fec(order, dim);
|
||||
FiniteElementSpace L2fes(&mesh, &L2fec);
|
||||
|
||||
cout << "Number of H(div) dofs: "
|
||||
<< RTfes.GetTrueVSize() << endl;
|
||||
cout << "Number of L² dofs: "
|
||||
<< L2fes.GetTrueVSize() << endl;
|
||||
|
||||
// 5. Define the offsets for the block matrices
|
||||
Array<int> offsets(3);
|
||||
offsets[0] = 0;
|
||||
offsets[1] = RTfes.GetVSize();
|
||||
offsets[2] = L2fes.GetVSize();
|
||||
offsets.PartialSum();
|
||||
|
||||
BlockVector x(offsets), rhs(offsets);
|
||||
x = 0.0; rhs = 0.0;
|
||||
|
||||
// 6. Define the solution vectors as a finite element grid functions
|
||||
// corresponding to the fespaces.
|
||||
GridFunction u_gf, delta_psi_gf;
|
||||
delta_psi_gf.MakeRef(&RTfes,x,offsets[0]);
|
||||
u_gf.MakeRef(&L2fes,x,offsets[1]);
|
||||
|
||||
GridFunction psi_old_gf(&RTfes);
|
||||
GridFunction psi_gf(&RTfes);
|
||||
GridFunction u_old_gf(&L2fes);
|
||||
|
||||
// 7. Define initial guesses for the solution variables.
|
||||
delta_psi_gf = 0.0;
|
||||
psi_gf = 0.0;
|
||||
u_gf = 0.0;
|
||||
psi_old_gf = psi_gf;
|
||||
u_old_gf = u_gf;
|
||||
|
||||
// 8. Prepare for glvis output.
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock;
|
||||
if (visualization)
|
||||
{
|
||||
sol_sock.open(vishost,visport);
|
||||
sol_sock.precision(8);
|
||||
}
|
||||
|
||||
// 9. Coefficients to be used later.
|
||||
ConstantCoefficient neg_one(-1.0);
|
||||
ConstantCoefficient zero(0.0);
|
||||
ConstantCoefficient tichonov_cf(tichonov);
|
||||
ConstantCoefficient neg_tichonov_cf(-1.0*tichonov);
|
||||
ZCoefficient Z(sdim, psi_gf, alpha);
|
||||
DZCoefficient DZ(sdim, psi_gf, alpha);
|
||||
ScalarVectorProductCoefficient neg_Z(-1.0, Z);
|
||||
DivergenceGridFunctionCoefficient div_psi_cf(&psi_gf);
|
||||
DivergenceGridFunctionCoefficient div_psi_old_cf(&psi_old_gf);
|
||||
SumCoefficient psi_old_minus_psi(div_psi_old_cf, div_psi_cf, 1.0, -1.0);
|
||||
|
||||
// 10. Assemble constant matrices/vectors to avoid reassembly in the loop.
|
||||
LinearForm b0, b1;
|
||||
b0.MakeRef(&RTfes,rhs.GetBlock(0),0);
|
||||
b1.MakeRef(&L2fes,rhs.GetBlock(1),0);
|
||||
|
||||
b0.AddDomainIntegrator(new VectorFEDomainLFIntegrator(neg_Z));
|
||||
b1.AddDomainIntegrator(new DomainLFIntegrator(neg_one));
|
||||
b1.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
|
||||
|
||||
BilinearForm a00(&RTfes);
|
||||
a00.AddDomainIntegrator(new VectorFEMassIntegrator(DZ));
|
||||
a00.AddDomainIntegrator(new VectorFEMassIntegrator(tichonov_cf));
|
||||
|
||||
MixedBilinearForm a10(&RTfes,&L2fes);
|
||||
a10.AddDomainIntegrator(new VectorFEDivergenceIntegrator());
|
||||
a10.Assemble();
|
||||
a10.Finalize();
|
||||
SparseMatrix &A10 = a10.SpMat();
|
||||
SparseMatrix *A01 = Transpose(A10);
|
||||
|
||||
BilinearForm a11(&L2fes);
|
||||
a11.AddDomainIntegrator(new MassIntegrator(neg_tichonov_cf));
|
||||
a11.Assemble();
|
||||
a11.Finalize();
|
||||
SparseMatrix &A11 = a11.SpMat();
|
||||
|
||||
// 11. Iterate.
|
||||
int k;
|
||||
int total_iterations = 0;
|
||||
real_t increment_u = 0.1;
|
||||
GridFunction u_tmp(&L2fes);
|
||||
for (k = 0; k < max_it; k++)
|
||||
{
|
||||
u_tmp = u_old_gf;
|
||||
Z.SetAlpha(alpha);
|
||||
DZ.SetAlpha(alpha);
|
||||
|
||||
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
|
||||
|
||||
int j;
|
||||
for ( j = 0; j < 5; j++)
|
||||
{
|
||||
total_iterations++;
|
||||
|
||||
b0.Assemble();
|
||||
b1.Assemble();
|
||||
|
||||
a00.Assemble(false);
|
||||
a00.Finalize(false);
|
||||
SparseMatrix &A00 = a00.SpMat();
|
||||
|
||||
// Construct Schur-complement preconditioner
|
||||
Vector A00_diag(a00.Height());
|
||||
A00.GetDiag(A00_diag);
|
||||
A00_diag.Reciprocal();
|
||||
SparseMatrix *S = Mult_AtDA(*A01, A00_diag);
|
||||
|
||||
BlockDiagonalPreconditioner prec(offsets);
|
||||
prec.SetDiagonalBlock(0,new DSmoother(A00));
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
prec.SetDiagonalBlock(1,new GSSmoother(*S));
|
||||
#else
|
||||
prec.SetDiagonalBlock(1,new UMFPackSolver(*S));
|
||||
#endif
|
||||
prec.owns_blocks = 1;
|
||||
|
||||
BlockOperator A(offsets);
|
||||
A.SetBlock(0,0,&A00);
|
||||
A.SetBlock(1,0,&A10);
|
||||
A.SetBlock(0,1,A01);
|
||||
A.SetBlock(1,1,&A11);
|
||||
|
||||
GMRES(A,prec,rhs,x,0,2000,500,1e-12,0.0);
|
||||
delete S;
|
||||
|
||||
u_tmp -= u_gf;
|
||||
real_t Newton_update_size = u_tmp.ComputeL2Error(zero);
|
||||
u_tmp = u_gf;
|
||||
|
||||
// Damped Newton update
|
||||
psi_gf.Add(newton_scaling, delta_psi_gf);
|
||||
a00.Update();
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
sol_sock << "solution\n" << mesh << u_gf << "window_title 'Discrete solution'"
|
||||
<< flush;
|
||||
}
|
||||
|
||||
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
|
||||
|
||||
if (Newton_update_size < increment_u)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u_tmp = u_gf;
|
||||
u_tmp -= u_old_gf;
|
||||
increment_u = u_tmp.ComputeL2Error(zero);
|
||||
|
||||
mfem::out << "Number of Newton iterations = " << j+1 << endl;
|
||||
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
|
||||
|
||||
u_old_gf = u_gf;
|
||||
psi_old_gf = psi_gf;
|
||||
|
||||
if (increment_u < tol || k == max_it-1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
alpha *= max(growth_rate, 1_r);
|
||||
|
||||
}
|
||||
|
||||
mfem::out << "\n Outer iterations: " << k+1
|
||||
<< "\n Total iterations: " << total_iterations
|
||||
<< "\n Total dofs: " << RTfes.GetTrueVSize() + L2fes.GetTrueVSize()
|
||||
<< endl;
|
||||
|
||||
delete A01;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ZCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
MFEM_ASSERT(psi != NULL, "grid function is not set");
|
||||
MFEM_ASSERT(alpha > 0, "alpha is not positive");
|
||||
|
||||
Vector psi_vals(vdim);
|
||||
psi->GetVectorValue(T, ip, psi_vals);
|
||||
real_t norm = psi_vals.Norml2();
|
||||
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
|
||||
|
||||
V = psi_vals;
|
||||
V *= phi;
|
||||
}
|
||||
|
||||
void DZCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
MFEM_ASSERT(psi != NULL, "grid function is not set");
|
||||
MFEM_ASSERT(alpha > 0, "alpha is not positive");
|
||||
|
||||
Vector psi_vals(height);
|
||||
psi->GetVectorValue(T, ip, psi_vals);
|
||||
real_t norm = psi_vals.Norml2();
|
||||
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
|
||||
|
||||
K = 0.0;
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
K(i,i) = phi;
|
||||
for (int j = 0; j < height; j++)
|
||||
{
|
||||
K(i,j) -= psi_vals(i) * psi_vals(j) * pow(phi, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
// MFEM Example 40 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex40p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex40p -step 10 -gr 2.0
|
||||
// mpirun -np 4 ex40p -step 10 -gr 2.0 -o 3 -r 1
|
||||
// mpirun -np 4 ex40p -step 10 -gr 2.0 -r 4 -m ../data/l-shape.mesh
|
||||
// mpirun -np 4 ex40p -step 10 -gr 2.0 -r 2 -m ../data/fichera.mesh
|
||||
//
|
||||
// Description: This example code demonstrates how to use MFEM to solve the
|
||||
// eikonal equation,
|
||||
//
|
||||
// |∇𝑢| = 1 in Ω, 𝑢 = g on ∂Ω.
|
||||
//
|
||||
// The solution of this problem coincides with the unique optimum of
|
||||
// the nonlinear program
|
||||
//
|
||||
// maximize ∫_Ω 𝑢 d𝑥 subject to |∇𝑢| ≤ 1, 𝑢 = g on Ω, (⋆)
|
||||
//
|
||||
// which is the foundation for method implemented below.
|
||||
//
|
||||
// Following the proximal Galerkin methodology [1] (see also Example
|
||||
// 36), we construct a Legendre function for the unit ball
|
||||
// 𝐵₁ := {𝑥 ∈ Rⁿ | |𝑥| < 1}. Our choice is the Hellinger entropy,
|
||||
//
|
||||
// h(𝑥) = −( 1 − |𝑥|² )^{1/2},
|
||||
//
|
||||
// although other choices are possible, each leading to a slightly
|
||||
// different algorithm. We then adaptively regularize the optimization
|
||||
// problem (⋆) with the Bregman divergence of the Hellinger entropy,
|
||||
//
|
||||
// maximize ∫_Ω 𝑢 d𝑥 - αₖ⁻¹ Dₕ(∇𝑢,∇𝑢ₖ₋₁) subject to 𝑢 = g on Ω.
|
||||
//
|
||||
// This results in a sequence of functions ( 𝜓ₖ , 𝑢ₖ ),
|
||||
//
|
||||
// 𝑢ₖ → 𝑢, 𝜓ₖ/|𝜓ₖ| → ∇𝑢 as k → \infty,
|
||||
//
|
||||
// defined by the nonlinear saddle-point problems
|
||||
//
|
||||
// Find 𝜓ₖ ∈ H(div,Ω) and 𝑢ₖ ∈ L²(Ω) such that
|
||||
// ( Zₖ(𝜓ₖ) , τ ) + ( 𝑢ₖ , ∇⋅τ ) = ⟨ g , τ⋅n ⟩ ∀ τ ∈ H(div,Ω)
|
||||
// ( ∇⋅𝜓ₖ , v ) = ( ∇⋅𝜓ₖ₋₁ - 1 , v ) ∀ v ∈ L²(Ω)
|
||||
//
|
||||
// where Zₖ(𝜓) := ∇h⁻¹(αₖ 𝜓) = 𝜓 / ( αₖ⁻² + |𝜓|² )^{1/2} and step size
|
||||
// αₖ > 0. These saddle-point problems are solved using a damped Newton's
|
||||
// method. This example assumes that g = 0 and allows the step size to
|
||||
// grow geometrically, αₖ = α₀rᵏ, where r ≥ 1 is the growth rate.
|
||||
//
|
||||
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
|
||||
// preserving finite element method for pointwise bound constraints.
|
||||
// arXiv:2307.12444 [math.NA]
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
class ZCoefficient : public VectorCoefficient
|
||||
{
|
||||
protected:
|
||||
ParGridFunction *psi;
|
||||
real_t alpha;
|
||||
|
||||
public:
|
||||
ZCoefficient(int vdim, ParGridFunction &psi_, real_t alpha_ = 1.0)
|
||||
: VectorCoefficient(vdim), psi(&psi_), alpha(alpha_) { }
|
||||
|
||||
virtual void Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
void SetAlpha(real_t alpha_) { alpha = alpha_; }
|
||||
};
|
||||
|
||||
class DZCoefficient : public MatrixCoefficient
|
||||
{
|
||||
protected:
|
||||
ParGridFunction *psi;
|
||||
real_t alpha;
|
||||
|
||||
public:
|
||||
DZCoefficient(int height, ParGridFunction &psi_, real_t alpha_ = 1.0)
|
||||
: MatrixCoefficient(height), psi(&psi_), alpha(alpha_) { }
|
||||
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
void SetAlpha(real_t alpha_) { alpha = alpha_; }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 0. Initialize MPI and HYPRE.
|
||||
Mpi::Init();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
int order = 1;
|
||||
int max_it = 5;
|
||||
int ref_levels = 3;
|
||||
real_t alpha = 1.0;
|
||||
real_t growth_rate = 1.0;
|
||||
real_t newton_scaling = 0.9;
|
||||
real_t tichonov = 1e-1;
|
||||
real_t tol = 1e-4;
|
||||
bool visualization = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&ref_levels, "-r", "--refs",
|
||||
"Number of h-refinements.");
|
||||
args.AddOption(&max_it, "-mi", "--max-it",
|
||||
"Maximum number of iterations");
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"Stopping criteria based on the difference between"
|
||||
"successive solution updates");
|
||||
args.AddOption(&alpha, "-step", "--step",
|
||||
"Initial size alpha");
|
||||
args.AddOption(&growth_rate, "-gr", "--growth-rate",
|
||||
"Growth rate of the step size alpha");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
// 2. Read the mesh from the mesh file.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
int sdim = mesh.SpaceDimension();
|
||||
|
||||
MFEM_ASSERT(mesh.bdr_attributes.Size(),
|
||||
"This example does not currently support meshes"
|
||||
" without boundary attributes."
|
||||
)
|
||||
|
||||
// 3. Postprocess the mesh.
|
||||
// 3A. Refine the mesh to increase the resolution.
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
|
||||
// 3B. Interpolate the geometry after refinement to control geometry error.
|
||||
// NOTE: Minimum second-order interpolation is used to improve the accuracy.
|
||||
int curvature_order = max(order,2);
|
||||
mesh.SetCurvature(curvature_order);
|
||||
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
|
||||
// 4. Define the necessary finite element spaces on the mesh.
|
||||
RT_FECollection RTfec(order, dim);
|
||||
ParFiniteElementSpace RTfes(&pmesh, &RTfec);
|
||||
|
||||
L2_FECollection L2fec(order, dim);
|
||||
ParFiniteElementSpace L2fes(&pmesh, &L2fec);
|
||||
|
||||
int num_dofs_RT = RTfes.GlobalTrueVSize();
|
||||
int num_dofs_L2 = L2fes.GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of H(div) dofs: "
|
||||
<< num_dofs_RT << endl;
|
||||
cout << "Number of L² dofs: "
|
||||
<< num_dofs_L2 << endl;
|
||||
}
|
||||
|
||||
// 5. Define the offsets for the block matrices
|
||||
Array<int> offsets(3);
|
||||
offsets[0] = 0;
|
||||
offsets[1] = RTfes.GetVSize();
|
||||
offsets[2] = L2fes.GetVSize();
|
||||
offsets.PartialSum();
|
||||
|
||||
Array<int> toffsets(3);
|
||||
toffsets[0] = 0;
|
||||
toffsets[1] = RTfes.GetTrueVSize();
|
||||
toffsets[2] = L2fes.GetTrueVSize();
|
||||
toffsets.PartialSum();
|
||||
|
||||
BlockVector x(offsets), rhs(offsets);
|
||||
x = 0.0; rhs = 0.0;
|
||||
|
||||
BlockVector tx(toffsets), trhs(toffsets);
|
||||
tx = 0.0; trhs = 0.0;
|
||||
|
||||
// 6. Define the solution vectors as a finite element grid functions
|
||||
// corresponding to the fespaces.
|
||||
ParGridFunction u_gf, delta_psi_gf;
|
||||
delta_psi_gf.MakeRef(&RTfes,x,offsets[0]);
|
||||
u_gf.MakeRef(&L2fes,x,offsets[1]);
|
||||
|
||||
ParGridFunction psi_old_gf(&RTfes);
|
||||
ParGridFunction psi_gf(&RTfes);
|
||||
ParGridFunction u_old_gf(&L2fes);
|
||||
|
||||
// 7. Define initial guesses for the solution variables.
|
||||
delta_psi_gf = 0.0;
|
||||
psi_gf = 0.0;
|
||||
u_gf = 0.0;
|
||||
psi_old_gf = psi_gf;
|
||||
u_old_gf = u_gf;
|
||||
|
||||
// 8. Prepare for glvis output.
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock;
|
||||
if (visualization)
|
||||
{
|
||||
sol_sock.open(vishost,visport);
|
||||
sol_sock.precision(8);
|
||||
}
|
||||
|
||||
// 9. Coefficients to be used later.
|
||||
ConstantCoefficient neg_one(-1.0);
|
||||
ConstantCoefficient zero(0.0);
|
||||
ConstantCoefficient tichonov_cf(tichonov);
|
||||
ConstantCoefficient neg_tichonov_cf(-1.0*tichonov);
|
||||
ZCoefficient Z(sdim, psi_gf, alpha);
|
||||
DZCoefficient DZ(sdim, psi_gf, alpha);
|
||||
ScalarVectorProductCoefficient neg_Z(-1.0, Z);
|
||||
DivergenceGridFunctionCoefficient div_psi_cf(&psi_gf);
|
||||
DivergenceGridFunctionCoefficient div_psi_old_cf(&psi_old_gf);
|
||||
SumCoefficient psi_old_minus_psi(div_psi_old_cf, div_psi_cf, 1.0, -1.0);
|
||||
|
||||
// 10. Assemble constant matrices/vectors to avoid reassembly in the loop.
|
||||
ParLinearForm b0, b1;
|
||||
b0.MakeRef(&RTfes,rhs.GetBlock(0),0);
|
||||
b1.MakeRef(&L2fes,rhs.GetBlock(1),0);
|
||||
|
||||
b0.AddDomainIntegrator(new VectorFEDomainLFIntegrator(neg_Z));
|
||||
b1.AddDomainIntegrator(new DomainLFIntegrator(neg_one));
|
||||
b1.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
|
||||
|
||||
ParBilinearForm a00(&RTfes);
|
||||
a00.AddDomainIntegrator(new VectorFEMassIntegrator(DZ));
|
||||
a00.AddDomainIntegrator(new VectorFEMassIntegrator(tichonov_cf));
|
||||
|
||||
ParMixedBilinearForm a10(&RTfes,&L2fes);
|
||||
a10.AddDomainIntegrator(new VectorFEDivergenceIntegrator());
|
||||
a10.Assemble();
|
||||
a10.Finalize();
|
||||
HypreParMatrix *A10 = a10.ParallelAssemble();
|
||||
|
||||
HypreParMatrix *A01 = A10->Transpose();
|
||||
|
||||
ParBilinearForm a11(&L2fes);
|
||||
a11.AddDomainIntegrator(new MassIntegrator(neg_tichonov_cf));
|
||||
a11.Assemble();
|
||||
a11.Finalize();
|
||||
HypreParMatrix *A11 = a11.ParallelAssemble();
|
||||
|
||||
// 11. Iterate.
|
||||
int k;
|
||||
int total_iterations = 0;
|
||||
real_t increment_u = 0.1;
|
||||
ParGridFunction u_tmp(&L2fes);
|
||||
for (k = 0; k < max_it; k++)
|
||||
{
|
||||
u_tmp = u_old_gf;
|
||||
Z.SetAlpha(alpha);
|
||||
DZ.SetAlpha(alpha);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
|
||||
}
|
||||
|
||||
int j;
|
||||
for ( j = 0; j < 5; j++)
|
||||
{
|
||||
total_iterations++;
|
||||
|
||||
b0.Assemble();
|
||||
b0.ParallelAssemble(trhs.GetBlock(0));
|
||||
|
||||
b1.Assemble();
|
||||
b1.ParallelAssemble(trhs.GetBlock(1));
|
||||
|
||||
a00.Assemble(false);
|
||||
a00.Finalize(false);
|
||||
HypreParMatrix *A00 = a00.ParallelAssemble();
|
||||
|
||||
// Construct Schur-complement preconditioner
|
||||
HypreParVector A00_diag(MPI_COMM_WORLD, A00->GetGlobalNumRows(),
|
||||
A00->GetRowStarts());
|
||||
A00->GetDiag(A00_diag);
|
||||
HypreParMatrix S_tmp(*A01);
|
||||
S_tmp.InvScaleRows(A00_diag);
|
||||
HypreParMatrix *S = ParMult(A10, &S_tmp, true);
|
||||
|
||||
BlockDiagonalPreconditioner prec(toffsets);
|
||||
HypreBoomerAMG P00(*A00);
|
||||
P00.SetPrintLevel(0);
|
||||
HypreBoomerAMG P11(*S);
|
||||
P11.SetPrintLevel(0);
|
||||
prec.SetDiagonalBlock(0,&P00);
|
||||
prec.SetDiagonalBlock(1,&P11);
|
||||
|
||||
BlockOperator A(toffsets);
|
||||
A.SetBlock(0,0,A00);
|
||||
A.SetBlock(1,0,A10);
|
||||
A.SetBlock(0,1,A01);
|
||||
A.SetBlock(1,1,A11);
|
||||
|
||||
GMRESSolver gmres(MPI_COMM_WORLD);
|
||||
gmres.SetPrintLevel(-1);
|
||||
gmres.SetRelTol(1e-8);
|
||||
gmres.SetMaxIter(2000);
|
||||
gmres.SetKDim(500);
|
||||
gmres.SetOperator(A);
|
||||
gmres.SetPreconditioner(prec);
|
||||
gmres.Mult(trhs,tx);
|
||||
delete S;
|
||||
delete A00;
|
||||
|
||||
delta_psi_gf.SetFromTrueDofs(tx.GetBlock(0));
|
||||
u_gf.SetFromTrueDofs(tx.GetBlock(1));
|
||||
|
||||
u_tmp -= u_gf;
|
||||
real_t Newton_update_size = u_tmp.ComputeL2Error(zero);
|
||||
u_tmp = u_gf;
|
||||
|
||||
// Damped Newton update
|
||||
psi_gf.Add(newton_scaling, delta_psi_gf);
|
||||
a00.Update();
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock << "solution\n" << pmesh << u_gf << "window_title 'Discrete solution'"
|
||||
<< flush;
|
||||
}
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
|
||||
}
|
||||
|
||||
if (Newton_update_size < increment_u)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u_tmp = u_gf;
|
||||
u_tmp -= u_old_gf;
|
||||
increment_u = u_tmp.ComputeL2Error(zero);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "Number of Newton iterations = " << j+1 << endl;
|
||||
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
|
||||
}
|
||||
|
||||
u_old_gf = u_gf;
|
||||
psi_old_gf = psi_gf;
|
||||
|
||||
if (increment_u < tol || k == max_it-1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
alpha *= max(growth_rate, 1_r);
|
||||
|
||||
}
|
||||
|
||||
// 12. Print stats.
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "\n Outer iterations: " << k+1
|
||||
<< "\n Total iterations: " << total_iterations
|
||||
<< "\n Total dofs: " << RTfes.GetTrueVSize() + L2fes.GetTrueVSize()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// 13. Free the used memory.
|
||||
delete A01;
|
||||
delete A10;
|
||||
delete A11;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ZCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
MFEM_ASSERT(psi != NULL, "grid function is not set");
|
||||
MFEM_ASSERT(alpha > 0, "alpha is not positive");
|
||||
|
||||
Vector psi_vals(vdim);
|
||||
psi->GetVectorValue(T, ip, psi_vals);
|
||||
real_t norm = psi_vals.Norml2();
|
||||
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
|
||||
|
||||
V = psi_vals;
|
||||
V *= phi;
|
||||
}
|
||||
|
||||
void DZCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
MFEM_ASSERT(psi != NULL, "grid function is not set");
|
||||
MFEM_ASSERT(alpha > 0, "alpha is not positive");
|
||||
|
||||
Vector psi_vals(height);
|
||||
psi->GetVectorValue(T, ip, psi_vals);
|
||||
real_t norm = psi_vals.Norml2();
|
||||
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
|
||||
|
||||
K = 0.0;
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
K(i,i) = phi;
|
||||
for (int j = 0; j < height; j++)
|
||||
{
|
||||
K(i,j) -= psi_vals(i) * psi_vals(j) * pow(phi, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-5
@@ -23,14 +23,14 @@ MFEM_LIB_FILE = mfem_is_not_built
|
||||
|
||||
SEQ_EXAMPLES = ex0 ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 \
|
||||
ex17 ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex28 ex29 ex30 \
|
||||
ex31 ex33 ex34 ex36 ex37 ex38 ex39
|
||||
ex31 ex33 ex34 ex36 ex37 ex38 ex39 ex40
|
||||
PAR_EXAMPLES = ex0p ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p \
|
||||
ex12p ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p \
|
||||
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p ex34p ex35p ex36p \
|
||||
ex37p ex39p
|
||||
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
|
||||
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p \
|
||||
ex24p ex25p ex26p ex34p ex35p
|
||||
ex37p ex39p ex40p
|
||||
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex14 ex22 ex24 ex25 ex26 ex34
|
||||
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex14p \
|
||||
ex22p ex24p ex25p ex26p ex34p ex35p
|
||||
|
||||
ifeq ($(MFEM_USE_LAPACK),YES)
|
||||
SEQ_EXAMPLES += ex38
|
||||
@@ -138,6 +138,14 @@ ex10-test-seq: ex10
|
||||
@$(call mfem-test,$<,, Serial example,-tf 5)
|
||||
ex10p-test-par: ex10p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-tf 5)
|
||||
ex14-test-seq-cuda: ex14
|
||||
@$(call mfem-test,$<,, Serial CUDA example,-r 2 -pa -d cuda)
|
||||
ex14p-test-par-cuda: ex14p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel CUDA example,-rs 2 -rp 0 -pa -d cuda)
|
||||
ex14-test-seq-hip: ex14
|
||||
@$(call mfem-test,$<,, Serial HIP example,-r 2 -pa -d hip)
|
||||
ex14p-test-par-hip: ex14p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel HIP example,-rs 2 -rp 0 -pa -d hip)
|
||||
ex15-test-seq: ex15
|
||||
@$(call mfem-test,$<,, Serial example,-e 1)
|
||||
ex15p-test-par: ex15p
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1539,6 +1539,351 @@ const IntegrationRule &ConvectionIntegrator::GetRule(
|
||||
return GetRule(el,el,Trans);
|
||||
}
|
||||
|
||||
|
||||
void LaplaceIntegrator::AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat )
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
real_t w;
|
||||
|
||||
elmat.SetSize(nd);
|
||||
shape.SetSize(nd);
|
||||
laplace.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint (&ip);
|
||||
|
||||
el.CalcPhysShape(Trans, shape);
|
||||
el.CalcPhysLaplacian(Trans, laplace);
|
||||
|
||||
w = Trans.Weight() * ip.weight * alpha;
|
||||
if (Q)
|
||||
{
|
||||
w *= Q -> Eval(Trans, ip);
|
||||
}
|
||||
shape *= w;
|
||||
AddMultVWt(shape, laplace, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
void LaplaceIntegrator::AssembleElementMatrix2(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
int tr_nd = trial_fe.GetDof();
|
||||
int te_nd = test_fe.GetDof();
|
||||
|
||||
elmat.SetSize(te_nd, tr_nd);
|
||||
laplace.SetSize(tr_nd);
|
||||
shape.SetSize(te_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
|
||||
Trans);
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint (&ip);
|
||||
|
||||
test_fe.CalcPhysShape(Trans, shape);
|
||||
trial_fe.CalcPhysLaplacian(Trans, laplace);
|
||||
|
||||
real_t w = Trans.Weight() * ip.weight * alpha;
|
||||
if (Q)
|
||||
{
|
||||
w *= Q -> Eval(Trans, ip);
|
||||
}
|
||||
AddMult_a_VWt(w, shape, laplace, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
const IntegrationRule &LaplaceIntegrator::GetRule(
|
||||
const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans)
|
||||
{
|
||||
int order = trial_fe.GetOrder() + test_fe.GetOrder();
|
||||
return IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
void LaplaceGradIntegrator::AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat )
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
dim = el.GetDim();
|
||||
|
||||
elmat.SetSize(nd);
|
||||
dshape.SetSize(nd,dim);
|
||||
adjJ.SetSize(dim);
|
||||
laplace.SetSize(nd);
|
||||
vec2.SetSize(dim);
|
||||
BdFidxT.SetSize(nd);
|
||||
|
||||
Vector vec1;
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
|
||||
|
||||
Q->Eval(Q_ir, Trans, *ir);
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
el.CalcDShape(ip, dshape);
|
||||
el.CalcPhysLaplacian(Trans, laplace);
|
||||
|
||||
Trans.SetIntPoint(&ip);
|
||||
CalcAdjugate(Trans.Jacobian(), adjJ);
|
||||
Q_ir.GetColumnReference(i, vec1);
|
||||
vec1 *= alpha * ip.weight;
|
||||
|
||||
adjJ.Mult(vec1, vec2);
|
||||
dshape.Mult(vec2, BdFidxT);
|
||||
|
||||
AddMultVWt(BdFidxT, laplace, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
void LaplaceGradIntegrator::AssembleElementMatrix2(const FiniteElement
|
||||
&trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
dim = trial_fe.GetDim();
|
||||
int tr_nd = trial_fe.GetDof();
|
||||
int te_nd = test_fe.GetDof();
|
||||
|
||||
elmat.SetSize(te_nd, tr_nd);
|
||||
laplace.SetSize(tr_nd);
|
||||
dshape.SetSize(te_nd,dim);
|
||||
adjJ.SetSize(dim);
|
||||
vec2.SetSize(dim);
|
||||
BdFidxT.SetSize(te_nd);
|
||||
|
||||
Vector vec1;
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
|
||||
Trans);
|
||||
|
||||
Q->Eval(Q_ir, Trans, *ir);
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
test_fe.CalcDShape(ip, dshape);
|
||||
trial_fe.CalcPhysLaplacian(Trans, laplace);
|
||||
|
||||
Trans.SetIntPoint(&ip);
|
||||
CalcAdjugate(Trans.Jacobian(), adjJ);
|
||||
Q_ir.GetColumnReference(i, vec1);
|
||||
vec1 *= alpha * ip.weight;
|
||||
|
||||
adjJ.Mult(vec1, vec2);
|
||||
dshape.Mult(vec2, BdFidxT);
|
||||
|
||||
AddMultVWt(BdFidxT, laplace,elmat);
|
||||
}
|
||||
}
|
||||
|
||||
const IntegrationRule &LaplaceGradIntegrator::GetRule(
|
||||
const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans)
|
||||
{
|
||||
int order = trial_fe.GetOrder() + test_fe.GetOrder();
|
||||
return IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
void LaplaceLaplaceIntegrator::AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat )
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
real_t w;
|
||||
|
||||
elmat.SetSize(nd);
|
||||
laplace.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint (&ip);
|
||||
|
||||
el.CalcPhysLaplacian(Trans, laplace);
|
||||
|
||||
w = Trans.Weight() * ip.weight * alpha;
|
||||
if (Q)
|
||||
{
|
||||
w *= Q -> Eval(Trans, ip);
|
||||
}
|
||||
AddMult_a_VVt(w, laplace, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
void LaplaceLaplaceIntegrator::AssembleElementMatrix2(const FiniteElement
|
||||
&trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
int
|
||||
dim = trial_fe.GetDim();
|
||||
int tr_nd = trial_fe.GetDof();
|
||||
int te_nd = test_fe.GetDof();
|
||||
real_t w;
|
||||
|
||||
elmat.SetSize(te_nd, tr_nd);
|
||||
laplace.SetSize(tr_nd);
|
||||
te_laplace.SetSize(te_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
|
||||
Trans);
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint (&ip);
|
||||
|
||||
trial_fe.CalcPhysLaplacian(Trans, laplace);
|
||||
test_fe.CalcPhysLaplacian(Trans, te_laplace);
|
||||
|
||||
w = Trans.Weight() * ip.weight * alpha;
|
||||
if (Q)
|
||||
{
|
||||
w *= Q -> Eval(Trans, ip);
|
||||
}
|
||||
AddMult_a_VWt(w, te_laplace, laplace, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
const IntegrationRule &LaplaceLaplaceIntegrator::GetRule(
|
||||
const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans)
|
||||
{
|
||||
int order = trial_fe.GetOrder() + test_fe.GetOrder();
|
||||
return IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
void InverseEstimateIntegrator::AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat )
|
||||
{
|
||||
elmat = 0.0;
|
||||
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
|
||||
shape.SetSize(nd);
|
||||
dshape.SetSize(nd,dim);
|
||||
laplace.SetSize(nd);
|
||||
|
||||
lapmat.SetSize(nd,nd);
|
||||
bimat.SetSize(nd,nd);
|
||||
ovec.SetSize(nd);
|
||||
|
||||
real_t w,q;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = Trans.OrderGrad(&el) + Trans.Order() + el.GetOrder();
|
||||
ir = &IntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
|
||||
bimat = 0.0;
|
||||
lapmat = 0.0;
|
||||
ovec = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint(&ip);
|
||||
w = Trans.Weight()*ip.weight;
|
||||
if (Q)
|
||||
{
|
||||
q = Q->Eval(Trans, ip);
|
||||
}
|
||||
|
||||
el.CalcPhysDShape(Trans, dshape);
|
||||
AddMult_a_AAt(w*q, dshape, lapmat);
|
||||
|
||||
el.CalcPhysLaplacian(Trans, laplace);
|
||||
AddMult_a_VVt(w*q*q, laplace, bimat);
|
||||
|
||||
el.CalcPhysShape(Trans, shape);
|
||||
ovec.Add(w, shape);
|
||||
}
|
||||
|
||||
// Power method
|
||||
Vector x(nd);
|
||||
x.Randomize(696383532);
|
||||
|
||||
// Correct nullspace + inverse
|
||||
AddMult_a_VVt(1.0, ovec, lapmat);
|
||||
DenseMatrixInverse L_inv(lapmat);
|
||||
|
||||
// DenseMatrix M_i, Q_i;
|
||||
real_t alpha= 0.0, eval_i = 0.0, eval_prev = 0.0;
|
||||
|
||||
// Inverse power method
|
||||
Vector x_tmp(nd);
|
||||
int iter = 0;
|
||||
const real_t rel_tol = 1e-4;
|
||||
|
||||
alpha = ovec*ovec;
|
||||
ovec *= 1.0/sqrt(alpha);
|
||||
do
|
||||
{
|
||||
// Othogonalize
|
||||
alpha = x*ovec;
|
||||
x.Add(-alpha, ovec);
|
||||
|
||||
// MatVec (2x)
|
||||
bimat.Mult(x, x_tmp);
|
||||
L_inv.Mult(x_tmp, x);
|
||||
|
||||
eval_prev = eval_i;
|
||||
eval_i = x.Norml2();
|
||||
x *= 1.0/eval_i;
|
||||
++iter;
|
||||
}
|
||||
while ((iter < 10000) && (fabs(eval_i - eval_prev)/fabs(eval_i) > rel_tol));
|
||||
MFEM_VERIFY(fabs(eval_i - eval_prev)/fabs(eval_i) <= rel_tol,
|
||||
"Inverse power method did not converge."
|
||||
<< "\n\t iter = " << iter
|
||||
<< "\n\t eval_i = " << eval_i
|
||||
<< "\n\t eval_prev = " << eval_prev
|
||||
<< "\n\t fabs(eval_i - eval_prev)/fabs(eval_i) = "
|
||||
<< fabs(eval_i - eval_prev)/fabs(eval_i));
|
||||
cout<<"evev = "<<eval_i<<" "<<iter<<endl;
|
||||
}
|
||||
|
||||
const IntegrationRule &InverseEstimateIntegrator::GetRule(
|
||||
const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans)
|
||||
{
|
||||
// int order = Trans.OrderGrad(&trial_fe) + Trans.Order() + test_fe.GetOrder() - 2;
|
||||
int order = trial_fe.GetOrder() + test_fe.GetOrder();
|
||||
return IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
|
||||
void VectorMassIntegrator::AssembleElementMatrix
|
||||
( const FiniteElement &el, ElementTransformation &Trans,
|
||||
DenseMatrix &elmat )
|
||||
|
||||
+132
-3
@@ -1741,7 +1741,7 @@ public:
|
||||
{ vector_fe.CalcPhysDShape(Trans, shape); }
|
||||
};
|
||||
|
||||
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \cdot \nabla \cdot u, \nabla \cdot v)$ in 2D
|
||||
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \cdot \nabla u, \nabla \cdot v)$ in 2D
|
||||
or 3D and where $\hat{V}$ is a vector coefficient, $u$ is in $H^1$ and $v$ is in $H(div)$. */
|
||||
class MixedGradDivIntegrator : public MixedScalarVectorIntegrator
|
||||
{
|
||||
@@ -1780,7 +1780,7 @@ public:
|
||||
{ scalar_fe.CalcPhysDivShape(Trans, shape); }
|
||||
};
|
||||
|
||||
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \nabla \cdot u, \nabla \cdot v)$ in 2D
|
||||
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \nabla \cdot u, \nabla v)$ in 2D
|
||||
or 3D and where $\hat{V}$ is a vector coefficient, $u$ is in $H(div)$ and $v$ is in $H^1$. */
|
||||
class MixedDivGradIntegrator : public MixedScalarVectorIntegrator
|
||||
{
|
||||
@@ -1820,7 +1820,7 @@ public:
|
||||
{ scalar_fe.CalcPhysDivShape(Trans, shape); }
|
||||
};
|
||||
|
||||
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} u, \nabla \cdot v)$ in 2D or 3D
|
||||
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} u, \nabla v)$ in 2D or 3D
|
||||
and where $\hat{V}$ is a vector coefficient, $u$ is in $H^1$ or $L_2$ and $v$ is in $H^1$. */
|
||||
class MixedScalarWeakDivergenceIntegrator : public MixedScalarVectorIntegrator
|
||||
{
|
||||
@@ -2450,6 +2450,135 @@ public:
|
||||
DenseMatrix &);
|
||||
};
|
||||
|
||||
|
||||
/// $\alpha (Q \Delta u, v)$
|
||||
class LaplaceIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
real_t alpha;
|
||||
|
||||
private:
|
||||
Vector laplace, shape;
|
||||
|
||||
public:
|
||||
LaplaceIntegrator(Coefficient &q, real_t a = 1.0)
|
||||
: Q(&q) { alpha = a; }
|
||||
|
||||
virtual void AssembleElementMatrix(const FiniteElement &,
|
||||
ElementTransformation &,
|
||||
DenseMatrix &);
|
||||
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans);
|
||||
};
|
||||
|
||||
/// $\alpha (u, Q \Delta v)$
|
||||
class TransposeLaplaceIntegrator : public TransposeIntegrator
|
||||
{
|
||||
public:
|
||||
TransposeLaplaceIntegrator (Coefficient &q, real_t a = 1.0)
|
||||
: TransposeIntegrator(new LaplaceIntegrator(q, a)) { }
|
||||
};
|
||||
|
||||
/// $\alpha (\Delta u, Q \cdot \nabla v)$
|
||||
class LaplaceGradIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
VectorCoefficient *Q;
|
||||
real_t alpha;
|
||||
int dim;
|
||||
|
||||
private:
|
||||
Vector laplace, vec2, BdFidxT;
|
||||
DenseMatrix dshape, adjJ, Q_ir;
|
||||
|
||||
public:
|
||||
LaplaceGradIntegrator(VectorCoefficient &q, real_t a = 1.0)
|
||||
: Q(&q) { alpha = a; }
|
||||
|
||||
virtual void AssembleElementMatrix(const FiniteElement &,
|
||||
ElementTransformation &,
|
||||
DenseMatrix &);
|
||||
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans);
|
||||
};
|
||||
|
||||
/// $\alpha (Q \cdot \nabla u, \Delta v)$
|
||||
class GradLaplaceIntegrator : public TransposeIntegrator
|
||||
{
|
||||
public:
|
||||
GradLaplaceIntegrator(VectorCoefficient &q, real_t a = 1.0)
|
||||
: TransposeIntegrator(new LaplaceGradIntegrator(q, a)) { }
|
||||
};
|
||||
|
||||
/// $\alpha (Q \Delta u, \Delta v)$
|
||||
class LaplaceLaplaceIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
real_t alpha;
|
||||
|
||||
private:
|
||||
Vector laplace, te_laplace;
|
||||
|
||||
public:
|
||||
LaplaceLaplaceIntegrator(Coefficient &q, real_t a = 1.0)
|
||||
: Q(&q) { alpha = a; }
|
||||
|
||||
virtual void AssembleElementMatrix(const FiniteElement &,
|
||||
ElementTransformation &,
|
||||
DenseMatrix &);
|
||||
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans);
|
||||
};
|
||||
|
||||
// Alias for @LaplaceLaplaceIntegrator.
|
||||
using BiHarmonicIntegrator = LaplaceLaplaceIntegrator;
|
||||
|
||||
/// Get the inverse estimate
|
||||
class InverseEstimateIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
|
||||
private:
|
||||
Vector laplace, shape, ovec;//, vec2, BdFidxT;
|
||||
DenseMatrix dshape, lapmat, bimat;//, adjJ, Q_ir;
|
||||
|
||||
public:
|
||||
InverseEstimateIntegrator(Coefficient &q)
|
||||
: Q(&q) { }
|
||||
|
||||
virtual void AssembleElementMatrix(const FiniteElement &,
|
||||
ElementTransformation &,
|
||||
DenseMatrix &);
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans);
|
||||
};
|
||||
|
||||
/** Class for integrating the bilinear form $a(u,v) := (Q u, v)$,
|
||||
where $u=(u_1,\dots,u_n)$ and $v=(v_1,\dots,v_n)$, $u_i$ and $v_i$ are defined
|
||||
by scalar FE through standard transformation. */
|
||||
|
||||
+407
-4
@@ -807,6 +807,7 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
|
||||
|
||||
QuadratureSpaceBase &qspace = *qf.GetSpace();
|
||||
const int ne = qspace.GetNE();
|
||||
qf.HostWrite();
|
||||
DenseMatrix values;
|
||||
DenseSymmetricMatrix matrix;
|
||||
for (int iel = 0; iel < ne; ++iel)
|
||||
@@ -818,7 +819,7 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
|
||||
{
|
||||
const IntegrationPoint &ip = ir[iq];
|
||||
T.SetIntPoint(&ip);
|
||||
matrix.UseExternalData(&values(0, iq), vdim);
|
||||
matrix.UseExternalData(&values(0, iq), height);
|
||||
Eval(matrix, T, ip);
|
||||
}
|
||||
}
|
||||
@@ -828,13 +829,12 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
|
||||
void SymmetricMatrixCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
mat.SetSize(height);
|
||||
Eval(mat, T, ip);
|
||||
Eval(mat_aux, T, ip);
|
||||
for (int j = 0; j < width; ++j)
|
||||
{
|
||||
for (int i = 0; i < height; ++ i)
|
||||
{
|
||||
K(i, j) = mat(i, j);
|
||||
K(i, j) = mat_aux(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -924,6 +924,75 @@ void MatrixArrayCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
}
|
||||
}
|
||||
|
||||
MatrixArrayVectorCoefficient::MatrixArrayVectorCoefficient (int dim)
|
||||
: MatrixCoefficient (dim)
|
||||
{
|
||||
Coeff.SetSize(height);
|
||||
ownCoeff.SetSize(height);
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
Coeff[i] = NULL;
|
||||
ownCoeff[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void MatrixArrayVectorCoefficient::SetTime(real_t t)
|
||||
{
|
||||
for (int i=0; i < height; i++)
|
||||
{
|
||||
if (Coeff[i]) { Coeff[i]->SetTime(t); }
|
||||
}
|
||||
this->MatrixCoefficient::SetTime(t);
|
||||
}
|
||||
|
||||
void MatrixArrayVectorCoefficient::Set(int i, VectorCoefficient * c, bool own)
|
||||
{
|
||||
MFEM_ASSERT(i < height && i >= 0, "Row "
|
||||
<< i << " does not exist. " <<
|
||||
"Matrix height = " << height << ".");
|
||||
if (ownCoeff[i]) { delete Coeff[i]; }
|
||||
Coeff[i] = c;
|
||||
ownCoeff[i] = own;
|
||||
}
|
||||
|
||||
MatrixArrayVectorCoefficient::~MatrixArrayVectorCoefficient ()
|
||||
{
|
||||
for (int i=0; i < height; i++)
|
||||
{
|
||||
if (ownCoeff[i]) { delete Coeff[i]; }
|
||||
}
|
||||
}
|
||||
|
||||
void MatrixArrayVectorCoefficient::Eval(int i, Vector &V,
|
||||
ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
MFEM_ASSERT(i < height && i >= 0, "Row "
|
||||
<< i << " does not exist. " <<
|
||||
"Matrix height = " << height << ".");
|
||||
if (Coeff[i])
|
||||
{
|
||||
Coeff[i] -> Eval(V, T, ip);
|
||||
}
|
||||
else
|
||||
{
|
||||
V = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void MatrixArrayVectorCoefficient::Eval(DenseMatrix &K,
|
||||
ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
K.SetSize(height, width);
|
||||
Vector V(width);
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
this->Eval(i, V, T, ip);
|
||||
K.SetRow(i, V);
|
||||
}
|
||||
}
|
||||
|
||||
void MatrixRestrictedCoefficient::SetTime(real_t t)
|
||||
{
|
||||
if (c) { c->SetTime(t); }
|
||||
@@ -1041,6 +1110,27 @@ real_t DeterminantCoefficient::Eval(ElementTransformation &T,
|
||||
return ma.Det();
|
||||
}
|
||||
|
||||
TraceCoefficient::TraceCoefficient(MatrixCoefficient &A)
|
||||
: a(&A), ma(A.GetHeight(), A.GetWidth())
|
||||
{
|
||||
MFEM_ASSERT(A.GetHeight() == A.GetWidth(),
|
||||
"TraceCoefficient: "
|
||||
"Argument must be a square matrix.");
|
||||
}
|
||||
|
||||
void TraceCoefficient::SetTime(real_t t)
|
||||
{
|
||||
if (a) { a->SetTime(t); }
|
||||
this->Coefficient::SetTime(t);
|
||||
}
|
||||
|
||||
real_t TraceCoefficient::Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
a->Eval(ma, T, ip);
|
||||
return ma.Trace();
|
||||
}
|
||||
|
||||
VectorSumCoefficient::VectorSumCoefficient(int dim)
|
||||
: VectorCoefficient(dim),
|
||||
ACoef(NULL), BCoef(NULL),
|
||||
@@ -1326,6 +1416,30 @@ void InverseMatrixCoefficient::Eval(DenseMatrix &M,
|
||||
M.Invert();
|
||||
}
|
||||
|
||||
ExponentialMatrixCoefficient::ExponentialMatrixCoefficient(MatrixCoefficient &A)
|
||||
: MatrixCoefficient(A.GetHeight(), A.GetWidth()), a(&A)
|
||||
{
|
||||
MFEM_ASSERT(A.GetHeight() == A.GetWidth() && A.GetHeight() == 2,
|
||||
"ExponentialMatrixCoefficient: "
|
||||
<< "Argument must be a square 2x2 matrix."
|
||||
<< " Height = " << A.GetHeight()
|
||||
<< ", Width = " << A.GetWidth());
|
||||
}
|
||||
|
||||
void ExponentialMatrixCoefficient::SetTime(real_t t)
|
||||
{
|
||||
if (a) { a->SetTime(t); }
|
||||
this->MatrixCoefficient::SetTime(t);
|
||||
}
|
||||
|
||||
void ExponentialMatrixCoefficient::Eval(DenseMatrix &M,
|
||||
ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
a->Eval(M, T, ip);
|
||||
M.Exponential();
|
||||
}
|
||||
|
||||
OuterProductCoefficient::OuterProductCoefficient(VectorCoefficient &A,
|
||||
VectorCoefficient &B)
|
||||
: MatrixCoefficient(A.GetVDim(), B.GetVDim()), a(&A), b(&B),
|
||||
@@ -1390,6 +1504,295 @@ void CrossCrossCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
|
||||
M *= ((a == NULL ) ? aConst : a->Eval(T, ip) );
|
||||
}
|
||||
|
||||
|
||||
InverseEstimateCoefficient::InverseEstimateCoefficient(FiniteElementSpace *f)
|
||||
: fes(f), Q(NULL), ir(NULL)
|
||||
{
|
||||
ComputeInverseEstimates();
|
||||
}
|
||||
|
||||
InverseEstimateCoefficient::InverseEstimateCoefficient(FiniteElementSpace *f,
|
||||
Coefficient &q)
|
||||
: fes(f), Q(&q), ir(NULL)
|
||||
{
|
||||
ComputeInverseEstimates();
|
||||
}
|
||||
|
||||
GridFunction *InverseEstimateCoefficient::GetGridFunction()
|
||||
{
|
||||
FiniteElementCollection* fec_ec = new L2_FECollection(0,
|
||||
fes ->GetMesh()->Dimension());
|
||||
FiniteElementSpace *fes_ec = new FiniteElementSpace(fes ->GetMesh(), fec_ec);
|
||||
GridFunction *gf = new GridFunction(fes_ec, elemInvEst.GetData());
|
||||
gf->MakeOwner(fec_ec);
|
||||
return gf;
|
||||
}
|
||||
|
||||
void InverseEstimateCoefficient::ComputeInverseEstimates()
|
||||
{
|
||||
elemInvEst.SetSize(fes -> GetNE());
|
||||
SetIntRule(*fes->GetFE(0));
|
||||
for (int i = 0; i < fes -> GetNE(); i++)
|
||||
{
|
||||
elemInvEst[i] = ElementInverseEstimate(*fes->GetFE(i),
|
||||
*fes->GetElementTransformation(i));
|
||||
}
|
||||
}
|
||||
|
||||
void InverseEstimateCoefficient::SetIntRule(const FiniteElement &el)
|
||||
{
|
||||
ir = &IntRules.Get(el.GetGeomType(), 2*el.GetOrder());
|
||||
}
|
||||
|
||||
real_t InverseEstimateCoefficient::ElementInverseEstimate(
|
||||
const FiniteElement &el,
|
||||
ElementTransformation &Trans)
|
||||
{
|
||||
if (el.GetOrder() < 2)
|
||||
{
|
||||
return std::numeric_limits<real_t>::min();
|
||||
}
|
||||
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
|
||||
shape.SetSize(nd);
|
||||
dshape.SetSize(nd,dim);
|
||||
laplace.SetSize(nd);
|
||||
|
||||
lapmat.SetSize(nd,nd);
|
||||
bimat.SetSize(nd,nd);
|
||||
ovec.SetSize(nd);
|
||||
|
||||
real_t w,q = 1.0;
|
||||
|
||||
bimat = 0.0;
|
||||
lapmat = 0.0;
|
||||
ovec = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint(&ip);
|
||||
w = Trans.Weight()*ip.weight;
|
||||
if (Q)
|
||||
{
|
||||
q = Q->Eval(Trans, ip);
|
||||
}
|
||||
|
||||
el.CalcPhysDShape(Trans, dshape);
|
||||
AddMult_a_AAt(w*q, dshape, lapmat);
|
||||
|
||||
el.CalcPhysLaplacian(Trans, laplace);
|
||||
AddMult_a_VVt(w*q*q, laplace, bimat);
|
||||
|
||||
el.CalcPhysShape(Trans, shape);
|
||||
ovec.Add(w, shape);
|
||||
}
|
||||
ovec *= 1.0/ovec.Norml2();
|
||||
|
||||
// Correct nullspace
|
||||
AddMultVVt(ovec, lapmat);
|
||||
|
||||
// Return largest eigenvalue
|
||||
return bimat.Eigenvalue(lapmat);
|
||||
}
|
||||
|
||||
ElasticInverseEstimateCoefficient
|
||||
::ElasticInverseEstimateCoefficient(FiniteElementSpace *f)
|
||||
: fes(f), Q(NULL), ir(NULL)
|
||||
{
|
||||
ComputeInverseEstimates();
|
||||
}
|
||||
|
||||
ElasticInverseEstimateCoefficient
|
||||
::ElasticInverseEstimateCoefficient(FiniteElementSpace *f,
|
||||
Coefficient &q)
|
||||
: fes(f), Q(&q), ir(NULL)
|
||||
{
|
||||
ComputeInverseEstimates();
|
||||
}
|
||||
|
||||
GridFunction *ElasticInverseEstimateCoefficient::GetGridFunction()
|
||||
{
|
||||
FiniteElementCollection* fec_ec = new L2_FECollection(0,
|
||||
fes ->GetMesh()->Dimension());
|
||||
FiniteElementSpace *fes_ec = new FiniteElementSpace(fes ->GetMesh(), fec_ec);
|
||||
GridFunction *gf = new GridFunction(fes_ec, elemInvEst.GetData());
|
||||
gf->MakeOwner(fec_ec);
|
||||
return gf;
|
||||
}
|
||||
|
||||
void ElasticInverseEstimateCoefficient::ComputeInverseEstimates()
|
||||
{
|
||||
elemInvEst.SetSize(fes -> GetNE());
|
||||
SetIntRule(*fes->GetFE(0));
|
||||
int dim = fes->GetFE(0)->GetDim();
|
||||
|
||||
emat.SetSize(dim,dim);
|
||||
divmat.SetSize(dim,dim);
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
for (int j = 0; j < dim; j++)
|
||||
{
|
||||
emat(i,j)= new DenseMatrix();
|
||||
divmat(i,j)= new DenseMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
hmap.SetSize(dim,dim);
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
hmap(0,0) = 0;
|
||||
hmap(0,1) = hmap(1,0) = 1;
|
||||
hmap(1,1) = 2;
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
hmap(0,0) = 0;
|
||||
hmap(0,1) = hmap(1,0) = 1;
|
||||
hmap(0,2) = hmap(2,0) = 2;
|
||||
hmap(1,1) = 3;
|
||||
hmap(1,2) = hmap(2,1) = 4;
|
||||
hmap(2,2) = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem_error("Only implemented for 2D and 3D");
|
||||
}
|
||||
|
||||
for (int i = 0; i < fes -> GetNE(); i++)
|
||||
{
|
||||
elemInvEst[i] = ElementInverseEstimate(*fes->GetFE(i),
|
||||
*fes->GetElementTransformation(i));
|
||||
}
|
||||
}
|
||||
|
||||
void ElasticInverseEstimateCoefficient::SetIntRule(const FiniteElement &el)
|
||||
{
|
||||
ir = &IntRules.Get(el.GetGeomType(), 2*el.GetOrder());
|
||||
}
|
||||
|
||||
real_t ElasticInverseEstimateCoefficient::ElementInverseEstimate(
|
||||
const FiniteElement &el,
|
||||
ElementTransformation &Trans)
|
||||
{
|
||||
// if (el.GetDerivType() != (int) FiniteElement::HESS)
|
||||
// {
|
||||
// return std::numeric_limits<real_t>::min();
|
||||
// }
|
||||
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
|
||||
shape.SetSize(nd);
|
||||
dshape.SetSize(nd,dim);
|
||||
hshape.SetSize(nd,dim*(dim+1)/2);
|
||||
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
for (int j = 0; j < dim; j++)
|
||||
{
|
||||
emat(i,j)->SetSize(nd,nd);
|
||||
*emat(i,j) = 0.0;
|
||||
divmat(i,j)->SetSize(nd,nd);
|
||||
*divmat(i,j) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
real_t w,q = 1.0;
|
||||
for (int ii = 0; ii < ir->GetNPoints(); ii++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(ii);
|
||||
Trans.SetIntPoint(&ip);
|
||||
w = Trans.Weight()*ip.weight;
|
||||
if (Q)
|
||||
{
|
||||
q = Q->Eval(Trans, ip);
|
||||
}
|
||||
|
||||
el.CalcPhysDShape(Trans, dshape);
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
for (int j = 0; j < dim; j++)
|
||||
{
|
||||
AddMult_a_VVt(w*q, Vector(dshape.GetColumn(i),nd), *emat(j,j));
|
||||
|
||||
AddMult_a_VWt(w*q, Vector(dshape.GetColumn(i),nd),
|
||||
Vector(dshape.GetColumn(j),nd), *emat(j,i));
|
||||
|
||||
AddMult_a_VWt(w*q, Vector(dshape.GetColumn(j),nd),
|
||||
Vector(dshape.GetColumn(i),nd), *emat(i,j));
|
||||
|
||||
AddMult_a_VVt(w*q, Vector(dshape.GetColumn(j),nd), *emat(i,i));
|
||||
}
|
||||
}
|
||||
|
||||
el.CalcPhysHessian(Trans, hshape);
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
for (int j = 0; j < dim; j++)
|
||||
{
|
||||
for (int k = 0; k < dim; k++)
|
||||
{
|
||||
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,i)),nd),
|
||||
Vector(hshape.GetColumn(hmap(k,k)),nd), *divmat(j,j));
|
||||
|
||||
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,i)),nd),
|
||||
Vector(hshape.GetColumn(hmap(k,j)),nd), *divmat(j,k));
|
||||
|
||||
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,j)),nd),
|
||||
Vector(hshape.GetColumn(hmap(k,k)),nd), *divmat(i,j));
|
||||
|
||||
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,j)),nd),
|
||||
Vector(hshape.GetColumn(hmap(k,j)),nd), *divmat(i,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect matrices
|
||||
emat_tot.SetSize(nd*dim,nd*dim);
|
||||
divmat_tot.SetSize(nd*dim,nd*dim);
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
for (int j = 0; j < dim; j++)
|
||||
{
|
||||
emat_tot .SetSubMatrix(i*nd, j*nd, *emat(i,j));
|
||||
divmat_tot.SetSubMatrix(i*nd, j*nd, *divmat(i,j));
|
||||
}
|
||||
}
|
||||
|
||||
// Correct nullspace
|
||||
DenseMatrix ns;
|
||||
emat_tot.NullSpace(ns, 1e-10);
|
||||
for (int i = 0; i < ns.Width(); i++)
|
||||
{
|
||||
AddMultVVt(Vector(ns.GetColumn(i),nd*dim), emat_tot);
|
||||
}
|
||||
|
||||
// Return largest eigenvalue
|
||||
return divmat_tot.Eigenvalue(emat_tot);
|
||||
}
|
||||
|
||||
ElasticInverseEstimateCoefficient::~ElasticInverseEstimateCoefficient()
|
||||
{
|
||||
for (int i = 0; i < emat.NumRows(); i++)
|
||||
{
|
||||
for (int j = 0; j < emat.NumCols(); j++)
|
||||
{
|
||||
delete emat(i,j);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < divmat.NumRows(); i++)
|
||||
{
|
||||
for (int j = 0; j < divmat.NumCols(); j++)
|
||||
{
|
||||
delete divmat(i,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
real_t LpNormLoop(real_t p, Coefficient &coeff, Mesh &mesh,
|
||||
const IntegrationRule *irs[])
|
||||
{
|
||||
|
||||
+221
-6
@@ -1334,6 +1334,46 @@ public:
|
||||
virtual ~MatrixArrayCoefficient();
|
||||
};
|
||||
|
||||
/** @brief Matrix coefficient defined row-wise by an array of vector
|
||||
coefficients. Rows that are not set will evaluate to zero. The
|
||||
matrix coefficient is stored as an array indexing the rows of
|
||||
the matrix. */
|
||||
class MatrixArrayVectorCoefficient : public MatrixCoefficient
|
||||
{
|
||||
private:
|
||||
Array<VectorCoefficient *> Coeff;
|
||||
Array<bool> ownCoeff;
|
||||
|
||||
public:
|
||||
/** @brief Construct a coefficient matrix of dimensions @a dim * @a dim. The
|
||||
actual coefficients still need to be added with Set(). */
|
||||
explicit MatrixArrayVectorCoefficient (int dim);
|
||||
|
||||
/// Set the time for internally stored coefficients
|
||||
void SetTime(real_t t) override;
|
||||
|
||||
/// Get the vector coefficient located at the i-th row of the matrix
|
||||
VectorCoefficient* GetCoeff (int i) { return Coeff[i]; }
|
||||
|
||||
/** @brief Set the coefficient located at the i-th row of the matrix.
|
||||
By this will take ownership of the Coefficient passed in, but this
|
||||
can be overridden with the @a own parameter. */
|
||||
void Set(int i, VectorCoefficient * c, bool own=true);
|
||||
|
||||
using MatrixCoefficient::Eval;
|
||||
|
||||
/// Evaluate coefficient located at the i-th row of the matrix using integration
|
||||
/// point @a ip.
|
||||
void Eval(int i, Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
/// Evaluate the matrix coefficient @a ip.
|
||||
void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip) override;
|
||||
|
||||
virtual ~MatrixArrayVectorCoefficient();
|
||||
};
|
||||
|
||||
|
||||
/** @brief Derived matrix coefficient that has the value of the parent matrix
|
||||
coefficient where it is active and is zero otherwise. */
|
||||
@@ -1426,12 +1466,13 @@ public:
|
||||
class SymmetricMatrixCoefficient : public MatrixCoefficient
|
||||
{
|
||||
protected:
|
||||
|
||||
/// Internal matrix used when evaluating this coefficient as a DenseMatrix.
|
||||
DenseSymmetricMatrix mat;
|
||||
mutable DenseSymmetricMatrix mat_aux;
|
||||
public:
|
||||
/// Construct a dim x dim matrix coefficient.
|
||||
explicit SymmetricMatrixCoefficient(int dimension)
|
||||
: MatrixCoefficient(dimension, true) { }
|
||||
: MatrixCoefficient(dimension, true), mat_aux(height) { }
|
||||
|
||||
/// Get the size of the matrix.
|
||||
int GetSize() const { return height; }
|
||||
@@ -1464,8 +1505,9 @@ public:
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
/// Return a reference to the constant matrix.
|
||||
const DenseSymmetricMatrix& GetMatrix() { return mat; }
|
||||
|
||||
/// @deprecated Return a reference to the internal matrix used when evaluating this coefficient as a DenseMatrix.
|
||||
MFEM_DEPRECATED const DenseSymmetricMatrix& GetMatrix() { return mat_aux; }
|
||||
|
||||
virtual ~SymmetricMatrixCoefficient() { }
|
||||
};
|
||||
@@ -1485,6 +1527,10 @@ public:
|
||||
/// Evaluate the matrix coefficient at @a ip.
|
||||
virtual void Eval(DenseSymmetricMatrix &M, ElementTransformation &T,
|
||||
const IntegrationPoint &ip) { M = mat; }
|
||||
|
||||
/// Return a reference to the constant matrix.
|
||||
const DenseSymmetricMatrix& GetMatrix() { return mat; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1761,6 +1807,31 @@ public:
|
||||
const IntegrationPoint &ip);
|
||||
};
|
||||
|
||||
/// Scalar coefficient defined as the trace of a matrix coefficient
|
||||
class TraceCoefficient : public Coefficient
|
||||
{
|
||||
private:
|
||||
MatrixCoefficient * a;
|
||||
|
||||
mutable DenseMatrix ma;
|
||||
|
||||
public:
|
||||
/// Construct with the matrix.
|
||||
TraceCoefficient(MatrixCoefficient &A);
|
||||
|
||||
/// Set the time for internally stored coefficients
|
||||
void SetTime(real_t t);
|
||||
|
||||
/// Reset the matrix coefficient
|
||||
void SetACoef(MatrixCoefficient &A) { a = &A; }
|
||||
/// Return the matrix coefficient
|
||||
MatrixCoefficient * GetACoef() const { return a; }
|
||||
|
||||
/// Evaluate the trace coefficient at @a ip.
|
||||
virtual real_t Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
};
|
||||
|
||||
/// Vector coefficient defined as the linear combination of two vectors
|
||||
class VectorSumCoefficient : public VectorCoefficient
|
||||
{
|
||||
@@ -2112,7 +2183,7 @@ public:
|
||||
const IntegrationPoint &ip);
|
||||
};
|
||||
|
||||
/// Matrix coefficient defined as the transpose a matrix coefficient
|
||||
/// Matrix coefficient defined as the transpose of a matrix coefficient
|
||||
class TransposeMatrixCoefficient : public MatrixCoefficient
|
||||
{
|
||||
private:
|
||||
@@ -2135,7 +2206,7 @@ public:
|
||||
const IntegrationPoint &ip);
|
||||
};
|
||||
|
||||
/// Matrix coefficient defined as the inverse a matrix coefficient.
|
||||
/// Matrix coefficient defined as the inverse of a matrix coefficient.
|
||||
class InverseMatrixCoefficient : public MatrixCoefficient
|
||||
{
|
||||
private:
|
||||
@@ -2158,6 +2229,29 @@ public:
|
||||
const IntegrationPoint &ip);
|
||||
};
|
||||
|
||||
/// Matrix coefficient defined as the exponential of a matrix coefficient.
|
||||
class ExponentialMatrixCoefficient : public MatrixCoefficient
|
||||
{
|
||||
private:
|
||||
MatrixCoefficient * a;
|
||||
|
||||
public:
|
||||
/// Construct the matrix coefficient. Result is $ \exp(A) $.
|
||||
ExponentialMatrixCoefficient(MatrixCoefficient &A);
|
||||
|
||||
/// Set the time for internally stored coefficients
|
||||
void SetTime(real_t t);
|
||||
|
||||
/// Reset the matrix coefficient
|
||||
void SetACoef(MatrixCoefficient &A) { a = &A; }
|
||||
/// Return the matrix coefficient
|
||||
MatrixCoefficient * GetACoef() const { return a; }
|
||||
|
||||
/// Evaluate the matrix coefficient at @a ip.
|
||||
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
};
|
||||
|
||||
/// Matrix coefficient defined as the outer product of two vector coefficients.
|
||||
class OuterProductCoefficient : public MatrixCoefficient
|
||||
{
|
||||
@@ -2234,6 +2328,127 @@ public:
|
||||
};
|
||||
///@}
|
||||
|
||||
/** @brief
|
||||
*/
|
||||
class InverseEstimateCoefficient : public Coefficient
|
||||
{
|
||||
private:
|
||||
///
|
||||
Vector elemInvEst;
|
||||
/// FE space on which the grid function lives. Owned if #fec is not NULL.
|
||||
FiniteElementSpace *fes;
|
||||
|
||||
///
|
||||
const IntegrationRule *ir;
|
||||
|
||||
///
|
||||
Coefficient *Q;
|
||||
Vector laplace, shape, ovec, evec;
|
||||
DenseMatrix dshape, lapmat, bimat;
|
||||
|
||||
///
|
||||
void SetIntRule(const FiniteElement &el);
|
||||
|
||||
///
|
||||
void ComputeInverseEstimates();
|
||||
|
||||
real_t ElementInverseEstimate(const FiniteElement &el,
|
||||
ElementTransformation &Trans);
|
||||
|
||||
public:
|
||||
///
|
||||
InverseEstimateCoefficient(FiniteElementSpace *f);
|
||||
InverseEstimateCoefficient(FiniteElementSpace *f, Coefficient &q);
|
||||
|
||||
/// Caller gets owner ship of GridFunction and
|
||||
GridFunction *GetGridFunction();
|
||||
|
||||
/// Reset the scalar factor
|
||||
void SetDiffusion(Coefficient &q)
|
||||
{
|
||||
if (Q != &q)
|
||||
{
|
||||
Q = &q;
|
||||
ComputeInverseEstimates();
|
||||
}
|
||||
}
|
||||
/// Return the scalar factor
|
||||
Coefficient * GetDiffusion() const { return Q; }
|
||||
|
||||
/// Evaluate the coefficient at @a ip.
|
||||
virtual real_t Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{ return elemInvEst[T.ElementNo]; }
|
||||
|
||||
};
|
||||
|
||||
class ElasticInverseEstimateCoefficient : public Coefficient
|
||||
{
|
||||
private:
|
||||
///
|
||||
Vector elemInvEst;
|
||||
/// FE space on which the grid function lives. Owned if #fec is not NULL.
|
||||
FiniteElementSpace *fes;
|
||||
|
||||
///
|
||||
const IntegrationRule *ir;
|
||||
|
||||
///
|
||||
Coefficient *Q;
|
||||
Vector shape, ovec, evec;
|
||||
DenseMatrix dshape, hshape, emat_tot, divmat_tot;
|
||||
Array2D<DenseMatrix*> emat,divmat;
|
||||
Array2D<int> hmap;
|
||||
|
||||
///
|
||||
void SetIntRule(const FiniteElement &el);
|
||||
|
||||
///
|
||||
void ComputeInverseEstimates();
|
||||
|
||||
///
|
||||
real_t ElementInverseEstimate(const FiniteElement &el,
|
||||
ElementTransformation &Trans);
|
||||
|
||||
public:
|
||||
///
|
||||
ElasticInverseEstimateCoefficient(FiniteElementSpace *f);
|
||||
ElasticInverseEstimateCoefficient(FiniteElementSpace *f, Coefficient &q);
|
||||
|
||||
/// Caller gets owner ship of GridFunction and
|
||||
GridFunction *GetGridFunction();
|
||||
|
||||
/// Reset the scalar factor
|
||||
void SetDiffusion(Coefficient &q)
|
||||
{
|
||||
if (Q != &q)
|
||||
{
|
||||
Q = &q;
|
||||
ComputeInverseEstimates();
|
||||
}
|
||||
}
|
||||
void SetShearModulus(Coefficient &q) { SetDiffusion(q);}
|
||||
|
||||
/// Return the scalar factor
|
||||
Coefficient * GetDiffusion() const { return Q; }
|
||||
Coefficient * GetModulus() const { return GetDiffusion(); }
|
||||
|
||||
/// Evaluate the coefficient at @a ip.
|
||||
virtual real_t Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{ return elemInvEst[T.ElementNo]; }
|
||||
|
||||
// Destructor
|
||||
~ElasticInverseEstimateCoefficient();
|
||||
|
||||
};
|
||||
|
||||
|
||||
///@}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Vector quadrature function coefficient which requires that the
|
||||
quadrature rules used for this vector coefficient be the same as those that
|
||||
live within the supplied QuadratureFunction. */
|
||||
|
||||
+17
-2
@@ -52,6 +52,15 @@ protected:
|
||||
const DenseMatrix &EvalTransAdjugateJ();
|
||||
const DenseMatrix &EvalInverseJ();
|
||||
|
||||
/// @name Tolerance used for point comparisons
|
||||
///@{
|
||||
#ifdef MFEM_USE_DOUBLE
|
||||
static constexpr real_t tol_0 = 1e-15;
|
||||
#elif defined(MFEM_USE_SINGLE)
|
||||
static constexpr real_t tol_0 = 1e-7;
|
||||
#endif
|
||||
///@}
|
||||
|
||||
public:
|
||||
|
||||
/** This enumeration declares the values stored in
|
||||
@@ -176,7 +185,7 @@ public:
|
||||
returned. This method is not 100 percent reliable for non-linear
|
||||
transformations. */
|
||||
virtual int TransformBack(const Vector &pt, IntegrationPoint &ip,
|
||||
const real_t phys_tol = 1e-15) = 0;
|
||||
const real_t phys_tol = tol_0) = 0;
|
||||
|
||||
virtual ~ElementTransformation() { }
|
||||
};
|
||||
@@ -281,9 +290,15 @@ public:
|
||||
rel_qpts_order(-1),
|
||||
solver_type(NewtonElementProject),
|
||||
max_iter(16),
|
||||
#ifdef MFEM_USE_DOUBLE
|
||||
ref_tol(1e-15),
|
||||
phys_rtol(1e-15),
|
||||
ip_tol(1e-8),
|
||||
#elif defined(MFEM_USE_SINGLE)
|
||||
ref_tol(1e-7),
|
||||
phys_rtol(1e-7),
|
||||
ip_tol(1e-4),
|
||||
#endif
|
||||
print_level(-1)
|
||||
{ }
|
||||
|
||||
@@ -449,7 +464,7 @@ public:
|
||||
returned. This method is not 100 percent reliable for non-linear
|
||||
transformations. */
|
||||
virtual int TransformBack(const Vector & v, IntegrationPoint & ip,
|
||||
const real_t phys_rel_tol = 1e-15)
|
||||
const real_t phys_rel_tol = tol_0)
|
||||
{
|
||||
InverseElementTransformation inv_tr(this);
|
||||
inv_tr.SetPhysicalRelTol(phys_rel_tol);
|
||||
|
||||
+8
-8
@@ -221,7 +221,7 @@ void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans,
|
||||
{
|
||||
for (int nd = 0; nd < dof; nd++)
|
||||
{
|
||||
Laplacian[nd] = hess(nd,0) + hess(nd,4) + hess(nd,5);
|
||||
Laplacian[nd] = hess(nd,0) + hess(nd,3) + hess(nd,5);
|
||||
}
|
||||
}
|
||||
else if (dim == 2)
|
||||
@@ -259,10 +259,10 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
|
||||
scale[1] = 2*Gij(0,1);
|
||||
scale[2] = 2*Gij(0,2);
|
||||
|
||||
scale[3] = 2*Gij(1,2);
|
||||
scale[4] = Gij(2,2);
|
||||
scale[3] = Gij(1,1);
|
||||
scale[4] = 2*Gij(1,2);
|
||||
|
||||
scale[5] = Gij(1,1);
|
||||
scale[5] = Gij(2,2);
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
@@ -299,12 +299,12 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
|
||||
map[2] = 2;
|
||||
|
||||
map[3] = 1;
|
||||
map[4] = 5;
|
||||
map[5] = 3;
|
||||
map[4] = 3;
|
||||
map[5] = 4;
|
||||
|
||||
map[6] = 2;
|
||||
map[7] = 3;
|
||||
map[8] = 4;
|
||||
map[7] = 4;
|
||||
map[8] = 5;
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
|
||||
+29
-27
@@ -299,7 +299,8 @@ public:
|
||||
NONE, ///< No derivatives implemented
|
||||
GRAD, ///< Implements CalcDShape methods
|
||||
DIV, ///< Implements CalcDivShape methods
|
||||
CURL ///< Implements CalcCurlShape methods
|
||||
CURL, ///< Implements CalcCurlShape methods
|
||||
HESS ///< Implements CalcHessian & CalcDShape methods
|
||||
};
|
||||
|
||||
/** @brief Construct FiniteElement with given
|
||||
@@ -356,7 +357,7 @@ public:
|
||||
|
||||
/** @brief Returns the FiniteElement::DerivType of the element describing the
|
||||
spatial derivative method implemented, one of {NONE, GRAD,
|
||||
DIV, CURL}. */
|
||||
DIV, CURL, HESS}. */
|
||||
int GetDerivType() const { return deriv_type; }
|
||||
|
||||
/** @brief Returns the FiniteElement::DerivType of the element describing how
|
||||
@@ -394,7 +395,32 @@ public:
|
||||
/// Get a const reference to the nodes of the element
|
||||
const IntegrationRule & GetNodes() const { return Nodes; }
|
||||
|
||||
// virtual functions for finite elements on vector spaces
|
||||
/** @brief Evaluate the Hessians of all shape functions of a scalar finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
|
||||
part of the Hessian of one shape function.
|
||||
The order in 2D is {u_xx, u_xy, u_yy}.
|
||||
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
|
||||
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
|
||||
element in physical space at the given point @a ip. */
|
||||
/** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
|
||||
void CalcPhysHessian(ElementTransformation &Trans,
|
||||
DenseMatrix& Hessian) const;
|
||||
|
||||
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
|
||||
element in physical space at the given point @a ip. */
|
||||
/** The size (#dof) of @a Laplacian must be set in advance. */
|
||||
void CalcPhysLaplacian(ElementTransformation &Trans,
|
||||
Vector& Laplacian) const;
|
||||
|
||||
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
|
||||
element in physical space at the given point @a ip. */
|
||||
/** The size (#dof) of @a Laplacian must be set in advance. */
|
||||
void CalcPhysLinLaplacian(ElementTransformation &Trans,
|
||||
Vector& Laplacian) const;
|
||||
|
||||
/** @brief Evaluate the values of all shape functions of a *vector* finite
|
||||
element in reference space at the given point @a ip. */
|
||||
@@ -454,30 +480,6 @@ public:
|
||||
*/
|
||||
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
|
||||
|
||||
/** @brief Evaluate the Hessians of all shape functions of a scalar finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
|
||||
part of the Hessian of one shape function.
|
||||
The order in 2D is {u_xx, u_xy, u_yy}.
|
||||
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
|
||||
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
|
||||
virtual void CalcPhysHessian(ElementTransformation &Trans,
|
||||
DenseMatrix& Hessian) const;
|
||||
|
||||
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** The size (#dof) of @a Laplacian must be set in advance. */
|
||||
virtual void CalcPhysLaplacian(ElementTransformation &Trans,
|
||||
Vector& Laplacian) const;
|
||||
|
||||
virtual void CalcPhysLinLaplacian(ElementTransformation &Trans,
|
||||
Vector& Laplacian) const;
|
||||
|
||||
/** @brief Return the local interpolation matrix @a I (Dof x Dof) where the
|
||||
fine element is the image of the base geometry under the given
|
||||
transformation. */
|
||||
|
||||
+624
-11
@@ -349,10 +349,10 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip,
|
||||
d2sum[1] += ( hessian(o,1) = dsx*dsy*sz*weights(o) );
|
||||
d2sum[2] += ( hessian(o,2) = dsx*sy*dsz*weights(o) );
|
||||
|
||||
d2sum[3] += ( hessian(o,3) = sx*dsy*dsz*weights(o) );
|
||||
d2sum[3] += ( hessian(o,3) = sx*d2sy*sz*weights(o) );
|
||||
d2sum[4] += ( hessian(o,4) = sx*dsy*dsz*weights(o) );
|
||||
|
||||
d2sum[4] += ( hessian(o,4) = sx*sy*d2sz*weights(o) );
|
||||
d2sum[5] += ( hessian(o,5) = sx*d2sy*sz*weights(o) );
|
||||
d2sum[5] += ( hessian(o,5) = sx*sy*d2sz*weights(o) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -387,19 +387,632 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip,
|
||||
+ u[o]*sum*(2*dsum[0]*dsum[2] - d2sum[2]);
|
||||
|
||||
hessian(o,3) = hessian(o,3)*sum
|
||||
- du(o,1)*sum*dsum[2]
|
||||
- du(o,2)*sum*dsum[1]
|
||||
+ u[o]*sum*(2*dsum[1]*dsum[2] - d2sum[3]);
|
||||
- 2*du(o,1)*sum*dsum[1]
|
||||
+ u[o]*sum*(2*dsum[1]*dsum[1] - d2sum[3]);
|
||||
|
||||
hessian(o,4) = hessian(o,4)*sum
|
||||
- 2*du(o,2)*sum*dsum[2]
|
||||
+ u[o]*sum*(2*dsum[2]*dsum[2] - d2sum[4]);
|
||||
- du(o,1)*sum*dsum[2]
|
||||
- du(o,2)*sum*dsum[1]
|
||||
+ u[o]*sum*(2*dsum[1]*dsum[2] - d2sum[4]);
|
||||
|
||||
hessian(o,5) = hessian(o,5)*sum
|
||||
- 2*du(o,1)*sum*dsum[1]
|
||||
+ u[o]*sum*(2*dsum[1]*dsum[1] - d2sum[5]);
|
||||
|
||||
- 2*du(o,2)*sum*dsum[2]
|
||||
+ u[o]*sum*(2*dsum[2]*dsum[2] - d2sum[5]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NURBS_HDiv2DFiniteElement::SetOrder() const
|
||||
{
|
||||
orders[0] = kv[0]->GetOrder();
|
||||
orders[1] = kv[1]->GetOrder();
|
||||
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
|
||||
kv1[0] = kv[0]->DegreeElevate(1);
|
||||
kv1[1] = kv[1]->DegreeElevate(1);
|
||||
|
||||
shape_x.SetSize(orders[0]+1);
|
||||
shape_y.SetSize(orders[1]+1);
|
||||
|
||||
dshape_x.SetSize(orders[0]+1);
|
||||
dshape_y.SetSize(orders[1]+1);
|
||||
|
||||
d2shape_x.SetSize(orders[0]+1);
|
||||
d2shape_y.SetSize(orders[1]+1);
|
||||
|
||||
shape1_x.SetSize(orders[0]+2);
|
||||
shape1_y.SetSize(orders[1]+2);
|
||||
|
||||
dshape1_x.SetSize(orders[0]+2);
|
||||
dshape1_y.SetSize(orders[1]+2);
|
||||
|
||||
d2shape1_x.SetSize(orders[0]+2);
|
||||
d2shape1_y.SetSize(orders[1]+2);
|
||||
|
||||
order = max(orders[0]+1, orders[1]+1);
|
||||
dof = (orders[0] + 2)*(orders[1] + 1)
|
||||
+ (orders[1] + 1)*(orders[1] + 2);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof);
|
||||
weights.SetSize(dof);
|
||||
}
|
||||
|
||||
void NURBS_HDiv2DFiniteElement::CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
|
||||
|
||||
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
|
||||
|
||||
int o = 0;
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy = shape_y(j);
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
shape(o,0) = shape1_x(i)*sy;
|
||||
shape(o,1) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1 = shape1_y(j);
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
shape(o,0) = 0.0;
|
||||
shape(o,1) = shape_x(i)*sy1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HDiv2DFiniteElement::CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
CalcVShape(Trans.GetIntPoint(), shape);
|
||||
const DenseMatrix & J = Trans.Jacobian();
|
||||
MFEM_ASSERT(J.Width() == 2 && J.Height() == 2,
|
||||
"NURBS_HDiv2DFiniteElement cannot be embedded in "
|
||||
"3 dimensional spaces");
|
||||
for (int i=0; i<dof; i++)
|
||||
{
|
||||
real_t sx = shape(i, 0);
|
||||
real_t sy = shape(i, 1);
|
||||
shape(i, 0) = sx * J(0, 0) + sy * J(0, 1);
|
||||
shape(i, 1) = sx * J(1, 0) + sy * J(1, 1);
|
||||
}
|
||||
shape *= (1.0 / Trans.Weight());
|
||||
}
|
||||
|
||||
void NURBS_HDiv2DFiniteElement::CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const
|
||||
{
|
||||
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
|
||||
|
||||
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
|
||||
|
||||
int o = 0;
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy = shape_y(j);
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
divshape(o) = dshape1_x(i)*sy;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t dsy1 = dshape1_y(j);
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
divshape(o) = shape_x(i)*dsy1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NURBS_HDiv2DFiniteElement::~NURBS_HDiv2DFiniteElement()
|
||||
{
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
}
|
||||
|
||||
|
||||
void NURBS_HDiv3DFiniteElement::SetOrder() const
|
||||
{
|
||||
orders[0] = kv[0]->GetOrder();
|
||||
orders[1] = kv[1]->GetOrder();
|
||||
orders[2] = kv[2]->GetOrder();
|
||||
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
if (kv1[2]) { delete kv1[2]; }
|
||||
|
||||
kv1[0] = kv[0]->DegreeElevate(1);
|
||||
kv1[1] = kv[1]->DegreeElevate(1);
|
||||
kv1[2] = kv[2]->DegreeElevate(1);
|
||||
|
||||
shape_x.SetSize(orders[0]+1);
|
||||
shape_y.SetSize(orders[1]+1);
|
||||
shape_z.SetSize(orders[2]+1);
|
||||
|
||||
dshape_x.SetSize(orders[0]+1);
|
||||
dshape_y.SetSize(orders[1]+1);
|
||||
dshape_z.SetSize(orders[2]+1);
|
||||
|
||||
d2shape_x.SetSize(orders[0]+1);
|
||||
d2shape_y.SetSize(orders[1]+1);
|
||||
d2shape_z.SetSize(orders[2]+1);
|
||||
|
||||
shape1_x.SetSize(orders[0]+2);
|
||||
shape1_y.SetSize(orders[1]+2);
|
||||
shape1_z.SetSize(orders[2]+2);
|
||||
|
||||
dshape1_x.SetSize(orders[0]+2);
|
||||
dshape1_y.SetSize(orders[1]+2);
|
||||
dshape1_z.SetSize(orders[2]+2);
|
||||
|
||||
d2shape1_x.SetSize(orders[0]+2);
|
||||
d2shape1_y.SetSize(orders[1]+2);
|
||||
d2shape1_z.SetSize(orders[2]+2);
|
||||
|
||||
order = max(orders[0]+1, max( orders[1]+1, orders[2]+1));
|
||||
dof = (orders[0] + 2)*(orders[1] + 1)*(orders[2] + 1) +
|
||||
(orders[0] + 1)*(orders[1] + 2)*(orders[2] + 1) +
|
||||
(orders[0] + 1)*(orders[1] + 1)*(orders[2] + 2);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof);
|
||||
weights.SetSize(dof);
|
||||
}
|
||||
|
||||
void NURBS_HDiv3DFiniteElement::CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
|
||||
kv[2]->CalcShape(shape_z, ijk[2], ip.z);
|
||||
|
||||
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
|
||||
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
|
||||
|
||||
shape = 0.0;
|
||||
int o = 0;
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_sz = shape_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
shape(o,0) = shape1_x(i)*sy_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1_sz = shape1_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
shape(o,1) = shape_x(i)*sy1_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t sz1 = shape1_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_sz1 = shape_y(j)*sz1;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
shape(o,2) = shape_x(i)*sy_sz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HDiv3DFiniteElement::CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
CalcVShape(Trans.GetIntPoint(), shape);
|
||||
const DenseMatrix & J = Trans.Jacobian();
|
||||
MFEM_ASSERT(J.Width() == 3 && J.Height() == 3,
|
||||
"RT_R2D_FiniteElement cannot be embedded in "
|
||||
"3 dimensional spaces");
|
||||
for (int i=0; i<dof; i++)
|
||||
{
|
||||
real_t sx = shape(i, 0);
|
||||
real_t sy = shape(i, 1);
|
||||
real_t sz = shape(i, 2);
|
||||
shape(i, 0) = sx * J(0, 0) + sy * J(0, 1) + sz * J(0, 2);
|
||||
shape(i, 1) = sx * J(1, 0) + sy * J(1, 1) + sz * J(1, 2);
|
||||
shape(i, 2) = sx * J(2, 0) + sy * J(2, 1) + sz * J(2, 2);
|
||||
}
|
||||
shape *= (1.0 / Trans.Weight());
|
||||
}
|
||||
|
||||
void NURBS_HDiv3DFiniteElement::CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const
|
||||
{
|
||||
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
|
||||
kv[2]->CalcShape ( shape_z, ijk[2], ip.z);
|
||||
|
||||
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
|
||||
kv1[2]->CalcDShape(dshape1_z, ijk[2], ip.z);
|
||||
|
||||
int o = 0;
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_sz = shape_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
divshape(o) = dshape1_x(i)*sy_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t dy1_sz = dshape1_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
divshape(o) = shape_x(i)*dy1_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t dz1 = dshape1_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_dz1 = shape_y(j)*dz1;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
divshape(o) = shape_x(i)*sy_dz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NURBS_HDiv3DFiniteElement::~NURBS_HDiv3DFiniteElement()
|
||||
{
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
if (kv1[2]) { delete kv1[2]; }
|
||||
}
|
||||
|
||||
void NURBS_HCurl2DFiniteElement::SetOrder() const
|
||||
{
|
||||
orders[0] = kv[0]->GetOrder();
|
||||
orders[1] = kv[1]->GetOrder();
|
||||
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
|
||||
kv1[0] = kv[0]->DegreeElevate(1);
|
||||
kv1[1] = kv[1]->DegreeElevate(1);
|
||||
|
||||
shape_x.SetSize(orders[0]+1);
|
||||
shape_y.SetSize(orders[1]+1);
|
||||
|
||||
dshape_x.SetSize(orders[0]+1);
|
||||
dshape_y.SetSize(orders[1]+1);
|
||||
|
||||
d2shape_x.SetSize(orders[0]+1);
|
||||
d2shape_y.SetSize(orders[1]+1);
|
||||
|
||||
shape1_x.SetSize(orders[0]+2);
|
||||
shape1_y.SetSize(orders[1]+2);
|
||||
|
||||
dshape1_x.SetSize(orders[0]+2);
|
||||
dshape1_y.SetSize(orders[1]+2);
|
||||
|
||||
d2shape1_x.SetSize(orders[0]+2);
|
||||
d2shape1_y.SetSize(orders[1]+2);
|
||||
|
||||
order = max(orders[0]+1, orders[1]+1);
|
||||
dof = (orders[0] + 1)*(orders[1] + 2)
|
||||
+ (orders[1] + 2)*(orders[1] + 1);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof);
|
||||
weights.SetSize(dof);
|
||||
}
|
||||
|
||||
void NURBS_HCurl2DFiniteElement::CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
|
||||
|
||||
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
|
||||
|
||||
int o = 0;
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1 = shape1_y(j);
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
shape(o,0) = shape_x(i)*sy1;
|
||||
shape(o,1) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy = shape_y(j);
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
shape(o,0) = 0.0;
|
||||
shape(o,1) = shape1_x(i)*sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HCurl2DFiniteElement::CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
CalcVShape(Trans.GetIntPoint(), shape);
|
||||
const DenseMatrix & JI = Trans.InverseJacobian();
|
||||
MFEM_ASSERT(JI.Width() == 2 && JI.Height() == 2,
|
||||
"NURBS_HCurl2DFiniteElement cannot be embedded in "
|
||||
"3 dimensional spaces");
|
||||
for (int i=0; i<dof; i++)
|
||||
{
|
||||
real_t sx = shape(i, 0);
|
||||
real_t sy = shape(i, 1);
|
||||
shape(i, 0) = sx * JI(0, 0) + sy * JI(1, 0);
|
||||
shape(i, 1) = sx * JI(0, 1) + sy * JI(1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HCurl2DFiniteElement::CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const
|
||||
{
|
||||
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
|
||||
|
||||
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
|
||||
|
||||
int o = 0;
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t dsy1 = dshape1_y(j);
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
curl_shape(o,0) = -shape_x(i)*dsy1;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy = shape_y(j);
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
curl_shape(o,0) = dshape1_x(i)*sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NURBS_HCurl2DFiniteElement::~NURBS_HCurl2DFiniteElement()
|
||||
{
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
}
|
||||
|
||||
|
||||
void NURBS_HCurl3DFiniteElement::SetOrder() const
|
||||
{
|
||||
orders[0] = kv[0]->GetOrder();
|
||||
orders[1] = kv[1]->GetOrder();
|
||||
orders[2] = kv[2]->GetOrder();
|
||||
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
if (kv1[2]) { delete kv1[2]; }
|
||||
|
||||
kv1[0] = kv[0]->DegreeElevate(1);
|
||||
kv1[1] = kv[1]->DegreeElevate(1);
|
||||
kv1[2] = kv[2]->DegreeElevate(1);
|
||||
|
||||
shape_x.SetSize(orders[0]+1);
|
||||
shape_y.SetSize(orders[1]+1);
|
||||
shape_z.SetSize(orders[2]+1);
|
||||
|
||||
dshape_x.SetSize(orders[0]+1);
|
||||
dshape_y.SetSize(orders[1]+1);
|
||||
dshape_z.SetSize(orders[2]+1);
|
||||
|
||||
d2shape_x.SetSize(orders[0]+1);
|
||||
d2shape_y.SetSize(orders[1]+1);
|
||||
d2shape_z.SetSize(orders[2]+1);
|
||||
|
||||
shape1_x.SetSize(orders[0]+2);
|
||||
shape1_y.SetSize(orders[1]+2);
|
||||
shape1_z.SetSize(orders[2]+2);
|
||||
|
||||
dshape1_x.SetSize(orders[0]+2);
|
||||
dshape1_y.SetSize(orders[1]+2);
|
||||
dshape1_z.SetSize(orders[2]+2);
|
||||
|
||||
d2shape1_x.SetSize(orders[0]+2);
|
||||
d2shape1_y.SetSize(orders[1]+2);
|
||||
d2shape1_z.SetSize(orders[2]+2);
|
||||
|
||||
order = max(orders[0]+1, max( orders[1]+1, orders[2]+1));
|
||||
dof = (orders[0] + 1)*(orders[1] + 2)*(orders[2] + 2) +
|
||||
(orders[0] + 2)*(orders[1] + 1)*(orders[2] + 2) +
|
||||
(orders[0] + 2)*(orders[1] + 2)*(orders[2] + 1);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof);
|
||||
weights.SetSize(dof);
|
||||
}
|
||||
|
||||
void NURBS_HCurl3DFiniteElement::CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
|
||||
kv[2]->CalcShape(shape_z, ijk[2], ip.z);
|
||||
|
||||
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
|
||||
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
|
||||
|
||||
shape = 0.0;
|
||||
int o = 0;
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t sz1 = shape1_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1_sz1 = shape1_y(j)*sz1;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
shape(o,0) = shape_x(i)*sy1_sz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t sz1 = shape1_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_sz1 = shape_y(j)*sz1;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
shape(o,1) = shape1_x(i)*sy_sz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1_sz = shape1_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
shape(o,2) = shape1_x(i)*sy1_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HCurl3DFiniteElement::CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
CalcVShape(Trans.GetIntPoint(), shape);
|
||||
const DenseMatrix & JI = Trans.InverseJacobian();
|
||||
MFEM_ASSERT(JI.Width() == 3 && JI.Height() == 3,
|
||||
"NURBS_HCurl3DFiniteElement must be in a"
|
||||
"3 dimensional spaces");
|
||||
for (int i=0; i<dof; i++)
|
||||
{
|
||||
real_t sx = shape(i, 0);
|
||||
real_t sy = shape(i, 1);
|
||||
real_t sz = shape(i, 2);
|
||||
shape(i, 0) = sx * JI(0, 0) + sy * JI(1, 0) + sz * JI(2, 0);
|
||||
shape(i, 1) = sx * JI(0, 1) + sy * JI(1, 1) + sz * JI(2, 1);
|
||||
shape(i, 2) = sx * JI(0, 2) + sy * JI(1, 2) + sz * JI(2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HCurl3DFiniteElement::CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const
|
||||
{
|
||||
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
|
||||
kv[2]->CalcShape ( shape_z, ijk[2], ip.z);
|
||||
|
||||
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
|
||||
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
|
||||
|
||||
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
|
||||
kv1[2]->CalcDShape(dshape1_z, ijk[2], ip.z);
|
||||
|
||||
int o = 0;
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t sz1 = shape1_z(k), dsz1 = dshape1_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1_dsz1 = shape1_y(j)*dsz1,
|
||||
dsy1_sz1 = dshape1_y(j)*sz1;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
curl_shape(o,0) = 0.0;
|
||||
curl_shape(o,1) = shape_x(i)*sy1_dsz1;
|
||||
curl_shape(o,2) = -shape_x(i)*dsy1_sz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t sz1 = shape1_z(k), dsz1 = dshape1_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_dsz1 = shape_y(j)*dsz1,
|
||||
sy_sz1 = shape_y(j)*sz1;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
curl_shape(o,0) = -shape1_x(i)*sy_dsz1;
|
||||
curl_shape(o,1) = 0.0;
|
||||
curl_shape(o,2) = dshape1_x(i)*sy_sz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1_sz = shape1_y(j)*sz,
|
||||
dsy1_sz = dshape1_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
curl_shape(o,0) = shape1_x(i)*dsy1_sz;
|
||||
curl_shape(o,1) = -dshape1_x(i)*sy1_sz;
|
||||
curl_shape(o,2) = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NURBS_HCurl3DFiniteElement::~NURBS_HCurl3DFiniteElement()
|
||||
{
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
if (kv1[2]) { delete kv1[2]; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+380
-23
@@ -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();
|
||||
|
||||
+210
-74
@@ -12,6 +12,8 @@
|
||||
// Implementation of GridFunction
|
||||
|
||||
#include "gridfunc.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "bilinearform.hpp"
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "../mesh/nurbs.hpp"
|
||||
#include "../general/text.hpp"
|
||||
@@ -39,7 +41,7 @@ GridFunction::GridFunction(Mesh *m, std::istream &input)
|
||||
UseDevice(true);
|
||||
|
||||
fes = new FiniteElementSpace;
|
||||
fec = fes->Load(m, input);
|
||||
fec_owned = fes->Load(m, input);
|
||||
|
||||
skip_comment_lines(input, '#');
|
||||
istream::int_type next_char = input.peek();
|
||||
@@ -81,10 +83,10 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
|
||||
int vdim, ordering;
|
||||
|
||||
fes = gf_array[0]->FESpace();
|
||||
fec = FiniteElementCollection::New(fes->FEColl()->Name());
|
||||
fec_owned = FiniteElementCollection::New(fes->FEColl()->Name());
|
||||
vdim = fes->GetVDim();
|
||||
ordering = fes->GetOrdering();
|
||||
fes = new FiniteElementSpace(m, fec, vdim, ordering);
|
||||
fes = new FiniteElementSpace(m, fec_owned, vdim, ordering);
|
||||
SetSize(fes->GetVSize());
|
||||
|
||||
if (m->NURBSext)
|
||||
@@ -153,11 +155,11 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
|
||||
|
||||
void GridFunction::Destroy()
|
||||
{
|
||||
if (fec)
|
||||
if (fec_owned)
|
||||
{
|
||||
delete fes;
|
||||
delete fec;
|
||||
fec = NULL;
|
||||
delete fec_owned;
|
||||
fec_owned = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,10 +327,9 @@ int GridFunction::VectorDim() const
|
||||
const FiniteElement *fe;
|
||||
if (!fes->GetNE())
|
||||
{
|
||||
const FiniteElementCollection *fe_coll = fes->FEColl();
|
||||
static const Geometry::Type geoms[3] =
|
||||
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
|
||||
fe = fe_coll->
|
||||
fe = fes->FEColl()->
|
||||
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
}
|
||||
else
|
||||
@@ -350,7 +351,8 @@ int GridFunction::CurlDim() const
|
||||
{
|
||||
static const Geometry::Type geoms[3] =
|
||||
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
|
||||
fe = fec->FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
fe = fes->FEColl()->
|
||||
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1321,9 +1323,9 @@ void GridFunction::ProjectVectorFieldOn(GridFunction &vec_field, int comp)
|
||||
}
|
||||
}
|
||||
|
||||
void GridFunction::AccumulateAndCountDerivativeValues(int comp, int der_comp,
|
||||
GridFunction &der,
|
||||
Array<int> &zones_per_dof)
|
||||
void GridFunction::AccumulateAndCountDerivativeValues(
|
||||
int comp, int der_comp, GridFunction &der,
|
||||
Array<int> &zones_per_dof) const
|
||||
{
|
||||
FiniteElementSpace * der_fes = der.FESpace();
|
||||
ElementTransformation * transf;
|
||||
@@ -1374,7 +1376,8 @@ void GridFunction::AccumulateAndCountDerivativeValues(int comp, int der_comp,
|
||||
}
|
||||
}
|
||||
|
||||
void GridFunction::GetDerivative(int comp, int der_comp, GridFunction &der)
|
||||
void GridFunction::GetDerivative(int comp, int der_comp,
|
||||
GridFunction &der) const
|
||||
{
|
||||
Array<int> overlap;
|
||||
AccumulateAndCountDerivativeValues(comp, der_comp, der, overlap);
|
||||
@@ -2061,41 +2064,37 @@ void GridFunction::AccumulateAndCountBdrValues(
|
||||
Coefficient *coeff[], VectorCoefficient *vcoeff, const Array<int> &attr,
|
||||
Array<int> &values_counter)
|
||||
{
|
||||
int i, j, fdof, d, ind, vdim;
|
||||
real_t val;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *transf;
|
||||
Array<int> vdofs;
|
||||
Vector vc;
|
||||
|
||||
values_counter.SetSize(Size());
|
||||
values_counter = 0;
|
||||
|
||||
vdim = fes->GetVDim();
|
||||
|
||||
const int vdim = fes->GetVDim();
|
||||
HostReadWrite();
|
||||
|
||||
for (i = 0; i < fes->GetNBE(); i++)
|
||||
for (int i = 0; i < fes->GetNBE(); i++)
|
||||
{
|
||||
if (attr[fes->GetBdrAttribute(i) - 1] == 0) { continue; }
|
||||
|
||||
fe = fes->GetBE(i);
|
||||
fdof = fe->GetDof();
|
||||
transf = fes->GetBdrElementTransformation(i);
|
||||
const FiniteElement *fe = fes->GetBE(i);
|
||||
const int fdof = fe->GetDof();
|
||||
ElementTransformation *transf = fes->GetBdrElementTransformation(i);
|
||||
const IntegrationRule &ir = fe->GetNodes();
|
||||
fes->GetBdrElementVDofs(i, vdofs);
|
||||
|
||||
for (j = 0; j < fdof; j++)
|
||||
for (int j = 0; j < fdof; j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
if (vcoeff) { vcoeff->Eval(vc, *transf, ip); }
|
||||
for (d = 0; d < vdim; d++)
|
||||
for (int d = 0; d < vdim; d++)
|
||||
{
|
||||
if (!vcoeff && !coeff[d]) { continue; }
|
||||
|
||||
val = vcoeff ? vc(d) : coeff[d]->Eval(*transf, ip);
|
||||
if ( (ind = vdofs[fdof*d+j]) < 0 )
|
||||
real_t val = vcoeff ? vc(d) : coeff[d]->Eval(*transf, ip);
|
||||
int ind = vdofs[fdof*d+j];
|
||||
if ( ind < 0 )
|
||||
{
|
||||
val = -val, ind = -1-ind;
|
||||
}
|
||||
@@ -2117,10 +2116,11 @@ void GridFunction::AccumulateAndCountBdrValues(
|
||||
// iff A_ij != 0. It is sufficient to resolve just the first level of
|
||||
// dependency, since A is a projection matrix: A^n = A due to cR.cP = I.
|
||||
// Cases like these arise in 3D when boundary edges are constrained by
|
||||
// (depend on) internal faces/elements. We use the virtual method
|
||||
// GetBoundaryClosure from NCMesh to resolve the dependencies.
|
||||
|
||||
if (fes->Nonconforming() && fes->GetMesh()->Dimension() == 3)
|
||||
// (depend on) internal faces/elements, or for internal boundaries in 2 or
|
||||
// 3D. We use the virtual method GetBoundaryClosure from NCMesh to resolve
|
||||
// the dependencies.
|
||||
if (fes->Nonconforming() && (fes->GetMesh()->Dimension() == 2 ||
|
||||
fes->GetMesh()->Dimension() == 3))
|
||||
{
|
||||
Vector vals;
|
||||
Mesh *mesh = fes->GetMesh();
|
||||
@@ -2128,26 +2128,19 @@ void GridFunction::AccumulateAndCountBdrValues(
|
||||
Array<int> bdr_edges, bdr_vertices, bdr_faces;
|
||||
ncmesh->GetBoundaryClosure(attr, bdr_vertices, bdr_edges, bdr_faces);
|
||||
|
||||
for (i = 0; i < bdr_edges.Size(); i++)
|
||||
auto mark_dofs = [&](ElementTransformation &transf, const FiniteElement &fe)
|
||||
{
|
||||
int edge = bdr_edges[i];
|
||||
fes->GetEdgeVDofs(edge, vdofs);
|
||||
if (vdofs.Size() == 0) { continue; }
|
||||
|
||||
transf = mesh->GetEdgeTransformation(edge);
|
||||
transf->Attribute = -1; // TODO: set the boundary attribute
|
||||
fe = fes->GetEdgeElement(edge);
|
||||
if (!vcoeff)
|
||||
{
|
||||
vals.SetSize(fe->GetDof());
|
||||
for (d = 0; d < vdim; d++)
|
||||
vals.SetSize(fe.GetDof());
|
||||
for (int d = 0; d < vdim; d++)
|
||||
{
|
||||
if (!coeff[d]) { continue; }
|
||||
|
||||
fe->Project(*coeff[d], *transf, vals);
|
||||
fe.Project(*coeff[d], transf, vals);
|
||||
for (int k = 0; k < vals.Size(); k++)
|
||||
{
|
||||
ind = vdofs[d*vals.Size()+k];
|
||||
const int ind = vdofs[d*vals.Size()+k];
|
||||
if (++values_counter[ind] == 1)
|
||||
{
|
||||
(*this)(ind) = vals(k);
|
||||
@@ -2161,11 +2154,11 @@ void GridFunction::AccumulateAndCountBdrValues(
|
||||
}
|
||||
else // vcoeff != NULL
|
||||
{
|
||||
vals.SetSize(vdim*fe->GetDof());
|
||||
fe->Project(*vcoeff, *transf, vals);
|
||||
vals.SetSize(vdim*fe.GetDof());
|
||||
fe.Project(*vcoeff, transf, vals);
|
||||
for (int k = 0; k < vals.Size(); k++)
|
||||
{
|
||||
ind = vdofs[k];
|
||||
const int ind = vdofs[k];
|
||||
if (++values_counter[ind] == 1)
|
||||
{
|
||||
(*this)(ind) = vals(k);
|
||||
@@ -2176,6 +2169,26 @@ void GridFunction::AccumulateAndCountBdrValues(
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (auto edge : bdr_edges)
|
||||
{
|
||||
fes->GetEdgeVDofs(edge, vdofs);
|
||||
if (vdofs.Size() == 0) { continue; }
|
||||
|
||||
ElementTransformation *transf = mesh->GetEdgeTransformation(edge);
|
||||
const FiniteElement *fe = fes->GetEdgeElement(edge);
|
||||
mark_dofs(*transf, *fe);
|
||||
}
|
||||
|
||||
for (auto face : bdr_faces)
|
||||
{
|
||||
fes->GetFaceVDofs(face, vdofs);
|
||||
if (vdofs.Size() == 0) { continue; }
|
||||
|
||||
ElementTransformation *transf = mesh->GetFaceTransformation(face);
|
||||
const FiniteElement *fe = fes->GetFaceElement(face);
|
||||
mark_dofs(*transf, *fe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2228,26 +2241,37 @@ void GridFunction::AccumulateAndCountBdrTangentValues(
|
||||
accumulate_dofs(dofs, lvec, *this, values_counter);
|
||||
}
|
||||
|
||||
if (fes->Nonconforming() && fes->GetMesh()->Dimension() == 3)
|
||||
if (fes->Nonconforming() && (fes->GetMesh()->Dimension() == 2 ||
|
||||
fes->GetMesh()->Dimension() == 3))
|
||||
{
|
||||
Mesh *mesh = fes->GetMesh();
|
||||
NCMesh *ncmesh = mesh->ncmesh;
|
||||
Array<int> bdr_edges, bdr_vertices, bdr_faces;
|
||||
ncmesh->GetBoundaryClosure(bdr_attr, bdr_vertices, bdr_edges, bdr_faces);
|
||||
|
||||
for (int i = 0; i < bdr_edges.Size(); i++)
|
||||
for (auto edge : bdr_edges)
|
||||
{
|
||||
int edge = bdr_edges[i];
|
||||
fes->GetEdgeDofs(edge, dofs);
|
||||
if (dofs.Size() == 0) { continue; }
|
||||
|
||||
T = mesh->GetEdgeTransformation(edge);
|
||||
T->Attribute = -1; // TODO: set the boundary attribute
|
||||
fe = fes->GetEdgeElement(edge);
|
||||
lvec.SetSize(fe->GetDof());
|
||||
fe->Project(vcoeff, *T, lvec);
|
||||
accumulate_dofs(dofs, lvec, *this, values_counter);
|
||||
}
|
||||
|
||||
for (auto face : bdr_faces)
|
||||
{
|
||||
fes->GetFaceDofs(face, dofs);
|
||||
if (dofs.Size() == 0) { continue; }
|
||||
|
||||
T = mesh->GetFaceTransformation(face);
|
||||
fe = fes->GetFaceElement(face);
|
||||
lvec.SetSize(fe->GetDof());
|
||||
fe->Project(vcoeff, *T, lvec);
|
||||
accumulate_dofs(dofs, lvec, *this, values_counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2350,19 +2374,48 @@ void GridFunction::ProjectCoefficient(Coefficient &coeff)
|
||||
|
||||
if (delta_c == NULL)
|
||||
{
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
if (fes->GetNURBSext() == NULL)
|
||||
{
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
|
||||
if (doftrans)
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
doftrans->TransformPrimal(vals);
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformPrimal(vals);
|
||||
}
|
||||
SetSubVector(vdofs, vals);
|
||||
}
|
||||
SetSubVector(vdofs, vals);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Define and assemble linear form
|
||||
LinearForm b(fes);
|
||||
b.AddDomainIntegrator(new DomainLFIntegrator(coeff));
|
||||
b.Assemble();
|
||||
|
||||
// Define and assemble bilinear form
|
||||
BilinearForm a(fes);
|
||||
a.AddDomainIntegrator(new MassIntegrator());
|
||||
a.Assemble();
|
||||
|
||||
// Set solver and preconditioner
|
||||
SparseMatrix A(a.SpMat());
|
||||
GSSmoother prec(A);
|
||||
CGSolver cg;
|
||||
cg.SetOperator(A);
|
||||
cg.SetPreconditioner(prec);
|
||||
cg.SetRelTol(1e-12);
|
||||
cg.SetMaxIter(1000);
|
||||
cg.SetPrintLevel(0);
|
||||
|
||||
// Solve and get solution
|
||||
*this = 0.0;
|
||||
cg.Mult(b,*this);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2403,22 +2456,54 @@ void GridFunction::ProjectCoefficient(
|
||||
|
||||
void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff)
|
||||
{
|
||||
int i;
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
|
||||
DofTransformation * doftrans = NULL;
|
||||
|
||||
for (i = 0; i < fes->GetNE(); i++)
|
||||
if (fes->GetNURBSext() == NULL)
|
||||
{
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
|
||||
if (doftrans)
|
||||
|
||||
int i;
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
|
||||
DofTransformation * doftrans = NULL;
|
||||
|
||||
for (i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
doftrans->TransformPrimal(vals);
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformPrimal(vals);
|
||||
}
|
||||
SetSubVector(vdofs, vals);
|
||||
}
|
||||
SetSubVector(vdofs, vals);
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Define and assemble linear form
|
||||
LinearForm b(fes);
|
||||
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(vcoeff));
|
||||
b.Assemble();
|
||||
|
||||
// Define and assemble bilinear form
|
||||
BilinearForm a(fes);
|
||||
a.AddDomainIntegrator(new VectorFEMassIntegrator());
|
||||
a.Assemble();
|
||||
|
||||
// Set solver and preconditioner
|
||||
SparseMatrix A(a.SpMat());
|
||||
GSSmoother prec(A);
|
||||
CGSolver cg;
|
||||
cg.SetOperator(A);
|
||||
cg.SetPreconditioner(prec);
|
||||
cg.SetRelTol(1e-12);
|
||||
cg.SetMaxIter(1000);
|
||||
cg.SetPrintLevel(0);
|
||||
|
||||
// Solve and get solution
|
||||
*this = 0.0;
|
||||
cg.Mult(b,*this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2966,6 +3051,57 @@ real_t GridFunction::ComputeDivError(
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
}
|
||||
|
||||
real_t GridFunction::ComputeLaplaceError(
|
||||
Coefficient *exlap, const IntegrationRule *irs[]) const
|
||||
{
|
||||
real_t error = 0.0, a;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *Tr;
|
||||
Array<int> dofs;
|
||||
int intorder, fdof;
|
||||
Vector laplace;
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
laplace.SetSize(fdof);
|
||||
fe = fes->GetFE(i);
|
||||
Tr = fes->GetElementTransformation(i);
|
||||
intorder = 2*fe->GetOrder() + 3;
|
||||
const IntegrationRule *ir;
|
||||
if (irs)
|
||||
{
|
||||
ir = irs[fe->GetGeomType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
fes->GetElementDofs(i, dofs);
|
||||
fdof = fe->GetDof();
|
||||
laplace.SetSize(fdof);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
Tr->SetIntPoint(&ip);
|
||||
fe->CalcPhysLaplacian(*Tr, laplace);
|
||||
a = 0;
|
||||
for (int k = 0; k < fdof; k++)
|
||||
if (dofs[k] >= 0)
|
||||
{
|
||||
a += (*this)(dofs[k]) * laplace(k);
|
||||
}
|
||||
else
|
||||
{
|
||||
a -= (*this)(-1-dofs[k]) * laplace(k);
|
||||
}
|
||||
a -= exlap->Eval(*Tr, ip);
|
||||
error += ip.weight * Tr->Weight() * a * a;
|
||||
}
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
}
|
||||
|
||||
real_t GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
Coefficient *ell_coeff,
|
||||
class JumpScaling jump_scaling,
|
||||
@@ -3904,7 +4040,7 @@ void GridFunction::LegacyNCReorder()
|
||||
mesh->GetEdgeVertices(i, ev);
|
||||
if (old_vertex[ev[0]] > old_vertex[ev[1]])
|
||||
{
|
||||
const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, -1);
|
||||
const int *ind = fes->FEColl()->DofOrderForOrientation(Geometry::SEGMENT, -1);
|
||||
|
||||
fes->GetEdgeInteriorDofs(i, dofs);
|
||||
for (int k = 0; k < dofs.Size(); k++)
|
||||
|
||||
+21
-15
@@ -30,14 +30,14 @@ namespace mfem
|
||||
class GridFunction : public Vector
|
||||
{
|
||||
protected:
|
||||
/// FE space on which the grid function lives. Owned if #fec is not NULL.
|
||||
/// FE space on which the grid function lives. Owned if #fec_owned is not NULL.
|
||||
FiniteElementSpace *fes;
|
||||
|
||||
/** @brief Used when the grid function is read from a file. It can also be
|
||||
set explicitly, see MakeOwner().
|
||||
|
||||
If not NULL, this pointer is owned by the GridFunction. */
|
||||
FiniteElementCollection *fec;
|
||||
FiniteElementCollection *fec_owned;
|
||||
|
||||
long fes_sequence; // see FiniteElementSpace::sequence, Mesh::sequence
|
||||
|
||||
@@ -72,16 +72,16 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
GridFunction() { fes = NULL; fec = NULL; fes_sequence = 0; UseDevice(true); }
|
||||
GridFunction() { fes = NULL; fec_owned = NULL; fes_sequence = 0; UseDevice(true); }
|
||||
|
||||
/// Copy constructor. The internal true-dof vector #t_vec is not copied.
|
||||
GridFunction(const GridFunction &orig)
|
||||
: Vector(orig), fes(orig.fes), fec(NULL), fes_sequence(orig.fes_sequence)
|
||||
: Vector(orig), fes(orig.fes), fec_owned(NULL), fes_sequence(orig.fes_sequence)
|
||||
{ UseDevice(true); }
|
||||
|
||||
/// Construct a GridFunction associated with the FiniteElementSpace @a *f.
|
||||
GridFunction(FiniteElementSpace *f) : Vector(f->GetVSize())
|
||||
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
|
||||
/// Construct a GridFunction using previously allocated array @a data.
|
||||
/** The GridFunction does not assume ownership of @a data which is assumed to
|
||||
@@ -91,13 +91,13 @@ public:
|
||||
*/
|
||||
GridFunction(FiniteElementSpace *f, real_t *data)
|
||||
: Vector(data, f->GetVSize())
|
||||
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
|
||||
/** @brief Construct a GridFunction using previously allocated Vector @a base
|
||||
starting at the given offset, @a base_offset. */
|
||||
GridFunction(FiniteElementSpace *f, Vector &base, int base_offset = 0)
|
||||
: Vector(base, base_offset, f->GetVSize())
|
||||
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
|
||||
/// Construct a GridFunction on the given Mesh, using the data from @a input.
|
||||
/** The content of @a input should be in the format created by the method
|
||||
@@ -116,12 +116,12 @@ public:
|
||||
GridFunction &operator=(const GridFunction &rhs)
|
||||
{ return operator=((const Vector &)rhs); }
|
||||
|
||||
/// Make the GridFunction the owner of #fec and #fes.
|
||||
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec
|
||||
/// Make the GridFunction the owner of #fec_owned and #fes.
|
||||
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec_owned
|
||||
and #fes is taken away. */
|
||||
void MakeOwner(FiniteElementCollection *fec_) { fec = fec_; }
|
||||
void MakeOwner(FiniteElementCollection *fec_) { fec_owned = fec_; }
|
||||
|
||||
FiniteElementCollection *OwnFEC() { return fec; }
|
||||
FiniteElementCollection *OwnFEC() { return fec_owned; }
|
||||
|
||||
int VectorDim() const;
|
||||
int CurlDim() const;
|
||||
@@ -321,7 +321,7 @@ public:
|
||||
@param[out] der The resulting derivative (scalar function). The
|
||||
FiniteElementSpace of this function must be set
|
||||
before the call. */
|
||||
void GetDerivative(int comp, int der_comp, GridFunction &der);
|
||||
void GetDerivative(int comp, int der_comp, GridFunction &der) const;
|
||||
|
||||
real_t GetDivergence(ElementTransformation &tr) const;
|
||||
|
||||
@@ -387,7 +387,8 @@ public:
|
||||
/** @brief Project @a coeff Coefficient to @a this GridFunction. The
|
||||
projection computation depends on the choice of the FiniteElementSpace
|
||||
#fes. Note that this is usually interpolation at the degrees of freedom
|
||||
in each element (not L2 projection). */
|
||||
in each element (not L2 projection). For NURBS spaces these degrees of
|
||||
freedom are not available and L2 projection is resorted to as fallback. */
|
||||
virtual void ProjectCoefficient(Coefficient &coeff);
|
||||
|
||||
/** @brief Project @a coeff Coefficient to @a this GridFunction, using one
|
||||
@@ -398,7 +399,8 @@ public:
|
||||
/** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction. The
|
||||
projection computation depends on the choice of the FiniteElementSpace
|
||||
#fes. Note that this is usually interpolation at the degrees of freedom
|
||||
in each element (not L2 projection).*/
|
||||
in each element (not L2 projection). For NURBS spaces these degrees of
|
||||
freedom are not available and L2 projection is resorted to as fallback. */
|
||||
void ProjectCoefficient(VectorCoefficient &vcoeff);
|
||||
|
||||
/** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction, using
|
||||
@@ -443,7 +445,7 @@ protected:
|
||||
GetDerivative() method; see its documentation. */
|
||||
void AccumulateAndCountDerivativeValues(int comp, int der_comp,
|
||||
GridFunction &der,
|
||||
Array<int> &zones_per_dof);
|
||||
Array<int> &zones_per_dof) const;
|
||||
|
||||
void AccumulateAndCountBdrValues(Coefficient *coeff[],
|
||||
VectorCoefficient *vcoeff,
|
||||
@@ -531,6 +533,10 @@ public:
|
||||
virtual real_t ComputeDivError(Coefficient *exdiv,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns ||lap u_ex - lap u_h||_L2 for H1 elements
|
||||
virtual real_t ComputeLaplaceError(Coefficient *exlap,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns the Face Jumps error for L2 elements. The error can be weighted
|
||||
/// by a constant nu, by nu/h, or nu*p^2/h, depending on the value of
|
||||
/// @a jump_scaling.
|
||||
|
||||
@@ -1393,8 +1393,10 @@ GSOPGSLIB::~GSOPGSLIB()
|
||||
void GSOPGSLIB::UpdateIdentifiers(const Array<long long> &ids)
|
||||
{
|
||||
long long minval = ids.Min();
|
||||
#ifdef MFEM_USE_MPI
|
||||
MPI_Allreduce(MPI_IN_PLACE, &minval, 1, MPI_LONG_LONG_INT,
|
||||
MPI_MIN, gsl_comm->c);
|
||||
#endif
|
||||
MFEM_VERIFY(minval >= 0, "Unique identifier cannot be negative.");
|
||||
if (gsl_data != NULL) { gslib_gs_free(gsl_data); }
|
||||
num_ids = ids.Size();
|
||||
|
||||
+44
-44
@@ -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.
|
||||
|
||||
@@ -123,6 +123,35 @@ void DomainLFGradIntegrator::AssembleDeltaElementVect(
|
||||
dshape.Mult(Qvec, elvect);
|
||||
}
|
||||
|
||||
void DomainLFLaplaceIntegrator::AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
Vector &elvect)
|
||||
{
|
||||
int dof = el.GetDof();
|
||||
|
||||
laplace.SetSize(dof); // vector of size dof
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = NULL;//IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
ir = &IntRules.Get(el.GetGeomType(), oa * el.GetOrder() + ob + 4);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
Tr.SetIntPoint (&ip);
|
||||
real_t val = Tr.Weight() * Q.Eval(Tr, ip) * alpha;
|
||||
|
||||
el.CalcPhysLaplacian(Tr, laplace);
|
||||
|
||||
add(elvect, ip.weight * val, laplace, elvect);
|
||||
}
|
||||
}
|
||||
|
||||
void BoundaryLFIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
|
||||
@@ -174,6 +174,29 @@ public:
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
|
||||
/// Class for domain integrator $ L(v) := (f, \Delta v) $
|
||||
class DomainLFLaplaceIntegrator : public LinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
Vector laplace;
|
||||
Coefficient &Q;
|
||||
real_t alpha;
|
||||
int oa, ob;
|
||||
public:
|
||||
/// Constructs the domain integrator $ (Q, \nabla v) $
|
||||
DomainLFLaplaceIntegrator(Coefficient &QF, real_t alp = 1.0, int a = 2,
|
||||
int b = 0)
|
||||
: Q(QF), oa(a), ob(b) { alpha = alp; }
|
||||
|
||||
/** Given a particular Finite Element and a transformation (Tr)
|
||||
computes the element right hand side element vector, elvect. */
|
||||
virtual void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
Vector &elvect);
|
||||
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
|
||||
|
||||
/// Class for boundary integration $ L(v) := (g, v) $
|
||||
class BoundaryLFIntegrator : public LinearFormIntegrator
|
||||
|
||||
+5
-4
@@ -39,9 +39,10 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, const GridFunction *gf,
|
||||
{
|
||||
const FiniteElementSpace *glob_fes = gf->FESpace();
|
||||
// duplicate the FiniteElementCollection from 'gf'
|
||||
fec = FiniteElementCollection::New(glob_fes->FEColl()->Name());
|
||||
fec_owned = FiniteElementCollection::New(glob_fes->FEColl()->Name());
|
||||
// create a local ParFiniteElementSpace from the global one:
|
||||
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning, fec);
|
||||
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning,
|
||||
fec_owned);
|
||||
SetSize(pfes->GetVSize());
|
||||
|
||||
if (partitioning)
|
||||
@@ -81,7 +82,7 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, std::istream &input)
|
||||
: GridFunction(pmesh, input)
|
||||
{
|
||||
// Convert the FiniteElementSpace, fes, to a ParFiniteElementSpace:
|
||||
pfes = new ParFiniteElementSpace(pmesh, fec, fes->GetVDim(),
|
||||
pfes = new ParFiniteElementSpace(pmesh, fec_owned, fes->GetVDim(),
|
||||
fes->GetOrdering());
|
||||
delete fes;
|
||||
fes = pfes;
|
||||
@@ -520,7 +521,7 @@ void ParGridFunction::CountElementsPerVDof(Array<int> &elem_per_vdof) const
|
||||
}
|
||||
|
||||
void ParGridFunction::GetDerivative(int comp, int der_comp,
|
||||
ParGridFunction &der)
|
||||
ParGridFunction &der) const
|
||||
{
|
||||
Array<int> overlap;
|
||||
AccumulateAndCountDerivativeValues(comp, der_comp, der, overlap);
|
||||
|
||||
+1
-1
@@ -231,7 +231,7 @@ public:
|
||||
void CountElementsPerVDof(Array<int> &elem_per_vdof) const override;
|
||||
|
||||
/// Parallel version of GridFunction::GetDerivative(); see its documentation.
|
||||
void GetDerivative(int comp, int der_comp, ParGridFunction &der);
|
||||
void GetDerivative(int comp, int der_comp, ParGridFunction &der) const;
|
||||
|
||||
/** Sets the output vector @a dof_vals to the values of the degrees of
|
||||
freedom of element @a el. If @a el is greater than or equal to the number
|
||||
|
||||
+238
-124
@@ -2949,6 +2949,15 @@ void TMOP_Integrator::EnableSurfaceFitting(const GridFunction &s0,
|
||||
MFEM_VERIFY(surf_fit_pos == NULL,
|
||||
"Using both fitting approaches is not supported.");
|
||||
|
||||
const int dim = s0.FESpace()->GetMesh()->Dimension();
|
||||
Mesh *mesh = s0.FESpace()->GetMesh();
|
||||
MFEM_VERIFY(mesh->GetNodes()->Size() == dim*s0.Size(),
|
||||
"Mesh and level-set polynomial order must be the same.");
|
||||
const H1_FECollection *fec = dynamic_cast<const H1_FECollection *>
|
||||
(s0.FESpace()->FEColl());
|
||||
MFEM_VERIFY(fec, "Only H1_FECollection is supported for the surface fitting "
|
||||
"grid function.");
|
||||
|
||||
delete surf_fit_gf;
|
||||
surf_fit_gf = new GridFunction(s0);
|
||||
surf_fit_gf->CountElementsPerVDof(surf_fit_dof_count);
|
||||
@@ -2987,12 +2996,24 @@ void TMOP_Integrator::EnableSurfaceFitting(const GridFunction &pos,
|
||||
void TMOP_Integrator::EnableSurfaceFitting(const ParGridFunction &s0,
|
||||
const Array<bool> &smarker,
|
||||
Coefficient &coeff,
|
||||
AdaptivityEvaluator &ae)
|
||||
AdaptivityEvaluator &ae,
|
||||
AdaptivityEvaluator *aegrad,
|
||||
AdaptivityEvaluator *aehess)
|
||||
{
|
||||
// To have both we must duplicate the markers.
|
||||
MFEM_VERIFY(surf_fit_pos == NULL,
|
||||
"Using both fitting approaches is not supported.");
|
||||
|
||||
const int dim = s0.FESpace()->GetMesh()->Dimension();
|
||||
ParMesh *pmesh = s0.ParFESpace()->GetParMesh();
|
||||
MFEM_VERIFY(pmesh->GetNodes()->Size() == dim*s0.Size(),
|
||||
"Mesh and level-set polynomial order must be the same.");
|
||||
const H1_FECollection *fec = dynamic_cast<const H1_FECollection *>
|
||||
(s0.FESpace()->FEColl());
|
||||
MFEM_VERIFY(fec, "Only H1_FECollection is supported for the surface fitting "
|
||||
"grid function.");
|
||||
|
||||
|
||||
delete surf_fit_gf;
|
||||
surf_fit_gf = new GridFunction(s0);
|
||||
s0.CountElementsPerVDof(surf_fit_dof_count);
|
||||
@@ -3000,11 +3021,80 @@ void TMOP_Integrator::EnableSurfaceFitting(const ParGridFunction &s0,
|
||||
surf_fit_coeff = &coeff;
|
||||
surf_fit_eval = &ae;
|
||||
|
||||
surf_fit_eval->SetParMetaInfo(*s0.ParFESpace()->GetParMesh(),
|
||||
*s0.ParFESpace());
|
||||
surf_fit_eval->SetParMetaInfo(*pmesh, *s0.ParFESpace());
|
||||
surf_fit_eval->SetInitialField
|
||||
(*surf_fit_gf->FESpace()->GetMesh()->GetNodes(), *surf_fit_gf);
|
||||
surf_fit_gf_bg = false;
|
||||
|
||||
if (!aegrad) { return; }
|
||||
|
||||
MFEM_VERIFY(aehess, "AdaptivityEvaluator for Hessians must be provided too.");
|
||||
|
||||
ParFiniteElementSpace *fes = s0.ParFESpace();
|
||||
|
||||
// FE space for gradients.
|
||||
delete surf_fit_grad;
|
||||
H1_FECollection *fec_grad = new H1_FECollection(fec->GetOrder(), dim,
|
||||
fec->GetBasisType());
|
||||
ParFiniteElementSpace *fes_grad = new ParFiniteElementSpace(pmesh, fec_grad,
|
||||
dim);
|
||||
// Initial gradients.
|
||||
surf_fit_grad = new GridFunction(fes_grad);
|
||||
surf_fit_grad->MakeOwner(fec_grad);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
ParGridFunction surf_fit_grad_comp(fes, surf_fit_grad->GetData()+d*s0.Size());
|
||||
s0.GetDerivative(1, d, surf_fit_grad_comp);
|
||||
}
|
||||
surf_fit_eval_grad = aegrad;
|
||||
surf_fit_eval_grad->SetParMetaInfo(*pmesh, *fes_grad);
|
||||
surf_fit_eval_grad->SetInitialField(*pmesh->GetNodes(), *surf_fit_grad);
|
||||
|
||||
// FE space for Hessians.
|
||||
delete surf_fit_hess;
|
||||
H1_FECollection *fec_hess = new H1_FECollection(fec->GetOrder(), dim,
|
||||
fec->GetBasisType());
|
||||
ParFiniteElementSpace *fes_hess = new ParFiniteElementSpace(pmesh, fec_hess,
|
||||
dim*dim);
|
||||
// Initial Hessians.
|
||||
surf_fit_hess = new GridFunction(fes_hess);
|
||||
surf_fit_hess->MakeOwner(fec_hess);
|
||||
int id = 0;
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int idir = 0; idir < dim; idir++)
|
||||
{
|
||||
ParGridFunction surf_fit_grad_comp(fes,
|
||||
surf_fit_grad->GetData()+d*s0.Size());
|
||||
ParGridFunction surf_fit_hess_comp(fes,
|
||||
surf_fit_hess->GetData()+id*s0.Size());
|
||||
surf_fit_grad_comp.GetDerivative(1, idir, surf_fit_hess_comp);
|
||||
id++;
|
||||
}
|
||||
}
|
||||
surf_fit_eval_hess = aehess;
|
||||
surf_fit_eval_hess->SetParMetaInfo(*pmesh, *fes_hess);
|
||||
surf_fit_eval_hess->SetInitialField(*pmesh->GetNodes(), *surf_fit_hess);
|
||||
|
||||
// Store DOF indices that are marked for fitting. Used to reduce work for
|
||||
// transferring information between source/background and current mesh.
|
||||
surf_fit_marker_dof_index.SetSize(0);
|
||||
#ifdef MFEM_USE_GSLIB
|
||||
if (dynamic_cast<InterpolatorFP *>(surf_fit_eval) &&
|
||||
dynamic_cast<InterpolatorFP *>(surf_fit_eval_grad) &&
|
||||
dynamic_cast<InterpolatorFP *>(surf_fit_eval_hess))
|
||||
{
|
||||
for (int i = 0; i < surf_fit_marker->Size(); i++)
|
||||
{
|
||||
if ((*surf_fit_marker)[i] == true)
|
||||
{
|
||||
surf_fit_marker_dof_index.Append(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
*surf_fit_grad = 0.0;
|
||||
*surf_fit_hess = 0.0;
|
||||
}
|
||||
|
||||
void TMOP_Integrator::EnableSurfaceFittingFromSource(
|
||||
@@ -3022,16 +3112,17 @@ void TMOP_Integrator::EnableSurfaceFittingFromSource(
|
||||
// Setup for level set function
|
||||
delete surf_fit_gf;
|
||||
surf_fit_gf = new GridFunction(s0);
|
||||
*surf_fit_gf = 0.0;
|
||||
surf_fit_marker = &smarker;
|
||||
surf_fit_coeff = &coeff;
|
||||
surf_fit_eval = &ae;
|
||||
|
||||
surf_fit_gf_bg = true;
|
||||
surf_fit_eval->SetParMetaInfo(*s_bg.ParFESpace()->GetParMesh(),
|
||||
*s_bg.ParFESpace());
|
||||
surf_fit_eval->SetInitialField
|
||||
(*s_bg.FESpace()->GetMesh()->GetNodes(), s_bg);
|
||||
GridFunction *nodes = s0.FESpace()->GetMesh()->GetNodes();
|
||||
surf_fit_eval->ComputeAtNewPosition(*nodes, *surf_fit_gf,
|
||||
nodes->FESpace()->GetOrdering());
|
||||
|
||||
// Setup for gradient on background mesh
|
||||
MFEM_VERIFY(s_bg_grad.ParFESpace()->GetOrdering() ==
|
||||
@@ -3041,11 +3132,11 @@ void TMOP_Integrator::EnableSurfaceFittingFromSource(
|
||||
delete surf_fit_grad;
|
||||
surf_fit_grad = new GridFunction(s0_grad);
|
||||
*surf_fit_grad = 0.0;
|
||||
surf_fit_eval_bg_grad = &age;
|
||||
surf_fit_eval_bg_hess = &ahe;
|
||||
surf_fit_eval_bg_grad->SetParMetaInfo(*s_bg_grad.ParFESpace()->GetParMesh(),
|
||||
*s_bg_grad.ParFESpace());
|
||||
surf_fit_eval_bg_grad->SetInitialField
|
||||
surf_fit_eval_grad = &age;
|
||||
surf_fit_eval_hess = &ahe;
|
||||
surf_fit_eval_grad->SetParMetaInfo(*s_bg_grad.ParFESpace()->GetParMesh(),
|
||||
*s_bg_grad.ParFESpace());
|
||||
surf_fit_eval_grad->SetInitialField
|
||||
(*s_bg_grad.FESpace()->GetMesh()->GetNodes(), s_bg_grad);
|
||||
|
||||
// Setup for Hessian on background mesh
|
||||
@@ -3056,9 +3147,9 @@ void TMOP_Integrator::EnableSurfaceFittingFromSource(
|
||||
delete surf_fit_hess;
|
||||
surf_fit_hess = new GridFunction(s0_hess);
|
||||
*surf_fit_hess = 0.0;
|
||||
surf_fit_eval_bg_hess->SetParMetaInfo(*s_bg_hess.ParFESpace()->GetParMesh(),
|
||||
*s_bg_hess.ParFESpace());
|
||||
surf_fit_eval_bg_hess->SetInitialField
|
||||
surf_fit_eval_hess->SetParMetaInfo(*s_bg_hess.ParFESpace()->GetParMesh(),
|
||||
*s_bg_hess.ParFESpace());
|
||||
surf_fit_eval_hess->SetInitialField
|
||||
(*s_bg_hess.FESpace()->GetMesh()->GetNodes(), s_bg_hess);
|
||||
|
||||
// Count number of zones that share each of the DOFs
|
||||
@@ -3863,7 +3954,7 @@ void TMOP_Integrator::AssembleElemVecSurfFit(const FiniteElement &el_x,
|
||||
|
||||
Vector sigma_e(dof_s);
|
||||
DenseMatrix surf_fit_grad_e(dof_s, dim);
|
||||
if (surf_fit_gf || surf_fit_gf_bg)
|
||||
if (surf_fit_gf)
|
||||
{
|
||||
surf_fit_gf->GetSubVector(vdofs, sigma_e);
|
||||
|
||||
@@ -3871,7 +3962,7 @@ void TMOP_Integrator::AssembleElemVecSurfFit(const FiniteElement &el_x,
|
||||
// The FE coefficients of the gradient go in surf_fit_grad_e.
|
||||
Vector grad_ptr(surf_fit_grad_e.GetData(), dof_s * dim);
|
||||
DenseMatrix grad_phys; // This will be (dof x dim, dof).
|
||||
if (surf_fit_gf_bg)
|
||||
if (surf_fit_grad)
|
||||
{
|
||||
surf_fit_grad->FESpace()->GetElementVDofs(el_id, dofs);
|
||||
surf_fit_grad->GetSubVector(dofs, grad_ptr);
|
||||
@@ -3945,7 +4036,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
|
||||
Vector sigma_e(dof_s);
|
||||
DenseMatrix surf_fit_grad_e(dof_s, dim);
|
||||
DenseMatrix surf_fit_hess_e(dof_s, dim*dim);
|
||||
if (surf_fit_gf || surf_fit_gf_bg)
|
||||
if (surf_fit_gf)
|
||||
{
|
||||
surf_fit_gf->GetSubVector(vdofs, sigma_e);
|
||||
|
||||
@@ -3953,7 +4044,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
|
||||
// The FE coefficients of the gradient go in surf_fit_grad_e.
|
||||
Vector grad_ptr(surf_fit_grad_e.GetData(), dof_s * dim);
|
||||
DenseMatrix grad_phys; // This will be (dof x dim, dof).
|
||||
if (surf_fit_gf_bg)
|
||||
if (surf_fit_grad)
|
||||
{
|
||||
surf_fit_grad->FESpace()->GetElementVDofs(el_id, dofs);
|
||||
surf_fit_grad->GetSubVector(dofs, grad_ptr);
|
||||
@@ -3967,7 +4058,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
|
||||
// Project the Hessian of sigma in the same space.
|
||||
// The FE coefficients of the Hessian go in surf_fit_hess_e.
|
||||
Vector hess_ptr(surf_fit_hess_e.GetData(), dof_s*dim*dim);
|
||||
if (surf_fit_gf_bg)
|
||||
if (surf_fit_hess)
|
||||
{
|
||||
surf_fit_hess->FESpace()->GetElementVDofs(el_id, dofs);
|
||||
surf_fit_hess->GetSubVector(dofs, hess_ptr);
|
||||
@@ -3994,7 +4085,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
|
||||
Tpr.SetIntPoint(&ip);
|
||||
real_t w = surf_fit_normal * surf_fit_coeff->Eval(Tpr, ip);
|
||||
|
||||
if (surf_fit_gf || surf_fit_gf_bg)
|
||||
if (surf_fit_gf)
|
||||
{
|
||||
Vector gg_ptr(surf_fit_hess_s.GetData(), dim * dim);
|
||||
surf_fit_hess_e.GetRow(s, gg_ptr);
|
||||
@@ -4376,6 +4467,130 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x,
|
||||
dx = detv_avg_min / dxscale;
|
||||
}
|
||||
|
||||
void TMOP_Integrator::RemapSurfaceFittingLevelSetAtNodes(const Vector &new_x,
|
||||
int new_x_ordering)
|
||||
{
|
||||
if (!surf_fit_gf) { return; }
|
||||
|
||||
if (surf_fit_marker_dof_index.Size())
|
||||
{
|
||||
// Interpolate information only at DOFs marked for fitting.
|
||||
const int dim = surf_fit_gf->FESpace()->GetMesh()->Dimension();
|
||||
const int cnt = surf_fit_marker_dof_index.Size();
|
||||
const int total_cnt = new_x.Size()/dim;
|
||||
Vector new_x_sorted(cnt*dim);
|
||||
if (new_x_ordering == 0)
|
||||
{
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
new_x_sorted(i + d*cnt) = new_x(dof_index + d*total_cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
new_x_sorted(d + i*dim) = new_x(d + dof_index*dim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interpolate values of the LS.
|
||||
Vector surf_fit_gf_int, surf_fit_grad_int, surf_fit_hess_int;
|
||||
surf_fit_eval->ComputeAtNewPosition(new_x_sorted, surf_fit_gf_int,
|
||||
new_x_ordering);
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
(*surf_fit_gf)[dof_index] = surf_fit_gf_int(i);
|
||||
}
|
||||
|
||||
// Interpolate gradients of the LS.
|
||||
surf_fit_eval_grad->ComputeAtNewPosition(new_x_sorted, surf_fit_grad_int,
|
||||
new_x_ordering);
|
||||
// Assumes surf_fit_grad and surf_fit_gf share the same space
|
||||
const int grad_dim = surf_fit_grad->VectorDim();
|
||||
const int grad_cnt = surf_fit_grad->Size()/grad_dim;
|
||||
if (surf_fit_grad->FESpace()->GetOrdering() == Ordering::byNODES)
|
||||
{
|
||||
for (int d = 0; d < grad_dim; d++)
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
(*surf_fit_grad)[dof_index + d*grad_cnt] =
|
||||
surf_fit_grad_int(i + d*cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
for (int d = 0; d < grad_dim; d++)
|
||||
{
|
||||
(*surf_fit_grad)[dof_index*grad_dim + d] =
|
||||
surf_fit_grad_int(i*grad_dim + d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interpolate Hessians of the LS.
|
||||
surf_fit_eval_hess->ComputeAtNewPosition(new_x_sorted, surf_fit_hess_int,
|
||||
new_x_ordering);
|
||||
// Assumes surf_fit_hess and surf_fit_gf share the same space
|
||||
const int hess_dim = surf_fit_hess->VectorDim();
|
||||
const int hess_cnt = surf_fit_hess->Size()/hess_dim;
|
||||
if (surf_fit_hess->FESpace()->GetOrdering() == Ordering::byNODES)
|
||||
{
|
||||
for (int d = 0; d < hess_dim; d++)
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
(*surf_fit_hess)[dof_index + d*hess_cnt] =
|
||||
surf_fit_hess_int(i + d*cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
for (int d = 0; d < hess_dim; d++)
|
||||
{
|
||||
(*surf_fit_hess)[dof_index*hess_dim + d] =
|
||||
surf_fit_hess_int(i*hess_dim + d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
surf_fit_eval->ComputeAtNewPosition(new_x, *surf_fit_gf, new_x_ordering);
|
||||
if (surf_fit_eval_grad)
|
||||
{
|
||||
surf_fit_eval_grad->ComputeAtNewPosition(new_x, *surf_fit_grad,
|
||||
new_x_ordering);
|
||||
}
|
||||
if (surf_fit_eval_hess)
|
||||
{
|
||||
surf_fit_eval_hess->ComputeAtNewPosition(new_x, *surf_fit_hess,
|
||||
new_x_ordering);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TMOP_Integrator::
|
||||
UpdateAfterMeshPositionChange(const Vector &x_new,
|
||||
const FiniteElementSpace &x_fes)
|
||||
@@ -4406,112 +4621,11 @@ UpdateAfterMeshPositionChange(const Vector &x_new,
|
||||
adapt_lim_eval->ComputeAtNewPosition(x_new, *adapt_lim_gf, ordering);
|
||||
}
|
||||
|
||||
// Update surf_fit_gf if surface fitting is enabled.
|
||||
// Update surf_fit_gf (and optionally its gradients) if surface
|
||||
// fitting is enabled.
|
||||
if (surf_fit_gf)
|
||||
{
|
||||
if (surf_fit_gf_bg)
|
||||
{
|
||||
// Interpolate information for only DOFs marked for fitting.
|
||||
const int dim = surf_fit_gf->FESpace()->GetMesh()->Dimension();
|
||||
const int cnt = surf_fit_marker_dof_index.Size();
|
||||
const int total_cnt = x_new.Size()/dim;
|
||||
Vector new_x_sorted(cnt*dim);
|
||||
if (ordering == 0)
|
||||
{
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
new_x_sorted(i + d*cnt) = x_new(dof_index + d*total_cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
new_x_sorted(d + i*dim) = x_new(d + dof_index*dim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector surf_fit_gf_int, surf_fit_grad_int, surf_fit_hess_int;
|
||||
surf_fit_eval->ComputeAtNewPosition(
|
||||
new_x_sorted, surf_fit_gf_int, ordering);
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
(*surf_fit_gf)[dof_index] = surf_fit_gf_int(i);
|
||||
}
|
||||
|
||||
surf_fit_eval_bg_grad->ComputeAtNewPosition(
|
||||
new_x_sorted, surf_fit_grad_int, ordering);
|
||||
// Assumes surf_fit_grad and surf_fit_gf share the same space
|
||||
const int grad_dim = surf_fit_grad->VectorDim();
|
||||
const int grad_cnt = surf_fit_grad->Size()/grad_dim;
|
||||
if (surf_fit_grad->FESpace()->GetOrdering() == Ordering::byNODES)
|
||||
{
|
||||
for (int d = 0; d < grad_dim; d++)
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
(*surf_fit_grad)[dof_index + d*grad_cnt] =
|
||||
surf_fit_grad_int(i + d*cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
for (int d = 0; d < grad_dim; d++)
|
||||
{
|
||||
(*surf_fit_grad)[dof_index*dim + d] =
|
||||
surf_fit_grad_int(i*dim + d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
surf_fit_eval_bg_hess->ComputeAtNewPosition(
|
||||
new_x_sorted, surf_fit_hess_int, ordering);
|
||||
// Assumes surf_fit_hess and surf_fit_gf share the same space
|
||||
const int hess_dim = surf_fit_hess->VectorDim();
|
||||
const int hess_cnt = surf_fit_hess->Size()/hess_dim;
|
||||
if (surf_fit_hess->FESpace()->GetOrdering() == Ordering::byNODES)
|
||||
{
|
||||
for (int d = 0; d < hess_dim; d++)
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
(*surf_fit_hess)[dof_index + d*hess_cnt] =
|
||||
surf_fit_hess_int(i + d*cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
int dof_index = surf_fit_marker_dof_index[i];
|
||||
for (int d = 0; d < hess_dim; d++)
|
||||
{
|
||||
(*surf_fit_hess)[dof_index*dim + d] =
|
||||
surf_fit_hess_int(i*dim + d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
surf_fit_eval->ComputeAtNewPosition(x_new, *surf_fit_gf, ordering);
|
||||
}
|
||||
RemapSurfaceFittingLevelSetAtNodes(x_new, ordering);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-10
@@ -1784,12 +1784,11 @@ protected:
|
||||
// Fitting to given physical positions.
|
||||
TMOP_QuadraticLimiter *surf_fit_limiter; // Owned. Created internally.
|
||||
const GridFunction *surf_fit_pos; // Not owned. Positions to fit.
|
||||
real_t surf_fit_normal;
|
||||
bool surf_fit_gf_bg;
|
||||
GridFunction *surf_fit_grad, *surf_fit_hess;
|
||||
AdaptivityEvaluator *surf_fit_eval_bg_grad, *surf_fit_eval_bg_hess;
|
||||
Array<int> surf_fit_dof_count;
|
||||
Array<int> surf_fit_marker_dof_index;
|
||||
real_t surf_fit_normal; // Normalization factor.
|
||||
GridFunction *surf_fit_grad, *surf_fit_hess; // Owned. Created internally.
|
||||
AdaptivityEvaluator *surf_fit_eval_grad, *surf_fit_eval_hess; // Not owned.
|
||||
Array<int> surf_fit_dof_count; // Number of dofs per node.
|
||||
Array<int> surf_fit_marker_dof_index; // Indices of nodes to fit.
|
||||
|
||||
DiscreteAdaptTC *discr_tc;
|
||||
|
||||
@@ -1985,6 +1984,10 @@ protected:
|
||||
real_t ComputeUntanglerMaxMuBarrier(const Vector &x,
|
||||
const FiniteElementSpace &fes);
|
||||
|
||||
// Remaps the internal surface fitting gridfunction object at provided
|
||||
// locations.
|
||||
void RemapSurfaceFittingLevelSetAtNodes(const Vector &new_x,
|
||||
int new_x_ordering);
|
||||
public:
|
||||
/** @param[in] m TMOP_QualityMetric for r-adaptivity (not owned).
|
||||
@param[in] tc Target-matrix construction algorithm to use (not owned).
|
||||
@@ -2000,9 +2003,8 @@ public:
|
||||
surf_fit_marker(NULL), surf_fit_coeff(NULL),
|
||||
surf_fit_gf(NULL), surf_fit_eval(NULL),
|
||||
surf_fit_limiter(NULL), surf_fit_pos(NULL),
|
||||
surf_fit_normal(1.0),
|
||||
surf_fit_gf_bg(false), surf_fit_grad(NULL), surf_fit_hess(NULL),
|
||||
surf_fit_eval_bg_grad(NULL), surf_fit_eval_bg_hess(NULL),
|
||||
surf_fit_normal(1.0), surf_fit_grad(NULL), surf_fit_hess(NULL),
|
||||
surf_fit_eval_grad(NULL), surf_fit_eval_hess(NULL),
|
||||
discr_tc(dynamic_cast<DiscreteAdaptTC *>(tc)),
|
||||
fdflag(false), dxscale(1.0e3), fd_call_flag(false), exact_action(false)
|
||||
{ PA.enabled = false; }
|
||||
@@ -2103,9 +2105,15 @@ public:
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
/// Parallel support for surface fitting to the zero level set of a function.
|
||||
/// Here, we add two optional inputs: @a aegrad and @a aehess. When provided,
|
||||
/// the first and second derivative of the input level set are computed on
|
||||
/// the initial mesh, and @a aegrad and @a aehess are used to remap grad_s(x)
|
||||
/// from grad_s0(x0) and hess_s(x) from hess_s0(x0), respectively.
|
||||
void EnableSurfaceFitting(const ParGridFunction &s0,
|
||||
const Array<bool> &smarker, Coefficient &coeff,
|
||||
AdaptivityEvaluator &ae);
|
||||
AdaptivityEvaluator &ae,
|
||||
AdaptivityEvaluator *aegrad = NULL,
|
||||
AdaptivityEvaluator *aehess = NULL);
|
||||
|
||||
/** @brief Fitting of certain DOFs in the current mesh to the zero level set
|
||||
of a function defined on another (finer) source mesh.
|
||||
|
||||
+88
-36
@@ -429,11 +429,13 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
#endif
|
||||
|
||||
real_t scale = 1.0;
|
||||
real_t avg_surf_fit_err, max_surf_fit_err = 0.0;
|
||||
if (surf_fit_max_threshold > 0.0)
|
||||
bool fitting = IsSurfaceFittingEnabled();
|
||||
real_t init_fit_avg_err, init_fit_max_err = 0.0;
|
||||
if (fitting && surf_fit_converge_error)
|
||||
{
|
||||
GetSurfaceFittingError(x_out_loc, avg_surf_fit_err, max_surf_fit_err);
|
||||
if (max_surf_fit_err < surf_fit_max_threshold)
|
||||
GetSurfaceFittingError(x_out_loc, init_fit_avg_err, init_fit_max_err);
|
||||
// Check for convergence
|
||||
if (init_fit_max_err < surf_fit_max_err_limit)
|
||||
{
|
||||
if (print_options.iterations)
|
||||
{
|
||||
@@ -444,11 +446,12 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
return scale;
|
||||
}
|
||||
}
|
||||
if (adapt_inc_count >= max_adapt_inc_count)
|
||||
|
||||
if (surf_fit_adapt_count >= surf_fit_adapt_count_limit)
|
||||
{
|
||||
if (print_options.iterations)
|
||||
{
|
||||
mfem::out << "TMOPNewtonSolver converged "
|
||||
mfem::out << "TMOPNewtonSolver terminated "
|
||||
"based on max number of times surface fitting weight can"
|
||||
"be increased. \n";
|
||||
}
|
||||
@@ -467,7 +470,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
// reference to detect deteriorations.
|
||||
MFEM_VERIFY(min_det_ptr != NULL, " Initial mesh was valid, but"
|
||||
" intermediate mesh is invalid. Contact TMOP Developers.");
|
||||
MFEM_VERIFY(min_detJ_threshold == 0.0,
|
||||
MFEM_VERIFY(min_detJ_limit == 0.0,
|
||||
"This setup is not supported. Contact TMOP Developers.");
|
||||
*min_det_ptr = untangle_factor * min_detT_in;
|
||||
}
|
||||
@@ -478,6 +481,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
bool x_out_ok = false;
|
||||
real_t energy_out = 0.0, min_detT_out;
|
||||
const real_t norm_in = Norm(r);
|
||||
real_t avg_fit_err, max_fit_err = 0.0;
|
||||
|
||||
const real_t detJ_factor = (solver_type == 1) ? 0.25 : 0.5;
|
||||
compute_metric_quantile_flag = false;
|
||||
@@ -488,6 +492,9 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
// Perform the line search.
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
avg_fit_err = 0.0;
|
||||
max_fit_err = 0.0;
|
||||
|
||||
// Update the mesh and get the L-vector in x_out_loc.
|
||||
add(x, -scale, c, x_out);
|
||||
if (serial)
|
||||
@@ -502,7 +509,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
|
||||
// Check the changes in detJ.
|
||||
min_detT_out = ComputeMinDet(x_out_loc, *fes);
|
||||
if (untangling == false && min_detT_out <= min_detJ_threshold)
|
||||
if (untangling == false && min_detT_out <= min_detJ_limit)
|
||||
{
|
||||
// No untangling, and detJ got negative (or small) -- no good.
|
||||
if (print_options.iterations)
|
||||
@@ -529,18 +536,19 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
// Check the changes in total energy.
|
||||
ProcessNewState(x_out);
|
||||
|
||||
real_t avg_fit_err, max_fit_err = 0.0;
|
||||
if (surf_fit_max_threshold > 0.0)
|
||||
// Ensure sufficient decrease in fitting error if we are trying to
|
||||
// converge based on error.
|
||||
if (fitting && surf_fit_converge_error)
|
||||
{
|
||||
GetSurfaceFittingError(x_out_loc, avg_fit_err, max_fit_err);
|
||||
}
|
||||
if (surf_fit_max_threshold > 0.0 && max_fit_err >= 1.2*max_surf_fit_err)
|
||||
{
|
||||
if (print_options.iterations)
|
||||
if (max_fit_err >= 1.2*init_fit_max_err)
|
||||
{
|
||||
mfem::out << "Scale = " << scale << " Surf fit err increased.\n";
|
||||
if (print_options.iterations)
|
||||
{
|
||||
mfem::out << "Scale = " << scale << " Surf fit err increased.\n";
|
||||
}
|
||||
scale *= 0.5; continue;
|
||||
}
|
||||
scale *= 0.5; continue;
|
||||
}
|
||||
|
||||
if (serial)
|
||||
@@ -614,7 +622,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
|
||||
if (x_out_ok == false) { scale = 0.0; }
|
||||
|
||||
if (surf_fit_scale_factor > 0.0) { update_surf_fit_coeff = true; }
|
||||
if (surf_fit_scale_factor > 0.0) { surf_fit_coeff_update = true; }
|
||||
compute_metric_quantile_flag = true;
|
||||
|
||||
return scale;
|
||||
@@ -657,7 +665,7 @@ void TMOPNewtonSolver::GetSurfaceFittingWeight(Array<real_t> &weights) const
|
||||
for (int i = 0; i < integs.Size(); i++)
|
||||
{
|
||||
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
|
||||
if (ti)
|
||||
if (ti && ti->IsSurfaceFittingEnabled())
|
||||
{
|
||||
weight = ti->GetSurfaceFittingWeight();
|
||||
weights.Append(weight);
|
||||
@@ -668,8 +676,11 @@ void TMOPNewtonSolver::GetSurfaceFittingWeight(Array<real_t> &weights) const
|
||||
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
|
||||
for (int j = 0; j < ati.Size(); j++)
|
||||
{
|
||||
weight = ati[j]->GetSurfaceFittingWeight();
|
||||
weights.Append(weight);
|
||||
if (ati[j]->IsSurfaceFittingEnabled())
|
||||
{
|
||||
weight = ati[j]->GetSurfaceFittingWeight();
|
||||
weights.Append(weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -716,6 +727,39 @@ void TMOPNewtonSolver::GetSurfaceFittingError(const Vector &x_loc,
|
||||
}
|
||||
}
|
||||
|
||||
bool TMOPNewtonSolver::IsSurfaceFittingEnabled() const
|
||||
{
|
||||
const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
|
||||
const Array<NonlinearFormIntegrator*> &integs = *nlf->GetDNFI();
|
||||
TMOP_Integrator *ti = NULL;
|
||||
TMOPComboIntegrator *co = NULL;
|
||||
|
||||
for (int i = 0; i < integs.Size(); i++)
|
||||
{
|
||||
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
|
||||
if (ti)
|
||||
{
|
||||
if (ti->IsSurfaceFittingEnabled())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
|
||||
if (co)
|
||||
{
|
||||
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
|
||||
for (int j = 0; j < ati.Size(); j++)
|
||||
{
|
||||
if (ati[j]->IsSurfaceFittingEnabled())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
|
||||
{
|
||||
const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
|
||||
@@ -801,38 +845,46 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
|
||||
// adaptive surface fitting is enabled. The idea is to increase the
|
||||
// coefficient if the surface fitting error does not sufficiently
|
||||
// decrease between subsequent TMOPNewtonSolver iterations.
|
||||
if (update_surf_fit_coeff)
|
||||
if (surf_fit_coeff_update)
|
||||
{
|
||||
// Get surface fitting errors.
|
||||
GetSurfaceFittingError(x_loc, surf_fit_err_avg, surf_fit_err_max);
|
||||
GetSurfaceFittingError(x_loc, surf_fit_avg_err, surf_fit_max_err);
|
||||
// Get array with surface fitting weights.
|
||||
Array<real_t> weights;
|
||||
GetSurfaceFittingWeight(weights);
|
||||
Array<real_t> fitweights;
|
||||
GetSurfaceFittingWeight(fitweights);
|
||||
|
||||
if (print_options.iterations)
|
||||
{
|
||||
mfem::out << "Avg/Max surface fitting error: " <<
|
||||
surf_fit_err_avg << " " <<
|
||||
surf_fit_err_max << "\n";
|
||||
surf_fit_avg_err << " " <<
|
||||
surf_fit_max_err << "\n";
|
||||
mfem::out << "Min/Max surface fitting weight: " <<
|
||||
weights.Min() << " " << weights.Max() << "\n";
|
||||
fitweights.Min() << " " << fitweights.Max() << "\n";
|
||||
}
|
||||
|
||||
real_t change_surf_fit_err = surf_fit_err_avg_prvs-surf_fit_err_avg;
|
||||
real_t rel_change_surf_fit_err = change_surf_fit_err/surf_fit_err_avg_prvs;
|
||||
real_t change_surf_fit_err = surf_fit_avg_err_prvs-surf_fit_avg_err;
|
||||
real_t rel_change_surf_fit_err = change_surf_fit_err/surf_fit_avg_err_prvs;
|
||||
|
||||
// Increase the surface fitting coefficient if the surface fitting error
|
||||
// does not decrease sufficiently.
|
||||
if (rel_change_surf_fit_err < surf_fit_rel_change_threshold)
|
||||
// does not decrease sufficiently. If we are converging based on residual,
|
||||
// also make sure we have not reached the maximum fitting weight and
|
||||
// error threshold.
|
||||
if (rel_change_surf_fit_err < surf_fit_err_rel_change_limit &&
|
||||
(surf_fit_converge_error ||
|
||||
(fitweights.Max() < surf_fit_weight_limit &&
|
||||
surf_fit_max_err > surf_fit_max_err_limit)))
|
||||
{
|
||||
UpdateSurfaceFittingWeight(surf_fit_scale_factor);
|
||||
adapt_inc_count += 1;
|
||||
real_t scale_factor = std::min(surf_fit_scale_factor,
|
||||
surf_fit_weight_limit/fitweights.Max());
|
||||
UpdateSurfaceFittingWeight(scale_factor);
|
||||
surf_fit_adapt_count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
adapt_inc_count = 0;
|
||||
surf_fit_adapt_count = 0;
|
||||
}
|
||||
surf_fit_err_avg_prvs = surf_fit_err_avg;
|
||||
update_surf_fit_coeff = false;
|
||||
surf_fit_avg_err_prvs = surf_fit_avg_err;
|
||||
surf_fit_coeff_update = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+87
-26
@@ -134,18 +134,20 @@ protected:
|
||||
int solver_type;
|
||||
bool parallel;
|
||||
|
||||
// Line search step is rejected if min(detJ) <= min_detJ_threshold.
|
||||
real_t min_detJ_threshold = 0.0;
|
||||
// Line search step is rejected if min(detJ) <= min_detJ_limit.
|
||||
real_t min_detJ_limit = 0.0;
|
||||
|
||||
// Surface fitting variables.
|
||||
mutable real_t surf_fit_err_avg_prvs = 10000.0;
|
||||
mutable real_t surf_fit_err_avg, surf_fit_err_max;
|
||||
mutable bool update_surf_fit_coeff = false;
|
||||
real_t surf_fit_max_threshold = -1.0;
|
||||
real_t surf_fit_rel_change_threshold = 0.001;
|
||||
mutable real_t surf_fit_avg_err_prvs = 10000.0;
|
||||
mutable real_t surf_fit_avg_err, surf_fit_max_err;
|
||||
mutable bool surf_fit_coeff_update = false;
|
||||
real_t surf_fit_max_err_limit = -1.0;
|
||||
real_t surf_fit_err_rel_change_limit = 0.001;
|
||||
real_t surf_fit_scale_factor = 0.0;
|
||||
mutable int adapt_inc_count = 0;
|
||||
mutable int max_adapt_inc_count = 10;
|
||||
mutable int surf_fit_adapt_count = 0;
|
||||
mutable int surf_fit_adapt_count_limit = 10;
|
||||
mutable real_t surf_fit_weight_limit = 1e10;
|
||||
bool surf_fit_converge_error = false;
|
||||
|
||||
// Minimum determinant over the whole mesh. Used for mesh untangling.
|
||||
real_t *min_det_ptr = nullptr;
|
||||
@@ -191,6 +193,9 @@ protected:
|
||||
void GetSurfaceFittingWeight(Array<real_t> &weights) const;
|
||||
///@}
|
||||
|
||||
/// Check if surface fitting is enabled.
|
||||
bool IsSurfaceFittingEnabled() const;
|
||||
|
||||
public:
|
||||
#ifdef MFEM_USE_MPI
|
||||
TMOPNewtonSolver(MPI_Comm comm, const IntegrationRule &irule, int type = 0)
|
||||
@@ -224,38 +229,94 @@ public:
|
||||
/// (ii) surface fitting weight.
|
||||
virtual void ProcessNewState(const Vector &x) const;
|
||||
|
||||
/** @name Methods for adaptive surface fitting weight. (Experimental) */
|
||||
/// Enable/Disable adaptive surface fitting weight.
|
||||
/// The weight is modified after each TMOPNewtonSolver iteration as:
|
||||
/// w_{k+1} = w_{k} * @a surf_fit_scale_factor if relative change in
|
||||
/// max surface fitting error < @a surf_fit_rel_change_threshold.
|
||||
/// The solver terminates if the maximum surface fitting error does
|
||||
/// not sufficiently decrease for @a max_adapt_inc_count consecutive
|
||||
/// solver iterations or if the max error falls below @a surf_fit_max_threshold.
|
||||
void EnableAdaptiveSurfaceFitting()
|
||||
{
|
||||
surf_fit_scale_factor = 10.0;
|
||||
surf_fit_rel_change_threshold = 0.001;
|
||||
}
|
||||
/** @name Methods for adaptive surface fitting.
|
||||
\brief These methods control the behavior of the weight and the
|
||||
termination of the solver. (Experimental)
|
||||
|
||||
Adaptive fitting weight: The weight is modified after each
|
||||
TMOPNewtonSolver iteration as:
|
||||
w_{k+1} = w_{k} * \ref surf_fit_scale_factor if the relative
|
||||
change in average fitting error < \ref surf_fit_err_rel_change_limit.
|
||||
When converging based on the residual, we enforce the fitting weight
|
||||
to be at-most \ref surf_fit_weight_limit, and increase it only if the
|
||||
fitting error is below user prescribed threshold
|
||||
(\ref surf_fit_max_err_limit).
|
||||
See \ref SetAdaptiveSurfaceFittingScalingFactor and
|
||||
\ref SetAdaptiveSurfaceFittingRelativeChangeThreshold.
|
||||
|
||||
Note that the solver stops if the maximum surface fitting error
|
||||
does not sufficiently decrease for \ref surf_fit_adapt_count_limit (default 10)
|
||||
consecutive increments of the fitting weight during weight adaptation.
|
||||
This typically occurs when the mesh cannot align with the level-set
|
||||
without degrading element quality.
|
||||
See \ref SetMaxNumberofIncrementsForAdaptiveFitting.
|
||||
|
||||
Convergence criterion: There are two modes, residual- and error-based,
|
||||
which can be toggled using \ref SetSurfaceFittingConvergenceBasedOnError.
|
||||
|
||||
(i) Residual based (default): Stop when the norm of the gradient of the
|
||||
TMOP objective reaches the prescribed tolerance. This method is best used
|
||||
with a reasonable value for \ref surf_fit_weight_limit when the
|
||||
adaptive surface fitting scheme is used. See method
|
||||
\ref SetSurfaceFittingWeightLimit.
|
||||
|
||||
(ii) Error based: Stop when the maximum fitting error
|
||||
reaches the user-prescribed threshold, \ref surf_fit_max_err_limit.
|
||||
In this case, \ref surf_fit_weight_limit is ignored during weight
|
||||
adaptation.
|
||||
*/
|
||||
///@{
|
||||
void SetAdaptiveSurfaceFittingScalingFactor(real_t factor)
|
||||
{
|
||||
MFEM_VERIFY(factor > 1.0, "Scaling factor must be greater than 1.");
|
||||
surf_fit_scale_factor = factor;
|
||||
}
|
||||
void SetAdaptiveSurfaceFittingRelativeChangeThreshold(real_t threshold)
|
||||
{
|
||||
surf_fit_rel_change_threshold = threshold;
|
||||
surf_fit_err_rel_change_limit = threshold;
|
||||
}
|
||||
/// Used for stopping based on the number of consecutive failed weight
|
||||
/// adaptation iterations.
|
||||
// TODO: Rename to SetMaxNumberofIncrementsForAdaptiveSurfaceFitting
|
||||
// in future.
|
||||
void SetMaxNumberofIncrementsForAdaptiveFitting(int count)
|
||||
{
|
||||
max_adapt_inc_count = count;
|
||||
surf_fit_adapt_count_limit = count;
|
||||
}
|
||||
/// Used for error-based surface fitting termination.
|
||||
void SetTerminationWithMaxSurfaceFittingError(real_t max_error)
|
||||
{
|
||||
surf_fit_max_threshold = max_error;
|
||||
surf_fit_max_err_limit = max_error;
|
||||
surf_fit_converge_error = true;
|
||||
}
|
||||
/// Could be used with both error-based or residual-based convergence.
|
||||
void SetSurfaceFittingMaxErrorLimit(real_t max_error)
|
||||
{
|
||||
surf_fit_max_err_limit = max_error;
|
||||
}
|
||||
/// Used for residual-based surface fitting termination.
|
||||
void SetSurfaceFittingWeightLimit(real_t weight)
|
||||
{
|
||||
surf_fit_weight_limit = weight;
|
||||
}
|
||||
/// Toggle convergence based on residual or error.
|
||||
void SetSurfaceFittingConvergenceBasedOnError(bool mode)
|
||||
{
|
||||
surf_fit_converge_error = mode;
|
||||
if (surf_fit_converge_error)
|
||||
{
|
||||
MFEM_VERIFY(surf_fit_max_err_limit >= 0,
|
||||
"Fitting error based convergence requires the user to "
|
||||
"first set the error threshold."
|
||||
"See SetTerminationWithMaxSurfaceFittingError");
|
||||
}
|
||||
}
|
||||
///@}
|
||||
|
||||
/// Set minimum determinant enforced during line-search.
|
||||
void SetMinimumDeterminantThreshold(real_t threshold)
|
||||
{
|
||||
min_detJ_threshold = threshold;
|
||||
min_detJ_limit = threshold;
|
||||
}
|
||||
|
||||
virtual void Mult(const Vector &b, Vector &x) const
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -134,7 +134,7 @@ int socketbuf::open(const char hostname[], int port)
|
||||
{
|
||||
closesocket(socket_descriptor);
|
||||
socket_descriptor = -2;
|
||||
return -1;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -148,7 +148,7 @@ int socketbuf::open(const char hostname[], int port)
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
return 0;
|
||||
return (socket_descriptor < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
int socketbuf::close()
|
||||
|
||||
@@ -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++)
|
||||
|
||||
+538
-522
File diff suppressed because it is too large
Load Diff
+28
-8
@@ -207,6 +207,10 @@ public:
|
||||
/// Replaces the current matrix with its square root inverse
|
||||
void SquareRootInverse();
|
||||
|
||||
/// Replaces the current matrix with its exponential
|
||||
/// (currently only supports 2x2 matrices)
|
||||
void Exponential();
|
||||
|
||||
/// Calculates the determinant of the matrix
|
||||
/// (optimized for 2x2, 3x3, and 4x4 matrices)
|
||||
real_t Det() const;
|
||||
@@ -268,35 +272,51 @@ public:
|
||||
/// Compute the square of the Frobenius norm of the matrix
|
||||
real_t FNorm2() const { real_t s, n2; FNorm(s, n2); return s*s*n2; }
|
||||
|
||||
/// Compute eigenvalues of A x = ev x where A = *this
|
||||
/** Compute eigenvalues of A x = ev x where A = *this
|
||||
A is assumed to be symmetric. */
|
||||
void Eigenvalues(Vector &ev)
|
||||
{ Eigensystem(ev); }
|
||||
|
||||
/// Compute eigenvalues and eigenvectors of A x = ev x where A = *this
|
||||
/** Compute ith eigenvalue of A x = ev x where A = *this
|
||||
A is assumed to be symmetric. */
|
||||
real_t Eigenvalue(int i = -1);
|
||||
|
||||
/** Compute eigenvalues and eigenvectors of A x = ev x where A = *this
|
||||
A is assumed to be symmetric. */
|
||||
void Eigenvalues(Vector &ev, DenseMatrix &evect)
|
||||
{ Eigensystem(ev, &evect); }
|
||||
|
||||
/// Compute eigenvalues and eigenvectors of A x = ev x where A = *this
|
||||
/** Compute eigenvalues and eigenvectors of A x = ev x where A = *this
|
||||
A is assumed to be symmetric. */
|
||||
void Eigensystem(Vector &ev, DenseMatrix &evect)
|
||||
{ Eigensystem(ev, &evect); }
|
||||
|
||||
/** Compute generalized eigenvalues and eigenvectors of A x = ev B x,
|
||||
where A = *this */
|
||||
/** Compute generalized eigenvalues of A x = ev B x, where A = *this
|
||||
A and B are assumed to be symmetric. */
|
||||
void Eigenvalues(DenseMatrix &b, Vector &ev)
|
||||
{ Eigensystem(b, ev); }
|
||||
|
||||
/// Compute generalized eigenvalues of A x = ev B x, where A = *this
|
||||
/** Compute ith eigenvalue of A x = ev B x where A = *this
|
||||
A and B are assumed to be symmetric. */
|
||||
real_t Eigenvalue(DenseMatrix &b, int i = -1);
|
||||
|
||||
/** Compute generalized eigenvalues and eigenvectors of A x = ev B x,
|
||||
where A = *this. A and B are assumed to be symmetric.*/
|
||||
void Eigenvalues(DenseMatrix &b, Vector &ev, DenseMatrix &evect)
|
||||
{ Eigensystem(b, ev, &evect); }
|
||||
|
||||
/** Compute generalized eigenvalues and eigenvectors of A x = ev B x,
|
||||
where A = *this */
|
||||
where A = *this. A and B are assumed to be symmetric.*/
|
||||
void Eigensystem(DenseMatrix &b, Vector &ev, DenseMatrix &evect)
|
||||
{ Eigensystem(b, ev, &evect); }
|
||||
|
||||
void SingularValues(Vector &sv) const;
|
||||
int Rank(real_t tol) const;
|
||||
|
||||
/** Compute the Null Space of the matrix, such that A x = 0,
|
||||
where A = *this* and x is a column of ns */
|
||||
void NullSpace(DenseMatrix &ns, real_t tol);
|
||||
|
||||
/// Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
|
||||
real_t CalcSingularvalue(const int i) const;
|
||||
|
||||
@@ -318,7 +338,6 @@ public:
|
||||
void SetCol(int c, const real_t* col);
|
||||
void SetCol(int c, const Vector &col);
|
||||
|
||||
|
||||
/// Set all entries of a row to the specified value.
|
||||
void SetRow(int row, real_t value);
|
||||
/// Set all entries of a column to the specified value.
|
||||
@@ -342,6 +361,7 @@ public:
|
||||
void Transpose(const DenseMatrix &A);
|
||||
/// (*this) = 1/2 ((*this) + (*this)^t)
|
||||
void Symmetrize();
|
||||
bool IsSymmetric(real_t tol = 1e-10);
|
||||
|
||||
void Lump();
|
||||
|
||||
|
||||
+70
-66
@@ -410,19 +410,19 @@ HYPRE_Int HypreParVector::Randomize(HYPRE_Int seed)
|
||||
return hypre_ParVectorSetRandomValues(x,seed);
|
||||
}
|
||||
|
||||
void HypreParVector::Print(const char *fname) const
|
||||
void HypreParVector::Print(const std::string &fname) const
|
||||
{
|
||||
hypre_ParVectorPrint(x,fname);
|
||||
hypre_ParVectorPrint(x, fname.c_str());
|
||||
}
|
||||
|
||||
void HypreParVector::Read(MPI_Comm comm, const char *fname)
|
||||
void HypreParVector::Read(MPI_Comm comm, const std::string &fname)
|
||||
{
|
||||
if (own_ParVector)
|
||||
{
|
||||
hypre_ParVectorDestroy(x);
|
||||
}
|
||||
data.Delete();
|
||||
x = hypre_ParVectorRead(comm, fname);
|
||||
x = hypre_ParVectorRead(comm, fname.c_str());
|
||||
own_ParVector = true;
|
||||
_SetDataAndSize_();
|
||||
}
|
||||
@@ -792,6 +792,44 @@ static void SyncBackBoolCSR(Table *bool_csr, MemoryIJData &mem_csr)
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Return the size of the partitioning arrays, see @ref
|
||||
/// hypre_partitioning_descr.
|
||||
static int GetPartitioningArraySize(MPI_Comm comm)
|
||||
{
|
||||
if (HYPRE_AssumedPartitionCheck())
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int comm_size;
|
||||
MPI_Comm_size(comm, &comm_size);
|
||||
return comm_size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Returns true if the row and col arrays are equal (across all MPI
|
||||
/// ranks).
|
||||
///
|
||||
/// Both @a row and @a col are partitioning arrays, whose length is returned by
|
||||
/// GetPartitioningArraySize(), see @ref hypre_partitioning_descr.
|
||||
static bool RowAndColStartsAreEqual(MPI_Comm comm, HYPRE_BigInt *rows,
|
||||
HYPRE_BigInt *cols)
|
||||
{
|
||||
const int part_size = GetPartitioningArraySize(comm);
|
||||
bool are_equal = true;
|
||||
for (int i = 0; i < part_size; ++i)
|
||||
{
|
||||
if (rows[i] != cols[i])
|
||||
{
|
||||
are_equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MPI_Allreduce(MPI_IN_PLACE, &are_equal, 1, MPI_C_BOOL, MPI_LAND, comm);
|
||||
return are_equal;
|
||||
}
|
||||
|
||||
// static method
|
||||
signed char HypreParMatrix::HypreCsrToMem(hypre_CSRMatrix *h_mat,
|
||||
MemoryType h_mat_mt,
|
||||
@@ -924,7 +962,7 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
|
||||
hypre_ParCSRMatrixSetNumNonzeros(A);
|
||||
|
||||
/* Make sure that the first entry in each row is the diagonal one. */
|
||||
if (row_starts == col_starts)
|
||||
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
|
||||
{
|
||||
HypreReadWrite();
|
||||
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
|
||||
@@ -974,11 +1012,12 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
|
||||
hypre_ParCSRMatrixSetNumNonzeros(A);
|
||||
|
||||
/* Make sure that the first entry in each row is the diagonal one. */
|
||||
if (row_starts == col_starts)
|
||||
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
|
||||
{
|
||||
HypreReadWrite();
|
||||
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
|
||||
SyncBackCSR(diag, mem_diag); // update diag, if needed
|
||||
// update diag, if needed
|
||||
if (!own_diag_offd) { SyncBackCSR(diag, mem_diag); }
|
||||
}
|
||||
|
||||
hypre_MatvecCommPkgCreate(A);
|
||||
@@ -1031,7 +1070,7 @@ HypreParMatrix::HypreParMatrix(
|
||||
hypre_ParCSRMatrixSetNumNonzeros(A);
|
||||
|
||||
/* Make sure that the first entry in each row is the diagonal one. */
|
||||
if (row_starts == col_starts)
|
||||
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
|
||||
{
|
||||
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
|
||||
}
|
||||
@@ -1093,7 +1132,7 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
|
||||
hypre_CSRMatrixDestroy(csr_a);
|
||||
|
||||
/* Make sure that the first entry in each row is the diagonal one. */
|
||||
if (row_starts == col_starts)
|
||||
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
|
||||
{
|
||||
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(new_A));
|
||||
}
|
||||
@@ -1132,7 +1171,7 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
|
||||
hypre_ParCSRMatrixSetNumNonzeros(A);
|
||||
|
||||
/* Make sure that the first entry in each row is the diagonal one. */
|
||||
if (row_starts == col_starts)
|
||||
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
|
||||
{
|
||||
HypreReadWrite();
|
||||
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
|
||||
@@ -1247,11 +1286,10 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
|
||||
Init();
|
||||
|
||||
// Determine partitioning size, and my column start and end
|
||||
int part_size;
|
||||
const int part_size = GetPartitioningArraySize(comm);
|
||||
HYPRE_BigInt my_col_start, my_col_end; // my range: [my_col_start, my_col_end)
|
||||
if (HYPRE_AssumedPartitionCheck())
|
||||
{
|
||||
part_size = 2;
|
||||
my_col_start = cols[0];
|
||||
my_col_end = cols[1];
|
||||
}
|
||||
@@ -1259,15 +1297,14 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
|
||||
{
|
||||
int myid;
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
MPI_Comm_size(comm, &part_size);
|
||||
part_size++;
|
||||
my_col_start = cols[myid];
|
||||
my_col_end = cols[myid+1];
|
||||
}
|
||||
|
||||
// Copy in the row and column partitionings
|
||||
const bool rows_eq_cols = RowAndColStartsAreEqual(comm, rows, cols);
|
||||
HYPRE_BigInt *row_starts, *col_starts;
|
||||
if (rows == cols)
|
||||
if (rows_eq_cols)
|
||||
{
|
||||
row_starts = col_starts = mfem_hypre_TAlloc_host(HYPRE_BigInt, part_size);
|
||||
for (int i = 0; i < part_size; i++)
|
||||
@@ -1360,14 +1397,14 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
|
||||
}
|
||||
|
||||
hypre_ParCSRMatrixSetNumNonzeros(A);
|
||||
/* Make sure that the first entry in each row is the diagonal one. */
|
||||
if (row_starts == col_starts)
|
||||
// Make sure that the first entry in each row is the diagonal one.
|
||||
if (rows_eq_cols)
|
||||
{
|
||||
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
|
||||
}
|
||||
#if MFEM_HYPRE_VERSION > 22200
|
||||
mfem_hypre_TFree_host(row_starts);
|
||||
if (rows != cols)
|
||||
if (!rows_eq_cols)
|
||||
{
|
||||
mfem_hypre_TFree_host(col_starts);
|
||||
}
|
||||
@@ -1480,16 +1517,7 @@ void HypreParMatrix::CopyRowStarts()
|
||||
return;
|
||||
}
|
||||
|
||||
int row_starts_size;
|
||||
if (HYPRE_AssumedPartitionCheck())
|
||||
{
|
||||
row_starts_size = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
MPI_Comm_size(hypre_ParCSRMatrixComm(A), &row_starts_size);
|
||||
row_starts_size++; // num_proc + 1
|
||||
}
|
||||
const int row_starts_size = GetPartitioningArraySize(hypre_ParCSRMatrixComm(A));
|
||||
|
||||
HYPRE_BigInt *old_row_starts = hypre_ParCSRMatrixRowStarts(A);
|
||||
HYPRE_BigInt *new_row_starts = mfem_hypre_CTAlloc_host(HYPRE_BigInt,
|
||||
@@ -1520,16 +1548,7 @@ void HypreParMatrix::CopyColStarts()
|
||||
return;
|
||||
}
|
||||
|
||||
int col_starts_size;
|
||||
if (HYPRE_AssumedPartitionCheck())
|
||||
{
|
||||
col_starts_size = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
MPI_Comm_size(hypre_ParCSRMatrixComm(A), &col_starts_size);
|
||||
col_starts_size++; // num_proc + 1
|
||||
}
|
||||
const int col_starts_size = GetPartitioningArraySize(hypre_ParCSRMatrixComm(A));
|
||||
|
||||
HYPRE_BigInt *old_col_starts = hypre_ParCSRMatrixColStarts(A);
|
||||
HYPRE_BigInt *new_col_starts = mfem_hypre_CTAlloc_host(HYPRE_BigInt,
|
||||
@@ -2291,13 +2310,8 @@ void HypreParMatrix::Threshold(real_t threshold)
|
||||
A = parcsr_A_ptr;
|
||||
|
||||
hypre_ParCSRMatrixSetNumNonzeros(A);
|
||||
/* Make sure that the first entry in each row is the diagonal one. */
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
if (row_starts == col_starts)
|
||||
#else
|
||||
if ((row_starts[0] == col_starts[0]) &&
|
||||
(row_starts[1] == col_starts[1]))
|
||||
#endif
|
||||
// Make sure that the first entry in each row is the diagonal one.
|
||||
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
|
||||
{
|
||||
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
|
||||
}
|
||||
@@ -2623,48 +2637,38 @@ void HypreParMatrix::EliminateBC(const Array<int> &ess_dofs,
|
||||
mfem_hypre_TFree(eliminate_col);
|
||||
}
|
||||
|
||||
void HypreParMatrix::Print(const char *fname, HYPRE_Int offi,
|
||||
void HypreParMatrix::Print(const std::string &fname, HYPRE_Int offi,
|
||||
HYPRE_Int offj) const
|
||||
{
|
||||
HostRead();
|
||||
hypre_ParCSRMatrixPrintIJ(A,offi,offj,fname);
|
||||
hypre_ParCSRMatrixPrintIJ(A, offi, offj, fname.c_str());
|
||||
HypreRead();
|
||||
}
|
||||
|
||||
void HypreParMatrix::Read(MPI_Comm comm, const char *fname)
|
||||
void HypreParMatrix::Read(MPI_Comm comm, const std::string &fname)
|
||||
{
|
||||
Destroy();
|
||||
Init();
|
||||
|
||||
HYPRE_ParCSRMatrix A_parcsr;
|
||||
HYPRE_Int base_i, base_j;
|
||||
hypre_ParCSRMatrixReadIJ(comm, fname, &base_i, &base_j, &A);
|
||||
hypre_ParCSRMatrixReadIJ(comm, fname.c_str(), &base_i, &base_j, &A_parcsr);
|
||||
|
||||
WrapHypreParCSRMatrix(A_parcsr, true);
|
||||
|
||||
hypre_ParCSRMatrixSetNumNonzeros(A);
|
||||
|
||||
if (!hypre_ParCSRMatrixCommPkg(A)) { hypre_MatvecCommPkgCreate(A); }
|
||||
|
||||
height = GetNumRows();
|
||||
width = GetNumCols();
|
||||
}
|
||||
|
||||
void HypreParMatrix::Read_IJMatrix(MPI_Comm comm, const char *fname)
|
||||
void HypreParMatrix::Read_IJMatrix(MPI_Comm comm, const std::string &fname)
|
||||
{
|
||||
Destroy();
|
||||
Init();
|
||||
|
||||
HYPRE_IJMatrix A_ij;
|
||||
HYPRE_IJMatrixRead(fname, comm, 5555, &A_ij); // HYPRE_PARCSR = 5555
|
||||
HYPRE_IJMatrixRead(fname.c_str(), comm, 5555, &A_ij); // HYPRE_PARCSR = 5555
|
||||
|
||||
HYPRE_ParCSRMatrix A_parcsr;
|
||||
HYPRE_IJMatrixGetObject(A_ij, (void**) &A_parcsr);
|
||||
|
||||
A = (hypre_ParCSRMatrix*)A_parcsr;
|
||||
WrapHypreParCSRMatrix(A_parcsr, true);
|
||||
|
||||
hypre_ParCSRMatrixSetNumNonzeros(A);
|
||||
|
||||
if (!hypre_ParCSRMatrixCommPkg(A)) { hypre_MatvecCommPkgCreate(A); }
|
||||
|
||||
height = GetNumRows();
|
||||
width = GetNumCols();
|
||||
}
|
||||
|
||||
void HypreParMatrix::PrintCommPkg(std::ostream &os) const
|
||||
|
||||
+8
-6
@@ -364,10 +364,10 @@ public:
|
||||
HYPRE_Int Randomize(HYPRE_Int seed);
|
||||
|
||||
/// Prints the locally owned rows in parallel
|
||||
void Print(const char *fname) const;
|
||||
void Print(const std::string &fname) const;
|
||||
|
||||
/// Reads a HypreParVector from files saved with HypreParVector::Print
|
||||
void Read(MPI_Comm comm, const char *fname);
|
||||
void Read(MPI_Comm comm, const std::string &fname);
|
||||
|
||||
/// Calls hypre's destroy function
|
||||
~HypreParVector();
|
||||
@@ -919,12 +919,14 @@ public:
|
||||
const Memory<HYPRE_Int> &GetDiagMemoryJ() const { return mem_diag.J; }
|
||||
const Memory<real_t> &GetDiagMemoryData() const { return mem_diag.data; }
|
||||
|
||||
/// Prints the locally owned rows in parallel
|
||||
void Print(const char *fname, HYPRE_Int offi = 0, HYPRE_Int offj = 0) const;
|
||||
/// @brief Prints the locally owned rows in parallel. The resulting files can
|
||||
/// be read with Read_IJMatrix().
|
||||
void Print(const std::string &fname, HYPRE_Int offi = 0,
|
||||
HYPRE_Int offj = 0) const;
|
||||
/// Reads the matrix from a file
|
||||
void Read(MPI_Comm comm, const char *fname);
|
||||
void Read(MPI_Comm comm, const std::string &fname);
|
||||
/// Read a matrix saved as a HYPRE_IJMatrix
|
||||
void Read_IJMatrix(MPI_Comm comm, const char *fname);
|
||||
void Read_IJMatrix(MPI_Comm comm, const std::string &fname);
|
||||
|
||||
/// Print information about the hypre_ParCSRCommPkg of the HypreParMatrix.
|
||||
void PrintCommPkg(std::ostream &out = mfem::out) const;
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_LAPACK_HPP
|
||||
#define MFEM_LAPACK_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
#define MFEM_LAPACK_PREFIX(stub) s##stub
|
||||
#define MFEM_LAPACK_COMPLEX(stub) c##stub
|
||||
#elif defined(MFEM_USE_DOUBLE)
|
||||
#define MFEM_LAPACK_PREFIX(stub) d##stub
|
||||
#define MFEM_LAPACK_COMPLEX(stub) z##stub
|
||||
#endif
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(gemm_)(char *, char *, int *, int *, int *, real_t *,
|
||||
real_t *, int *, real_t *, int *, real_t *, real_t *,
|
||||
int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(getrf_)(int *, int *, real_t *, int *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(getrs_)(char *, int *, int *, real_t *, int *, int *,
|
||||
real_t *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(getri_)(int *N, real_t *A, int *LDA, int *IPIV, real_t *WORK,
|
||||
int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(syevr_)(char *JOBZ, char *RANGE, char *UPLO, int *N,
|
||||
real_t *A, int *LDA, real_t *VL, real_t *VU, int *IL,
|
||||
int *IU, real_t *ABSTOL, int *M, real_t *W,
|
||||
real_t *Z, int *LDZ, int *ISUPPZ, real_t *WORK,
|
||||
int *LWORK, int *IWORK, int *LIWORK, int *INFO);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(syev_)(char *JOBZ, char *UPLO, int *N, real_t *A, int *LDA,
|
||||
real_t *W, real_t *WORK, int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(sygv_) (int *ITYPE, char *JOBZ, char *UPLO, int * N,
|
||||
real_t *A, int *LDA, real_t *B, int *LDB, real_t *W,
|
||||
real_t *WORK, int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(sygvx_)(int *ITYPE, char *JOBZ, char *RANGE, char *UPLO,
|
||||
int *N, double *A, int *LDA, double *B, int *LDB,
|
||||
double *VL, double *VU, int *IL, int *IU,
|
||||
double *ABSTOL, int *M, double *W, double *Z,
|
||||
int *LDZ, double *WORK, int *LWORK,int *IWORK,
|
||||
int *IFAIL, int *INFO);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(gesvd_)(char *JOBU, char *JOBVT, int *M, int *N, real_t *A,
|
||||
int *LDA, real_t *S, real_t *U, int *LDU, real_t *VT,
|
||||
int *LDVT, real_t *WORK, int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(trsm_)(char *side, char *uplo, char *transa, char *diag,
|
||||
int *m, int *n, real_t *alpha, real_t *a, int *lda,
|
||||
real_t *b, int *ldb);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(ggev_)(char *jobvl, char *jobvr, int *n, real_t *a, int *lda,
|
||||
real_t *B, int *ldb, real_t *alphar, real_t *alphai,
|
||||
real_t *beta, real_t *vl, int * ldvl, real_t * vr,
|
||||
int * ldvr, real_t * work, int * lwork, int* info);
|
||||
|
||||
// Cholesky factorizations/solves
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(potrf_)(char *, int *, real_t *, int *, int *);
|
||||
// Solve
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(potrs_)(char *, int *, int *, real_t *, int *, real_t *,
|
||||
int *, int *);
|
||||
// Triangular Solves
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(trtrs_)(char *, char*, char *, int *, int *, real_t *, int *,
|
||||
real_t *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(potri_)(char *, int *, real_t *, int*, int *);
|
||||
|
||||
// LAPACK routines for NNLSSolver
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(ormqr_)(char *, char *, int *, int *, int *, real_t *, int*,
|
||||
real_t *, real_t *, int *, real_t *, int*, int*);
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(geqrf_)(int *, int *, real_t *, int *, real_t *, real_t *,
|
||||
int *, int *);
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(gemv_)(char *, int *, int *, real_t *, real_t *, int *,
|
||||
real_t *, int *, real_t *, real_t *, int *);
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(trsm_)(char *side, char *uplo, char *transa, char *diag,
|
||||
int *m, int *n, real_t *alpha, real_t *a, int *lda,
|
||||
real_t *b, int *ldb);
|
||||
|
||||
// Complex
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(getrf_)(int *, int *, std::complex<real_t> *, int *, int *,
|
||||
int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(getrs_)(char *, int *, int *, std::complex<real_t> *, int *,
|
||||
int *, std::complex<real_t> *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(getri_)(int *, std::complex<real_t> *, int *, int *,
|
||||
std::complex<real_t> *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(trsm_)(char *, char *, char *, char *, int *, int *,
|
||||
std::complex<real_t> *, std::complex<real_t> *,
|
||||
int *, std::complex<real_t> *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(potrf_)(char *, int *, std::complex<real_t> *, int *,
|
||||
int *);
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(trtrs_)(char *, char*, char *, int *, int *,
|
||||
std::complex<real_t> *, int *,
|
||||
std::complex<real_t> *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(potri_)(char *, int *, std::complex<real_t> *, int*, int *);
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(potrs_)(char *, int *, int *, std::complex<real_t> *, int *,
|
||||
std::complex<real_t> *, int *, int *);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+130
-52
@@ -309,18 +309,51 @@ public:
|
||||
|
||||
|
||||
/// Base abstract class for first order time dependent operators.
|
||||
/** Operator of the form: (x,t) -> f(x,t), where k = f(x,t) generally solves the
|
||||
algebraic equation F(x,k,t) = G(x,t). The functions F and G represent the
|
||||
_implicit_ and _explicit_ parts of the operator, respectively. For explicit
|
||||
operators, F(x,k,t) = k, so f(x,t) = G(x,t). */
|
||||
/** Operator of the form: (u,t) -> k(u,t), where k generally solves the
|
||||
algebraic equation F(u,k,t) = G(u,t). The functions F and G represent the
|
||||
_implicit_ and _explicit_ parts of the operator, respectively.
|
||||
|
||||
A common use for this class is representing a differential algebraic
|
||||
equation of the form $ F(y,\frac{dy}{dt},t) = G(y,t) $.
|
||||
|
||||
For example, consider an ordinary differential equation of the form
|
||||
$ M \frac{dy}{dt} = g(y,t) $. There are various ways of expressing this ODE
|
||||
as a TimeDependentOperator depending on the choices for F and G. Here are
|
||||
some common choices:
|
||||
|
||||
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t),
|
||||
2. F(u,k,t) = M k and G(u,t) = g(u,t),
|
||||
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0.
|
||||
|
||||
Note that depending on the ODE solver, some of the above choices may be
|
||||
preferable to the others.
|
||||
*/
|
||||
class TimeDependentOperator : public Operator
|
||||
{
|
||||
public:
|
||||
/// Enum used to describe the form of the time-dependent operator.
|
||||
/** The type should be set by classes derived from TimeDependentOperator to
|
||||
describe the form, in terms of the functions F and G, used by the
|
||||
specific derived class. This information can be queried by classes or
|
||||
functions (like time stepping algorithms) to make choices about the
|
||||
algorithm to use, or to ensure that the TimeDependentOperator uses the
|
||||
form expected by the class/function.
|
||||
|
||||
For example, assume that a derived class is implementing the ODE
|
||||
$M \frac{dy}{dt} = g(y,t)$ and chooses to define $F(u,k,t) = M k$ and
|
||||
$G(u,t) = g(u,t)$. Then it cannot use type EXPLICIT, unless $M = I$, or
|
||||
type HOMOGENEOUS, unless $g(u,t) = 0$. If, on the other hand, the derived
|
||||
class chooses to define $F(u,k,t) = k$ and $G(u,t) = M^{-1} g(y,t)$, then
|
||||
the natural choice is to set the type to EXPLICIT, even though setting it
|
||||
to IMPLICIT is also not wrong -- doing so will simply fail to inform
|
||||
methods that query this information that it uses a more specific
|
||||
implementation, EXPLICIT, that may allow the use of algorithms that
|
||||
support only the EXPLICIT type. */
|
||||
enum Type
|
||||
{
|
||||
EXPLICIT, ///< This type assumes F(x,k,t) = k, i.e. k = f(x,t) = G(x,t).
|
||||
EXPLICIT, ///< This type assumes F(u,k,t) = k.
|
||||
IMPLICIT, ///< This is the most general type, no assumptions on F and G.
|
||||
HOMOGENEOUS ///< This type assumes that G(x,t) = 0.
|
||||
HOMOGENEOUS ///< This type assumes that G(u,t) = 0.
|
||||
};
|
||||
|
||||
/// Evaluation mode. See SetEvalMode() for details.
|
||||
@@ -328,29 +361,30 @@ public:
|
||||
{
|
||||
/** Normal evaluation. */
|
||||
NORMAL,
|
||||
/** Assuming additive split, f(x,t) = f1(x,t) + f2(x,t), evaluate the
|
||||
first term, f1. */
|
||||
/** Assuming additive split, k(u,t) = k1(u,t) + k2(u,t), evaluate the
|
||||
first term, k1. */
|
||||
ADDITIVE_TERM_1,
|
||||
/** Assuming additive split, f(x,t) = f1(x,t) + f2(x,t), evaluate the
|
||||
second term, f2. */
|
||||
/** Assuming additive split, k(u,t) = k1(u,t) + k2(u,t), evaluate the
|
||||
second term, k2. */
|
||||
ADDITIVE_TERM_2
|
||||
};
|
||||
|
||||
protected:
|
||||
real_t t; ///< Current time.
|
||||
Type type; ///< Describes the form of the TimeDependentOperator.
|
||||
Type type; /**< @brief Describes the form of the TimeDependentOperator, see
|
||||
the documentation of #Type. */
|
||||
EvalMode eval_mode; ///< Current evaluation mode.
|
||||
|
||||
public:
|
||||
/** @brief Construct a "square" TimeDependentOperator y = f(x,t), where x and
|
||||
y have the same dimension @a n. */
|
||||
/** @brief Construct a "square" TimeDependentOperator (u,t) -> k(u,t), where
|
||||
u and k have the same dimension @a n. */
|
||||
explicit TimeDependentOperator(int n = 0, real_t t_ = 0.0,
|
||||
Type type_ = EXPLICIT)
|
||||
: Operator(n) { t = t_; type = type_; eval_mode = NORMAL; }
|
||||
|
||||
/** @brief Construct a TimeDependentOperator y = f(x,t), where x and y have
|
||||
dimensions @a w and @a h, respectively. */
|
||||
TimeDependentOperator(int h, int w, real_t t_ = 0.0, Type type_ = EXPLICIT)
|
||||
/** @brief Construct a TimeDependentOperator (u,t) -> k(u,t), where u and k
|
||||
have dimensions @a w and @a h, respectively. */
|
||||
TimeDependentOperator(int h, int w, double t_ = 0.0, Type type_ = EXPLICIT)
|
||||
: Operator(h, w) { t = t_; type = type_; eval_mode = NORMAL; }
|
||||
|
||||
/// Read the currently set time.
|
||||
@@ -373,7 +407,7 @@ public:
|
||||
/** The evaluation mode is a switch that allows time-stepping methods to
|
||||
request evaluation of separate components/terms of the time-dependent
|
||||
operator. For example, IMEX methods typically assume additive split of
|
||||
the operator: f(x,t) = f1(x,t) + f2(x,t) and they rely on the ability to
|
||||
the operator: k(u,t) = k1(u,t) + k2(u,t) and they rely on the ability to
|
||||
evaluate the two terms separately.
|
||||
|
||||
Generally, setting the evaluation mode should affect the behavior of all
|
||||
@@ -384,62 +418,104 @@ public:
|
||||
{ eval_mode = new_eval_mode; }
|
||||
|
||||
/** @brief Perform the action of the explicit part of the operator, G:
|
||||
@a y = G(@a x, t) where t is the current time.
|
||||
@a v = G(@a u, t) where t is the current time.
|
||||
|
||||
Presently, this method is used by some PETSc ODE solvers, for more
|
||||
details, see the PETSc Manual. */
|
||||
virtual void ExplicitMult(const Vector &x, Vector &y) const;
|
||||
virtual void ExplicitMult(const Vector &u, Vector &v) const;
|
||||
|
||||
/** @brief Perform the action of the implicit part of the operator, F:
|
||||
@a y = F(@a x, @a k, t) where t is the current time.
|
||||
@a v = F(@a u, @a k, t) where t is the current time.
|
||||
|
||||
Presently, this method is used by some PETSc ODE solvers, for more
|
||||
details, see the PETSc Manual.*/
|
||||
virtual void ImplicitMult(const Vector &x, const Vector &k, Vector &y) const;
|
||||
virtual void ImplicitMult(const Vector &u, const Vector &k, Vector &v) const;
|
||||
|
||||
/** @brief Perform the action of the operator: @a y = k = f(@a x, t), where
|
||||
k solves the algebraic equation F(@a x, k, t) = G(@a x, t) and t is the
|
||||
current time. */
|
||||
virtual void Mult(const Vector &x, Vector &y) const;
|
||||
/** @brief Perform the action of the operator (u,t) -> k(u,t) where t is the
|
||||
current time set by SetTime() and @a k satisfies
|
||||
F(@a u, @a k, t) = G(@a u, t).
|
||||
|
||||
/** @brief Solve the equation: @a k = f(@a x + @a dt @a k, t), for the
|
||||
unknown @a k at the current time t.
|
||||
For solving an ordinary differential equation of the form
|
||||
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined in
|
||||
various ways, e.g.:
|
||||
|
||||
For general F and G, the equation for @a k becomes:
|
||||
F(@a x + @a dt @a k, @a k, t) = G(@a x + @a dt @a k, t).
|
||||
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
|
||||
2. F(u,k,t) = M k and G(u,t) = g(u,t)
|
||||
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0.
|
||||
|
||||
The input vector @a x corresponds to time index (or cycle) n, while the
|
||||
currently set time, #t, and the result vector @a k correspond to time
|
||||
index n+1. The time step @a dt corresponds to the time interval between
|
||||
cycles n and n+1.
|
||||
Regardless of the choice of F and G, this function should always compute
|
||||
@a k = inv(M) g(@a u, t). */
|
||||
virtual void Mult(const Vector &u, Vector &v) const override;
|
||||
|
||||
This method allows for the abstract implementation of some time
|
||||
integration methods, including diagonal implicit Runge-Kutta (DIRK)
|
||||
methods and the backward Euler method in particular.
|
||||
/** @brief Solve for the unknown @a k, at the current time t, the following
|
||||
equation:
|
||||
F(@a u + @a gamma @a k, @a k, t) = G(@a u + @a gamma @a k, t).
|
||||
|
||||
For solving an ordinary differential equation of the form
|
||||
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined in
|
||||
various ways, e.g.:
|
||||
|
||||
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
|
||||
2. F(u,k,t) = M k and G(u,t) = g(u,t)
|
||||
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
|
||||
|
||||
Regardless of the choice of F and G, this function should solve for @a k
|
||||
in M @a k = g(@a u + @a gamma @a k, t).
|
||||
|
||||
To see how @a k can be useful, consider the backward Euler method defined
|
||||
by $ y(t + \Delta t) = y(t) + \Delta t k_0 $ where
|
||||
$ M k_0 = g \big( y(t) + \Delta t k_0, t + \Delta t \big) $. A backward
|
||||
Euler integrator can use @a k from this function for $k_0$, with the call
|
||||
using @a u set to $ y(t) $, @a gamma set to $ \Delta t$, and time set to
|
||||
$t + \Delta t$. See class BackwardEulerSolver.
|
||||
|
||||
Generalizing further, consider a diagonally implicit Runge-Kutta (DIRK)
|
||||
method defined by
|
||||
$ y(t + \Delta t) = y(t) + \Delta t \sum_{i=1}^s b_i k_i $ where
|
||||
$ M k_i = g \big( y(t) + \Delta t \sum_{j=1}^i a_{ij} k_j,
|
||||
t + c_i \Delta t \big) $.
|
||||
A DIRK integrator can use @a k from this function, with @a u set to
|
||||
$ y(t) + \Delta t \sum_{j=1}^{i-1} a_{ij} k_j $ and @a gamma set to
|
||||
$ a_{ii} \Delta t $, for $ k_i $. For example, see class SDIRK33Solver.
|
||||
|
||||
If not re-implemented, this method simply generates an error. */
|
||||
virtual void ImplicitSolve(const real_t dt, const Vector &x, Vector &k);
|
||||
virtual void ImplicitSolve(const real_t gamma, const Vector &u, Vector &k);
|
||||
|
||||
/** @brief Return an Operator representing (dF/dk @a shift + dF/dx) at the
|
||||
given @a x, @a k, and the currently set time.
|
||||
/** @brief Return an Operator representing (dF/dk @a shift + dF/du) at the
|
||||
given @a u, @a k, and the currently set time.
|
||||
|
||||
Presently, this method is used by some PETSc ODE solvers, for more
|
||||
details, see the PETSc Manual. */
|
||||
virtual Operator& GetImplicitGradient(const Vector &x, const Vector &k,
|
||||
virtual Operator& GetImplicitGradient(const Vector &u, const Vector &k,
|
||||
real_t shift) const;
|
||||
|
||||
/** @brief Return an Operator representing dG/dx at the given point @a x and
|
||||
/** @brief Return an Operator representing dG/du at the given point @a u and
|
||||
the currently set time.
|
||||
|
||||
Presently, this method is used by some PETSc ODE solvers, for more
|
||||
details, see the PETSc Manual. */
|
||||
virtual Operator& GetExplicitGradient(const Vector &x) const;
|
||||
virtual Operator& GetExplicitGradient(const Vector &u) const;
|
||||
|
||||
/** @brief Setup the ODE linear system $ A(x,t) = (I - gamma J) $ or
|
||||
$ A = (M - gamma J) $, where $ J(x,t) = \frac{df}{dt(x,t)} $.
|
||||
/** @brief Setup a linear system as needed by some SUNDIALS ODE solvers.
|
||||
|
||||
@param[in] x The state at which $A(x,t)$ should be evaluated.
|
||||
@param[in] fx The current value of the ODE rhs function, $f(x,t)$.
|
||||
For solving an ordinary differential equation of the form
|
||||
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined as one
|
||||
of the following:
|
||||
|
||||
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
|
||||
2. F(u,k,t) = M k and G(u,t) = g(u,t)
|
||||
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
|
||||
|
||||
This function performs setup to solve $ A x = b $ where A is either
|
||||
|
||||
1. A(@a y,t) = I - @a gamma inv(M) J(@a y,t)
|
||||
2. A(@a y,t) = M - @a gamma J(@a y,t)
|
||||
3. A(@a y,t) = M - @a gamma J(@a y,t)
|
||||
|
||||
with J = dg/dy (or a reasonable approximation thereof).
|
||||
|
||||
@param[in] y The state at which A(@a y,t) should be evaluated.
|
||||
@param[in] v The value of inv(M) g(y,t) for 1 or g(y,t) for 2 & 3.
|
||||
@param[in] jok Flag indicating if the Jacobian should be updated.
|
||||
@param[out] jcur Flag to signal if the Jacobian was updated.
|
||||
@param[in] gamma The scaled time step value.
|
||||
@@ -448,10 +524,10 @@ public:
|
||||
|
||||
Presently, this method is used by SUNDIALS ODE solvers, for more
|
||||
details, see the SUNDIALS User Guides. */
|
||||
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
|
||||
virtual int SUNImplicitSetup(const Vector &y, const Vector &v,
|
||||
int jok, int *jcur, real_t gamma);
|
||||
|
||||
/** @brief Solve the ODE linear system $ A x = b $ as setup by
|
||||
/** @brief Solve the ODE linear system A @a x = @a b, where A is defined by
|
||||
the method SUNImplicitSetup().
|
||||
|
||||
@param[in] b The linear system right-hand side.
|
||||
@@ -464,7 +540,8 @@ public:
|
||||
details, see the SUNDIALS User Guides. */
|
||||
virtual int SUNImplicitSolve(const Vector &b, Vector &x, real_t tol);
|
||||
|
||||
/** @brief Setup the mass matrix in the ODE system $ M y' = f(y,t) $ .
|
||||
/** @brief Setup the mass matrix in the ODE system
|
||||
$ M \frac{dy}{dt} = g(y,t) $ .
|
||||
|
||||
If not re-implemented, this method simply generates an error.
|
||||
|
||||
@@ -472,8 +549,8 @@ public:
|
||||
details, see the ARKode User Guide. */
|
||||
virtual int SUNMassSetup();
|
||||
|
||||
/** @brief Solve the mass matrix linear system $ M x = b $
|
||||
as setup by the method SUNMassSetup().
|
||||
/** @brief Solve the mass matrix linear system M @a x = @a b, where M is
|
||||
defined by the method SUNMassSetup().
|
||||
|
||||
@param[in] b The linear system right-hand side.
|
||||
@param[in,out] x On input, the initial guess. On output, the solution.
|
||||
@@ -485,7 +562,8 @@ public:
|
||||
details, see the ARKode User Guide. */
|
||||
virtual int SUNMassSolve(const Vector &b, Vector &x, real_t tol);
|
||||
|
||||
/** @brief Compute the mass matrix-vector product $ v = M x $ .
|
||||
/** @brief Compute the mass matrix-vector product @a v = M @a x, where M is
|
||||
defined by the method SUNMassSetup().
|
||||
|
||||
@param[in] x The vector to multiply.
|
||||
@param[out] v The result of the matrix-vector product.
|
||||
|
||||
+53
-138
@@ -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;
|
||||
|
||||
+14
-5
@@ -58,6 +58,20 @@ DenseSymmetricMatrix &DenseSymmetricMatrix::operator=(real_t c)
|
||||
return *this;
|
||||
}
|
||||
|
||||
DenseSymmetricMatrix &DenseSymmetricMatrix::operator=(const DenseSymmetricMatrix
|
||||
&m)
|
||||
{
|
||||
SetSize(m.height);
|
||||
|
||||
const int hw = m.GetStoredSize();
|
||||
for (int i = 0; i < hw; i++)
|
||||
{
|
||||
data[i] = m.data[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
real_t &DenseSymmetricMatrix::Elem(int i, int j)
|
||||
{
|
||||
return (*this)(i,j);
|
||||
@@ -89,11 +103,6 @@ MatrixInverse *DenseSymmetricMatrix::Inverse() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DenseSymmetricMatrix::Print (std::ostream & os, int width_) const
|
||||
{
|
||||
mfem_error("DenseSymmetricMatrix::Print() not implemented!");
|
||||
}
|
||||
|
||||
DenseSymmetricMatrix::~DenseSymmetricMatrix()
|
||||
{
|
||||
data.Delete();
|
||||
|
||||
+3
-3
@@ -102,6 +102,9 @@ public:
|
||||
|
||||
DenseSymmetricMatrix &operator*=(real_t c);
|
||||
|
||||
/// Sets the matrix size and elements equal to those of m
|
||||
DenseSymmetricMatrix &operator=(const DenseSymmetricMatrix &m);
|
||||
|
||||
std::size_t MemoryUsage() const { return data.Capacity() * sizeof(real_t); }
|
||||
|
||||
/// Shortcut for mfem::Read( GetMemory(), TotalSize(), on_dev).
|
||||
@@ -134,9 +137,6 @@ public:
|
||||
/// Returns a pointer to (an approximation) of the matrix inverse.
|
||||
virtual MatrixInverse *Inverse() const;
|
||||
|
||||
/// Prints matrix to stream out.
|
||||
virtual void Print (std::ostream & out = mfem::out, int width_ = 4) const;
|
||||
|
||||
/// Destroys the symmetric matrix.
|
||||
virtual ~DenseSymmetricMatrix();
|
||||
};
|
||||
|
||||
+43
-11
@@ -466,7 +466,8 @@ void Mesh::GetBdrElementTransformation(int i,
|
||||
{
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
pm(k,j) = nodes(vdofs[n*k+j]);
|
||||
int idx = vdofs[n*k+j];
|
||||
pm(k,j) = nodes((idx<0)? -1-idx:idx);
|
||||
}
|
||||
}
|
||||
ElTr->SetFE(bdr_el);
|
||||
@@ -7131,17 +7132,15 @@ Table *Mesh::GetEdgeVertexTable() const
|
||||
|
||||
Table *Mesh::GetVertexToElementTable()
|
||||
{
|
||||
int i, j, nv, *v;
|
||||
|
||||
Table *vert_elem = new Table;
|
||||
|
||||
vert_elem->MakeI(NumOfVertices);
|
||||
|
||||
for (i = 0; i < NumOfElements; i++)
|
||||
for (int i = 0; i < NumOfElements; i++)
|
||||
{
|
||||
nv = elements[i]->GetNVertices();
|
||||
v = elements[i]->GetVertices();
|
||||
for (j = 0; j < nv; j++)
|
||||
const int nv = elements[i]->GetNVertices();
|
||||
const int *v = elements[i]->GetVertices();
|
||||
for (int j = 0; j < nv; j++)
|
||||
{
|
||||
vert_elem->AddAColumnInRow(v[j]);
|
||||
}
|
||||
@@ -7149,11 +7148,11 @@ Table *Mesh::GetVertexToElementTable()
|
||||
|
||||
vert_elem->MakeJ();
|
||||
|
||||
for (i = 0; i < NumOfElements; i++)
|
||||
for (int i = 0; i < NumOfElements; i++)
|
||||
{
|
||||
nv = elements[i]->GetNVertices();
|
||||
v = elements[i]->GetVertices();
|
||||
for (j = 0; j < nv; j++)
|
||||
const int nv = elements[i]->GetNVertices();
|
||||
const int *v = elements[i]->GetVertices();
|
||||
for (int j = 0; j < nv; j++)
|
||||
{
|
||||
vert_elem->AddConnection(v[j], i);
|
||||
}
|
||||
@@ -7164,6 +7163,39 @@ Table *Mesh::GetVertexToElementTable()
|
||||
return vert_elem;
|
||||
}
|
||||
|
||||
Table *Mesh::GetVertexToBdrElementTable()
|
||||
{
|
||||
Table *vert_bdr_elem = new Table;
|
||||
|
||||
vert_bdr_elem->MakeI(NumOfVertices);
|
||||
|
||||
for (int i = 0; i < NumOfBdrElements; i++)
|
||||
{
|
||||
const int nv = boundary[i]->GetNVertices();
|
||||
const int *v = boundary[i]->GetVertices();
|
||||
for (int j = 0; j < nv; j++)
|
||||
{
|
||||
vert_bdr_elem->AddAColumnInRow(v[j]);
|
||||
}
|
||||
}
|
||||
|
||||
vert_bdr_elem->MakeJ();
|
||||
|
||||
for (int i = 0; i < NumOfBdrElements; i++)
|
||||
{
|
||||
const int nv = boundary[i]->GetNVertices();
|
||||
const int *v = boundary[i]->GetVertices();
|
||||
for (int j = 0; j < nv; j++)
|
||||
{
|
||||
vert_bdr_elem->AddConnection(v[j], i);
|
||||
}
|
||||
}
|
||||
|
||||
vert_bdr_elem->ShiftUpI();
|
||||
|
||||
return vert_bdr_elem;
|
||||
}
|
||||
|
||||
Table *Mesh::GetFaceToElementTable() const
|
||||
{
|
||||
Table *face_elem = new Table;
|
||||
|
||||
+6
-1
@@ -857,7 +857,9 @@ public:
|
||||
vectors using Mesh::CreatePeriodicVertexMapping.
|
||||
@note MFEM requires that each edge of the resulting mesh be uniquely
|
||||
identifiable by a pair of distinct vertices. As a consequence, periodic
|
||||
boundaries must be connected by at least three edges. */
|
||||
boundaries must be separated by at least two interior vertices.
|
||||
@note The resulting mesh uses a discontinuous nodal function, see
|
||||
SetCurvature() for further details. */
|
||||
static Mesh MakePeriodic(const Mesh &orig_mesh, const std::vector<int> &v2v);
|
||||
|
||||
///@}
|
||||
@@ -1535,6 +1537,9 @@ public:
|
||||
/// @note The returned Table should be deleted by the caller
|
||||
Table *GetVertexToElementTable();
|
||||
|
||||
/// @note The returned Table should be deleted by the caller
|
||||
Table *GetVertexToBdrElementTable();
|
||||
|
||||
/// Return the "face"-element Table. Here "face" refers to face (3D),
|
||||
/// edge (2D), or vertex (1D).
|
||||
///
|
||||
|
||||
+16
-4
@@ -1151,15 +1151,24 @@ void Mesh::ReadXML_VTKMesh(std::istream &input, int &curved, int &read_gf,
|
||||
}
|
||||
if (cells_xml == NULL) { MFEM_ABORT(erstr); }
|
||||
|
||||
// Read the element attributes, which are stored as CellData named "material"
|
||||
// Read the element attributes, which are stored as CellData named either
|
||||
// "material" or "attribute". We prioritize "material" over "attribute" for
|
||||
// backwards compatibility.
|
||||
Array<int> cell_attributes;
|
||||
bool found_attributes = false;
|
||||
for (const XMLElement *cell_data_xml = piece->FirstChildElement();
|
||||
cell_data_xml != NULL;
|
||||
cell_data_xml = cell_data_xml->NextSiblingElement())
|
||||
{
|
||||
if (StringCompare(cell_data_xml->Name(), "CellData")
|
||||
&& StringCompare(cell_data_xml->Attribute("Scalars"), "material"))
|
||||
const bool is_cell_data =
|
||||
StringCompare(cell_data_xml->Name(), "CellData");
|
||||
const bool is_material =
|
||||
StringCompare(cell_data_xml->Attribute("Scalars"), "material");
|
||||
const bool is_attribute =
|
||||
StringCompare(cell_data_xml->Attribute("Scalars"), "attribute");
|
||||
if (is_cell_data && (is_material || (is_attribute && !found_attributes)))
|
||||
{
|
||||
found_attributes = true;
|
||||
const XMLElement *data_xml = cell_data_xml->FirstChildElement();
|
||||
if (data_xml != NULL && StringCompare(data_xml->Name(), "DataArray"))
|
||||
{
|
||||
@@ -1274,6 +1283,7 @@ void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf,
|
||||
// Read the cell materials
|
||||
// bool found_material = false;
|
||||
Array<int> cell_attributes;
|
||||
bool found_attributes = false;
|
||||
while ((input.good()))
|
||||
{
|
||||
getline(input, buff);
|
||||
@@ -1281,8 +1291,10 @@ void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf,
|
||||
{
|
||||
break; // We have entered the POINT_DATA block. Quit.
|
||||
}
|
||||
else if (buff.rfind("SCALARS material") == 0)
|
||||
else if (buff.rfind("SCALARS material") == 0 ||
|
||||
(buff.rfind("SCALARS attribute") == 0 && !found_attributes))
|
||||
{
|
||||
found_attributes = true;
|
||||
getline(input, buff); // LOOKUP_TABLE default
|
||||
if (buff.rfind("LOOKUP_TABLE default") != 0)
|
||||
{
|
||||
|
||||
+103
-18
@@ -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
|
||||
|
||||
@@ -37,3 +37,4 @@ add_subdirectory(tribol)
|
||||
add_subdirectory(hooke)
|
||||
add_subdirectory(dpg)
|
||||
add_subdirectory(hdiv-linear-solver)
|
||||
add_subdirectory(stabilized)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,17 +11,17 @@
|
||||
//
|
||||
// MFEM Ultraweak DPG parallel example for convection-diffusion
|
||||
//
|
||||
// Compile with: make pconvection-diffusion
|
||||
// Compile with: make pconvection-diffusion
|
||||
//
|
||||
// sample runs
|
||||
// mpirun -np 4 pconvection-diffusion -o 2 -ref 3 -prob 0 -eps 1e-1 -beta '4 2' -theta 0.0
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 3 -prob 0 -eps 1e-2 -beta '2 3' -theta 0.0
|
||||
// mpirun -np 4 pconvection-diffusion -m ../../data/inline-hex.mesh -o 2 -ref 1 -prob 0 -sc -eps 1e-1 -theta 0.0
|
||||
// mpirun -np 4 pconvection-diffusion -o 2 -ref 3 -prob 0 -eps 1e-1 -beta '4 2' -theta 0.0
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 3 -prob 0 -eps 1e-2 -beta '2 3' -theta 0.0
|
||||
// mpirun -np 4 pconvection-diffusion -m ../../data/inline-hex.mesh -o 2 -ref 1 -prob 0 -sc -eps 1e-1 -theta 0.0
|
||||
|
||||
// AMR runs
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 10 -prob 1 -eps 1e-3 -beta '1 0' -theta 0.7 -sc
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 15 -prob 2 -eps 5e-3 -theta 0.7 -sc
|
||||
// mpirun -np 4 pconvection-diffusion -o 2 -ref 12 -prob 3 -eps 1e-2 -beta '1 2' -theta 0.7 -sc
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 10 -prob 1 -eps 1e-3 -beta '1 0' -theta 0.7 -sc
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 15 -prob 2 -eps 5e-3 -theta 0.7 -sc
|
||||
// mpirun -np 4 pconvection-diffusion -o 2 -ref 12 -prob 3 -eps 1e-2 -beta '1 2' -theta 0.7 -sc
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve a parallel
|
||||
|
||||
@@ -14,18 +14,18 @@
|
||||
// Compile with: make pdiffusion
|
||||
//
|
||||
// Sample runs
|
||||
// mpirun -np 4 pdiffusion -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 2 -theta 0.0 -prob 0
|
||||
// mpirun -np 4 pdiffusion -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -theta 0.0 -prob 0 -sc
|
||||
// mpirun -np 4 pdiffusion -m ../../data/beam-tet.mesh -o 3 -sref 0 -pref 2 -theta 0.0 -prob 0 -sc
|
||||
// mpirun -np 4 pdiffusion -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 2 -theta 0.0 -prob 0
|
||||
// mpirun -np 4 pdiffusion -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -theta 0.0 -prob 0 -sc
|
||||
// mpirun -np 4 pdiffusion -m ../../data/beam-tet.mesh -o 3 -sref 0 -pref 2 -theta 0.0 -prob 0 -sc
|
||||
|
||||
// L-shape runs
|
||||
// Note: uniform ref are expected to give sub-optimal rate for the L-shape problem (rate = 2/3)
|
||||
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 5 -theta 0.0 -prob 1
|
||||
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 5 -theta 0.0 -prob 1
|
||||
|
||||
// L-shape AMR runs
|
||||
// mpirun -np 4 pdiffusion -o 1 -sref 1 -pref 10 -theta 0.8 -prob 1
|
||||
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 8 -theta 0.75 -prob 1 -sc
|
||||
// mpirun -np 4 pdiffusion -o 3 -sref 1 -pref 6 -theta 0.75 -prob 1 -sc -do 2
|
||||
// mpirun -np 4 pdiffusion -o 1 -sref 1 -pref 10 -theta 0.8 -prob 1
|
||||
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 8 -theta 0.75 -prob 1 -sc
|
||||
// mpirun -np 4 pdiffusion -o 3 -sref 1 -pref 6 -theta 0.75 -prob 1 -sc -do 2
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
// Compile with: make pmaxwell
|
||||
//
|
||||
// sample run
|
||||
// mpirun -np 4 pmaxwell -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4
|
||||
// mpirun -np 4 pmaxwell -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4
|
||||
|
||||
// AMR run. Note that this is a computationally intensive sample run.
|
||||
// We recommend trying it on a large machine with more mpi ranks
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve
|
||||
|
||||
@@ -206,7 +206,7 @@ int main (int argc, char *argv[])
|
||||
solver.SetMaxIter(200);
|
||||
solver.SetRelTol(1e-10);
|
||||
solver.SetAbsTol(0.0);
|
||||
solver.EnableAdaptiveSurfaceFitting();
|
||||
solver.SetAdaptiveSurfaceFittingScalingFactor(10);
|
||||
solver.SetTerminationWithMaxSurfaceFittingError(1e-3);
|
||||
|
||||
// Solve.
|
||||
|
||||
@@ -34,6 +34,22 @@ real_t circle_level_set(const Vector &x)
|
||||
}
|
||||
}
|
||||
|
||||
real_t squircle_level_set(const Vector &x)
|
||||
{
|
||||
const int dim = x.Size();
|
||||
if (dim == 2)
|
||||
{
|
||||
const real_t xc = x(0) - 0.5, yc = x(1) - 0.5;
|
||||
return std::pow(xc, 4.0) + std::pow(yc, 4.0) - std::pow(0.24, 4.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
const real_t xc = x(0) - 0.5, yc = x(1) - 0.5, zc = x(2) - 0.5;
|
||||
return std::pow(xc, 4.0) + std::pow(yc, 4.0) +
|
||||
std::pow(zc, 4.0) - std::pow(0.24, 4.0);
|
||||
}
|
||||
}
|
||||
|
||||
real_t in_circle(const Vector &x, const Vector &x_center, real_t radius)
|
||||
{
|
||||
Vector x_current = x;
|
||||
|
||||
@@ -33,13 +33,15 @@
|
||||
// Compile with: make pmesh-fitting
|
||||
//
|
||||
// Sample runs:
|
||||
// Interface fitting:
|
||||
// mpirun -np 4 pmesh-fitting -o 3 -mid 58 -tid 1 -ni 200 -vl 1 -sfc 5e4 -rtol 1e-5
|
||||
// mpirun -np 4 pmesh-fitting -m square01-tri.mesh -o 3 -rs 0 -mid 58 -tid 1 -ni 200 -vl 1 -sfc 1e4 -rtol 1e-5
|
||||
// Surface fitting:
|
||||
// mpirun -np 4 pmesh-fitting -o 3 -mid 58 -tid 1 -vl 1 -sfc 5e4 -rtol 1e-5
|
||||
// mpirun -np 4 pmesh-fitting -m square01-tri.mesh -o 3 -rs 0 -mid 58 -tid 1 -vl 1 -sfc 1e4 -rtol 1e-5
|
||||
// Surface fitting with weight adaptation and termination based on fitting error:
|
||||
// mpirun -np 4 pmesh-fitting -o 2 -mid 2 -tid 1 -ni 100 -vl 2 -sfc 10 -rtol 1e-20 -st 0 -sfa 10.0 -sft 1e-5
|
||||
// Fitting to Fischer-Tropsch reactor like domain (requires GSLIB):
|
||||
// * mpirun -np 6 pmesh-fitting -m ../../data/inline-tri.mesh -o 2 -rs 4 -mid 2 -tid 1 -vl 2 -sfc 100 -rtol 1e-12 -ni 100 -li 40 -ae 1 -bnd -sbgmesh -slstype 2 -smtype 0 -sfa 10.0 -sft 1e-4 -amriter 5 -dist -mod-bndr-attr
|
||||
// mpirun -np 4 pmesh-fitting -o 2 -mid 2 -tid 1 -vl 2 -sfc 10 -rtol 1e-20 -sfa 10.0 -sft 1e-5 -no-resid
|
||||
// Surface fitting with weight adaptation, limit on max weight, and convergence based on residual.
|
||||
// * mpirun -np 4 pmesh-fitting -m ../../data/inline-tri.mesh -o 2 -mid 2 -tid 4 -vl 2 -sfc 10 -rtol 1e-10 -sfa 10.0 -sft 1e-5 -bgamriter 3 -sbgmesh -ae 1 -marking -slstype 3 -resid -sfcmax 10000 -mod-bndr-attr
|
||||
// Surface fitting to Fischer-Tropsch reactor like domain (requires GSLIB):
|
||||
// * mpirun -np 6 pmesh-fitting -m ../../data/inline-tri.mesh -o 2 -rs 4 -mid 2 -tid 1 -vl 2 -sfc 100 -rtol 1e-12 -li 20 -ae 1 -bnd -sbgmesh -slstype 2 -smtype 0 -sfa 10.0 -sft 1e-4 -no-resid -bgamriter 5 -dist -mod-bndr-attr
|
||||
|
||||
#include "mesh-fitting.hpp"
|
||||
|
||||
@@ -48,12 +50,16 @@ using namespace std;
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// 0. Initialize MPI and HYPRE.
|
||||
#ifdef HYPRE_USING_GPU
|
||||
cout << "\nThis miniapp is NOT supported with the GPU version of hypre.\n\n";
|
||||
return MFEM_SKIP_RETURN_VALUE;
|
||||
#endif
|
||||
|
||||
Mpi::Init(argc, argv);
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
// 1. Set the method's default parameters.
|
||||
// Set the method's default parameters.
|
||||
const char *mesh_file = "square01.mesh";
|
||||
int mesh_poly_deg = 1;
|
||||
int rs_levels = 1;
|
||||
@@ -61,7 +67,6 @@ int main (int argc, char *argv[])
|
||||
int metric_id = 2;
|
||||
int target_id = 1;
|
||||
real_t surface_fit_const = 100.0;
|
||||
int quad_type = 1;
|
||||
int quad_order = 8;
|
||||
int solver_type = 0;
|
||||
int solver_iter = 20;
|
||||
@@ -70,27 +75,28 @@ int main (int argc, char *argv[])
|
||||
#else
|
||||
real_t solver_rtol = 1e-10;
|
||||
#endif
|
||||
int solver_art_type = 0;
|
||||
int lin_solver = 2;
|
||||
int max_lin_iter = 100;
|
||||
bool move_bnd = true;
|
||||
bool visualization = true;
|
||||
bool visualization = false;
|
||||
int verbosity_level = 0;
|
||||
int adapt_eval = 0;
|
||||
const char *devopt = "cpu";
|
||||
real_t surface_fit_adapt = 0.0;
|
||||
real_t surface_fit_threshold = -10;
|
||||
real_t surf_fit_const_max = 1e20;
|
||||
bool adapt_marking = false;
|
||||
bool surf_bg_mesh = false;
|
||||
bool comp_dist = false;
|
||||
int surf_ls_type = 1;
|
||||
int marking_type = 0;
|
||||
bool mod_bndr_attr = false;
|
||||
bool material = false;
|
||||
bool surf_bg_mesh = false;
|
||||
bool comp_dist = false;
|
||||
int surf_ls_type = 1;
|
||||
int marking_type = 0;
|
||||
bool mod_bndr_attr = false;
|
||||
bool material = false;
|
||||
int mesh_node_ordering = 0;
|
||||
int amr_iters = 0;
|
||||
int bg_amr_iters = 0;
|
||||
bool conv_residual = true;
|
||||
|
||||
// 2. Parse command-line options.
|
||||
// Parse command-line options.
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
@@ -111,11 +117,6 @@ int main (int argc, char *argv[])
|
||||
"5: Ideal shape, given size (in physical space)");
|
||||
args.AddOption(&surface_fit_const, "-sfc", "--surface-fit-const",
|
||||
"Surface preservation constant.");
|
||||
args.AddOption(&quad_type, "-qt", "--quad-type",
|
||||
"Quadrature rule type:\n\t"
|
||||
"1: Gauss-Lobatto\n\t"
|
||||
"2: Gauss-Legendre\n\t"
|
||||
"3: Closed uniform points");
|
||||
args.AddOption(&quad_order, "-qo", "--quad_order",
|
||||
"Order of the quadrature rule.");
|
||||
args.AddOption(&solver_type, "-st", "--solver-type",
|
||||
@@ -124,11 +125,6 @@ int main (int argc, char *argv[])
|
||||
"Maximum number of Newton iterations.");
|
||||
args.AddOption(&solver_rtol, "-rtol", "--newton-rel-tolerance",
|
||||
"Relative tolerance for the Newton solver.");
|
||||
args.AddOption(&solver_art_type, "-art", "--adaptive-rel-tol",
|
||||
"Type of adaptive relative linear solver tolerance:\n\t"
|
||||
"0: None (default)\n\t"
|
||||
"1: Eisenstat-Walker type 1\n\t"
|
||||
"2: Eisenstat-Walker type 2");
|
||||
args.AddOption(&lin_solver, "-ls", "--lin-solver",
|
||||
"Linear solver:\n\t"
|
||||
"0: l1-Jacobi\n\t"
|
||||
@@ -151,10 +147,12 @@ int main (int argc, char *argv[])
|
||||
args.AddOption(&devopt, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&surface_fit_adapt, "-sfa", "--adaptive-surface-fit",
|
||||
"Enable or disable adaptive surface fitting.");
|
||||
"Scaling factor for surface fitting weight.");
|
||||
args.AddOption(&surface_fit_threshold, "-sft", "--surf-fit-threshold",
|
||||
"Set threshold for surface fitting. TMOP solver will"
|
||||
"terminate when max surface fitting error is below this limit");
|
||||
args.AddOption(&surf_fit_const_max, "-sfcmax", "--surf-fit-const-max",
|
||||
"Max surface fitting weight allowed");
|
||||
args.AddOption(&adapt_marking, "-marking", "--adaptive-marking", "-no-amarking",
|
||||
"--no-adaptive-marking",
|
||||
"Enable or disable adaptive marking surface fitting.");
|
||||
@@ -165,9 +163,9 @@ int main (int argc, char *argv[])
|
||||
"-no-dist","--no-comp-dist",
|
||||
"Compute distance from 0 level set or not.");
|
||||
args.AddOption(&surf_ls_type, "-slstype", "--surf-ls-type",
|
||||
"1 - Circle (DEFAULT), 2 - Squircle, 3 - Butterfly.");
|
||||
"1 - Circle (DEFAULT), 2 - reactor level-set, 3 - squircle.");
|
||||
args.AddOption(&marking_type, "-smtype", "--surf-marking-type",
|
||||
"1 - Interface (DEFAULT), 2 - Boundary attribute.");
|
||||
"0 - Interface (DEFAULT), otherwise Boundary attribute.");
|
||||
args.AddOption(&mod_bndr_attr, "-mod-bndr-attr", "--modify-boundary-attribute",
|
||||
"-fix-bndr-attr", "--fix-boundary-attribute",
|
||||
"Change boundary attribute based on alignment with Cartesian axes.");
|
||||
@@ -176,8 +174,11 @@ int main (int argc, char *argv[])
|
||||
args.AddOption(&mesh_node_ordering, "-mno", "--mesh_node_ordering",
|
||||
"Ordering of mesh nodes."
|
||||
"0 (default): byNodes, 1: byVDIM");
|
||||
args.AddOption(&amr_iters, "-amriter", "--amr-iter",
|
||||
args.AddOption(&bg_amr_iters, "-bgamriter", "--amr-iter",
|
||||
"Number of amr iterations on background mesh");
|
||||
args.AddOption(&conv_residual, "-resid", "--resid", "-no-resid",
|
||||
"--no-resid",
|
||||
"Enable residual based convergence.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
@@ -189,7 +190,11 @@ int main (int argc, char *argv[])
|
||||
Device device(devopt);
|
||||
if (myid == 0) { device.Print();}
|
||||
|
||||
// 3. Initialize and refine the starting mesh.
|
||||
MFEM_VERIFY(surface_fit_const > 0.0,
|
||||
"This miniapp is for surface fitting only. See (p)mesh-optimizer"
|
||||
"miniapps for general high-order mesh optimization.");
|
||||
|
||||
// Initialize and refine the starting mesh.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1, false);
|
||||
for (int lev = 0; lev < rs_levels; lev++)
|
||||
{
|
||||
@@ -207,6 +212,10 @@ int main (int argc, char *argv[])
|
||||
{
|
||||
ls_coeff = new FunctionCoefficient(reactor);
|
||||
}
|
||||
else if (surf_ls_type == 3) //squircle
|
||||
{
|
||||
ls_coeff = new FunctionCoefficient(squircle_level_set);
|
||||
}
|
||||
else if (surf_ls_type == 6) // 3D shape
|
||||
{
|
||||
ls_coeff = new FunctionCoefficient(csg_cubecylsph);
|
||||
@@ -220,7 +229,7 @@ int main (int argc, char *argv[])
|
||||
delete mesh;
|
||||
for (int lev = 0; lev < rp_levels; lev++) { pmesh->UniformRefinement(); }
|
||||
|
||||
// 4. Setup background mesh for surface fitting
|
||||
// Setup background mesh for surface fitting
|
||||
ParMesh *pmesh_surf_fit_bg = NULL;
|
||||
if (surf_bg_mesh)
|
||||
{
|
||||
@@ -240,10 +249,10 @@ int main (int argc, char *argv[])
|
||||
delete mesh_surf_fit_bg;
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use vector finite
|
||||
// elements which are tensor products of quadratic finite elements. The
|
||||
// number of components in the vector finite element space is specified by
|
||||
// the last parameter of the FiniteElementSpace constructor.
|
||||
// Define a finite element space on the mesh. Here we use vector finite
|
||||
// elements which are tensor products of quadratic finite elements. The
|
||||
// number of components in the vector finite element space is specified by
|
||||
// the last parameter of the FiniteElementSpace constructor.
|
||||
FiniteElementCollection *fec;
|
||||
if (mesh_poly_deg <= 0)
|
||||
{
|
||||
@@ -254,21 +263,21 @@ int main (int argc, char *argv[])
|
||||
ParFiniteElementSpace *pfespace =
|
||||
new ParFiniteElementSpace(pmesh, fec, dim, mesh_node_ordering);
|
||||
|
||||
// 6. Make the mesh curved based on the above finite element space. This
|
||||
// means that we define the mesh elements through a fespace-based
|
||||
// transformation of the reference element.
|
||||
// Make the mesh curved based on the above finite element space. This
|
||||
// means that we define the mesh elements through a fespace-based
|
||||
// transformation of the reference element.
|
||||
pmesh->SetNodalFESpace(pfespace);
|
||||
|
||||
// 7. Get the mesh nodes (vertices and other degrees of freedom in the finite
|
||||
// element space) as a finite element grid function in fespace. Note that
|
||||
// changing x automatically changes the shapes of the mesh elements.
|
||||
// Get the mesh nodes (vertices and other degrees of freedom in the finite
|
||||
// element space) as a finite element grid function in fespace. Note that
|
||||
// changing x automatically changes the shapes of the mesh elements.
|
||||
ParGridFunction x(pfespace);
|
||||
pmesh->SetNodalGridFunction(&x);
|
||||
x.SetTrueVector();
|
||||
|
||||
// 10. Save the starting (prior to the optimization) mesh to a file. This
|
||||
// output can be viewed later using GLVis: "glvis -m perturbed -np
|
||||
// num_mpi_tasks".
|
||||
// Save the starting (prior to the optimization) mesh to a file. This
|
||||
// output can be viewed later using GLVis: "glvis -m perturbed -np
|
||||
// num_mpi_tasks".
|
||||
{
|
||||
ostringstream mesh_name;
|
||||
mesh_name << "perturbed.mesh";
|
||||
@@ -326,16 +335,7 @@ int main (int argc, char *argv[])
|
||||
TMOP_Integrator *tmop_integ = new TMOP_Integrator(metric, target_c);
|
||||
|
||||
// Setup the quadrature rules for the TMOP integrator.
|
||||
IntegrationRules *irules = NULL;
|
||||
switch (quad_type)
|
||||
{
|
||||
case 1: irules = &IntRulesLo; break;
|
||||
case 2: irules = &IntRules; break;
|
||||
case 3: irules = &IntRulesCU; break;
|
||||
default:
|
||||
if (myid == 0) { cout << "Unknown quad_type: " << quad_type << endl; }
|
||||
return 3;
|
||||
}
|
||||
IntegrationRules *irules = &IntRulesLo;
|
||||
tmop_integ->SetIntegrationRules(*irules, quad_order);
|
||||
if (myid == 0 && dim == 2)
|
||||
{
|
||||
@@ -423,7 +423,7 @@ int main (int argc, char *argv[])
|
||||
if (surf_bg_mesh)
|
||||
{
|
||||
OptimizeMeshWithAMRAroundZeroLevelSet(*pmesh_surf_fit_bg, *ls_coeff,
|
||||
amr_iters, *surf_fit_bg_gf0);
|
||||
bg_amr_iters, *surf_fit_bg_gf0);
|
||||
pmesh_surf_fit_bg->Rebalance();
|
||||
surf_fit_bg_fes->Update();
|
||||
surf_fit_bg_gf0->Update();
|
||||
@@ -505,6 +505,7 @@ int main (int argc, char *argv[])
|
||||
ModifyAttributeForMarkingDOFS(pmesh, mat, 0);
|
||||
ModifyAttributeForMarkingDOFS(pmesh, mat, 1);
|
||||
}
|
||||
pmesh->SetAttributes();
|
||||
|
||||
GridFunctionCoefficient coeff_mat(&mat);
|
||||
surf_fit_mat_gf.ProjectDiscCoefficient(coeff_mat,
|
||||
@@ -579,6 +580,22 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// Unify marker across processor boundary
|
||||
surf_fit_mat_gf.ExchangeFaceNbrData();
|
||||
{
|
||||
GroupCommunicator &gcomm = surf_fit_mat_gf.ParFESpace()->GroupComm();
|
||||
Array<real_t> gf_array(surf_fit_mat_gf.GetData(),
|
||||
surf_fit_mat_gf.Size());
|
||||
gcomm.Reduce<real_t>(gf_array, GroupCommunicator::Max);
|
||||
gcomm.Bcast(gf_array);
|
||||
}
|
||||
surf_fit_mat_gf.ExchangeFaceNbrData();
|
||||
|
||||
for (int i = 0; i < surf_fit_mat_gf.Size(); i++)
|
||||
{
|
||||
surf_fit_marker[i] = surf_fit_mat_gf(i) == 1.0;
|
||||
}
|
||||
|
||||
// Set AdaptivityEvaluators for transferring information from initial
|
||||
// mesh to current mesh as it moves during adaptivity.
|
||||
if (adapt_eval == 0)
|
||||
@@ -590,11 +607,8 @@ int main (int argc, char *argv[])
|
||||
{
|
||||
#ifdef MFEM_USE_GSLIB
|
||||
adapt_surface = new InterpolatorFP;
|
||||
if (surf_bg_mesh)
|
||||
{
|
||||
adapt_grad_surface = new InterpolatorFP;
|
||||
adapt_hess_surface = new InterpolatorFP;
|
||||
}
|
||||
adapt_grad_surface = new InterpolatorFP;
|
||||
adapt_hess_surface = new InterpolatorFP;
|
||||
#else
|
||||
MFEM_ABORT("MFEM is not built with GSLIB support!");
|
||||
#endif
|
||||
@@ -604,7 +618,9 @@ int main (int argc, char *argv[])
|
||||
if (!surf_bg_mesh)
|
||||
{
|
||||
tmop_integ->EnableSurfaceFitting(surf_fit_gf0, surf_fit_marker,
|
||||
surf_fit_coeff, *adapt_surface);
|
||||
surf_fit_coeff, *adapt_surface,
|
||||
adapt_grad_surface,
|
||||
adapt_hess_surface);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -632,16 +648,9 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
}
|
||||
pmesh->SetAttributes();
|
||||
|
||||
// 13. Setup the final NonlinearForm (which defines the integral of interest,
|
||||
// its first and second derivatives). Here we can use a combination of
|
||||
// metrics, i.e., optimize the sum of two integrals, where both are
|
||||
// scaled by used-defined space-dependent weights. Note that there are
|
||||
// no command-line options for the weights and the type of the second
|
||||
// metric; one should update those in the code.
|
||||
// Setup the final NonlinearForm.
|
||||
ParNonlinearForm a(pfespace);
|
||||
ConstantCoefficient *metric_coeff1 = NULL;
|
||||
a.AddDomainIntegrator(tmop_integ);
|
||||
|
||||
// Compute the minimum det(J) of the starting mesh.
|
||||
@@ -674,10 +683,10 @@ int main (int argc, char *argv[])
|
||||
surf_fit_coeff.constant = surface_fit_const;
|
||||
}
|
||||
|
||||
// 14. Fix all boundary nodes, or fix only a given component depending on the
|
||||
// boundary attributes of the given mesh. Attributes 1/2/3 correspond to
|
||||
// fixed x/y/z components of the node. Attribute dim+1 corresponds to
|
||||
// an entirely fixed node.
|
||||
// Fix all boundary nodes, or fix only a given component depending on the
|
||||
// boundary attributes of the given mesh. Attributes 1/2/3 correspond to
|
||||
// fixed x/y/z components of the node. Attribute dim+1 corresponds to
|
||||
// an entirely fixed node.
|
||||
if (move_bnd == false)
|
||||
{
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
@@ -733,8 +742,7 @@ int main (int argc, char *argv[])
|
||||
a.SetEssentialVDofs(ess_vdofs);
|
||||
}
|
||||
|
||||
// 15. As we use the Newton method to solve the resulting nonlinear system,
|
||||
// here we setup the linear solver for the system's Jacobian.
|
||||
// Setup the linear solver for the system's Jacobian.
|
||||
Solver *S = NULL, *S_prec = NULL;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
const real_t linsol_rtol = 1e-5;
|
||||
@@ -784,8 +792,14 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
if (surface_fit_threshold > 0)
|
||||
{
|
||||
solver.SetTerminationWithMaxSurfaceFittingError(surface_fit_threshold);
|
||||
solver.SetSurfaceFittingMaxErrorLimit(surface_fit_threshold);
|
||||
}
|
||||
solver.SetSurfaceFittingConvergenceBasedOnError(!conv_residual);
|
||||
if (conv_residual)
|
||||
{
|
||||
solver.SetSurfaceFittingWeightLimit(surf_fit_const_max);
|
||||
}
|
||||
|
||||
// Provide all integration rules in case of a mixed mesh.
|
||||
solver.SetIntegrationRules(*irules, quad_order);
|
||||
if (solver_type == 0)
|
||||
@@ -797,18 +811,14 @@ int main (int argc, char *argv[])
|
||||
solver.SetRelTol(solver_rtol);
|
||||
solver.SetAbsTol(0.0);
|
||||
solver.SetMinimumDeterminantThreshold(0.001*min_detJ);
|
||||
if (solver_art_type > 0)
|
||||
{
|
||||
solver.SetAdaptiveLinRtol(solver_art_type, 0.5, 0.9);
|
||||
}
|
||||
solver.SetPrintLevel(verbosity_level >= 1 ? 1 : -1);
|
||||
solver.SetOperator(a);
|
||||
Vector b(0);
|
||||
solver.Mult(b, x.GetTrueVector());
|
||||
x.SetFromTrueVector();
|
||||
|
||||
// 16. Save the optimized mesh to a file. This output can be viewed later
|
||||
// using GLVis: "glvis -m optimized -np num_mpi_tasks".
|
||||
// Save the optimized mesh to a file. This output can be viewed later
|
||||
// using GLVis: "glvis -m optimized -np num_mpi_tasks".
|
||||
{
|
||||
ostringstream mesh_name;
|
||||
mesh_name << "optimized.mesh";
|
||||
@@ -842,9 +852,13 @@ int main (int argc, char *argv[])
|
||||
|
||||
if (surface_fit_const > 0.0)
|
||||
{
|
||||
adapt_surface->ComputeAtNewPosition(x, surf_fit_gf0,
|
||||
x.FESpace()->GetOrdering());
|
||||
if (visualization)
|
||||
{
|
||||
socketstream vis2, vis3;
|
||||
socketstream vis1, vis2, vis3;
|
||||
common::VisualizeField(vis1, "localhost", 19916, surf_fit_gf0,
|
||||
"Level Set", 000, 400, 300, 300);
|
||||
common::VisualizeField(vis2, "localhost", 19916, mat,
|
||||
"Materials", 300, 400, 300, 300);
|
||||
common::VisualizeField(vis3, "localhost", 19916, surf_fit_mat_gf,
|
||||
@@ -859,7 +873,7 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 18. Visualize the mesh displacement.
|
||||
// Visualize the mesh displacement.
|
||||
if (visualization)
|
||||
{
|
||||
x0 -= x;
|
||||
@@ -870,7 +884,6 @@ int main (int argc, char *argv[])
|
||||
|
||||
delete S;
|
||||
delete S_prec;
|
||||
delete metric_coeff1;
|
||||
delete adapt_surface;
|
||||
delete adapt_grad_surface;
|
||||
delete adapt_hess_surface;
|
||||
|
||||
@@ -55,6 +55,9 @@ MESH_FILES = $(notdir $(wildcard $(SRC)*.mesh))
|
||||
$(MESH_FILES): %: $(SRC)%
|
||||
ln -sf $(<) .
|
||||
multidomain: | $(MESH_FILES)
|
||||
# The target 'copy-data' is used by the makefile in ../../tests/unit
|
||||
.PHONY: copy-data
|
||||
copy-data: | $(MESH_FILES)
|
||||
endif
|
||||
|
||||
MFEM_TESTS = MINIAPPS
|
||||
|
||||
@@ -13,6 +13,18 @@ add_mfem_miniapp(nurbs_ex1
|
||||
MAIN nurbs_ex1.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(nurbs_ex3
|
||||
MAIN nurbs_ex3.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(nurbs_ex5
|
||||
MAIN nurbs_ex5.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(nurbs_ex24
|
||||
MAIN nurbs_ex24.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(nurbs_curveint
|
||||
MAIN nurbs_curveint.cpp
|
||||
LIBRARIES mfem)
|
||||
@@ -29,6 +41,14 @@ add_mfem_miniapp(nurbs_patch_ex1
|
||||
MAIN nurbs_patch_ex1.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(nurbs_solenoidal
|
||||
MAIN nurbs_solenoidal.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(nurbs_biharm
|
||||
MAIN nurbs_biharm.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
if (MFEM_ENABLE_TESTING)
|
||||
add_test(NAME nurbs_ex1_1d_r1_o2_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
|
||||
@@ -64,6 +84,10 @@ if (MFEM_ENABLE_TESTING)
|
||||
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 2)
|
||||
|
||||
add_test(NAME nurbs_ex1_neu_r2_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -r 2 --neu "3")
|
||||
|
||||
add_test(NAME nurbs_ex1_weak_mp_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/ball-nurbs.mesh -o 2 --weak-bc -r 0)
|
||||
@@ -125,9 +149,64 @@ if (MFEM_ENABLE_TESTING)
|
||||
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/two-cubes-nurbs-autoedge.mesh -o 1 -r 3 -rf ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/two-cubes.ref)
|
||||
|
||||
add_test(NAME nurbs_ex1_periodic_2d
|
||||
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -r 2 --master "3" --slave "4")
|
||||
|
||||
add_test(NAME nurbs_ex1_periodic_3d
|
||||
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube-nurbs.mesh -pm "1" -ps "2" -rf ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube.ref)
|
||||
-m ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube-nurbs.mesh
|
||||
-rf ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube.ref
|
||||
--master "1" --slave "2")
|
||||
|
||||
add_test(NAME nurbs_ex3_2d_r1_o2_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex3> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
|
||||
|
||||
add_test(NAME nurbs_ex3_3d_r1_o2_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex3> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2)
|
||||
|
||||
add_test(NAME nurbs_ex5_2d_r1_o2_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex5> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
|
||||
|
||||
add_test(NAME nurbs_ex5_3d_r1_o2_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex5> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2)
|
||||
|
||||
add_test(NAME nurbs_ex24_2d_r1_o2_p0_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 0)
|
||||
|
||||
add_test(NAME nurbs_ex24_2d_r1_o2_p2_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 2)
|
||||
|
||||
add_test(NAME nurbs_ex24_3d_r1_o2_p0_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2 -p 0)
|
||||
|
||||
add_test(NAME nurbs_ex24_3d_r1_o2_p1_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2 -p 1)
|
||||
|
||||
add_test(NAME nurbs_ex24_3d_r1_o2_p2_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2 -p 2)
|
||||
|
||||
add_test(NAME nurbs_solenoidal_2d_r1_o2_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_solenoidal> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -r 1 -o 2)
|
||||
|
||||
add_test(NAME nurbs_solenoidal_3d_r1_o2_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_solenoidal> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2)
|
||||
|
||||
add_test(NAME nurbs_biharm_ser
|
||||
COMMAND $<TARGET_FILE:nurbs_biharm> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
|
||||
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
@@ -135,6 +214,10 @@ if (MFEM_USE_MPI)
|
||||
MAIN nurbs_ex1p.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(nurbs_ex11p
|
||||
MAIN nurbs_ex11p.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
if (MFEM_ENABLE_TESTING)
|
||||
add_test(NAME nurbs_ex1p_np=4
|
||||
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
|
||||
@@ -169,13 +252,7 @@ if (MFEM_USE_MPI)
|
||||
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
|
||||
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1)
|
||||
endif()
|
||||
|
||||
add_mfem_miniapp(nurbs_ex11p
|
||||
MAIN nurbs_ex11p.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
if (MFEM_ENABLE_TESTING)
|
||||
add_test(NAME nurbs_ex11p_np=4
|
||||
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
|
||||
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex11p> -no-vis
|
||||
|
||||
+33
-4
@@ -21,8 +21,7 @@ CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
SEQ_MINIAPPS = nurbs_ex1 nurbs_patch_ex1 nurbs_curveint nurbs_printfunc nurbs_naca_cmesh
|
||||
|
||||
SEQ_MINIAPPS = nurbs_ex1 nurbs_patch_ex1 nurbs_ex3 nurbs_ex5 nurbs_ex24 nurbs_curveint nurbs_printfunc nurbs_solenoidal nurbs_naca_cmesh
|
||||
PAR_MINIAPPS = nurbs_ex1p nurbs_ex11p
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
MINIAPPS = $(SEQ_MINIAPPS)
|
||||
@@ -103,6 +102,36 @@ endif
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(EX1PATCH_ARGS_2))
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(EX1PATCH_ARGS_3))
|
||||
|
||||
EX3_ARGS_1 := -m $(MFEM_DIR)/data/square-nurbs.mesh -r 1 -o 2
|
||||
EX3_ARGS_2 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2
|
||||
nurbs_ex3-test-seq: nurbs_ex3
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(EX3_ARGS_1))
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(EX3_ARGS_2))
|
||||
|
||||
EX5_ARGS_1 := -m $(MFEM_DIR)/data/square-nurbs.mesh -r 1 -o 2
|
||||
EX5_ARGS_2 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2
|
||||
nurbs_ex5-test-seq: nurbs_ex5
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(EX5_ARGS_1))
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(EX5_ARGS_2))
|
||||
|
||||
EX24_ARGS_1 := -m $(MFEM_DIR)/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 0
|
||||
EX24_ARGS_2 := -m $(MFEM_DIR)/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 2
|
||||
EX24_ARGS_3 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2 -p 0
|
||||
EX24_ARGS_4 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2 -p 1
|
||||
EX24_ARGS_5 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2 -p 2
|
||||
nurbs_ex24-test-seq: nurbs_ex24
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_1))
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_2))
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_3))
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_4))
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_5))
|
||||
|
||||
SOL_ARGS_1 := -m $(MFEM_DIR)/data/pipe-nurbs-2d.mesh -r 1 -o 2
|
||||
SOL_ARGS_1 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2
|
||||
nurbs_sol-test-seq: nurbs_solenoidal
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(SOL_ARGS_1))
|
||||
@$(call mfem-test,$<,, NURBS miniapp,$(SOl_ARGS_2))
|
||||
|
||||
CI_ARGS_1 := -uw -n 9 -no-visit
|
||||
CI_ARGS_2 := -nw -n 9 -no-visit
|
||||
|
||||
@@ -151,6 +180,6 @@ clean-build:
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
clean-exec:
|
||||
@rm -f refined.mesh sin-fit.mesh mesh.* sol.* mode_* naca-cmesh.mesh
|
||||
@rm -rf Example1*
|
||||
@rm -f refined.mesh sin-fit.mesh ex5.mesh exsol.mesh mesh.* sol.* mode_* naca-cmesh.mesh sol_?.gf
|
||||
@rm -rf Example1* Example3* Example5* Solenoidal_* ParaView
|
||||
@rm -rf CurveInt Naca_cmesh glvis_naca-cmesh.mesh
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
//
|
||||
// Stabilized Convection-Diffusion
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
real_t kappa_param = 1.0;
|
||||
|
||||
real_t dif_fun(const Vector & x)
|
||||
{
|
||||
return kappa_param;
|
||||
}
|
||||
|
||||
real_t force_fun(const Vector & x)
|
||||
{
|
||||
int d = x.Size();
|
||||
|
||||
real_t kappa = dif_fun(x);
|
||||
|
||||
real_t pi = (real_t)(M_PI);
|
||||
|
||||
real_t sx = sin(pi*x[0]);
|
||||
real_t sy = 1.0;
|
||||
real_t sz = 1.0;
|
||||
|
||||
if (d >= 2)
|
||||
{
|
||||
sy = sin(pi*x[1]);
|
||||
}
|
||||
if (d >= 3)
|
||||
{
|
||||
sz = sin(pi*x[2]);
|
||||
}
|
||||
|
||||
return d*d*kappa*pi*pi*pi*pi*sx*sy*sz;
|
||||
}
|
||||
|
||||
real_t sol_fun(const Vector & x)
|
||||
{
|
||||
real_t pi = (real_t)(M_PI);
|
||||
|
||||
real_t sx = sin(pi*x[0]);
|
||||
real_t sy = 1.0;
|
||||
real_t sz = 1.0;
|
||||
|
||||
int d = x.Size();
|
||||
if (d >= 2)
|
||||
{
|
||||
sy = sin(pi*x[1]);
|
||||
}
|
||||
if (d >= 3)
|
||||
{
|
||||
sz = sin(pi*x[2]);
|
||||
}
|
||||
|
||||
return sx*sy*sz;
|
||||
}
|
||||
|
||||
void grad_fun(const Vector & x, Vector & a)
|
||||
{
|
||||
real_t pi = (real_t)(M_PI);
|
||||
|
||||
real_t sx = sin(pi*x[0]);
|
||||
real_t cx = cos(pi*x[0]);
|
||||
real_t sy = 1.0;
|
||||
real_t cy = 1.0;
|
||||
real_t sz = 1.0;
|
||||
real_t cz = 1.0;
|
||||
|
||||
int d = x.Size();
|
||||
if (d >= 2)
|
||||
{
|
||||
sy = sin(pi*x[1]);
|
||||
cy = cos(pi*x[1]);
|
||||
}
|
||||
if (d >= 3)
|
||||
{
|
||||
sz = sin(pi*x[2]);
|
||||
cz = cos(pi*x[2]);
|
||||
}
|
||||
|
||||
a[0] = pi*cx*sy;
|
||||
a[1] = pi*sx*cy;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
real_t lap_fun(const Vector & x)
|
||||
{
|
||||
real_t pi = (real_t)(M_PI);
|
||||
|
||||
real_t sx = sin(pi*x[0]);
|
||||
real_t cx = cos(pi*x[0]);
|
||||
real_t sy = 1.0;
|
||||
real_t cy = 1.0;
|
||||
real_t sz = 1.0;
|
||||
real_t cz = 1.0;
|
||||
|
||||
int d = x.Size();
|
||||
if (d >= 2)
|
||||
{
|
||||
sy = sin(pi*x[1]);
|
||||
cy = cos(pi*x[1]);
|
||||
}
|
||||
if (d >= 3)
|
||||
{
|
||||
sz = sin(pi*x[2]);
|
||||
cz = cos(pi*x[2]);
|
||||
}
|
||||
|
||||
return -d*pi*pi*sx*sy*sz;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../../data/square-nurbs.mesh";
|
||||
const char *per_file = "none";
|
||||
const char *ref_file = "";
|
||||
int ref_levels = 0;
|
||||
Array<int> master(0);
|
||||
Array<int> slave(0);
|
||||
bool static_cond = false;
|
||||
bool visualization = false;
|
||||
real_t penalty = -1;
|
||||
Array<int> order(1);
|
||||
order[0] = 2;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly, -1 for auto.");
|
||||
args.AddOption(&per_file, "-p", "--per",
|
||||
"Periodic BCS file.");
|
||||
args.AddOption(&ref_file, "-rf", "--ref-file",
|
||||
"File with refinement data");
|
||||
args.AddOption(&master, "-pm", "--master",
|
||||
"Master boundaries for periodic BCs");
|
||||
args.AddOption(&slave, "-ps", "--slave",
|
||||
"Slave boundaries for periodic BCs");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
args.AddOption(&kappa_param, "-k", "--kappa",
|
||||
"Sets the diffusion parameters, should be positive."
|
||||
" Negative values are replaced with function defined in source.");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(mfem::out);
|
||||
return 1;
|
||||
}
|
||||
|
||||
args.PrintOptions(mfem::out);
|
||||
|
||||
if (order.Min()< 2)
|
||||
{
|
||||
mfem_error("Wrong order.");
|
||||
}
|
||||
// 2. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 3. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement and knot insertion of knots defined
|
||||
// in a refinement file. We choose 'ref_levels' to be the largest number
|
||||
// that gives a final mesh with no more than 50,000 elements.
|
||||
{
|
||||
// Mesh refinement as defined in refinement file
|
||||
if (mesh->NURBSext && (strlen(ref_file) != 0))
|
||||
{
|
||||
mesh->RefineNURBSFromFile(ref_file);
|
||||
}
|
||||
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
mesh->PrintInfo();
|
||||
}
|
||||
|
||||
// 4. Define a finite element space on the mesh. Here we use continuous
|
||||
// Lagrange finite elements of the specified order. If order < 1, we
|
||||
// instead use an isoparametric/isogeometric space.
|
||||
FiniteElementCollection *fec;
|
||||
NURBSExtension *NURBSext = NULL;
|
||||
int own_fec = 0;
|
||||
|
||||
if (mesh->NURBSext)
|
||||
{
|
||||
fec = new NURBSFECollection(order[0]);
|
||||
own_fec = 1;
|
||||
|
||||
int nkv = mesh->NURBSext->GetNKV();
|
||||
if (order.Size() == 1)
|
||||
{
|
||||
int tmp = order[0];
|
||||
order.SetSize(nkv);
|
||||
order = tmp;
|
||||
}
|
||||
|
||||
if (order.Size() != nkv ) { mfem_error("Wrong number of orders set."); }
|
||||
NURBSext = new NURBSExtension(mesh->NURBSext, order);
|
||||
|
||||
// Read periodic BCs from file
|
||||
std::ifstream in;
|
||||
in.open(per_file, std::ifstream::in);
|
||||
if (in.is_open())
|
||||
{
|
||||
int psize;
|
||||
in >> psize;
|
||||
master.SetSize(psize);
|
||||
slave.SetSize(psize);
|
||||
master.Load(in, psize);
|
||||
slave.Load(in, psize);
|
||||
in.close();
|
||||
}
|
||||
master.Print();
|
||||
slave.Print();
|
||||
NURBSext->ConnectBoundaries(master,slave);
|
||||
}
|
||||
else if (order[0] == -1) // Isoparametric
|
||||
{
|
||||
if (mesh->GetNodes())
|
||||
{
|
||||
fec = mesh->GetNodes()->OwnFEC();
|
||||
own_fec = 0;
|
||||
mfem::out << "Using isoparametric FEs: " << fec->Name() << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem::out <<"Mesh does not have FEs --> Assume order 1.\n";
|
||||
fec = new H1_FECollection(1, dim);
|
||||
own_fec = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (order.Size() > 1) { cout <<"Wrong number of orders set, needs one.\n"; }
|
||||
fec = new H1_FECollection(abs(order[0]), dim);
|
||||
own_fec = 1;
|
||||
}
|
||||
|
||||
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, NURBSext, fec);
|
||||
mfem::out << "Number of finite element unknowns: "
|
||||
<< fespace->GetTrueVSize() << endl;
|
||||
|
||||
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined by marking all
|
||||
// the boundary attributes from the mesh as essential (Dirichlet) and
|
||||
// converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
|
||||
// Remove periodic BCs
|
||||
for (int i = 0; i < master.Size(); i++)
|
||||
{
|
||||
ess_bdr[master[i]-1] = 0;
|
||||
ess_bdr[slave[i]-1] = 0;
|
||||
}
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
|
||||
// the basis functions in the finite element fespace.
|
||||
ConstantCoefficient u_dir(0.0);
|
||||
|
||||
Coefficient *kappa_tmp;
|
||||
if (kappa_param < 0.0)
|
||||
{
|
||||
kappa_tmp = new FunctionCoefficient(dif_fun);
|
||||
}
|
||||
else
|
||||
{
|
||||
kappa_tmp = new ConstantCoefficient(kappa_param);
|
||||
}
|
||||
|
||||
Coefficient& kappa = *kappa_tmp;
|
||||
FunctionCoefficient force(force_fun);
|
||||
|
||||
LinearForm *b = new LinearForm(fespace);
|
||||
b->AddDomainIntegrator(new DomainLFIntegrator(force));
|
||||
b->Assemble();
|
||||
|
||||
// 7. Define the solution vector x as a finite element grid function
|
||||
// corresponding to fespace. Initialize x with initial guess of zero,
|
||||
// which satisfies the boundary conditions.
|
||||
GridFunction x(fespace);
|
||||
x = 0.0;
|
||||
|
||||
// 8. Set up the bilinear form a(.,.) on the finite element space
|
||||
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
|
||||
// domain integrator.
|
||||
BilinearForm *a = new BilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new LaplaceLaplaceIntegrator(kappa));
|
||||
|
||||
// 9. Assemble the bilinear form and the corresponding linear system,
|
||||
// applying any necessary transformations such as: eliminating boundary
|
||||
// conditions, applying conforming constraints for non-conforming AMR,
|
||||
// static condensation, etc.
|
||||
if (static_cond) { a->EnableStaticCondensation(); }
|
||||
a->Assemble();
|
||||
|
||||
SparseMatrix A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
mfem::out << "Size of linear system: " << A.Height() << endl;
|
||||
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
// 10. Define a simple Jacobi preconditioner and use it to
|
||||
// solve the system A X = B with PCG.
|
||||
GSSmoother M(A);
|
||||
GMRES(A, M, B, X, 1, 2000, 2000, 1e-16, 0.0);
|
||||
#else
|
||||
// 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
|
||||
UMFPackSolver umf_solver;
|
||||
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
|
||||
umf_solver.SetOperator(A);
|
||||
umf_solver.Mult(B, X);
|
||||
#endif
|
||||
|
||||
// 11. Recover the solution as a finite element grid function.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 12. Save the refined mesh and the solution. This output can be viewed later
|
||||
// using GLVis: "glvis -m refined.mesh -g sol.gf".
|
||||
{
|
||||
ofstream mesh_ofs("refined.mesh");
|
||||
mesh_ofs.precision(8);
|
||||
mesh->Print(mesh_ofs);
|
||||
ofstream sol_ofs("sol.gf");
|
||||
sol_ofs.precision(8);
|
||||
x.Save(sol_ofs);
|
||||
sol_ofs.close();
|
||||
}
|
||||
|
||||
// 13. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *mesh << x << flush;
|
||||
}
|
||||
|
||||
// 14. Error computation
|
||||
Vector norm(3);
|
||||
int order_quad = 3*order.Max() + 4;
|
||||
const IntegrationRule *irs[Geometry::NumGeom];
|
||||
for (int i=0; i < Geometry::NumGeom; ++i)
|
||||
{
|
||||
irs[i] = &(IntRules.Get(i, order_quad));
|
||||
}
|
||||
FunctionCoefficient sol_cf(sol_fun);
|
||||
VectorFunctionCoefficient grad_cf(mesh->Dimension(), grad_fun);
|
||||
FunctionCoefficient lap_cf(lap_fun);
|
||||
|
||||
norm[0]= x.ComputeL2Error(sol_cf,irs);
|
||||
norm[1]= x.ComputeGradError(&grad_cf, irs);
|
||||
norm[2] = x.ComputeLaplaceError(&lap_cf, irs);
|
||||
|
||||
mfem::out << "|| x_h - x_ex || = " << norm[0] << "\n";
|
||||
mfem::out << "|| grad x_h - grad x_ex || = " << norm[1] << "\n";
|
||||
mfem::out << "|| lap x_h - lap x_ex || = " << norm[2] << "\n";
|
||||
|
||||
// 15. Save data in the VisIt format
|
||||
VisItDataCollection visit_dc("Biharm", mesh);
|
||||
visit_dc.RegisterField("solution", &x);
|
||||
visit_dc.Save();
|
||||
|
||||
// 16. Free the used memory.
|
||||
delete fespace;
|
||||
if (own_fec) { delete fec; }
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+71
-103
@@ -6,6 +6,7 @@
|
||||
// nurbs_ex1 -m ../../data/square-nurbs.mesh -o 2 --weak-bc
|
||||
// nurbs_ex1 -m ../../data/cube-nurbs.mesh -o 2 -no-ibp
|
||||
// nurbs_ex1 -m ../../data/pipe-nurbs-2d.mesh -o 2 -no-ibp
|
||||
// nurbs_ex1 -m ../../data/pipe-nurbs-2d.mesh -o 2 -r 2 --neu "3"
|
||||
// nurbs_ex1 -m ../../data/square-disc-nurbs.mesh -o -1
|
||||
// nurbs_ex1 -m ../../data/disc-nurbs.mesh -o -1
|
||||
// nurbs_ex1 -m ../../data/pipe-nurbs.mesh -o -1
|
||||
@@ -52,101 +53,17 @@ public:
|
||||
inline bool operator==(const Data& d1,const Data& d2) { return (d1.x == d2.x); }
|
||||
inline bool operator <(const Data& d1,const Data& d2) { return (d1.x < d2.x); }
|
||||
|
||||
/** Class for integrating the bilinear form a(u,v) := (Q Laplace u, v) where Q
|
||||
can be a scalar coefficient. */
|
||||
class Diffusion2Integrator: public BilinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector shape,laplace;
|
||||
#endif
|
||||
Coefficient *Q;
|
||||
|
||||
public:
|
||||
/// Construct a diffusion integrator with coefficient Q = 1
|
||||
Diffusion2Integrator() { Q = NULL; }
|
||||
|
||||
/// Construct a diffusion integrator with a scalar coefficient q
|
||||
Diffusion2Integrator (Coefficient &q) : Q(&q) { }
|
||||
|
||||
/** Given a particular Finite Element
|
||||
computes the element stiffness matrix elmat. */
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
real_t w;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape(nd);
|
||||
Vector laplace(nd);
|
||||
#else
|
||||
shape.SetSize(nd);
|
||||
laplace.SetSize(nd);
|
||||
#endif
|
||||
elmat.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order;
|
||||
if (el.Space() == FunctionSpace::Pk)
|
||||
{
|
||||
order = 2*el.GetOrder() - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
order = 2*el.GetOrder() + dim - 1;
|
||||
}
|
||||
|
||||
if (el.Space() == FunctionSpace::rQk)
|
||||
{
|
||||
ir = &RefinedIntRules.Get(el.GetGeomType(),order);
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &IntRules.Get(el.GetGeomType(),order);
|
||||
}
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint(&ip);
|
||||
w = -ip.weight * Trans.Weight();
|
||||
|
||||
el.CalcShape(ip, shape);
|
||||
el.CalcPhysLaplacian(Trans, laplace);
|
||||
|
||||
if (Q)
|
||||
{
|
||||
w *= Q->Eval(Trans, ip);
|
||||
}
|
||||
|
||||
for (int jj = 0; jj < nd; jj++)
|
||||
{
|
||||
for (int ii = 0; ii < nd; ii++)
|
||||
{
|
||||
elmat(ii, jj) += w*shape(ii)*laplace(jj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../../data/star.mesh";
|
||||
const char *mesh_file = "../../data/square-nurbs.mesh";
|
||||
const char *per_file = "none";
|
||||
const char *ref_file = "";
|
||||
int ref_levels = -1;
|
||||
Array<int> master(0);
|
||||
Array<int> slave(0);
|
||||
Array<int> neu(0);
|
||||
bool static_cond = false;
|
||||
bool visualization = 1;
|
||||
int lod = 0;
|
||||
@@ -169,6 +86,8 @@ int main(int argc, char *argv[])
|
||||
"Master boundaries for periodic BCs");
|
||||
args.AddOption(&slave, "-ps", "--slave",
|
||||
"Slave boundaries for periodic BCs");
|
||||
args.AddOption(&neu, "-n", "--neu",
|
||||
"Boundaries with Neumann BCs");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
@@ -266,8 +185,6 @@ int main(int argc, char *argv[])
|
||||
slave.Load(in, psize);
|
||||
in.close();
|
||||
}
|
||||
master.Print();
|
||||
slave.Print();
|
||||
NURBSext->ConnectBoundaries(master,slave);
|
||||
}
|
||||
else if (order[0] == -1) // Isoparametric
|
||||
@@ -323,39 +240,84 @@ int main(int argc, char *argv[])
|
||||
// In this example, the boundary conditions are defined by marking all
|
||||
// the boundary attributes from the mesh as essential (Dirichlet) and
|
||||
// converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
Array<int> ess_bdr(0);
|
||||
Array<int> neu_bdr(0);
|
||||
Array<int> per_bdr(0);
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(mesh->bdr_attributes.Max());
|
||||
if (strongBC)
|
||||
ess_bdr.SetSize(mesh->bdr_attributes.Max());
|
||||
neu_bdr.SetSize(mesh->bdr_attributes.Max());
|
||||
per_bdr.SetSize(mesh->bdr_attributes.Max());
|
||||
|
||||
ess_bdr = 1;
|
||||
neu_bdr = 0;
|
||||
per_bdr = 0;
|
||||
|
||||
// Apply Neumann BCs
|
||||
for (int i = 0; i < neu.Size(); i++)
|
||||
{
|
||||
ess_bdr = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_bdr = 0;
|
||||
if ( neu[i]-1 >= 0 &&
|
||||
neu[i]-1 < mesh->bdr_attributes.Max())
|
||||
{
|
||||
ess_bdr[neu[i]-1] = 0;
|
||||
neu_bdr[neu[i]-1] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout <<"Neumann boundary "<<neu[i]<<" out of range -- discarded"<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove periodic BCs
|
||||
// Correct for periodic BCs
|
||||
for (int i = 0; i < master.Size(); i++)
|
||||
{
|
||||
ess_bdr[master[i]-1] = 0;
|
||||
ess_bdr[slave[i]-1] = 0;
|
||||
if ( master[i]-1 >= 0 &&
|
||||
master[i]-1 < mesh->bdr_attributes.Max())
|
||||
{
|
||||
ess_bdr[master[i]-1] = 0;
|
||||
neu_bdr[master[i]-1] = 0;
|
||||
per_bdr[master[i]-1] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout <<"Master boundary "<<master[i]<<" out of range -- discarded"<< endl;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < slave.Size(); i++)
|
||||
{
|
||||
if ( slave[i]-1 >= 0 &&
|
||||
slave[i]-1 < mesh->bdr_attributes.Max())
|
||||
{
|
||||
ess_bdr[slave[i]-1] = 0;
|
||||
neu_bdr[slave[i]-1] = 0;
|
||||
per_bdr[slave[i]-1] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout <<"Slave boundary "<<slave[i]<<" out of range -- discarded"<< endl;
|
||||
}
|
||||
}
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
cout <<"Boundary conditions:"<< endl;
|
||||
cout <<" - Periodic : "; per_bdr.Print();
|
||||
cout <<" - Essential : "; ess_bdr.Print();
|
||||
cout <<" - Neumann : "; neu_bdr.Print();
|
||||
|
||||
|
||||
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
|
||||
// the basis functions in the finite element fespace.
|
||||
ConstantCoefficient one(1.0);
|
||||
ConstantCoefficient mone(-1.0);
|
||||
ConstantCoefficient zero(0.0);
|
||||
|
||||
LinearForm *b = new LinearForm(fespace);
|
||||
b->AddDomainIntegrator(new DomainLFIntegrator(one));
|
||||
b->AddBoundaryIntegrator( new BoundaryLFIntegrator(one),neu_bdr);
|
||||
if (!strongBC)
|
||||
b->AddBdrFaceIntegrator(
|
||||
new DGDirichletLFIntegrator(zero, one, -1.0, kappa));
|
||||
new DGDirichletLFIntegrator(zero, one, -1.0, kappa), ess_bdr);
|
||||
|
||||
b->Assemble();
|
||||
|
||||
// 7. Define the solution vector x as a finite element grid function
|
||||
@@ -374,12 +336,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
a->AddDomainIntegrator(new Diffusion2Integrator(one));
|
||||
a->AddDomainIntegrator(new LaplaceIntegrator(one, -1.0));
|
||||
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(mone, 0.0, 0.0), neu_bdr);
|
||||
}
|
||||
|
||||
if (!strongBC)
|
||||
{
|
||||
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, -1.0, kappa));
|
||||
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, -1.0, kappa), ess_bdr);
|
||||
}
|
||||
|
||||
// 9. Assemble the bilinear form and the corresponding linear system,
|
||||
@@ -391,6 +354,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
SparseMatrix A;
|
||||
Vector B, X;
|
||||
Array<int> ess_tdof_list(0);
|
||||
if (strongBC)
|
||||
{
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
cout << "Size of linear system: " << A.Height() << endl;
|
||||
|
||||
@@ -0,0 +1,459 @@
|
||||
// MFEM Example 24 -- modified for NURBS FE
|
||||
//
|
||||
// Compile with: make nurbs_ex24
|
||||
//
|
||||
// Sample runs: nurbs_ex24 -m ../../data/pipe-nurbs-2d.mesh -o 2
|
||||
// nurbs_ex24 -m ../../data/pipe-nurbs-2d.mesh -p 2
|
||||
// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2
|
||||
// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2 -p 1
|
||||
// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2 -p 2
|
||||
// nurbs_ex24 -m ../../data/escher.mesh
|
||||
// nurbs_ex24 -m ../../data/escher.mesh -o 2
|
||||
// nurbs_ex24 -m ../../data/fichera.mesh
|
||||
// nurbs_ex24 -m ../../data/fichera-q2.vtk
|
||||
// nurbs_ex24 -m ../../data/fichera-q3.mesh
|
||||
// nurbs_ex24 -m ../../data/amr-quad.mesh -o 2
|
||||
// nurbs_ex24 -m ../../data/amr-hex.mesh
|
||||
//
|
||||
// Device sample runs -- do not work for NURBS:
|
||||
// nurbs_ex24 -m ../../data/escher.mesh -pa -d cuda
|
||||
// nurbs_ex24 -m ../../data/escher.mesh -pa -d raja-cuda
|
||||
// nurbs_ex24 -m ../../data/escher.mesh -pa -d raja-omp
|
||||
//
|
||||
// Description: This example code illustrates usage of mixed finite element
|
||||
// spaces, with three variants:
|
||||
//
|
||||
// 0) (grad p, u) for p in H^1 tested against u in H(curl)
|
||||
// 1) (curl v, u) for v in H(curl) tested against u in H(div), 3D
|
||||
// 2) (div v, q) for v in H(div) tested against q in L_2
|
||||
//
|
||||
// Using different approaches, we project the gradient, curl, or
|
||||
// divergence to the appropriate space.
|
||||
//
|
||||
// NURBS-based H(curl) and H(div) spaces only implemented
|
||||
// for meshes consisting of a single patch.
|
||||
//
|
||||
// We recommend viewing examples 1, 3, and 5 before viewing this
|
||||
// example.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
real_t p_exact(const Vector &x);
|
||||
void gradp_exact(const Vector &, Vector &);
|
||||
real_t div_gradp_exact(const Vector &x);
|
||||
void v_exact(const Vector &x, Vector &v);
|
||||
void curlv_exact(const Vector &x, Vector &cv);
|
||||
|
||||
int dim;
|
||||
real_t freq = 1.0, kappa;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../../data/cube-nurbs.mesh";
|
||||
int ref_levels = -1;
|
||||
int order = 1;
|
||||
bool NURBS = true;
|
||||
int prob = 0;
|
||||
bool static_cond = false;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
bool visualization = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly, -1 for auto.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&NURBS, "-n", "--nurbs", "-nn","--no-nurbs",
|
||||
"NURBS.");
|
||||
args.AddOption(&prob, "-p", "--problem-type",
|
||||
"Choose between 0: grad, 1: curl, 2: div");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
kappa = freq * M_PI;
|
||||
|
||||
// 2. Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
device.Print();
|
||||
|
||||
// 3. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
dim = mesh->Dimension();
|
||||
if ((prob == 1) &&(dim != 3))
|
||||
{
|
||||
MFEM_ABORT("The curl problem is only defined in 3D.");
|
||||
}
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
|
||||
// largest number that gives a final mesh with no more than 50,000
|
||||
// elements.
|
||||
{
|
||||
if (ref_levels < 0)
|
||||
{
|
||||
ref_levels = (int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
|
||||
}
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use Nedelec or
|
||||
// Raviart-Thomas finite elements of the specified order.
|
||||
FiniteElementCollection *trial_fec = nullptr;
|
||||
FiniteElementCollection *test_fec = nullptr;
|
||||
NURBSExtension *NURBSext = nullptr;
|
||||
if (mesh->NURBSext && NURBS)
|
||||
{
|
||||
NURBSext = new NURBSExtension(mesh->NURBSext, order);
|
||||
if (prob == 0)
|
||||
{
|
||||
trial_fec = new NURBSFECollection(order);
|
||||
test_fec = new NURBS_HCurlFECollection(order, dim);
|
||||
}
|
||||
else if (prob == 1)
|
||||
{
|
||||
trial_fec = new NURBS_HCurlFECollection(order, dim);
|
||||
test_fec = new NURBS_HDivFECollection(order, dim);
|
||||
}
|
||||
else
|
||||
{
|
||||
trial_fec = new NURBS_HDivFECollection(order, dim);
|
||||
test_fec = new NURBSFECollection(order);
|
||||
}
|
||||
mfem::out<<"Create NURBS fec and ext"<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prob == 0)
|
||||
{
|
||||
trial_fec = new H1_FECollection(order, dim);
|
||||
test_fec = new ND_FECollection(order, dim);
|
||||
}
|
||||
else if (prob == 1)
|
||||
{
|
||||
trial_fec = new ND_FECollection(order, dim);
|
||||
test_fec = new RT_FECollection(order-1, dim);
|
||||
}
|
||||
else
|
||||
{
|
||||
trial_fec = new RT_FECollection(order-1, dim);
|
||||
test_fec = new L2_FECollection(order-1, dim);
|
||||
}
|
||||
}
|
||||
|
||||
FiniteElementSpace trial_fes(mesh, NURBSext, trial_fec);
|
||||
FiniteElementSpace test_fes(mesh,trial_fes.StealNURBSext(), test_fec);
|
||||
|
||||
int trial_size = trial_fes.GetTrueVSize();
|
||||
int test_size = test_fes.GetTrueVSize();
|
||||
|
||||
if (prob == 0)
|
||||
{
|
||||
cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
|
||||
cout << "Number of H1 finite element unknowns: " << trial_size << endl;
|
||||
}
|
||||
else if (prob == 1)
|
||||
{
|
||||
cout << "Number of Nedelec finite element unknowns: " << trial_size << endl;
|
||||
cout << "Number of Raviart-Thomas finite element unknowns: " << test_size <<
|
||||
endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Number of Raviart-Thomas finite element unknowns: "
|
||||
<< trial_size << endl;
|
||||
cout << "Number of L2 finite element unknowns: " << test_size << endl;
|
||||
}
|
||||
|
||||
// 6. Define the solution vector as a finite element grid function
|
||||
// corresponding to the trial fespace.
|
||||
GridFunction gftest(&test_fes);
|
||||
GridFunction gftrial(&trial_fes);
|
||||
GridFunction x(&test_fes);
|
||||
FunctionCoefficient p_coef(p_exact);
|
||||
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
|
||||
VectorFunctionCoefficient v_coef(sdim, v_exact);
|
||||
VectorFunctionCoefficient curlv_coef(sdim, curlv_exact);
|
||||
FunctionCoefficient divgradp_coef(div_gradp_exact);
|
||||
|
||||
if (prob == 0)
|
||||
{
|
||||
gftrial.ProjectCoefficient(p_coef);
|
||||
}
|
||||
else if (prob == 1)
|
||||
{
|
||||
gftrial.ProjectCoefficient(v_coef);
|
||||
}
|
||||
else
|
||||
{
|
||||
gftrial.ProjectCoefficient(gradp_coef);
|
||||
}
|
||||
|
||||
gftrial.SetTrueVector();
|
||||
gftrial.SetFromTrueVector();
|
||||
|
||||
// 7. Set up the bilinear forms for L2 projection.
|
||||
ConstantCoefficient one(1.0);
|
||||
BilinearForm a(&test_fes);
|
||||
MixedBilinearForm a_mixed(&trial_fes, &test_fes);
|
||||
if (pa)
|
||||
{
|
||||
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
a_mixed.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
}
|
||||
|
||||
if (prob == 0)
|
||||
{
|
||||
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
|
||||
a_mixed.AddDomainIntegrator(new MixedVectorGradientIntegrator(one));
|
||||
}
|
||||
else if (prob == 1)
|
||||
{
|
||||
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
|
||||
a_mixed.AddDomainIntegrator(new MixedVectorCurlIntegrator(one));
|
||||
}
|
||||
else
|
||||
{
|
||||
a.AddDomainIntegrator(new MassIntegrator(one));
|
||||
a_mixed.AddDomainIntegrator(new VectorFEDivergenceIntegrator(one));
|
||||
}
|
||||
|
||||
// 8. Assemble the bilinear form and the corresponding linear system,
|
||||
// applying any necessary transformations such as: eliminating boundary
|
||||
// conditions, applying conforming constraints for non-conforming AMR,
|
||||
// static condensation, etc.
|
||||
if (static_cond) { a.EnableStaticCondensation(); }
|
||||
|
||||
a.Assemble();
|
||||
if (!pa) { a.Finalize(); }
|
||||
|
||||
a_mixed.Assemble();
|
||||
if (!pa) { a_mixed.Finalize(); }
|
||||
|
||||
if (pa)
|
||||
{
|
||||
a_mixed.Mult(gftrial, x);
|
||||
}
|
||||
else
|
||||
{
|
||||
SparseMatrix& mixed = a_mixed.SpMat();
|
||||
mixed.Mult(gftrial, x);
|
||||
}
|
||||
|
||||
// 9. Define and apply a PCG solver for Ax = b with Jacobi preconditioner.
|
||||
{
|
||||
GridFunction rhs(&test_fes);
|
||||
rhs = x;
|
||||
x = 0.0;
|
||||
|
||||
CGSolver cg;
|
||||
cg.SetRelTol(1e-12);
|
||||
cg.SetMaxIter(1000);
|
||||
cg.SetPrintLevel(1);
|
||||
if (pa)
|
||||
{
|
||||
Array<int> ess_tdof_list; // empty
|
||||
OperatorJacobiSmoother Jacobi(a, ess_tdof_list);
|
||||
|
||||
cg.SetOperator(a);
|
||||
cg.SetPreconditioner(Jacobi);
|
||||
cg.Mult(rhs, x);
|
||||
}
|
||||
else
|
||||
{
|
||||
SparseMatrix& Amat = a.SpMat();
|
||||
DSmoother Jacobi(Amat);
|
||||
|
||||
cg.SetOperator(Amat);
|
||||
cg.SetPreconditioner(Jacobi);
|
||||
cg.Mult(rhs, x);
|
||||
}
|
||||
}
|
||||
|
||||
// 10. Compute the projection of the exact field.
|
||||
GridFunction exact_proj(&test_fes);
|
||||
if (prob == 0)
|
||||
{
|
||||
exact_proj.ProjectCoefficient(gradp_coef);
|
||||
}
|
||||
else if (prob == 1)
|
||||
{
|
||||
exact_proj.ProjectCoefficient(curlv_coef);
|
||||
}
|
||||
else
|
||||
{
|
||||
exact_proj.ProjectCoefficient(divgradp_coef);
|
||||
}
|
||||
|
||||
exact_proj.SetTrueVector();
|
||||
exact_proj.SetFromTrueVector();
|
||||
|
||||
// 11. Compute and print the L_2 norm of the error.
|
||||
if (prob == 0)
|
||||
{
|
||||
real_t errSol = x.ComputeL2Error(gradp_coef);
|
||||
real_t errProj = exact_proj.ComputeL2Error(gradp_coef);
|
||||
|
||||
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in H(curl): "
|
||||
"|| E_h - grad p ||_{L_2} = " << errSol << '\n' << endl;
|
||||
cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
|
||||
"||_{L_2} = " << errProj << '\n' << endl;
|
||||
}
|
||||
else if (prob == 1)
|
||||
{
|
||||
real_t errSol = x.ComputeL2Error(curlv_coef);
|
||||
real_t errProj = exact_proj.ComputeL2Error(curlv_coef);
|
||||
|
||||
cout << "\n Solution of (E_h,w) = (curl v_h,w) for E_h and w in H(div): "
|
||||
"|| E_h - curl v ||_{L_2} = " << errSol << '\n' << endl;
|
||||
cout << " Projection E_h of exact curl v in H(div): || E_h - curl v "
|
||||
"||_{L_2} = " << errProj << '\n' << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
int order_quad = max(3, 2*order+1);
|
||||
const IntegrationRule *irs[Geometry::NumGeom];
|
||||
for (int i=0; i < Geometry::NumGeom; ++i)
|
||||
{
|
||||
irs[i] = &(IntRules.Get(i, order_quad));
|
||||
}
|
||||
|
||||
real_t errSol = x.ComputeL2Error(divgradp_coef, irs);
|
||||
real_t errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
|
||||
|
||||
cout << "\n Solution of (f_h,q) = (div v_h,q) for f_h and q in L_2: "
|
||||
"|| f_h - div v ||_{L_2} = " << errSol << '\n' << endl;
|
||||
|
||||
cout << " Projection f_h of exact div v in L_2: || f_h - div v "
|
||||
"||_{L_2} = " << errProj << '\n' << endl;
|
||||
}
|
||||
|
||||
// 12. Save the refined mesh and the solution. This output can be viewed
|
||||
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
|
||||
ofstream mesh_ofs("refined.mesh");
|
||||
mesh_ofs.precision(8);
|
||||
mesh->Print(mesh_ofs);
|
||||
ofstream sol_ofs("sol.gf");
|
||||
sol_ofs.precision(8);
|
||||
x.Save(sol_ofs);
|
||||
|
||||
// 13. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *mesh << x << flush;
|
||||
}
|
||||
|
||||
// 14. Free the used memory.
|
||||
delete trial_fec;
|
||||
delete test_fec;
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
real_t p_exact(const Vector &x)
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
return sin(x(0)) * sin(x(1)) * sin(x(2));
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
return sin(x(0)) * sin(x(1));
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void gradp_exact(const Vector &x, Vector &f)
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
f(0) = cos(x(0)) * sin(x(1)) * sin(x(2));
|
||||
f(1) = sin(x(0)) * cos(x(1)) * sin(x(2));
|
||||
f(2) = sin(x(0)) * sin(x(1)) * cos(x(2));
|
||||
}
|
||||
else
|
||||
{
|
||||
f(0) = cos(x(0)) * sin(x(1));
|
||||
f(1) = sin(x(0)) * cos(x(1));
|
||||
if (x.Size() == 3) { f(2) = 0.0; }
|
||||
}
|
||||
}
|
||||
|
||||
real_t div_gradp_exact(const Vector &x)
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
return -3.0 * sin(x(0)) * sin(x(1)) * sin(x(2));
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
return -2.0 * sin(x(0)) * sin(x(1));
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void v_exact(const Vector &x, Vector &v)
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
v(0) = sin(kappa * x(1));
|
||||
v(1) = sin(kappa * x(2));
|
||||
v(2) = sin(kappa * x(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
v(0) = sin(kappa * x(1));
|
||||
v(1) = sin(kappa * x(0));
|
||||
if (x.Size() == 3) { v(2) = 0.0; }
|
||||
}
|
||||
}
|
||||
|
||||
void curlv_exact(const Vector &x, Vector &cv)
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
cv(0) = -kappa * cos(kappa * x(2));
|
||||
cv(1) = -kappa * cos(kappa * x(0));
|
||||
cv(2) = -kappa * cos(kappa * x(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
cv = 0.0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
// MFEM Example 3 -- modified for NURBS FE
|
||||
//
|
||||
// Compile with: make nurbs_ex3
|
||||
//
|
||||
// Sample runs: nurbs_ex3 -m ../../data/square-nurbs.mesh
|
||||
// nurbs_ex3 -m ../../data/square-nurbs.mesh -o 2
|
||||
// nurbs_ex3 -m ../../data/cube-nurbs.mesh
|
||||
//
|
||||
// Description: This example code solves a simple electromagnetic diffusion
|
||||
// problem corresponding to the second order definite Maxwell
|
||||
// equation curl curl E + E = f with boundary condition
|
||||
// E x n = <given tangential field>. Here, we use a given exact
|
||||
// solution E and compute the corresponding r.h.s. f.
|
||||
// We discretize with Nedelec finite elements in 2D or 3D.
|
||||
//
|
||||
// The example demonstrates the use of H(curl) finite element
|
||||
// spaces with the curl-curl and the (vector finite element) mass
|
||||
// bilinear form, as well as the computation of discretization
|
||||
// error when the exact solution is known. Static condensation is
|
||||
// also illustrated.
|
||||
//
|
||||
// NURBS-based H(curl) spaces only implemented for meshes
|
||||
// consisting of a single patch.
|
||||
//
|
||||
// We recommend viewing examples 1-2 before viewing this example.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
// Exact solution, E, and r.h.s., f. See below for implementation.
|
||||
void E_exact(const Vector &, Vector &);
|
||||
void f_exact(const Vector &, Vector &);
|
||||
real_t freq = 1.0, kappa;
|
||||
int dim;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../../data/square-nurbs.mesh";
|
||||
int ref_levels = -1;
|
||||
bool NURBS = true;
|
||||
int order = 1;
|
||||
bool static_cond = false;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
bool visualization = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly, -1 for auto.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&NURBS, "-n", "--nurbs", "-nn","--no-nurbs",
|
||||
"NURBS.");
|
||||
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
|
||||
" solution.");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
kappa = freq * M_PI;
|
||||
|
||||
// 2. Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
device.Print();
|
||||
|
||||
// 3. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
|
||||
// largest number that gives a final mesh with no more than 50,000
|
||||
// elements.
|
||||
{
|
||||
if (ref_levels < 0)
|
||||
{
|
||||
ref_levels =
|
||||
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
|
||||
}
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use the
|
||||
// Raviart-Thomas finite elements of the specified order.
|
||||
FiniteElementCollection *fec = nullptr;
|
||||
NURBSExtension *NURBSext = nullptr;
|
||||
|
||||
if (mesh->NURBSext && NURBS)
|
||||
{
|
||||
fec = new NURBS_HCurlFECollection(order,dim);
|
||||
NURBSext = new NURBSExtension(mesh->NURBSext, order);
|
||||
mfem::out<<"Create NURBS fec and ext"<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
NURBS = false;
|
||||
fec = new ND_FECollection(order, dim);
|
||||
mfem::out<<"Create Normal fec"<<std::endl;
|
||||
}
|
||||
|
||||
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, NURBSext, fec);
|
||||
cout << "Number of finite element unknowns: "
|
||||
<< fespace->GetTrueVSize() << endl;
|
||||
|
||||
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined by marking all
|
||||
// the boundary attributes from the mesh as essential (Dirichlet) and
|
||||
// converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
cout << "Number of knowns in essential BCs: "
|
||||
<< ess_tdof_list.Size() << endl;
|
||||
|
||||
// 7. Set up the linear form b(.) which corresponds to the right-hand side
|
||||
// of the FEM linear system, which in this case is (f,phi_i) where f is
|
||||
// given by the function f_exact and phi_i are the basis functions in the
|
||||
// finite element fespace.
|
||||
VectorFunctionCoefficient f(sdim, f_exact);
|
||||
LinearForm *b = new LinearForm(fespace);
|
||||
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
|
||||
b->Assemble();
|
||||
|
||||
// 8. Define the solution vector x as a finite element grid function
|
||||
// corresponding to fespace. Initialize x by projecting the exact
|
||||
// solution. Note that only values from the boundary edges will be used
|
||||
// when eliminating the non-homogeneous boundary condition to modify the
|
||||
// r.h.s. vector b.
|
||||
GridFunction x(fespace);
|
||||
VectorFunctionCoefficient E(sdim, E_exact);
|
||||
x.ProjectCoefficient(E);
|
||||
|
||||
// 9. Set up the bilinear form corresponding to the EM diffusion operator
|
||||
// curl muinv curl + sigma I, by adding the curl-curl and the mass domain
|
||||
// integrators.
|
||||
Coefficient *muinv = new ConstantCoefficient(1.0);
|
||||
Coefficient *sigma = new ConstantCoefficient(1.0);
|
||||
BilinearForm *a = new BilinearForm(fespace);
|
||||
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
|
||||
|
||||
// 10. Assemble the bilinear form and the corresponding linear system,
|
||||
// applying any necessary transformations such as: eliminating boundary
|
||||
// conditions, applying conforming constraints for non-conforming AMR,
|
||||
// static condensation, etc.
|
||||
if (static_cond) { a->EnableStaticCondensation(); }
|
||||
a->Assemble();
|
||||
|
||||
OperatorPtr A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
cout << "Size of linear system: " << A->Height() << endl;
|
||||
|
||||
// 11. Solve the linear system A X = B.
|
||||
if (pa) // Jacobi preconditioning in partial assembly mode
|
||||
{
|
||||
OperatorJacobiSmoother M(*a, ess_tdof_list);
|
||||
PCG(*A, M, B, X, 1, 1000, 1e-12, 0.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
// 11. Define a simple symmetric Gauss-Seidel preconditioner and use it to
|
||||
// solve the system Ax=b with PCG.
|
||||
GSSmoother M((SparseMatrix&)(*A));
|
||||
PCG(*A, M, B, X, 1, 500, 1e-12, 0.0);
|
||||
#else
|
||||
// 11. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the
|
||||
// system.
|
||||
UMFPackSolver umf_solver;
|
||||
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
|
||||
umf_solver.SetOperator(*A);
|
||||
umf_solver.Mult(B, X);
|
||||
#endif
|
||||
}
|
||||
|
||||
// 12. Recover the solution as a finite element grid function.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 13. Compute and print the L^2 norm of the error.
|
||||
cout << "\n|| E_h - E ||_{L^2} = " << x.ComputeL2Error(E) << '\n' << endl;
|
||||
|
||||
// 14. Save the refined mesh and the solution. This output can be viewed
|
||||
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
|
||||
{
|
||||
ofstream mesh_ofs("refined.mesh");
|
||||
mesh_ofs.precision(8);
|
||||
mesh->Print(mesh_ofs);
|
||||
ofstream sol_ofs("sol.gf");
|
||||
sol_ofs.precision(8);
|
||||
x.Save(sol_ofs);
|
||||
}
|
||||
|
||||
// 15. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *mesh << x << flush;
|
||||
}
|
||||
|
||||
// 16. Create output in visit format
|
||||
VisItDataCollection visit_dc("Example3", mesh);
|
||||
visit_dc.RegisterField("x", &x);
|
||||
visit_dc.Save();
|
||||
|
||||
// 17. Free the used memory.
|
||||
delete a;
|
||||
delete sigma;
|
||||
delete muinv;
|
||||
delete b;
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void E_exact(const Vector &x, Vector &E)
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
E(0) = sin(kappa * x(1));
|
||||
E(1) = sin(kappa * x(2));
|
||||
E(2) = sin(kappa * x(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
E(0) = sin(kappa * x(1));
|
||||
E(1) = sin(kappa * x(0));
|
||||
if (x.Size() == 3) { E(2) = 0.0; }
|
||||
}
|
||||
}
|
||||
|
||||
void f_exact(const Vector &x, Vector &f)
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
|
||||
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
|
||||
f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
|
||||
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
|
||||
if (x.Size() == 3) { f(2) = 0.0; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,498 @@
|
||||
// MFEM Example 5 -- modified for NURBS FE
|
||||
//
|
||||
// Compile with: make nurbs_ex5
|
||||
//
|
||||
// Sample runs: nurbs_ex5 -m ../../data/square-nurbs.mesh -o 3
|
||||
// nurbs_ex5 -m ../../data/cube-nurbs.mesh -r 3
|
||||
// nurbs_ex5 -m ../../data/pipe-nurbs-2d.mesh
|
||||
// nurbs_ex5 -m ../../data/beam-tet.mesh
|
||||
// nurbs_ex5 -m ../../data/beam-hex.mesh
|
||||
// nurbs_ex5 -m ../../data/escher.mesh
|
||||
// nurbs_ex5 -m ../../data/fichera.mesh
|
||||
//
|
||||
// Device sample runs -- do not work for NURBS:
|
||||
// nurbs_ex5 -m ../../data/escher.mesh -pa -d cuda
|
||||
// nurbs_ex5 -m ../../data/escher.mesh -pa -d raja-cuda
|
||||
// nurbs_ex5 -m ../../data/escher.mesh -pa -d raja-omp
|
||||
//
|
||||
// Description: This example code solves a simple 2D/3D mixed Darcy problem
|
||||
// corresponding to the saddle point system
|
||||
//
|
||||
// k*u + grad p = f
|
||||
// - div u = g
|
||||
//
|
||||
// with natural boundary condition -p = <given pressure>.
|
||||
// Here, we use a given exact solution (u,p) and compute the
|
||||
// corresponding r.h.s. (f,g). We discretize with Raviart-Thomas
|
||||
// finite elements (velocity u) and piecewise discontinuous
|
||||
// polynomials (pressure p).
|
||||
//
|
||||
// NURBS-based H(div) spaces only implemented for meshes
|
||||
// consisting of a single patch.
|
||||
//
|
||||
// The example demonstrates the use of the BlockOperator class, as
|
||||
// well as the collective saving of several grid functions in
|
||||
// VisIt (visit.llnl.gov) and ParaView (paraview.org) formats.
|
||||
//
|
||||
// We recommend viewing examples 1-4 before viewing this example.
|
||||
|
||||
// Sample runs: nurbs_ex3 -m ../../data/square-nurbs.mesh
|
||||
// nurbs_ex3 -m ../../data/square-nurbs.mesh -o 2
|
||||
// nurbs_ex3 -m ../../data/cube-nurbs.mesh
|
||||
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
// Define the analytical solution and forcing terms / boundary conditions
|
||||
void uFun_ex(const Vector & x, Vector & u);
|
||||
real_t pFun_ex(const Vector & x);
|
||||
void fFun(const Vector & x, Vector & f);
|
||||
real_t gFun(const Vector & x);
|
||||
real_t f_natural(const Vector & x);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
StopWatch chrono;
|
||||
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../../data/square-nurbs.mesh";
|
||||
int ref_levels = -1;
|
||||
int order = 1;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
bool visualization = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly, -1 for auto.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
// 2. Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
device.Print();
|
||||
|
||||
// 3. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
|
||||
// largest number that gives a final mesh with no more than 10,000
|
||||
// elements.
|
||||
{
|
||||
if (ref_levels < 0)
|
||||
{
|
||||
ref_levels =
|
||||
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
|
||||
}
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use the
|
||||
// Raviart-Thomas finite elements of the specified order.
|
||||
FiniteElementCollection *hdiv_coll = nullptr;
|
||||
FiniteElementCollection *l2_coll = nullptr;
|
||||
NURBSExtension *NURBSext = nullptr;
|
||||
|
||||
if (mesh->NURBSext && !pa)
|
||||
{
|
||||
hdiv_coll = new NURBS_HDivFECollection(order,dim);
|
||||
l2_coll = new NURBSFECollection(order);
|
||||
NURBSext = new NURBSExtension(mesh->NURBSext, order);
|
||||
mfem::out<<"Create NURBS fec and ext"<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
hdiv_coll = new RT_FECollection(order, dim);
|
||||
l2_coll = new L2_FECollection(order, dim);
|
||||
mfem::out<<"Create Normal fec"<<std::endl;
|
||||
}
|
||||
pa = false;
|
||||
FiniteElementSpace *W_space = new FiniteElementSpace(mesh, NURBSext, l2_coll);
|
||||
FiniteElementSpace *R_space = new FiniteElementSpace(mesh,
|
||||
W_space->StealNURBSext(),
|
||||
hdiv_coll);
|
||||
|
||||
// 6. Define the BlockStructure of the problem, i.e. define the array of
|
||||
// offsets for each variable. The last component of the Array is the sum
|
||||
// of the dimensions of each block.
|
||||
Array<int> block_offsets(3); // number of variables + 1
|
||||
block_offsets[0] = 0;
|
||||
block_offsets[1] = R_space->GetVSize();
|
||||
block_offsets[2] = W_space->GetVSize();
|
||||
block_offsets.PartialSum();
|
||||
|
||||
std::cout << "***********************************************************\n";
|
||||
std::cout << "dim(R) = " << block_offsets[1] - block_offsets[0] << "\n";
|
||||
std::cout << "dim(W) = " << block_offsets[2] - block_offsets[1] << "\n";
|
||||
std::cout << "dim(R+W) = " << block_offsets.Last() << "\n";
|
||||
std::cout << "***********************************************************\n";
|
||||
{
|
||||
Array<int> ess_tdof_list;
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
R_space->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
cout << "Number boundary dofs in H(div): "
|
||||
<< ess_tdof_list.Size() << endl;
|
||||
}
|
||||
|
||||
{
|
||||
Array<int> ess_tdof_list;
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
W_space->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
cout << "Number boundary dofs in H1: "
|
||||
<< ess_tdof_list.Size() << endl;
|
||||
}
|
||||
|
||||
// 7. Define the coefficients, analytical solution, and rhs of the PDE.
|
||||
ConstantCoefficient k(1.0);
|
||||
|
||||
VectorFunctionCoefficient fcoeff(dim, fFun);
|
||||
FunctionCoefficient fnatcoeff(f_natural);
|
||||
FunctionCoefficient gcoeff(gFun);
|
||||
|
||||
VectorFunctionCoefficient ucoeff(dim, uFun_ex);
|
||||
FunctionCoefficient pcoeff(pFun_ex);
|
||||
|
||||
// 8. Allocate memory (x, rhs) for the analytical solution and the right hand
|
||||
// side. Define the GridFunction u,p for the finite element solution and
|
||||
// linear forms fform and gform for the right hand side. The data
|
||||
// allocated by x and rhs are passed as a reference to the grid functions
|
||||
// (u,p) and the linear forms (fform, gform).
|
||||
MemoryType mt = device.GetMemoryType();
|
||||
BlockVector x(block_offsets, mt), rhs(block_offsets, mt);
|
||||
|
||||
LinearForm *fform(new LinearForm);
|
||||
fform->Update(R_space, rhs.GetBlock(0), 0);
|
||||
fform->AddDomainIntegrator(new VectorFEDomainLFIntegrator(fcoeff));
|
||||
fform->AddBoundaryIntegrator(new VectorFEBoundaryFluxLFIntegrator(fnatcoeff));
|
||||
fform->Assemble();
|
||||
fform->SyncAliasMemory(rhs);
|
||||
|
||||
LinearForm *gform(new LinearForm);
|
||||
gform->Update(W_space, rhs.GetBlock(1), 0);
|
||||
gform->AddDomainIntegrator(new DomainLFIntegrator(gcoeff));
|
||||
gform->Assemble();
|
||||
gform->SyncAliasMemory(rhs);
|
||||
|
||||
// 9. Assemble the finite element matrices for the Darcy operator
|
||||
//
|
||||
// D = [ M B^T ]
|
||||
// [ B 0 ]
|
||||
// where:
|
||||
//
|
||||
// M = \int_\Omega k u_h \cdot v_h d\Omega u_h, v_h \in R_h
|
||||
// B = -\int_\Omega \div u_h q_h d\Omega u_h \in R_h, q_h \in W_h
|
||||
BilinearForm *mVarf(new BilinearForm(R_space));
|
||||
MixedBilinearForm *bVarf(new MixedBilinearForm(R_space, W_space));
|
||||
|
||||
if (pa) { mVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(k));
|
||||
mVarf->Assemble();
|
||||
if (!pa) { mVarf->Finalize(); }
|
||||
|
||||
if (pa) { bVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
|
||||
bVarf->Assemble();
|
||||
if (!pa) { bVarf->Finalize(); }
|
||||
|
||||
BlockOperator darcyOp(block_offsets);
|
||||
|
||||
TransposeOperator *Bt = NULL;
|
||||
|
||||
if (pa)
|
||||
{
|
||||
Bt = new TransposeOperator(bVarf);
|
||||
|
||||
darcyOp.SetBlock(0,0, mVarf);
|
||||
darcyOp.SetBlock(0,1, Bt, -1.0);
|
||||
darcyOp.SetBlock(1,0, bVarf, -1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SparseMatrix &M(mVarf->SpMat());
|
||||
SparseMatrix &B(bVarf->SpMat());
|
||||
B *= -1.;
|
||||
Bt = new TransposeOperator(&B);
|
||||
|
||||
darcyOp.SetBlock(0,0, &M);
|
||||
darcyOp.SetBlock(0,1, Bt);
|
||||
darcyOp.SetBlock(1,0, &B);
|
||||
}
|
||||
|
||||
// 10. Construct the operators for preconditioner
|
||||
//
|
||||
// P = [ diag(M) 0 ]
|
||||
// [ 0 B diag(M)^-1 B^T ]
|
||||
//
|
||||
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
|
||||
// pressure Schur Complement
|
||||
SparseMatrix *MinvBt = NULL;
|
||||
Vector Md(mVarf->Height());
|
||||
|
||||
BlockDiagonalPreconditioner darcyPrec(block_offsets);
|
||||
Solver *invM, *invS;
|
||||
SparseMatrix *S = NULL;
|
||||
|
||||
if (pa)
|
||||
{
|
||||
mVarf->AssembleDiagonal(Md);
|
||||
auto Md_host = Md.HostRead();
|
||||
Vector invMd(mVarf->Height());
|
||||
for (int i=0; i<mVarf->Height(); ++i)
|
||||
{
|
||||
invMd(i) = 1.0 / Md_host[i];
|
||||
}
|
||||
|
||||
Vector BMBt_diag(bVarf->Height());
|
||||
bVarf->AssembleDiagonal_ADAt(invMd, BMBt_diag);
|
||||
|
||||
Array<int> ess_tdof_list; // empty
|
||||
|
||||
invM = new OperatorJacobiSmoother(Md, ess_tdof_list);
|
||||
invS = new OperatorJacobiSmoother(BMBt_diag, ess_tdof_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
SparseMatrix &M(mVarf->SpMat());
|
||||
M.GetDiag(Md);
|
||||
Md.HostReadWrite();
|
||||
|
||||
SparseMatrix &B(bVarf->SpMat());
|
||||
MinvBt = Transpose(B);
|
||||
|
||||
for (int i = 0; i < Md.Size(); i++)
|
||||
{
|
||||
MinvBt->ScaleRow(i, 1./Md(i));
|
||||
}
|
||||
|
||||
S = Mult(B, *MinvBt);
|
||||
|
||||
invM = new DSmoother(M);
|
||||
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
invS = new GSSmoother(*S);
|
||||
#else
|
||||
invS = new UMFPackSolver(*S);
|
||||
#endif
|
||||
}
|
||||
|
||||
invM->iterative_mode = false;
|
||||
invS->iterative_mode = false;
|
||||
|
||||
darcyPrec.SetDiagonalBlock(0, invM);
|
||||
darcyPrec.SetDiagonalBlock(1, invS);
|
||||
|
||||
// 11. Solve the linear system with MINRES.
|
||||
// Check the norm of the unpreconditioned residual.
|
||||
int maxIter(10000);
|
||||
real_t rtol(1.e-10);
|
||||
real_t atol(1.e-10);
|
||||
|
||||
chrono.Clear();
|
||||
chrono.Start();
|
||||
MINRESSolver solver;
|
||||
solver.SetAbsTol(atol);
|
||||
solver.SetRelTol(rtol);
|
||||
solver.SetMaxIter(maxIter);
|
||||
solver.SetOperator(darcyOp);
|
||||
solver.SetPreconditioner(darcyPrec);
|
||||
solver.SetPrintLevel(1);
|
||||
x = 0.0;
|
||||
solver.Mult(rhs, x);
|
||||
if (device.IsEnabled()) { x.HostRead(); }
|
||||
chrono.Stop();
|
||||
|
||||
if (solver.GetConverged())
|
||||
{
|
||||
std::cout << "MINRES converged in " << solver.GetNumIterations()
|
||||
<< " iterations with a residual norm of "
|
||||
<< solver.GetFinalNorm() << ".\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "MINRES did not converge in " << solver.GetNumIterations()
|
||||
<< " iterations. Residual norm is " << solver.GetFinalNorm()
|
||||
<< ".\n";
|
||||
}
|
||||
std::cout << "MINRES solver took " << chrono.RealTime() << "s.\n";
|
||||
|
||||
// 12. Create the grid functions u and p. Compute the L2 error norms.
|
||||
GridFunction u, p;
|
||||
u.MakeRef(R_space, x.GetBlock(0), 0);
|
||||
p.MakeRef(W_space, x.GetBlock(1), 0);
|
||||
|
||||
int order_quad = max(2, 2*order+1);
|
||||
const IntegrationRule *irs[Geometry::NumGeom];
|
||||
for (int i=0; i < Geometry::NumGeom; ++i)
|
||||
{
|
||||
irs[i] = &(IntRules.Get(i, order_quad));
|
||||
}
|
||||
|
||||
real_t err_u = u.ComputeL2Error(ucoeff, irs);
|
||||
real_t norm_u = ComputeLpNorm(2., ucoeff, *mesh, irs);
|
||||
real_t err_p = p.ComputeL2Error(pcoeff, irs);
|
||||
real_t norm_p = ComputeLpNorm(2., pcoeff, *mesh, irs);
|
||||
|
||||
std::cout << "|| u_h - u_ex || / || u_ex || = " << err_u / norm_u << "\n";
|
||||
std::cout << "|| p_h - p_ex || / || p_ex || = " << err_p / norm_p << "\n";
|
||||
|
||||
// 13. Save the mesh and the solution. This output can be viewed later using
|
||||
// GLVis: "glvis -m ex5.mesh -g sol_u.gf" or "glvis -m ex5.mesh -g
|
||||
// sol_p.gf".
|
||||
{
|
||||
ofstream mesh_ofs("ex5.mesh");
|
||||
mesh_ofs.precision(8);
|
||||
mesh->Print(mesh_ofs);
|
||||
|
||||
ofstream u_ofs("sol_u.gf");
|
||||
u_ofs.precision(8);
|
||||
u.Save(u_ofs);
|
||||
|
||||
ofstream p_ofs("sol_p.gf");
|
||||
p_ofs.precision(8);
|
||||
p.Save(p_ofs);
|
||||
}
|
||||
|
||||
// 14. Save data in the VisIt format
|
||||
VisItDataCollection visit_dc("Example5", mesh);
|
||||
visit_dc.RegisterField("velocity", &u);
|
||||
visit_dc.RegisterField("pressure", &p);
|
||||
visit_dc.Save();
|
||||
|
||||
// 15. Save data in the ParaView format
|
||||
ParaViewDataCollection paraview_dc("Example5", mesh);
|
||||
paraview_dc.SetPrefixPath("ParaView");
|
||||
paraview_dc.SetLevelsOfDetail(order);
|
||||
paraview_dc.SetCycle(0);
|
||||
paraview_dc.SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc.SetHighOrderOutput(true);
|
||||
paraview_dc.SetTime(0.0); // set the time
|
||||
paraview_dc.RegisterField("velocity",&u);
|
||||
paraview_dc.RegisterField("pressure",&p);
|
||||
paraview_dc.Save();
|
||||
|
||||
// 16. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream u_sock(vishost, visport);
|
||||
u_sock.precision(8);
|
||||
u_sock << "solution\n" << *mesh << u << "window_title 'Velocity'" << endl;
|
||||
socketstream p_sock(vishost, visport);
|
||||
p_sock.precision(8);
|
||||
p_sock << "solution\n" << *mesh << p << "window_title 'Pressure'" << endl;
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
delete fform;
|
||||
delete gform;
|
||||
delete invM;
|
||||
delete invS;
|
||||
delete S;
|
||||
delete Bt;
|
||||
delete MinvBt;
|
||||
delete mVarf;
|
||||
delete bVarf;
|
||||
delete W_space;
|
||||
delete R_space;
|
||||
delete l2_coll;
|
||||
delete hdiv_coll;
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uFun_ex(const Vector & x, Vector & u)
|
||||
{
|
||||
real_t xi(x(0));
|
||||
real_t yi(x(1));
|
||||
real_t zi(0.0);
|
||||
if (x.Size() == 3)
|
||||
{
|
||||
zi = x(2);
|
||||
}
|
||||
|
||||
u(0) = - exp(xi)*sin(yi)*cos(zi);
|
||||
u(1) = - exp(xi)*cos(yi)*cos(zi);
|
||||
|
||||
if (x.Size() == 3)
|
||||
{
|
||||
u(2) = exp(xi)*sin(yi)*sin(zi);
|
||||
}
|
||||
}
|
||||
|
||||
// Change if needed
|
||||
real_t pFun_ex(const Vector & x)
|
||||
{
|
||||
real_t xi(x(0));
|
||||
real_t yi(x(1));
|
||||
real_t zi(0.0);
|
||||
|
||||
if (x.Size() == 3)
|
||||
{
|
||||
zi = x(2);
|
||||
}
|
||||
|
||||
return exp(xi)*sin(yi)*cos(zi);
|
||||
}
|
||||
|
||||
void fFun(const Vector & x, Vector & f)
|
||||
{
|
||||
f = 0.0;
|
||||
}
|
||||
|
||||
real_t gFun(const Vector & x)
|
||||
{
|
||||
if (x.Size() == 3)
|
||||
{
|
||||
return -pFun_ex(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
real_t f_natural(const Vector & x)
|
||||
{
|
||||
return (-pFun_ex(x));
|
||||
}
|
||||
@@ -153,7 +153,8 @@ int main(int argc, char *argv[])
|
||||
if (patchAssembly && reducedIntegration && !pa)
|
||||
{
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
MFEM_ABORT("Reduced integration is not supported in single precision.");
|
||||
cout << "Reduced integration is not supported in single precision.\n";
|
||||
return MFEM_SKIP_RETURN_VALUE;
|
||||
#endif
|
||||
|
||||
di->SetIntegrationMode(NonlinearFormIntegrator::Mode::PATCHWISE_REDUCED);
|
||||
|
||||
@@ -0,0 +1,401 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
//
|
||||
// ------------------------------------------------------------
|
||||
// NURBS Solenoidal Miniapp: Project solenoidal velocity
|
||||
// ------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
// Compile with: make nurbs_solenoidal
|
||||
//
|
||||
// Sample runs: nurbs_solenoidal -m ../../data/square-nurbs.mesh -o 2
|
||||
// nurbs_solenoidal -m ../../data/cube-nurbs.mesh -o 2
|
||||
//
|
||||
// Description: This code projects a velocity field, and forces this field
|
||||
// to be solenoidal, viz. the divergence is zero. If the correct
|
||||
// discrete spaces are chosen the divergence is pointwise zero.
|
||||
//
|
||||
// This is achieved by solving a simple 2D/3D mixed Darcy problem
|
||||
// corresponding to the saddle point system (similar to ex5)
|
||||
//
|
||||
// u + grad p = u_ex
|
||||
// - div u = 0
|
||||
//
|
||||
// NURBS-based H(div) spaces only implemented for meshes
|
||||
// consisting of a single patch.
|
||||
//
|
||||
// Here, u_ex is the specified velocity field. If u_ex is
|
||||
// divergence free, we expect the pressure to converge to zero.
|
||||
// We discretize with H(div) and L2/H1 conforming elements.
|
||||
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
|
||||
void u_2d(const Vector & x, Vector & u)
|
||||
{
|
||||
real_t xi(x(0));
|
||||
real_t yi(x(1));
|
||||
|
||||
int p = 4;
|
||||
|
||||
u(0) = pow(xi,p + 1)*pow(yi,p );
|
||||
u(1) = -pow(xi,p )*pow(yi,p + 1);
|
||||
}
|
||||
|
||||
void u_3d(const Vector & x, Vector & u)
|
||||
{
|
||||
real_t xi(x(0));
|
||||
real_t yi(x(1));
|
||||
real_t zi(x(2));
|
||||
|
||||
int p = 4;
|
||||
|
||||
real_t cx = 3.0/4.0;
|
||||
real_t cy = 2.0/3.0;
|
||||
real_t cz = -cx - cy;
|
||||
|
||||
u(0) = cx*pow(xi,p + 1)*pow(yi,p )*pow(zi,p );
|
||||
u(1) = cy*pow(xi,p )*pow(yi,p + 1)*pow(zi,p );
|
||||
u(2) = cz*pow(xi,p )*pow(yi,p )*pow(zi,p + 1);
|
||||
}
|
||||
|
||||
// Define the analytical solution and forcing terms / boundary conditions
|
||||
void u_ex(const Vector & x, Vector & u)
|
||||
{
|
||||
if (x.Size() == 2)
|
||||
{
|
||||
u_2d(x, u);
|
||||
}
|
||||
else if (x.Size() == 3)
|
||||
{
|
||||
u_3d(x, u);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
StopWatch chrono;
|
||||
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../../data/square-nurbs.mesh";
|
||||
int ref_levels = -1;
|
||||
int order = 1;
|
||||
const char *device_config = "cpu";
|
||||
bool visualization = 1;
|
||||
bool NURBS = true;
|
||||
bool div_free = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly, -1 for auto.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&div_free, "-df", "--div-free", "-p","--proj",
|
||||
"Div-free or standard projection.");
|
||||
args.AddOption(&NURBS, "-n", "--nurbs", "-nn","--no-nurbs",
|
||||
"NURBS.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(mfem::out);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(mfem::out);
|
||||
|
||||
// 2. Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
device.Print();
|
||||
|
||||
// 3. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
|
||||
// largest number that gives a final mesh with no more than 10,000
|
||||
// elements.
|
||||
{
|
||||
if (ref_levels < 0)
|
||||
{
|
||||
ref_levels =
|
||||
(int)floor(log(5000./mesh->GetNE())/log(2.)/dim);
|
||||
}
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use the
|
||||
// Raviart-Thomas finite elements of the specified order.
|
||||
FiniteElementCollection *hdiv_coll = nullptr;
|
||||
FiniteElementCollection *l2_coll = nullptr;
|
||||
NURBSExtension *NURBSext = nullptr;
|
||||
|
||||
if (mesh->NURBSext&& NURBS)
|
||||
{
|
||||
hdiv_coll = new NURBS_HDivFECollection(order, dim);
|
||||
l2_coll = new NURBSFECollection(order);
|
||||
NURBSext = new NURBSExtension(mesh->NURBSext, order);
|
||||
mfem::out<<"Create NURBS fec and ext"<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
NURBS = false;
|
||||
hdiv_coll = new RT_FECollection(order, dim);
|
||||
l2_coll = new L2_FECollection(order, dim);
|
||||
mfem::out<<"Create Normal fec"<<std::endl;
|
||||
}
|
||||
|
||||
FiniteElementSpace *W_space = new FiniteElementSpace(mesh, NURBSext, l2_coll);
|
||||
FiniteElementSpace *R_space = new FiniteElementSpace(mesh,
|
||||
W_space->StealNURBSext(),
|
||||
hdiv_coll);
|
||||
|
||||
// 6. Define the BlockStructure of the problem, i.e. define the array of
|
||||
// offsets for each variable. The last component of the Array is the sum
|
||||
// of the dimensions of each block.
|
||||
Array<int> block_offsets(3); // number of variables + 1
|
||||
block_offsets[0] = 0;
|
||||
block_offsets[1] = R_space->GetVSize();
|
||||
block_offsets[2] = W_space->GetVSize();
|
||||
block_offsets.PartialSum();
|
||||
|
||||
mfem::out << "***********************************************************\n";
|
||||
mfem::out << "dim(R) = " << block_offsets[1] - block_offsets[0] << "\n";
|
||||
mfem::out << "dim(W) = " << block_offsets[2] - block_offsets[1] << "\n";
|
||||
mfem::out << "dim(R+W) = " << block_offsets.Last() << "\n";
|
||||
mfem::out << "***********************************************************\n";
|
||||
|
||||
// 7. Define the coefficients, analytical solution, and rhs of the PDE.
|
||||
ConstantCoefficient one(1.0);
|
||||
ConstantCoefficient zero(0.0);
|
||||
VectorFunctionCoefficient ucoeff(dim, u_ex);
|
||||
|
||||
// 8. Allocate memory (x, rhs) for the analytical solution and the right hand
|
||||
// side. Define the GridFunction u,p for the finite element solution and
|
||||
// linear forms fform and gform for the right hand side. The data
|
||||
// allocated by x and rhs are passed as a reference to the grid functions
|
||||
// (u,p) and the linear forms (fform, gform).
|
||||
MemoryType mt = device.GetMemoryType();
|
||||
BlockVector x(block_offsets, mt), rhs(block_offsets, mt);
|
||||
rhs = 0.0;
|
||||
|
||||
LinearForm *fform(new LinearForm);
|
||||
fform->Update(R_space, rhs.GetBlock(0), 0);
|
||||
fform->AddDomainIntegrator(new VectorFEDomainLFIntegrator(ucoeff));
|
||||
fform->Assemble();
|
||||
fform->SyncAliasMemory(rhs);
|
||||
|
||||
// 9. Assemble the finite element matrices for the Darcy operator
|
||||
//
|
||||
// D = [ M B^T ]
|
||||
// [ B 0 ]
|
||||
// where:
|
||||
//
|
||||
// M = \int_\Omega k u_h \cdot v_h d\Omega u_h, v_h \in R_h
|
||||
// B = -\int_\Omega \div u_h q_h d\Omega u_h \in R_h, q_h \in W_h
|
||||
BilinearForm *mVarf(new BilinearForm(R_space));
|
||||
MixedBilinearForm *bVarf(new MixedBilinearForm(R_space, W_space));
|
||||
|
||||
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(one));
|
||||
mVarf->Assemble();
|
||||
mVarf->Finalize();
|
||||
|
||||
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
|
||||
bVarf->Assemble();
|
||||
bVarf->Finalize();
|
||||
|
||||
SparseMatrix &M(mVarf->SpMat());
|
||||
SparseMatrix &B(bVarf->SpMat());
|
||||
B *= -1.;
|
||||
TransposeOperator *Bt = new TransposeOperator(&B);
|
||||
|
||||
BlockOperator darcyOp(block_offsets);
|
||||
darcyOp.SetBlock(0,0, &M);
|
||||
if (div_free) { darcyOp.SetBlock(0,1, Bt); }
|
||||
if (div_free) { darcyOp.SetBlock(1,0, &B); }
|
||||
|
||||
// 10. Construct the operators for preconditioner
|
||||
//
|
||||
// P = [ diag(M) 0 ]
|
||||
// [ 0 B diag(M)^-1 B^T ]
|
||||
//
|
||||
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
|
||||
// pressure Schur Complement
|
||||
Vector Md(mVarf->Height());
|
||||
M.GetDiag(Md);
|
||||
Md.HostReadWrite();
|
||||
SparseMatrix *MinvBt = Transpose(B);
|
||||
for (int i = 0; i < Md.Size(); i++)
|
||||
{
|
||||
MinvBt->ScaleRow(i, 1./Md(i));
|
||||
}
|
||||
SparseMatrix *S = Mult(B, *MinvBt);
|
||||
Solver *invS;
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
invS = new GSSmoother(*S);
|
||||
#else
|
||||
invS = new UMFPackSolver(*S);
|
||||
#endif
|
||||
invS->iterative_mode = false;
|
||||
|
||||
Solver *invM = new GSSmoother(M);
|
||||
invM->iterative_mode = false;
|
||||
|
||||
BlockDiagonalPreconditioner darcyPrec(block_offsets);
|
||||
darcyPrec.SetDiagonalBlock(0, invM);
|
||||
darcyPrec.SetDiagonalBlock(1, invS);
|
||||
|
||||
// 11. Solve the linear system with MINRES.
|
||||
// Check the norm of the unpreconditioned residual.
|
||||
int maxIter(10000);
|
||||
real_t rtol(10*std::numeric_limits<real_t>::epsilon());
|
||||
real_t atol(10*std::numeric_limits<real_t>::epsilon());
|
||||
|
||||
chrono.Clear();
|
||||
chrono.Start();
|
||||
MINRESSolver solver;
|
||||
solver.SetAbsTol(atol);
|
||||
solver.SetRelTol(rtol);
|
||||
solver.SetMaxIter(maxIter);
|
||||
solver.SetOperator(darcyOp);
|
||||
solver.SetPreconditioner(darcyPrec);
|
||||
solver.SetPrintLevel(2);
|
||||
x = 0.0;
|
||||
solver.Mult(rhs, x);
|
||||
if (device.IsEnabled()) { x.HostRead(); }
|
||||
chrono.Stop();
|
||||
|
||||
if (solver.GetConverged())
|
||||
{
|
||||
mfem::out << "MINRES converged in " << solver.GetNumIterations()
|
||||
<< " iterations with a residual norm of "
|
||||
<< solver.GetFinalNorm() << ".\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem::out << "MINRES did not converge in " << solver.GetNumIterations()
|
||||
<< " iterations. Residual norm is " << solver.GetFinalNorm()
|
||||
<< ".\n";
|
||||
}
|
||||
mfem::out << "MINRES solver took " << chrono.RealTime() << "s.\n";
|
||||
|
||||
// 12. Create the grid functions u and p
|
||||
GridFunction u, p, uu, vv, ww;
|
||||
u.MakeRef(R_space, x.GetBlock(0), 0);
|
||||
p.MakeRef(W_space, x.GetBlock(1), 0);
|
||||
|
||||
// 13. Save the mesh and the solution. This output can be viewed later using
|
||||
// GLVis: "glvis -m exsol.mesh -g sol_u.gf" or "glvis -m exsol.mesh -g
|
||||
// sol_p.gf".
|
||||
{
|
||||
ofstream mesh_ofs("exsol.mesh");
|
||||
mesh_ofs.precision(8);
|
||||
mesh->Print(mesh_ofs);
|
||||
|
||||
ofstream u_ofs("sol_u.gf");
|
||||
u_ofs.precision(8);
|
||||
u.Save(u_ofs);
|
||||
|
||||
ofstream p_ofs("sol_p.gf");
|
||||
p_ofs.precision(8);
|
||||
p.Save(p_ofs);
|
||||
}
|
||||
|
||||
// 14. Save data in the VisIt format
|
||||
VisItDataCollection visit_dc("Solenoidal", mesh);
|
||||
visit_dc.RegisterField("velocity", &u);
|
||||
visit_dc.RegisterField("pressure", &p);
|
||||
visit_dc.Save();
|
||||
|
||||
// 15. Save data in the ParaView format
|
||||
ParaViewDataCollection paraview_dc("Solenoidal", mesh);
|
||||
paraview_dc.SetPrefixPath("ParaView");
|
||||
paraview_dc.SetLevelsOfDetail(order);
|
||||
paraview_dc.SetCycle(0);
|
||||
paraview_dc.SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc.SetHighOrderOutput(true);
|
||||
paraview_dc.SetTime(0.0); // set the time
|
||||
paraview_dc.RegisterField("velocity",&u);
|
||||
paraview_dc.RegisterField("pressure",&p);
|
||||
paraview_dc.Save();
|
||||
|
||||
// 16. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream u_sock(vishost, visport);
|
||||
u_sock.precision(8);
|
||||
u_sock << "solution\n" << *mesh << u << "window_title 'Velocity'" << endl;
|
||||
socketstream p_sock(vishost, visport);
|
||||
p_sock.precision(8);
|
||||
p_sock << "solution\n" << *mesh << p << "window_title 'Pressure'" << endl;
|
||||
}
|
||||
|
||||
// 17. Compute errors
|
||||
int order_quad = 2*order+2;
|
||||
const IntegrationRule *irs[Geometry::NumGeom];
|
||||
for (int i=0; i < Geometry::NumGeom; ++i)
|
||||
{
|
||||
irs[i] = &(IntRules.Get(i, order_quad));
|
||||
}
|
||||
|
||||
real_t err_u = u.ComputeL2Error(ucoeff, irs);
|
||||
real_t err_p = p.ComputeL2Error(zero, irs);
|
||||
real_t err_div = u.ComputeDivError(&zero, irs);
|
||||
|
||||
mfem::out << "|| u_h - u_ex || = " << err_u << "\n";
|
||||
mfem::out << "|| div u_h - div u_ex || = " << err_div << "\n";
|
||||
mfem::out << "|| p_h - p_ex || = " << err_p << "\n";
|
||||
|
||||
// 18. Free the used memory.
|
||||
delete fform;
|
||||
delete invM;
|
||||
delete invS;
|
||||
delete S;
|
||||
delete Bt;
|
||||
delete MinvBt;
|
||||
delete mVarf;
|
||||
delete bVarf;
|
||||
delete W_space;
|
||||
delete R_space;
|
||||
delete l2_coll;
|
||||
delete hdiv_coll;
|
||||
delete mesh;
|
||||
|
||||
if (err_div > 1e4*std::numeric_limits<real_t>::epsilon() )
|
||||
{
|
||||
mfem::out << "std::numeric_limits<real_t>::epsilon() = "
|
||||
<< std::numeric_limits<real_t>::epsilon() << "\n";
|
||||
mfem_error("Divergence error larger than expected");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
# LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
#
|
||||
# This file is part of the MFEM library. For more information and source code
|
||||
# availability visit https://mfem.org.
|
||||
#
|
||||
# MFEM is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
|
||||
list(APPEND STAB_COMMON_SOURCES
|
||||
stab_tau.cpp stab_condif.cpp stab_navsto.cpp)
|
||||
list(APPEND STAB_COMMON_HEADERS
|
||||
stab_tau.hpp stab_condif.hpp stab_navsto.hpp manu.hpp skew.hpp)
|
||||
|
||||
set(STAB_COMMON_FILES
|
||||
EXTRA_SOURCES ${STAB_COMMON_SOURCES}
|
||||
EXTRA_HEADERS ${STAB_COMMON_HEADERS})
|
||||
|
||||
add_mfem_miniapp(condif
|
||||
MAIN condif.cpp
|
||||
${STAB_COMMON_FILES}
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(navsto
|
||||
MAIN navsto.cpp
|
||||
${STAB_COMMON_FILES}
|
||||
LIBRARIES mfem)
|
||||
|
||||
if (MFEM_ENABLE_TESTING)
|
||||
add_test(NAME ex_condif
|
||||
COMMAND $<TARGET_FILE:condif> -no-vis
|
||||
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
add_mfem_miniapp(navsto_p
|
||||
MAIN navsto_p.cpp
|
||||
${STAB_COMMON_FILES}
|
||||
LIBRARIES mfem)
|
||||
|
||||
if (MFEM_ENABLE_TESTING)
|
||||
add_test(NAME navsto_np=4
|
||||
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
|
||||
${MPIEXEC_PREFLAGS} $<TARGET_FILE:navsto> -no-vis
|
||||
${MPIEXEC_POSTFLAGS}
|
||||
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,405 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
//
|
||||
// Stabilized Convection-Diffusion
|
||||
|
||||
#include "stab_condif.hpp"
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
real_t att_param = 1.0;
|
||||
real_t kappa_param = 1.0;
|
||||
real_t pi = (real_t)(M_PI);
|
||||
|
||||
using VectorFun = std::function<void(const Vector & x, Vector & a)>;
|
||||
using ScalarFun = std::function<real_t(const Vector & x)>;
|
||||
|
||||
#include "skew.hpp"
|
||||
#include "manu.hpp"
|
||||
|
||||
void evaluate1D(Vector &x, Vector &f, GridFunction *gf, int lod)
|
||||
{
|
||||
// Get Mesh and Nodes gridfunction
|
||||
Mesh *mesh = gf->FESpace()->GetMesh();
|
||||
GridFunction *nodes = mesh->GetNodes();
|
||||
if (!nodes)
|
||||
{
|
||||
nodes = new GridFunction(gf->FESpace());
|
||||
mesh->GetNodes(*nodes);
|
||||
}
|
||||
|
||||
// Evaluate
|
||||
std::list<pair<real_t,real_t>> sol;
|
||||
Vector vals,coords;
|
||||
for (int i = 0; i < mesh->GetNE(); i++)
|
||||
{
|
||||
int geom = mesh->GetElementBaseGeometry(i);
|
||||
RefinedGeometry *refined_geo = GlobGeometryRefiner.Refine(( Geometry::Type)geom, 1, lod);
|
||||
|
||||
gf->GetValues(i, refined_geo->RefPts, vals);
|
||||
nodes->GetValues(i, refined_geo->RefPts, coords);
|
||||
|
||||
for (int j = 0; j < vals.Size(); j++)
|
||||
{
|
||||
sol.push_back(std::make_pair(coords[j],vals[j]));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort and make unique
|
||||
sol.sort();
|
||||
sol.unique();
|
||||
|
||||
// Convert to Vectors
|
||||
x.SetSize(sol.size());
|
||||
f.SetSize(sol.size());
|
||||
int i = 0;
|
||||
for (std::list<pair<real_t,real_t>>::iterator d = sol.begin() ; d != sol.end(); ++d, i++)
|
||||
{
|
||||
x[i] = d->first;
|
||||
f[i] = d->second;
|
||||
}
|
||||
}
|
||||
|
||||
StabType GetStabilisationType(int stype)
|
||||
{
|
||||
switch (stype)
|
||||
{
|
||||
case GALERKIN:
|
||||
mfem::out<<"Galerkin formulation"<<std::endl;
|
||||
break;
|
||||
case SUPG:
|
||||
mfem::out<<"SUPG formulation"<<std::endl;
|
||||
break;
|
||||
case GLS:
|
||||
mfem::out<<"GLS formulation"<<std::endl;
|
||||
break;
|
||||
case VMS:
|
||||
mfem::out<<"VMS formulation"<<std::endl;
|
||||
break;
|
||||
default:
|
||||
mfem::out<<"GAL"<<"\t"<<"SUPG"<<"\t"<<"GLS"<<"\t"<<"VMS"<<std::endl;
|
||||
mfem::out<<GALERKIN<<"\t"<<SUPG<<"\t"<<GLS<<"\t"<<VMS<<std::endl;
|
||||
mfem_error("Wrong formulation");
|
||||
}
|
||||
return (StabType) stype;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../../data/inline-quad.mesh";
|
||||
const char *ref_file = "";
|
||||
int problem = 0;
|
||||
int sstype = -2;
|
||||
bool static_cond = false;
|
||||
bool visualization = false;
|
||||
int lod = 0;
|
||||
real_t penalty = -1;
|
||||
Array<int> order(1);
|
||||
order[0] = 2;
|
||||
int ref_levels = 0;
|
||||
|
||||
bool mono = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ref_file, "-rf", "--ref-file",
|
||||
"File with refinement data");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh.");
|
||||
args.AddOption(&kappa_param , "-k", "--kappa",
|
||||
"Sets the diffusion parameters, should be positive.");
|
||||
args.AddOption(&att_param , "-a", "--att",
|
||||
"Sets the velocity direction");
|
||||
args.AddOption(&problem, "-p", "--problem",
|
||||
"Select the problem to solve:\n\t"
|
||||
" 0 = convection skew-to-the mesh\n\t"
|
||||
" 1 = manufactured solution\n");
|
||||
args.AddOption(&sstype, "-s", "--stab", " Stabilization type:\n\t"
|
||||
" -2 = Galerkin\n\t"
|
||||
" -1 = GLS\n\t"
|
||||
" 0 = SUPG\n\t"
|
||||
" 1 = VMS\n");
|
||||
args.AddOption(&mono, "-mo", "--mono", "-co",
|
||||
"--comp",
|
||||
"Use a monolithic integrator or a composed one.");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&lod, "-lod", "--level-of-detail",
|
||||
"Refinement level for 1D solution output (0 means no output).");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
|
||||
}
|
||||
args.PrintOptions(mfem::out);
|
||||
|
||||
|
||||
|
||||
// 2. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 3. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement and knot insertion of knots defined
|
||||
// in a refinement file. We choose 'ref_levels' to be the largest number
|
||||
// that gives a final mesh with no more than 50,000 elements.
|
||||
{
|
||||
// Mesh refinement as defined in refinement file
|
||||
if (mesh->NURBSext && (strlen(ref_file) != 0))
|
||||
{
|
||||
mesh->RefineNURBSFromFile(ref_file);
|
||||
}
|
||||
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
mesh->PrintInfo();
|
||||
}
|
||||
|
||||
// 4. Define a finite element space on the mesh. Here we use continuous
|
||||
// Lagrange finite elements of the specified order. If order < 1, we
|
||||
// instead use an isoparametric/isogeometric space.
|
||||
FiniteElementCollection *fec;
|
||||
NURBSExtension *NURBSext = nullptr;
|
||||
int own_fec = 1;
|
||||
|
||||
if (mesh->NURBSext)
|
||||
{
|
||||
fec = new NURBSFECollection(order[0]);
|
||||
|
||||
int nkv = mesh->NURBSext->GetNKV();
|
||||
if (order.Size() == 1)
|
||||
{
|
||||
int tmp = order[0];
|
||||
order.SetSize(nkv);
|
||||
order = tmp;
|
||||
}
|
||||
|
||||
if (order.Size() != nkv ) { mfem_error("Wrong number of orders set."); }
|
||||
NURBSext = new NURBSExtension(mesh->NURBSext, order);
|
||||
}
|
||||
else if (order[0] == -1) // Isoparametric
|
||||
{
|
||||
if (mesh->GetNodes())
|
||||
{
|
||||
fec = mesh->GetNodes()->OwnFEC();
|
||||
own_fec = 0;
|
||||
mfem::out << "Using isoparametric FEs: " << fec->Name() << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem::out <<"Mesh does not have FEs --> Assume order 1.\n";
|
||||
fec = new H1_FECollection(1, dim);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (order.Size() > 1) { cout <<"Wrong number of orders set, needs one.\n"; }
|
||||
fec = new H1_FECollection(abs(order[0]), dim);
|
||||
}
|
||||
|
||||
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, NURBSext, fec);
|
||||
mfem::out << "Number of finite element unknowns: "
|
||||
<< fespace->GetTrueVSize() << endl;
|
||||
|
||||
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined by marking all
|
||||
// the boundary attributes from the mesh as essential (Dirichlet) and
|
||||
// converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
|
||||
// the basis functions in the finite element fespace.
|
||||
VectorFunctionCoefficient *adv, *grad;
|
||||
FunctionCoefficient *kappa,*force, *sol, *lap;
|
||||
|
||||
if (problem == 0)
|
||||
{
|
||||
if (mesh->Dimension() != 2) mfem_error("Advection skew to the mesh needs a 2D mesh!");
|
||||
adv = new VectorFunctionCoefficient(mesh->Dimension(), skew::adv);
|
||||
kappa= new FunctionCoefficient(skew::kappa);
|
||||
|
||||
force = new FunctionCoefficient(skew::force);
|
||||
sol = new FunctionCoefficient(skew::sol);
|
||||
grad = new VectorFunctionCoefficient(mesh->Dimension(), skew::grad);
|
||||
lap = new FunctionCoefficient(skew::laplace);
|
||||
|
||||
}
|
||||
else if (problem == 1)
|
||||
{
|
||||
adv = new VectorFunctionCoefficient(mesh->Dimension(), manufactured::adv);
|
||||
kappa= new FunctionCoefficient(manufactured::kappa);
|
||||
|
||||
force = new FunctionCoefficient(manufactured::force);
|
||||
sol = new FunctionCoefficient(manufactured::sol);
|
||||
grad = new VectorFunctionCoefficient(mesh->Dimension(), manufactured::grad);
|
||||
lap = new FunctionCoefficient(manufactured::laplace);
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem_error("Incorrect problem!");
|
||||
}
|
||||
|
||||
// 7. Define the solution vector x as a finite element grid function
|
||||
// corresponding to fespace. Initialize x with initial guess of zero,
|
||||
// which satisfies the boundary conditions.
|
||||
GridFunction x(fespace);
|
||||
x.ProjectCoefficient(*sol);
|
||||
|
||||
if (problem == 1)
|
||||
{
|
||||
Vector norm(3);
|
||||
norm[0] = x.ComputeL2Error(*sol);
|
||||
norm[1] = x.ComputeGradError(grad);
|
||||
norm[2] = x.ComputeLaplaceError(lap);
|
||||
|
||||
mfem::out << "|| x_h - x_ex || = " << norm[0] << "\n";
|
||||
mfem::out << "|| grad x_h - grad x_ex || = " << norm[1] << "\n";
|
||||
mfem::out << "|| lap x_h - lap x_ex || = " << norm[2] << "\n";
|
||||
}
|
||||
|
||||
// 9. Assemble the bilinear form and the corresponding linear system,
|
||||
// applying any necessary transformations such as: eliminating boundary
|
||||
// conditions, applying conforming constraints for non-conforming AMR,
|
||||
// static condensation, etc.
|
||||
StabType stype = GetStabilisationType(sstype);
|
||||
FFH92Tau tau (adv, kappa, fespace);
|
||||
StabConDifComposition stab_condif_comp(adv, kappa, force, &tau);
|
||||
|
||||
BilinearForm a(fespace);
|
||||
LinearForm b(fespace);
|
||||
|
||||
if (mono)
|
||||
{
|
||||
a.AddDomainIntegrator(new StabConDifIntegrator(adv, kappa, force, &tau, stype));
|
||||
b.AddDomainIntegrator(new StabConDifIntegrator(adv, kappa, force, &tau, stype));
|
||||
}
|
||||
else
|
||||
{
|
||||
stab_condif_comp.SetBilinearIntegrators(&a, stype);
|
||||
stab_condif_comp.SetLinearIntegrators(&b, stype);
|
||||
}
|
||||
|
||||
a.Assemble();
|
||||
b.Assemble();
|
||||
|
||||
if (static_cond) { a.EnableStaticCondensation(); }
|
||||
SparseMatrix A;
|
||||
Vector B, X;
|
||||
|
||||
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
|
||||
|
||||
mfem::out << "Size of linear system: " << A.Height() << endl;
|
||||
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
// 10. Define a simple Jacobi preconditioner and use it to
|
||||
// solve the system A X = B with PCG.
|
||||
GSSmoother M(A);
|
||||
GMRES(A, M, B, X, 1, 2000, 2000, 1e-16, 0.0);
|
||||
#else
|
||||
// 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
|
||||
UMFPackSolver umf_solver;
|
||||
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
|
||||
umf_solver.SetOperator(A);
|
||||
umf_solver.Mult(B, X);
|
||||
#endif
|
||||
|
||||
// 11. Recover the solution as a finite element grid function.
|
||||
a.RecoverFEMSolution(X, b, x);
|
||||
|
||||
// 12. Save the refined mesh and the solution. This output can be viewed later
|
||||
// using GLVis: "glvis -m refined.mesh -g sol.gf".
|
||||
{
|
||||
ofstream mesh_ofs("refined.mesh");
|
||||
mesh_ofs.precision(8);
|
||||
mesh->Print(mesh_ofs);
|
||||
ofstream sol_ofs("sol.gf");
|
||||
sol_ofs.precision(8);
|
||||
x.Save(sol_ofs);
|
||||
sol_ofs.close();
|
||||
}
|
||||
|
||||
// 13. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *mesh << x << flush;
|
||||
}
|
||||
|
||||
if (mesh->Dimension() == 1 && lod > 0)
|
||||
{
|
||||
Vector coord, val;
|
||||
evaluate1D(coord, val, &x, lod);
|
||||
|
||||
ofstream sol_ofs("solution.dat");
|
||||
for (int i = 0; i < x.Size();i++)
|
||||
{
|
||||
sol_ofs<<coord[i] <<"\t"<<val[i]<<endl;
|
||||
}
|
||||
sol_ofs.close();
|
||||
}
|
||||
|
||||
// 14. Error computation
|
||||
if (problem == 1)
|
||||
{
|
||||
Vector norm(3);
|
||||
norm[0] = x.ComputeL2Error(*sol);
|
||||
norm[1] = x.ComputeGradError(grad);
|
||||
norm[2] = x.ComputeLaplaceError(lap);
|
||||
|
||||
mfem::out << "|| x_h - x_ex || = " << norm[0] << "\n";
|
||||
mfem::out << "|| grad x_h - grad x_ex || = " << norm[1] << "\n";
|
||||
mfem::out << "|| lap x_h - lap x_ex || = " << norm[2] << "\n";
|
||||
}
|
||||
|
||||
// 15. Save data in the VisIt format
|
||||
VisItDataCollection visit_dc("condif", mesh);
|
||||
visit_dc.RegisterField("solution", &x);
|
||||
visit_dc.Save();
|
||||
|
||||
// 16. Free the used memory.
|
||||
delete fespace;
|
||||
if (own_fec) { delete fec; }
|
||||
delete mesh;
|
||||
delete adv, grad;
|
||||
delete kappa, force, sol, lap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
namespace manufactured
|
||||
{
|
||||
|
||||
//----------------------------------------------------------
|
||||
void adv(const Vector & x, Vector & a)
|
||||
{
|
||||
a[1] = 1.0/(1.0 + att_param*att_param);
|
||||
a[0] = sqrt(1.0 - a[1]*a[1]);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
real_t kappa(const Vector & x)
|
||||
{
|
||||
return kappa_param;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
real_t force(const Vector & x)
|
||||
{
|
||||
int d = x.Size();
|
||||
|
||||
Vector a(d);
|
||||
adv(x, a);
|
||||
real_t ax = a[0];
|
||||
real_t ay = 0.0;
|
||||
real_t az = 0.0;
|
||||
real_t k = kappa(x);
|
||||
|
||||
real_t sx = sin(pi*x[0]);
|
||||
real_t cx = cos(pi*x[0]);
|
||||
real_t sy = 1.0;
|
||||
real_t cy = 1.0;
|
||||
real_t sz = 1.0;
|
||||
real_t cz = 1.0;
|
||||
|
||||
if (d >= 2)
|
||||
{
|
||||
sy = sin(pi*x[1]);
|
||||
cy = cos(pi*x[1]);
|
||||
ay = a[1];
|
||||
}
|
||||
if (d >= 3)
|
||||
{
|
||||
sz = sin(pi*x[2]);
|
||||
cz = cos(pi*x[2]);
|
||||
az = a[2];
|
||||
}
|
||||
|
||||
return ax*pi*cx*sy*sz
|
||||
+ ay*pi*sx*cy*sz
|
||||
+ az*pi*sx*sy*cz + d*k*pi*pi*sx*sy*sz;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
real_t sol(const Vector & x)
|
||||
{
|
||||
real_t sx = sin(pi*x[0]);
|
||||
real_t sy = 1.0;
|
||||
real_t sz = 1.0;
|
||||
|
||||
int d = x.Size();
|
||||
if (d >= 2)
|
||||
{
|
||||
sy = sin(pi*x[1]);
|
||||
}
|
||||
if (d >= 3)
|
||||
{
|
||||
sz = sin(pi*x[2]);
|
||||
}
|
||||
|
||||
return sx*sy*sz;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------
|
||||
void grad(const Vector & x, Vector &grad)
|
||||
{
|
||||
real_t sx = sin(pi*x[0]);
|
||||
real_t sy = 1.0;
|
||||
real_t sz = 1.0;
|
||||
|
||||
real_t gx = pi*cos(pi*x[0]);
|
||||
real_t gy = 0.0;
|
||||
real_t gz = 0.0;
|
||||
|
||||
grad[0] = gx;
|
||||
|
||||
int d = x.Size();
|
||||
if (d >= 2)
|
||||
{
|
||||
sy = sin(pi*x[1]);
|
||||
gy = pi*cos(pi*x[1]);
|
||||
|
||||
grad[0] = gx*sy;
|
||||
grad[1] = sx*gy;
|
||||
}
|
||||
if (d >= 3)
|
||||
{
|
||||
sz = sin(pi*x[2]);
|
||||
gz = pi*cos(pi*x[2]);
|
||||
|
||||
grad[0] = gx*sy*sz;
|
||||
grad[1] = sx*gy*sz;
|
||||
grad[2] = sx*sy*gz;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
real_t laplace(const Vector & x)
|
||||
{
|
||||
return -x.Size()*pi*pi*sol(x);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
//
|
||||
// Stabilized Navier-Stokes
|
||||
|
||||
#include "stab_navsto.hpp"
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
real_t kappa_param = 1.0;
|
||||
real_t pi = (real_t)(M_PI);
|
||||
|
||||
using VectorFun = std::function<void(const Vector & x, Vector & a)>;
|
||||
using ScalarFun = std::function<real_t(const Vector & x)>;
|
||||
|
||||
void sol_fun(const Vector & x, Vector &sol)
|
||||
{
|
||||
sol = 0.0;
|
||||
if ((x[1] - 0.99 > 0.0) &&
|
||||
(fabs(x[0] - 0.5) < 0.49) )
|
||||
{
|
||||
sol[0] = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
real_t kappa_fun(const Vector & x)
|
||||
{
|
||||
return kappa_param;
|
||||
}
|
||||
|
||||
void force_fun(const Vector & x, Vector &f)
|
||||
{
|
||||
f = 0.0;
|
||||
// f[0] = x[1]*(1.0-x[1])*x[0]*(1.0-x[0]);
|
||||
}
|
||||
|
||||
StabType GetStabilisationType(int stype)
|
||||
{
|
||||
switch (stype)
|
||||
{
|
||||
case GALERKIN:
|
||||
mfem::out<<"Galerkin formulation"<<std::endl;
|
||||
break;
|
||||
case SUPG:
|
||||
mfem::out<<"SUPG formulation"<<std::endl;
|
||||
break;
|
||||
case GLS:
|
||||
mfem::out<<"GLS formulation"<<std::endl;
|
||||
break;
|
||||
case VMS:
|
||||
mfem::out<<"VMS formulation"<<std::endl;
|
||||
break;
|
||||
default:
|
||||
mfem::out<<"GAL"<<"\t"<<"SUPG"<<"\t"<<"GLS"<<"\t"<<"VMS"<<std::endl;
|
||||
mfem::out<<GALERKIN<<"\t"<<SUPG<<"\t"<<GLS<<"\t"<<VMS<<std::endl;
|
||||
mfem_error("Wrong formulation");
|
||||
}
|
||||
return (StabType) stype;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Parse command-line options.
|
||||
const char *mesh_file = "../../data/inline-quad.mesh";
|
||||
const char *ref_file = "";
|
||||
int problem = 0;
|
||||
int sstype = -2;
|
||||
bool static_cond = false;
|
||||
bool visualization = false;
|
||||
|
||||
real_t penalty = -1;
|
||||
int order = 1;
|
||||
int ref_levels = 0;
|
||||
|
||||
bool mono = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ref_file, "-rf", "--ref-file",
|
||||
"File with refinement data");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order isoparametric space.");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh.");
|
||||
args.AddOption(&kappa_param , "-k", "--kappa",
|
||||
"Sets the diffusion parameters, should be positive.");
|
||||
args.AddOption(&problem, "-p", "--problem",
|
||||
"Select the problem to solve:\n\t"
|
||||
" 0 = convection skew-to-the mesh\n\t"
|
||||
" 1 = manufactured solution\n");
|
||||
args.AddOption(&sstype, "-s", "--stab", " Stabilization type:\n\t"
|
||||
" -2 = Galerkin\n\t"
|
||||
" -1 = GLS\n\t"
|
||||
" 0 = SUPG\n\t"
|
||||
" 1 = VMS\n");
|
||||
args.AddOption(&mono, "-mo", "--mono", "-co",
|
||||
"--comp",
|
||||
"Use a monolithic integrator or a composed one.");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
|
||||
}
|
||||
args.PrintOptions(mfem::out);
|
||||
|
||||
// Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
|
||||
// Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement and knot insertion of knots defined
|
||||
// in a refinement file. We choose 'ref_levels' to be the largest number
|
||||
// that gives a final mesh with no more than 50,000 elements.
|
||||
{
|
||||
// Mesh refinement as defined in refinement file
|
||||
if (mesh.NURBSext && (strlen(ref_file) != 0))
|
||||
{
|
||||
mesh.RefineNURBSFromFile(ref_file);
|
||||
}
|
||||
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
mesh.PrintInfo();
|
||||
}
|
||||
|
||||
// Define a finite element space on the mesh. Here we use continuous
|
||||
// Lagrange finite elements of the specified order. If order < 1, we
|
||||
// instead use an isoparametric/isogeometric space.
|
||||
Array<FiniteElementCollection *> fecs(2);
|
||||
fecs[0] = new H1_FECollection(order, dim);
|
||||
fecs[1] = new H1_FECollection(order, dim);
|
||||
|
||||
Array<FiniteElementSpace *> spaces(2);
|
||||
spaces[0] = new FiniteElementSpace(&mesh, fecs[0], dim);
|
||||
spaces[1] = new FiniteElementSpace(&mesh, fecs[1]);
|
||||
|
||||
mfem::out << "Number of finite element unknowns:\n"
|
||||
<< "\tVelocity = "<<spaces[0]->GetTrueVSize() << endl
|
||||
<< "\tPressure = "<<spaces[1]->GetTrueVSize() << endl;
|
||||
// Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined by marking all
|
||||
// the boundary attributes from the mesh as essential (Dirichlet) and
|
||||
// converting them to a list of true dofs.
|
||||
Array<Array<int> *> ess_bdr(2);
|
||||
Array<int> ess_tdof_list;
|
||||
|
||||
Array<int> ess_bdr_u(spaces[0]->GetMesh()->bdr_attributes.Max());
|
||||
Array<int> ess_bdr_p(spaces[1]->GetMesh()->bdr_attributes.Max());
|
||||
|
||||
ess_bdr_p = 0;
|
||||
ess_bdr_u = 1;
|
||||
|
||||
ess_bdr[0] = &ess_bdr_u;
|
||||
ess_bdr[1] = &ess_bdr_p;
|
||||
|
||||
// Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
|
||||
// the basis functions in the finite element fespace.
|
||||
|
||||
// Define the solution vector xp as a finite element grid function
|
||||
Array<int> bOffsets(3);
|
||||
bOffsets[0] = 0;
|
||||
bOffsets[1] = spaces[0]->GetTrueVSize();
|
||||
bOffsets[2] = spaces[1]->GetTrueVSize();
|
||||
bOffsets.PartialSum();
|
||||
|
||||
BlockVector xp(bOffsets);
|
||||
|
||||
GridFunction x_u(spaces[0]);
|
||||
GridFunction x_p(spaces[1]);
|
||||
|
||||
x_u.MakeTRef(spaces[0], xp.GetBlock(0), 0);
|
||||
x_p.MakeTRef(spaces[1], xp.GetBlock(1), 0);
|
||||
|
||||
VectorFunctionCoefficient sol(dim, sol_fun);
|
||||
|
||||
x_u.ProjectCoefficient(sol);
|
||||
x_p = 0.0;
|
||||
|
||||
x_u.SetTrueVector();
|
||||
x_p.SetTrueVector();
|
||||
|
||||
// Define the output
|
||||
VisItDataCollection visit_dc("navsto", &mesh);
|
||||
visit_dc.RegisterField("u", &x_u);
|
||||
visit_dc.RegisterField("p", &x_p);
|
||||
visit_dc.SetCycle(0);
|
||||
visit_dc.Save();
|
||||
|
||||
// Define the problem parameters
|
||||
FunctionCoefficient kappa(kappa_fun);
|
||||
VectorFunctionCoefficient force(dim, force_fun);
|
||||
|
||||
// Define the stabilisation parameters
|
||||
VectorGridFunctionCoefficient adv(&x_u);
|
||||
ElasticInverseEstimateCoefficient invEst(spaces[0]);
|
||||
FFH92Tau tau(&adv, &kappa, &invEst, 4.0);
|
||||
FF91Delta delta(&adv, &kappa, &invEst);
|
||||
|
||||
tau.print = delta.print = true;
|
||||
|
||||
// Define the block nonlinear form
|
||||
BlockNonlinearForm Hform(spaces);
|
||||
Hform.AddDomainIntegrator(new StabInNavStoIntegrator(kappa, force, tau, delta));
|
||||
Array<Vector *> rhs(2);
|
||||
rhs = nullptr; // Set all entries in the array
|
||||
Hform.SetEssentialBC(ess_bdr, rhs);
|
||||
|
||||
// Set up the preconditioner
|
||||
JacobianPreconditioner jac_prec(bOffsets,
|
||||
Array<Solver *>({new GSSmoother(0,5),
|
||||
new GSSmoother(0,5)}));
|
||||
|
||||
// Set up the Jacobian solver
|
||||
GeneralResidualMonitor j_monitor("\t\t\t\tFGMRES", 25);
|
||||
FGMRESSolver j_gmres;
|
||||
j_gmres.iterative_mode = false;
|
||||
j_gmres.SetRelTol(1e-2);
|
||||
j_gmres.SetAbsTol(1e-12);
|
||||
j_gmres.SetMaxIter(300);
|
||||
j_gmres.SetPrintLevel(-1);
|
||||
j_gmres.SetMonitor(j_monitor);
|
||||
j_gmres.SetPreconditioner(jac_prec);
|
||||
|
||||
// Set up the newton solver
|
||||
SystemResidualMonitor newton_monitor("Newton", 1, bOffsets, &visit_dc);
|
||||
NewtonSolver newton_solver;
|
||||
newton_solver.iterative_mode = true;
|
||||
newton_solver.SetPrintLevel(-1);
|
||||
newton_solver.SetMonitor(newton_monitor);
|
||||
newton_solver.SetRelTol(1e-4);
|
||||
newton_solver.SetAbsTol(1e-8);
|
||||
newton_solver.SetMaxIter(25);
|
||||
newton_solver.SetSolver(j_gmres);
|
||||
newton_solver.SetOperator(Hform);
|
||||
|
||||
// Solve the Newton system
|
||||
Vector zero;
|
||||
newton_solver.Mult(zero, xp);
|
||||
|
||||
// Save data in the VisIt format
|
||||
visit_dc.SetCycle(999999);
|
||||
visit_dc.Save();
|
||||
|
||||
// Free the used memory.
|
||||
for (int i = 0; i < fecs.Size(); ++i)
|
||||
{
|
||||
delete fecs[i];
|
||||
}
|
||||
for (int i = 0; i < spaces.Size(); ++i)
|
||||
{
|
||||
delete spaces[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
//
|
||||
// Stabilized Navier-Stokes
|
||||
|
||||
#include "stab_navsto.hpp"
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
real_t kappa_param = 1.0;
|
||||
real_t pi = (real_t)(M_PI);
|
||||
|
||||
using VectorFun = std::function<void(const Vector & x, Vector & a)>;
|
||||
using ScalarFun = std::function<real_t(const Vector & x)>;
|
||||
|
||||
void sol_fun(const Vector & x, Vector &sol)
|
||||
{
|
||||
sol = 0.0;
|
||||
if ((x[1] - 0.99 > 0.0) &&
|
||||
(fabs(x[0] - 0.5) < 0.49) )
|
||||
{
|
||||
sol[0] = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
real_t kappa_fun(const Vector & x)
|
||||
{
|
||||
return kappa_param;
|
||||
}
|
||||
|
||||
void force_fun(const Vector & x, Vector &f)
|
||||
{
|
||||
f = 0.0;
|
||||
// f[0] = x[1]*(1.0-x[1])*x[0]*(1.0-x[0]);
|
||||
}
|
||||
|
||||
StabType GetStabilisationType(int stype)
|
||||
{
|
||||
switch (stype)
|
||||
{
|
||||
case GALERKIN:
|
||||
mfem::out<<"Galerkin formulation"<<std::endl;
|
||||
break;
|
||||
case SUPG:
|
||||
mfem::out<<"SUPG formulation"<<std::endl;
|
||||
break;
|
||||
case GLS:
|
||||
mfem::out<<"GLS formulation"<<std::endl;
|
||||
break;
|
||||
case VMS:
|
||||
mfem::out<<"VMS formulation"<<std::endl;
|
||||
break;
|
||||
default:
|
||||
mfem::out<<"GAL"<<"\t"<<"SUPG"<<"\t"<<"GLS"<<"\t"<<"VMS"<<std::endl;
|
||||
mfem::out<<GALERKIN<<"\t"<<SUPG<<"\t"<<GLS<<"\t"<<VMS<<std::endl;
|
||||
mfem_error("Wrong formulation");
|
||||
}
|
||||
return (StabType) stype;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Initialize MPI and HYPRE.
|
||||
Mpi::Init(argc, argv);
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
// Parse command-line options.
|
||||
const char *mesh_file = "../../data/inline-quad.mesh";
|
||||
const char *ref_file = "";
|
||||
int problem = 0;
|
||||
int sstype = -2;
|
||||
bool static_cond = false;
|
||||
bool visualization = false;
|
||||
|
||||
real_t penalty = -1;
|
||||
int order = 1;
|
||||
int ref_levels = 0;
|
||||
|
||||
bool mono = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ref_file, "-rf", "--ref-file",
|
||||
"File with refinement data");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order isoparametric space.");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh.");
|
||||
args.AddOption(&kappa_param , "-k", "--kappa",
|
||||
"Sets the diffusion parameters, should be positive.");
|
||||
args.AddOption(&problem, "-p", "--problem",
|
||||
"Select the problem to solve:\n\t"
|
||||
" 0 = convection skew-to-the mesh\n\t"
|
||||
" 1 = manufactured solution\n");
|
||||
args.AddOption(&sstype, "-s", "--stab", " Stabilization type:\n\t"
|
||||
" -2 = Galerkin\n\t"
|
||||
" -1 = GLS\n\t"
|
||||
" 0 = SUPG\n\t"
|
||||
" 1 = VMS\n");
|
||||
args.AddOption(&mono, "-mo", "--mono", "-co",
|
||||
"--comp",
|
||||
"Use a monolithic integrator or a composed one.");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0) args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0) args.PrintOptions(cout);
|
||||
|
||||
// Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
|
||||
// the same code.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
|
||||
// Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement and knot insertion of knots defined
|
||||
// in a refinement file. We choose 'ref_levels' to be the largest number
|
||||
// that gives a final mesh with no more than 50,000 elements.
|
||||
{
|
||||
// Mesh refinement as defined in refinement file
|
||||
if (mesh.NURBSext && (strlen(ref_file) != 0))
|
||||
{
|
||||
mesh.RefineNURBSFromFile(ref_file);
|
||||
}
|
||||
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
if (myid == 0) mesh.PrintInfo();
|
||||
}
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
|
||||
// Define a finite element space on the mesh. Here we use continuous
|
||||
// Lagrange finite elements of the specified order. If order < 1, we
|
||||
// instead use an isoparametric/isogeometric space.
|
||||
Array<FiniteElementCollection *> fecs(2);
|
||||
fecs[0] = new H1_FECollection(order, dim);
|
||||
fecs[1] = new H1_FECollection(order, dim);
|
||||
|
||||
Array<ParFiniteElementSpace *> spaces(2);
|
||||
spaces[0] = new ParFiniteElementSpace(&pmesh, fecs[0], dim);//, Ordering::byVDIM);
|
||||
spaces[1] = new ParFiniteElementSpace(&pmesh, fecs[1]);
|
||||
|
||||
Array<int> tdof(num_procs),udof(num_procs),pdof(num_procs);
|
||||
tdof = 0;
|
||||
tdof[myid] = spaces[0]->TrueVSize();
|
||||
MPI_Reduce(tdof.GetData(), udof.GetData(), num_procs, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
|
||||
|
||||
tdof = 0;
|
||||
tdof[myid] = spaces[1]->TrueVSize();
|
||||
MPI_Reduce(tdof.GetData(), pdof.GetData(), num_procs, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "Number of finite element unknowns:\n";
|
||||
mfem::out << "\tVelocity = "<<spaces[0]->GlobalTrueVSize() << endl;
|
||||
mfem::out << "\tPressure = "<<spaces[1]->GlobalTrueVSize() << endl;
|
||||
mfem::out << "Number of finite element unknowns per partition:\n";
|
||||
mfem::out << "\tVelocity = ";udof.Print(mfem::out, num_procs);
|
||||
mfem::out << "\tPressure = ";pdof.Print(mfem::out, num_procs);
|
||||
}
|
||||
|
||||
// Mark all velocity boundary dofs as essential
|
||||
Array<Array<int> *> ess_bdr(2);
|
||||
// Array<int> ess_tdof_list;
|
||||
|
||||
Array<int> ess_bdr_u(spaces[0]->GetMesh()->bdr_attributes.Max());
|
||||
Array<int> ess_bdr_p(spaces[1]->GetMesh()->bdr_attributes.Max());
|
||||
|
||||
ess_bdr_p = 0;
|
||||
ess_bdr_u = 1;
|
||||
|
||||
ess_bdr[0] = &ess_bdr_u;
|
||||
ess_bdr[1] = &ess_bdr_p;
|
||||
|
||||
// Define the solution vector xp as a finite element grid function
|
||||
Array<int> bOffsets(3);
|
||||
bOffsets[0] = 0;
|
||||
bOffsets[1] = spaces[0]->TrueVSize();
|
||||
bOffsets[2] = spaces[1]->TrueVSize();
|
||||
bOffsets.PartialSum();
|
||||
|
||||
BlockVector xp(bOffsets);
|
||||
|
||||
ParGridFunction x_u(spaces[0]);
|
||||
ParGridFunction x_p(spaces[1]);
|
||||
|
||||
VectorFunctionCoefficient sol(dim, sol_fun);
|
||||
x_u.ProjectCoefficient(sol);
|
||||
x_p = 0.0;
|
||||
|
||||
x_u.GetTrueDofs(xp.GetBlock(0));
|
||||
x_p.GetTrueDofs(xp.GetBlock(1));
|
||||
|
||||
VisItDataCollection visit_dc("navsto", &pmesh);
|
||||
visit_dc.RegisterField("u", &x_u);
|
||||
visit_dc.RegisterField("p", &x_p);
|
||||
visit_dc.SetCycle(0);
|
||||
visit_dc.Save();
|
||||
|
||||
// Define the problem parameters
|
||||
FunctionCoefficient kappa(kappa_fun);
|
||||
VectorFunctionCoefficient force(dim, force_fun);
|
||||
|
||||
// Define the stabilisation parameters
|
||||
VectorGridFunctionCoefficient adv(&x_u);
|
||||
ElasticInverseEstimateCoefficient invEst(spaces[0]);
|
||||
FFH92Tau tau(&adv, &kappa, &invEst, 4.0);
|
||||
FF91Delta delta(&adv, &kappa, &invEst);
|
||||
|
||||
tau.print = delta.print = (myid == 0);
|
||||
|
||||
// Define the block nonlinear form
|
||||
ParBlockNonlinearForm Hform(spaces);
|
||||
Hform.AddDomainIntegrator(new StabInNavStoIntegrator(kappa, force, tau, delta));
|
||||
Array<Vector *> rhs(2);
|
||||
rhs = nullptr; // Set all entries in the array
|
||||
Hform.SetEssentialBC(ess_bdr, rhs);
|
||||
|
||||
// Set up the preconditioner
|
||||
JacobianPreconditioner jac_prec(bOffsets,
|
||||
Array<Solver *>({new HypreSmoother(),
|
||||
new HypreSmoother()}));
|
||||
|
||||
// Set up the Jacobian solver
|
||||
GeneralResidualMonitor j_monitor(MPI_COMM_WORLD,"\t\t\t\tFGMRES", 25);
|
||||
FGMRESSolver j_gmres(MPI_COMM_WORLD);
|
||||
j_gmres.iterative_mode = false;
|
||||
j_gmres.SetRelTol(1e-2);
|
||||
j_gmres.SetAbsTol(1e-12);
|
||||
j_gmres.SetMaxIter(300);
|
||||
j_gmres.SetPrintLevel(-1);
|
||||
j_gmres.SetMonitor(j_monitor);
|
||||
j_gmres.SetPreconditioner(jac_prec);
|
||||
|
||||
// Set up the newton solver
|
||||
SystemResidualMonitor newton_monitor(MPI_COMM_WORLD,"Newton", 1, bOffsets, &visit_dc, &xp,
|
||||
Array<ParGridFunction *>({&x_u, &x_p}));
|
||||
NewtonSolver newton_solver(MPI_COMM_WORLD);
|
||||
newton_solver.iterative_mode = true;
|
||||
newton_solver.SetPrintLevel(-1);
|
||||
newton_solver.SetMonitor(newton_monitor);
|
||||
newton_solver.SetRelTol(1e-4);
|
||||
newton_solver.SetAbsTol(1e-8);
|
||||
newton_solver.SetMaxIter(25);
|
||||
newton_solver.SetSolver(j_gmres);
|
||||
newton_solver.SetOperator(Hform);
|
||||
|
||||
// Solve the Newton system
|
||||
Vector zero;
|
||||
newton_solver.Mult(zero, xp);
|
||||
|
||||
// Save data in the VisIt format
|
||||
// Define the output
|
||||
// Save data in the VisIt format
|
||||
visit_dc.SetCycle(999999);
|
||||
visit_dc.Save();
|
||||
|
||||
// Free the used memory.
|
||||
for (int i = 0; i < fecs.Size(); ++i)
|
||||
{
|
||||
delete fecs[i];
|
||||
}
|
||||
for (int i = 0; i < spaces.Size(); ++i)
|
||||
{
|
||||
delete spaces[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
namespace skew
|
||||
{
|
||||
|
||||
//----------------------------------------------------------
|
||||
void adv(const Vector & x, Vector & a)
|
||||
{
|
||||
a[1] = 1.0/(1.0 + att_param*att_param);
|
||||
a[0] = sqrt(1.0 - a[1]*a[1]);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
real_t kappa(const Vector & x)
|
||||
{
|
||||
return kappa_param;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
real_t force(const Vector & x)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
real_t sol(const Vector & x)
|
||||
{
|
||||
if ((x[1] - x[0] - 0.2 < 0.0)
|
||||
&(x[0] + x[1] -0.99 < 0.0))
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
void grad(const Vector & x, Vector &grad)
|
||||
{
|
||||
grad = 0.0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
real_t laplace(const Vector & x)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "stab_condif.hpp"
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
StabConDifIntegrator::StabConDifIntegrator(VectorCoefficient *a,
|
||||
Coefficient *k,
|
||||
Coefficient *f,
|
||||
Tau *t, StabType s)
|
||||
: adv(a), kappa(k), force(f), tau(t), stab(s), own_tau(false)
|
||||
{
|
||||
if (tau == nullptr)
|
||||
{
|
||||
tau = new FFH92Tau(adv, kappa, 12.0);
|
||||
own_tau = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
tau->SetConvection(adv);
|
||||
tau->SetDiffusion(kappa);
|
||||
}
|
||||
}
|
||||
|
||||
StabConDifIntegrator::~StabConDifIntegrator()
|
||||
{
|
||||
if (own_tau) { delete tau; }
|
||||
}
|
||||
|
||||
const IntegrationRule &StabConDifIntegrator::GetRule(
|
||||
const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans)
|
||||
{
|
||||
int order = trial_fe.GetOrder() + test_fe.GetOrder();
|
||||
return IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
void StabConDifIntegrator::AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat )
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
real_t w,k,t = 0;
|
||||
Vector a(dim);
|
||||
|
||||
elmat.SetSize(nd);
|
||||
shape.SetSize(nd);
|
||||
dshape.SetSize(nd,dim);
|
||||
adshape.SetSize(nd);
|
||||
laplace.SetSize(nd);
|
||||
trail.SetSize(nd);
|
||||
test.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = NonlinearFormIntegrator::IntRule ? NonlinearFormIntegrator::IntRule : &GetRule(el, el, Trans);
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint (&ip);
|
||||
w = Trans.Weight() * ip.weight;
|
||||
|
||||
// Calculate shapes
|
||||
el.CalcPhysShape(Trans, shape);
|
||||
el.CalcPhysDShape(Trans, dshape);
|
||||
|
||||
// Evaluate coefficients
|
||||
k = kappa->Eval(Trans, ip);
|
||||
adv->Eval(a, Trans, ip);
|
||||
|
||||
// Galerkin convection term
|
||||
dshape.Mult(a, adshape);
|
||||
AddMult_a_VWt(w, shape, adshape, elmat);
|
||||
|
||||
// Galerkin diffusion term
|
||||
AddMult_a_AAt(w*k, dshape, elmat);
|
||||
|
||||
if (stab != GALERKIN)
|
||||
{
|
||||
// Calculate shapes
|
||||
el.CalcPhysLaplacian(Trans, laplace);
|
||||
|
||||
// Evaluate coefficients
|
||||
t = tau->Eval(Trans, ip);
|
||||
|
||||
// Stablization term
|
||||
// - GLS: stab = -1
|
||||
// - SUPG: stab = 0
|
||||
// - VMS: stab = +1
|
||||
add(adshape, stab*k, laplace, test);
|
||||
add(adshape, -k, laplace, trail);
|
||||
AddMult_a_VWt(w*t, test, trail, elmat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StabConDifIntegrator::AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
Vector &elvect)
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
real_t w,k,t,f;
|
||||
Vector a(dim);
|
||||
|
||||
elvect.SetSize(nd);
|
||||
shape.SetSize(nd);
|
||||
dshape.SetSize(nd,dim);
|
||||
adshape.SetSize(nd);
|
||||
laplace.SetSize(nd);
|
||||
test.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = LinearFormIntegrator::IntRule ? LinearFormIntegrator::IntRule : &GetRule(el, el, Trans);
|
||||
|
||||
elvect = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint (&ip);
|
||||
w = Trans.Weight() * ip.weight;
|
||||
|
||||
// Calculate shapes
|
||||
el.CalcPhysShape(Trans, shape);
|
||||
|
||||
// Evaluate coefficients
|
||||
f = force->Eval(Trans, ip);
|
||||
|
||||
// Galerkin term
|
||||
elvect.Add(w*f, shape);
|
||||
|
||||
if (stab != GALERKIN)
|
||||
{
|
||||
// Calculate shapes
|
||||
el.CalcPhysDShape(Trans, dshape);
|
||||
el.CalcPhysLaplacian(Trans, laplace);
|
||||
|
||||
// Evaluate coefficients
|
||||
k = kappa->Eval(Trans, ip);
|
||||
adv->Eval(a, Trans, ip);
|
||||
t = tau->Eval(Trans, ip);
|
||||
|
||||
// Advective derivative
|
||||
dshape.Mult(a, adshape);
|
||||
|
||||
// Stablization term
|
||||
// - GLS: stab = -1
|
||||
// - SUPG: stab = 0
|
||||
// - VMS: stab = +1
|
||||
add(adshape, stab*k, laplace, test);
|
||||
elvect.Add(w*f*t, test);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
StabConDifComposition::StabConDifComposition(VectorCoefficient *a,
|
||||
Coefficient *k,
|
||||
Coefficient *f,
|
||||
Tau *t)
|
||||
: adv(a), kappa(k), force(f), tau(t), own_tau(false)
|
||||
{
|
||||
if (tau == nullptr)
|
||||
{
|
||||
tau = new FFH92Tau(adv, kappa, 12.0);
|
||||
own_tau = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
tau->SetConvection(adv);
|
||||
tau->SetDiffusion(kappa);
|
||||
}
|
||||
|
||||
// SUPG coefficients
|
||||
adv_tau = new ScalarVectorProductCoefficient(*tau, *adv);
|
||||
adv_tau_force = new ScalarVectorProductCoefficient(*force, *adv_tau);
|
||||
adv_tau_kappa = new ScalarVectorProductCoefficient(*kappa, *adv_tau);
|
||||
adv_tau_adv = new OuterProductCoefficient(*adv_tau, *adv);
|
||||
|
||||
// GLS/VMS coefficients
|
||||
kappa_tau = new ProductCoefficient(*kappa, *tau);
|
||||
kappa_tau_kappa = new ProductCoefficient(*kappa_tau, *kappa);
|
||||
kappa_tau_force = new ProductCoefficient(*kappa_tau, *force);
|
||||
}
|
||||
|
||||
StabConDifComposition::~StabConDifComposition()
|
||||
{
|
||||
if (own_tau) { delete tau; }
|
||||
delete adv_tau, adv_tau_kappa, adv_tau_adv, adv_tau_force,
|
||||
kappa_tau, kappa_tau_kappa,kappa_tau_force;
|
||||
}
|
||||
|
||||
void StabConDifComposition::SetBilinearIntegrators(BilinearForm *a, StabType stype)
|
||||
{
|
||||
a->AddDomainIntegrator(new ConservativeConvectionIntegrator(*adv));
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator(*kappa));
|
||||
if (stype == GALERKIN) return;
|
||||
|
||||
// Add SUPG terms
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator(*adv_tau_adv));
|
||||
a->AddDomainIntegrator(new GradLaplaceIntegrator(*adv_tau_kappa, 1.0));
|
||||
if (stype == SUPG) return;
|
||||
|
||||
// Add VMS/GLS terms
|
||||
real_t s = (stype == GLS)? -1.0: 1.0;
|
||||
a->AddDomainIntegrator(new LaplaceGradIntegrator(*adv_tau_kappa,-s));
|
||||
a->AddDomainIntegrator(new LaplaceLaplaceIntegrator(*kappa_tau_kappa,-s));
|
||||
}
|
||||
|
||||
void StabConDifComposition::SetLinearIntegrators(LinearForm *b, StabType stype)
|
||||
{
|
||||
b->AddDomainIntegrator(new DomainLFIntegrator(*force));
|
||||
if (stype == GALERKIN) return;
|
||||
|
||||
// Add SUPG terms
|
||||
b->AddDomainIntegrator(new DomainLFGradIntegrator(*adv_tau_force));
|
||||
if (stype == SUPG) return;
|
||||
|
||||
// Add VMS/GLS terms
|
||||
real_t s = (stype == GLS)? -1.0: 1.0;
|
||||
b->AddDomainIntegrator(new DomainLFLaplaceIntegrator(*kappa_tau_force,-s));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_STAB_CONDIF_HPP
|
||||
#define MFEM_STAB_CONDIF_HPP
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include "stab_tau.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/** This Class defines a monolithic integrator for stabilized multi-dimensional
|
||||
convection-diffusion.
|
||||
|
||||
$(a \cdot \nabla u, v) + (\kappa \nabla u, \nabla v)
|
||||
+ \sum (a \cdot \nabla u - \kappa \Delta u, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
|
||||
|
||||
$(f, \nabla v)
|
||||
+ \sum (f, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
|
||||
*/
|
||||
class StabConDifIntegrator : public BilinearFormIntegrator,
|
||||
public LinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
/// The advection field
|
||||
VectorCoefficient *adv;
|
||||
/// The diffusion parameter and force fields
|
||||
Coefficient *kappa, *force;
|
||||
|
||||
/// The stabilization parameter
|
||||
Tau *tau;
|
||||
bool own_tau;
|
||||
|
||||
StabType stab;
|
||||
|
||||
private:
|
||||
Vector laplace, shape, adshape, trail, test;
|
||||
DenseMatrix dshape;
|
||||
|
||||
public:
|
||||
StabConDifIntegrator(VectorCoefficient *a,
|
||||
Coefficient *k,
|
||||
Coefficient *f,
|
||||
Tau *t = nullptr, StabType s = GALERKIN);
|
||||
|
||||
~StabConDifIntegrator();
|
||||
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans);
|
||||
|
||||
virtual void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
Vector &elvect);
|
||||
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
|
||||
/** This Class composes standard integrators to obtain a stabilized formulation for
|
||||
multi-dimensional convection-diffusion.
|
||||
|
||||
$(a \cdot \nabla u, v) + (\kappa \nabla u, \nabla v)
|
||||
+ \sum (a \cdot \nabla u - \kappa \Delta u, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
|
||||
|
||||
$(f, \nabla v)
|
||||
+ \sum (f, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
|
||||
*/
|
||||
class StabConDifComposition
|
||||
{
|
||||
|
||||
private:
|
||||
/// The advection field
|
||||
VectorCoefficient *adv;
|
||||
/// The diffusion parameter and force fields
|
||||
Coefficient *kappa, *force;
|
||||
|
||||
/// The stabilization parameter
|
||||
Tau *tau;
|
||||
bool own_tau;
|
||||
|
||||
//// Helper coefficients for defining the weak forms
|
||||
VectorCoefficient *adv_tau;
|
||||
Coefficient *kappa_tau;
|
||||
|
||||
/// SUPG coefficients
|
||||
VectorCoefficient *adv_tau_force;
|
||||
VectorCoefficient *adv_tau_kappa;
|
||||
MatrixCoefficient *adv_tau_adv;
|
||||
|
||||
/// GLS/VMS coefficients
|
||||
Coefficient *kappa_tau_kappa;
|
||||
Coefficient *kappa_tau_force;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor
|
||||
@a a: is the advection velocity field.
|
||||
@a k: is the diffusion param field.
|
||||
@a f: is the force field. */
|
||||
StabConDifComposition(VectorCoefficient *a,
|
||||
Coefficient *k,
|
||||
Coefficient *f,
|
||||
Tau *t = nullptr);
|
||||
|
||||
/// Destructor
|
||||
~StabConDifComposition();
|
||||
|
||||
/// This method sets the integrators for the bilinearform
|
||||
void SetBilinearIntegrators(BilinearForm *a, StabType s);
|
||||
|
||||
/// This method sets the integrators for the linearform
|
||||
void SetLinearIntegrators(LinearForm *b, StabType s);
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,394 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "stab_navsto.hpp"
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
StabInNavStoIntegrator::StabInNavStoIntegrator(Coefficient &mu_,
|
||||
VectorCoefficient &force_,
|
||||
Tau &t, Tau &d, StabType s)
|
||||
: c_mu(&mu_), c_force(&force_), tau(&t), delta(&d), stab(s)
|
||||
{ }
|
||||
|
||||
void StabInNavStoIntegrator::SetDim(int dim_)
|
||||
{
|
||||
if (dim_ != dim)
|
||||
{
|
||||
dim = dim_;
|
||||
u.SetSize(dim);
|
||||
f.SetSize(dim);
|
||||
res.SetSize(dim);
|
||||
up.SetSize(dim);
|
||||
grad_u.SetSize(dim);
|
||||
hess_u.SetSize(dim, (dim*(dim+1))/2);
|
||||
grad_p.SetSize(dim);
|
||||
hmap.SetSize(dim,dim);
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
hmap(0,0) = 0;
|
||||
hmap(0,1) = hmap(1,0) = 1;
|
||||
hmap(1,1) = 2;
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
hmap(0,0) = 0;
|
||||
hmap(0,1) = hmap(1,0) = 1;
|
||||
hmap(0,2) = hmap(2,0) = 2;
|
||||
hmap(1,1) = 3;
|
||||
hmap(1,2) = hmap(2,1) = 4;
|
||||
hmap(2,2) = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem_error("Only implemented for 2D and 3D");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
real_t StabInNavStoIntegrator::GetElementEnergy(
|
||||
const Array<const FiniteElement *>&el,
|
||||
ElementTransformation &Tr,
|
||||
const Array<const Vector *>&elfun)
|
||||
{
|
||||
if (el.Size() != 2)
|
||||
{
|
||||
mfem_error("StabInNavStoIntegrator::GetElementEnergy"
|
||||
" has incorrect block finite element space size!");
|
||||
}
|
||||
SetDim(el[0]->GetDim());
|
||||
int dof_u = el[0]->GetDof();
|
||||
|
||||
sh_u.SetSize(dof_u);
|
||||
elf_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
|
||||
|
||||
int intorder = 2*el[0]->GetOrder();
|
||||
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
|
||||
|
||||
real_t energy = 0.0;
|
||||
|
||||
for (int i = 0; i < ir.GetNPoints(); ++i)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
Tr.SetIntPoint(&ip);
|
||||
|
||||
real_t w = ip.weight * Tr.Weight();
|
||||
|
||||
el[0]->CalcPhysShape(Tr, sh_u);
|
||||
elf_u.MultTranspose(sh_u, u);
|
||||
|
||||
energy += w*(u*u)/2;
|
||||
}
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
void StabInNavStoIntegrator::AssembleElementVector(
|
||||
const Array<const FiniteElement *> &el,
|
||||
ElementTransformation &Tr,
|
||||
const Array<const Vector *> &elfun,
|
||||
const Array<Vector *> &elvec)
|
||||
{
|
||||
if (el.Size() != 2)
|
||||
{
|
||||
mfem_error("StabInNavStoIntegrator::AssembleElementVector"
|
||||
" has finite element space of incorrect block number");
|
||||
}
|
||||
|
||||
int dof_u = el[0]->GetDof();
|
||||
int dof_p = el[1]->GetDof();
|
||||
|
||||
SetDim(el[0]->GetDim());
|
||||
int spaceDim = Tr.GetSpaceDim();
|
||||
bool hess = (el[0]->GetDerivType() == (int) FiniteElement::HESS);
|
||||
if (dim != spaceDim)
|
||||
{
|
||||
mfem_error("StabInNavStoIntegrator::AssembleElementVector"
|
||||
" is not defined on manifold meshes");
|
||||
}
|
||||
elvec[0]->SetSize(dof_u*dim);
|
||||
elvec[1]->SetSize(dof_p);
|
||||
|
||||
*elvec[0] = 0.0;
|
||||
*elvec[1] = 0.0;
|
||||
|
||||
elf_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
|
||||
elv_u.UseExternalData(elvec[0]->GetData(), dof_u, dim);
|
||||
|
||||
sh_u.SetSize(dof_u);
|
||||
shg_u.SetSize(dof_u, dim);
|
||||
ushg_u.SetSize(dof_u);
|
||||
shh_u.SetSize(dof_u, (dim*(dim+1))/2);
|
||||
sh_p.SetSize(dof_p);
|
||||
shg_p.SetSize(dof_p, dim);
|
||||
|
||||
int intorder = 2*el[0]->GetOrder();
|
||||
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
|
||||
|
||||
for (int i = 0; i < ir.GetNPoints(); ++i)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
Tr.SetIntPoint(&ip);
|
||||
real_t w = ip.weight * Tr.Weight();
|
||||
real_t mu = c_mu->Eval(Tr, ip);
|
||||
c_force->Eval(f, Tr, ip);
|
||||
|
||||
// Compute shape and interpolate
|
||||
el[0]->CalcPhysShape(Tr, sh_u);
|
||||
elf_u.MultTranspose(sh_u, u);
|
||||
|
||||
el[0]->CalcPhysDShape(Tr, shg_u);
|
||||
shg_u.Mult(u, ushg_u);
|
||||
MultAtB(elf_u, shg_u, grad_u);
|
||||
|
||||
if (hess)
|
||||
{
|
||||
el[0]->CalcPhysHessian(Tr,shh_u);
|
||||
MultAtB(elf_u, shh_u, hess_u);
|
||||
}
|
||||
else
|
||||
{
|
||||
shh_u = 0.0;
|
||||
hess_u = 0.0;
|
||||
}
|
||||
|
||||
el[1]->CalcPhysShape(Tr, sh_p);
|
||||
real_t p = sh_p*(*elfun[1]);
|
||||
|
||||
el[1]->CalcPhysDShape(Tr, shg_p);
|
||||
shg_p.MultTranspose(*elfun[1], grad_p);
|
||||
|
||||
// Compute strong residual
|
||||
grad_u.Mult(u,res); // Add convection
|
||||
res += grad_p; // Add pressure
|
||||
res -= f; // Subtract force
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
for (int j = 0; j < dim; ++j)
|
||||
{
|
||||
res[j] -= mu*(hess_u(j,hmap(i,i)) +
|
||||
hess_u(i,hmap(j,i))); // Add diffusion
|
||||
}
|
||||
}
|
||||
|
||||
// Compute stability params
|
||||
real_t t = tau->Eval(Tr, ip);
|
||||
real_t d = delta->Eval(Tr, ip);
|
||||
|
||||
// Compute momentum weak residual
|
||||
flux.Diag(-p + d*grad_u.Trace(),dim); // Add pressure & LSIC to flux
|
||||
grad_u.Symmetrize(); // Grad to strain
|
||||
flux.Add(2*mu,grad_u); // Add stress to flux
|
||||
AddMult_a_VVt(-1.0, u, flux); // Add convection to flux
|
||||
AddMult_a_VWt(t, res, u, flux); // Add SUPG to flux --> check order u and res
|
||||
AddMult_a_ABt(w, shg_u, flux, elv_u); // Add flux term to rhs
|
||||
AddMult_a_VWt(-w, sh_u, f, elv_u); // Add force term to rhs
|
||||
|
||||
// Compute momentum weak residual
|
||||
elvec[1]->Add(w*grad_u.Trace(), sh_p); // Add Galerkin term
|
||||
shg_p.Mult(res, sh_p); // PSPG help term
|
||||
elvec[1]->Add(w*t, sh_p); // Add PSPG term - sign looks worng?
|
||||
}
|
||||
}
|
||||
|
||||
void StabInNavStoIntegrator::AssembleElementGrad(
|
||||
const Array<const FiniteElement*> &el,
|
||||
ElementTransformation &Tr,
|
||||
const Array<const Vector *> &elfun,
|
||||
const Array2D<DenseMatrix *> &elmats)
|
||||
{
|
||||
int dof_u = el[0]->GetDof();
|
||||
int dof_p = el[1]->GetDof();
|
||||
|
||||
SetDim(el[0]->GetDim());
|
||||
bool hess = (el[0]->GetDerivType() == (int) FiniteElement::HESS);
|
||||
|
||||
elf_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
|
||||
|
||||
elmats(0,0)->SetSize(dof_u*dim, dof_u*dim);
|
||||
elmats(0,1)->SetSize(dof_u*dim, dof_p);
|
||||
elmats(1,0)->SetSize(dof_p, dof_u*dim);
|
||||
elmats(1,1)->SetSize(dof_p, dof_p);
|
||||
|
||||
*elmats(0,0) = 0.0;
|
||||
*elmats(0,1) = 0.0;
|
||||
*elmats(1,0) = 0.0;
|
||||
*elmats(1,1) = 0.0;
|
||||
|
||||
sh_u.SetSize(dof_u);
|
||||
shg_u.SetSize(dof_u, dim);
|
||||
ushg_u.SetSize(dof_u);
|
||||
sh_p.SetSize(dof_p);
|
||||
shg_p.SetSize(dof_p, dim);
|
||||
|
||||
int intorder = 2*el[0]->GetOrder();
|
||||
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
|
||||
|
||||
for (int i = 0; i < ir.GetNPoints(); ++i)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
Tr.SetIntPoint(&ip);
|
||||
real_t w = ip.weight * Tr.Weight();
|
||||
real_t mu = c_mu->Eval(Tr, ip);
|
||||
real_t t = tau->Eval(Tr, ip);
|
||||
real_t d = delta->Eval(Tr, ip);
|
||||
|
||||
el[0]->CalcPhysShape(Tr, sh_u);
|
||||
elf_u.MultTranspose(sh_u, u);
|
||||
|
||||
el[0]->CalcPhysDShape(Tr, shg_u);
|
||||
MultAtB(elf_u, shg_u, grad_u);
|
||||
|
||||
shg_u.Mult(u, ushg_u);
|
||||
|
||||
el[1]->CalcPhysShape(Tr, sh_p);
|
||||
real_t p = sh_p*(*elfun[1]);
|
||||
|
||||
el[1]->CalcPhysDShape(Tr, shg_p);
|
||||
shg_p.MultTranspose(*elfun[1], grad_p);
|
||||
|
||||
// u,u block
|
||||
for (int i_u = 0; i_u < dof_u; ++i_u)
|
||||
{
|
||||
for (int j_u = 0; j_u < dof_u; ++j_u)
|
||||
{
|
||||
// Diffusion
|
||||
real_t mat = 0.0;
|
||||
for (int dim_u = 0; dim_u < dim; ++dim_u)
|
||||
{
|
||||
mat += shg_u(i_u,dim_u)*shg_u(j_u,dim_u);
|
||||
}
|
||||
mat *= mu;
|
||||
|
||||
// Convection
|
||||
mat -= ushg_u(i_u)*sh_u(j_u); // Galerkin
|
||||
mat += t*ushg_u(i_u)*ushg_u(j_u); // SUPG
|
||||
|
||||
mat *= w;
|
||||
for (int dim_u = 0; dim_u < dim; ++dim_u)
|
||||
{
|
||||
(*elmats(0,0))(i_u + dim_u*dof_u, j_u + dim_u*dof_u) += mat;
|
||||
}
|
||||
|
||||
for (int i_dim = 0; i_dim < dim; ++i_dim)
|
||||
{
|
||||
for (int j_dim = 0; j_dim < dim; ++j_dim)
|
||||
{
|
||||
(*elmats(0,0))(i_u + i_dim*dof_u, j_u + j_dim*dof_u) +=
|
||||
(mu + d)*shg_u(i_u,j_dim)*shg_u(j_u,i_dim)*w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// u,p and p,u blocks
|
||||
for (int i_p = 0; i_p < dof_p; ++i_p)
|
||||
{
|
||||
for (int j_u = 0; j_u < dof_u; ++j_u)
|
||||
{
|
||||
for (int dim_u = 0; dim_u < dim; ++dim_u)
|
||||
{
|
||||
(*elmats(0,1))(j_u + dof_u * dim_u, i_p) += (shg_p(i_p, dim_u)*t*ushg_u(j_u)
|
||||
-shg_u(j_u,dim_u)*sh_p(i_p))*w;
|
||||
(*elmats(1,0))(i_p, j_u + dof_u * dim_u) += shg_u(j_u,dim_u)*sh_p(i_p)*w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// p,p block
|
||||
AddMult_a_AAt(w*t, shg_p, *elmats(1,1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GeneralResidualMonitor::MonitorResidual(int it, real_t norm,
|
||||
const Vector &r, bool final)
|
||||
{
|
||||
if (it == 0)
|
||||
{
|
||||
norm0 = norm;
|
||||
}
|
||||
|
||||
if ((print_level > 0 && it%print_level == 0) || final)
|
||||
{
|
||||
mfem::out << prefix << " iteration " << std::setw(2) << it
|
||||
<< " : ||r|| = " << norm
|
||||
<< ", ||r||/||r_0|| = " << 100*norm/norm0<<" % \n";
|
||||
}
|
||||
}
|
||||
|
||||
void SystemResidualMonitor::MonitorResidual(int it, real_t norm,
|
||||
const Vector &r, bool final)
|
||||
{
|
||||
if (dc && (it > 0))
|
||||
{
|
||||
if (rank > 1)
|
||||
{
|
||||
for (int i = 0; i < nvar; ++i)
|
||||
{
|
||||
pgf[i]->Distribute(xp->GetBlock(i));
|
||||
}
|
||||
}
|
||||
dc->SetCycle(it);
|
||||
dc->Save();
|
||||
}
|
||||
|
||||
Vector vnorm(nvar);
|
||||
|
||||
for (int i = 0; i < nvar; ++i)
|
||||
{
|
||||
Vector r_i(r.GetData() + bOffsets[i], bOffsets[i+1] - bOffsets[i]);
|
||||
if ( rank == 1 )
|
||||
{
|
||||
vnorm[i] = r_i.Norml2();
|
||||
}
|
||||
else
|
||||
{
|
||||
vnorm[i] = sqrt(InnerProduct(MPI_COMM_WORLD, r_i, r_i));
|
||||
}
|
||||
if (it == 0) norm0[i] = vnorm[i];
|
||||
}
|
||||
|
||||
bool print = (print_level > 0 && it%print_level == 0) || final;
|
||||
if (print)
|
||||
{
|
||||
mfem::out << prefix << " iteration " << std::setw(3) << it <<"\n"
|
||||
<< " ||r|| \t"<< "||r||/||r_0|| \n";
|
||||
for (int i = 0; i < nvar; ++i)
|
||||
{
|
||||
mfem::out <<vnorm[i]<<"\t"<< 100*vnorm[i]/norm0[i]<<" % \n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void JacobianPreconditioner::SetOperator(const Operator &op)
|
||||
{
|
||||
BlockOperator *jacobian = (BlockOperator *) &op;
|
||||
|
||||
for (int i = 0; i < prec.Size(); ++i)
|
||||
{
|
||||
prec[i]->SetOperator(jacobian->GetBlock(i,i));
|
||||
SetDiagonalBlock(i, prec[i]);
|
||||
}
|
||||
|
||||
SetBlock(1,0, const_cast<Operator*>(&jacobian->GetBlock(1,0)));
|
||||
}
|
||||
|
||||
JacobianPreconditioner::~JacobianPreconditioner()
|
||||
{
|
||||
for (int i = 0; i < prec.Size(); ++i)
|
||||
{
|
||||
delete prec[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_STAB_NAVSTO_HPP
|
||||
#define MFEM_STAB_NAVSTO_HPP
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include "stab_tau.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/** Stabilized incompressible Navier-Stokes integrator
|
||||
Start with Galerkin for stokes - done
|
||||
Add convection - done
|
||||
Modify diffusion - done
|
||||
Add difussion to residual - done
|
||||
CHECK NUMBERING HESSIAN -> NURBS = WRONG?? 2D = ok --> 3D??? --> DONE NEEDS CHECKING???
|
||||
Inverse estimate check order -> done
|
||||
Add force -> done
|
||||
Parallel --> done
|
||||
|
||||
|
||||
Add supg - rhs done, jac conv + press --> ignore diffusion for now
|
||||
Add pspg - rhs done, jac conv + press --> ignore diffusion for now
|
||||
Add lsic - rhs done, jac conv + press --> ignore diffusion for now
|
||||
|
||||
Add correct inverse estimate -> done?? number does not coincide with H&C
|
||||
|
||||
Add VMS/GLS
|
||||
Add selection option of different stab modes
|
||||
|
||||
Add Hessian check to inverse estimate
|
||||
|
||||
|
||||
Check
|
||||
- Hessian numbering in 3D
|
||||
- Power method --> Laplack / null-space
|
||||
- Elastic Inverse estimate
|
||||
|
||||
Leopoldo P. Franca, Sérgio L. Frey
|
||||
Stabilized finite element methods:
|
||||
II. The incompressible Navier-Stokes equations.
|
||||
Computer Methods in Applied Mechanics and Engineering, 99(2-3), 209-233.
|
||||
|
||||
https://doi.org/10.1016/0045-7825(92)90041-H
|
||||
https://www.sciencedirect.com/science/article/pii/004578259290041H
|
||||
|
||||
*/
|
||||
class StabInNavStoIntegrator : public BlockNonlinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
Coefficient *c_mu;
|
||||
VectorCoefficient *c_force;
|
||||
Vector u, f, grad_p;
|
||||
DenseMatrix flux;
|
||||
|
||||
DenseMatrix elf_u, elv_u;
|
||||
// Vector elf_u, elv_u;//
|
||||
DenseMatrix elf_p, elv_p;
|
||||
Vector sh_u, ushg_u, sh_p;
|
||||
DenseMatrix shg_u, shh_u, shg_p, grad_u, hess_u;
|
||||
Array2D<int> hmap;
|
||||
|
||||
/// The stabilization parameters
|
||||
StabType stab;
|
||||
Tau *tau = nullptr;
|
||||
Tau *delta = nullptr;
|
||||
Vector res, up;
|
||||
|
||||
/// The advection field
|
||||
VectorCoefficient *adv = nullptr; // tbd???
|
||||
|
||||
int dim = -1;
|
||||
void SetDim(int dim);
|
||||
|
||||
public:
|
||||
StabInNavStoIntegrator(Coefficient &mu_,
|
||||
VectorCoefficient &force_,
|
||||
Tau &t, Tau &d,
|
||||
StabType s = GALERKIN);
|
||||
|
||||
virtual real_t GetElementEnergy(const Array<const FiniteElement *>&el,
|
||||
ElementTransformation &Tr,
|
||||
const Array<const Vector *> &elfun);
|
||||
|
||||
/// Perform the local action of the NonlinearFormIntegrator
|
||||
virtual void AssembleElementVector(const Array<const FiniteElement *> &el,
|
||||
ElementTransformation &Tr,
|
||||
const Array<const Vector *> &elfun,
|
||||
const Array<Vector *> &elvec);
|
||||
|
||||
/// Assemble the local gradient matrix
|
||||
virtual void AssembleElementGrad(const Array<const FiniteElement*> &el,
|
||||
ElementTransformation &Tr,
|
||||
const Array<const Vector *> &elfun,
|
||||
const Array2D<DenseMatrix *> &elmats);
|
||||
};
|
||||
|
||||
class GeneralResidualMonitor : public IterativeSolverMonitor
|
||||
{
|
||||
public:
|
||||
GeneralResidualMonitor(const std::string& prefix_, int print_lvl)
|
||||
: prefix(prefix_)
|
||||
{
|
||||
print_level = print_lvl;
|
||||
rank = 1;
|
||||
}
|
||||
|
||||
GeneralResidualMonitor(MPI_Comm comm,
|
||||
const std::string& prefix_, int print_lvl)
|
||||
: prefix(prefix_)
|
||||
{
|
||||
#ifndef MFEM_USE_MPI
|
||||
print_level = print_lvl;
|
||||
#else
|
||||
MPI_Comm_rank(comm, &rank);
|
||||
if (rank == 0)
|
||||
{
|
||||
print_level = print_lvl;
|
||||
}
|
||||
else
|
||||
{
|
||||
print_level = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final);
|
||||
|
||||
private:
|
||||
const std::string prefix;
|
||||
int rank, print_level;
|
||||
mutable real_t norm0;
|
||||
};
|
||||
|
||||
class SystemResidualMonitor : public IterativeSolverMonitor
|
||||
{
|
||||
public:
|
||||
SystemResidualMonitor(const std::string& prefix_,
|
||||
int print_lvl,
|
||||
Array<int> &offsets,
|
||||
DataCollection *dc_ = nullptr)
|
||||
: prefix(prefix_), bOffsets(offsets), dc(dc_)
|
||||
{
|
||||
print_level = print_lvl;
|
||||
nvar = bOffsets.Size()-1;
|
||||
norm0.SetSize(nvar);
|
||||
rank = 1;
|
||||
}
|
||||
|
||||
SystemResidualMonitor(MPI_Comm comm,
|
||||
const std::string& prefix_,
|
||||
int print_lvl,
|
||||
Array<int> &offsets)
|
||||
: prefix(prefix_), bOffsets(offsets), dc(nullptr), xp(nullptr)
|
||||
{
|
||||
#ifndef MFEM_USE_MPI
|
||||
print_level = print_lvl;
|
||||
rank = 1;
|
||||
#else
|
||||
MPI_Comm_rank(comm, &rank);
|
||||
if (rank == 0)
|
||||
{
|
||||
print_level = print_lvl;
|
||||
}
|
||||
else
|
||||
{
|
||||
print_level = -1;
|
||||
}
|
||||
#endif
|
||||
nvar = bOffsets.Size()-1;
|
||||
norm0.SetSize(nvar);
|
||||
}
|
||||
SystemResidualMonitor(MPI_Comm comm,
|
||||
const std::string& prefix_,
|
||||
int print_lvl,
|
||||
Array<int> &offsets,
|
||||
DataCollection *dc_,
|
||||
BlockVector *x,
|
||||
Array<ParGridFunction *> pgf_)
|
||||
: prefix(prefix_), bOffsets(offsets), dc(dc_), xp(x), pgf(pgf_)
|
||||
{
|
||||
#ifndef MFEM_USE_MPI
|
||||
print_level = print_lvl;
|
||||
rank = 1;
|
||||
#else
|
||||
MPI_Comm_rank(comm, &rank);
|
||||
if (rank == 0)
|
||||
{
|
||||
print_level = print_lvl;
|
||||
}
|
||||
else
|
||||
{
|
||||
print_level = -1;
|
||||
}
|
||||
#endif
|
||||
nvar = bOffsets.Size()-1;
|
||||
norm0.SetSize(nvar);
|
||||
}
|
||||
|
||||
|
||||
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final);
|
||||
|
||||
private:
|
||||
const std::string prefix;
|
||||
int print_level, nvar, rank;
|
||||
mutable Vector norm0;
|
||||
// Offsets for extracting block vector segments
|
||||
Array<int> &bOffsets;
|
||||
DataCollection *dc;
|
||||
BlockVector *xp;
|
||||
Array<ParGridFunction *> pgf;
|
||||
};
|
||||
|
||||
// Custom block preconditioner for the Jacobian
|
||||
class JacobianPreconditioner : public BlockLowerTriangularPreconditioner //BlockDiagonalPreconditioner
|
||||
{
|
||||
protected:
|
||||
Array<Solver *> prec;
|
||||
public:
|
||||
JacobianPreconditioner(Array<int> &offsets, Array<Solver *> p)
|
||||
: BlockLowerTriangularPreconditioner (offsets), prec(p)
|
||||
{ MFEM_VERIFY(offsets.Size()-1 == p.Size(), ""); };
|
||||
|
||||
virtual void SetOperator(const Operator &op);
|
||||
|
||||
virtual ~JacobianPreconditioner();
|
||||
};
|
||||
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,124 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "stab_tau.hpp"
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
real_t FFH92Tau::GetElementSize(ElementTransformation &T)
|
||||
{
|
||||
const DenseMatrix &dxdxi = T.Jacobian();
|
||||
row.SetSize(dim);
|
||||
h.SetSize(dim);
|
||||
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
dxdxi.GetRow(i, row);
|
||||
h[i] = row.Norml2();
|
||||
}
|
||||
switch (dim)
|
||||
{
|
||||
case 1:
|
||||
return h[0];
|
||||
case 2:
|
||||
return h[0]*h[1]*sqrt(2.0/(h[0]*h[0] + h[1]*h[1]));
|
||||
case 3:
|
||||
return h[0]*h[1]*h[2]*(3.0/(h[0]*h[0] + h[1]*h[1] + h[2]*h[2]));
|
||||
}
|
||||
mfem_error("Wrong dim!");
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
real_t FFH92Tau::GetInverseEstimate(ElementTransformation &T,
|
||||
const IntegrationPoint &ip, real_t scale)
|
||||
{
|
||||
if (Ci>0.0)
|
||||
{
|
||||
return 1.0/Ci;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0/(invEst_cf->Eval(T,ip)*scale);
|
||||
}
|
||||
}
|
||||
|
||||
real_t FFH92Tau::Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
real_t k = kappa->Eval(T, ip);
|
||||
adv->Eval(a, T, ip);
|
||||
real_t hk = GetElementSize(T);
|
||||
real_t ci = GetInverseEstimate(T, ip, hk*hk);
|
||||
real_t mk = std::min(1.0/3.0, 2*ci);
|
||||
real_t ap = a.Normlp(p);
|
||||
// Prevent division by zero
|
||||
ap = std::max(ap,std::numeric_limits<real_t>::min());
|
||||
real_t pe = mk*ap*hk/(k_fac*k); // k_fac = 2 for CD and k_fac = 4 for NS
|
||||
real_t xi = std::min(pe,1.0);
|
||||
real_t tau = hk*xi/(2*ap);
|
||||
|
||||
if (print)
|
||||
{
|
||||
std::cout<<"\n==========================\n";
|
||||
std::cout<<" kappa = "<<k <<std::endl;
|
||||
std::cout<<" adv = "; a.Print(std::cout);
|
||||
std::cout<<" h = "<<hk <<std::endl;
|
||||
std::cout<<" Ci = "<<ci<<" "
|
||||
<<( (Ci<0) ? "(Computed)" :"(Specified)")<<std::endl;
|
||||
std::cout<<" 1/Ci = "<<1.0/ci<<std::endl;
|
||||
std::cout<<" mk = "<<mk <<std::endl;
|
||||
std::cout<<" |a|_p = "<<ap <<std::endl;
|
||||
std::cout<<" Pe = "<<pe <<std::endl;
|
||||
std::cout<<" xi = "<<xi <<std::endl;
|
||||
std::cout<<" tau = "<<tau<<std::endl;
|
||||
std::cout<<" tau = "<<mk*hk*hk/(8*k)<<std::endl;
|
||||
std::cout<<"==========================\n\n";
|
||||
print = false;
|
||||
}
|
||||
|
||||
return tau;
|
||||
}
|
||||
|
||||
real_t FF91Delta::Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
real_t k = kappa->Eval(T, ip);
|
||||
adv->Eval(a, T, ip);
|
||||
real_t hk = GetElementSize(T);
|
||||
real_t ci = GetInverseEstimate(T, ip, hk*hk);
|
||||
real_t mk = std::min(1.0/3.0, 2*ci);
|
||||
real_t ap = a.Normlp(p); // Preventing division by zero not necessary
|
||||
real_t pe = mk*ap*hk/(k_fac*k);
|
||||
real_t xi = std::min(pe,1.0);
|
||||
real_t delta = lambda*ap*hk*xi;
|
||||
|
||||
if (print)
|
||||
{
|
||||
std::cout<<"\n==========================\n";
|
||||
std::cout<<" kappa = "<<k <<std::endl;
|
||||
std::cout<<" adv = "; a.Print(std::cout);
|
||||
std::cout<<" h = "<<hk <<std::endl;
|
||||
std::cout<<" Ci = "<<ci<<" "
|
||||
<<( (Ci<0) ? "(Computed)" :"(Specified)")<<std::endl;
|
||||
std::cout<<" 1/Ci = "<<1.0/ci<<std::endl;
|
||||
std::cout<<" mk = "<<mk <<std::endl;
|
||||
std::cout<<" |a|_p = "<<ap <<std::endl;
|
||||
std::cout<<" Pe = "<<pe <<std::endl;
|
||||
std::cout<<" xi = "<<xi <<std::endl;
|
||||
std::cout<<" lambda = "<<lambda <<std::endl;
|
||||
std::cout<<" delta = "<<delta<<std::endl;
|
||||
std::cout<<"==========================\n\n";
|
||||
print = false;
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user