Compare commits
336
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f229f0f7e6 | ||
|
|
d1900599b3 | ||
|
|
28668c80a4 | ||
|
|
45b97f706f | ||
|
|
11ef8f00c3 | ||
|
|
c1ec6e4d8a | ||
|
|
201f8de928 | ||
|
|
528f87600d | ||
|
|
33166c66f0 | ||
|
|
462e587088 | ||
|
|
3bb2e78df6 | ||
|
|
41ba2ae92f | ||
|
|
5eab337ff1 | ||
|
|
e45a40473b | ||
|
|
0952809e5e | ||
|
|
b9a1f8689e | ||
|
|
b479f97b54 | ||
|
|
5fc313d2f2 | ||
|
|
299a8d6c14 | ||
|
|
5683932a61 | ||
|
|
2432eefc23 | ||
|
|
8030334a97 | ||
|
|
e13989a293 | ||
|
|
63da26c00f | ||
|
|
708c477714 | ||
|
|
5a38a2e712 | ||
|
|
5af524009e | ||
|
|
2137ce1f4f | ||
|
|
c32d62f83c | ||
|
|
8aa00234d8 | ||
|
|
fbc4083001 | ||
|
|
ffa4f84108 | ||
|
|
988439f60a | ||
|
|
9343ffad7b | ||
|
|
e2a8206d35 | ||
|
|
f5219a2484 | ||
|
|
36d28c6e3e | ||
|
|
098be49296 | ||
|
|
b5b4b5da7d | ||
|
|
7f1eb85c45 | ||
|
|
878f94f998 | ||
|
|
74e538404e | ||
|
|
a042d2db0d | ||
|
|
01819638f7 | ||
|
|
acb5f5acf7 | ||
|
|
fe918fcdd4 | ||
|
|
c240df5fbe | ||
|
|
950198a3f2 | ||
|
|
d808463114 | ||
|
|
5447bcf8a9 | ||
|
|
ef6d80189f | ||
|
|
7ace2dedf1 | ||
|
|
36dea0cf38 | ||
|
|
94ca7d26e8 | ||
|
|
46e35d0bce | ||
|
|
d582c31370 | ||
|
|
8876a84dd4 | ||
|
|
8153d11274 | ||
|
|
827ed64113 | ||
|
|
ef9f02ba53 | ||
|
|
e9a0b0620a | ||
|
|
4d9d444248 | ||
|
|
6e2badecca | ||
|
|
99b45fcb02 | ||
|
|
003dc46a84 | ||
|
|
7fac0fbd07 | ||
|
|
9a327eeca6 | ||
|
|
086f6c9847 | ||
|
|
480e90b41b | ||
|
|
bc6ba0252a | ||
|
|
262fa6173d | ||
|
|
e4b8584a16 | ||
|
|
7912d6915d | ||
|
|
293d9009ae | ||
|
|
51bde67bb1 | ||
|
|
9caa48d5c8 | ||
|
|
f4d286b4b7 | ||
|
|
45e2636921 | ||
|
|
57876fbfb0 | ||
|
|
c3eb769a2a | ||
|
|
9286d89b0e | ||
|
|
47b519047a | ||
|
|
35225e045e | ||
|
|
22c1087503 | ||
|
|
469096892f | ||
|
|
cd5d2f7c04 | ||
|
|
7fc2ce350d | ||
|
|
cbae29ad06 | ||
|
|
4c1d842c72 | ||
|
|
4aa0ed52af | ||
|
|
fca4c314d4 | ||
|
|
8712d02570 | ||
|
|
e5fec6279b | ||
|
|
e90e96f9a5 | ||
|
|
459def6d79 | ||
|
|
cc00ef7d90 | ||
|
|
2c0346bc36 | ||
|
|
56186d8770 | ||
|
|
1645b854a4 | ||
|
|
69fd2f9051 | ||
|
|
a5d230f199 | ||
|
|
ba4b627e68 | ||
|
|
62c535d0ee | ||
|
|
17829d1c38 | ||
|
|
dd198ce3f9 | ||
|
|
b9f36468ba | ||
|
|
76bcd044d0 | ||
|
|
84ce403ffb | ||
|
|
df09aea4da | ||
|
|
d2840464ba | ||
|
|
0dff351b2e | ||
|
|
55a914321d | ||
|
|
1410aef639 | ||
|
|
e1ac8ca08c | ||
|
|
28916b23a4 | ||
|
|
7476c00f2b | ||
|
|
7a0137c496 | ||
|
|
4267b2af05 | ||
|
|
e37daad5eb | ||
|
|
20b4b72071 | ||
|
|
ddf80492c5 | ||
|
|
712ae82026 | ||
|
|
53dd97e0d8 | ||
|
|
0c413570c4 | ||
|
|
f8d18cd4be | ||
|
|
994d83dd80 | ||
|
|
f218efae09 | ||
|
|
43bb865c26 | ||
|
|
dd9b723cfd | ||
|
|
87362ca1ca | ||
|
|
a6afefc6a5 | ||
|
|
e1dc4680d3 | ||
|
|
44985dacc0 | ||
|
|
9c77f6b407 | ||
|
|
8df0341e11 | ||
|
|
af24eaea27 | ||
|
|
f8c6512cf9 | ||
|
|
e6ce6e7532 | ||
|
|
7338e797bb | ||
|
|
31d931a99c | ||
|
|
3ae930c93b | ||
|
|
36f882257e | ||
|
|
8adb7461b0 | ||
|
|
716e370d35 | ||
|
|
37c0768fe3 | ||
|
|
d395caad9b | ||
|
|
3e5e18797c | ||
|
|
aab273b303 | ||
|
|
217b77d5f0 | ||
|
|
bb67d6cb98 | ||
|
|
6a48f8e165 | ||
|
|
696cbd05e8 | ||
|
|
6c8a4188a1 | ||
|
|
829b123641 | ||
|
|
bd52201add | ||
|
|
812ecce84a | ||
|
|
172c38b675 | ||
|
|
875b5f3f52 | ||
|
|
be1f36a523 | ||
|
|
d4c7dd3490 | ||
|
|
e55fb21538 | ||
|
|
a966b0502f | ||
|
|
1bac61ad1c | ||
|
|
c7451115d8 | ||
|
|
72ae003a00 | ||
|
|
d67098b8f8 | ||
|
|
0e6dbaf050 | ||
|
|
32afc8565c | ||
|
|
48ace60875 | ||
|
|
9b6ee6fcad | ||
|
|
1a1639b87e | ||
|
|
3735aa504b | ||
|
|
367dda6794 | ||
|
|
e4a85f79cd | ||
|
|
22ec7e7ada | ||
|
|
678101938b | ||
|
|
9a3aa18c62 | ||
|
|
5a3ba1424a | ||
|
|
3bb8419a96 | ||
|
|
ce29282f63 | ||
|
|
9575299ae3 | ||
|
|
995ceca6c2 | ||
|
|
012aa50cd3 | ||
|
|
d0193919c4 | ||
|
|
422ca290b5 | ||
|
|
59e1d7bf27 | ||
|
|
09dd9656c8 | ||
|
|
e9afca2cd6 | ||
|
|
6abd0e6002 | ||
|
|
656e3062b4 | ||
|
|
9c9c519175 | ||
|
|
8300809562 | ||
|
|
cce7296ffe | ||
|
|
a445ad00da | ||
|
|
4db7e1a107 | ||
|
|
c51a1c4aa9 | ||
|
|
d489908e50 | ||
|
|
c4eda188d5 | ||
|
|
677eb4c876 | ||
|
|
69a4aa70b9 | ||
|
|
f07c2f460d | ||
|
|
09c557bdd7 | ||
|
|
e487da01c5 | ||
|
|
b6b6843ad2 | ||
|
|
66a1379947 | ||
|
|
546ba6c11e | ||
|
|
67ba63c2f4 | ||
|
|
99c2967920 | ||
|
|
2dc419f1ae | ||
|
|
450d6cea6d | ||
|
|
75df4ad3e6 | ||
|
|
4048d46443 | ||
|
|
bbd4edce83 | ||
|
|
1742616cac | ||
|
|
2c64bbab79 | ||
|
|
785fa7adc2 | ||
|
|
0248c58591 | ||
|
|
160e783638 | ||
|
|
ddd2500a9c | ||
|
|
2b5dee2b95 | ||
|
|
26393f230f | ||
|
|
8e9948d729 | ||
|
|
9bbbd8c324 | ||
|
|
a19e7cb38e | ||
|
|
3a2912bc0b | ||
|
|
5cfd284cb8 | ||
|
|
eeae538115 | ||
|
|
8a98c0332f | ||
|
|
84d44db3a7 | ||
|
|
c97af2f3dc | ||
|
|
c4ca3bfc5f | ||
|
|
b03cf507be | ||
|
|
066dc9b078 | ||
|
|
70854254e7 | ||
|
|
646df28ac8 | ||
|
|
73d4f987e4 | ||
|
|
c59d519c89 | ||
|
|
1ec2cba9e8 | ||
|
|
26cc1f8387 | ||
|
|
85fe35bec2 | ||
|
|
b57fa2b127 | ||
|
|
596909138a | ||
|
|
c11a76f2c1 | ||
|
|
51d32ad293 | ||
|
|
a433e9e0b4 | ||
|
|
abac61f5b5 | ||
|
|
a121a9d186 | ||
|
|
58ecbf6150 | ||
|
|
bad5ae41d1 | ||
|
|
e773e07373 | ||
|
|
c3ded3c003 | ||
|
|
e706802ed5 | ||
|
|
9e97ad8bb3 | ||
|
|
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 |
+11
@@ -272,16 +272,27 @@ miniapps/navier/*_output
|
||||
|
||||
miniapps/nurbs/nurbs_ex1
|
||||
miniapps/nurbs/nurbs_ex1p
|
||||
miniapps/nurbs/nurbs_ex3
|
||||
miniapps/nurbs/nurbs_ex5
|
||||
miniapps/nurbs/nurbs_ex11p
|
||||
miniapps/nurbs/nurbs_ex24
|
||||
miniapps/nurbs/nurbs_solenoidal
|
||||
miniapps/nurbs/nurbs_printfunc
|
||||
miniapps/nurbs/nurbs_patch_ex1
|
||||
miniapps/nurbs/nurbs_curveint
|
||||
miniapps/nurbs/refined.mesh
|
||||
miniapps/nurbs/mesh.*
|
||||
miniapps/nurbs/sol_?.gf
|
||||
miniapps/nurbs/sol.*
|
||||
miniapps/nurbs/mode_*
|
||||
miniapps/nurbs/Example1*
|
||||
miniapps/nurbs/Example3*
|
||||
miniapps/nurbs/Example5*
|
||||
miniapps/nurbs/Solenoidal*
|
||||
miniapps/nurbs/ParaView
|
||||
miniapps/nurbs/sin-fit.mesh
|
||||
miniapps/nurbs/ex5.mesh
|
||||
miniapps/nurbs/exsol.mesh
|
||||
miniapps/nurbs/CurveInt
|
||||
miniapps/nurbs/nurbs_naca_cmesh
|
||||
miniapps/nurbs/naca-cmesh.mesh
|
||||
|
||||
+5
-5
@@ -22,7 +22,7 @@ include:
|
||||
# the "needs" keyword and express the DAG of jobs for more efficiency.
|
||||
# - We use setup and setup_baseline phases to download content outside of mfem
|
||||
# directory.
|
||||
# - Allocate/Release is where quartz resource are allocated/released once for all.
|
||||
# - Allocate/Release is where ruby resource are allocated/released once for all.
|
||||
# - Build and Test is where we build and MFEM for multiple toolchains.
|
||||
# - Baseline_checks gathers baseline-type test suites execution
|
||||
# - Baseline_publish, only available on master, allows to update baseline
|
||||
@@ -53,7 +53,7 @@ variables:
|
||||
AUTOTEST_COMMIT: "YES"
|
||||
|
||||
# Trigger subpipelines:
|
||||
quartz-build-and-test:
|
||||
ruby-build-and-test:
|
||||
stage: sub-pipelines
|
||||
variables:
|
||||
# Explicitly pass down values that we want to be able to set when triggering
|
||||
@@ -61,10 +61,10 @@ quartz-build-and-test:
|
||||
AUTOTEST: "${AUTOTEST}"
|
||||
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
|
||||
trigger:
|
||||
include: .gitlab/quartz-build-and-test.yml
|
||||
include: .gitlab/ruby-build-and-test.yml
|
||||
strategy: depend
|
||||
|
||||
quartz-baseline:
|
||||
ruby-baseline:
|
||||
stage: sub-pipelines
|
||||
variables:
|
||||
# Explicitly pass down values that we want to be able to set when triggering
|
||||
@@ -73,7 +73,7 @@ quartz-baseline:
|
||||
AUTOTEST: "${AUTOTEST}"
|
||||
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
|
||||
trigger:
|
||||
include: .gitlab/quartz-baseline.yml
|
||||
include: .gitlab/ruby-baseline.yml
|
||||
strategy: depend
|
||||
|
||||
lassen-build-and-test:
|
||||
|
||||
+3
-3
@@ -24,7 +24,7 @@ and `test type`.
|
||||
|
||||
Machines typically include:
|
||||
|
||||
* Quartz: Intel bi-socket x86
|
||||
* Ruby: 2nd Gen Intel Xeon (Cascade Lake)
|
||||
* Lassen: Power9 + Nvidia GPU
|
||||
* Corona: AMD GPU
|
||||
|
||||
@@ -76,13 +76,13 @@ with a spack spec of MFEM, within the limits permitted by the MFEM spack
|
||||
package.
|
||||
|
||||
In any build-and-test sub-pipeline a job basically consists in defining the
|
||||
spack spec to use. Adding a job on quartz for example resumes to:
|
||||
spack spec to use. Adding a job on ruby for example resumes to:
|
||||
|
||||
```yaml
|
||||
<job_name>:
|
||||
variables:
|
||||
SPEC: "<spack_spec>"
|
||||
extends: .build_and_test_on_quartz
|
||||
extends: .build_and_test_on_ruby
|
||||
```
|
||||
|
||||
The remaining and non trivial work is to make sure this spec is working. To
|
||||
|
||||
@@ -24,7 +24,7 @@ variables:
|
||||
# TODO: add a clean-up mechanism
|
||||
BUILD_ROOT: ${USER_CI_TOP_DIR}/${CI_PROJECT_NAME}-${MACHINE_NAME}-pipeline-${CI_PIPELINE_ID}
|
||||
|
||||
# On LLNL's quartz, there is only one allocation shared among jobs in order to
|
||||
# On LLNL's ruby, there is only one allocation shared among jobs in order to
|
||||
# save time and resource. This allocation has to be uniquely named so that we
|
||||
# are sure to retrieve it.
|
||||
ALLOC_NAME: ${CI_PROJECT_NAME}_ci_${CI_PIPELINE_ID}
|
||||
|
||||
@@ -9,17 +9,17 @@
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# GitLab pipelines configurations for the Quartz machine at LLNL
|
||||
# GitLab pipelines configurations for the Ruby machine at LLNL
|
||||
variables:
|
||||
MACHINE_NAME: quartz
|
||||
MACHINE_NAME: ruby
|
||||
|
||||
.on_quartz:
|
||||
.on_ruby:
|
||||
tags:
|
||||
- shell
|
||||
- quartz
|
||||
- ruby
|
||||
rules:
|
||||
# Don't run quartz jobs if...
|
||||
- if: '$CI_COMMIT_BRANCH =~ /_qnone/ || $ON_QUARTZ == "OFF"'
|
||||
# Don't run ruby jobs if...
|
||||
- if: '$CI_COMMIT_BRANCH =~ /_qnone/ || $ON_RUBY == "OFF"'
|
||||
when: never
|
||||
# Don't run autotest update if...
|
||||
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
|
||||
@@ -40,13 +40,13 @@ variables:
|
||||
- when: on_success
|
||||
|
||||
# Spack helped builds
|
||||
# Generic quartz build job, extending build script
|
||||
.build_and_test_on_quartz:
|
||||
extends: [.on_quartz]
|
||||
# Generic ruby build job, extending build script
|
||||
.build_and_test_on_ruby:
|
||||
extends: [.on_ruby]
|
||||
stage: build_and_test
|
||||
script:
|
||||
# THREADS is used by 'tests/gitlab/build_and_test', run below
|
||||
- export THREADS=12
|
||||
- export THREADS=16
|
||||
- echo ${ALLOC_NAME}
|
||||
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
|
||||
- echo ${JOBID}
|
||||
@@ -18,7 +18,7 @@
|
||||
setup_baseline:
|
||||
tags:
|
||||
- shell
|
||||
- quartz
|
||||
- ruby
|
||||
stage: setup
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
setup:
|
||||
tags:
|
||||
- shell
|
||||
- quartz
|
||||
- ruby
|
||||
stage: setup
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
|
||||
@@ -19,8 +19,8 @@ stages:
|
||||
- cleanup
|
||||
- baseline_publish
|
||||
|
||||
baselinecheck_mfem_intel_quartz:
|
||||
extends: [.on_quartz]
|
||||
baselinecheck_mfem_intel_ruby:
|
||||
extends: [.on_ruby]
|
||||
stage: baseline_check
|
||||
variables:
|
||||
# TPLS_DIR is used in .gitlab/scripts/baseline to provide the tpls location
|
||||
@@ -32,7 +32,7 @@ baselinecheck_mfem_intel_quartz:
|
||||
- echo ${BUILD_ROOT}
|
||||
- echo ${TPLS_DIR}
|
||||
# Used by the tests in MFEM/tests:
|
||||
- export MFEM_TEST_NP=32
|
||||
- export MFEM_TEST_NP=48
|
||||
# The next script uses the following environment variables:
|
||||
# * BASELINE_TEST, SYS_TYPE, CI_PROJECT_DIR, ARTIFACTS_DIR,
|
||||
# * BUILD_ROOT, TPLS_DIR, MACHINE_NAME
|
||||
@@ -44,18 +44,16 @@ baselinecheck_mfem_intel_quartz:
|
||||
allow_failure: true
|
||||
|
||||
cleanup:
|
||||
extends: .on_quartz
|
||||
extends: .on_ruby
|
||||
stage: cleanup
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
- echo "BUILD_ROOT=${BUILD_ROOT}"
|
||||
- rm -rf "${BUILD_ROOT}" || true
|
||||
- echo "CI_PROJECT_DIR=${CI_PROJECT_DIR}"
|
||||
- make -C "${CI_PROJECT_DIR}" distclean
|
||||
|
||||
report_baseline:
|
||||
extends: [.on_quartz]
|
||||
extends: [.on_ruby]
|
||||
stage: baseline_report
|
||||
script:
|
||||
- echo ${MACHINE_NAME}
|
||||
@@ -115,8 +113,8 @@ report_baseline:
|
||||
exit $err
|
||||
) 9> autotest.lock
|
||||
|
||||
baselinepublish_mfem_quartz:
|
||||
extends: [.on_quartz]
|
||||
baselinepublish_mfem_ruby:
|
||||
extends: [.on_ruby]
|
||||
stage: baseline_publish
|
||||
rules:
|
||||
# - if: '$CI_COMMIT_BRANCH == "master" || $REBASELINE == "YES"'
|
||||
@@ -131,5 +129,5 @@ baselinepublish_mfem_quartz:
|
||||
|
||||
include:
|
||||
- local: .gitlab/configs/common.yml
|
||||
- local: .gitlab/configs/quartz-config.yml
|
||||
- local: .gitlab/configs/ruby-config.yml
|
||||
- local: .gitlab/configs/setup-baseline.yml
|
||||
@@ -19,54 +19,54 @@ stages:
|
||||
allocate_resource:
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
extends: .on_quartz
|
||||
extends: .on_ruby
|
||||
stage: allocate_resource
|
||||
script:
|
||||
- echo ${ALLOC_NAME}
|
||||
- salloc --exclusive --nodes=1 --reservation=ci --time=60 --no-shell --job-name=${ALLOC_NAME}
|
||||
timeout: 6h
|
||||
|
||||
# GitLab jobs for the Quartz machine at LLNL
|
||||
# GitLab jobs for the Ruby machine at LLNL
|
||||
debug_ser_gcc_10:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +debug~mpi"
|
||||
extends: .build_and_test_on_quartz
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
debug_par_gcc_10:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +debug+mpi"
|
||||
extends: .build_and_test_on_quartz
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
opt_ser_gcc_10:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 ~mpi"
|
||||
extends: .build_and_test_on_quartz
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
opt_par_gcc_10:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1"
|
||||
extends: .build_and_test_on_quartz
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
opt_par_gcc_10_sundials:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +sundials"
|
||||
extends: .build_and_test_on_quartz
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
opt_par_gcc_10_petsc:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +petsc ^petsc+mumps~superlu-dist"
|
||||
extends: .build_and_test_on_quartz
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
opt_par_gcc_10_pumi:
|
||||
variables:
|
||||
SPEC: "%gcc@10.3.1 +pumi"
|
||||
extends: .build_and_test_on_quartz
|
||||
extends: .build_and_test_on_ruby
|
||||
|
||||
# Release
|
||||
release_resource:
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
extends: .on_quartz
|
||||
extends: .on_ruby
|
||||
stage: release_resource_and_report
|
||||
script:
|
||||
- echo ${ALLOC_NAME}
|
||||
@@ -78,17 +78,17 @@ release_resource:
|
||||
report_job_success:
|
||||
stage: release_resource_and_report
|
||||
extends:
|
||||
- .on_quartz
|
||||
- .on_ruby
|
||||
- .report_job_success
|
||||
|
||||
report_job_failure:
|
||||
stage: release_resource_and_report
|
||||
extends:
|
||||
- .on_quartz
|
||||
- .on_ruby
|
||||
- .report_job_failure
|
||||
|
||||
include:
|
||||
- local: .gitlab/configs/common.yml
|
||||
- local: .gitlab/configs/quartz-config.yml
|
||||
- local: .gitlab/configs/ruby-config.yml
|
||||
- local: .gitlab/configs/setup-build-and-test.yml
|
||||
- local: .gitlab/configs/report-build-and-test.yml
|
||||
@@ -14,7 +14,7 @@
|
||||
# locals
|
||||
glob_err=${BASELINE_TEST}.err
|
||||
base=${BASELINE_TEST}-${SYS_TYPE}
|
||||
if [[ "${MACHINE_NAME}" == "quartz" ]]; then
|
||||
if [[ "${MACHINE_NAME}" == "ruby" ]]; then
|
||||
base="${BASELINE_TEST}-${MACHINE_NAME}"
|
||||
fi
|
||||
base_diff=${base}.diff
|
||||
@@ -31,8 +31,8 @@ cd tests
|
||||
mkdir _${BASELINE_TEST} && cd _${BASELINE_TEST}
|
||||
|
||||
# run
|
||||
if [[ "${MACHINE_NAME}" == "quartz" || "${MACHINE_NAME}" == "ruby" ]]; then
|
||||
salloc --nodes=1 --reservation=ci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
|
||||
if [[ "${MACHINE_NAME}" == "ruby" ]]; then
|
||||
salloc --nodes=1 --exclusive --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
|
||||
@@ -41,11 +41,11 @@ else
|
||||
echo "Unknown machine: MACHINE_NAME=$MACHINE_NAME"
|
||||
exit 1
|
||||
fi
|
||||
status="$?"
|
||||
|
||||
# post
|
||||
mkdir ${artifacts_path}
|
||||
|
||||
status=0
|
||||
if [[ -f ${BASELINE_TEST}.out ]]; then
|
||||
cp ${BASELINE_TEST}.out ${artifacts_path}
|
||||
fi
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# There will be collision between corona and quartz baselines.
|
||||
# There will be collision between corona and ruby baselines.
|
||||
# Once the corresponding files have been generated, we can switch to machine
|
||||
# specific ref.
|
||||
ARTIFACT_PATH=${CI_PROJECT_DIR}/${ARTIFACTS_DIR}/baseline-${SYS_TYPE}
|
||||
@@ -21,7 +21,7 @@ PATCH_FILE=${ARTIFACT_PATH}.patch
|
||||
FULL_FILE=${ARTIFACT_PATH}.out
|
||||
DIFF_FILE=${ARTIFACT_PATH}.diff
|
||||
|
||||
# There will be collision between corona and quartz baselines.
|
||||
# There will be collision between corona and ruby baselines.
|
||||
# Once the corresponding files have been generated, we can switch to machine
|
||||
# specific ref.
|
||||
SAVED_NAME=baseline-${SYS_TYPE}.saved
|
||||
|
||||
@@ -11,9 +11,28 @@
|
||||
Version 4.7.1 (development)
|
||||
===========================
|
||||
|
||||
- Refactored the `ARKStepSolver` class (ARKODE interface) to use
|
||||
`TimeDependentOperator::Mult` only when the associated ODE operator is
|
||||
expressed in explicit form (i.e., `TimeDependentOperator::isExplicit()`),
|
||||
otherwise `TimeDependentOperator::ExplicitMult` is used. A check has been
|
||||
added to `ARKStepSolver` to verify that the associated ODE operator is not in
|
||||
explicit form when a mass matrix solver is enabled via a call to either the
|
||||
`UseMFEMMassLinearSolver` or `UseSundialsMassLinearSolver` methods. This is
|
||||
because enabling a mass matrix solver assumes that F(u,k,t) = M k in the
|
||||
associated ODE operator.
|
||||
|
||||
- Added support for custom interpolation procedure in FindPointsGSLIB.
|
||||
|
||||
- Added NURBS-based H(div) and H(curl) elements in 2D and 3D. Only on single
|
||||
patch meshes. Only implemented for serial computations.
|
||||
|
||||
- Added miniapps to demonstrate the H(div) and H(curl) NURBS elements.
|
||||
|
||||
- Added an MFEM example for the eikonal equation. This new solver is based on
|
||||
the proximal Galerkin method introduced by Keith and Surowiec.
|
||||
|
||||
- API change: in class GridFunction, 'fec' was renamed to 'fec_owned'.
|
||||
|
||||
|
||||
Version 4.7, released on May 7, 2024
|
||||
====================================
|
||||
@@ -38,6 +57,9 @@ Meshing improvements
|
||||
|
||||
- Added support for internal boundary elements in nonconforming meshes.
|
||||
|
||||
- Added ExodusII output capability. The writer can handle first-order (Pyramid5,
|
||||
Wedge6, Hex8, Tet4) and second-order FE types (Pyramid14, Wedge18, Hex27, Tet10).
|
||||
|
||||
- The ReadCubit Genesis mesh importer has been rewritten to improve readability.
|
||||
|
||||
Discretization improvements
|
||||
|
||||
@@ -273,7 +273,13 @@ Installation options:
|
||||
PREFIX - Specify the installation directory. The library (libmfem.a) will be
|
||||
installed in $(PREFIX)/lib, the headers in $(PREFIX)/include, and
|
||||
the configuration makefile (config.mk) in $(PREFIX)/share/mfem.
|
||||
INSTALL - Specify the install program, e.g /usr/bin/install
|
||||
INSTALL - Specify the install program, default = /usr/bin/install
|
||||
INSTALL_DEF_PERM - Specify the default install permissions. This affects
|
||||
headers and configuration makefiles, default = 644
|
||||
INSTALL_BIN_PERM - Specify the install permissions for binaries. This only
|
||||
affects the shared version of the library, default = 755
|
||||
INSTALL_DIR_PERM - Specify the install permissions for directories and,
|
||||
on macOS/BSD, for symlinks as well, default = 755
|
||||
|
||||
MFEM library features/options (GNU make)
|
||||
----------------------------------------
|
||||
|
||||
@@ -95,6 +95,10 @@ else
|
||||
# Silence unused command line argument warnings when generating dependencies
|
||||
# with mpicxx and clang
|
||||
DEP_FLAGS := -Wno-unused-command-line-argument $(DEP_FLAGS)
|
||||
# Silence "ignoring duplicate libraries" warnings on new (Xcode 15) linker
|
||||
ifneq (,$(findstring PROJECT:dyld,$(shell ld -v 2>&1)))
|
||||
LDFLAGS_INTERNAL = -Xlinker -no_warn_duplicate_libraries
|
||||
endif
|
||||
endif
|
||||
|
||||
# Set CXXFLAGS to overwrite the default selection of DEBUG_FLAGS/OPTIM_FLAGS
|
||||
|
||||
+83
-13
@@ -32,7 +32,7 @@ groups_serial=(
|
||||
'"examples"
|
||||
"Examples:"
|
||||
"examples"
|
||||
"ex{,1,2,3}[0-9].cpp"'
|
||||
"ex{,[1-9]}[0-9].cpp"'
|
||||
# "ex1.cpp"'
|
||||
'"sundials"
|
||||
"SUNDIALS examples:"
|
||||
@@ -58,6 +58,10 @@ groups_serial=(
|
||||
"HiOp examples:"
|
||||
"examples/hiop"
|
||||
"ex9.cpp"'
|
||||
'"moonolith"
|
||||
"Moonolith examples:"
|
||||
"examples/moonolith"
|
||||
"ex1.cpp"'
|
||||
'"pumi"
|
||||
"PUMI examples:"
|
||||
"examples/pumi"
|
||||
@@ -66,25 +70,38 @@ groups_serial=(
|
||||
'"meshing"
|
||||
"Meshing miniapps:"
|
||||
"miniapps/meshing"
|
||||
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
|
||||
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp mesh-quality.cpp
|
||||
polar-nc.cpp reflector.cpp shaper.cpp trimmer.cpp twist.cpp
|
||||
mesh-optimizer.cpp minimal-surface.cpp"'
|
||||
'"adjoint"
|
||||
"Adjoint miniapps:"
|
||||
"miniapps/adjoint"
|
||||
"cvsRoberts_ASAi_dns.cpp"'
|
||||
'"autodiff"
|
||||
"Autodiff miniapps:"
|
||||
"miniapps/autodiff"
|
||||
"seq_example.cpp seq_test.cpp"' # 'seq_test.cpp' has no sample runs
|
||||
'"dpg"
|
||||
"DPG miniapps:"
|
||||
"miniapps/dpg"
|
||||
"{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
|
||||
'"gslib"
|
||||
"GSLIB miniapps:"
|
||||
"miniapps/gslib"
|
||||
"field-diff.cpp field-interp.cpp findpts.cpp schwarz_ex1.cpp "'
|
||||
# todo: miniapps/mtop
|
||||
'"nurbs"
|
||||
"NURBS miniapps:"
|
||||
"miniapps/nurbs"
|
||||
"nurbs_ex1.cpp"'
|
||||
# todo: add other nurbs miniapps
|
||||
# todo: miniapps/solvers (serial)
|
||||
'"tools"
|
||||
"Tools miniapps:"
|
||||
"miniapps/tools"
|
||||
"convert-dc.cpp display-basis.cpp get-values.cpp load-dc.cpp
|
||||
lor-transfer.cpp"'
|
||||
# todo: add other tools miniapps
|
||||
'"toys"
|
||||
"Toys miniapps:"
|
||||
"miniapps/toys"
|
||||
@@ -100,7 +117,7 @@ groups_parallel=(
|
||||
'"examples"
|
||||
"Examples:"
|
||||
"examples"
|
||||
"ex{,1,2,3}[0-9]p.cpp"'
|
||||
"ex{,[1-9]}[0-9]p.cpp"'
|
||||
# "ex1p.cpp"'
|
||||
'"sundials"
|
||||
"SUNDIALS examples:"
|
||||
@@ -126,6 +143,10 @@ groups_parallel=(
|
||||
"HiOp examples:"
|
||||
"examples/hiop"
|
||||
"ex9p.cpp"'
|
||||
'"moonolith"
|
||||
"Moonolith examples:"
|
||||
"examples/moonolith"
|
||||
"ex{1,2}p.cpp"'
|
||||
'"pumi"
|
||||
"PUMI examples:"
|
||||
"examples/pumi"
|
||||
@@ -138,24 +159,41 @@ groups_parallel=(
|
||||
'"meshing"
|
||||
"Meshing miniapps:"
|
||||
"miniapps/meshing"
|
||||
"pmesh-optimizer.cpp pmesh-fitting.cpp pminimal-surface.cpp"'
|
||||
"pmesh-optimizer.cpp pmesh-fitting.cpp pminimal-surface.cpp
|
||||
fit-node-position.cpp"'
|
||||
'"electromagnetics"
|
||||
"Electromagnetics miniapps:"
|
||||
"miniapps/electromagnetics"
|
||||
"joule.cpp"'
|
||||
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
|
||||
# "{joule,maxwell,tesla,volta}.cpp"' # todo: multiline sample runs
|
||||
'"adjoint"
|
||||
"Adjoint miniapps:"
|
||||
"miniapps/adjoint"
|
||||
"adjoint_advection_diffusion.cpp"'
|
||||
'"autodiff"
|
||||
"Autodiff miniapps:"
|
||||
"miniapps/autodiff"
|
||||
"par_example.cpp"'
|
||||
'"dpg"
|
||||
"DPG miniapps:"
|
||||
"miniapps/dpg"
|
||||
"p{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
|
||||
'"gslib"
|
||||
"GSLIB miniapps:"
|
||||
"miniapps/gslib"
|
||||
"pfindpts.cpp schwarz_ex1p.cpp"'
|
||||
'"hdiv-linear-solver"
|
||||
"H(div) linear solver miniapps:"
|
||||
"miniapps/hdiv-linear-solver"
|
||||
"grad_div.cpp darcy.cpp"'
|
||||
# 'miniapps/hooke/hooke.cpp' has no sample runs
|
||||
# todo: miniapps/mtop
|
||||
# todo: miniapps/multidomain
|
||||
'"navier"
|
||||
"Navier miniapps:"
|
||||
"miniapps/navier"
|
||||
"navier_cht.cpp"'
|
||||
# todo: add other navier miniapps
|
||||
'"nurbs"
|
||||
"NURBS miniapps:"
|
||||
"miniapps/nurbs"
|
||||
@@ -164,14 +202,18 @@ groups_parallel=(
|
||||
"Shifted miniapps:"
|
||||
"miniapps/shifted"
|
||||
"distance.cpp"'
|
||||
# todo: add other shifted miniapps
|
||||
'"solvers"
|
||||
"Solvers miniapps:"
|
||||
"miniapps/solvers"
|
||||
"block-solvers.cpp"'
|
||||
# todo: add other solvers miniapps
|
||||
# todo: miniapps/spde
|
||||
'"tools"
|
||||
"Tools miniapps:"
|
||||
"miniapps/tools"
|
||||
"convert-cd.cpp get-values.cpp load-dc.cpp"'
|
||||
"convert-dc.cpp get-values.cpp load-dc.cpp"'
|
||||
# todo: add other tools miniapps
|
||||
'"convergence"
|
||||
"Convergence tests:"
|
||||
"tests/convergence"
|
||||
@@ -186,7 +228,7 @@ groups_all=(
|
||||
'"examples"
|
||||
"Examples:"
|
||||
"examples"
|
||||
"ex\"{,1,2,3}[0-9]\"{,p}.cpp"'
|
||||
"ex\"{,[1-9]}[0-9]\"{,p}.cpp"'
|
||||
'"sundials"
|
||||
"SUNDIALS examples:"
|
||||
"examples/sundials"
|
||||
@@ -215,10 +257,14 @@ groups_all=(
|
||||
"HiOp examples:"
|
||||
"examples/hiop"
|
||||
"ex9.cpp ex9p.cpp"'
|
||||
'"moonolith"
|
||||
"Moonolith examples:"
|
||||
"examples/moonolith"
|
||||
"ex1.cpp ex{1,2}p.cpp"'
|
||||
'"pumi"
|
||||
"PUMI examples:"
|
||||
"examples/pumi"
|
||||
"ex1.cpp ex1p.cpp ex2.cpp ex6p.cpp"'
|
||||
"ex1.cpp ex2.cpp ex1p.cpp ex6p.cpp"'
|
||||
'"superlu"
|
||||
"Superlu examples:"
|
||||
"examples/superlu"
|
||||
@@ -226,43 +272,67 @@ groups_all=(
|
||||
'"meshing"
|
||||
"Meshing miniapps:"
|
||||
"miniapps/meshing"
|
||||
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
|
||||
{,p}mesh-optimizer.cpp pmesh-fitting.cpp {,p}minimal-surface.cpp"'
|
||||
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp mesh-quality.cpp
|
||||
polar-nc.cpp reflector.cpp shaper.cpp trimmer.cpp twist.cpp
|
||||
{,p}mesh-optimizer.cpp pmesh-fitting.cpp {,p}minimal-surface.cpp
|
||||
fit-node-position.cpp"'
|
||||
'"electromagnetics"
|
||||
"Electromagnetics miniapps:"
|
||||
"miniapps/electromagnetics"
|
||||
"joule.cpp"'
|
||||
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
|
||||
# "{joule,maxwell,tesla,volta}.cpp"' # todo: multiline sample runs
|
||||
'"adjoint"
|
||||
"Adjoint miniapps:"
|
||||
"miniapps/adjoint"
|
||||
"adjoint_advection_diffusion.cpp cvsRoberts_ASAi_dns.cpp"'
|
||||
"cvsRoberts_ASAi_dns.cpp adjoint_advection_diffusion.cpp"'
|
||||
'"autodiff"
|
||||
"Autodiff miniapps:"
|
||||
"miniapps/autodiff"
|
||||
"seq_example.cpp seq_test.cpp par_example.cpp"'
|
||||
# 'seq_test.cpp' has no sample runs
|
||||
'"dpg"
|
||||
"DPG miniapps:"
|
||||
"miniapps/dpg"
|
||||
"{,p}{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
|
||||
'"gslib"
|
||||
"GSLIB miniapps:"
|
||||
"miniapps/gslib"
|
||||
"field-diff.cpp field-interp.cpp findpts.cpp schwarz_ex1.cpp pfindpts.cpp
|
||||
schwarz_ex1p.cpp"'
|
||||
'"hdiv-linear-solver"
|
||||
"H(div) linear solver miniapps:"
|
||||
"miniapps/hdiv-linear-solver"
|
||||
"grad_div.cpp darcy.cpp"'
|
||||
# 'miniapps/hooke/hooke.cpp' has no sample runs
|
||||
# todo: miniapps/mtop
|
||||
# todo: miniapps/multidomain
|
||||
'"navier"
|
||||
"Navier miniapps:"
|
||||
"miniapps/navier"
|
||||
"navier_cht.cpp"'
|
||||
# todo: add other navier miniapps
|
||||
'"nurbs"
|
||||
"NURBS miniapps:"
|
||||
"miniapps/nurbs"
|
||||
"nurbs_ex1.cpp nurbs_ex1p.cpp nurbs_ex11p.cpp"'
|
||||
# todo: add other nurbs miniapps
|
||||
'"shifted"
|
||||
"Shifted miniapps:"
|
||||
"miniapps/shifted"
|
||||
"distance.cpp"'
|
||||
# todo: add other shifted miniapps
|
||||
'"solvers"
|
||||
"Solvers miniapps:"
|
||||
"miniapps/solvers"
|
||||
"block-solvers.cpp"'
|
||||
# todo: add other solvers miniapps
|
||||
# todo: miniapps/spde
|
||||
'"tools"
|
||||
"Tools miniapps:"
|
||||
"miniapps/tools"
|
||||
"convert-dc.cpp display-basis.cpp get-values.cpp load-dc.cpp
|
||||
lor-transfer.cpp"'
|
||||
# todo: add other tools miniapps
|
||||
'"toys"
|
||||
"Toys miniapps:"
|
||||
"miniapps/toys"
|
||||
@@ -386,7 +456,7 @@ function help_message()
|
||||
mfem_config [${mfem_config}]
|
||||
Set MFEM configuration options
|
||||
make [${make}], mpiexec [${mpiexec}], mpiexec_np [${mpiexec_np}]
|
||||
Their values can also set using the respective uppercase environment
|
||||
Their values can also be set using the respective uppercase environment
|
||||
variable
|
||||
mfem_build_dir [${mfem_build_dir}]
|
||||
Same as '-d': set this variable to something different from <mfem_dir>
|
||||
|
||||
@@ -18,9 +18,9 @@ elements
|
||||
boundary
|
||||
4
|
||||
1 1 0 1
|
||||
1 1 2 3
|
||||
1 1 3 0
|
||||
1 1 1 2
|
||||
2 1 2 3
|
||||
3 1 3 0
|
||||
4 1 1 2
|
||||
|
||||
edges
|
||||
4
|
||||
|
||||
@@ -1049,7 +1049,8 @@ RECURSIVE = NO
|
||||
EXCLUDE = @MFEM_SOURCE_DIR@/config/_config.hpp \
|
||||
@MFEM_SOURCE_DIR@/config/get_hypre_version.cpp \
|
||||
@MFEM_SOURCE_DIR@/general/tinyxml2.h \
|
||||
@MFEM_SOURCE_DIR@/general/tinyxml2.cpp
|
||||
@MFEM_SOURCE_DIR@/general/tinyxml2.cpp \
|
||||
@MFEM_SOURCE_DIR@/linalg/lapack.hpp
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||
|
||||
@@ -182,6 +182,21 @@ namespace mfem {
|
||||
* <a class="el" href="examples_2superlu_2ex1p_8cpp_source.html">1p</a>,
|
||||
* demonstrating the use of MFEM's \link superlu.hpp SuperLU integration\endlink.
|
||||
*
|
||||
* <H4>NURBS Examples</H4>
|
||||
* - Variants of Examples
|
||||
* <a class="el" href="nurbs__ex1_8cpp_source.html">1</a>,
|
||||
* <a class="el" href="nurbs__ex1p_8cpp_source.html">1p</a>,
|
||||
* <a class="el" href="nurbs__ex3_8cpp_source.html">3</a>,
|
||||
* <a class="el" href="nurbs__ex5_8cpp_source.html">5</a>,
|
||||
* <a class="el" href="nurbs__ex11p_8cpp_source.html">11p</a>, and
|
||||
* <a class="el" href="nurbs__ex24_8cpp_source.html">24</a>,
|
||||
* demonstrating howto perform NURBS-based Isogeometric Analysis.
|
||||
* - Variant of Example <a class="el" href="nurbs__patch__ex1_8cpp_source.html">1</a>: demonstrates the use of patch integration
|
||||
* - <a class="el" href="nurbs__solenoidal_8cpp_source.html">NURBS Divergence-free</a>: solve a solenoidal vector projection with NURBS-based H(div) elements
|
||||
* - <a class="el" href="nurbs__curveint_8cpp_source.html">NURBS Interpolation</a>: NURBS interpolation of given geometry
|
||||
* - <a class="el" href="nurbs__naca__cmesh_8cpp_source.html">NURBS NACA Mesher</a>: generate NURBS based mesh around a NACA foil
|
||||
* - <a class="el" href="nurbs__printfunc_8cpp_source.html">NURBS Printer</a>: print the NURBS-basis
|
||||
*
|
||||
* <H3>Miniapps</H3>
|
||||
* - <a class="el" href="volta_8cpp_source.html">Volta</a>: simple electrostatics simulation code
|
||||
* - <a class="el" href="tesla_8cpp_source.html">Tesla</a>: simple magnetostatics simulation code
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/amgx/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/caliper,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
+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);
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/ginkgo/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
@@ -96,6 +96,7 @@ public:
|
||||
{
|
||||
Vector w_glob(width);
|
||||
pfes.Dof_TrueDof_Matrix()->MultTranspose(w, w_glob);
|
||||
w_glob.HostReadWrite(); // read+write -> can use w_glob(i) (non-const)
|
||||
for (int i = 0; i < width; i++) { grad(0, i) = w_glob(i); }
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/hiop/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
+3
-4
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ..
|
||||
MFEM_BUILD_DIR ?= ..
|
||||
MFEM_INSTALL_DIR ?= ../mfem
|
||||
SRC = $(if $(MFEM_DIR:..=),$(MFEM_DIR)/examples/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/moonolith/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/petsc/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/pumi/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
@@ -31,11 +31,21 @@ include_directories(BEFORE ${PROJECT_BINARY_DIR})
|
||||
add_custom_target(test_sundials
|
||||
${CMAKE_CTEST_COMMAND} -R sundials USES_TERMINAL)
|
||||
|
||||
# Add one executable per cpp file, adding "sundials_" as prefix. Sets
|
||||
# "test_sundials" as a target that depends on the given examples.
|
||||
# Add one executable per cpp file, adding "sundials_" as prefix so the CMake
|
||||
# target is unique from those in the non-SUNDIALS examples. Also sets
|
||||
# "test_sundials" as a target that depends on the given SUNDIALS examples.
|
||||
set(PFX sundials_)
|
||||
add_mfem_examples(SUNDIALS_EXAMPLES_SRCS ${PFX} "" test_sundials)
|
||||
|
||||
# Remove "sundials_" prefix from exectuable name for consistency with GNU build
|
||||
# system.
|
||||
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
|
||||
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
|
||||
string(REPLACE ".cpp" "" TARGET_NAME "${PFX}${SRC_FILENAME}")
|
||||
string(REPLACE ${PFX} "" EXE_NAME ${TARGET_NAME})
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${EXE_NAME})
|
||||
endforeach()
|
||||
|
||||
# Testing.
|
||||
# The SUNDIALS tests can be run separately using the target "test_sundials"
|
||||
# which builds the examples and runs:
|
||||
@@ -51,7 +61,10 @@ if (MFEM_ENABLE_TESTING)
|
||||
set(EX10_COMMON_OPTS -m ../../data/beam-quad.mesh -o 2 -s 5 -dt 0.15 -tf 6 -vs 10)
|
||||
set(EX10_TEST_OPTS ${EX10_COMMON_OPTS} -r 2)
|
||||
set(EX10P_TEST_OPTS ${EX10_COMMON_OPTS} -rp 1)
|
||||
# Example 16: use the default options
|
||||
# Example 16: test ARKODE with implicit time stepping using mass form
|
||||
set(EX16_COMMON_OPTS -s 15)
|
||||
set(EX16_TEST_OPTS ${EX16_COMMON_OPTS})
|
||||
set(EX16P_TEST_OPTS ${EX16_COMMON_OPTS})
|
||||
|
||||
# Add the tests: one test per source file.
|
||||
foreach(SRC_FILE ${SUNDIALS_EXAMPLES_SRCS})
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// MFEM Example 10
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex10
|
||||
// Compile with:
|
||||
// make ex10 (GNU make)
|
||||
// make sundials_ex10 (CMake)
|
||||
//
|
||||
// Sample runs:
|
||||
// ex10 -m ../../data/beam-quad.mesh -r 2 -o 2 -s 12 -dt 0.15 -vs 10
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// MFEM Example 10 - Parallel Version
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex10p
|
||||
// Compile with:
|
||||
// make ex10p (GNU make)
|
||||
// make sundials_ex10p (CMake)
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 4 ex10p -m ../../data/beam-quad.mesh -rp 1 -o 2 -s 12 -dt 0.15 -vs 10
|
||||
|
||||
+256
-163
@@ -1,15 +1,21 @@
|
||||
// MFEM Example 16
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex16
|
||||
// Compile with:
|
||||
// make ex16 (GNU make)
|
||||
// make sundials_ex16 (CMake)
|
||||
//
|
||||
// Sample runs: ex16
|
||||
// ex16 -m ../../data/inline-tri.mesh
|
||||
// ex16 -m ../../data/disc-nurbs.mesh -tf 2
|
||||
// ex16 -s 12 -a 0.0 -k 1.0
|
||||
// ex16 -s 15 -a 0.0 -k 1.0
|
||||
// ex16 -s 8 -a 1.0 -k 0.0 -dt 1e-4 -tf 5e-2 -vs 25
|
||||
// ex16 -s 11 -a 1.0 -k 0.0 -dt 1e-4 -tf 5e-2 -vs 25
|
||||
// ex16 -s 9 -a 0.5 -k 0.5 -o 4 -dt 1e-4 -tf 2e-2 -vs 25
|
||||
// ex16 -s 12 -a 0.5 -k 0.5 -o 4 -dt 1e-4 -tf 2e-2 -vs 25
|
||||
// ex16 -s 10 -dt 1.0e-4 -tf 4.0e-2 -vs 40
|
||||
// ex16 -s 13 -dt 1.0e-4 -tf 4.0e-2 -vs 40
|
||||
// ex16 -m ../../data/fichera-q2.mesh
|
||||
// ex16 -m ../../data/escher.mesh
|
||||
// ex16 -m ../../data/beam-tet.mesh -tf 10 -dt 0.1
|
||||
@@ -37,75 +43,102 @@
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
/** After spatial discretization, the conduction model can be written as:
|
||||
/** After spatial discretization, the conduction model is expressed as
|
||||
*
|
||||
* du/dt = M^{-1}(-Ku)
|
||||
* M du/dt = - K(u) u
|
||||
*
|
||||
* where u is the vector representing the temperature, M is the mass matrix,
|
||||
* and K is the diffusion operator with diffusivity depending on u:
|
||||
* and K(u) is the diffusion operator with diffusivity depending on u:
|
||||
* (\kappa + \alpha u).
|
||||
*
|
||||
* Class ConductionOperator represents the right-hand side of the above ODE.
|
||||
* Class ConductionOperatorOperator represents the above ODE operator in the
|
||||
* general form F(u, k, t) = G(u, t) where
|
||||
*
|
||||
* 1. F(u, du/dt, t) = du/dt (ODE is expressed in EXPLICIT form)
|
||||
* G(u, t) = - inv(M) K(u) u
|
||||
* 2. F(u, du/dt, t) = M du/dt (ODE is expressed in IMPLICIT form)
|
||||
* G(u, t) = - K(u) u
|
||||
*/
|
||||
class ConductionOperator : public TimeDependentOperator
|
||||
{
|
||||
protected:
|
||||
FiniteElementSpace &fespace;
|
||||
Array<int> ess_tdof_list; // this list remains empty for pure Neumann b.c.
|
||||
|
||||
BilinearForm *M;
|
||||
BilinearForm *K;
|
||||
BilinearForm M;
|
||||
SparseMatrix Mmat;
|
||||
|
||||
SparseMatrix Mmat, Kmat;
|
||||
SparseMatrix *T; // T = M + dt K
|
||||
const real_t alpha, kappa;
|
||||
std::unique_ptr<BilinearForm> K;
|
||||
SparseMatrix Kmat;
|
||||
|
||||
std::unique_ptr<SparseMatrix> T; // T = M + gam K(u)
|
||||
|
||||
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
|
||||
DSmoother M_prec; // Preconditioner for the mass matrix M
|
||||
|
||||
CGSolver T_solver; // Implicit solver for T = M + dt K
|
||||
CGSolver T_solver; // Implicit solver for T = M + gam K(u)
|
||||
DSmoother T_prec; // Preconditioner for the implicit solver
|
||||
|
||||
double alpha, kappa;
|
||||
|
||||
mutable Vector z; // auxiliary vector
|
||||
|
||||
public:
|
||||
ConductionOperator(FiniteElementSpace &f, double alpha, double kappa,
|
||||
const Vector &u);
|
||||
|
||||
virtual void Mult(const Vector &u, Vector &du_dt) const;
|
||||
ConductionOperator(FiniteElementSpace &f, const real_t alpha,
|
||||
const real_t kappa, const Vector &u,
|
||||
const Type &ode_expression_type);
|
||||
|
||||
/** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
|
||||
This is the only requirement for high-order SDIRK implicit integration.*/
|
||||
virtual void ImplicitSolve(const double dt, const Vector &u, Vector &k);
|
||||
// Compute K(u_n) for use as an approximation in - K(u) u
|
||||
void SetConductionTensor(const Vector &u);
|
||||
|
||||
/// Custom Jacobian system solver for the SUNDIALS time integrators.
|
||||
/** For the ODE system represented by ConductionOperator
|
||||
/** Compute G(u, t) as defined in the IMPLICIT expression form of the ODE
|
||||
operator, i.e., @a v = - K(u_n) @a u. Note that K(u_n) is an
|
||||
approximation to K(u). */
|
||||
void ExplicitMult(const Vector &u, Vector &v) const override;
|
||||
|
||||
M du/dt = -K(u),
|
||||
/** Solve for k in F(u, k, t) = G(u, t) for either EXPLICIT or IMPLICIT
|
||||
expression forms of the ODE operator, i.e., @a k = - inv(M) K(u_n) @a u.
|
||||
Note that K(u_n) is an approximation to K(u). */
|
||||
void Mult(const Vector &u, Vector &k) const override;
|
||||
|
||||
this class facilitates the solution of linear systems of the form
|
||||
/** Solve for k in F(u + gam*k, k, t) = G(u + gam*k, t) for either EXPLICIT
|
||||
or IMPLICIT expression forms of the ODE operator, i.e.,
|
||||
[ M + @a gam K(u_n) ] @a k = - K(u_n) @a u . Note that K(u_n) is an
|
||||
approximation to K(u). */
|
||||
void ImplicitSolve(const real_t gam, const Vector &u, Vector &k) override;
|
||||
|
||||
(M + γK) y = M b,
|
||||
/** Setup to solve for dk in [dF/dk + gam*dF/du - gam*dG/du] dk = G - F for
|
||||
either EXPLICIT or IMPLICIT expression forms of the ODE operator, i.e.,
|
||||
[M - @a gam Jf(u)] dk = G - F, where Jf(u) is an approximation of the
|
||||
Jacobian of -K(u) u. The approximation chosen here is Jf(u) = -K(u_n). */
|
||||
int SUNImplicitSetup(const Vector &u, const Vector &fu, int jok, int *jcur,
|
||||
real_t gam) override;
|
||||
|
||||
for given b, u (not used), and γ = GetTimeStep(). */
|
||||
/** Solve for @a dk in the system in SUNImplicitSetup to the given tolerance,
|
||||
with the residual @a r providing either
|
||||
1. @a r = G - F = inv(M) f(u) - k (EXPLICIT expression form)
|
||||
1. @a r = G - F = f(u) - M k (IMPLICIT expression form)
|
||||
*/
|
||||
int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol) override;
|
||||
|
||||
/** Setup the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
|
||||
int jok, int *jcur, double gamma);
|
||||
int SUNMassSetup() override;
|
||||
|
||||
/** Solve the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSolve(const Vector &b, Vector &x, double tol);
|
||||
int SUNMassSolve(const Vector &b, Vector &x, real_t tol) override;
|
||||
|
||||
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
|
||||
void SetParameters(const Vector &u);
|
||||
|
||||
virtual ~ConductionOperator();
|
||||
int SUNMassMult(const Vector &x, Vector &v) override;
|
||||
};
|
||||
|
||||
double InitialTemperature(const Vector &x);
|
||||
real_t InitialTemperature(const Vector &x)
|
||||
{
|
||||
if (x.Norml2() < 0.5)
|
||||
{
|
||||
return 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -117,16 +150,16 @@ int main(int argc, char *argv[])
|
||||
int ref_levels = 2;
|
||||
int order = 2;
|
||||
int ode_solver_type = 9; // CVODE implicit BDF
|
||||
double t_final = 0.5;
|
||||
double dt = 1.0e-2;
|
||||
double alpha = 1.0e-2;
|
||||
double kappa = 0.5;
|
||||
real_t t_final = 0.5;
|
||||
real_t dt = 1.0e-2;
|
||||
real_t alpha = 1.0e-2;
|
||||
real_t kappa = 0.5;
|
||||
bool visualization = true;
|
||||
bool visit = false;
|
||||
int vis_steps = 5;
|
||||
|
||||
// Relative and absolute tolerances for CVODE and ARKODE.
|
||||
const double reltol = 1e-4, abstol = 1e-4;
|
||||
const real_t reltol = 1e-4, abstol = 1e-4;
|
||||
|
||||
int precision = 8;
|
||||
cout.precision(precision);
|
||||
@@ -151,7 +184,10 @@ int main(int argc, char *argv[])
|
||||
"9 - CVODE (implicit BDF),\n\t"
|
||||
"10 - ARKODE (default explicit),\n\t"
|
||||
"11 - ARKODE (explicit Fehlberg-6-4-5),\n\t"
|
||||
"12 - ARKODE (default impicit).");
|
||||
"12 - ARKODE (default implicit),\n\t"
|
||||
"13 - ARKODE (default explicit with MFEM mass solve),\n\t"
|
||||
"14 - ARKODE (explicit Fehlberg-6-4-5 with MFEM mass solve),\n\t"
|
||||
"15 - ARKODE (default implicit with MFEM mass solve).");
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -174,16 +210,13 @@ int main(int argc, char *argv[])
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
if (ode_solver_type < 1 || ode_solver_type > 12)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 3;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
bool use_mass_solver = ode_solver_type >= 13;
|
||||
|
||||
// 2. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral and hexahedral meshes with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
std::unique_ptr<Mesh> mesh(new Mesh(mesh_file, 1, 1));
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 3. Refine the mesh to increase the resolution. In this example we do
|
||||
@@ -197,7 +230,7 @@ int main(int argc, char *argv[])
|
||||
// 4. Define the vector finite element space representing the current and the
|
||||
// initial temperature, u_ref.
|
||||
H1_FECollection fe_coll(order, dim);
|
||||
FiniteElementSpace fespace(mesh, &fe_coll);
|
||||
FiniteElementSpace fespace(mesh.get(), &fe_coll);
|
||||
|
||||
int fe_size = fespace.GetTrueVSize();
|
||||
cout << "Number of temperature unknowns: " << fe_size << endl;
|
||||
@@ -211,8 +244,17 @@ int main(int argc, char *argv[])
|
||||
Vector u;
|
||||
u_gf.GetTrueDofs(u);
|
||||
|
||||
// 6. Initialize the conduction operator and the visualization.
|
||||
ConductionOperator oper(fespace, alpha, kappa, u);
|
||||
// 6. Initialize the conduction ODE operator and the visualization.
|
||||
ConductionOperator::Type ode_expression_type;
|
||||
if (use_mass_solver)
|
||||
{
|
||||
ode_expression_type = ConductionOperator::Type::IMPLICIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ode_expression_type = ConductionOperator::Type::EXPLICIT;
|
||||
}
|
||||
ConductionOperator oper(fespace, alpha, kappa, u, ode_expression_type);
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
{
|
||||
@@ -224,7 +266,7 @@ int main(int argc, char *argv[])
|
||||
u_gf.Save(osol);
|
||||
}
|
||||
|
||||
VisItDataCollection visit_dc("Example16", mesh);
|
||||
VisItDataCollection visit_dc("Example16", mesh.get());
|
||||
visit_dc.RegisterField("temperature", &u_gf);
|
||||
if (visit)
|
||||
{
|
||||
@@ -258,52 +300,75 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// 7. Define the ODE solver used for time integration.
|
||||
double t = 0.0;
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKStepSolver *arkode = NULL;
|
||||
real_t t = 0.0;
|
||||
std::unique_ptr<ODESolver> ode_solver;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// MFEM explicit methods
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 1: ode_solver = std::make_unique<ForwardEulerSolver>(); break;
|
||||
case 2: ode_solver = std::make_unique<RK2Solver>(0.5); break; // midpoint method
|
||||
case 3: ode_solver = std::make_unique<RK3SSPSolver>(); break;
|
||||
case 4: ode_solver = std::make_unique<RK4Solver>(); break;
|
||||
// MFEM implicit L-stable methods
|
||||
case 5: ode_solver = new BackwardEulerSolver; break;
|
||||
case 6: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 7: ode_solver = new SDIRK33Solver; break;
|
||||
case 5: ode_solver = std::make_unique<BackwardEulerSolver>(); break;
|
||||
case 6: ode_solver = std::make_unique<SDIRK23Solver>(2); break;
|
||||
case 7: ode_solver = std::make_unique<SDIRK33Solver>(); break;
|
||||
// CVODE
|
||||
case 8:
|
||||
cvode = new CVODESolver(CV_ADAMS);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 9:
|
||||
cvode = new CVODESolver(CV_BDF);
|
||||
{
|
||||
int cvode_solver_type;
|
||||
if (ode_solver_type == 8)
|
||||
{
|
||||
cvode_solver_type = CV_ADAMS;
|
||||
}
|
||||
else
|
||||
{
|
||||
cvode_solver_type = CV_BDF;
|
||||
}
|
||||
std::unique_ptr<CVODESolver> cvode(new CVODESolver(cvode_solver_type));
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
ode_solver = std::move(cvode);
|
||||
break;
|
||||
}
|
||||
// ARKODE
|
||||
case 10:
|
||||
case 11:
|
||||
arkode = new ARKStepSolver(ARKStepSolver::EXPLICIT);
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
{
|
||||
ARKStepSolver::Type arkode_solver_type;
|
||||
if (ode_solver_type == 12 || ode_solver_type == 15)
|
||||
{
|
||||
arkode_solver_type = ARKStepSolver::IMPLICIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
arkode_solver_type = ARKStepSolver::EXPLICIT;
|
||||
}
|
||||
std::unique_ptr<ARKStepSolver> arkode(
|
||||
new ARKStepSolver(arkode_solver_type));
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 11)
|
||||
if (ode_solver_type == 11 || ode_solver_type == 14)
|
||||
{
|
||||
arkode->SetERKTableNum(ARKODE_FEHLBERG_13_7_8);
|
||||
}
|
||||
ode_solver = arkode; break;
|
||||
case 12:
|
||||
arkode = new ARKStepSolver(ARKStepSolver::IMPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
if (use_mass_solver)
|
||||
{
|
||||
arkode->UseMFEMMassLinearSolver(SUNFALSE);
|
||||
}
|
||||
ode_solver = std::move(arkode);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
|
||||
@@ -311,8 +376,14 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Since we want to update the diffusion coefficient after every time step,
|
||||
// we need to use the "one-step" mode of the SUNDIALS solvers.
|
||||
if (cvode) { cvode->SetStepMode(CV_ONE_STEP); }
|
||||
if (arkode) { arkode->SetStepMode(ARK_ONE_STEP); }
|
||||
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
|
||||
{
|
||||
cvode->SetStepMode(CV_ONE_STEP);
|
||||
}
|
||||
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
|
||||
{
|
||||
arkode->SetStepMode(ARK_ONE_STEP);
|
||||
}
|
||||
|
||||
// 8. Perform time-integration (looping over the time iterations, ti, with a
|
||||
// time-step dt).
|
||||
@@ -323,7 +394,7 @@ int main(int argc, char *argv[])
|
||||
bool last_step = false;
|
||||
for (int ti = 1; !last_step; ti++)
|
||||
{
|
||||
double dt_real = min(dt, t_final - t);
|
||||
real_t dt_real = min(dt, t_final - t);
|
||||
|
||||
// Note that since we are using the "one-step" mode of the SUNDIALS
|
||||
// solvers, they will, generally, step over the final time and will not
|
||||
@@ -337,8 +408,14 @@ int main(int argc, char *argv[])
|
||||
if (last_step || (ti % vis_steps) == 0)
|
||||
{
|
||||
cout << "step " << ti << ", t = " << t << endl;
|
||||
if (cvode) { cvode->PrintInfo(); }
|
||||
if (arkode) { arkode->PrintInfo(); }
|
||||
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
|
||||
{
|
||||
cvode->PrintInfo();
|
||||
}
|
||||
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
|
||||
{
|
||||
arkode->PrintInfo();
|
||||
}
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
if (visualization)
|
||||
@@ -353,137 +430,153 @@ int main(int argc, char *argv[])
|
||||
visit_dc.Save();
|
||||
}
|
||||
}
|
||||
oper.SetParameters(u);
|
||||
oper.SetConductionTensor(u);
|
||||
}
|
||||
tic_toc.Stop();
|
||||
cout << "Done, " << tic_toc.RealTime() << "s." << endl;
|
||||
|
||||
// 9. Save the final solution. This output can be viewed later using GLVis:
|
||||
// "glvis -m ex16.mesh -g ex16-final.gf".
|
||||
{
|
||||
ofstream osol("ex16-final.gf");
|
||||
osol.precision(precision);
|
||||
u_gf.Save(osol);
|
||||
}
|
||||
|
||||
// 10. Free the used memory.
|
||||
delete ode_solver;
|
||||
delete mesh;
|
||||
u_gf.Save("ex16-final.gf", precision);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConductionOperator::ConductionOperator(FiniteElementSpace &f, double al,
|
||||
double kap, const Vector &u)
|
||||
: TimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL), K(NULL),
|
||||
T(NULL), z(height)
|
||||
ConductionOperator::ConductionOperator(FiniteElementSpace &fes,
|
||||
const real_t alpha, const real_t kappa,
|
||||
const Vector &u,
|
||||
const Type &ode_expression_type)
|
||||
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
|
||||
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace), z(height)
|
||||
{
|
||||
const double rel_tol = 1e-8;
|
||||
// specify a relative tolerance for all solves with MFEM integrators
|
||||
const real_t rel_tol = 1e-8;
|
||||
|
||||
M = new BilinearForm(&fespace);
|
||||
M->AddDomainIntegrator(new MassIntegrator());
|
||||
M->Assemble();
|
||||
M->FormSystemMatrix(ess_tdof_list, Mmat);
|
||||
M.AddDomainIntegrator(new MassIntegrator());
|
||||
M.Assemble();
|
||||
M.FormSystemMatrix(ess_tdof_list, Mmat);
|
||||
|
||||
M_solver.iterative_mode = false;
|
||||
M_solver.SetRelTol(rel_tol);
|
||||
M_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
|
||||
M_solver.SetAbsTol(0.0);
|
||||
M_solver.SetMaxIter(50);
|
||||
M_solver.SetPrintLevel(0);
|
||||
M_solver.SetPreconditioner(M_prec);
|
||||
M_solver.SetOperator(Mmat);
|
||||
|
||||
alpha = al;
|
||||
kappa = kap;
|
||||
|
||||
T_solver.iterative_mode = false;
|
||||
T_solver.SetRelTol(rel_tol);
|
||||
T_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
|
||||
T_solver.SetAbsTol(0.0);
|
||||
T_solver.SetMaxIter(100);
|
||||
T_solver.SetPrintLevel(0);
|
||||
T_solver.SetPreconditioner(T_prec);
|
||||
|
||||
SetParameters(u);
|
||||
SetConductionTensor(u);
|
||||
}
|
||||
|
||||
void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
|
||||
{
|
||||
// Compute:
|
||||
// du_dt = M^{-1}*-K(u)
|
||||
// for du_dt
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg(); // z = -z
|
||||
M_solver.Mult(z, du_dt);
|
||||
}
|
||||
|
||||
void ConductionOperator::ImplicitSolve(const double dt,
|
||||
const Vector &u, Vector &du_dt)
|
||||
{
|
||||
// Solve the equation:
|
||||
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
|
||||
// for du_dt
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
T_solver.SetOperator(*T);
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg();
|
||||
T_solver.Mult(z, du_dt);
|
||||
}
|
||||
|
||||
void ConductionOperator::SetParameters(const Vector &u)
|
||||
void ConductionOperator::SetConductionTensor(const Vector &u)
|
||||
{
|
||||
// Compute K(u_n).
|
||||
GridFunction u_alpha_gf(&fespace);
|
||||
u_alpha_gf.SetFromTrueDofs(u);
|
||||
for (int i = 0; i < u_alpha_gf.Size(); i++)
|
||||
{
|
||||
u_alpha_gf(i) = kappa + alpha*u_alpha_gf(i);
|
||||
}
|
||||
|
||||
delete K;
|
||||
K = new BilinearForm(&fespace);
|
||||
|
||||
GridFunctionCoefficient u_coeff(&u_alpha_gf);
|
||||
|
||||
K = std::make_unique<BilinearForm>(&fespace);
|
||||
K->AddDomainIntegrator(new DiffusionIntegrator(u_coeff));
|
||||
K->Assemble();
|
||||
K->FormSystemMatrix(ess_tdof_list, Kmat);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSetup(const Vector &x,
|
||||
const Vector &fx, int jok, int *jcur,
|
||||
double gamma)
|
||||
void ConductionOperator::ExplicitMult(const Vector &u, Vector &v) const
|
||||
{
|
||||
// Setup the ODE Jacobian T = M + gamma K.
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, gamma, Kmat);
|
||||
// Compute - K(u_n) u.
|
||||
Kmat.Mult(u, v);
|
||||
v.Neg();
|
||||
}
|
||||
|
||||
void ConductionOperator::Mult(const Vector &u, Vector &k) const
|
||||
{
|
||||
// Compute - inv(M) K(u_n) u.
|
||||
ExplicitMult(u, z);
|
||||
M_solver.Mult(z, k);
|
||||
}
|
||||
|
||||
void ConductionOperator::ImplicitSolve(const real_t gam, const Vector &u,
|
||||
Vector &k)
|
||||
{
|
||||
// Solve for k in M k = - K(u_n) [u + gam*k].
|
||||
ExplicitMult(u, z);
|
||||
T = std::unique_ptr<SparseMatrix>(Add(1.0, Mmat, gam, Kmat));
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = 1;
|
||||
return (0);
|
||||
T_solver.Mult(z, k);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &b, Vector &x, double tol)
|
||||
int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
|
||||
int jok, int *jcur, real_t gam)
|
||||
{
|
||||
// Solve the system A x = z => (M - gamma K) x = M b.
|
||||
Mmat.Mult(b, z);
|
||||
T_solver.Mult(z, x);
|
||||
return (0);
|
||||
// Compute T = M + gamma K(u_n).
|
||||
T = std::unique_ptr<SparseMatrix>(Add(1.0, Mmat, gam, Kmat));
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
ConductionOperator::~ConductionOperator()
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
|
||||
real_t tol)
|
||||
{
|
||||
delete T;
|
||||
delete M;
|
||||
delete K;
|
||||
}
|
||||
|
||||
double InitialTemperature(const Vector &x)
|
||||
{
|
||||
if (x.Norml2() < 0.5)
|
||||
// Solve the system [M + gamma K(u_n)] dk = - K(u_n) u - M k.
|
||||
// What value r is providing depends on the ODE expression form:
|
||||
// EXPLICIT form: r = -inv(M) K(u_n) u - k
|
||||
// IMPLICIT form: r = -K(u_n) u - M k
|
||||
T_solver.SetRelTol(tol);
|
||||
if (isExplicit())
|
||||
{
|
||||
return 2.0;
|
||||
Mmat.Mult(r, z);
|
||||
T_solver.Mult(z, dk);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0;
|
||||
T_solver.Mult(r, dk);
|
||||
}
|
||||
if (T_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SUNLS_CONV_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassSetup()
|
||||
{
|
||||
// Do nothing b/c mass solver was setup in constructor.
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
|
||||
{
|
||||
// Solve the system M x = b.
|
||||
M_solver.SetRelTol(tol);
|
||||
M_solver.Mult(b, x);
|
||||
if (M_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SUNLS_CONV_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
|
||||
{
|
||||
// Compute M x.
|
||||
Mmat.Mult(x, v);
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
+285
-188
@@ -1,16 +1,22 @@
|
||||
// MFEM Example 16 - Parallel Version
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex16p
|
||||
// Compile with:
|
||||
// make ex16p (GNU make)
|
||||
// make sundials_ex16p (CMake)
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 4 ex16p
|
||||
// mpirun -np 4 ex16p -m ../../data/inline-tri.mesh
|
||||
// mpirun -np 4 ex16p -m ../../data/disc-nurbs.mesh -tf 2
|
||||
// mpirun -np 4 ex16p -s 12 -a 0.0 -k 1.0
|
||||
// mpirun -np 4 ex16p -s 15 -a 0.0 -k 1.0
|
||||
// mpirun -np 4 ex16p -s 8 -a 1.0 -k 0.0 -dt 4e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 4 ex16p -s 11 -a 1.0 -k 0.0 -dt 4e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 8 ex16p -s 9 -a 0.5 -k 0.5 -o 4 -dt 8e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 8 ex16p -s 12 -a 0.5 -k 0.5 -o 4 -dt 8e-6 -tf 2e-2 -vs 50
|
||||
// mpirun -np 4 ex16p -s 10 -dt 2.0e-4 -tf 4.0e-2
|
||||
// mpirun -np 4 ex16p -s 13 -dt 2.0e-4 -tf 4.0e-2
|
||||
// mpirun -np 16 ex16p -m ../../data/fichera-q2.mesh
|
||||
// mpirun -np 16 ex16p -m ../../data/escher-p2.mesh
|
||||
// mpirun -np 8 ex16p -m ../../data/beam-tet.mesh -tf 10 -dt 0.1
|
||||
@@ -38,66 +44,102 @@
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
/** After spatial discretization, the conduction model can be written as:
|
||||
/** After spatial discretization, the conduction model is expressed as
|
||||
*
|
||||
* du/dt = M^{-1}(-Ku)
|
||||
* M du/dt = - K(u) u
|
||||
*
|
||||
* where u is the vector representing the temperature, M is the mass matrix,
|
||||
* and K is the diffusion operator with diffusivity depending on u:
|
||||
* and K(u) is the diffusion operator with diffusivity depending on u:
|
||||
* (\kappa + \alpha u).
|
||||
*
|
||||
* Class ConductionOperator represents the right-hand side of the above ODE.
|
||||
* Class ConductionOperatorOperator represents the above ODE operator in the
|
||||
* general form F(u, k, t) = G(u, t) where either
|
||||
*
|
||||
* 1. F(u, du/dt, t) = du/dt (ODE is expressed in EXPLICIT form)
|
||||
* G(u, t) = - inv(M) K(u) u
|
||||
* 2. F(u, du/dt, t) = M du/dt (ODE is expressed in IMPLICIT form)
|
||||
* G(u, t) = - K(u) u
|
||||
*/
|
||||
class ConductionOperator : public TimeDependentOperator
|
||||
{
|
||||
protected:
|
||||
ParFiniteElementSpace &fespace;
|
||||
Array<int> ess_tdof_list; // this list remains empty for pure Neumann b.c.
|
||||
|
||||
ParBilinearForm *M;
|
||||
ParBilinearForm *K;
|
||||
|
||||
ParBilinearForm M;
|
||||
HypreParMatrix Mmat;
|
||||
|
||||
const real_t alpha, kappa;
|
||||
std::unique_ptr<BilinearForm> K;
|
||||
HypreParMatrix Kmat;
|
||||
HypreParMatrix *T; // T = M + dt K
|
||||
double current_dt;
|
||||
|
||||
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
|
||||
HypreSmoother M_prec; // Preconditioner for the mass matrix M
|
||||
std::unique_ptr<HypreParMatrix> T; // T = M + gam K(u)
|
||||
|
||||
CGSolver T_solver; // Implicit solver for T = M + dt K
|
||||
HypreSmoother T_prec; // Preconditioner for the implicit solver
|
||||
CGSolver M_solver; // Krylov solver for inverting the mass matrix M
|
||||
HypreSmoother M_prec; // Preconditioner for the mass matrix M
|
||||
|
||||
double alpha, kappa;
|
||||
CGSolver T_solver; // Implicit solver for T = M + gam K(u)
|
||||
HypreSmoother T_prec; // Preconditioner for the implicit solver
|
||||
|
||||
mutable Vector z; // auxiliary vector
|
||||
|
||||
public:
|
||||
ConductionOperator(ParFiniteElementSpace &f, double alpha, double kappa,
|
||||
const Vector &u);
|
||||
|
||||
virtual void Mult(const Vector &u, Vector &du_dt) const;
|
||||
ConductionOperator(ParFiniteElementSpace &f, const real_t alpha,
|
||||
const real_t kappa, const Vector &u,
|
||||
const Type &ode_expression_type);
|
||||
|
||||
/** Solve the Backward-Euler equation: k = f(u + dt*k, t), for the unknown k.
|
||||
This is the only requirement for high-order SDIRK implicit integration.*/
|
||||
virtual void ImplicitSolve(const double dt, const Vector &u, Vector &k);
|
||||
// Compute K(u_n) for use as an approximation in - K(u) u
|
||||
void SetConductionTensor(const Vector &u);
|
||||
|
||||
/** Setup the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
|
||||
int jok, int *jcur, double gamma);
|
||||
/** Compute G(u, t) as defined in the IMPLICIT expression form of the ODE
|
||||
operator, i.e., @a v = - K(u_n) @a u. Note that K(u_n) is an
|
||||
approximation to K(u). */
|
||||
void ExplicitMult(const Vector &u, Vector &v) const override;
|
||||
|
||||
/** Solve the system (M + dt K) x = M b. This method is used by the implicit
|
||||
SUNDIALS solvers. */
|
||||
virtual int SUNImplicitSolve(const Vector &b, Vector &x, double tol);
|
||||
/** Solve for k in F(u, k, t) = G(u, t) for either EXPLICIT or IMPLICIT
|
||||
expression forms of the ODE operator, i.e., @a k = - inv(M) K(u_n) @a u.
|
||||
Note that K(u_n) is an approximation to K(u). */
|
||||
void Mult(const Vector &u, Vector &k) const override;
|
||||
|
||||
/// Update the diffusion BilinearForm K using the given true-dof vector `u`.
|
||||
void SetParameters(const Vector &u);
|
||||
/** Solve for k in F(u + gam*k, k, t) = G(u + gam*k, t) for either EXPLICIT
|
||||
or IMPLICIT expression forms of the ODE operator, i.e.,
|
||||
[ M + @a gam K(u_n) ] @a k = - K(u_n) @a u . Note that K(u_n) is an
|
||||
approximation to K(u). */
|
||||
void ImplicitSolve(const real_t gam, const Vector &u, Vector &k) override;
|
||||
|
||||
virtual ~ConductionOperator();
|
||||
/** Setup to solve for dk in [dF/dk + gam*dF/du - gam*dG/du] dk = G - F for
|
||||
either EXPLICIT or IMPLICIT expression forms of the ODE operator, i.e.,
|
||||
[M - @a gam Jf(u)] dk = G - F, where Jf(u) is an approximation of the
|
||||
Jacobian of -K(u) u. The approximation chosen here is Jf(u) = -K(u_n). */
|
||||
int SUNImplicitSetup(const Vector &u, const Vector &fu, int jok, int *jcur,
|
||||
real_t gam) override;
|
||||
|
||||
/** Solve for @a dk in the system in SUNImplicitSetup to the given tolerance,
|
||||
with the residual @a r providing either
|
||||
1. @a r = G - F = inv(M) f(u) - k (EXPLICIT expression form)
|
||||
1. @a r = G - F = f(u) - M k (IMPLICIT expression form)
|
||||
*/
|
||||
int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol) override;
|
||||
|
||||
int SUNMassSetup() override;
|
||||
|
||||
int SUNMassSolve(const Vector &b, Vector &x, real_t tol) override;
|
||||
|
||||
int SUNMassMult(const Vector &x, Vector &v) override;
|
||||
};
|
||||
|
||||
double InitialTemperature(const Vector &x);
|
||||
real_t InitialTemperature(const Vector &x)
|
||||
{
|
||||
if (x.Norml2() < 0.5)
|
||||
{
|
||||
return 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -114,16 +156,16 @@ int main(int argc, char *argv[])
|
||||
int par_ref_levels = 1;
|
||||
int order = 2;
|
||||
int ode_solver_type = 9; // CVODE implicit BDF
|
||||
double t_final = 0.5;
|
||||
double dt = 1.0e-2;
|
||||
double alpha = 1.0e-2;
|
||||
double kappa = 0.5;
|
||||
real_t t_final = 0.5;
|
||||
real_t dt = 1.0e-2;
|
||||
real_t alpha = 1.0e-2;
|
||||
real_t kappa = 0.5;
|
||||
bool visualization = true;
|
||||
bool visit = false;
|
||||
int vis_steps = 5;
|
||||
|
||||
// Relative and absolute tolerances for CVODE and ARKODE.
|
||||
const double reltol = 1e-4, abstol = 1e-4;
|
||||
const real_t reltol = 1e-4, abstol = 1e-4;
|
||||
|
||||
int precision = 8;
|
||||
cout.precision(precision);
|
||||
@@ -150,7 +192,10 @@ int main(int argc, char *argv[])
|
||||
"9 - CVODE (implicit BDF),\n\t"
|
||||
"10 - ARKODE (default explicit),\n\t"
|
||||
"11 - ARKODE (explicit Fehlberg-6-4-5),\n\t"
|
||||
"12 - ARKODE (default impicit).");
|
||||
"12 - ARKODE (default implicit),\n\t"
|
||||
"13 - ARKODE (default explicit with MFEM mass solve),\n\t"
|
||||
"14 - ARKODE (explicit Fehlberg-6-4-5 with MFEM mass solve),\n\t"
|
||||
"15 - ARKODE (default implicit with MFEM mass solve).");
|
||||
args.AddOption(&t_final, "-tf", "--t-final",
|
||||
"Final time; start time is 0.");
|
||||
args.AddOption(&dt, "-dt", "--time-step",
|
||||
@@ -174,40 +219,33 @@ int main(int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (myid == 0)
|
||||
if (Mpi::Root())
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
// check for valid ODE solver option
|
||||
if (ode_solver_type < 1 || ode_solver_type > 12)
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
bool use_mass_solver = ode_solver_type >= 13;
|
||||
|
||||
// 3. Read the serial mesh from the given mesh file on all processors. We can
|
||||
// 3. Define a parallel mesh by a partitioning of a serial mesh. Read the
|
||||
// serial mesh from the given mesh file on all processors. We can
|
||||
// handle triangular, quadrilateral, tetrahedral and hexahedral meshes
|
||||
// with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 4. Refine the mesh in serial to increase the resolution. In this example
|
||||
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
|
||||
// a command-line parameter.
|
||||
for (int lev = 0; lev < ser_ref_levels; lev++)
|
||||
std::unique_ptr<ParMesh> pmesh;
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
std::unique_ptr<Mesh> mesh(new Mesh(mesh_file, 1, 1));
|
||||
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
// 4. Refine the mesh in serial to increase the resolution. In this example
|
||||
// we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
|
||||
// a command-line parameter.
|
||||
for (int lev = 0; lev < ser_ref_levels; lev++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 5. Refine this mesh further in parallel to increase the resolution.
|
||||
// Once the parallel mesh is defined, the serial mesh can be deleted.
|
||||
pmesh = std::make_unique<ParMesh>(MPI_COMM_WORLD, *mesh);
|
||||
}
|
||||
for (int lev = 0; lev < par_ref_levels; lev++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
@@ -215,8 +253,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 6. Define the vector finite element space representing the current and the
|
||||
// initial temperature, u_ref.
|
||||
int dim = pmesh->Dimension();
|
||||
H1_FECollection fe_coll(order, dim);
|
||||
ParFiniteElementSpace fespace(pmesh, &fe_coll);
|
||||
ParFiniteElementSpace fespace(pmesh.get(), &fe_coll);
|
||||
|
||||
int fe_size = fespace.GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
@@ -233,8 +272,17 @@ int main(int argc, char *argv[])
|
||||
Vector u;
|
||||
u_gf.GetTrueDofs(u);
|
||||
|
||||
// 8. Initialize the conduction operator and the VisIt visualization.
|
||||
ConductionOperator oper(fespace, alpha, kappa, u);
|
||||
// 8. Initialize the conduction ODE operator and the visualization.
|
||||
ConductionOperator::Type ode_expression_type;
|
||||
if (use_mass_solver)
|
||||
{
|
||||
ode_expression_type = ConductionOperator::Type::IMPLICIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ode_expression_type = ConductionOperator::Type::EXPLICIT;
|
||||
}
|
||||
ConductionOperator oper(fespace, alpha, kappa, u, ode_expression_type);
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
{
|
||||
@@ -249,7 +297,7 @@ int main(int argc, char *argv[])
|
||||
u_gf.Save(osol);
|
||||
}
|
||||
|
||||
VisItDataCollection visit_dc("Example16-Parallel", pmesh);
|
||||
VisItDataCollection visit_dc("Example16-Parallel", pmesh.get());
|
||||
visit_dc.RegisterField("temperature", &u_gf);
|
||||
if (visit)
|
||||
{
|
||||
@@ -293,52 +341,76 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
// 9. Define the ODE solver used for time integration.
|
||||
double t = 0.0;
|
||||
ODESolver *ode_solver = NULL;
|
||||
CVODESolver *cvode = NULL;
|
||||
ARKStepSolver *arkode = NULL;
|
||||
real_t t = 0.0;
|
||||
std::unique_ptr<ODESolver> ode_solver;
|
||||
switch (ode_solver_type)
|
||||
{
|
||||
// MFEM explicit methods
|
||||
case 1: ode_solver = new ForwardEulerSolver; break;
|
||||
case 2: ode_solver = new RK2Solver(0.5); break; // midpoint method
|
||||
case 3: ode_solver = new RK3SSPSolver; break;
|
||||
case 4: ode_solver = new RK4Solver; break;
|
||||
case 1: ode_solver = std::make_unique<ForwardEulerSolver>(); break;
|
||||
case 2: ode_solver = std::make_unique<RK2Solver>(0.5); break; // midpoint method
|
||||
case 3: ode_solver = std::make_unique<RK3SSPSolver>(); break;
|
||||
case 4: ode_solver = std::make_unique<RK4Solver>(); break;
|
||||
// MFEM implicit L-stable methods
|
||||
case 5: ode_solver = new BackwardEulerSolver; break;
|
||||
case 6: ode_solver = new SDIRK23Solver(2); break;
|
||||
case 7: ode_solver = new SDIRK33Solver; break;
|
||||
case 5: ode_solver = std::make_unique<BackwardEulerSolver>(); break;
|
||||
case 6: ode_solver = std::make_unique<SDIRK23Solver>(2); break;
|
||||
case 7: ode_solver = std::make_unique<SDIRK33Solver>(); break;
|
||||
// CVODE
|
||||
case 8:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_ADAMS);
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
case 9:
|
||||
cvode = new CVODESolver(MPI_COMM_WORLD, CV_BDF);
|
||||
{
|
||||
int cvode_solver_type;
|
||||
if (ode_solver_type == 8)
|
||||
{
|
||||
cvode_solver_type = CV_ADAMS;
|
||||
}
|
||||
else
|
||||
{
|
||||
cvode_solver_type = CV_BDF;
|
||||
}
|
||||
std::unique_ptr<CVODESolver> cvode(
|
||||
new CVODESolver(MPI_COMM_WORLD, cvode_solver_type));
|
||||
cvode->Init(oper);
|
||||
cvode->SetSStolerances(reltol, abstol);
|
||||
cvode->SetMaxStep(dt);
|
||||
ode_solver = cvode; break;
|
||||
ode_solver = std::move(cvode);
|
||||
break;
|
||||
}
|
||||
// ARKODE
|
||||
case 10:
|
||||
case 11:
|
||||
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::EXPLICIT);
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
{
|
||||
ARKStepSolver::Type arkode_solver_type;
|
||||
if (ode_solver_type == 12 || ode_solver_type == 15)
|
||||
{
|
||||
arkode_solver_type = ARKStepSolver::IMPLICIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
arkode_solver_type = ARKStepSolver::EXPLICIT;
|
||||
}
|
||||
std::unique_ptr<ARKStepSolver> arkode(
|
||||
new ARKStepSolver(MPI_COMM_WORLD, arkode_solver_type));
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
if (ode_solver_type == 11)
|
||||
if (ode_solver_type == 11 || ode_solver_type == 14)
|
||||
{
|
||||
arkode->SetERKTableNum(ARKODE_FEHLBERG_13_7_8);
|
||||
}
|
||||
ode_solver = arkode; break;
|
||||
case 12:
|
||||
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::IMPLICIT);
|
||||
arkode->Init(oper);
|
||||
arkode->SetSStolerances(reltol, abstol);
|
||||
arkode->SetMaxStep(dt);
|
||||
ode_solver = arkode; break;
|
||||
if (use_mass_solver)
|
||||
{
|
||||
arkode->UseMFEMMassLinearSolver(SUNFALSE);
|
||||
}
|
||||
ode_solver = std::move(arkode);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Initialize MFEM integrators, SUNDIALS integrators are initialized above
|
||||
@@ -346,12 +418,18 @@ int main(int argc, char *argv[])
|
||||
|
||||
// Since we want to update the diffusion coefficient after every time step,
|
||||
// we need to use the "one-step" mode of the SUNDIALS solvers.
|
||||
if (cvode) { cvode->SetStepMode(CV_ONE_STEP); }
|
||||
if (arkode) { arkode->SetStepMode(ARK_ONE_STEP); }
|
||||
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
|
||||
{
|
||||
cvode->SetStepMode(CV_ONE_STEP);
|
||||
}
|
||||
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
|
||||
{
|
||||
arkode->SetStepMode(ARK_ONE_STEP);
|
||||
}
|
||||
|
||||
// 10. Perform time-integration (looping over the time iterations, ti, with a
|
||||
// time-step dt).
|
||||
if (myid == 0)
|
||||
if (Mpi::Root())
|
||||
{
|
||||
cout << "Integrating the ODE ..." << endl;
|
||||
}
|
||||
@@ -361,7 +439,7 @@ int main(int argc, char *argv[])
|
||||
bool last_step = false;
|
||||
for (int ti = 1; !last_step; ti++)
|
||||
{
|
||||
double dt_real = min(dt, t_final - t);
|
||||
real_t dt_real = min(dt, t_final - t);
|
||||
|
||||
// Note that since we are using the "one-step" mode of the SUNDIALS
|
||||
// solvers, they will, generally, step over the final time and will not
|
||||
@@ -377,8 +455,14 @@ int main(int argc, char *argv[])
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "step " << ti << ", t = " << t << endl;
|
||||
if (cvode) { cvode->PrintInfo(); }
|
||||
if (arkode) { arkode->PrintInfo(); }
|
||||
if (CVODESolver* cvode = dynamic_cast<CVODESolver*>(ode_solver.get()))
|
||||
{
|
||||
cvode->PrintInfo();
|
||||
}
|
||||
else if (ARKStepSolver* arkode = dynamic_cast<ARKStepSolver*>(ode_solver.get()))
|
||||
{
|
||||
arkode->PrintInfo();
|
||||
}
|
||||
}
|
||||
|
||||
u_gf.SetFromTrueDofs(u);
|
||||
@@ -395,46 +479,38 @@ int main(int argc, char *argv[])
|
||||
visit_dc.Save();
|
||||
}
|
||||
}
|
||||
oper.SetParameters(u);
|
||||
oper.SetConductionTensor(u);
|
||||
}
|
||||
tic_toc.Stop();
|
||||
if (myid == 0)
|
||||
if (Mpi::Root())
|
||||
{
|
||||
cout << "Done, " << tic_toc.RealTime() << "s." << endl;
|
||||
}
|
||||
|
||||
// 11. Save the final solution in parallel. This output can be viewed later
|
||||
// using GLVis: "glvis -np <np> -m ex16-mesh -g ex16-final".
|
||||
{
|
||||
ostringstream sol_name;
|
||||
sol_name << "ex16-final." << setfill('0') << setw(6) << myid;
|
||||
ofstream osol(sol_name.str().c_str());
|
||||
osol.precision(precision);
|
||||
u_gf.Save(osol);
|
||||
}
|
||||
|
||||
// 12. Free the used memory.
|
||||
delete ode_solver;
|
||||
delete pmesh;
|
||||
u_gf.Save("ex16-final", precision);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConductionOperator::ConductionOperator(ParFiniteElementSpace &f, double al,
|
||||
double kap, const Vector &u)
|
||||
: TimeDependentOperator(f.GetTrueVSize(), 0.0), fespace(f), M(NULL), K(NULL),
|
||||
T(NULL),
|
||||
M_solver(f.GetComm()), T_solver(f.GetComm()), z(height)
|
||||
ConductionOperator::ConductionOperator(ParFiniteElementSpace &fes,
|
||||
const real_t alpha, const real_t kappa,
|
||||
const Vector &u,
|
||||
const Type &ode_expression_type)
|
||||
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
|
||||
fespace(fes), alpha(alpha), kappa(kappa), M(&fespace),
|
||||
M_solver(fes.GetComm()), T_solver(fes.GetComm()), z(height)
|
||||
{
|
||||
const double rel_tol = 1e-8;
|
||||
// specify a relative tolerance for all solves with MFEM integrators
|
||||
const real_t rel_tol = 1e-8;
|
||||
|
||||
M = new ParBilinearForm(&fespace);
|
||||
M->AddDomainIntegrator(new MassIntegrator());
|
||||
M->Assemble(0); // keep sparsity pattern of M and K the same
|
||||
M->FormSystemMatrix(ess_tdof_list, Mmat);
|
||||
M.AddDomainIntegrator(new MassIntegrator());
|
||||
M.Assemble(0); // keep zeros to keep sparsity pattern of M and K the same
|
||||
M.FormSystemMatrix(ess_tdof_list, Mmat);
|
||||
|
||||
M_solver.iterative_mode = false;
|
||||
M_solver.SetRelTol(rel_tol);
|
||||
M_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
|
||||
M_solver.SetAbsTol(0.0);
|
||||
M_solver.SetMaxIter(100);
|
||||
M_solver.SetPrintLevel(0);
|
||||
@@ -442,97 +518,118 @@ ConductionOperator::ConductionOperator(ParFiniteElementSpace &f, double al,
|
||||
M_solver.SetPreconditioner(M_prec);
|
||||
M_solver.SetOperator(Mmat);
|
||||
|
||||
alpha = al;
|
||||
kappa = kap;
|
||||
|
||||
T_solver.iterative_mode = false;
|
||||
T_solver.SetRelTol(rel_tol);
|
||||
T_solver.SetRelTol(rel_tol); // will be overwritten with SUNDIALS integrators
|
||||
T_solver.SetAbsTol(0.0);
|
||||
T_solver.SetMaxIter(100);
|
||||
T_solver.SetPrintLevel(0);
|
||||
T_solver.SetPreconditioner(T_prec);
|
||||
|
||||
SetParameters(u);
|
||||
SetConductionTensor(u);
|
||||
}
|
||||
|
||||
void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
|
||||
{
|
||||
// Compute:
|
||||
// du_dt = M^{-1}*-K(u)
|
||||
// for du_dt
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg(); // z = -z
|
||||
M_solver.Mult(z, du_dt);
|
||||
}
|
||||
|
||||
void ConductionOperator::ImplicitSolve(const double dt,
|
||||
const Vector &u, Vector &du_dt)
|
||||
{
|
||||
// Solve the equation:
|
||||
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
|
||||
// for du_dt
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
T_solver.SetOperator(*T);
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg();
|
||||
T_solver.Mult(z, du_dt);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSetup(const Vector &x,
|
||||
const Vector &fx, int jok, int *jcur,
|
||||
double gamma)
|
||||
{
|
||||
// Setup the ODE Jacobian T = M + gamma K.
|
||||
if (T) { delete T; }
|
||||
T = Add(1.0, Mmat, gamma, Kmat);
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &b, Vector &x, double tol)
|
||||
{
|
||||
// Solve the system A x = z => (M - gamma K) x = M b.
|
||||
Mmat.Mult(b, z);
|
||||
T_solver.Mult(z, x);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void ConductionOperator::SetParameters(const Vector &u)
|
||||
void ConductionOperator::SetConductionTensor(const Vector &u)
|
||||
{
|
||||
// Compute K(u_n).
|
||||
ParGridFunction u_alpha_gf(&fespace);
|
||||
u_alpha_gf.SetFromTrueDofs(u);
|
||||
for (int i = 0; i < u_alpha_gf.Size(); i++)
|
||||
{
|
||||
u_alpha_gf(i) = kappa + alpha*u_alpha_gf(i);
|
||||
}
|
||||
|
||||
delete K;
|
||||
K = new ParBilinearForm(&fespace);
|
||||
|
||||
GridFunctionCoefficient u_coeff(&u_alpha_gf);
|
||||
|
||||
K = std::make_unique<ParBilinearForm>(&fespace);
|
||||
K->AddDomainIntegrator(new DiffusionIntegrator(u_coeff));
|
||||
K->Assemble(0); // keep sparsity pattern of M and K the same
|
||||
K->Assemble(0); // keep zeros to keep sparsity pattern of M and K the same
|
||||
K->FormSystemMatrix(ess_tdof_list, Kmat);
|
||||
}
|
||||
|
||||
ConductionOperator::~ConductionOperator()
|
||||
void ConductionOperator::ExplicitMult(const Vector &u, Vector &v) const
|
||||
{
|
||||
delete T;
|
||||
delete M;
|
||||
delete K;
|
||||
// Compute - K(u_n) u.
|
||||
Kmat.Mult(u, v);
|
||||
v.Neg();
|
||||
}
|
||||
|
||||
double InitialTemperature(const Vector &x)
|
||||
void ConductionOperator::Mult(const Vector &u, Vector &k) const
|
||||
{
|
||||
if (x.Norml2() < 0.5)
|
||||
// Compute - inv(M) K(u_n) u.
|
||||
ExplicitMult(u, z);
|
||||
M_solver.Mult(z, k);
|
||||
}
|
||||
|
||||
void ConductionOperator::ImplicitSolve(const real_t gam, const Vector &u,
|
||||
Vector &k)
|
||||
{
|
||||
// Solve for k in M k = - K(u_n) [u + gam*k].
|
||||
ExplicitMult(u, z);
|
||||
T = std::unique_ptr<HypreParMatrix>(Add(1.0, Mmat, gam, Kmat));
|
||||
T_solver.SetOperator(*T);
|
||||
T_solver.Mult(z, k);
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
|
||||
int jok, int *jcur, real_t gam)
|
||||
{
|
||||
// Compute T = M + gamma K(u_n).
|
||||
T = std::unique_ptr<HypreParMatrix>(Add(1.0, Mmat, gam, Kmat));
|
||||
T_solver.SetOperator(*T);
|
||||
*jcur = SUNTRUE; // this should eventually only be set true if K(u) is used
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
|
||||
real_t tol)
|
||||
{
|
||||
// Solve the system [M + gamma K(u_n)] dk = - K(u_n) u - M k.
|
||||
// What value r is providing depends on the ODE expression form:
|
||||
// EXPLICIT form: r = -inv(M) K(u_n) u - k
|
||||
// IMPLICIT form: r = -K(u_n) u - M k
|
||||
T_solver.SetRelTol(tol);
|
||||
if (isExplicit())
|
||||
{
|
||||
return 2.0;
|
||||
Mmat.Mult(r, z);
|
||||
T_solver.Mult(z, dk);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0;
|
||||
T_solver.Mult(r, dk);
|
||||
}
|
||||
if (T_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SUNLS_CONV_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassSetup()
|
||||
{
|
||||
// Do nothing b/c mass solver was setup in constructor.
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
|
||||
{
|
||||
// Solve the system M x = b.
|
||||
M_solver.SetRelTol(tol);
|
||||
M_solver.Mult(b, x);
|
||||
if (M_solver.GetConverged())
|
||||
{
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SUNLS_CONV_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
|
||||
{
|
||||
// Compute M x.
|
||||
Mmat.Mult(x, v);
|
||||
return SUNLS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// MFEM Example 9
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex9
|
||||
// Compile with:
|
||||
// make ex9 (GNU make)
|
||||
// make sundials_ex9 (CMake)
|
||||
//
|
||||
// Sample runs:
|
||||
// ex9 -m ../../data/periodic-segment.mesh -p 0 -r 2 -s 7 -dt 0.005
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// MFEM Example 9 - Parallel Version
|
||||
// SUNDIALS Modification
|
||||
//
|
||||
// Compile with: make ex9p
|
||||
// Compile with:
|
||||
// make ex9p (GNU make)
|
||||
// make sundials_ex9p (CMake)
|
||||
//
|
||||
// Sample runs:
|
||||
// mpirun -np 4 ex9p -m ../../data/periodic-segment.mesh -p 1 -rp 1 -s 7 -dt 0.0025
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/sundials/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
@@ -100,6 +99,12 @@ ex10-test-seq: ex10
|
||||
@$(call mfem-test,$<,, $(SERIAL_NAME),$(EX10_ARGS))
|
||||
ex10p-test-par: ex10p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME),$(EX10P_ARGS))
|
||||
# Example 16: test ARKODE with implicit time stepping using mass form
|
||||
EX16_COMMON_ARGS := -s 15
|
||||
ex16-test-seq: ex16
|
||||
@$(call mfem-test,$<,, $(SERIAL_NAME),$(EX16_COMMON_ARGS))
|
||||
ex16p-test-par: ex16p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), $(PARALLEL_NAME),$(EX16_COMMON_ARGS))
|
||||
|
||||
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
|
||||
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/superlu/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
+17
-2
@@ -52,6 +52,15 @@ protected:
|
||||
const DenseMatrix &EvalTransAdjugateJ();
|
||||
const DenseMatrix &EvalInverseJ();
|
||||
|
||||
/// @name Tolerance used for point comparisons
|
||||
///@{
|
||||
#ifdef MFEM_USE_DOUBLE
|
||||
static constexpr real_t tol_0 = 1e-15;
|
||||
#elif defined(MFEM_USE_SINGLE)
|
||||
static constexpr real_t tol_0 = 1e-7;
|
||||
#endif
|
||||
///@}
|
||||
|
||||
public:
|
||||
|
||||
/** This enumeration declares the values stored in
|
||||
@@ -176,7 +185,7 @@ public:
|
||||
returned. This method is not 100 percent reliable for non-linear
|
||||
transformations. */
|
||||
virtual int TransformBack(const Vector &pt, IntegrationPoint &ip,
|
||||
const real_t phys_tol = 1e-15) = 0;
|
||||
const real_t phys_tol = tol_0) = 0;
|
||||
|
||||
virtual ~ElementTransformation() { }
|
||||
};
|
||||
@@ -281,9 +290,15 @@ public:
|
||||
rel_qpts_order(-1),
|
||||
solver_type(NewtonElementProject),
|
||||
max_iter(16),
|
||||
#ifdef MFEM_USE_DOUBLE
|
||||
ref_tol(1e-15),
|
||||
phys_rtol(1e-15),
|
||||
ip_tol(1e-8),
|
||||
#elif defined(MFEM_USE_SINGLE)
|
||||
ref_tol(1e-7),
|
||||
phys_rtol(1e-7),
|
||||
ip_tol(1e-4),
|
||||
#endif
|
||||
print_level(-1)
|
||||
{ }
|
||||
|
||||
@@ -449,7 +464,7 @@ public:
|
||||
returned. This method is not 100 percent reliable for non-linear
|
||||
transformations. */
|
||||
virtual int TransformBack(const Vector & v, IntegrationPoint & ip,
|
||||
const real_t phys_rel_tol = 1e-15)
|
||||
const real_t phys_rel_tol = tol_0)
|
||||
{
|
||||
InverseElementTransformation inv_tr(this);
|
||||
inv_tr.SetPhysicalRelTol(phys_rel_tol);
|
||||
|
||||
+26
-25
@@ -394,7 +394,32 @@ public:
|
||||
/// Get a const reference to the nodes of the element
|
||||
const IntegrationRule & GetNodes() const { return Nodes; }
|
||||
|
||||
// virtual functions for finite elements on vector spaces
|
||||
/** @brief Evaluate the Hessians of all shape functions of a scalar finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
|
||||
part of the Hessian of one shape function.
|
||||
The order in 2D is {u_xx, u_xy, u_yy}.
|
||||
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
|
||||
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
|
||||
element in physical space at the given point @a ip. */
|
||||
/** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
|
||||
void CalcPhysHessian(ElementTransformation &Trans,
|
||||
DenseMatrix& Hessian) const;
|
||||
|
||||
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
|
||||
element in physical space at the given point @a ip. */
|
||||
/** The size (#dof) of @a Laplacian must be set in advance. */
|
||||
void CalcPhysLaplacian(ElementTransformation &Trans,
|
||||
Vector& Laplacian) const;
|
||||
|
||||
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
|
||||
element in physical space at the given point @a ip. */
|
||||
/** The size (#dof) of @a Laplacian must be set in advance. */
|
||||
void CalcPhysLinLaplacian(ElementTransformation &Trans,
|
||||
Vector& Laplacian) const;
|
||||
|
||||
/** @brief Evaluate the values of all shape functions of a *vector* finite
|
||||
element in reference space at the given point @a ip. */
|
||||
@@ -454,30 +479,6 @@ public:
|
||||
*/
|
||||
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
|
||||
|
||||
/** @brief Evaluate the Hessians of all shape functions of a scalar finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
|
||||
part of the Hessian of one shape function.
|
||||
The order in 2D is {u_xx, u_xy, u_yy}.
|
||||
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
|
||||
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
|
||||
virtual void CalcPhysHessian(ElementTransformation &Trans,
|
||||
DenseMatrix& Hessian) const;
|
||||
|
||||
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** The size (#dof) of @a Laplacian must be set in advance. */
|
||||
virtual void CalcPhysLaplacian(ElementTransformation &Trans,
|
||||
Vector& Laplacian) const;
|
||||
|
||||
virtual void CalcPhysLinLaplacian(ElementTransformation &Trans,
|
||||
Vector& Laplacian) const;
|
||||
|
||||
/** @brief Return the local interpolation matrix @a I (Dof x Dof) where the
|
||||
fine element is the image of the base geometry under the given
|
||||
transformation. */
|
||||
|
||||
+614
-1
@@ -398,8 +398,621 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip,
|
||||
hessian(o,5) = hessian(o,5)*sum
|
||||
- 2*du(o,1)*sum*dsum[1]
|
||||
+ u[o]*sum*(2*dsum[1]*dsum[1] - d2sum[5]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NURBS_HDiv2DFiniteElement::SetOrder() const
|
||||
{
|
||||
orders[0] = kv[0]->GetOrder();
|
||||
orders[1] = kv[1]->GetOrder();
|
||||
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
|
||||
kv1[0] = kv[0]->DegreeElevate(1);
|
||||
kv1[1] = kv[1]->DegreeElevate(1);
|
||||
|
||||
shape_x.SetSize(orders[0]+1);
|
||||
shape_y.SetSize(orders[1]+1);
|
||||
|
||||
dshape_x.SetSize(orders[0]+1);
|
||||
dshape_y.SetSize(orders[1]+1);
|
||||
|
||||
d2shape_x.SetSize(orders[0]+1);
|
||||
d2shape_y.SetSize(orders[1]+1);
|
||||
|
||||
shape1_x.SetSize(orders[0]+2);
|
||||
shape1_y.SetSize(orders[1]+2);
|
||||
|
||||
dshape1_x.SetSize(orders[0]+2);
|
||||
dshape1_y.SetSize(orders[1]+2);
|
||||
|
||||
d2shape1_x.SetSize(orders[0]+2);
|
||||
d2shape1_y.SetSize(orders[1]+2);
|
||||
|
||||
order = max(orders[0]+1, orders[1]+1);
|
||||
dof = (orders[0] + 2)*(orders[1] + 1)
|
||||
+ (orders[1] + 1)*(orders[1] + 2);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof);
|
||||
weights.SetSize(dof);
|
||||
}
|
||||
|
||||
void NURBS_HDiv2DFiniteElement::CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
|
||||
|
||||
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
|
||||
|
||||
int o = 0;
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy = shape_y(j);
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
shape(o,0) = shape1_x(i)*sy;
|
||||
shape(o,1) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1 = shape1_y(j);
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
shape(o,0) = 0.0;
|
||||
shape(o,1) = shape_x(i)*sy1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HDiv2DFiniteElement::CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
CalcVShape(Trans.GetIntPoint(), shape);
|
||||
const DenseMatrix & J = Trans.Jacobian();
|
||||
MFEM_ASSERT(J.Width() == 2 && J.Height() == 2,
|
||||
"NURBS_HDiv2DFiniteElement cannot be embedded in "
|
||||
"3 dimensional spaces");
|
||||
for (int i=0; i<dof; i++)
|
||||
{
|
||||
real_t sx = shape(i, 0);
|
||||
real_t sy = shape(i, 1);
|
||||
shape(i, 0) = sx * J(0, 0) + sy * J(0, 1);
|
||||
shape(i, 1) = sx * J(1, 0) + sy * J(1, 1);
|
||||
}
|
||||
shape *= (1.0 / Trans.Weight());
|
||||
}
|
||||
|
||||
void NURBS_HDiv2DFiniteElement::CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const
|
||||
{
|
||||
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
|
||||
|
||||
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
|
||||
|
||||
int o = 0;
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy = shape_y(j);
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
divshape(o) = dshape1_x(i)*sy;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t dsy1 = dshape1_y(j);
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
divshape(o) = shape_x(i)*dsy1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NURBS_HDiv2DFiniteElement::~NURBS_HDiv2DFiniteElement()
|
||||
{
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
}
|
||||
|
||||
|
||||
void NURBS_HDiv3DFiniteElement::SetOrder() const
|
||||
{
|
||||
orders[0] = kv[0]->GetOrder();
|
||||
orders[1] = kv[1]->GetOrder();
|
||||
orders[2] = kv[2]->GetOrder();
|
||||
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
if (kv1[2]) { delete kv1[2]; }
|
||||
|
||||
kv1[0] = kv[0]->DegreeElevate(1);
|
||||
kv1[1] = kv[1]->DegreeElevate(1);
|
||||
kv1[2] = kv[2]->DegreeElevate(1);
|
||||
|
||||
shape_x.SetSize(orders[0]+1);
|
||||
shape_y.SetSize(orders[1]+1);
|
||||
shape_z.SetSize(orders[2]+1);
|
||||
|
||||
dshape_x.SetSize(orders[0]+1);
|
||||
dshape_y.SetSize(orders[1]+1);
|
||||
dshape_z.SetSize(orders[2]+1);
|
||||
|
||||
d2shape_x.SetSize(orders[0]+1);
|
||||
d2shape_y.SetSize(orders[1]+1);
|
||||
d2shape_z.SetSize(orders[2]+1);
|
||||
|
||||
shape1_x.SetSize(orders[0]+2);
|
||||
shape1_y.SetSize(orders[1]+2);
|
||||
shape1_z.SetSize(orders[2]+2);
|
||||
|
||||
dshape1_x.SetSize(orders[0]+2);
|
||||
dshape1_y.SetSize(orders[1]+2);
|
||||
dshape1_z.SetSize(orders[2]+2);
|
||||
|
||||
d2shape1_x.SetSize(orders[0]+2);
|
||||
d2shape1_y.SetSize(orders[1]+2);
|
||||
d2shape1_z.SetSize(orders[2]+2);
|
||||
|
||||
order = max(orders[0]+1, max( orders[1]+1, orders[2]+1));
|
||||
dof = (orders[0] + 2)*(orders[1] + 1)*(orders[2] + 1) +
|
||||
(orders[0] + 1)*(orders[1] + 2)*(orders[2] + 1) +
|
||||
(orders[0] + 1)*(orders[1] + 1)*(orders[2] + 2);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof);
|
||||
weights.SetSize(dof);
|
||||
}
|
||||
|
||||
void NURBS_HDiv3DFiniteElement::CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
|
||||
kv[2]->CalcShape(shape_z, ijk[2], ip.z);
|
||||
|
||||
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
|
||||
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
|
||||
|
||||
shape = 0.0;
|
||||
int o = 0;
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_sz = shape_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
shape(o,0) = shape1_x(i)*sy_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1_sz = shape1_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
shape(o,1) = shape_x(i)*sy1_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t sz1 = shape1_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_sz1 = shape_y(j)*sz1;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
shape(o,2) = shape_x(i)*sy_sz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HDiv3DFiniteElement::CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
CalcVShape(Trans.GetIntPoint(), shape);
|
||||
const DenseMatrix & J = Trans.Jacobian();
|
||||
MFEM_ASSERT(J.Width() == 3 && J.Height() == 3,
|
||||
"RT_R2D_FiniteElement cannot be embedded in "
|
||||
"3 dimensional spaces");
|
||||
for (int i=0; i<dof; i++)
|
||||
{
|
||||
real_t sx = shape(i, 0);
|
||||
real_t sy = shape(i, 1);
|
||||
real_t sz = shape(i, 2);
|
||||
shape(i, 0) = sx * J(0, 0) + sy * J(0, 1) + sz * J(0, 2);
|
||||
shape(i, 1) = sx * J(1, 0) + sy * J(1, 1) + sz * J(1, 2);
|
||||
shape(i, 2) = sx * J(2, 0) + sy * J(2, 1) + sz * J(2, 2);
|
||||
}
|
||||
shape *= (1.0 / Trans.Weight());
|
||||
}
|
||||
|
||||
void NURBS_HDiv3DFiniteElement::CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const
|
||||
{
|
||||
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
|
||||
kv[2]->CalcShape ( shape_z, ijk[2], ip.z);
|
||||
|
||||
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
|
||||
kv1[2]->CalcDShape(dshape1_z, ijk[2], ip.z);
|
||||
|
||||
int o = 0;
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_sz = shape_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
divshape(o) = dshape1_x(i)*sy_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t dy1_sz = dshape1_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
divshape(o) = shape_x(i)*dy1_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t dz1 = dshape1_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_dz1 = shape_y(j)*dz1;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
divshape(o) = shape_x(i)*sy_dz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NURBS_HDiv3DFiniteElement::~NURBS_HDiv3DFiniteElement()
|
||||
{
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
if (kv1[2]) { delete kv1[2]; }
|
||||
}
|
||||
|
||||
void NURBS_HCurl2DFiniteElement::SetOrder() const
|
||||
{
|
||||
orders[0] = kv[0]->GetOrder();
|
||||
orders[1] = kv[1]->GetOrder();
|
||||
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
|
||||
kv1[0] = kv[0]->DegreeElevate(1);
|
||||
kv1[1] = kv[1]->DegreeElevate(1);
|
||||
|
||||
shape_x.SetSize(orders[0]+1);
|
||||
shape_y.SetSize(orders[1]+1);
|
||||
|
||||
dshape_x.SetSize(orders[0]+1);
|
||||
dshape_y.SetSize(orders[1]+1);
|
||||
|
||||
d2shape_x.SetSize(orders[0]+1);
|
||||
d2shape_y.SetSize(orders[1]+1);
|
||||
|
||||
shape1_x.SetSize(orders[0]+2);
|
||||
shape1_y.SetSize(orders[1]+2);
|
||||
|
||||
dshape1_x.SetSize(orders[0]+2);
|
||||
dshape1_y.SetSize(orders[1]+2);
|
||||
|
||||
d2shape1_x.SetSize(orders[0]+2);
|
||||
d2shape1_y.SetSize(orders[1]+2);
|
||||
|
||||
order = max(orders[0]+1, orders[1]+1);
|
||||
dof = (orders[0] + 1)*(orders[1] + 2)
|
||||
+ (orders[1] + 2)*(orders[1] + 1);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof);
|
||||
weights.SetSize(dof);
|
||||
}
|
||||
|
||||
void NURBS_HCurl2DFiniteElement::CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
|
||||
|
||||
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
|
||||
|
||||
int o = 0;
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1 = shape1_y(j);
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
shape(o,0) = shape_x(i)*sy1;
|
||||
shape(o,1) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy = shape_y(j);
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
shape(o,0) = 0.0;
|
||||
shape(o,1) = shape1_x(i)*sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HCurl2DFiniteElement::CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
CalcVShape(Trans.GetIntPoint(), shape);
|
||||
const DenseMatrix & JI = Trans.InverseJacobian();
|
||||
MFEM_ASSERT(JI.Width() == 2 && JI.Height() == 2,
|
||||
"NURBS_HCurl2DFiniteElement cannot be embedded in "
|
||||
"3 dimensional spaces");
|
||||
for (int i=0; i<dof; i++)
|
||||
{
|
||||
real_t sx = shape(i, 0);
|
||||
real_t sy = shape(i, 1);
|
||||
shape(i, 0) = sx * JI(0, 0) + sy * JI(1, 0);
|
||||
shape(i, 1) = sx * JI(0, 1) + sy * JI(1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HCurl2DFiniteElement::CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const
|
||||
{
|
||||
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
|
||||
|
||||
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
|
||||
|
||||
int o = 0;
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t dsy1 = dshape1_y(j);
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
curl_shape(o,0) = -shape_x(i)*dsy1;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy = shape_y(j);
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
curl_shape(o,0) = dshape1_x(i)*sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NURBS_HCurl2DFiniteElement::~NURBS_HCurl2DFiniteElement()
|
||||
{
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
}
|
||||
|
||||
|
||||
void NURBS_HCurl3DFiniteElement::SetOrder() const
|
||||
{
|
||||
orders[0] = kv[0]->GetOrder();
|
||||
orders[1] = kv[1]->GetOrder();
|
||||
orders[2] = kv[2]->GetOrder();
|
||||
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
if (kv1[2]) { delete kv1[2]; }
|
||||
|
||||
kv1[0] = kv[0]->DegreeElevate(1);
|
||||
kv1[1] = kv[1]->DegreeElevate(1);
|
||||
kv1[2] = kv[2]->DegreeElevate(1);
|
||||
|
||||
shape_x.SetSize(orders[0]+1);
|
||||
shape_y.SetSize(orders[1]+1);
|
||||
shape_z.SetSize(orders[2]+1);
|
||||
|
||||
dshape_x.SetSize(orders[0]+1);
|
||||
dshape_y.SetSize(orders[1]+1);
|
||||
dshape_z.SetSize(orders[2]+1);
|
||||
|
||||
d2shape_x.SetSize(orders[0]+1);
|
||||
d2shape_y.SetSize(orders[1]+1);
|
||||
d2shape_z.SetSize(orders[2]+1);
|
||||
|
||||
shape1_x.SetSize(orders[0]+2);
|
||||
shape1_y.SetSize(orders[1]+2);
|
||||
shape1_z.SetSize(orders[2]+2);
|
||||
|
||||
dshape1_x.SetSize(orders[0]+2);
|
||||
dshape1_y.SetSize(orders[1]+2);
|
||||
dshape1_z.SetSize(orders[2]+2);
|
||||
|
||||
d2shape1_x.SetSize(orders[0]+2);
|
||||
d2shape1_y.SetSize(orders[1]+2);
|
||||
d2shape1_z.SetSize(orders[2]+2);
|
||||
|
||||
order = max(orders[0]+1, max( orders[1]+1, orders[2]+1));
|
||||
dof = (orders[0] + 1)*(orders[1] + 2)*(orders[2] + 2) +
|
||||
(orders[0] + 2)*(orders[1] + 1)*(orders[2] + 2) +
|
||||
(orders[0] + 2)*(orders[1] + 2)*(orders[2] + 1);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof);
|
||||
weights.SetSize(dof);
|
||||
}
|
||||
|
||||
void NURBS_HCurl3DFiniteElement::CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
|
||||
kv[2]->CalcShape(shape_z, ijk[2], ip.z);
|
||||
|
||||
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
|
||||
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
|
||||
|
||||
shape = 0.0;
|
||||
int o = 0;
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t sz1 = shape1_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1_sz1 = shape1_y(j)*sz1;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
shape(o,0) = shape_x(i)*sy1_sz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t sz1 = shape1_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_sz1 = shape_y(j)*sz1;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
shape(o,1) = shape1_x(i)*sy_sz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1_sz = shape1_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
shape(o,2) = shape1_x(i)*sy1_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HCurl3DFiniteElement::CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
CalcVShape(Trans.GetIntPoint(), shape);
|
||||
const DenseMatrix & JI = Trans.InverseJacobian();
|
||||
MFEM_ASSERT(JI.Width() == 3 && JI.Height() == 3,
|
||||
"NURBS_HCurl3DFiniteElement must be in a"
|
||||
"3 dimensional spaces");
|
||||
for (int i=0; i<dof; i++)
|
||||
{
|
||||
real_t sx = shape(i, 0);
|
||||
real_t sy = shape(i, 1);
|
||||
real_t sz = shape(i, 2);
|
||||
shape(i, 0) = sx * JI(0, 0) + sy * JI(1, 0) + sz * JI(2, 0);
|
||||
shape(i, 1) = sx * JI(0, 1) + sy * JI(1, 1) + sz * JI(2, 1);
|
||||
shape(i, 2) = sx * JI(0, 2) + sy * JI(1, 2) + sz * JI(2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
void NURBS_HCurl3DFiniteElement::CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const
|
||||
{
|
||||
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
|
||||
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
|
||||
kv[2]->CalcShape ( shape_z, ijk[2], ip.z);
|
||||
|
||||
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
|
||||
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
|
||||
|
||||
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
|
||||
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
|
||||
kv1[2]->CalcDShape(dshape1_z, ijk[2], ip.z);
|
||||
|
||||
int o = 0;
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t sz1 = shape1_z(k), dsz1 = dshape1_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1_dsz1 = shape1_y(j)*dsz1,
|
||||
dsy1_sz1 = dshape1_y(j)*sz1;
|
||||
for (int i = 0; i <= orders[0]; i++, o++)
|
||||
{
|
||||
curl_shape(o,0) = 0.0;
|
||||
curl_shape(o,1) = shape_x(i)*sy1_dsz1;
|
||||
curl_shape(o,2) = -shape_x(i)*dsy1_sz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]+1; k++)
|
||||
{
|
||||
const real_t sz1 = shape1_z(k), dsz1 = dshape1_z(k);
|
||||
for (int j = 0; j <= orders[1]; j++)
|
||||
{
|
||||
const real_t sy_dsz1 = shape_y(j)*dsz1,
|
||||
sy_sz1 = shape_y(j)*sz1;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
curl_shape(o,0) = -shape1_x(i)*sy_dsz1;
|
||||
curl_shape(o,1) = 0.0;
|
||||
curl_shape(o,2) = dshape1_x(i)*sy_sz1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k <= orders[2]; k++)
|
||||
{
|
||||
const real_t sz = shape_z(k);
|
||||
for (int j = 0; j <= orders[1]+1; j++)
|
||||
{
|
||||
const real_t sy1_sz = shape1_y(j)*sz,
|
||||
dsy1_sz = dshape1_y(j)*sz;
|
||||
for (int i = 0; i <= orders[0]+1; i++, o++)
|
||||
{
|
||||
curl_shape(o,0) = shape1_x(i)*dsy1_sz;
|
||||
curl_shape(o,1) = -dshape1_x(i)*sy1_sz;
|
||||
curl_shape(o,2) = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NURBS_HCurl3DFiniteElement::~NURBS_HCurl3DFiniteElement()
|
||||
{
|
||||
if (kv1[0]) { delete kv1[0]; }
|
||||
if (kv1[1]) { delete kv1[1]; }
|
||||
if (kv1[2]) { delete kv1[2]; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+380
-23
@@ -20,7 +20,7 @@ namespace mfem
|
||||
class KnotVector;
|
||||
|
||||
/// An arbitrary order and dimension NURBS element
|
||||
class NURBSFiniteElement : public ScalarFiniteElement
|
||||
class NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Array <const KnotVector*> kv;
|
||||
@@ -30,31 +30,34 @@ protected:
|
||||
|
||||
public:
|
||||
/** @brief Construct NURBSFiniteElement with given
|
||||
@param D Reference space dimension
|
||||
@param G Geometry type (of type Geometry::Type)
|
||||
@param Do Number of degrees of freedom in the FiniteElement
|
||||
@param O Order/degree of the FiniteElement
|
||||
@param F FunctionSpace type of the FiniteElement
|
||||
@param dim Reference space dimension
|
||||
*/
|
||||
NURBSFiniteElement(int D, Geometry::Type G, int Do, int O, int F)
|
||||
: ScalarFiniteElement(D, G, Do, O, F)
|
||||
NURBSFiniteElement(int dim)
|
||||
{
|
||||
ijk = NULL;
|
||||
patch = elem = -1;
|
||||
kv.SetSize(dim);
|
||||
weights.SetSize(dof);
|
||||
weights = 1.0;
|
||||
}
|
||||
|
||||
/// Resets the patch and element data stored in the element
|
||||
void Reset () const { patch = elem = -1; }
|
||||
/// Set which IJK in patch should be evaluated
|
||||
void SetIJK (const int *IJK) const { ijk = IJK; }
|
||||
/// Get which patch is currently considered
|
||||
int GetPatch () const { return patch; }
|
||||
/// Set which patch should be evaluated
|
||||
void SetPatch (int p) const { patch = p; }
|
||||
/// Set which elemenet should be evaluated
|
||||
int GetElement () const { return elem; }
|
||||
/// Get which element is currently considered
|
||||
void SetElement (int e) const { elem = e; }
|
||||
/// Get the KnotVectors
|
||||
Array <const KnotVector*> &KnotVectors() const { return kv; }
|
||||
/// Get the Weights
|
||||
Vector &Weights () const { return weights; }
|
||||
/// Update the NURBSFiniteElement according to the currently set knot vectors
|
||||
/// Update the polynomial order according to the currently set knotvectors
|
||||
/// Resizes all internal data members to have the correct size
|
||||
/// related to the polynomial order
|
||||
virtual void SetOrder () const { }
|
||||
|
||||
/// Returns the indices (i,j) in 2D or (i,j,k) in 3D of this element in the
|
||||
@@ -64,7 +67,8 @@ public:
|
||||
|
||||
|
||||
/// An arbitrary order 1D NURBS element on a segment
|
||||
class NURBS1DFiniteElement : public NURBSFiniteElement
|
||||
class NURBS1DFiniteElement : public ScalarFiniteElement,
|
||||
public NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Vector shape_x;
|
||||
@@ -72,7 +76,8 @@ protected:
|
||||
public:
|
||||
/// Construct the NURBS1DFiniteElement of order @a p
|
||||
NURBS1DFiniteElement(int p)
|
||||
: NURBSFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk),
|
||||
: ScalarFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk),
|
||||
NURBSFiniteElement(1),
|
||||
shape_x(p + 1) { }
|
||||
|
||||
virtual void SetOrder() const;
|
||||
@@ -84,7 +89,8 @@ public:
|
||||
};
|
||||
|
||||
/// An arbitrary order 2D NURBS element on a square
|
||||
class NURBS2DFiniteElement : public NURBSFiniteElement
|
||||
class NURBS2DFiniteElement : public ScalarFiniteElement,
|
||||
public NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Vector u, shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
|
||||
@@ -93,16 +99,18 @@ protected:
|
||||
public:
|
||||
/// Construct the NURBS2DFiniteElement of order @a p
|
||||
NURBS2DFiniteElement(int p)
|
||||
: NURBSFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p,
|
||||
FunctionSpace::Qk),
|
||||
: ScalarFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p,
|
||||
FunctionSpace::Qk),
|
||||
NURBSFiniteElement(2),
|
||||
u(dof), shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
|
||||
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1), du(dof,2)
|
||||
{ orders[0] = orders[1] = p; }
|
||||
|
||||
/// Construct the NURBS2DFiniteElement with x-order @a px and y-order @a py
|
||||
NURBS2DFiniteElement(int px, int py)
|
||||
: NURBSFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1),
|
||||
std::max(px, py), FunctionSpace::Qk),
|
||||
: ScalarFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1),
|
||||
std::max(px, py), FunctionSpace::Qk),
|
||||
NURBSFiniteElement(2),
|
||||
u(dof), shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
|
||||
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1), du(dof,2)
|
||||
{ orders[0] = px; orders[1] = py; }
|
||||
@@ -116,7 +124,8 @@ public:
|
||||
};
|
||||
|
||||
/// An arbitrary order 3D NURBS element on a cube
|
||||
class NURBS3DFiniteElement : public NURBSFiniteElement
|
||||
class NURBS3DFiniteElement : public ScalarFiniteElement,
|
||||
public NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Vector u, shape_x, shape_y, shape_z;
|
||||
@@ -127,8 +136,9 @@ protected:
|
||||
public:
|
||||
/// Construct the NURBS3DFiniteElement of order @a p
|
||||
NURBS3DFiniteElement(int p)
|
||||
: NURBSFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p,
|
||||
FunctionSpace::Qk),
|
||||
: ScalarFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p,
|
||||
FunctionSpace::Qk),
|
||||
NURBSFiniteElement(3),
|
||||
u(dof), shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
|
||||
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
|
||||
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1), du(dof,3)
|
||||
@@ -137,8 +147,9 @@ public:
|
||||
/// Construct the NURBS3DFiniteElement with x-order @a px and y-order @a py
|
||||
/// and z-order @a pz
|
||||
NURBS3DFiniteElement(int px, int py, int pz)
|
||||
: NURBSFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1),
|
||||
std::max(std::max(px,py),pz), FunctionSpace::Qk),
|
||||
: ScalarFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1),
|
||||
std::max(std::max(px,py),pz), FunctionSpace::Qk),
|
||||
NURBSFiniteElement(2),
|
||||
u(dof), shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
|
||||
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
|
||||
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1), du(dof,3)
|
||||
@@ -152,6 +163,352 @@ public:
|
||||
DenseMatrix &hessian) const;
|
||||
};
|
||||
|
||||
|
||||
/** An arbitrary order H(div)-conforming 2D NURBS element on a square.
|
||||
More details in the following papers:
|
||||
|
||||
[1] Annalisa Buffa, Carlo De Falco, Giancarlo Sangalli
|
||||
"Isogeometric analysis: stable elements for the 2D Stokes equation."
|
||||
International Journal for Numerical Methods in Fluids 65 (11‐12) 1407-1422
|
||||
|
||||
[2] John A Evans, Thomas JR Hughes
|
||||
"Isogeometric divergence-conforming B-splines for the unsteady Navier–Stokes equations."
|
||||
Journal of Computational Physics (241) 141-167
|
||||
*/
|
||||
class NURBS_HDiv2DFiniteElement : public VectorFiniteElement,
|
||||
public NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
|
||||
mutable Vector shape1_x, shape1_y, dshape1_x, dshape1_y, d2shape1_x, d2shape1_y;
|
||||
mutable Vector u;
|
||||
mutable DenseMatrix du;
|
||||
mutable Array <const KnotVector*> kv1;
|
||||
|
||||
public:
|
||||
/// Construct the NURBS_HDiv2DFiniteElement of order @a p
|
||||
NURBS_HDiv2DFiniteElement(int p)
|
||||
: VectorFiniteElement(2, Geometry::SQUARE, 2*(p + 1)*(p + 2), p,
|
||||
H_DIV,FunctionSpace::Qk),
|
||||
NURBSFiniteElement(2),
|
||||
shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
|
||||
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1),
|
||||
shape1_x(p + 2), shape1_y(p + 2), dshape1_x(p + 2),
|
||||
dshape1_y(p + 2), d2shape1_x(p + 2), d2shape1_y(p + 2),
|
||||
u(dof), du(dof,2)
|
||||
{
|
||||
orders[0] = orders[1] = p;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
}
|
||||
|
||||
/// Construct the NURBS_HDiv2DFiniteElement with x-order @a px and y-order @a py
|
||||
NURBS_HDiv2DFiniteElement(int px, int py)
|
||||
: VectorFiniteElement(2, Geometry::SQUARE,
|
||||
(px + 2)*(py + 1)+(px + 1)*(py + 2),
|
||||
std::max(px, py), H_DIV, FunctionSpace::Qk),
|
||||
NURBSFiniteElement(2),
|
||||
shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
|
||||
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1),
|
||||
shape1_x(px + 2), shape1_y(py + 2), dshape1_x(px + 2),
|
||||
dshape1_y(py + 2), d2shape1_x(px + 2), d2shape1_y(py + 2),
|
||||
u(dof), du(dof,2)
|
||||
{
|
||||
orders[0] = px; orders[1] = py;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
}
|
||||
|
||||
virtual void SetOrder() const;
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the values of all shape functions of a *vector* finite
|
||||
element in physical space at the point described by @a Trans. */
|
||||
/** Each row of the result DenseMatrix @a shape contains the components of
|
||||
one vector shape function. The size (#dof x SDim) of @a shape must be set
|
||||
in advance, where SDim >= #dim is the physical space dimension as
|
||||
described by @a Trans. */
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the divergence of all shape functions of a *vector*
|
||||
finite element in reference space at the given point @a ip. */
|
||||
/** The size (#dof) of the result Vector @a divshape must be set in advance.
|
||||
*/
|
||||
virtual void CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const;
|
||||
|
||||
~NURBS_HDiv2DFiniteElement();
|
||||
};
|
||||
|
||||
|
||||
/** An arbitrary order H(div)-conforming 3D NURBS element on a cube
|
||||
More details in the following papers:
|
||||
|
||||
[1] Annalisa Buffa, Carlo De Falco, Giancarlo Sangalli
|
||||
"Isogeometric analysis: stable elements for the 2D Stokes equation."
|
||||
International Journal for Numerical Methods in Fluids 65 (11‐12) 1407-1422
|
||||
|
||||
[2] John A Evans, Thomas JR Hughes
|
||||
"Isogeometric divergence-conforming B-splines for the unsteady
|
||||
Navier–Stokes equations."
|
||||
Journal of Computational Physics (241) 141-167 */
|
||||
class NURBS_HDiv3DFiniteElement : public VectorFiniteElement,
|
||||
public NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Vector shape_x, shape_y, shape_z;
|
||||
mutable Vector dshape_x, dshape_y, dshape_z;
|
||||
mutable Vector d2shape_x, d2shape_y, d2shape_z;
|
||||
mutable Vector shape1_x, shape1_y, shape1_z;
|
||||
mutable Vector dshape1_x, dshape1_y, dshape1_z;
|
||||
mutable Vector d2shape1_x, d2shape1_y, d2shape1_z;
|
||||
mutable Vector u;
|
||||
mutable DenseMatrix du;
|
||||
mutable Array <const KnotVector*> kv1;
|
||||
|
||||
public:
|
||||
/// Construct the NURBS_HDiv3DFiniteElement of order @a p
|
||||
NURBS_HDiv3DFiniteElement(int p)
|
||||
: VectorFiniteElement(3, Geometry::CUBE, 3*(p + 1)*(p + 1)*(p + 2),
|
||||
p, H_DIV,FunctionSpace::Qk),
|
||||
NURBSFiniteElement(3),
|
||||
shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
|
||||
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
|
||||
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1),
|
||||
shape1_x(p + 2), shape1_y(p + 2), shape1_z(p + 2),
|
||||
dshape1_x(p + 2), dshape1_y(p + 2),dshape1_z(p + 2),
|
||||
d2shape1_x(p + 2), d2shape1_y(p + 2), d2shape1_z(p + 2),
|
||||
u(dof), du(dof,3)
|
||||
{
|
||||
orders[0] = orders[1] = orders[2] = p;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
kv1[2] = nullptr;
|
||||
}
|
||||
|
||||
/// Construct the NURBS_HDiv3DFiniteElement with x-order @a px, y-order @a py and z-order @a pz
|
||||
NURBS_HDiv3DFiniteElement(int px, int py, int pz)
|
||||
: VectorFiniteElement(3, Geometry::CUBE,
|
||||
(px + 2)*(py + 1)*(pz + 1) +
|
||||
(px + 1)*(py + 2)*(pz + 1) +
|
||||
(px + 1)*(py + 1)*(pz + 2),
|
||||
std::max(px, py), H_DIV, FunctionSpace::Qk),
|
||||
NURBSFiniteElement(3),
|
||||
shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
|
||||
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
|
||||
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1),
|
||||
shape1_x(px + 2), shape1_y(py + 2), shape1_z(pz + 2),
|
||||
dshape1_x(px + 2), dshape1_y(py + 2),dshape1_z(pz + 2),
|
||||
d2shape1_x(px + 2), d2shape1_y(py + 2), d2shape1_z(pz + 2),
|
||||
u(dof), du(dof,3)
|
||||
{
|
||||
orders[0] = px; orders[1] = py; orders[2] = pz;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
kv1[2] = nullptr;
|
||||
}
|
||||
|
||||
virtual void SetOrder() const;
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the values of all shape functions of a *vector* finite
|
||||
element in physical space at the point described by @a Trans. */
|
||||
/** Each row of the result DenseMatrix @a shape contains the components of
|
||||
one vector shape function. The size (#dof x SDim) of @a shape must be set
|
||||
in advance, where SDim >= #dim is the physical space dimension as
|
||||
described by @a Trans. */
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the divergence of all shape functions of a *vector*
|
||||
finite element in reference space at the given point @a ip. */
|
||||
/** The size (#dof) of the result Vector @a divshape must be set in advance.
|
||||
*/
|
||||
virtual void CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const;
|
||||
|
||||
~NURBS_HDiv3DFiniteElement();
|
||||
};
|
||||
|
||||
|
||||
/** An arbitrary order H(curl)-conforming 2D NURBS element on a square
|
||||
More details in the following paper:
|
||||
|
||||
[1] Annalisa Buffa, Giancarlo Sangalli, Rafael Vázquez
|
||||
"Isogeometric analysis in electromagnetics: B-splines approximation."
|
||||
Computer Methods in Applied Mechanics and Engineering (199) 1143-1152 */
|
||||
class NURBS_HCurl2DFiniteElement : public VectorFiniteElement,
|
||||
public NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
|
||||
mutable Vector shape1_x, shape1_y, dshape1_x, dshape1_y, d2shape1_x, d2shape1_y;
|
||||
mutable Vector u;
|
||||
mutable DenseMatrix du;
|
||||
mutable Array <const KnotVector*> kv1;
|
||||
|
||||
public:
|
||||
/// Construct the NURBS_HCurl2DFiniteElement of order @a p
|
||||
NURBS_HCurl2DFiniteElement(int p)
|
||||
: VectorFiniteElement(2, Geometry::SQUARE, 2*(p + 1)*(p + 2), p,
|
||||
H_CURL,FunctionSpace::Qk),
|
||||
NURBSFiniteElement(2),
|
||||
shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
|
||||
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1),
|
||||
shape1_x(p + 2), shape1_y(p + 2), dshape1_x(p + 2),
|
||||
dshape1_y(p + 2), d2shape1_x(p + 2), d2shape1_y(p + 2),
|
||||
u(dof), du(dof,2)
|
||||
{
|
||||
orders[0] = orders[1] = p;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
}
|
||||
|
||||
/// Construct the NURBS_HCurl2DFiniteElement with x-order @a px and y-order @a py
|
||||
NURBS_HCurl2DFiniteElement(int px, int py)
|
||||
: VectorFiniteElement(2, Geometry::SQUARE,
|
||||
(px + 1)*(py + 2)+(px + 2)*(py + 1),
|
||||
std::max(px, py), H_CURL, FunctionSpace::Qk),
|
||||
NURBSFiniteElement(2),
|
||||
shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
|
||||
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1),
|
||||
shape1_x(px + 2), shape1_y(py + 2), dshape1_x(px + 2),
|
||||
dshape1_y(py + 2), d2shape1_x(px + 2), d2shape1_y(py + 2),
|
||||
u(dof), du(dof,2)
|
||||
{
|
||||
orders[0] = px; orders[1] = py;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
}
|
||||
|
||||
virtual void SetOrder() const;
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the values of all shape functions of a *vector* finite
|
||||
element in physical space at the point described by @a Trans. */
|
||||
/** Each row of the result DenseMatrix @a shape contains the components of
|
||||
one vector shape function. The size (#dof x SDim) of @a shape must be set
|
||||
in advance, where SDim >= #dim is the physical space dimension as
|
||||
described by @a Trans. */
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the curl of all shape functions of a *vector* finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** Each row of the result DenseMatrix @a curl_shape contains the components
|
||||
of the curl of one vector shape function. The size (#dof x CDim) of
|
||||
@a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
|
||||
CDim = 1 for #dim = 2. */
|
||||
virtual void CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
|
||||
~NURBS_HCurl2DFiniteElement();
|
||||
};
|
||||
|
||||
|
||||
/** An arbitrary order H(curl)-conforming 3D NURBS element on a cube
|
||||
More details in the following paper:
|
||||
|
||||
[1] Annalisa Buffa, Giancarlo Sangalli, Rafael Vázquez
|
||||
"Isogeometric analysis in electromagnetics: B-splines approximation."
|
||||
Computer Methods in Applied Mechanics and Engineering (199) 1143-1152 */
|
||||
class NURBS_HCurl3DFiniteElement : public VectorFiniteElement,
|
||||
public NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Vector shape_x, shape_y, shape_z;
|
||||
mutable Vector dshape_x, dshape_y, dshape_z;
|
||||
mutable Vector d2shape_x, d2shape_y, d2shape_z;
|
||||
mutable Vector shape1_x, shape1_y, shape1_z;
|
||||
mutable Vector dshape1_x, dshape1_y, dshape1_z;
|
||||
mutable Vector d2shape1_x, d2shape1_y, d2shape1_z;
|
||||
mutable Vector u;
|
||||
mutable DenseMatrix du;
|
||||
mutable Array <const KnotVector*> kv1;
|
||||
|
||||
public:
|
||||
/// Construct the NURBS_HCurl3DFiniteElement of order @a p
|
||||
NURBS_HCurl3DFiniteElement(int p)
|
||||
: VectorFiniteElement(3, Geometry::CUBE, 3*(p + 1)*(p + 2)*(p + 2), p,
|
||||
H_CURL,FunctionSpace::Qk),
|
||||
NURBSFiniteElement(3),
|
||||
shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
|
||||
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
|
||||
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1),
|
||||
shape1_x(p + 2), shape1_y(p + 2), shape1_z(p + 2),
|
||||
dshape1_x(p + 2), dshape1_y(p + 2),dshape1_z(p + 2),
|
||||
d2shape1_x(p + 2), d2shape1_y(p + 2), d2shape1_z(p + 2),
|
||||
u(dof), du(dof,3)
|
||||
{
|
||||
orders[0] = orders[1] = orders[2] = p;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
kv1[2] = nullptr;
|
||||
}
|
||||
|
||||
/// Construct the NURBS_HCurl3DFiniteElement with x-order @a px, y-order @a py and z-order @a pz
|
||||
NURBS_HCurl3DFiniteElement(int px, int py, int pz)
|
||||
: VectorFiniteElement(3, Geometry::CUBE,
|
||||
(px + 1)*(py + 2)*(pz + 2) +
|
||||
(px + 2)*(py + 1)*(pz + 2) +
|
||||
(px + 2)*(py + 2)*(pz + 1),
|
||||
std::max(std::max(px, py), pz), H_CURL, FunctionSpace::Qk),
|
||||
NURBSFiniteElement(3),
|
||||
shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
|
||||
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
|
||||
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1),
|
||||
shape1_x(px + 2), shape1_y(py + 2), shape1_z(pz + 2),
|
||||
dshape1_x(px + 2), dshape1_y(py + 2),dshape1_z(pz + 2),
|
||||
d2shape1_x(px + 2), d2shape1_y(py + 2), d2shape1_z(pz + 2),
|
||||
u(dof), du(dof,3)
|
||||
{
|
||||
orders[0] = px; orders[1] = py; orders[2] = pz;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
kv1[2] = nullptr;
|
||||
}
|
||||
|
||||
virtual void SetOrder() const;
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the values of all shape functions of a *vector* finite
|
||||
element in physical space at the point described by @a Trans. */
|
||||
/** Each row of the result DenseMatrix @a shape contains the components of
|
||||
one vector shape function. The size (#dof x SDim) of @a shape must be set
|
||||
in advance, where SDim >= #dim is the physical space dimension as
|
||||
described by @a Trans. */
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the curl of all shape functions of a *vector* finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** Each row of the result DenseMatrix @a curl_shape contains the components
|
||||
of the curl of one vector shape function. The size (#dof x CDim) of
|
||||
@a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
|
||||
CDim = 1 for #dim = 2. */
|
||||
virtual void CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
|
||||
~NURBS_HCurl3DFiniteElement();
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
+214
@@ -344,6 +344,32 @@ FiniteElementCollection *FiniteElementCollection::New(const char *name)
|
||||
{
|
||||
fec = new Local_FECollection(name + 6);
|
||||
}
|
||||
else if (!strncmp(name, "NURBS_HDiv", 10))
|
||||
{
|
||||
if (name[10] != '\0')
|
||||
{
|
||||
// "NURBS" + "number" --> fixed order nurbs collection
|
||||
fec = new NURBS_HDivFECollection(atoi(name + 10));
|
||||
}
|
||||
else
|
||||
{
|
||||
// "NURBS" --> variable order nurbs collection
|
||||
fec = new NURBS_HDivFECollection();
|
||||
}
|
||||
}
|
||||
else if (!strncmp(name, "NURBS_HCurl", 11))
|
||||
{
|
||||
if (name[11] != '\0')
|
||||
{
|
||||
// "NURBS" + "number" --> fixed order nurbs collection
|
||||
fec = new NURBS_HCurlFECollection(atoi(name + 11));
|
||||
}
|
||||
else
|
||||
{
|
||||
// "NURBS" --> variable order nurbs collection
|
||||
fec = new NURBS_HCurlFECollection();
|
||||
}
|
||||
}
|
||||
else if (!strncmp(name, "NURBS", 5))
|
||||
{
|
||||
if (name[5] != '\0')
|
||||
@@ -3533,4 +3559,192 @@ FiniteElementCollection *NURBSFECollection::GetTraceCollection() const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
NURBS_HDivFECollection::NURBS_HDivFECollection(int Order, const int dim)
|
||||
: NURBSFECollection((Order == VariableOrder) ? 1 : Order)
|
||||
{
|
||||
const int order = (Order == VariableOrder) ? 1 : Order;
|
||||
|
||||
SegmentFE = new NURBS1DFiniteElement(order);
|
||||
QuadrilateralFE = new NURBS2DFiniteElement(order);
|
||||
|
||||
QuadrilateralVFE = new NURBS_HDiv2DFiniteElement(order);
|
||||
ParallelepipedVFE = new NURBS_HDiv3DFiniteElement(order);
|
||||
|
||||
if (dim != -1) { SetDim(dim); }
|
||||
SetOrder(Order);
|
||||
}
|
||||
|
||||
void NURBS_HDivFECollection::SetDim(int dim)
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
sFE = SegmentFE;
|
||||
qFE = QuadrilateralVFE;
|
||||
hFE = nullptr;
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
sFE = nullptr;
|
||||
qFE = QuadrilateralFE;
|
||||
hFE = ParallelepipedVFE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem::err<<"Dimension = "<<dim<<endl;
|
||||
mfem_error ("NURBS_HDivFECollection: wrong dimension!");
|
||||
}
|
||||
}
|
||||
|
||||
NURBS_HDivFECollection::~NURBS_HDivFECollection()
|
||||
{
|
||||
delete SegmentFE;
|
||||
delete QuadrilateralFE;
|
||||
delete QuadrilateralVFE;
|
||||
delete ParallelepipedVFE;
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
NURBS_HDivFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::SEGMENT: return sFE;
|
||||
case Geometry::SQUARE: return qFE;
|
||||
case Geometry::CUBE: return hFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("NURBS_HDivFECollection: unknown geometry type.");
|
||||
}
|
||||
return QuadrilateralFE; // Make some compilers happy
|
||||
}
|
||||
|
||||
void NURBS_HDivFECollection::SetOrder(int Order) const
|
||||
{
|
||||
mOrder = Order;
|
||||
if (Order != VariableOrder)
|
||||
{
|
||||
snprintf(name, 16, "NURBS_HDiv%i", Order);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(name, 16, "NURBS_HDiv");
|
||||
}
|
||||
}
|
||||
|
||||
int NURBS_HDivFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
mfem_error("NURBS_HDivFECollection::DofForGeometry");
|
||||
return 0; // Make some compilers happy
|
||||
}
|
||||
|
||||
const int *NURBS_HDivFECollection::DofOrderForOrientation(
|
||||
Geometry::Type GeomType,
|
||||
int Or) const
|
||||
{
|
||||
mfem_error("NURBS_HDivFECollection::DofOrderForOrientation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FiniteElementCollection *NURBS_HDivFECollection::GetTraceCollection() const
|
||||
{
|
||||
MFEM_ABORT("NURBS finite elements can not be statically condensed!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NURBS_HCurlFECollection::NURBS_HCurlFECollection(int Order, const int dim)
|
||||
: NURBSFECollection((Order == VariableOrder) ? 1 : Order)
|
||||
{
|
||||
const int order = (Order == VariableOrder) ? 1 : Order;
|
||||
|
||||
SegmentFE = new NURBS1DFiniteElement(order+1);
|
||||
QuadrilateralFE = new NURBS2DFiniteElement(order+1);
|
||||
|
||||
QuadrilateralVFE = new NURBS_HCurl2DFiniteElement(order);
|
||||
ParallelepipedVFE = new NURBS_HCurl3DFiniteElement(order);
|
||||
if (dim != -1) { SetDim(dim); }
|
||||
SetOrder(Order);
|
||||
}
|
||||
|
||||
void NURBS_HCurlFECollection::SetDim(int dim)
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
sFE = SegmentFE;
|
||||
qFE = QuadrilateralVFE;
|
||||
hFE = nullptr;
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
sFE = nullptr;
|
||||
qFE = QuadrilateralFE;
|
||||
hFE = ParallelepipedVFE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem::err<<"Dimension = "<<dim<<endl;
|
||||
mfem_error ("NURBS_HCurlFECollection: wrong dimension!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
NURBS_HCurlFECollection::~NURBS_HCurlFECollection()
|
||||
{
|
||||
delete SegmentFE;
|
||||
delete QuadrilateralFE;
|
||||
delete QuadrilateralVFE;
|
||||
delete ParallelepipedVFE;
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
NURBS_HCurlFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::SEGMENT: return sFE;
|
||||
case Geometry::SQUARE: return qFE;
|
||||
case Geometry::CUBE: return hFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("NURBS_HCurlFECollection: unknown geometry type.");
|
||||
}
|
||||
return QuadrilateralFE; // Make some compilers happy
|
||||
}
|
||||
|
||||
void NURBS_HCurlFECollection::SetOrder(int Order) const
|
||||
{
|
||||
mOrder = Order;
|
||||
if (Order != VariableOrder)
|
||||
{
|
||||
snprintf(name, 16, "NURBS_HCurl%i", Order);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(name, 16, "NURBS_HCurl");
|
||||
}
|
||||
}
|
||||
|
||||
int NURBS_HCurlFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
mfem_error("NURBS_HCurlFECollection::DofForGeometry");
|
||||
return 0; // Make some compilers happy
|
||||
}
|
||||
|
||||
const int *NURBS_HCurlFECollection::DofOrderForOrientation(
|
||||
Geometry::Type GeomType,
|
||||
int Or) const
|
||||
{
|
||||
mfem_error("NURBS_HCurlFECollection::DofOrderForOrientation");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FiniteElementCollection *NURBS_HCurlFECollection::GetTraceCollection() const
|
||||
{
|
||||
MFEM_ABORT("NURBS finite elements can not be statically condensed!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+109
-4
@@ -680,8 +680,8 @@ public:
|
||||
/// Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
|
||||
class NURBSFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
PointFiniteElement *PointFE;
|
||||
protected:
|
||||
PointFiniteElement *PointFE;
|
||||
NURBS1DFiniteElement *SegmentFE;
|
||||
NURBS2DFiniteElement *QuadrilateralFE;
|
||||
NURBS3DFiniteElement *ParallelepipedFE;
|
||||
@@ -701,13 +701,15 @@ public:
|
||||
order, or VariableOrder (default). */
|
||||
explicit NURBSFECollection(int Order = VariableOrder);
|
||||
|
||||
void Reset() const
|
||||
virtual void Reset() const
|
||||
{
|
||||
SegmentFE->Reset();
|
||||
QuadrilateralFE->Reset();
|
||||
ParallelepipedFE->Reset();
|
||||
}
|
||||
|
||||
virtual void SetDim(const int dim) {};
|
||||
|
||||
/** @brief Get the order of the NURBS collection: either a positive number,
|
||||
when using fixed order, or VariableOrder. */
|
||||
/** @note Not to be confused with FiniteElementCollection::GetOrder(). */
|
||||
@@ -715,7 +717,7 @@ public:
|
||||
|
||||
/** @brief Set the order and the name, based on the given @a Order: either a
|
||||
positive number for fixed order, or VariableOrder. */
|
||||
void SetOrder(int Order) const;
|
||||
virtual void SetOrder(int Order) const;
|
||||
|
||||
const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const override;
|
||||
@@ -734,6 +736,109 @@ public:
|
||||
virtual ~NURBSFECollection();
|
||||
};
|
||||
|
||||
/// Arbitrary order H(div) NURBS finite elements.
|
||||
class NURBS_HDivFECollection : public NURBSFECollection
|
||||
{
|
||||
private:
|
||||
|
||||
NURBS1DFiniteElement *SegmentFE;
|
||||
NURBS2DFiniteElement *QuadrilateralFE;
|
||||
|
||||
NURBS_HDiv2DFiniteElement *QuadrilateralVFE;
|
||||
NURBS_HDiv3DFiniteElement *ParallelepipedVFE;
|
||||
|
||||
FiniteElement *sFE;
|
||||
FiniteElement *qFE;
|
||||
FiniteElement *hFE;
|
||||
|
||||
public:
|
||||
|
||||
/** @brief The parameter @a Order must be either a positive number, for fixed
|
||||
order, or VariableOrder (default). */
|
||||
explicit NURBS_HDivFECollection(int Order = VariableOrder, const int vdim = -1);
|
||||
|
||||
virtual void Reset() const override
|
||||
{
|
||||
SegmentFE->Reset();
|
||||
QuadrilateralFE->Reset();
|
||||
QuadrilateralVFE->Reset();
|
||||
ParallelepipedVFE->Reset();
|
||||
}
|
||||
|
||||
virtual void SetDim(const int dim) override;
|
||||
|
||||
/** @brief Set the order and the name, based on the given @a Order: either a
|
||||
positive number for fixed order, or VariableOrder. */
|
||||
virtual void SetOrder(int Order) const override;
|
||||
|
||||
const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const override;
|
||||
|
||||
int DofForGeometry(Geometry::Type GeomType) const override;
|
||||
|
||||
const int *DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const override;
|
||||
|
||||
const char *Name() const override { return name; }
|
||||
|
||||
int GetContType() const override { return CONTINUOUS; }
|
||||
|
||||
FiniteElementCollection *GetTraceCollection() const override;
|
||||
|
||||
virtual ~NURBS_HDivFECollection();
|
||||
};
|
||||
|
||||
/// Arbitrary order H(curl) NURBS finite elements.
|
||||
class NURBS_HCurlFECollection : public NURBSFECollection
|
||||
{
|
||||
private:
|
||||
NURBS1DFiniteElement *SegmentFE;
|
||||
NURBS2DFiniteElement *QuadrilateralFE;
|
||||
|
||||
NURBS_HCurl2DFiniteElement *QuadrilateralVFE;
|
||||
NURBS_HCurl3DFiniteElement *ParallelepipedVFE;
|
||||
|
||||
FiniteElement *sFE;
|
||||
FiniteElement *qFE;
|
||||
FiniteElement *hFE;
|
||||
public:
|
||||
|
||||
/** @brief The parameter @a Order must be either a positive number, for fixed
|
||||
order, or VariableOrder (default). */
|
||||
explicit NURBS_HCurlFECollection(int Order = VariableOrder,
|
||||
const int vdim = -1);
|
||||
|
||||
virtual void Reset() const override
|
||||
{
|
||||
SegmentFE->Reset();
|
||||
QuadrilateralFE->Reset();
|
||||
QuadrilateralVFE->Reset();
|
||||
ParallelepipedVFE->Reset();
|
||||
}
|
||||
|
||||
virtual void SetDim(const int dim) override;
|
||||
|
||||
/** @brief Set the order and the name, based on the given @a Order: either a
|
||||
positive number for fixed order, or VariableOrder. */
|
||||
virtual void SetOrder(int Order) const override;
|
||||
|
||||
const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const override;
|
||||
|
||||
int DofForGeometry(Geometry::Type GeomType) const override;
|
||||
|
||||
const int *DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const override;
|
||||
|
||||
const char *Name() const override { return name; }
|
||||
|
||||
int GetContType() const override { return CONTINUOUS; }
|
||||
|
||||
FiniteElementCollection *GetTraceCollection() const override;
|
||||
|
||||
virtual ~NURBS_HCurlFECollection();
|
||||
};
|
||||
|
||||
/// Piecewise-(bi/tri)linear continuous finite elements.
|
||||
class LinearFECollection : public FiniteElementCollection
|
||||
{
|
||||
|
||||
+263
-38
@@ -1525,6 +1525,67 @@ SparseMatrix *FiniteElementSpace::RefinementMatrix_main(
|
||||
return P;
|
||||
}
|
||||
|
||||
SparseMatrix *FiniteElementSpace::VariableOrderRefinementMatrix(
|
||||
const int coarse_ndofs, const Table &coarse_elem_dof) const
|
||||
{
|
||||
MFEM_VERIFY(mesh->GetLastOperation() == Mesh::REFINE, "");
|
||||
|
||||
Array<int> dofs, coarse_dofs, coarse_vdofs;
|
||||
Vector row;
|
||||
|
||||
Mesh::GeometryList elem_geoms(*mesh);
|
||||
|
||||
SparseMatrix *P = new SparseMatrix(GetVSize(), coarse_ndofs*vdim);
|
||||
|
||||
Array<int> mark(P->Height());
|
||||
mark = 0;
|
||||
|
||||
const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
|
||||
DenseMatrix lP;
|
||||
IsoparametricTransformation isotr;
|
||||
for (int k = 0; k < mesh->GetNE(); k++)
|
||||
{
|
||||
const Embedding &emb = rtrans.embeddings[k];
|
||||
const Geometry::Type geom = mesh->GetElementBaseGeometry(k);
|
||||
|
||||
const FiniteElement *fe = GetFE(k);
|
||||
isotr.SetIdentityTransformation(geom);
|
||||
const int ldof = fe->GetDof();
|
||||
lP.SetSize(ldof, ldof);
|
||||
const DenseTensor &pmats = rtrans.point_matrices[geom];
|
||||
isotr.SetPointMat(pmats(emb.matrix));
|
||||
fe->GetLocalInterpolation(isotr, lP);
|
||||
|
||||
const int fine_ldof = lP.Height();
|
||||
|
||||
elem_dof->GetRow(k, dofs);
|
||||
coarse_elem_dof.GetRow(emb.parent, coarse_dofs);
|
||||
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
{
|
||||
coarse_dofs.Copy(coarse_vdofs);
|
||||
DofsToVDofs(vd, coarse_vdofs, coarse_ndofs);
|
||||
|
||||
for (int i = 0; i < fine_ldof; i++)
|
||||
{
|
||||
const int r = DofToVDof(dofs[i], vd);
|
||||
int m = (r >= 0) ? r : (-1 - r);
|
||||
|
||||
if (!mark[m])
|
||||
{
|
||||
lP.GetRow(i, row);
|
||||
P->SetRow(r, coarse_vdofs, row);
|
||||
mark[m] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_VERIFY(mark.Sum() == P->Height(), "Not all rows of P set.");
|
||||
P->Finalize();
|
||||
return P;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetLocalRefinementMatrices(
|
||||
Geometry::Type geom, DenseTensor &localP) const
|
||||
{
|
||||
@@ -1556,15 +1617,20 @@ SparseMatrix* FiniteElementSpace::RefinementMatrix(int old_ndofs,
|
||||
"Previous mesh is not coarser.");
|
||||
|
||||
Mesh::GeometryList elem_geoms(*mesh);
|
||||
|
||||
DenseTensor localP[Geometry::NumGeom];
|
||||
for (int i = 0; i < elem_geoms.Size(); i++)
|
||||
if (!IsVariableOrder())
|
||||
{
|
||||
GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
|
||||
DenseTensor localP[Geometry::NumGeom];
|
||||
for (int i = 0; i < elem_geoms.Size(); i++)
|
||||
{
|
||||
GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
|
||||
}
|
||||
return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
|
||||
localP);
|
||||
}
|
||||
else
|
||||
{
|
||||
return VariableOrderRefinementMatrix(old_ndofs, *old_elem_dof);
|
||||
}
|
||||
|
||||
return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
|
||||
localP);
|
||||
}
|
||||
|
||||
FiniteElementSpace::RefinementOperator::RefinementOperator(
|
||||
@@ -1582,9 +1648,12 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
|
||||
|
||||
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
|
||||
|
||||
for (int i = 0; i < elem_geoms.Size(); i++)
|
||||
if (!fespace->IsVariableOrder())
|
||||
{
|
||||
fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
|
||||
for (int i = 0; i < elem_geoms.Size(); i++)
|
||||
{
|
||||
fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
ConstructDoFTransArray();
|
||||
@@ -1597,10 +1666,13 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
|
||||
{
|
||||
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
|
||||
|
||||
for (int i = 0; i < elem_geoms.Size(); i++)
|
||||
if (!fespace->IsVariableOrder())
|
||||
{
|
||||
fespace->GetLocalRefinementMatrices(*coarse_fes, elem_geoms[i],
|
||||
localP[elem_geoms[i]]);
|
||||
for (int i = 0; i < elem_geoms.Size(); i++)
|
||||
{
|
||||
fespace->GetLocalRefinementMatrices(*coarse_fes, elem_geoms[i],
|
||||
localP[elem_geoms[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
// Make a copy of the coarse elem_dof Table.
|
||||
@@ -1676,11 +1748,25 @@ void FiniteElementSpace::RefinementOperator::Mult(const Vector &x,
|
||||
|
||||
Vector subY, subX;
|
||||
|
||||
DenseMatrix eP;
|
||||
IsoparametricTransformation isotr;
|
||||
|
||||
for (int k = 0; k < mesh_ref->GetNE(); k++)
|
||||
{
|
||||
const Embedding &emb = trans_ref.embeddings[k];
|
||||
const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
|
||||
const DenseMatrix &lP = localP[geom](emb.matrix);
|
||||
if (fespace->IsVariableOrder())
|
||||
{
|
||||
const FiniteElement *fe = fespace->GetFE(k);
|
||||
isotr.SetIdentityTransformation(geom);
|
||||
const int ldof = fe->GetDof();
|
||||
eP.SetSize(ldof, ldof);
|
||||
const DenseTensor &pmats = trans_ref.point_matrices[geom];
|
||||
isotr.SetPointMat(pmats(emb.matrix));
|
||||
fe->GetLocalInterpolation(isotr, eP);
|
||||
}
|
||||
const DenseMatrix &lP = (fespace->IsVariableOrder()) ? eP : localP[geom](
|
||||
emb.matrix);
|
||||
|
||||
subY.SetSize(lP.Height());
|
||||
|
||||
@@ -1745,11 +1831,28 @@ void FiniteElementSpace::RefinementOperator::MultTranspose(const Vector &x,
|
||||
|
||||
Vector subY, subX, subYt;
|
||||
|
||||
DenseMatrix eP;
|
||||
IsoparametricTransformation isotr;
|
||||
const FiniteElement *fe = nullptr;
|
||||
|
||||
for (int k = 0; k < mesh_ref->GetNE(); k++)
|
||||
{
|
||||
const Embedding &emb = trans_ref.embeddings[k];
|
||||
const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
|
||||
const DenseMatrix &lP = localP[geom](emb.matrix);
|
||||
|
||||
if (fespace->IsVariableOrder())
|
||||
{
|
||||
fe = fespace->GetFE(k);
|
||||
isotr.SetIdentityTransformation(geom);
|
||||
const int ldof = fe->GetDof();
|
||||
eP.SetSize(ldof);
|
||||
const DenseTensor &pmats = trans_ref.point_matrices[geom];
|
||||
isotr.SetPointMat(pmats(emb.matrix));
|
||||
fe->GetLocalInterpolation(isotr, eP);
|
||||
}
|
||||
|
||||
const DenseMatrix &lP = (fespace->IsVariableOrder()) ? eP : localP[geom](
|
||||
emb.matrix);
|
||||
|
||||
DofTransformation *doftrans = fespace->GetElementDofs(k, f_dofs);
|
||||
old_elem_dof->GetRow(emb.parent, c_dofs);
|
||||
@@ -2108,9 +2211,12 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
|
||||
Mesh::GeometryList elem_geoms(*mesh);
|
||||
|
||||
DenseTensor localR[Geometry::NumGeom];
|
||||
for (int i = 0; i < elem_geoms.Size(); i++)
|
||||
if (!IsVariableOrder())
|
||||
{
|
||||
GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
|
||||
for (int i = 0; i < elem_geoms.Size(); i++)
|
||||
{
|
||||
GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
SparseMatrix *R = new SparseMatrix(ndofs*vdim, old_ndofs*vdim);
|
||||
@@ -2125,14 +2231,34 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
|
||||
|
||||
bool is_dg = FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS;
|
||||
int num_marked = 0;
|
||||
const FiniteElement *fe = nullptr;
|
||||
DenseMatrix localRVO; //for variable order only
|
||||
for (int k = 0; k < dtrans.embeddings.Size(); k++)
|
||||
{
|
||||
const Embedding &emb = dtrans.embeddings[k];
|
||||
Geometry::Type geom = mesh->GetElementBaseGeometry(emb.parent);
|
||||
DenseMatrix &lR = localR[geom](emb.matrix);
|
||||
|
||||
if (IsVariableOrder())
|
||||
{
|
||||
fe = GetFE(emb.parent);
|
||||
const DenseTensor &pmats = dtrans.point_matrices[geom];
|
||||
const int ldof = fe->GetDof();
|
||||
|
||||
IsoparametricTransformation isotr;
|
||||
isotr.SetIdentityTransformation(geom);
|
||||
|
||||
localRVO.SetSize(ldof, ldof);
|
||||
isotr.SetPointMat(pmats(emb.matrix));
|
||||
// Local restriction is size ldofxldof assuming that the parent and
|
||||
// child are of same polynomial order.
|
||||
fe->GetLocalRestriction(isotr, localRVO);
|
||||
}
|
||||
DenseMatrix &lR = IsVariableOrder() ? localRVO : localR[geom](emb.matrix);
|
||||
|
||||
elem_dof->GetRow(emb.parent, dofs);
|
||||
old_elem_dof->GetRow(k, old_dofs);
|
||||
MFEM_VERIFY(old_dofs.Size() == dofs.Size(),
|
||||
"Parent and child must have same #dofs.");
|
||||
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
{
|
||||
@@ -2158,7 +2284,7 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_dg)
|
||||
if (!is_dg && !IsVariableOrder())
|
||||
{
|
||||
MFEM_VERIFY(num_marked == R->Height(),
|
||||
"internal error: not all rows of R were set.");
|
||||
@@ -2216,6 +2342,7 @@ void FiniteElementSpace::Constructor(Mesh *mesh_, NURBSExtension *NURBSext_,
|
||||
|
||||
const NURBSFECollection *nurbs_fec =
|
||||
dynamic_cast<const NURBSFECollection *>(fec_);
|
||||
|
||||
if (nurbs_fec)
|
||||
{
|
||||
MFEM_VERIFY(mesh_->NURBSext, "NURBS FE space requires a NURBS mesh.");
|
||||
@@ -2312,12 +2439,63 @@ void FiniteElementSpace::UpdateNURBS()
|
||||
face_dof = NULL;
|
||||
face_to_be.DeleteAll();
|
||||
|
||||
// Depending on the element type create the appropriate extensions
|
||||
// for the individual components.
|
||||
dynamic_cast<const NURBSFECollection *>(fec)->Reset();
|
||||
|
||||
ndofs = NURBSext->GetNDof();
|
||||
elem_dof = NURBSext->GetElementDofTable();
|
||||
bdr_elem_dof = NURBSext->GetBdrElementDofTable();
|
||||
if (dynamic_cast<const NURBS_HDivFECollection *>(fec))
|
||||
{
|
||||
VNURBSext.SetSize(mesh->Dimension());
|
||||
for (int d = 0; d < mesh->Dimension(); d++)
|
||||
{
|
||||
VNURBSext[d] = NURBSext->GetDivExtension(d);
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamic_cast<const NURBS_HCurlFECollection *>(fec))
|
||||
{
|
||||
VNURBSext.SetSize(mesh->Dimension());
|
||||
for (int d = 0; d < mesh->Dimension(); d++)
|
||||
{
|
||||
VNURBSext[d] = NURBSext->GetCurlExtension(d);
|
||||
}
|
||||
}
|
||||
|
||||
// If required: concatenate the dof tables of the individual components into
|
||||
// one dof table for the vector fespace.
|
||||
if (VNURBSext.Size() == 2)
|
||||
{
|
||||
int offset1 = VNURBSext[0]->GetNDof();
|
||||
ndofs = VNURBSext[0]->GetNDof() + VNURBSext[1]->GetNDof();
|
||||
|
||||
// Merge Tables
|
||||
elem_dof = new Table(*VNURBSext[0]->GetElementDofTable(),
|
||||
*VNURBSext[1]->GetElementDofTable(),offset1 );
|
||||
|
||||
bdr_elem_dof = new Table(*VNURBSext[0]->GetBdrElementDofTable(),
|
||||
*VNURBSext[1]->GetBdrElementDofTable(),offset1);
|
||||
}
|
||||
else if (VNURBSext.Size() == 3)
|
||||
{
|
||||
int offset1 = VNURBSext[0]->GetNDof();
|
||||
int offset2 = offset1 + VNURBSext[1]->GetNDof();
|
||||
ndofs = offset2 + VNURBSext[2]->GetNDof();
|
||||
|
||||
// Merge Tables
|
||||
elem_dof = new Table(*VNURBSext[0]->GetElementDofTable(),
|
||||
*VNURBSext[1]->GetElementDofTable(),offset1,
|
||||
*VNURBSext[2]->GetElementDofTable(),offset2);
|
||||
|
||||
bdr_elem_dof = new Table(*VNURBSext[0]->GetBdrElementDofTable(),
|
||||
*VNURBSext[1]->GetBdrElementDofTable(),offset1,
|
||||
*VNURBSext[2]->GetBdrElementDofTable(),offset2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ndofs = NURBSext->GetNDof();
|
||||
elem_dof = NURBSext->GetElementDofTable();
|
||||
bdr_elem_dof = NURBSext->GetBdrElementDofTable();
|
||||
}
|
||||
mesh_sequence = mesh->GetSequence();
|
||||
sequence++;
|
||||
}
|
||||
@@ -3319,11 +3497,21 @@ void FiniteElementSpace::Destroy()
|
||||
dof_elem_array.DeleteAll();
|
||||
dof_ldof_array.DeleteAll();
|
||||
|
||||
for (int i = 0; i < VNURBSext.Size(); i++)
|
||||
{
|
||||
delete VNURBSext[i];
|
||||
}
|
||||
|
||||
if (NURBSext)
|
||||
{
|
||||
if (own_ext) { delete NURBSext; }
|
||||
delete face_dof;
|
||||
face_to_be.DeleteAll();
|
||||
if (VNURBSext.Size() > 0 )
|
||||
{
|
||||
delete elem_dof;
|
||||
delete bdr_elem_dof;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3335,6 +3523,8 @@ void FiniteElementSpace::Destroy()
|
||||
delete [] bdofs;
|
||||
}
|
||||
ceed::RemoveBasisAndRestriction(this);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void FiniteElementSpace::DestroyDoFTransArray()
|
||||
@@ -3353,19 +3543,27 @@ void FiniteElementSpace::GetTransferOperator(
|
||||
|
||||
if (T.Type() == Operator::MFEM_SPARSEMAT)
|
||||
{
|
||||
Mesh::GeometryList elem_geoms(*mesh);
|
||||
|
||||
DenseTensor localP[Geometry::NumGeom];
|
||||
for (int i = 0; i < elem_geoms.Size(); i++)
|
||||
if (!IsVariableOrder())
|
||||
{
|
||||
GetLocalRefinementMatrices(coarse_fes, elem_geoms[i],
|
||||
localP[elem_geoms[i]]);
|
||||
Mesh::GeometryList elem_geoms(*mesh);
|
||||
|
||||
DenseTensor localP[Geometry::NumGeom];
|
||||
for (int i = 0; i < elem_geoms.Size(); i++)
|
||||
{
|
||||
GetLocalRefinementMatrices(coarse_fes, elem_geoms[i],
|
||||
localP[elem_geoms[i]]);
|
||||
}
|
||||
T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
|
||||
coarse_fes.GetElementToDofTable(),
|
||||
coarse_fes.
|
||||
GetElementToFaceOrientationTable(),
|
||||
localP));
|
||||
}
|
||||
else
|
||||
{
|
||||
T.Reset(VariableOrderRefinementMatrix(coarse_fes.GetNDofs(),
|
||||
coarse_fes.GetElementToDofTable()));
|
||||
}
|
||||
T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
|
||||
coarse_fes.GetElementToDofTable(),
|
||||
coarse_fes.
|
||||
GetElementToFaceOrientationTable(),
|
||||
localP));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3416,19 +3614,33 @@ void FiniteElementSpace::GetTrueTransferOperator(
|
||||
|
||||
void FiniteElementSpace::UpdateElementOrders()
|
||||
{
|
||||
const CoarseFineTransformations &cf_tr = mesh->GetRefinementTransforms();
|
||||
|
||||
Array<char> new_order(mesh->GetNE());
|
||||
switch (mesh->GetLastOperation())
|
||||
{
|
||||
case Mesh::REFINE:
|
||||
{
|
||||
const CoarseFineTransformations &cf_tr = mesh->GetRefinementTransforms();
|
||||
for (int i = 0; i < mesh->GetNE(); i++)
|
||||
{
|
||||
new_order[i] = elem_order[cf_tr.embeddings[i].parent];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mesh::DEREFINE:
|
||||
{
|
||||
const CoarseFineTransformations &cf_tr =
|
||||
mesh->ncmesh->GetDerefinementTransforms();
|
||||
Table coarse_to_fine;
|
||||
cf_tr.MakeCoarseToFineTable(coarse_to_fine);
|
||||
Array<int> tabrow;
|
||||
for (int i = 0; i < coarse_to_fine.Size(); i++)
|
||||
{
|
||||
coarse_to_fine.GetRow(i, tabrow);
|
||||
//For now we require that all children are of same polynomial order.
|
||||
new_order[i] = elem_order[tabrow[0]];
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MFEM_ABORT("not implemented yet");
|
||||
}
|
||||
@@ -3523,11 +3735,23 @@ void FiniteElementSpace::Update(bool want_transform)
|
||||
{
|
||||
BuildConformingInterpolation();
|
||||
Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
|
||||
if (cP && cR)
|
||||
if (IsVariableOrder())
|
||||
{
|
||||
Th.SetOperatorOwner(false);
|
||||
Th.Reset(new TripleProductOperator(cP.get(), cR.get(), Th.Ptr(),
|
||||
false, false, true));
|
||||
if (cP && cR_hp)
|
||||
{
|
||||
Th.SetOperatorOwner(false);
|
||||
Th.Reset(new TripleProductOperator(cP.get(), cR_hp.get(), Th.Ptr(),
|
||||
false, false, true));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cP && cR)
|
||||
{
|
||||
Th.SetOperatorOwner(false);
|
||||
Th.Reset(new TripleProductOperator(cP.get(), cR.get(), Th.Ptr(),
|
||||
false, false, true));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3640,6 +3864,7 @@ FiniteElementCollection *FiniteElementSpace::Load(Mesh *m, std::istream &input)
|
||||
input >> ord;
|
||||
|
||||
NURBSFECollection *nurbs_fec = dynamic_cast<NURBSFECollection*>(r_fec);
|
||||
if (nurbs_fec) { nurbs_fec->SetDim(m->Dimension()); }
|
||||
NURBSExtension *nurbs_ext = NULL;
|
||||
if (fes_format == 90) // original format, v0.9
|
||||
{
|
||||
|
||||
+15
-1
@@ -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();
|
||||
@@ -644,7 +655,10 @@ public:
|
||||
const ElementRestrictionOperator *GetElementRestriction(
|
||||
ElementDofOrdering e_ordering) const;
|
||||
|
||||
/// Return an Operator that converts L-vectors to E-vectors on each face.
|
||||
/** @brief Return an Operator that converts L-vectors to E-vectors on each
|
||||
face. */
|
||||
/** @warning only meshes with tensor-product elements are currently
|
||||
supported. */
|
||||
virtual const FaceRestriction *GetFaceRestriction(
|
||||
ElementDofOrdering f_ordering, FaceType,
|
||||
L2FaceValues mul = L2FaceValues::DoubleValued) const;
|
||||
|
||||
+96
-33
@@ -12,6 +12,8 @@
|
||||
// Implementation of GridFunction
|
||||
|
||||
#include "gridfunc.hpp"
|
||||
#include "linearform.hpp"
|
||||
#include "bilinearform.hpp"
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "../mesh/nurbs.hpp"
|
||||
#include "../general/text.hpp"
|
||||
@@ -39,7 +41,7 @@ GridFunction::GridFunction(Mesh *m, std::istream &input)
|
||||
UseDevice(true);
|
||||
|
||||
fes = new FiniteElementSpace;
|
||||
fec = fes->Load(m, input);
|
||||
fec_owned = fes->Load(m, input);
|
||||
|
||||
skip_comment_lines(input, '#');
|
||||
istream::int_type next_char = input.peek();
|
||||
@@ -81,10 +83,10 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
|
||||
int vdim, ordering;
|
||||
|
||||
fes = gf_array[0]->FESpace();
|
||||
fec = FiniteElementCollection::New(fes->FEColl()->Name());
|
||||
fec_owned = FiniteElementCollection::New(fes->FEColl()->Name());
|
||||
vdim = fes->GetVDim();
|
||||
ordering = fes->GetOrdering();
|
||||
fes = new FiniteElementSpace(m, fec, vdim, ordering);
|
||||
fes = new FiniteElementSpace(m, fec_owned, vdim, ordering);
|
||||
SetSize(fes->GetVSize());
|
||||
|
||||
if (m->NURBSext)
|
||||
@@ -153,11 +155,11 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
|
||||
|
||||
void GridFunction::Destroy()
|
||||
{
|
||||
if (fec)
|
||||
if (fec_owned)
|
||||
{
|
||||
delete fes;
|
||||
delete fec;
|
||||
fec = NULL;
|
||||
delete fec_owned;
|
||||
fec_owned = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,10 +327,9 @@ int GridFunction::VectorDim() const
|
||||
const FiniteElement *fe;
|
||||
if (!fes->GetNE())
|
||||
{
|
||||
const FiniteElementCollection *fe_coll = fes->FEColl();
|
||||
static const Geometry::Type geoms[3] =
|
||||
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
|
||||
fe = fe_coll->
|
||||
fe = fes->FEColl()->
|
||||
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
}
|
||||
else
|
||||
@@ -350,7 +351,8 @@ int GridFunction::CurlDim() const
|
||||
{
|
||||
static const Geometry::Type geoms[3] =
|
||||
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
|
||||
fe = fec->FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
fe = fes->FEColl()->
|
||||
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2372,19 +2374,48 @@ void GridFunction::ProjectCoefficient(Coefficient &coeff)
|
||||
|
||||
if (delta_c == NULL)
|
||||
{
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
if (fes->GetNURBSext() == NULL)
|
||||
{
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
|
||||
if (doftrans)
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
doftrans->TransformPrimal(vals);
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformPrimal(vals);
|
||||
}
|
||||
SetSubVector(vdofs, vals);
|
||||
}
|
||||
SetSubVector(vdofs, vals);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Define and assemble linear form
|
||||
LinearForm b(fes);
|
||||
b.AddDomainIntegrator(new DomainLFIntegrator(coeff));
|
||||
b.Assemble();
|
||||
|
||||
// Define and assemble bilinear form
|
||||
BilinearForm a(fes);
|
||||
a.AddDomainIntegrator(new MassIntegrator());
|
||||
a.Assemble();
|
||||
|
||||
// Set solver and preconditioner
|
||||
SparseMatrix A(a.SpMat());
|
||||
GSSmoother prec(A);
|
||||
CGSolver cg;
|
||||
cg.SetOperator(A);
|
||||
cg.SetPreconditioner(prec);
|
||||
cg.SetRelTol(1e-12);
|
||||
cg.SetMaxIter(1000);
|
||||
cg.SetPrintLevel(0);
|
||||
|
||||
// Solve and get solution
|
||||
*this = 0.0;
|
||||
cg.Mult(b,*this);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2425,22 +2456,54 @@ void GridFunction::ProjectCoefficient(
|
||||
|
||||
void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff)
|
||||
{
|
||||
int i;
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
|
||||
DofTransformation * doftrans = NULL;
|
||||
|
||||
for (i = 0; i < fes->GetNE(); i++)
|
||||
if (fes->GetNURBSext() == NULL)
|
||||
{
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
|
||||
if (doftrans)
|
||||
|
||||
int i;
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
|
||||
DofTransformation * doftrans = NULL;
|
||||
|
||||
for (i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
doftrans->TransformPrimal(vals);
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformPrimal(vals);
|
||||
}
|
||||
SetSubVector(vdofs, vals);
|
||||
}
|
||||
SetSubVector(vdofs, vals);
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Define and assemble linear form
|
||||
LinearForm b(fes);
|
||||
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(vcoeff));
|
||||
b.Assemble();
|
||||
|
||||
// Define and assemble bilinear form
|
||||
BilinearForm a(fes);
|
||||
a.AddDomainIntegrator(new VectorFEMassIntegrator());
|
||||
a.Assemble();
|
||||
|
||||
// Set solver and preconditioner
|
||||
SparseMatrix A(a.SpMat());
|
||||
GSSmoother prec(A);
|
||||
CGSolver cg;
|
||||
cg.SetOperator(A);
|
||||
cg.SetPreconditioner(prec);
|
||||
cg.SetRelTol(1e-12);
|
||||
cg.SetMaxIter(1000);
|
||||
cg.SetPrintLevel(0);
|
||||
|
||||
// Solve and get solution
|
||||
*this = 0.0;
|
||||
cg.Mult(b,*this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3926,7 +3989,7 @@ void GridFunction::LegacyNCReorder()
|
||||
mesh->GetEdgeVertices(i, ev);
|
||||
if (old_vertex[ev[0]] > old_vertex[ev[1]])
|
||||
{
|
||||
const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, -1);
|
||||
const int *ind = fes->FEColl()->DofOrderForOrientation(Geometry::SEGMENT, -1);
|
||||
|
||||
fes->GetEdgeInteriorDofs(i, dofs);
|
||||
for (int k = 0; k < dofs.Size(); k++)
|
||||
|
||||
+15
-13
@@ -30,14 +30,14 @@ namespace mfem
|
||||
class GridFunction : public Vector
|
||||
{
|
||||
protected:
|
||||
/// FE space on which the grid function lives. Owned if #fec is not NULL.
|
||||
/// FE space on which the grid function lives. Owned if #fec_owned is not NULL.
|
||||
FiniteElementSpace *fes;
|
||||
|
||||
/** @brief Used when the grid function is read from a file. It can also be
|
||||
set explicitly, see MakeOwner().
|
||||
|
||||
If not NULL, this pointer is owned by the GridFunction. */
|
||||
FiniteElementCollection *fec;
|
||||
FiniteElementCollection *fec_owned;
|
||||
|
||||
long fes_sequence; // see FiniteElementSpace::sequence, Mesh::sequence
|
||||
|
||||
@@ -72,16 +72,16 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
GridFunction() { fes = NULL; fec = NULL; fes_sequence = 0; UseDevice(true); }
|
||||
GridFunction() { fes = NULL; fec_owned = NULL; fes_sequence = 0; UseDevice(true); }
|
||||
|
||||
/// Copy constructor. The internal true-dof vector #t_vec is not copied.
|
||||
GridFunction(const GridFunction &orig)
|
||||
: Vector(orig), fes(orig.fes), fec(NULL), fes_sequence(orig.fes_sequence)
|
||||
: Vector(orig), fes(orig.fes), fec_owned(NULL), fes_sequence(orig.fes_sequence)
|
||||
{ UseDevice(true); }
|
||||
|
||||
/// Construct a GridFunction associated with the FiniteElementSpace @a *f.
|
||||
GridFunction(FiniteElementSpace *f) : Vector(f->GetVSize())
|
||||
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
|
||||
/// Construct a GridFunction using previously allocated array @a data.
|
||||
/** The GridFunction does not assume ownership of @a data which is assumed to
|
||||
@@ -91,13 +91,13 @@ public:
|
||||
*/
|
||||
GridFunction(FiniteElementSpace *f, real_t *data)
|
||||
: Vector(data, f->GetVSize())
|
||||
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
|
||||
/** @brief Construct a GridFunction using previously allocated Vector @a base
|
||||
starting at the given offset, @a base_offset. */
|
||||
GridFunction(FiniteElementSpace *f, Vector &base, int base_offset = 0)
|
||||
: Vector(base, base_offset, f->GetVSize())
|
||||
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
|
||||
/// Construct a GridFunction on the given Mesh, using the data from @a input.
|
||||
/** The content of @a input should be in the format created by the method
|
||||
@@ -116,12 +116,12 @@ public:
|
||||
GridFunction &operator=(const GridFunction &rhs)
|
||||
{ return operator=((const Vector &)rhs); }
|
||||
|
||||
/// Make the GridFunction the owner of #fec and #fes.
|
||||
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec
|
||||
/// Make the GridFunction the owner of #fec_owned and #fes.
|
||||
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec_owned
|
||||
and #fes is taken away. */
|
||||
void MakeOwner(FiniteElementCollection *fec_) { fec = fec_; }
|
||||
void MakeOwner(FiniteElementCollection *fec_) { fec_owned = fec_; }
|
||||
|
||||
FiniteElementCollection *OwnFEC() { return fec; }
|
||||
FiniteElementCollection *OwnFEC() { return fec_owned; }
|
||||
|
||||
int VectorDim() const;
|
||||
int CurlDim() const;
|
||||
@@ -387,7 +387,8 @@ public:
|
||||
/** @brief Project @a coeff Coefficient to @a this GridFunction. The
|
||||
projection computation depends on the choice of the FiniteElementSpace
|
||||
#fes. Note that this is usually interpolation at the degrees of freedom
|
||||
in each element (not L2 projection). */
|
||||
in each element (not L2 projection). For NURBS spaces these degrees of
|
||||
freedom are not available and L2 projection is resorted to as fallback. */
|
||||
virtual void ProjectCoefficient(Coefficient &coeff);
|
||||
|
||||
/** @brief Project @a coeff Coefficient to @a this GridFunction, using one
|
||||
@@ -398,7 +399,8 @@ public:
|
||||
/** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction. The
|
||||
projection computation depends on the choice of the FiniteElementSpace
|
||||
#fes. Note that this is usually interpolation at the degrees of freedom
|
||||
in each element (not L2 projection).*/
|
||||
in each element (not L2 projection). For NURBS spaces these degrees of
|
||||
freedom are not available and L2 projection is resorted to as fallback. */
|
||||
void ProjectCoefficient(VectorCoefficient &vcoeff);
|
||||
|
||||
/** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction, using
|
||||
|
||||
+114
@@ -1168,6 +1168,120 @@ void FindPointsGSLIB::InterpolateGeneral(const GridFunction &field_in,
|
||||
} // parallel
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::DistributePointInfoToOwningMPIRanks(
|
||||
Array<unsigned int> &recv_elem, Vector &recv_ref,
|
||||
Array<unsigned int> &recv_code)
|
||||
{
|
||||
MFEM_VERIFY(points_cnt,
|
||||
"Invalid size. Please make sure to call FindPoints method "
|
||||
"before calling this function.");
|
||||
|
||||
// Pack data to send via crystal router
|
||||
struct gslib::array *outpt = new gslib::array;
|
||||
|
||||
struct out_pt { double rst[3]; uint index, elem, proc, code; };
|
||||
struct out_pt *pt;
|
||||
array_init(struct out_pt, outpt, points_cnt);
|
||||
outpt->n=points_cnt;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
|
||||
for (int index = 0; index < points_cnt; index++)
|
||||
{
|
||||
pt->index = index;
|
||||
pt->elem = gsl_mfem_elem[index];
|
||||
pt->proc = gsl_proc[index];
|
||||
pt->code = gsl_code[index];
|
||||
for (int d = 0; d < dim; ++d)
|
||||
{
|
||||
pt->rst[d]= gsl_mfem_ref(index*dim + d);
|
||||
}
|
||||
++pt;
|
||||
}
|
||||
|
||||
// Transfer data to target MPI ranks
|
||||
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
|
||||
|
||||
// Store received data
|
||||
const int points_recv = outpt->n;
|
||||
recv_proc.SetSize(points_recv);
|
||||
recv_elem.SetSize(points_recv);
|
||||
recv_index.SetSize(points_recv);
|
||||
recv_code.SetSize(points_recv);
|
||||
recv_ref.SetSize(points_recv*dim);
|
||||
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < points_recv; index++)
|
||||
{
|
||||
recv_index[index] = pt->index;
|
||||
recv_elem[index] = pt->elem;
|
||||
recv_proc[index] = pt->proc;
|
||||
recv_code[index] = pt->code;
|
||||
for (int d = 0; d < dim; ++d)
|
||||
{
|
||||
recv_ref(index*dim + d)= pt->rst[d];
|
||||
}
|
||||
++pt;
|
||||
}
|
||||
|
||||
array_free(outpt);
|
||||
delete outpt;
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::DistributeInterpolatedValues(const Vector &int_vals,
|
||||
const int vdim,
|
||||
const int ordering,
|
||||
Vector &field_out) const
|
||||
{
|
||||
const int points_recv = recv_index.Size();;
|
||||
MFEM_VERIFY(points_recv == 0 ||
|
||||
int_vals.Size() % points_recv == 0,
|
||||
"Incompatible size. Please return interpolated values"
|
||||
"corresponding to points received using"
|
||||
"SendCoordinatesToOwningProcessors.");
|
||||
field_out.SetSize(points_cnt*vdim);
|
||||
|
||||
for (int v = 0; v < vdim; v++)
|
||||
{
|
||||
// Pack data to send via crystal router
|
||||
struct gslib::array *outpt = new gslib::array;
|
||||
struct out_pt { double val; uint index, proc; };
|
||||
struct out_pt *pt;
|
||||
array_init(struct out_pt, outpt, points_recv);
|
||||
outpt->n=points_recv;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < points_recv; index++)
|
||||
{
|
||||
pt->index = recv_index[index];
|
||||
pt->proc = recv_proc[index];
|
||||
pt->val = ordering == Ordering::byNODES ?
|
||||
int_vals(index + v*points_recv) :
|
||||
int_vals(index*vdim + v);
|
||||
++pt;
|
||||
}
|
||||
|
||||
// Transfer data to target MPI ranks
|
||||
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
|
||||
|
||||
// Store received data
|
||||
MFEM_VERIFY(outpt->n == points_cnt, "Incompatible size. Number of points "
|
||||
"received does not match the number of points originally "
|
||||
"found using FindPoints.");
|
||||
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < points_cnt; index++)
|
||||
{
|
||||
int idx = ordering == Ordering::byNODES ?
|
||||
pt->index + v*points_cnt :
|
||||
pt->index*vdim + v;
|
||||
field_out(idx) = pt->val;
|
||||
++pt;
|
||||
}
|
||||
|
||||
array_free(outpt);
|
||||
delete outpt;
|
||||
}
|
||||
}
|
||||
|
||||
void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
|
||||
GridFunction *gfmax,
|
||||
const double bb_t, const double newt_tol,
|
||||
|
||||
+66
-19
@@ -34,7 +34,7 @@ namespace mfem
|
||||
*
|
||||
* There are three key functions in FindPointsGSLIB:
|
||||
*
|
||||
* 1. Setup - constructs the internal data structures of gslib.
|
||||
* 1. Setup - constructs the internal data structures of gslib. See \ref Setup.
|
||||
*
|
||||
* 2. FindPoints - for any given arbitrary set of points in physical space,
|
||||
* gslib finds the element number, MPI rank, and the reference space
|
||||
@@ -45,12 +45,23 @@ namespace mfem
|
||||
* on an element edge/face or near the domain boundary, and gslib also
|
||||
* returns a distance to the border. Points near (but outside) the domain
|
||||
* boundary must then be marked as not found using the distance returned
|
||||
* by gslib.
|
||||
* by gslib. See \ref FindPoints.
|
||||
*
|
||||
* 3. Interpolate - Interpolates any grid function at the points found using 2.
|
||||
* For functions in L2 finite element space, use \ref SetL2AvgType to
|
||||
* specify how to interpolate values at points located at element boundaries
|
||||
* where the function might be multi-valued. See \ref Interpolate.
|
||||
*
|
||||
* FindPointsGSLIB provides interface to use these functions individually or
|
||||
* using a single call.
|
||||
* FindPointsGSLIB also provides interface to use these functions through a
|
||||
* single call.
|
||||
*
|
||||
* For custom interpolation (e.g., evaluating strain rate tensor), we provide
|
||||
* functions that use gslib to send element index and corresponding
|
||||
* reference-space coordinates for each point to the mpi rank that the element
|
||||
* is located on. Then, custom interpolation can be defined locally by the user
|
||||
* before sending the values back to mpi ranks where the query originated from.
|
||||
* See \ref DistributePointInfoToOwningMPIRanks and
|
||||
* \ref DistributeInterpolatedValues.
|
||||
*/
|
||||
class FindPointsGSLIB
|
||||
{
|
||||
@@ -74,7 +85,8 @@ protected:
|
||||
int dim, points_cnt;
|
||||
Array<unsigned int> gsl_code, gsl_proc, gsl_elem, gsl_mfem_elem;
|
||||
Vector gsl_mesh, gsl_ref, gsl_dist, gsl_mfem_ref;
|
||||
bool setupflag; // flag to indicate whether gslib data has been setup
|
||||
Array<unsigned int> recv_proc, recv_index; // data for custom interpolation
|
||||
bool setupflag; // flag to indicate if gslib data has been setup
|
||||
double default_interp_value; // used for points that are not found in the mesh
|
||||
AvgType avgtype; // average type used for L2 functions
|
||||
Array<int> split_element_map;
|
||||
@@ -118,9 +130,9 @@ public:
|
||||
virtual ~FindPointsGSLIB();
|
||||
|
||||
/** Initializes the internal mesh in gslib, by sending the positions of the
|
||||
Gauss-Lobatto nodes of the input Mesh object @a m.
|
||||
Gauss-Lobatto nodes of the input Mesh object \p m.
|
||||
Note: not tested with periodic (L2).
|
||||
Note: the input mesh @a m must have Nodes set.
|
||||
Note: the input mesh \p m must have Nodes set.
|
||||
|
||||
@param[in] m Input mesh.
|
||||
@param[in] bb_t (Optional) Relative size of bounding box around
|
||||
@@ -133,9 +145,9 @@ public:
|
||||
void Setup(Mesh &m, const double bb_t = 0.1,
|
||||
const double newt_tol = 1.0e-12,
|
||||
const int npt_max = 256);
|
||||
/** Searches positions given in physical space by @a point_pos.
|
||||
/** Searches positions given in physical space by \p point_pos.
|
||||
These positions can be ordered byNodes: (XXX...,YYY...,ZZZ) or
|
||||
byVDim: (XYZ,XYZ,....XYZ) specified by @a point_pos_ordering.
|
||||
byVDim: (XYZ,XYZ,....XYZ) specified by \p point_pos_ordering.
|
||||
This function populates the following member variables:
|
||||
#gsl_code Return codes for each point: inside element (0),
|
||||
element boundary (1), not found (2).
|
||||
@@ -164,20 +176,20 @@ public:
|
||||
/** Interpolation of field values at prescribed reference space positions.
|
||||
@param[in] field_in Function values that will be interpolated on the
|
||||
reference positions. Note: it is assumed that
|
||||
@a field_in is in H1 and in the same space as the
|
||||
\p field_in is in H1 and in the same space as the
|
||||
mesh that was given to Setup().
|
||||
@param[out] field_out Interpolated values. For points that are not found
|
||||
the value is set to #default_interp_value. */
|
||||
virtual void Interpolate(const GridFunction &field_in, Vector &field_out);
|
||||
/** Search positions and interpolate. The ordering (byNODES or byVDIM) of
|
||||
the output values in @a field_out corresponds to the ordering used
|
||||
in the input GridFunction @a field_in. */
|
||||
the output values in \p field_out corresponds to the ordering used
|
||||
in the input GridFunction \p field_in. */
|
||||
void Interpolate(const Vector &point_pos, const GridFunction &field_in,
|
||||
Vector &field_out,
|
||||
int point_pos_ordering = Ordering::byNODES);
|
||||
/** Setup FindPoints, search positions and interpolate. The ordering (byNODES
|
||||
or byVDIM) of the output values in @a field_out corresponds to the
|
||||
ordering used in the input GridFunction @a field_in. */
|
||||
or byVDIM) of the output values in \p field_out corresponds to the
|
||||
ordering used in the input GridFunction \p field_in. */
|
||||
void Interpolate(Mesh &m, const Vector &point_pos,
|
||||
const GridFunction &field_in, Vector &field_out,
|
||||
int point_pos_ordering = Ordering::byNODES);
|
||||
@@ -225,6 +237,41 @@ public:
|
||||
/// Return reference coordinates in [-1,1] (internal range in GSLIB) for each
|
||||
/// point found by FindPoints.
|
||||
virtual const Vector &GetGSLIBReferencePosition() const { return gsl_ref; }
|
||||
|
||||
/** @name Methods to support a custom interpolation procedure.
|
||||
\brief The physical-space point that the user seeks to interpolate at
|
||||
could be located inside an element on another mpi rank.
|
||||
To enable a custom interpolation procedure (e.g., strain tensor computation)
|
||||
we need a mechanism to first send element indices and reference-space
|
||||
coordinates to the mpi-ranks where each point is found. Then the custom
|
||||
interpolation can be done locally by the user before sending the
|
||||
interpolated values back to the mpi-ranks that the query originated from.
|
||||
Example usage looks something like this:
|
||||
|
||||
FindPoints() -> DistributePointInfoToOwningMPIRanks() -> Computation by
|
||||
user -> DistributeInterpolatedValues().
|
||||
*/
|
||||
///@{
|
||||
/// Distribute element indices in #gsl_mfem_elem, the reference coordinates
|
||||
/// #gsl_mfem_ref, and the code #gsl_code to the corresponding mpi-rank
|
||||
/// #gsl_proc for each point. The received information is provided locally
|
||||
/// in \p recv_elem, \p recv_ref (ordered by vdim), and \p recv_code.
|
||||
/// Note: The user can send empty Array/Vectors to the method as they are
|
||||
/// appropriately sized and filled internally.
|
||||
virtual void DistributePointInfoToOwningMPIRanks(
|
||||
Array<unsigned int> &recv_elem, Vector &recv_ref,
|
||||
Array<unsigned int> &recv_code);
|
||||
/// Return interpolated values back to the mpi-ranks #recv_proc that had
|
||||
/// sent the element indices and corresponding reference-space coordinates.
|
||||
/// Specify \p vdim and \p ordering (by nodes or by vdim) based on how the
|
||||
/// \p int_vals are structured. The received values are filled in
|
||||
/// \p field_out consistent with the original ordering of the points that
|
||||
/// were used in \ref FindPoints.
|
||||
virtual void DistributeInterpolatedValues(const Vector &int_vals,
|
||||
const int vdim,
|
||||
const int ordering,
|
||||
Vector &field_out) const;
|
||||
///@}
|
||||
};
|
||||
|
||||
/** \brief OversetFindPointsGSLIB enables use of findpts for arbitrary number of
|
||||
@@ -249,9 +296,9 @@ public:
|
||||
#endif
|
||||
|
||||
/** Initializes the internal mesh in gslib, by sending the positions of the
|
||||
Gauss-Lobatto nodes of the input Mesh object @a m.
|
||||
Gauss-Lobatto nodes of the input Mesh object \p m.
|
||||
Note: not tested with periodic meshes (L2).
|
||||
Note: the input mesh @a m must have Nodes set.
|
||||
Note: the input mesh \p m must have Nodes set.
|
||||
|
||||
@param[in] m Input mesh.
|
||||
@param[in] meshid A unique # for each overlapping mesh. This id is
|
||||
@@ -274,12 +321,12 @@ public:
|
||||
const double bb_t = 0.1, const double newt_tol = 1.0e-12,
|
||||
const int npt_max = 256);
|
||||
|
||||
/** Searches positions given in physical space by @a point_pos. All output
|
||||
/** Searches positions given in physical space by \p point_pos. All output
|
||||
Arrays and Vectors are expected to have the correct size.
|
||||
|
||||
@param[in] point_pos Positions to be found.
|
||||
@param[in] point_id Index of the mesh that the point belongs
|
||||
to (corresponding to @a meshid in Setup).
|
||||
to (corresponding to \p meshid in Setup).
|
||||
@param[in] point_pos_ordering Ordering of the points:
|
||||
byNodes: (XXX...,YYY...,ZZZ) or
|
||||
byVDim: (XYZ,XYZ,....XYZ) */
|
||||
@@ -342,7 +389,7 @@ public:
|
||||
enum GSOp {ADD, MUL, MIN, MAX};
|
||||
|
||||
/// Update the identifiers used for the gather-scatter operator.
|
||||
/// Same @a ids get grouped together and id == 0 does not participate.
|
||||
/// Same \p ids get grouped together and id == 0 does not participate.
|
||||
/// See class description.
|
||||
void UpdateIdentifiers(const Array<long long> &ids);
|
||||
|
||||
|
||||
+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.
|
||||
|
||||
+4
-3
@@ -39,9 +39,10 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, const GridFunction *gf,
|
||||
{
|
||||
const FiniteElementSpace *glob_fes = gf->FESpace();
|
||||
// duplicate the FiniteElementCollection from 'gf'
|
||||
fec = FiniteElementCollection::New(glob_fes->FEColl()->Name());
|
||||
fec_owned = FiniteElementCollection::New(glob_fes->FEColl()->Name());
|
||||
// create a local ParFiniteElementSpace from the global one:
|
||||
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning, fec);
|
||||
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning,
|
||||
fec_owned);
|
||||
SetSize(pfes->GetVSize());
|
||||
|
||||
if (partitioning)
|
||||
@@ -81,7 +82,7 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, std::istream &input)
|
||||
: GridFunction(pmesh, input)
|
||||
{
|
||||
// Convert the FiniteElementSpace, fes, to a ParFiniteElementSpace:
|
||||
pfes = new ParFiniteElementSpace(pmesh, fec, fes->GetVDim(),
|
||||
pfes = new ParFiniteElementSpace(pmesh, fec_owned, fes->GetVDim(),
|
||||
fes->GetOrdering());
|
||||
delete fes;
|
||||
fes = pfes;
|
||||
|
||||
+9
-7
@@ -751,11 +751,11 @@ void ConformingFaceRestriction::CheckFESpace(const ElementDofOrdering
|
||||
#ifdef MFEM_DEBUG
|
||||
const FiniteElement *fe0 = fes.GetFE(0);
|
||||
const TensorBasisElement *tfe = dynamic_cast<const TensorBasisElement*>(fe0);
|
||||
MFEM_VERIFY(tfe != NULL &&
|
||||
(tfe->GetBasisType()==BasisType::GaussLobatto ||
|
||||
tfe->GetBasisType()==BasisType::Positive),
|
||||
"Only Gauss-Lobatto and Bernstein basis are supported in "
|
||||
"ConformingFaceRestriction.");
|
||||
MFEM_VERIFY(tfe != NULL,
|
||||
"ConformingFaceRestriction only supports TensorBasisElements");
|
||||
MFEM_VERIFY(tfe->GetBasisType()==BasisType::GaussLobatto ||
|
||||
tfe->GetBasisType()==BasisType::Positive,
|
||||
"ConformingFaceRestriction only supports Gauss-Lobatto and Bernstein bases");
|
||||
|
||||
// Assuming all finite elements are using Gauss-Lobatto.
|
||||
const bool dof_reorder = (f_ordering == ElementDofOrdering::LEXICOGRAPHIC);
|
||||
@@ -855,7 +855,8 @@ void ConformingFaceRestriction::SetFaceDofsScatterIndices(
|
||||
"This method should not be used on nonconforming coarse faces.");
|
||||
MFEM_ASSERT(face.element[0].orientation==0,
|
||||
"FaceRestriction used on degenerated mesh.");
|
||||
MFEM_CONTRACT_VAR(f_ordering); // not supported yet
|
||||
MFEM_VERIFY(f_ordering == ElementDofOrdering::LEXICOGRAPHIC,
|
||||
"NATIVE ordering is not supported yet");
|
||||
|
||||
fes.GetFE(0)->GetFaceMap(face.element[0].local_face_id, face_map);
|
||||
|
||||
@@ -883,7 +884,8 @@ void ConformingFaceRestriction::SetFaceDofsGatherIndices(
|
||||
{
|
||||
MFEM_ASSERT(!(face.IsNonconformingCoarse()),
|
||||
"This method should not be used on nonconforming coarse faces.");
|
||||
MFEM_CONTRACT_VAR(f_ordering); // not supported yet
|
||||
MFEM_VERIFY(f_ordering == ElementDofOrdering::LEXICOGRAPHIC,
|
||||
"NATIVE ordering is not supported yet");
|
||||
|
||||
fes.GetFE(0)->GetFaceMap(face.element[0].local_face_id, face_map);
|
||||
|
||||
|
||||
+4
-4
@@ -3390,11 +3390,12 @@ real_t TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
|
||||
const IntegrationPoint &ip_s = ir_s->IntPoint(s);
|
||||
Tpr->SetIntPoint(&ip_s);
|
||||
double w = surf_fit_coeff->Eval(*Tpr, ip_s) * surf_fit_normal *
|
||||
1.0 / surf_fit_dof_count[scalar_dof_id];
|
||||
|
||||
if (surf_fit_gf)
|
||||
{
|
||||
energy += surf_fit_coeff->Eval(*Tpr, ip_s) * surf_fit_normal *
|
||||
sigma_e(s) * sigma_e(s);
|
||||
energy += w * sigma_e(s) * sigma_e(s);
|
||||
}
|
||||
if (surf_fit_pos)
|
||||
{
|
||||
@@ -3405,8 +3406,7 @@ real_t TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
pos(d) = PMatI(s, d);
|
||||
pos_target(d) = (*surf_fit_pos)(vdofs[d*dof + s]);
|
||||
}
|
||||
energy += surf_fit_coeff->Eval(*Tpr, ip_s) * surf_fit_normal *
|
||||
surf_fit_limiter->Eval(pos, pos_target, 1.0);
|
||||
energy += w * surf_fit_limiter->Eval(pos, pos_target, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,6 +217,21 @@ public:
|
||||
virtual WorstCaseType GetWorstCaseType() { return wctype; }
|
||||
};
|
||||
|
||||
/// 0 metric
|
||||
class TMOP_Metric_000 : public TMOP_QualityMetric
|
||||
{
|
||||
public:
|
||||
// W = 0.
|
||||
virtual real_t EvalW(const DenseMatrix &Jpt) const {return 0.0;}
|
||||
|
||||
virtual void EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const {P = 0.0;}
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const {A = 0.0;}
|
||||
|
||||
virtual int Id() const { return 0; }
|
||||
};
|
||||
|
||||
/// 2D non-barrier metric without a type.
|
||||
class TMOP_Metric_001 : public TMOP_QualityMetric
|
||||
{
|
||||
|
||||
@@ -1233,6 +1233,8 @@ void PRefinementTransferOperator::Mult(const Vector& x, Vector& y) const
|
||||
|
||||
int vdim = lFESpace.GetVDim();
|
||||
|
||||
y = 0.0;
|
||||
|
||||
for (int i = 0; i < mesh->GetNE(); i++)
|
||||
{
|
||||
DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
|
||||
|
||||
@@ -63,9 +63,9 @@
|
||||
#define MFEM_FOREACH_THREAD(i,k,N) for(int i=0; i<N; i++)
|
||||
#endif
|
||||
|
||||
// 'double' atomicAdd implementation for previous versions of CUDA
|
||||
// 'double' and 'float' atomicAdd implementation for previous versions of CUDA
|
||||
#if defined(MFEM_USE_CUDA) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600
|
||||
MFEM_DEVICE inline real_t atomicAdd(real_t *add, real_t val)
|
||||
MFEM_DEVICE inline mfem::real_t atomicAdd(mfem::real_t *add, mfem::real_t val)
|
||||
{
|
||||
unsigned long long int *ptr = (unsigned long long int *) add;
|
||||
unsigned long long int old = *ptr, reg;
|
||||
|
||||
@@ -51,7 +51,7 @@ int isockstream::establish()
|
||||
{
|
||||
// char myname[129];
|
||||
char myname[] = "localhost";
|
||||
int sfd;
|
||||
int sfd = -1;
|
||||
struct addrinfo hints, *res, *rp;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
|
||||
@@ -37,6 +37,78 @@ Table::Table(const Table &table)
|
||||
}
|
||||
}
|
||||
|
||||
Table::Table(const Table &table1,
|
||||
const Table &table2, int offset)
|
||||
{
|
||||
MFEM_ASSERT(table1.size == table2.size,
|
||||
"Tables have different sizes can not merge.");
|
||||
size = table1.size;
|
||||
|
||||
const int nnz = table1.I[size] + table2.I[size];
|
||||
I.New(size+1, table1.I.GetMemoryType());
|
||||
J.New(nnz, table1.J.GetMemoryType());
|
||||
|
||||
I[0] = 0;
|
||||
Array<int> row;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
I[i+1] = I[i];
|
||||
|
||||
table1.GetRow(i, row);
|
||||
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
|
||||
{
|
||||
J[ I[i+1] ] = row[r];
|
||||
}
|
||||
|
||||
table2.GetRow(i, row);
|
||||
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
|
||||
{
|
||||
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset : row[r] + offset;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Table::Table(const Table &table1,
|
||||
const Table &table2, int offset2,
|
||||
const Table &table3, int offset3)
|
||||
{
|
||||
MFEM_ASSERT(table1.size == table2.size,
|
||||
"Tables have different sizes can not merge.");
|
||||
MFEM_ASSERT(table1.size == table3.size,
|
||||
"Tables have different sizes can not merge.");
|
||||
size = table1.size;
|
||||
|
||||
const int nnz = table1.I[size] + table2.I[size] + table3.I[size];
|
||||
I.New(size+1, table1.I.GetMemoryType());
|
||||
J.New(nnz, table1.J.GetMemoryType());
|
||||
|
||||
I[0] = 0;
|
||||
Array<int> row;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
I[i+1] = I[i];
|
||||
|
||||
table1.GetRow(i, row);
|
||||
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
|
||||
{
|
||||
J[ I[i+1] ] = row[r];
|
||||
}
|
||||
|
||||
table2.GetRow(i, row);
|
||||
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
|
||||
{
|
||||
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset2 : row[r] + offset2;
|
||||
}
|
||||
|
||||
table3.GetRow(i, row);
|
||||
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
|
||||
{
|
||||
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset3 : row[r] + offset3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Table& Table::operator=(const Table &rhs)
|
||||
{
|
||||
Clear();
|
||||
|
||||
@@ -58,6 +58,14 @@ public:
|
||||
/// Copy constructor
|
||||
Table(const Table &);
|
||||
|
||||
/** Merge constructors
|
||||
This is used to combine two or three tables into one table.*/
|
||||
Table(const Table &table1,
|
||||
const Table &table2, int offset2);
|
||||
Table(const Table &table1,
|
||||
const Table &table2, int offset2,
|
||||
const Table &table3, int offset3);
|
||||
|
||||
/// Assignment operator: deep copy
|
||||
Table& operator=(const Table &rhs);
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
linadv
|
||||
output
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,204 @@
|
||||
# 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.
|
||||
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ..
|
||||
MFEM_BUILD_DIR ?= ..
|
||||
MFEM_INSTALL_DIR ?= ../mfem
|
||||
SRC = $(if $(MFEM_DIR:..=),$(MFEM_DIR)/linadvmcl/,)
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
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 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 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
|
||||
endif
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
EXAMPLES = $(SEQ_EXAMPLES)
|
||||
else
|
||||
EXAMPLES = $(PAR_EXAMPLES) $(SEQ_EXAMPLES)
|
||||
endif
|
||||
SUBDIRS =
|
||||
ifeq ($(MFEM_USE_AMGX),YES)
|
||||
SUBDIRS += amgx
|
||||
endif
|
||||
ifeq ($(MFEM_USE_GINKGO),YES)
|
||||
SUBDIRS += ginkgo
|
||||
endif
|
||||
ifeq ($(MFEM_USE_HIOP),YES)
|
||||
SUBDIRS += hiop
|
||||
endif
|
||||
ifeq ($(MFEM_USE_PETSC),YES)
|
||||
SUBDIRS += petsc
|
||||
endif
|
||||
ifeq ($(MFEM_USE_PUMI),YES)
|
||||
SUBDIRS += pumi
|
||||
endif
|
||||
ifeq ($(MFEM_USE_SUNDIALS),YES)
|
||||
SUBDIRS += sundials
|
||||
endif
|
||||
ifeq ($(MFEM_USE_SUPERLU),YES)
|
||||
SUBDIRS += superlu
|
||||
endif
|
||||
ifeq ($(MFEM_USE_MOONOLITH),YES)
|
||||
SUBDIRS += moonolith
|
||||
endif
|
||||
ifeq ($(MFEM_USE_CALIPER),YES)
|
||||
SUBDIRS += caliper
|
||||
endif
|
||||
|
||||
SUBDIRS_ALL = $(addsuffix /all,$(SUBDIRS))
|
||||
SUBDIRS_TEST = $(addsuffix /test,$(SUBDIRS))
|
||||
SUBDIRS_CLEAN = $(addsuffix /clean,$(SUBDIRS))
|
||||
SUBDIRS_TPRINT = $(addsuffix /test-print,$(SUBDIRS))
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .cpp .mk
|
||||
.PHONY: all clean clean-build clean-exec
|
||||
|
||||
# Remove built-in rule
|
||||
%: %.cpp
|
||||
|
||||
# Replace the default implicit rule for *.cpp files
|
||||
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
|
||||
|
||||
all: $(EXAMPLES) $(SUBDIRS_ALL)
|
||||
|
||||
.PHONY: $(SUBDIRS_ALL) $(SUBDIRS_TEST) $(SUBDIRS_CLEAN) $(SUBDIRS_TPRINT)
|
||||
$(SUBDIRS_ALL) $(SUBDIRS_TEST) $(SUBDIRS_CLEAN):
|
||||
$(MAKE) -C $(@D) $(@F)
|
||||
$(SUBDIRS_TPRINT):
|
||||
@$(MAKE) -C $(@D) $(@F)
|
||||
|
||||
# Additional dependencies
|
||||
ex18: $(SRC)ex18.hpp
|
||||
ex33: $(SRC)ex33.hpp
|
||||
ex37: $(SRC)ex37.hpp
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),YES)
|
||||
ex18p: $(SRC)ex18.hpp
|
||||
ex33p: $(SRC)ex33.hpp
|
||||
ex37p: $(SRC)ex37.hpp
|
||||
endif
|
||||
|
||||
MFEM_TESTS = EXAMPLES
|
||||
include $(MFEM_TEST_MK)
|
||||
test: $(SUBDIRS_TEST)
|
||||
test-print: $(SUBDIRS_TPRINT)
|
||||
|
||||
# Testing: Parallel vs. serial runs
|
||||
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
|
||||
%-test-par: %
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel example)
|
||||
%-test-seq: %
|
||||
@$(call mfem-test,$<,, Serial example)
|
||||
%-test-par-cuda: %
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel CUDA example,-d cuda)
|
||||
%-test-seq-cuda: %
|
||||
@$(call mfem-test,$<,, Serial CUDA example,-d cuda)
|
||||
%-test-par-hip: %
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel HIP example,-d hip)
|
||||
%-test-seq-hip: %
|
||||
@$(call mfem-test,$<,, Serial HIP example,-d hip)
|
||||
|
||||
# Testing: Specific execution options
|
||||
ex0-test-seq: ex0
|
||||
@$(call mfem-test,$<,, Serial example,,1)
|
||||
ex0p-test-par: ex0p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,,1)
|
||||
ex1-test-seq: ex1
|
||||
@$(call mfem-test,$<,, Serial example)
|
||||
ex1p-test-par: ex1p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel example)
|
||||
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
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-e 1)
|
||||
ex27-test-seq: ex27
|
||||
@$(call mfem-test,$<,, Serial example,-dg)
|
||||
ex27p-test-par: ex27p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-dg)
|
||||
ex37-test-seq: ex37
|
||||
@$(call mfem-test,$<,, Serial example,-mi 3)
|
||||
ex37p-test-par: ex37p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-mi 3)
|
||||
# Testing: optional tests
|
||||
ifeq ($(MFEM_USE_STRUMPACK),YES)
|
||||
ex11p-test-strumpack: ex11p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), STRUMPACK example,--strumpack)
|
||||
test-par-YES: ex11p-test-strumpack
|
||||
endif
|
||||
ifeq ($(MFEM_USE_SUPERLU),YES)
|
||||
ex11p-test-superlu: ex11p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), SuperLU_DIST example,--superlu)
|
||||
test-par-YES: ex11p-test-superlu
|
||||
endif
|
||||
ifeq ($(MFEM_USE_MKL_CPARDISO),YES)
|
||||
ex11p-test-cpardiso: ex11p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), MKL_CPARDISO example,--cpardiso)
|
||||
test-par-YES: ex11p-test-cpardiso
|
||||
endif
|
||||
|
||||
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
|
||||
|
||||
# Generate an error message if the MFEM library is not built and exit
|
||||
$(MFEM_LIB_FILE):
|
||||
$(error The MFEM library is not built)
|
||||
|
||||
clean: clean-build clean-exec $(SUBDIRS_CLEAN)
|
||||
|
||||
clean-build:
|
||||
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
clean-exec:
|
||||
@rm -f refined.mesh displaced.mesh mesh.* ex5.mesh ex6p-checkpoint.*
|
||||
@rm -rf Example5* Example9* Example15* Example16* Example23* ParaView
|
||||
@rm -f sphere_refined.* sol.* sol_u.* sol_p.* sol_r.* sol_i.*
|
||||
@rm -f ex9.mesh ex9-mesh.* ex9-init.* ex9-final.*
|
||||
@rm -f deformed.* velocity.* elastic_energy.* mode_* mode_deriv_* flux.*
|
||||
@rm -f ex5-p-*.bp ex9-p-*.bp ex12-p-*.bp ex16-p-*.bp
|
||||
@rm -f ex16.mesh ex16-mesh.* ex16-init.* ex16-final.*
|
||||
@rm -f deformation.* pressure.*
|
||||
@rm -f ex20.dat ex20p_?????.dat gnuplot_ex20.inp gnuplot_ex20p.inp
|
||||
@rm -f ex21*.mesh ex21*.sol ex21p_*.*
|
||||
@rm -f ex23.mesh ex23-*.gf
|
||||
@rm -f ex25.mesh ex25-*.gf ex25p-*.*
|
||||
@rm -f euler-?-final.* euler-?-init.* euler-mesh-final.* euler-mesh.*
|
||||
@rm -rf ex28_* ex28p_*
|
||||
@rm -rf cond.* cond_mesh.* cond_j.* dsol.* port_mesh.* port_mode.*
|
||||
@@ -44,6 +44,7 @@ list(APPEND HDRS
|
||||
handle.hpp
|
||||
invariants.hpp
|
||||
kernels.hpp
|
||||
lapack.hpp
|
||||
linalg.hpp
|
||||
matrix.hpp
|
||||
ode.hpp
|
||||
|
||||
+20
-138
@@ -10,60 +10,9 @@
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "complex_densemat.hpp"
|
||||
#include "lapack.hpp"
|
||||
#include <complex>
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
extern "C" void
|
||||
cgetrf_(int *, int *, std::complex<float> *, int *, int *, int *);
|
||||
extern "C" void
|
||||
cgetrs_(char *, int *, int *, std::complex<float> *, int *, int *,
|
||||
std::complex<float> *, int *, int *);
|
||||
extern "C" void
|
||||
cgetri_(int *, std::complex<float> *, int *, int *,
|
||||
std::complex<float> *, int *, int *);
|
||||
extern "C" void
|
||||
ctrsm_(char *, char *, char *, char *, int *, int *, std::complex<float> *,
|
||||
std::complex<float> *, int *, std::complex<float> *, int *);
|
||||
extern "C" void
|
||||
cpotrf_(char *, int *, std::complex<float> *, int *, int *);
|
||||
|
||||
extern "C" void
|
||||
ctrtrs_(char *, char*, char *, int *, int *, std::complex<float> *, int *,
|
||||
std::complex<float> *, int *, int *);
|
||||
extern "C" void
|
||||
cpotri_(char *, int *, std::complex<float> *, int*, int *);
|
||||
|
||||
extern "C" void
|
||||
cpotrs_(char *, int *, int *, std::complex<float> *, int *,
|
||||
std::complex<float> *, int *, int *);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
extern "C" void
|
||||
zgetrf_(int *, int *, std::complex<double> *, int *, int *, int *);
|
||||
extern "C" void
|
||||
zgetrs_(char *, int *, int *, std::complex<double> *, int *, int *,
|
||||
std::complex<double> *, int *, int *);
|
||||
extern "C" void
|
||||
zgetri_(int *, std::complex<double> *, int *, int *,
|
||||
std::complex<double> *, int *, int *);
|
||||
extern "C" void
|
||||
ztrsm_(char *, char *, char *, char *, int *, int *, std::complex<double> *,
|
||||
std::complex<double> *, int *, std::complex<double> *, int *);
|
||||
extern "C" void
|
||||
zpotrf_(char *, int *, std::complex<double> *, int *, int *);
|
||||
|
||||
extern "C" void
|
||||
ztrtrs_(char *, char*, char *, int *, int *, std::complex<double> *, int *,
|
||||
std::complex<double> *, int *, int *);
|
||||
extern "C" void
|
||||
zpotri_(char *, int *, std::complex<double> *, int*, int *);
|
||||
|
||||
extern "C" void
|
||||
zpotrs_(char *, int *, int *, std::complex<double> *, int *,
|
||||
std::complex<double> *, int *, int *);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
@@ -175,35 +124,17 @@ ComplexDenseMatrix * ComplexDenseMatrix::ComputeInverse()
|
||||
std::complex<real_t> qwork, *work;
|
||||
int info;
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
cgetrf_(&w, &w, data, &w, ipiv, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
zgetrf_(&w, &w, data, &w, ipiv, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_COMPLEX(getrf_)(&w, &w, data, &w, ipiv, &info);
|
||||
if (info)
|
||||
{
|
||||
mfem_error("DenseMatrix::Invert() : Error in ZGETRF");
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
cgetri_(&w, data, &w, ipiv, &qwork, &lwork, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
zgetri_(&w, data, &w, ipiv, &qwork, &lwork, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_COMPLEX(getri_)(&w, data, &w, ipiv, &qwork, &lwork, &info);
|
||||
lwork = (int) qwork.real();
|
||||
work = new std::complex<real_t>[lwork];
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
cgetri_(&w, data, &w, ipiv, work, &lwork, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
zgetri_(&w, data, &w, ipiv, work, &lwork, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_COMPLEX(getri_)(&w, data, &w, ipiv, work, &lwork, &info);
|
||||
if (info)
|
||||
{
|
||||
mfem_error("DenseMatrix::Invert() : Error in ZGETRI");
|
||||
@@ -493,11 +424,7 @@ bool ComplexLUFactors::Factor(int m, real_t TOL)
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
int info = 0;
|
||||
MFEM_VERIFY(data, "Matrix data not set");
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
if (m) { cgetrf_(&m, &m, data, &m, ipiv, &info); }
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
if (m) { zgetrf_(&m, &m, data, &m, ipiv, &info); }
|
||||
#endif
|
||||
if (m) { MFEM_LAPACK_COMPLEX(getrf_)(&m, &m, data, &m, ipiv, &info); }
|
||||
return info == 0;
|
||||
#else
|
||||
// compiling without LAPACK
|
||||
@@ -659,13 +586,10 @@ void ComplexLUFactors::Solve(int m, int n, real_t *X_r, real_t * X_i) const
|
||||
std::complex<real_t> * x = ComplexFactors::RealToComplex(m*n,X_r,X_i);
|
||||
char trans = 'N';
|
||||
int info = 0;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
if (m > 0 && n > 0) { cgetrs_(&trans, &m, &n, data, &m, ipiv, x, &m, &info); }
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
if (m > 0 && n > 0) { zgetrs_(&trans, &m, &n, data, &m, ipiv, x, &m, &info); }
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
if (m > 0 && n > 0)
|
||||
{
|
||||
MFEM_LAPACK_COMPLEX(getrs_)(&trans, &m, &n, data, &m, ipiv, x, &m, &info);
|
||||
}
|
||||
MFEM_VERIFY(!info, "LAPACK: error in ZGETRS");
|
||||
ComplexFactors::ComplexToReal(m*n,x,X_r,X_i);
|
||||
delete [] x;
|
||||
@@ -685,15 +609,8 @@ void ComplexLUFactors::RightSolve(int m, int n, real_t *X_r, real_t * X_i) const
|
||||
if (m > 0 && n > 0)
|
||||
{
|
||||
std::complex<real_t> alpha(1.0,0.0);
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ctrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
ctrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
ztrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
ztrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_COMPLEX(trsm_)(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
MFEM_LAPACK_COMPLEX(trsm_)(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
}
|
||||
#else
|
||||
// compiling without LAPACK
|
||||
@@ -815,13 +732,7 @@ bool ComplexCholeskyFactors::Factor(int m, real_t TOL)
|
||||
int info = 0;
|
||||
char uplo = 'L';
|
||||
MFEM_VERIFY(data, "Matrix data not set");
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
if (m) {cpotrf_(&uplo, &m, data, &m, &info);}
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
if (m) {zpotrf_(&uplo, &m, data, &m, &info);}
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
if (m) { MFEM_LAPACK_COMPLEX(potrf_)(&uplo, &m, data, &m, &info); }
|
||||
return info == 0;
|
||||
#else
|
||||
// Cholesky–Crout algorithm
|
||||
@@ -921,13 +832,8 @@ void ComplexCholeskyFactors::LSolve(int m, int n, real_t * X_r,
|
||||
char diag = 'N';
|
||||
int info = 0;
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ctrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
ztrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_COMPLEX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, x, &m,
|
||||
&info);
|
||||
MFEM_VERIFY(!info, "ComplexCholeskyFactors:LSolve:: info");
|
||||
#else
|
||||
for (int k = 0; k < n; k++)
|
||||
@@ -960,13 +866,8 @@ void ComplexCholeskyFactors::USolve(int m, int n, real_t * X_r,
|
||||
char diag = 'N';
|
||||
int info = 0;
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ctrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
ztrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_COMPLEX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, x, &m,
|
||||
&info);
|
||||
MFEM_VERIFY(!info, "ComplexCholeskyFactors:USolve:: info");
|
||||
#else
|
||||
// X <- L^{-t} X
|
||||
@@ -994,13 +895,7 @@ void ComplexCholeskyFactors::Solve(int m, int n, real_t * X_r,
|
||||
char uplo = 'L';
|
||||
int info = 0;
|
||||
std::complex<real_t> *x = ComplexFactors::RealToComplex(m*n,X_r,X_i);
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
cpotrs_(&uplo, &m, &n, data, &m, x, &m, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
zpotrs_(&uplo, &m, &n, data, &m, x, &m, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_COMPLEX(potrs_)(&uplo, &m, &n, data, &m, x, &m, &info);
|
||||
MFEM_VERIFY(!info, "ComplexCholeskyFactors:Solve:: info");
|
||||
ComplexFactors::ComplexToReal(m*n,x,X_r,X_i);
|
||||
delete x;
|
||||
@@ -1026,15 +921,8 @@ void ComplexCholeskyFactors::RightSolve(int m, int n, real_t * X_r,
|
||||
std::complex<real_t> alpha(1.0,0.0);
|
||||
if (m > 0 && n > 0)
|
||||
{
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ctrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
|
||||
ctrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
ztrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
|
||||
ztrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_COMPLEX(trsm_)(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
|
||||
MFEM_LAPACK_COMPLEX(trsm_)(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
|
||||
}
|
||||
#else
|
||||
// X <- X L^{-H}
|
||||
@@ -1085,13 +973,7 @@ void ComplexCholeskyFactors::GetInverseMatrix(int m, real_t * X_r,
|
||||
}
|
||||
char uplo = 'L';
|
||||
int info = 0;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
cpotri_(&uplo, &m, X, &m, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
zpotri_(&uplo, &m, X, &m, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_COMPLEX(potri_)(&uplo, &m, X, &m, &info);
|
||||
MFEM_VERIFY(!info, "ComplexCholeskyFactors:GetInverseMatrix:: info");
|
||||
// fill in the upper triangular part
|
||||
for (int i = 0; i<m; i++)
|
||||
|
||||
+69
-355
@@ -17,6 +17,7 @@
|
||||
#include "vector.hpp"
|
||||
#include "matrix.hpp"
|
||||
#include "densemat.hpp"
|
||||
#include "lapack.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../general/table.hpp"
|
||||
#include "../general/globals.hpp"
|
||||
@@ -32,103 +33,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
extern "C" void
|
||||
sgemm_(char *, char *, int *, int *, int *, float *, float *,
|
||||
int *, float *, int *, float *, float *, int *);
|
||||
extern "C" void
|
||||
sgetrf_(int *, int *, float *, int *, int *, int *);
|
||||
extern "C" void
|
||||
sgetrs_(char *, int *, int *, float *, int *, int *, float *, int *, int *);
|
||||
extern "C" void
|
||||
sgetri_(int *N, float *A, int *LDA, int *IPIV, float *WORK,
|
||||
int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
ssyevr_(char *JOBZ, char *RANGE, char *UPLO, int *N, float *A, int *LDA,
|
||||
float *VL, float *VU, int *IL, int *IU, float *ABSTOL, int *M,
|
||||
float *W, float *Z, int *LDZ, int *ISUPPZ, float *WORK, int *LWORK,
|
||||
int *IWORK, int *LIWORK, int *INFO);
|
||||
extern "C" void
|
||||
ssyev_(char *JOBZ, char *UPLO, int *N, float *A, int *LDA, float *W,
|
||||
float *WORK, int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
ssygv_ (int *ITYPE, char *JOBZ, char *UPLO, int * N, float *A, int *LDA,
|
||||
float *B, int *LDB, float *W, float *WORK, int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
sgesvd_(char *JOBU, char *JOBVT, int *M, int *N, float *A, int *LDA,
|
||||
float *S, float *U, int *LDU, float *VT, int *LDVT, float *WORK,
|
||||
int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
strsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n,
|
||||
float *alpha, float *a, int *lda, float *b, int *ldb);
|
||||
extern "C" void
|
||||
sggev_(char *jobvl, char *jobvr, int *n, float *a, int *lda, float *B,
|
||||
int *ldb, float *alphar, float *alphai, float *beta, float *vl,
|
||||
int * ldvl, float * vr, int * ldvr, float * work, int * lwork, int* info);
|
||||
|
||||
// Cholesky factorizations/solves
|
||||
extern "C" void
|
||||
spotrf_(char *, int *, float *, int *, int *);
|
||||
// Solve
|
||||
extern "C" void
|
||||
spotrs_(char *, int *, int *, float *, int *, float *, int *, int *);
|
||||
// Triangular Solves
|
||||
extern "C" void
|
||||
strtrs_(char *, char*, char *, int *, int *, float *, int *, float *, int *,
|
||||
int *);
|
||||
extern "C" void
|
||||
spotri_(char *, int *, float *, int*, int *);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
extern "C" void
|
||||
dgemm_(char *, char *, int *, int *, int *, double *, double *,
|
||||
int *, double *, int *, double *, double *, int *);
|
||||
extern "C" void
|
||||
dgetrf_(int *, int *, double *, int *, int *, int *);
|
||||
extern "C" void
|
||||
dgetrs_(char *, int *, int *, double *, int *, int *, double *, int *, int *);
|
||||
extern "C" void
|
||||
dgetri_(int *N, double *A, int *LDA, int *IPIV, double *WORK,
|
||||
int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
dsyevr_(char *JOBZ, char *RANGE, char *UPLO, int *N, double *A, int *LDA,
|
||||
double *VL, double *VU, int *IL, int *IU, double *ABSTOL, int *M,
|
||||
double *W, double *Z, int *LDZ, int *ISUPPZ, double *WORK, int *LWORK,
|
||||
int *IWORK, int *LIWORK, int *INFO);
|
||||
extern "C" void
|
||||
dsyev_(char *JOBZ, char *UPLO, int *N, double *A, int *LDA, double *W,
|
||||
double *WORK, int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
dsygv_ (int *ITYPE, char *JOBZ, char *UPLO, int * N, double *A, int *LDA,
|
||||
double *B, int *LDB, double *W, double *WORK, int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
dgesvd_(char *JOBU, char *JOBVT, int *M, int *N, double *A, int *LDA,
|
||||
double *S, double *U, int *LDU, double *VT, int *LDVT, double *WORK,
|
||||
int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
dtrsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n,
|
||||
double *alpha, double *a, int *lda, double *b, int *ldb);
|
||||
extern "C" void
|
||||
dggev_(char *jobvl, char *jobvr, int *n, double *a, int *lda, double *B,
|
||||
int *ldb, double *alphar, double *alphai, double *beta, double *vl,
|
||||
int * ldvl, double * vr, int * ldvr, double * work, int * lwork, int* info);
|
||||
|
||||
// Cholesky factorizations/solves
|
||||
extern "C" void
|
||||
dpotrf_(char *, int *, double *, int *, int *);
|
||||
// Solve
|
||||
extern "C" void
|
||||
dpotrs_(char *, int *, int *, double *, int *, double *, int *, int *);
|
||||
// Triangular Solves
|
||||
extern "C" void
|
||||
dtrtrs_(char *, char*, char *, int *, int *, double *, int *, double *, int *,
|
||||
int *);
|
||||
extern "C" void
|
||||
dpotri_(char *, int *, double *, int*, int *);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
@@ -801,36 +705,19 @@ void DenseMatrix::Invert()
|
||||
real_t qwork, *work;
|
||||
int info;
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgetrf_(&width, &width, data, &width, ipiv, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgetrf_(&width, &width, data, &width, ipiv, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(getrf_)(&width, &width, data, &width, ipiv, &info);
|
||||
|
||||
if (info)
|
||||
{
|
||||
mfem_error("DenseMatrix::Invert() : Error in DGETRF");
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgetri_(&width, data, &width, ipiv, &qwork, &lwork, &info);
|
||||
MFEM_LAPACK_PREFIX(getri_)(&width, data, &width, ipiv, &qwork, &lwork, &info);
|
||||
|
||||
lwork = (int) qwork;
|
||||
work = new float[lwork];
|
||||
work = new real_t[lwork];
|
||||
|
||||
sgetri_(&width, data, &width, ipiv, work, &lwork, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgetri_(&width, data, &width, ipiv, &qwork, &lwork, &info);
|
||||
|
||||
lwork = (int) qwork;
|
||||
work = new double[lwork];
|
||||
|
||||
dgetri_(&width, data, &width, ipiv, work, &lwork, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(getri_)(&width, data, &width, ipiv, work, &lwork, &info);
|
||||
|
||||
if (info)
|
||||
{
|
||||
@@ -1066,15 +953,9 @@ void dsyevr_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect)
|
||||
A[i] = data[i];
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ssyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dsyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
&ABSTOL, &M, W, Z, &LDZ, ISUPPZ, &QWORK, &LWORK,
|
||||
&QIWORK, &LIWORK, &INFO );
|
||||
MFEM_LAPACK_PREFIX(syevr_)(&JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL,
|
||||
&IU, &ABSTOL, &M, W, Z, &LDZ, ISUPPZ, &QWORK,
|
||||
&LWORK, &QIWORK, &LIWORK, &INFO);
|
||||
|
||||
LWORK = (int) QWORK;
|
||||
LIWORK = QIWORK;
|
||||
@@ -1082,15 +963,9 @@ void dsyevr_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect)
|
||||
WORK = new real_t[LWORK];
|
||||
IWORK = new int[LIWORK];
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ssyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dsyevr_( &JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL, &IU,
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
&ABSTOL, &M, W, Z, &LDZ, ISUPPZ, WORK, &LWORK,
|
||||
IWORK, &LIWORK, &INFO );
|
||||
MFEM_LAPACK_PREFIX(syevr_)(&JOBZ, &RANGE, &UPLO, &N, A, &LDA, &VL, &VU, &IL,
|
||||
&IU, &ABSTOL, &M, W, Z, &LDZ, ISUPPZ, WORK,
|
||||
&LWORK, IWORK, &LIWORK, &INFO);
|
||||
|
||||
if (INFO != 0)
|
||||
{
|
||||
@@ -1230,24 +1105,12 @@ void dsyev_Eigensystem(DenseMatrix &a, Vector &ev, DenseMatrix *evect)
|
||||
A[i] = data[i];
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ssyev_(&JOBZ, &UPLO, &N, A, &LDA, W, &QWORK, &LWORK, &INFO);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, &QWORK, &LWORK, &INFO);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(syev_)(&JOBZ, &UPLO, &N, A, &LDA, W, &QWORK, &LWORK, &INFO);
|
||||
|
||||
LWORK = (int) QWORK;
|
||||
WORK = new real_t[LWORK];
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ssyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(syev_)(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO);
|
||||
|
||||
if (INFO != 0)
|
||||
{
|
||||
@@ -1322,24 +1185,14 @@ void dsygv_Eigensystem(DenseMatrix &a, DenseMatrix &b, Vector &ev,
|
||||
B[i] = b_data[i];
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ssygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, &QWORK, &LWORK, &INFO);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dsygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, &QWORK, &LWORK, &INFO);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(sygv_)(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W,
|
||||
&QWORK, &LWORK, &INFO);
|
||||
|
||||
LWORK = (int) QWORK;
|
||||
WORK = new real_t[LWORK];
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ssygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, WORK, &LWORK, &INFO);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dsygv_(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, WORK, &LWORK, &INFO);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(sygv_)(&ITYPE, &JOBZ, &UPLO, &N, A, &LDA, B, &LDB, W, WORK,
|
||||
&LWORK, &INFO);
|
||||
|
||||
if (INFO != 0)
|
||||
{
|
||||
@@ -1391,26 +1244,14 @@ void DenseMatrix::SingularValues(Vector &sv) const
|
||||
int info;
|
||||
real_t qwork;
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgesvd_(&jobu, &jobvt, &m, &n, a, &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgesvd_(&jobu, &jobvt, &m, &n, a, &m,
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
s, u, &m, vt, &n, &qwork, &lwork, &info);
|
||||
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, a, &m, s, u, &m, vt, &n,
|
||||
&qwork, &lwork, &info);
|
||||
|
||||
lwork = (int) qwork;
|
||||
work = new real_t[lwork];
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgesvd_(&jobu, &jobvt, &m, &n, a, &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgesvd_(&jobu, &jobvt, &m, &n, a, &m,
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
s, u, &m, vt, &n, work, &lwork, &info);
|
||||
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, a, &m, s, u, &m, vt, &n,
|
||||
work, &lwork, &info);
|
||||
|
||||
delete [] work;
|
||||
if (info)
|
||||
@@ -2573,14 +2414,8 @@ void Mult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
|
||||
static real_t alpha = 1.0, beta = 0.0;
|
||||
int m = b.Height(), n = c.Width(), k = b.Width();
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
c.Data(), &k, &beta, a.Data(), &m);
|
||||
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
|
||||
c.Data(), &k, &beta, a.Data(), &m);
|
||||
#else
|
||||
const int ah = a.Height();
|
||||
const int aw = a.Width();
|
||||
@@ -2603,14 +2438,8 @@ void AddMult_a(real_t alpha, const DenseMatrix &b, const DenseMatrix &c,
|
||||
static real_t beta = 1.0;
|
||||
int m = b.Height(), n = c.Width(), k = b.Width();
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
c.Data(), &k, &beta, a.Data(), &m);
|
||||
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
|
||||
c.Data(), &k, &beta, a.Data(), &m);
|
||||
#else
|
||||
const int ah = a.Height();
|
||||
const int aw = a.Width();
|
||||
@@ -2641,12 +2470,8 @@ void AddMult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
|
||||
static real_t alpha = 1.0, beta = 1.0;
|
||||
int m = b.Height(), n = c.Width(), k = b.Width();
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgemm_(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
|
||||
#endif
|
||||
c.Data(), &k, &beta, a.Data(), &m);
|
||||
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, b.Data(), &m,
|
||||
c.Data(), &k, &beta, a.Data(), &m);
|
||||
#else
|
||||
const int ah = a.Height();
|
||||
const int aw = a.Width();
|
||||
@@ -2965,12 +2790,8 @@ void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
|
||||
static real_t alpha = 1.0, beta = 0.0;
|
||||
int m = A.Height(), n = B.Height(), k = A.Width();
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
|
||||
#endif
|
||||
B.Data(), &n, &beta, ABt.Data(), &m);
|
||||
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
|
||||
B.Data(), &n, &beta, ABt.Data(), &m);
|
||||
#elif 1
|
||||
const int ah = A.Height();
|
||||
const int bh = B.Height();
|
||||
@@ -3074,12 +2895,8 @@ void AddMultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
|
||||
static real_t alpha = 1.0, beta = 1.0;
|
||||
int m = A.Height(), n = B.Height(), k = A.Width();
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
|
||||
#endif
|
||||
B.Data(), &n, &beta, ABt.Data(), &m);
|
||||
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
|
||||
B.Data(), &n, &beta, ABt.Data(), &m);
|
||||
#elif 1
|
||||
const int ah = A.Height();
|
||||
const int bh = B.Height();
|
||||
@@ -3173,12 +2990,8 @@ void AddMult_a_ABt(real_t a, const DenseMatrix &A, const DenseMatrix &B,
|
||||
static real_t beta = 1.0;
|
||||
int m = A.Height(), n = B.Height(), k = A.Width();
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
|
||||
#endif
|
||||
B.Data(), &n, &beta, ABt.Data(), &m);
|
||||
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &m,
|
||||
B.Data(), &n, &beta, ABt.Data(), &m);
|
||||
#elif 1
|
||||
const int ah = A.Height();
|
||||
const int bh = B.Height();
|
||||
@@ -3234,12 +3047,8 @@ void MultAtB(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &AtB)
|
||||
static real_t alpha = 1.0, beta = 0.0;
|
||||
int m = A.Width(), n = B.Width(), k = A.Height();
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
|
||||
#endif
|
||||
B.Data(), &k, &beta, AtB.Data(), &m);
|
||||
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
|
||||
B.Data(), &k, &beta, AtB.Data(), &m);
|
||||
#elif 1
|
||||
const int ah = A.Height();
|
||||
const int aw = A.Width();
|
||||
@@ -3291,12 +3100,8 @@ void AddMultAtB(const DenseMatrix &A, const DenseMatrix &B,
|
||||
static real_t alpha = 1.0, beta = 1.0;
|
||||
int m = A.Width(), n = B.Width(), k = A.Height();
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
|
||||
#endif
|
||||
B.Data(), &k, &beta, AtB.Data(), &m);
|
||||
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
|
||||
B.Data(), &k, &beta, AtB.Data(), &m);
|
||||
#else
|
||||
const int ah = A.Height();
|
||||
const int aw = A.Width();
|
||||
@@ -3335,12 +3140,8 @@ void AddMult_a_AtB(real_t a, const DenseMatrix &A, const DenseMatrix &B,
|
||||
static real_t beta = 1.0;
|
||||
int m = A.Width(), n = B.Width(), k = A.Height();
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgemm_(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
|
||||
#endif
|
||||
B.Data(), &k, &beta, AtB.Data(), &m);
|
||||
MFEM_LAPACK_PREFIX(gemm_)(&transa, &transb, &m, &n, &k, &alpha, A.Data(), &k,
|
||||
B.Data(), &k, &beta, AtB.Data(), &m);
|
||||
#else
|
||||
const int ah = A.Height();
|
||||
const int aw = A.Width();
|
||||
@@ -3545,13 +3346,7 @@ bool LUFactors::Factor(int m, real_t TOL)
|
||||
{
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
int info = 0;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
if (m) { sgetrf_(&m, &m, data, &m, ipiv, &info); }
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
if (m) { dgetrf_(&m, &m, data, &m, ipiv, &info); }
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
if (m) { MFEM_LAPACK_PREFIX(getrf_)(&m, &m, data, &m, ipiv, &info); }
|
||||
return info == 0;
|
||||
#else
|
||||
// compiling without LAPACK
|
||||
@@ -3703,13 +3498,10 @@ void LUFactors::Solve(int m, int n, real_t *X) const
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
char trans = 'N';
|
||||
int info = 0;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
if (m > 0 && n > 0) { sgetrs_(&trans, &m, &n, data, &m, ipiv, X, &m, &info); }
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
if (m > 0 && n > 0) { dgetrs_(&trans, &m, &n, data, &m, ipiv, X, &m, &info); }
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
if (m > 0 && n > 0)
|
||||
{
|
||||
MFEM_LAPACK_PREFIX(getrs_)(&trans, &m, &n, data, &m, ipiv, X, &m, &info);
|
||||
}
|
||||
MFEM_VERIFY(!info, "LAPACK: error in DGETRS");
|
||||
#else
|
||||
// compiling without LAPACK
|
||||
@@ -3726,15 +3518,8 @@ void LUFactors::RightSolve(int m, int n, real_t *X) const
|
||||
real_t alpha = 1.0;
|
||||
if (m > 0 && n > 0)
|
||||
{
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
strsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
strsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dtrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
dtrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(trsm_)(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
MFEM_LAPACK_PREFIX(trsm_)(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
|
||||
}
|
||||
#else
|
||||
// compiling without LAPACK
|
||||
@@ -3911,13 +3696,7 @@ bool CholeskyFactors::Factor(int m, real_t TOL)
|
||||
int info = 0;
|
||||
char uplo = 'L';
|
||||
MFEM_VERIFY(data, "Matrix data not set");
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
if (m) {spotrf_(&uplo, &m, data, &m, &info);}
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
if (m) {dpotrf_(&uplo, &m, data, &m, &info);}
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
if (m) { MFEM_LAPACK_PREFIX(potrf_)(&uplo, &m, data, &m, &info); }
|
||||
return info == 0;
|
||||
#else
|
||||
// Cholesky–Crout algorithm
|
||||
@@ -4009,13 +3788,8 @@ void CholeskyFactors::LSolve(int m, int n, real_t * X) const
|
||||
char diag = 'N';
|
||||
int info = 0;
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
strtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dtrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, X, &m,
|
||||
&info);
|
||||
MFEM_VERIFY(!info, "CholeskyFactors:LSolve:: info");
|
||||
|
||||
#else
|
||||
@@ -4045,13 +3819,8 @@ void CholeskyFactors::USolve(int m, int n, real_t * X) const
|
||||
char diag = 'N';
|
||||
int info = 0;
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
strtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dtrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, X, &m, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, X, &m,
|
||||
&info);
|
||||
MFEM_VERIFY(!info, "CholeskyFactors:USolve:: info");
|
||||
|
||||
#else
|
||||
@@ -4077,13 +3846,7 @@ void CholeskyFactors::Solve(int m, int n, real_t * X) const
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
char uplo = 'L';
|
||||
int info = 0;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
spotrs_(&uplo, &m, &n, data, &m, X, &m, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dpotrs_(&uplo, &m, &n, data, &m, X, &m, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(potrs_)(&uplo, &m, &n, data, &m, X, &m, &info);
|
||||
MFEM_VERIFY(!info, "CholeskyFactors:Solve:: info");
|
||||
|
||||
#else
|
||||
@@ -4104,15 +3867,8 @@ void CholeskyFactors::RightSolve(int m, int n, real_t * X) const
|
||||
real_t alpha = 1.0;
|
||||
if (m > 0 && n > 0)
|
||||
{
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
strsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,X,&n);
|
||||
strsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,X,&n);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dtrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,X,&n);
|
||||
dtrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,X,&n);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(trsm_)(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,X,&n);
|
||||
MFEM_LAPACK_PREFIX(trsm_)(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,X,&n);
|
||||
}
|
||||
#else
|
||||
// X <- X L^{-t}
|
||||
@@ -4160,13 +3916,7 @@ void CholeskyFactors::GetInverseMatrix(int m, real_t * X) const
|
||||
}
|
||||
char uplo = 'L';
|
||||
int info = 0;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
spotri_(&uplo, &m, X, &m, &info);
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dpotri_(&uplo, &m, X, &m, &info);
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
MFEM_LAPACK_PREFIX(potri_)(&uplo, &m, X, &m, &info);
|
||||
MFEM_VERIFY(!info, "CholeskyFactors:GetInverseMatrix:: info");
|
||||
// fill in the upper triangular part
|
||||
for (int i = 0; i<m; i++)
|
||||
@@ -4350,14 +4100,8 @@ DenseMatrixEigensystem::DenseMatrixEigensystem(DenseMatrix &m)
|
||||
uplo = 'U';
|
||||
lwork = -1;
|
||||
real_t qwork;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ssyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dsyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
&qwork, &lwork, &info);
|
||||
MFEM_LAPACK_PREFIX(syev_)(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
|
||||
&qwork, &lwork, &info);
|
||||
|
||||
lwork = (int) qwork;
|
||||
work = new real_t[lwork];
|
||||
@@ -4385,14 +4129,8 @@ void DenseMatrixEigensystem::Eval()
|
||||
#endif
|
||||
|
||||
EVect = mat;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
ssyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dsyev_(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
work, &lwork, &info);
|
||||
MFEM_LAPACK_PREFIX(syev_)(&jobz, &uplo, &n, EVect.Data(), &n, EVal.GetData(),
|
||||
work, &lwork, &info);
|
||||
|
||||
if (info != 0)
|
||||
{
|
||||
@@ -4444,15 +4182,9 @@ DenseMatrixGeneralizedEigensystem::DenseMatrixGeneralizedEigensystem(
|
||||
int nl = max(1,Vl.Height());
|
||||
int nr = max(1,Vr.Height());
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
alphai, beta, Vl.Data(), &nl, Vr.Data(), &nr,
|
||||
&qwork, &lwork, &info);
|
||||
MFEM_LAPACK_PREFIX(ggev_)(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,
|
||||
alphar, alphai, beta, Vl.Data(), &nl, Vr.Data(),
|
||||
&nr, &qwork, &lwork, &info);
|
||||
|
||||
lwork = (int) qwork;
|
||||
work = new real_t[lwork];
|
||||
@@ -4465,15 +4197,9 @@ void DenseMatrixGeneralizedEigensystem::Eval()
|
||||
|
||||
A_copy = A;
|
||||
B_copy = B;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dggev_(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,alphar,
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
alphai, beta, Vl.Data(), &nl, Vr.Data(), &nr,
|
||||
work, &lwork, &info);
|
||||
MFEM_LAPACK_PREFIX(ggev_)(&jobvl,&jobvr,&n,A_copy.Data(),&n,B_copy.Data(),&n,
|
||||
alphar, alphai, beta, Vl.Data(), &nl, Vr.Data(),
|
||||
&nr, work, &lwork, &info);
|
||||
if (info != 0)
|
||||
{
|
||||
mfem::err << "DenseMatrixGeneralizedEigensystem::Eval(): DGGEV error code: "
|
||||
@@ -4554,14 +4280,8 @@ void DenseMatrixSVD::Init()
|
||||
sv.SetSize(min(m, n));
|
||||
real_t qwork;
|
||||
lwork = -1;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgesvd_(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(), NULL, &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgesvd_(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(), NULL, &m,
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
NULL, &n, &qwork, &lwork, &info);
|
||||
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, NULL, &m, sv.GetData(),
|
||||
NULL, &m, NULL, &n, &qwork, &lwork, &info);
|
||||
lwork = (int) qwork;
|
||||
work = new real_t[lwork];
|
||||
}
|
||||
@@ -4597,14 +4317,8 @@ void DenseMatrixSVD::Eval(DenseMatrix &M)
|
||||
datavt = Vt.Data();
|
||||
}
|
||||
Mc = M;
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgesvd_(&jobu, &jobvt, &m, &n, Mc.Data(), &m, sv.GetData(), datau, &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgesvd_(&jobu, &jobvt, &m, &n, Mc.Data(), &m, sv.GetData(), datau, &m,
|
||||
#else
|
||||
MFEM_ABORT("Floating point type undefined");
|
||||
#endif
|
||||
datavt, &n, work, &lwork, &info);
|
||||
MFEM_LAPACK_PREFIX(gesvd_)(&jobu, &jobvt, &m, &n, Mc.Data(), &m, sv.GetData(),
|
||||
datau, &m, datavt, &n, work, &lwork, &info);
|
||||
|
||||
if (info)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_LAPACK_HPP
|
||||
#define MFEM_LAPACK_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
#define MFEM_LAPACK_PREFIX(stub) s##stub
|
||||
#define MFEM_LAPACK_COMPLEX(stub) c##stub
|
||||
#elif defined(MFEM_USE_DOUBLE)
|
||||
#define MFEM_LAPACK_PREFIX(stub) d##stub
|
||||
#define MFEM_LAPACK_COMPLEX(stub) z##stub
|
||||
#endif
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(gemm_)(char *, char *, int *, int *, int *, real_t *,
|
||||
real_t *, int *, real_t *, int *, real_t *, real_t *,
|
||||
int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(getrf_)(int *, int *, real_t *, int *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(getrs_)(char *, int *, int *, real_t *, int *, int *,
|
||||
real_t *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(getri_)(int *N, real_t *A, int *LDA, int *IPIV, real_t *WORK,
|
||||
int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(syevr_)(char *JOBZ, char *RANGE, char *UPLO, int *N,
|
||||
real_t *A, int *LDA, real_t *VL, real_t *VU, int *IL,
|
||||
int *IU, real_t *ABSTOL, int *M, real_t *W,
|
||||
real_t *Z, int *LDZ, int *ISUPPZ, real_t *WORK,
|
||||
int *LWORK, int *IWORK, int *LIWORK, int *INFO);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(syev_)(char *JOBZ, char *UPLO, int *N, real_t *A, int *LDA,
|
||||
real_t *W, real_t *WORK, int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(sygv_) (int *ITYPE, char *JOBZ, char *UPLO, int * N,
|
||||
real_t *A, int *LDA, real_t *B, int *LDB, real_t *W,
|
||||
real_t *WORK, int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(gesvd_)(char *JOBU, char *JOBVT, int *M, int *N, real_t *A,
|
||||
int *LDA, real_t *S, real_t *U, int *LDU, real_t *VT,
|
||||
int *LDVT, real_t *WORK, int *LWORK, int *INFO);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(trsm_)(char *side, char *uplo, char *transa, char *diag,
|
||||
int *m, int *n, real_t *alpha, real_t *a, int *lda,
|
||||
real_t *b, int *ldb);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(ggev_)(char *jobvl, char *jobvr, int *n, real_t *a, int *lda,
|
||||
real_t *B, int *ldb, real_t *alphar, real_t *alphai,
|
||||
real_t *beta, real_t *vl, int * ldvl, real_t * vr,
|
||||
int * ldvr, real_t * work, int * lwork, int* info);
|
||||
|
||||
// Cholesky factorizations/solves
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(potrf_)(char *, int *, real_t *, int *, int *);
|
||||
// Solve
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(potrs_)(char *, int *, int *, real_t *, int *, real_t *,
|
||||
int *, int *);
|
||||
// Triangular Solves
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(trtrs_)(char *, char*, char *, int *, int *, real_t *, int *,
|
||||
real_t *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(potri_)(char *, int *, real_t *, int*, int *);
|
||||
|
||||
// LAPACK routines for NNLSSolver
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(ormqr_)(char *, char *, int *, int *, int *, real_t *, int*,
|
||||
real_t *, real_t *, int *, real_t *, int*, int*);
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(geqrf_)(int *, int *, real_t *, int *, real_t *, real_t *,
|
||||
int *, int *);
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(gemv_)(char *, int *, int *, real_t *, real_t *, int *,
|
||||
real_t *, int *, real_t *, real_t *, int *);
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_PREFIX(trsm_)(char *side, char *uplo, char *transa, char *diag,
|
||||
int *m, int *n, real_t *alpha, real_t *a, int *lda,
|
||||
real_t *b, int *ldb);
|
||||
|
||||
// Complex
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(getrf_)(int *, int *, std::complex<real_t> *, int *, int *,
|
||||
int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(getrs_)(char *, int *, int *, std::complex<real_t> *, int *,
|
||||
int *, std::complex<real_t> *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(getri_)(int *, std::complex<real_t> *, int *, int *,
|
||||
std::complex<real_t> *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(trsm_)(char *, char *, char *, char *, int *, int *,
|
||||
std::complex<real_t> *, std::complex<real_t> *,
|
||||
int *, std::complex<real_t> *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(potrf_)(char *, int *, std::complex<real_t> *, int *,
|
||||
int *);
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(trtrs_)(char *, char*, char *, int *, int *,
|
||||
std::complex<real_t> *, int *,
|
||||
std::complex<real_t> *, int *, int *);
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(potri_)(char *, int *, std::complex<real_t> *, int*, int *);
|
||||
|
||||
extern "C" void
|
||||
MFEM_LAPACK_COMPLEX(potrs_)(char *, int *, int *, std::complex<real_t> *, int *,
|
||||
std::complex<real_t> *, int *, int *);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+29
-10
@@ -420,8 +420,9 @@ public:
|
||||
/** @brief Perform the action of the explicit part of the operator, G:
|
||||
@a v = G(@a u, t) where t is the current time.
|
||||
|
||||
Presently, this method is used by some PETSc ODE solvers, for more
|
||||
details, see the PETSc Manual. */
|
||||
Presently, this method is used by some PETSc ODE solvers and the
|
||||
SUNDIALS ARKStep integrator, for more details, see either the PETSc
|
||||
Manual or the ARKode User Guide, respectively. */
|
||||
virtual void ExplicitMult(const Vector &u, Vector &v) const;
|
||||
|
||||
/** @brief Perform the action of the implicit part of the operator, F:
|
||||
@@ -445,7 +446,7 @@ public:
|
||||
|
||||
Regardless of the choice of F and G, this function should always compute
|
||||
@a k = inv(M) g(@a u, t). */
|
||||
virtual void Mult(const Vector &u, Vector &v) const override;
|
||||
virtual void Mult(const Vector &u, Vector &k) const override;
|
||||
|
||||
/** @brief Solve for the unknown @a k, at the current time t, the following
|
||||
equation:
|
||||
@@ -496,7 +497,17 @@ public:
|
||||
details, see the PETSc Manual. */
|
||||
virtual Operator& GetExplicitGradient(const Vector &u) const;
|
||||
|
||||
/** @brief Setup a linear system as needed by some SUNDIALS ODE solvers.
|
||||
/** @brief Setup a linear system as needed by some SUNDIALS ODE solvers to
|
||||
perform a similar action to ImplicitSolve, i.e., solve for k, at the
|
||||
current time t, in F(u + gamma k, k, t) = G(u + gamma k, t).
|
||||
|
||||
The SUNDIALS ODE solvers iteratively solve for k, as knew = kold + dk.
|
||||
The linear system here is for dk, obtained by linearizing the nonlinear
|
||||
system F(u + gamma knew, knew, t) = G(u + gamma knew, t) about dk = 0:
|
||||
F(u + gamma (kold + dk), kold + dk, t) = G(u + gamma (kold + dk), t)
|
||||
=> [dF/dk + gamma (dF/du - dG/du)] dk = G - F + O(dk^2)
|
||||
In other words, the linear system to be setup here is A dk = r, where
|
||||
A = [dF/dk + gamma (dF/du - dG/du)] and r = G - F.
|
||||
|
||||
For solving an ordinary differential equation of the form
|
||||
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined as one
|
||||
@@ -506,7 +517,7 @@ public:
|
||||
2. F(u,k,t) = M k and G(u,t) = g(u,t)
|
||||
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
|
||||
|
||||
This function performs setup to solve $ A x = b $ where A is either
|
||||
This function performs setup to solve $ A dk = r $ where A is either
|
||||
|
||||
1. A(@a y,t) = I - @a gamma inv(M) J(@a y,t)
|
||||
2. A(@a y,t) = M - @a gamma J(@a y,t)
|
||||
@@ -527,18 +538,26 @@ public:
|
||||
virtual int SUNImplicitSetup(const Vector &y, const Vector &v,
|
||||
int jok, int *jcur, real_t gamma);
|
||||
|
||||
/** @brief Solve the ODE linear system A @a x = @a b, where A is defined by
|
||||
the method SUNImplicitSetup().
|
||||
/** @brief Solve the ODE linear system A @a dk = @a r , where A and r are
|
||||
defined by the method SUNImplicitSetup().
|
||||
|
||||
@param[in] b The linear system right-hand side.
|
||||
@param[in,out] x On input, the initial guess. On output, the solution.
|
||||
For solving an ordinary differential equation of the form
|
||||
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined as one
|
||||
of the following:
|
||||
|
||||
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
|
||||
2. F(u,k,t) = M k and G(u,t) = g(u,t)
|
||||
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
|
||||
|
||||
@param[in] r inv(M) g(y,t) - k for 1 or g(y,t) - M k for 2 & 3.
|
||||
@param[in,out] dk On input, the initial guess. On output, the solution.
|
||||
@param[in] tol Linear solve tolerance.
|
||||
|
||||
If not re-implemented, this method simply generates an error.
|
||||
|
||||
Presently, this method is used by SUNDIALS ODE solvers, for more
|
||||
details, see the SUNDIALS User Guides. */
|
||||
virtual int SUNImplicitSolve(const Vector &b, Vector &x, real_t tol);
|
||||
virtual int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol);
|
||||
|
||||
/** @brief Setup the mass matrix in the ODE system
|
||||
$ M \frac{dy}{dt} = g(y,t) $ .
|
||||
|
||||
+92
-177
@@ -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"
|
||||
@@ -263,7 +264,7 @@ void OperatorJacobiSmoother::SetOperator(const Operator &op)
|
||||
oper = &op;
|
||||
height = op.Height();
|
||||
width = op.Width();
|
||||
MFEM_ASSERT(height == width, "not a square matrix!");
|
||||
MFEM_VERIFY(height == width, "not a square matrix!");
|
||||
// ess_tdof_list is only used with BilinearForm
|
||||
ess_tdof_list = nullptr;
|
||||
}
|
||||
@@ -304,8 +305,8 @@ void OperatorJacobiSmoother::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
// For empty MPI ranks, height may be 0:
|
||||
// MFEM_VERIFY(Height() > 0, "The diagonal hasn't been computed.");
|
||||
MFEM_ASSERT(x.Size() == Width(), "invalid input vector");
|
||||
MFEM_ASSERT(y.Size() == Height(), "invalid output vector");
|
||||
MFEM_VERIFY(x.Size() == Width(), "invalid input vector");
|
||||
MFEM_VERIFY(y.Size() == Height(), "invalid output vector");
|
||||
|
||||
if (iterative_mode)
|
||||
{
|
||||
@@ -591,7 +592,7 @@ void SLISolver::Mult(const Vector &b, Vector &x) const
|
||||
}
|
||||
initial_norm = nom0;
|
||||
|
||||
if (print_options.iterations | print_options.first_and_last)
|
||||
if (print_options.iterations || print_options.first_and_last)
|
||||
{
|
||||
mfem::out << " Iteration : " << setw(3) << right << 0 << " ||Br|| = "
|
||||
<< nom << (print_options.first_and_last ? " ..." : "") << '\n';
|
||||
@@ -743,7 +744,7 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
|
||||
}
|
||||
nom0 = nom = Dot(d, r);
|
||||
if (nom0 >= 0.0) { initial_norm = sqrt(nom0); }
|
||||
MFEM_ASSERT(IsFinite(nom), "nom = " << nom);
|
||||
MFEM_VERIFY(IsFinite(nom), "nom = " << nom);
|
||||
if (print_options.iterations || print_options.first_and_last)
|
||||
{
|
||||
mfem::out << " Iteration : " << setw(3) << 0 << " (B r, r) = "
|
||||
@@ -775,7 +776,7 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
|
||||
|
||||
oper->Mult(d, z); // z = A d
|
||||
den = Dot(z, d);
|
||||
MFEM_ASSERT(IsFinite(den), "den = " << den);
|
||||
MFEM_VERIFY(IsFinite(den), "den = " << den);
|
||||
if (den <= 0.0)
|
||||
{
|
||||
if (Dot(d, d) > 0.0 && print_options.warnings)
|
||||
@@ -810,7 +811,7 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
|
||||
{
|
||||
betanom = Dot(r, r);
|
||||
}
|
||||
MFEM_ASSERT(IsFinite(betanom), "betanom = " << betanom);
|
||||
MFEM_VERIFY(IsFinite(betanom), "betanom = " << betanom);
|
||||
if (betanom < 0.0)
|
||||
{
|
||||
if (print_options.warnings)
|
||||
@@ -854,7 +855,7 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
|
||||
}
|
||||
oper->Mult(d, z); // z = A d
|
||||
den = Dot(d, z);
|
||||
MFEM_ASSERT(IsFinite(den), "den = " << den);
|
||||
MFEM_VERIFY(IsFinite(den), "den = " << den);
|
||||
if (den <= 0.0)
|
||||
{
|
||||
if (Dot(d, d) > 0.0 && print_options.warnings)
|
||||
@@ -1024,7 +1025,7 @@ void GMRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
}
|
||||
}
|
||||
real_t beta = initial_norm = Norm(r); // beta = ||r||
|
||||
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
|
||||
MFEM_VERIFY(IsFinite(beta), "beta = " << beta);
|
||||
|
||||
final_norm = std::max(rel_tol*beta, abs_tol);
|
||||
|
||||
@@ -1074,7 +1075,7 @@ void GMRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
}
|
||||
|
||||
H(i+1,i) = Norm(w); // H(i+1,i) = ||w||
|
||||
MFEM_ASSERT(IsFinite(H(i+1,i)), "Norm(w) = " << H(i+1,i));
|
||||
MFEM_VERIFY(IsFinite(H(i+1,i)), "Norm(w) = " << H(i+1,i));
|
||||
if (v[i+1] == NULL) { v[i+1] = new Vector(n); }
|
||||
v[i+1]->Set(1.0/H(i+1,i), w); // v[i+1] = w / H(i+1,i)
|
||||
|
||||
@@ -1088,7 +1089,7 @@ void GMRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
ApplyPlaneRotation(s(i), s(i+1), cs(i), sn(i));
|
||||
|
||||
const real_t resid = fabs(s(i+1));
|
||||
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
|
||||
MFEM_VERIFY(IsFinite(resid), "resid = " << resid);
|
||||
|
||||
if (resid <= final_norm)
|
||||
{
|
||||
@@ -1127,7 +1128,7 @@ void GMRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
subtract(b, r, r);
|
||||
}
|
||||
beta = Norm(r); // beta = ||r||
|
||||
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
|
||||
MFEM_VERIFY(IsFinite(beta), "beta = " << beta);
|
||||
if (beta <= final_norm)
|
||||
{
|
||||
final_norm = beta;
|
||||
@@ -1184,7 +1185,7 @@ void FGMRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
r = b;
|
||||
}
|
||||
real_t beta = initial_norm = Norm(r); // beta = ||r||
|
||||
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
|
||||
MFEM_VERIFY(IsFinite(beta), "beta = " << beta);
|
||||
|
||||
final_norm = std::max(rel_tol*beta, abs_tol);
|
||||
|
||||
@@ -1261,7 +1262,7 @@ void FGMRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
ApplyPlaneRotation(s(i), s(i+1), cs(i), sn(i));
|
||||
|
||||
const real_t resid = fabs(s(i+1));
|
||||
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
|
||||
MFEM_VERIFY(IsFinite(resid), "resid = " << resid);
|
||||
if (print_options.iterations || (print_options.first_and_last &&
|
||||
resid <= final_norm))
|
||||
{
|
||||
@@ -1302,7 +1303,7 @@ void FGMRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
oper->Mult(x, r);
|
||||
subtract(b,r,r);
|
||||
beta = Norm(r);
|
||||
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
|
||||
MFEM_VERIFY(IsFinite(beta), "beta = " << beta);
|
||||
if (beta <= final_norm)
|
||||
{
|
||||
converged = true;
|
||||
@@ -1399,7 +1400,7 @@ void BiCGSTABSolver::Mult(const Vector &b, Vector &x) const
|
||||
rtilde = r;
|
||||
|
||||
resid = initial_norm = Norm(r);
|
||||
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
|
||||
MFEM_VERIFY(IsFinite(resid), "resid = " << resid);
|
||||
if (print_options.iterations || print_options.first_and_last)
|
||||
{
|
||||
mfem::out << " Iteration : " << setw(3) << 0
|
||||
@@ -1466,7 +1467,7 @@ void BiCGSTABSolver::Mult(const Vector &b, Vector &x) const
|
||||
alpha = rho_1 / Dot(rtilde, v);
|
||||
add(r, -alpha, v, s); // s = r - alpha * v
|
||||
resid = Norm(s);
|
||||
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
|
||||
MFEM_VERIFY(IsFinite(resid), "resid = " << resid);
|
||||
if (resid < tol_goal)
|
||||
{
|
||||
x.Add(alpha, phat); // x = x + alpha * phat
|
||||
@@ -1506,7 +1507,7 @@ void BiCGSTABSolver::Mult(const Vector &b, Vector &x) const
|
||||
|
||||
rho_2 = rho_1;
|
||||
resid = Norm(r);
|
||||
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
|
||||
MFEM_VERIFY(IsFinite(resid), "resid = " << resid);
|
||||
if (print_options.iterations)
|
||||
{
|
||||
mfem::out << " ||r|| = " << resid << '\n';
|
||||
@@ -1646,7 +1647,7 @@ void MINRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
prec->Mult(v1, u1);
|
||||
}
|
||||
eta = beta = initial_norm = sqrt(Dot(*z, v1));
|
||||
MFEM_ASSERT(IsFinite(eta), "eta = " << eta);
|
||||
MFEM_VERIFY(IsFinite(eta), "eta = " << eta);
|
||||
gamma0 = gamma1 = 1.;
|
||||
sigma0 = sigma1 = 0.;
|
||||
|
||||
@@ -1674,7 +1675,7 @@ void MINRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
}
|
||||
oper->Mult(*z, q);
|
||||
alpha = Dot(*z, q);
|
||||
MFEM_ASSERT(IsFinite(alpha), "alpha = " << alpha);
|
||||
MFEM_VERIFY(IsFinite(alpha), "alpha = " << alpha);
|
||||
if (it > 1) // (v0 == 0) for (it == 1)
|
||||
{
|
||||
q.Add(-beta, v0);
|
||||
@@ -1693,7 +1694,7 @@ void MINRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
prec->Mult(v0, q);
|
||||
beta = sqrt(Dot(v0, q));
|
||||
}
|
||||
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
|
||||
MFEM_VERIFY(IsFinite(beta), "beta = " << beta);
|
||||
rho1 = std::hypot(delta, beta);
|
||||
|
||||
if (it == 1)
|
||||
@@ -1719,7 +1720,7 @@ void MINRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
sigma1 = beta/rho1;
|
||||
|
||||
eta = -sigma1*eta;
|
||||
MFEM_ASSERT(IsFinite(eta), "eta = " << eta);
|
||||
MFEM_VERIFY(IsFinite(eta), "eta = " << eta);
|
||||
|
||||
if (fabs(eta) <= norm_goal)
|
||||
{
|
||||
@@ -1812,7 +1813,7 @@ void NewtonSolver::SetOperator(const Operator &op)
|
||||
oper = &op;
|
||||
height = op.Height();
|
||||
width = op.Width();
|
||||
MFEM_ASSERT(height == width, "square Operator is required.");
|
||||
MFEM_VERIFY(height == width, "square Operator is required.");
|
||||
|
||||
r.SetSize(width);
|
||||
c.SetSize(width);
|
||||
@@ -1820,8 +1821,8 @@ void NewtonSolver::SetOperator(const Operator &op)
|
||||
|
||||
void NewtonSolver::Mult(const Vector &b, Vector &x) const
|
||||
{
|
||||
MFEM_ASSERT(oper != NULL, "the Operator is not set (use SetOperator).");
|
||||
MFEM_ASSERT(prec != NULL, "the Solver is not set (use SetSolver).");
|
||||
MFEM_VERIFY(oper != NULL, "the Operator is not set (use SetOperator).");
|
||||
MFEM_VERIFY(prec != NULL, "the Solver is not set (use SetSolver).");
|
||||
|
||||
int it;
|
||||
real_t norm0, norm, norm_goal;
|
||||
@@ -1853,7 +1854,7 @@ void NewtonSolver::Mult(const Vector &b, Vector &x) const
|
||||
// x_{i+1} = x_i - [DF(x_i)]^{-1} [F(x_i)-b]
|
||||
for (it = 0; true; it++)
|
||||
{
|
||||
MFEM_ASSERT(IsFinite(norm), "norm = " << norm);
|
||||
MFEM_VERIFY(IsFinite(norm), "norm = " << norm);
|
||||
if (print_options.iterations)
|
||||
{
|
||||
mfem::out << "Newton iteration " << setw(2) << it
|
||||
@@ -2047,7 +2048,7 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const
|
||||
norm_goal = std::max(rel_tol*norm, abs_tol);
|
||||
for (it = 0; true; it++)
|
||||
{
|
||||
MFEM_ASSERT(IsFinite(norm), "norm = " << norm);
|
||||
MFEM_VERIFY(IsFinite(norm), "norm = " << norm);
|
||||
if (print_options.iterations)
|
||||
{
|
||||
mfem::out << "LBFGS iteration " << it
|
||||
@@ -2309,14 +2310,14 @@ OptimizationProblem::OptimizationProblem(const int insize,
|
||||
: C(C_), D(D_), c_e(NULL), d_lo(NULL), d_hi(NULL), x_lo(NULL), x_hi(NULL),
|
||||
input_size(insize)
|
||||
{
|
||||
if (C) { MFEM_ASSERT(C->Width() == input_size, "Wrong width of C."); }
|
||||
if (D) { MFEM_ASSERT(D->Width() == input_size, "Wrong width of D."); }
|
||||
if (C) { MFEM_VERIFY(C->Width() == input_size, "Wrong width of C."); }
|
||||
if (D) { MFEM_VERIFY(D->Width() == input_size, "Wrong width of D."); }
|
||||
}
|
||||
|
||||
void OptimizationProblem::SetEqualityConstraint(const Vector &c)
|
||||
{
|
||||
MFEM_ASSERT(C, "The C operator is unspecified -- can't set constraints.");
|
||||
MFEM_ASSERT(c.Size() == C->Height(), "Wrong size of the constraint.");
|
||||
MFEM_VERIFY(C, "The C operator is unspecified -- can't set constraints.");
|
||||
MFEM_VERIFY(c.Size() == C->Height(), "Wrong size of the constraint.");
|
||||
|
||||
c_e = &c;
|
||||
}
|
||||
@@ -2324,8 +2325,8 @@ void OptimizationProblem::SetEqualityConstraint(const Vector &c)
|
||||
void OptimizationProblem::SetInequalityConstraint(const Vector &dl,
|
||||
const Vector &dh)
|
||||
{
|
||||
MFEM_ASSERT(D, "The D operator is unspecified -- can't set constraints.");
|
||||
MFEM_ASSERT(dl.Size() == D->Height() && dh.Size() == D->Height(),
|
||||
MFEM_VERIFY(D, "The D operator is unspecified -- can't set constraints.");
|
||||
MFEM_VERIFY(dl.Size() == D->Height() && dh.Size() == D->Height(),
|
||||
"Wrong size of the constraint.");
|
||||
|
||||
d_lo = &dl; d_hi = &dh;
|
||||
@@ -2333,7 +2334,7 @@ void OptimizationProblem::SetInequalityConstraint(const Vector &dl,
|
||||
|
||||
void OptimizationProblem::SetSolutionBounds(const Vector &xl, const Vector &xh)
|
||||
{
|
||||
MFEM_ASSERT(xl.Size() == input_size && xh.Size() == input_size,
|
||||
MFEM_VERIFY(xl.Size() == input_size && xh.Size() == input_size,
|
||||
"Wrong size of the constraint.");
|
||||
|
||||
x_lo = &xl; x_hi = &xh;
|
||||
@@ -2354,8 +2355,8 @@ void SLBQPOptimizer::SetOptimizationProblem(const OptimizationProblem &prob)
|
||||
MFEM_WARNING("Objective functional is ignored as SLBQP always minimizes"
|
||||
"the l2 norm of (x - x_target).");
|
||||
}
|
||||
MFEM_ASSERT(prob.GetC(), "Linear constraint is not set.");
|
||||
MFEM_ASSERT(prob.GetC()->Height() == 1, "Solver expects scalar constraint.");
|
||||
MFEM_VERIFY(prob.GetC(), "Linear constraint is not set.");
|
||||
MFEM_VERIFY(prob.GetC()->Height() == 1, "Solver expects scalar constraint.");
|
||||
|
||||
problem = &prob;
|
||||
}
|
||||
@@ -2786,7 +2787,7 @@ void BlockILU::SetOperator(const Operator &op)
|
||||
}
|
||||
height = op.Height();
|
||||
width = op.Width();
|
||||
MFEM_ASSERT(A->Finalized(), "Matrix must be finalized.");
|
||||
MFEM_VERIFY(A->Finalized(), "Matrix must be finalized.");
|
||||
CreateBlockPattern(*A);
|
||||
Factorize();
|
||||
}
|
||||
@@ -2997,7 +2998,7 @@ void BlockILU::Factorize()
|
||||
|
||||
void BlockILU::Mult(const Vector &b, Vector &x) const
|
||||
{
|
||||
MFEM_ASSERT(height > 0, "BlockILU(0) preconditioner is not constructed");
|
||||
MFEM_VERIFY(height > 0, "BlockILU(0) preconditioner is not constructed");
|
||||
int nblockrows = Height()/block_size;
|
||||
y.SetSize(Height());
|
||||
|
||||
@@ -3292,7 +3293,7 @@ void KLUSolver::SetOperator(const Operator &op)
|
||||
{
|
||||
if (Numeric)
|
||||
{
|
||||
MFEM_ASSERT(Symbolic != 0,
|
||||
MFEM_VERIFY(Symbolic != 0,
|
||||
"Had Numeric pointer in KLU, but not Symbolic");
|
||||
klu_free_symbolic(&Symbolic, &Common);
|
||||
Symbolic = 0;
|
||||
@@ -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;
|
||||
|
||||
+74
-11
@@ -1267,24 +1267,32 @@ real_t SparseMatrix::InnerProduct(const Vector &x, const Vector &y) const
|
||||
|
||||
void SparseMatrix::GetRowSums(Vector &x) const
|
||||
{
|
||||
for (int i = 0; i < height; i++)
|
||||
if (Finalized())
|
||||
{
|
||||
real_t a = 0.0;
|
||||
if (A)
|
||||
auto d_I = ReadI();
|
||||
auto d_A = ReadData();
|
||||
auto d_x = x.Write();
|
||||
mfem::forall(height, [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
for (int j = I[i], end = I[i+1]; j < end; j++)
|
||||
real_t sum = 0.0;
|
||||
for (int j = d_I[i], end = d_I[i+1]; j < end; j++)
|
||||
{
|
||||
a += A[j];
|
||||
sum += d_A[j];
|
||||
}
|
||||
}
|
||||
else
|
||||
d_x[i] = sum;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
real_t a = 0.0;
|
||||
for (RowNode *np = Rows[i]; np != NULL; np = np->Prev)
|
||||
{
|
||||
a += np->Value;
|
||||
}
|
||||
x(i) = a;
|
||||
}
|
||||
x(i) = a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3300,7 +3308,7 @@ void SparseMatrix::Print(std::ostream & os, int width_) const
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (A == NULL)
|
||||
if (A.Empty())
|
||||
{
|
||||
RowNode *nd;
|
||||
for (i = 0; i < height; i++)
|
||||
@@ -3354,7 +3362,7 @@ void SparseMatrix::PrintMatlab(std::ostream & os) const
|
||||
os.setf(ios::scientific);
|
||||
std::streamsize old_prec = os.precision(14);
|
||||
|
||||
if (A == NULL)
|
||||
if (A.Empty())
|
||||
{
|
||||
RowNode *nd;
|
||||
for (i = 0; i < height; i++)
|
||||
@@ -3385,6 +3393,61 @@ void SparseMatrix::PrintMatlab(std::ostream & os) const
|
||||
os.flags(old_fmt);
|
||||
}
|
||||
|
||||
void SparseMatrix::PrintMathematica(std::ostream & os) const
|
||||
{
|
||||
int i, j;
|
||||
ios::fmtflags old_fmt = os.flags();
|
||||
os.setf(ios::scientific);
|
||||
std::streamsize old_prec = os.precision(14);
|
||||
|
||||
os << "(* Read file into Mathematica using: "
|
||||
<< "my_mat = Get[\"this_file_name\"] *)\n";
|
||||
os << "SparseArray[";
|
||||
|
||||
if (A == NULL)
|
||||
{
|
||||
RowNode *nd;
|
||||
int c = 0;
|
||||
os << "{\n";
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
for (nd = Rows[i], j = 0; nd != NULL; nd = nd->Prev, j++, c++)
|
||||
{
|
||||
os << "{"<< i+1 << ", " << nd->Column+1
|
||||
<< "} -> Internal`StringToMReal[\"" << nd->Value << "\"]";
|
||||
if (c < NumNonZeroElems() - 1) { os << ","; }
|
||||
os << '\n';
|
||||
}
|
||||
}
|
||||
os << "}\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
// HostRead forces synchronization
|
||||
HostReadI();
|
||||
HostReadJ();
|
||||
HostReadData();
|
||||
int c = 0;
|
||||
os << "{\n";
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
for (j = I[i]; j < I[i+1]; j++, c++)
|
||||
{
|
||||
os << "{" << i+1 << ", " << J[j]+1
|
||||
<< "} -> Internal`StringToMReal[\"" << A[j] << "\"]";
|
||||
if (c < NumNonZeroElems() - 1) { os << ","; }
|
||||
os << '\n';
|
||||
}
|
||||
}
|
||||
os << "}";
|
||||
}
|
||||
|
||||
os << ",{" << height << "," << width << "}]\n";
|
||||
|
||||
os.precision(old_prec);
|
||||
os.flags(old_fmt);
|
||||
}
|
||||
|
||||
void SparseMatrix::PrintMM(std::ostream & os) const
|
||||
{
|
||||
int i, j;
|
||||
@@ -3397,7 +3460,7 @@ void SparseMatrix::PrintMM(std::ostream & os) const
|
||||
|
||||
os << height << " " << width << " " << NumNonZeroElems() << '\n';
|
||||
|
||||
if (A == NULL)
|
||||
if (A.Empty())
|
||||
{
|
||||
RowNode *nd;
|
||||
for (i = 0; i < height; i++)
|
||||
|
||||
+14
-1
@@ -216,7 +216,7 @@ public:
|
||||
void ClearCuSparse() { ClearGPUSparse(); }
|
||||
|
||||
/// Check if the SparseMatrix is empty.
|
||||
bool Empty() const { return (A == NULL) && (Rows == NULL); }
|
||||
bool Empty() const { return A.Empty() && (Rows == NULL); }
|
||||
|
||||
/// Return the array #I.
|
||||
inline int *GetI() { return I; }
|
||||
@@ -657,6 +657,19 @@ public:
|
||||
/** @note The host in synchronized when the finalized matrix is on the device. */
|
||||
virtual void PrintMatlab(std::ostream &out = mfem::out) const;
|
||||
|
||||
/// Prints matrix as a SparseArray for importing into Mathematica.
|
||||
/** The resulting file can be read into Mathematica using an expression such
|
||||
as: my_mat = Get["output_file_name"]
|
||||
The Mathematica variable "my_mat" will then be assigned to a new
|
||||
SparseArray object containing the data from this MFEM SparseMatrix.
|
||||
|
||||
@note Mathematica uses 1-based indexing so the MFEM row and column
|
||||
indices will be sifted up by one in the Mathematica output.
|
||||
|
||||
@note The host in synchronized when the finalized matrix is on the
|
||||
device. */
|
||||
virtual void PrintMathematica(std::ostream &out = mfem::out) const;
|
||||
|
||||
/// Prints matrix in Matrix Market sparse format.
|
||||
/** @note The host in synchronized when the finalized matrix is on the device. */
|
||||
void PrintMM(std::ostream &out = mfem::out) const;
|
||||
|
||||
+37
-10
@@ -1341,38 +1341,59 @@ CVODESSolver::~CVODESSolver()
|
||||
// ARKStep interface
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int ARKStepSolver::RHS1(realtype t, const N_Vector y, N_Vector ydot,
|
||||
int ARKStepSolver::RHS1(realtype t, const N_Vector y, N_Vector result,
|
||||
void *user_data)
|
||||
{
|
||||
// Get data from N_Vectors
|
||||
const SundialsNVector mfem_y(y);
|
||||
SundialsNVector mfem_ydot(ydot);
|
||||
SundialsNVector mfem_result(result);
|
||||
ARKStepSolver *self = static_cast<ARKStepSolver*>(user_data);
|
||||
|
||||
// Compute f(t, y) in y' = f(t, y) or fe(t, y) in y' = fe(t, y) + fi(t, y)
|
||||
// Compute either f(t, y) in one of
|
||||
// 1. y' = f(t, y)
|
||||
// 2. M y' = f(t, y)
|
||||
// or fe(t, y) in one of
|
||||
// 1. y' = fe(t, y) + fi(t, y)
|
||||
// 2. M y' = fe(t, y) + fi(t, y)
|
||||
self->f->SetTime(t);
|
||||
if (self->rk_type == IMEX)
|
||||
{
|
||||
self->f->SetEvalMode(TimeDependentOperator::ADDITIVE_TERM_1);
|
||||
}
|
||||
self->f->Mult(mfem_y, mfem_ydot);
|
||||
if (self->f->isExplicit()) // ODE is in form 1
|
||||
{
|
||||
self->f->Mult(mfem_y, mfem_result);
|
||||
}
|
||||
else // ODE is in form 2
|
||||
{
|
||||
self->f->ExplicitMult(mfem_y, mfem_result);
|
||||
}
|
||||
|
||||
// Return success
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ARKStepSolver::RHS2(realtype t, const N_Vector y, N_Vector ydot,
|
||||
int ARKStepSolver::RHS2(realtype t, const N_Vector y, N_Vector result,
|
||||
void *user_data)
|
||||
{
|
||||
// Get data from N_Vectors
|
||||
const SundialsNVector mfem_y(y);
|
||||
SundialsNVector mfem_ydot(ydot);
|
||||
SundialsNVector mfem_result(result);
|
||||
ARKStepSolver *self = static_cast<ARKStepSolver*>(user_data);
|
||||
|
||||
// Compute fi(t, y) in y' = fe(t, y) + fi(t, y)
|
||||
// Compute fi(t, y) in one of
|
||||
// 1. y' = fe(t, y) + fi(t, y) (ODE is expressed in EXPLICIT form)
|
||||
// 2. M y' = fe(t, y) + fi(y, t) (ODE is expressed in IMPLICIT form)
|
||||
self->f->SetTime(t);
|
||||
self->f->SetEvalMode(TimeDependentOperator::ADDITIVE_TERM_2);
|
||||
self->f->Mult(mfem_y, mfem_ydot);
|
||||
if (self->f->isExplicit())
|
||||
{
|
||||
self->f->Mult(mfem_y, mfem_result);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->f->ExplicitMult(mfem_y, mfem_result);
|
||||
}
|
||||
|
||||
// Return success
|
||||
return (0);
|
||||
@@ -1567,7 +1588,7 @@ void ARKStepSolver::Init(TimeDependentOperator &f_)
|
||||
reinit = true;
|
||||
}
|
||||
|
||||
void ARKStepSolver::Step(Vector &x, double &t, double &dt)
|
||||
void ARKStepSolver::Step(Vector &x, real_t &t, real_t &dt)
|
||||
{
|
||||
Y->MakeRef(x, 0, x.Size());
|
||||
MFEM_VERIFY(Y->Size() == x.Size(), "size mismatch");
|
||||
@@ -1666,7 +1687,7 @@ void ARKStepSolver::UseMFEMMassLinearSolver(int tdep)
|
||||
LSM->content = this;
|
||||
LSM->ops->gettype = LSGetType;
|
||||
LSM->ops->solve = ARKStepSolver::MassSysSolve;
|
||||
LSA->ops->free = LSFree;
|
||||
LSM->ops->free = LSFree;
|
||||
|
||||
M = SUNMatNewEmpty(Sundials::GetContext());
|
||||
MFEM_VERIFY(M, "error in SUNMatNewEmpty()");
|
||||
@@ -1683,6 +1704,9 @@ void ARKStepSolver::UseMFEMMassLinearSolver(int tdep)
|
||||
// Set the linear system function
|
||||
flag = ARKStepSetMassFn(sundials_mem, ARKStepSolver::MassSysSetup);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassFn()");
|
||||
|
||||
// Check that the ODE is not expressed in EXPLICIT form
|
||||
MFEM_VERIFY(!f->isExplicit(), "ODE operator is expressed in EXPLICIT form")
|
||||
}
|
||||
|
||||
void ARKStepSolver::UseSundialsMassLinearSolver(int tdep)
|
||||
@@ -1703,6 +1727,9 @@ void ARKStepSolver::UseSundialsMassLinearSolver(int tdep)
|
||||
flag = ARKStepSetMassTimes(sundials_mem, NULL, ARKStepSolver::MassMult2,
|
||||
this);
|
||||
MFEM_VERIFY(flag == ARK_SUCCESS, "error in ARKStepSetMassTimes()");
|
||||
|
||||
// Check that the ODE is not expressed in EXPLICIT form
|
||||
MFEM_VERIFY(!f->isExplicit(), "ODE operator is expressed in EXPLICIT form")
|
||||
}
|
||||
|
||||
void ARKStepSolver::SetStepMode(int itask)
|
||||
|
||||
+1
-1
@@ -763,7 +763,7 @@ public:
|
||||
@note On input, the values of @a t and @a dt are used to compute desired
|
||||
output time for the integration, tout = @a t + @a dt.
|
||||
*/
|
||||
virtual void Step(Vector &x, double &t, double &dt);
|
||||
virtual void Step(Vector &x, real_t &t, real_t &dt) override;
|
||||
|
||||
/** @brief Attach the linear system setup and solve methods from the
|
||||
TimeDependentOperator i.e., SUNImplicitSetup() and SUNImplicitSolve() to
|
||||
|
||||
@@ -193,7 +193,8 @@ endif
|
||||
|
||||
# Compile flags used by MFEM: CPPFLAGS, CXXFLAGS, plus library flags
|
||||
INCFLAGS =
|
||||
# Link flags used by MFEM: library link flags plus LDFLAGS (added last)
|
||||
# Link flags used by MFEM: library link flags plus LDFLAGS and LDFLAGS_INTERNAL
|
||||
# (added at the end)
|
||||
ALL_LIBS =
|
||||
|
||||
# Building static and/or shared libraries:
|
||||
@@ -372,7 +373,7 @@ MFEM_TPLFLAGS ?= $(INCFLAGS)
|
||||
MFEM_INCFLAGS ?= -I@MFEM_INC_DIR@ @MFEM_TPLFLAGS@
|
||||
MFEM_PICFLAG ?= $(if $(shared),$(PICFLAG))
|
||||
MFEM_FLAGS ?= @MFEM_CPPFLAGS@ @MFEM_CXXFLAGS@ @MFEM_INCFLAGS@
|
||||
MFEM_EXT_LIBS ?= $(ALL_LIBS) $(LDFLAGS)
|
||||
MFEM_EXT_LIBS ?= $(ALL_LIBS) $(LDFLAGS) $(LDFLAGS_INTERNAL)
|
||||
MFEM_LIBS ?= $(if $(shared),$(BUILD_RPATH)) -L@MFEM_LIB_DIR@ -lmfem\
|
||||
@MFEM_EXT_LIBS@
|
||||
MFEM_LIB_FILE ?= @MFEM_LIB_DIR@/libmfem.$(if $(shared),$(SO_VER),a)
|
||||
@@ -581,53 +582,77 @@ clean: $(addsuffix /clean,$(EM_DIRS) $(TEST_DIRS))
|
||||
distclean: clean config/clean doc/clean
|
||||
rm -rf mfem/
|
||||
|
||||
# User-definable install permissions.
|
||||
# Install permissions for everything except directories and binaries:
|
||||
INSTALL_DEF_PERM ?= 644
|
||||
# Install permissions for binaries:
|
||||
INSTALL_BIN_PERM ?= 755
|
||||
# Install permissions for directories (and symlinks on macOS/BSD):
|
||||
INSTALL_DIR_PERM ?= 755
|
||||
|
||||
# Shortcuts, not to be modified by the user on the command line.
|
||||
# We use 'umask' because 'mkdir -p' (and 'install -d') do not use the mode
|
||||
# specified with the '-m' flag when creating non-existent parent directories.
|
||||
# WARNING: $(MKINSTALLDIR) changes the umask for commands following it as part
|
||||
# of the same shell expression unless it is placed inside '()' to be
|
||||
# executed in a sub-shell.
|
||||
override INSTALLDEF = $(INSTALL) -m $(INSTALL_DEF_PERM)
|
||||
override INSTALLMASK = $(shell printf "%o" $$((~0$(INSTALL_DIR_PERM) & 0777)))
|
||||
override MKINSTALLDIR = umask $(INSTALLMASK) && mkdir -p
|
||||
|
||||
INSTALL_SHARED_LIB = $(MFEM_CXX) $(MFEM_LINK_FLAGS) $(INSTALL_SOFLAGS)\
|
||||
$(OBJECT_FILES) $(EXT_LIBS) -o $(PREFIX_LIB)/libmfem.$(SO_VER) && \
|
||||
cd $(PREFIX_LIB) && ln -sf libmfem.$(SO_VER) libmfem.$(SO_EXT)
|
||||
cd $(PREFIX_LIB) && chmod $(INSTALL_BIN_PERM) libmfem.$(SO_VER) && \
|
||||
( umask $(INSTALLMASK) && ln -sf libmfem.$(SO_VER) libmfem.$(SO_EXT) )
|
||||
|
||||
install: $(if $(static),$(BLD)libmfem.a) $(if $(shared),$(BLD)libmfem.$(SO_EXT))
|
||||
mkdir -p $(PREFIX_LIB)
|
||||
$(MKINSTALLDIR) $(PREFIX_LIB)
|
||||
# install static and/or shared library
|
||||
$(if $(static),$(INSTALL) -m 640 $(BLD)libmfem.a $(PREFIX_LIB))
|
||||
$(if $(static),$(INSTALLDEF) $(BLD)libmfem.a $(PREFIX_LIB))
|
||||
$(if $(shared),$(INSTALL_SHARED_LIB))
|
||||
# install top level includes
|
||||
mkdir -p $(PREFIX_INC)/mfem
|
||||
$(INSTALL) -m 640 $(SRC)mfem.hpp $(SRC)mfem-performance.hpp \
|
||||
$(MKINSTALLDIR) $(PREFIX_INC)/mfem
|
||||
$(INSTALLDEF) $(SRC)mfem.hpp $(SRC)mfem-performance.hpp \
|
||||
$(PREFIX_INC)/mfem
|
||||
for hdr in mfem.hpp mfem-performance.hpp; do \
|
||||
printf '// Auto-generated file.\n#include "mfem/'$$hdr'"\n' \
|
||||
> $(PREFIX_INC)/$$hdr && chmod 640 $(PREFIX_INC)/$$hdr; done
|
||||
> $(PREFIX_INC)/$$hdr && \
|
||||
chmod $(INSTALL_DEF_PERM) $(PREFIX_INC)/$$hdr; done
|
||||
# install config include
|
||||
mkdir -p $(PREFIX_INC)/mfem/config
|
||||
$(INSTALL) -m 640 $(BLD)config/_config.hpp $(PREFIX_INC)/mfem/config/_config.hpp
|
||||
$(INSTALL) -m 640 $(SRC)config/config.hpp $(PREFIX_INC)/mfem/config/config.hpp
|
||||
$(INSTALL) -m 640 $(SRC)config/tconfig.hpp $(PREFIX_INC)/mfem/config
|
||||
$(MKINSTALLDIR) $(PREFIX_INC)/mfem/config
|
||||
$(INSTALLDEF) $(BLD)config/_config.hpp $(PREFIX_INC)/mfem/config
|
||||
$(INSTALLDEF) $(SRC)config/config.hpp $(PREFIX_INC)/mfem/config
|
||||
$(INSTALLDEF) $(SRC)config/tconfig.hpp $(PREFIX_INC)/mfem/config
|
||||
# install remaining includes in each subdirectory
|
||||
for dir in $(DIRS); do \
|
||||
mkdir -p $(PREFIX_INC)/mfem/$$dir && \
|
||||
$(INSTALL) -m 640 $(SRC)$$dir/*.hpp $(PREFIX_INC)/mfem/$$dir; \
|
||||
( $(MKINSTALLDIR) $(PREFIX_INC)/mfem/$$dir ) && \
|
||||
$(INSTALLDEF) $(SRC)$$dir/*.hpp $(PREFIX_INC)/mfem/$$dir; \
|
||||
done
|
||||
# install *.okl files
|
||||
for dir in $(OKL_DIRS); do \
|
||||
mkdir -p $(PREFIX_INC)/mfem/$$dir && \
|
||||
$(INSTALL) -m 640 $(SRC)$$dir/*.okl $(PREFIX_INC)/mfem/$$dir; \
|
||||
( $(MKINSTALLDIR) $(PREFIX_INC)/mfem/$$dir ) && \
|
||||
$(INSTALLDEF) $(SRC)$$dir/*.okl $(PREFIX_INC)/mfem/$$dir; \
|
||||
done
|
||||
# install libCEED q-function headers
|
||||
mkdir -p $(PREFIX_INC)/mfem/fem/ceed/integrators/mass
|
||||
$(INSTALL) -m 640 $(SRC)fem/ceed/integrators/mass/*.h $(PREFIX_INC)/mfem/fem/ceed/integrators/mass
|
||||
mkdir -p $(PREFIX_INC)/mfem/fem/ceed/integrators/convection
|
||||
$(INSTALL) -m 640 $(SRC)fem/ceed/integrators/convection/*.h $(PREFIX_INC)/mfem/fem/ceed/integrators/convection
|
||||
mkdir -p $(PREFIX_INC)/mfem/fem/ceed/integrators/diffusion
|
||||
$(INSTALL) -m 640 $(SRC)fem/ceed/integrators/diffusion/*.h $(PREFIX_INC)/mfem/fem/ceed/integrators/diffusion
|
||||
mkdir -p $(PREFIX_INC)/mfem/fem/ceed/integrators/nlconvection
|
||||
$(INSTALL) -m 640 $(SRC)fem/ceed/integrators/nlconvection/*.h $(PREFIX_INC)/mfem/fem/ceed/integrators/nlconvection
|
||||
$(MKINSTALLDIR) $(PREFIX_INC)/mfem/fem/ceed/integrators/mass
|
||||
$(INSTALLDEF) $(SRC)fem/ceed/integrators/mass/*.h \
|
||||
$(PREFIX_INC)/mfem/fem/ceed/integrators/mass
|
||||
$(MKINSTALLDIR) $(PREFIX_INC)/mfem/fem/ceed/integrators/convection
|
||||
$(INSTALLDEF) $(SRC)fem/ceed/integrators/convection/*.h \
|
||||
$(PREFIX_INC)/mfem/fem/ceed/integrators/convection
|
||||
$(MKINSTALLDIR) $(PREFIX_INC)/mfem/fem/ceed/integrators/diffusion
|
||||
$(INSTALLDEF) $(SRC)fem/ceed/integrators/diffusion/*.h \
|
||||
$(PREFIX_INC)/mfem/fem/ceed/integrators/diffusion
|
||||
$(MKINSTALLDIR) $(PREFIX_INC)/mfem/fem/ceed/integrators/nlconvection
|
||||
$(INSTALLDEF) $(SRC)fem/ceed/integrators/nlconvection/*.h \
|
||||
$(PREFIX_INC)/mfem/fem/ceed/integrators/nlconvection
|
||||
# install config.mk in $(PREFIX_SHARE)
|
||||
mkdir -p $(PREFIX_SHARE)
|
||||
$(MKINSTALLDIR) $(PREFIX_SHARE)
|
||||
$(MAKE) -C $(BLD)config config-mk CONFIG_MK=config-install.mk
|
||||
$(INSTALL) -m 640 $(BLD)config/config-install.mk $(PREFIX_SHARE)/config.mk
|
||||
$(INSTALLDEF) $(BLD)config/config-install.mk $(PREFIX_SHARE)/config.mk
|
||||
rm -f $(BLD)config/config-install.mk
|
||||
# install test.mk in $(PREFIX_SHARE)
|
||||
$(INSTALL) -m 640 $(SRC)config/test.mk $(PREFIX_SHARE)/test.mk
|
||||
$(INSTALLDEF) $(SRC)config/test.mk $(PREFIX_SHARE)
|
||||
|
||||
$(CONFIG_MK):
|
||||
# Skip the error message when '-B' make flag is used (unconditionally
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
set(SRCS
|
||||
attribute_sets.cpp
|
||||
element.cpp
|
||||
exodus_writer.cpp
|
||||
face_nbr_geom.cpp
|
||||
gmsh.cpp
|
||||
hexahedron.cpp
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+49
-16
@@ -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;
|
||||
@@ -13600,22 +13632,23 @@ Mesh &MeshPart::GetMesh()
|
||||
|
||||
MeshPartitioner::MeshPartitioner(Mesh &mesh_,
|
||||
int num_parts_,
|
||||
int *partitioning_,
|
||||
const int *partitioning_,
|
||||
int part_method)
|
||||
: mesh(mesh_)
|
||||
{
|
||||
if (partitioning_)
|
||||
{
|
||||
partitioning.MakeRef(partitioning_, mesh.GetNE(), false);
|
||||
partitioning.MakeRef(const_cast<int *>(partitioning_), mesh.GetNE(),
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
partitioning_ = mesh.GeneratePartitioning(num_parts_, part_method);
|
||||
// Mesh::GeneratePartitioning always uses new[] to allocate the,
|
||||
// partitioning, so we need to tell the memory manager to free it with
|
||||
// delete[] (even if a different host memory type has been selected).
|
||||
const MemoryType mt = MemoryType::HOST;
|
||||
partitioning.MakeRef(partitioning_, mesh.GetNE(), mt, true);
|
||||
constexpr MemoryType mt = MemoryType::HOST;
|
||||
partitioning.MakeRef(mesh.GeneratePartitioning(num_parts_, part_method),
|
||||
mesh.GetNE(), mt, true);
|
||||
}
|
||||
|
||||
Transpose(partitioning, part_to_element, num_parts_);
|
||||
|
||||
+10
-2
@@ -1537,6 +1537,9 @@ public:
|
||||
/// @note The returned Table should be deleted by the caller
|
||||
Table *GetVertexToElementTable();
|
||||
|
||||
/// @note The returned Table should be deleted by the caller
|
||||
Table *GetVertexToBdrElementTable();
|
||||
|
||||
/// Return the "face"-element Table. Here "face" refers to face (3D),
|
||||
/// edge (2D), or vertex (1D).
|
||||
///
|
||||
@@ -2331,6 +2334,11 @@ public:
|
||||
bool high_order_output=false,
|
||||
int compression_level=0);
|
||||
|
||||
#ifdef MFEM_USE_NETCDF
|
||||
/// @brief Export a mesh to an Exodus II file.
|
||||
void PrintExodusII(const std::string fpath);
|
||||
#endif
|
||||
|
||||
/** @brief Prints the mesh with boundary elements given by the boundary of
|
||||
the subdomains, so that the boundary of subdomain i has boundary
|
||||
attribute i+1. */
|
||||
@@ -2728,8 +2736,8 @@ public:
|
||||
Mesh::GeneratePartitioning() when the provided
|
||||
input partitioning is NULL.
|
||||
*/
|
||||
MeshPartitioner(Mesh &mesh_, int num_parts_, int *partitioning_ = NULL,
|
||||
int part_method = 1);
|
||||
MeshPartitioner(Mesh &mesh_, int num_parts_,
|
||||
const int *partitioning_ = nullptr, int part_method = 1);
|
||||
|
||||
/** @brief Construct a MeshPart corresponding to the given @a part_id.
|
||||
|
||||
|
||||
+109
-30
@@ -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++)
|
||||
@@ -4722,19 +4807,15 @@ const Array<int>& NURBSExtension::GetPatchBdrElements(int patch)
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParNURBSExtension::ParNURBSExtension(const ParNURBSExtension &orig)
|
||||
: NURBSExtension(orig),
|
||||
partitioning(orig.partitioning ? new int[orig.GetGNE()] : NULL),
|
||||
partitioning(orig.partitioning),
|
||||
gtopo(orig.gtopo),
|
||||
ldof_group(orig.ldof_group)
|
||||
{
|
||||
// Copy the partitioning, if not NULL
|
||||
if (partitioning)
|
||||
{
|
||||
std::memcpy(partitioning, orig.partitioning, orig.GetGNE()*sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
ParNURBSExtension::ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent,
|
||||
int *part, const Array<bool> &active_bel)
|
||||
const int *partitioning_,
|
||||
const Array<bool> &active_bel)
|
||||
: gtopo(comm)
|
||||
{
|
||||
if (parent->NumOfActiveElems < parent->NumOfElements)
|
||||
@@ -4772,11 +4853,11 @@ ParNURBSExtension::ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent,
|
||||
CountElements();
|
||||
CountBdrElements();
|
||||
|
||||
// copy 'part' to 'partitioning'
|
||||
partitioning = new int[GetGNE()];
|
||||
// copy 'partitioning_' to 'partitioning'
|
||||
partitioning.SetSize(GetGNE());
|
||||
for (int i = 0; i < GetGNE(); i++)
|
||||
{
|
||||
partitioning[i] = part[i];
|
||||
partitioning[i] = partitioning_[i];
|
||||
}
|
||||
SetActive(partitioning, active_bel);
|
||||
|
||||
@@ -4867,8 +4948,6 @@ ParNURBSExtension::ParNURBSExtension(NURBSExtension *parent,
|
||||
|
||||
delete parent;
|
||||
|
||||
partitioning = NULL;
|
||||
|
||||
MFEM_VERIFY(par_parent->partitioning,
|
||||
"parent ParNURBSExtension has no partitioning!");
|
||||
|
||||
|
||||
+34
-11
@@ -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]; }
|
||||
|
||||
@@ -872,7 +895,7 @@ class ParNURBSExtension : public NURBSExtension
|
||||
{
|
||||
private:
|
||||
/// Partitioning of the global elements by MPI rank
|
||||
int *partitioning;
|
||||
mfem::Array<int> partitioning;
|
||||
|
||||
/// Construct and return a table of DOFs for each global element.
|
||||
Table *GetGlobalElementDofTable();
|
||||
@@ -882,9 +905,10 @@ private:
|
||||
|
||||
/** @brief Set active global elements and boundary elements based on MPI
|
||||
ranks in @a partition and the array @a active_bel. */
|
||||
void SetActive(const int *partition, const Array<bool> &active_bel);
|
||||
void SetActive(const int *partitioning_, const Array<bool> &active_bel);
|
||||
|
||||
/// Set up GroupTopology @a gtopo for MPI communication.
|
||||
void BuildGroups(const int *partition, const Table &elem_dof);
|
||||
void BuildGroups(const int *partitioning_, const Table &elem_dof);
|
||||
|
||||
public:
|
||||
GroupTopology gtopo;
|
||||
@@ -895,11 +919,12 @@ public:
|
||||
ParNURBSExtension(const ParNURBSExtension &orig);
|
||||
|
||||
/** @brief Constructor for an MPI communicator @a comm, a global
|
||||
NURBSExtension @a parent, a partitioning @a part of the global elements
|
||||
by MPI rank, and a marker @a active_bel of active global boundary
|
||||
elements on this rank. The partitioning is deep-copied and will not be
|
||||
deleted by this object. */
|
||||
ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent, int *part,
|
||||
NURBSExtension @a parent, a partitioning @a partitioning_ of the global
|
||||
elements by MPI rank, and a marker @a active_bel of active global
|
||||
boundary elements on this rank. The partitioning is deep-copied and will
|
||||
not be deleted by this object. */
|
||||
ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent,
|
||||
const int *partitioning_,
|
||||
const Array<bool> &active_bel);
|
||||
|
||||
/** @brief Create a parallel version of @a parent with partitioning as in
|
||||
@@ -907,8 +932,6 @@ public:
|
||||
The @a parent can be either a local NURBSExtension or a global one. */
|
||||
ParNURBSExtension(NURBSExtension *parent,
|
||||
const ParNURBSExtension *par_parent);
|
||||
|
||||
virtual ~ParNURBSExtension() { delete [] partitioning; }
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
+22
-23
@@ -103,29 +103,32 @@ ParMesh& ParMesh::operator=(ParMesh &&mesh)
|
||||
return *this;
|
||||
}
|
||||
|
||||
ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
|
||||
ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, const int *partitioning_,
|
||||
int part_method)
|
||||
: glob_elem_offset(-1)
|
||||
, glob_offset_sequence(-1)
|
||||
, gtopo(comm)
|
||||
{
|
||||
int *partitioning = NULL;
|
||||
Array<bool> activeBdrElem;
|
||||
|
||||
MyComm = comm;
|
||||
MPI_Comm_size(MyComm, &NRanks);
|
||||
MPI_Comm_rank(MyComm, &MyRank);
|
||||
|
||||
Array<int> partitioning;
|
||||
Array<bool> activeBdrElem;
|
||||
|
||||
if (partitioning_)
|
||||
{
|
||||
partitioning.MakeRef(const_cast<int *>(partitioning_), mesh.GetNE(),
|
||||
false);
|
||||
}
|
||||
|
||||
if (mesh.Nonconforming())
|
||||
{
|
||||
if (partitioning_)
|
||||
ncmesh = pncmesh = new ParNCMesh(comm, *mesh.ncmesh, partitioning_);
|
||||
|
||||
if (!partitioning_)
|
||||
{
|
||||
partitioning = partitioning_;
|
||||
}
|
||||
ncmesh = pncmesh = new ParNCMesh(comm, *mesh.ncmesh, partitioning);
|
||||
if (!partitioning)
|
||||
{
|
||||
partitioning = new int[mesh.GetNE()];
|
||||
partitioning.SetSize(mesh.GetNE());
|
||||
for (int i = 0; i < mesh.GetNE(); i++)
|
||||
{
|
||||
partitioning[i] = pncmesh->InitialPartition(i);
|
||||
@@ -158,13 +161,14 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
|
||||
|
||||
ncmesh = pncmesh = NULL;
|
||||
|
||||
if (partitioning_)
|
||||
if (!partitioning_)
|
||||
{
|
||||
partitioning = partitioning_;
|
||||
}
|
||||
else
|
||||
{
|
||||
partitioning = mesh.GeneratePartitioning(NRanks, part_method);
|
||||
// Mesh::GeneratePartitioning always uses new[] to allocate the,
|
||||
// partitioning, so we need to tell the memory manager to free it with
|
||||
// delete[] (even if a different host memory type has been selected).
|
||||
constexpr MemoryType mt = MemoryType::HOST;
|
||||
partitioning.MakeRef(mesh.GeneratePartitioning(NRanks, part_method),
|
||||
mesh.GetNE(), mt, true);
|
||||
}
|
||||
|
||||
// re-enumerate the partitions to better map to actual processor
|
||||
@@ -306,11 +310,6 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
|
||||
SetVerticesFromNodes(Nodes);
|
||||
}
|
||||
|
||||
if (partitioning != partitioning_)
|
||||
{
|
||||
delete [] partitioning;
|
||||
}
|
||||
|
||||
have_face_nbr_data = false;
|
||||
}
|
||||
|
||||
@@ -730,7 +729,7 @@ void ParMesh::BuildVertexGroup(int ngroups, const Table &vert_element)
|
||||
}
|
||||
|
||||
void ParMesh::BuildSharedFaceElems(int ntri_faces, int nquad_faces,
|
||||
const Mesh& mesh, int *partitioning,
|
||||
const Mesh& mesh, const int *partitioning,
|
||||
const STable3D *faces_tbl,
|
||||
const Array<int> &face_group,
|
||||
const Array<int> &vert_global_local)
|
||||
|
||||
+2
-4
@@ -241,7 +241,7 @@ protected:
|
||||
void BuildVertexGroup(int ngroups, const Table& vert_element);
|
||||
|
||||
void BuildSharedFaceElems(int ntri_faces, int nquad_faces,
|
||||
const Mesh &mesh, int *partitioning,
|
||||
const Mesh &mesh, const int *partitioning,
|
||||
const STable3D *faces_tbl,
|
||||
const Array<int> &face_group,
|
||||
const Array<int> &vert_global_local);
|
||||
@@ -343,7 +343,7 @@ public:
|
||||
meshes and quick space-filling curve equipartitioning for nonconforming
|
||||
meshes (elements of nonconforming meshes should ideally be ordered as a
|
||||
sequence of face-neighbors). */
|
||||
ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_ = NULL,
|
||||
ParMesh(MPI_Comm comm, Mesh &mesh, const int *partitioning_ = nullptr,
|
||||
int part_method = 1);
|
||||
|
||||
/** Copy constructor. Performs a deep copy of (almost) all data, so that the
|
||||
@@ -438,8 +438,6 @@ public:
|
||||
|
||||
ParNCMesh* pncmesh;
|
||||
|
||||
int *partitioning_cache = nullptr;
|
||||
|
||||
int GetNGroups() const { return gtopo.NGroups(); }
|
||||
|
||||
///@{ @name These methods require group > 0
|
||||
|
||||
+4
-2
@@ -28,7 +28,8 @@ namespace mfem
|
||||
|
||||
using namespace bin_io;
|
||||
|
||||
ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh, int *part)
|
||||
ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh,
|
||||
const int *partitioning)
|
||||
: NCMesh(ncmesh)
|
||||
{
|
||||
MyComm = comm;
|
||||
@@ -39,7 +40,8 @@ ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh, int *part)
|
||||
// sequence of leaf elements into 'NRanks' parts
|
||||
for (int i = 0; i < leaf_elements.Size(); i++)
|
||||
{
|
||||
elements[leaf_elements[i]].rank = part ? part[i] : InitialPartition(i);
|
||||
elements[leaf_elements[i]].rank =
|
||||
partitioning ? partitioning[i] : InitialPartition(i);
|
||||
}
|
||||
|
||||
Update();
|
||||
|
||||
+12
-8
@@ -67,7 +67,8 @@ public:
|
||||
/// Construct by partitioning a serial NCMesh.
|
||||
/** SFC partitioning is used by default. A user-specified partition can be
|
||||
passed in 'part', where part[i] is the desired MPI rank for element i. */
|
||||
ParNCMesh(MPI_Comm comm, const NCMesh& ncmesh, int* part = NULL);
|
||||
ParNCMesh(MPI_Comm comm, const NCMesh& ncmesh,
|
||||
const int *partitioning = nullptr);
|
||||
|
||||
/** Load from a stream, parallel version. See the serial NCMesh::NCMesh
|
||||
counterpart for a description of the parameters. */
|
||||
@@ -81,7 +82,8 @@ public:
|
||||
|
||||
/** An override of NCMesh::Refine, which is called eventually, after making
|
||||
sure that refinements that occur on the processor boundary are sent to
|
||||
the neighbor processors so they can keep their ghost layers up to date.*/
|
||||
the neighbor processors so they can keep their ghost layers up to
|
||||
date. */
|
||||
void Refine(const Array<Refinement> &refinements) override;
|
||||
|
||||
/// Parallel version of NCMesh::LimitNCLevel.
|
||||
@@ -229,8 +231,8 @@ public:
|
||||
const Table &deref_table);
|
||||
|
||||
/** Extension of NCMesh::GetBoundaryClosure. Filters out ghost vertices and
|
||||
ghost edges from 'bdr_vertices' and 'bdr_edges', and uncovers hidden internal
|
||||
boundary faces. */
|
||||
ghost edges from 'bdr_vertices' and 'bdr_edges', and uncovers hidden
|
||||
internal boundary faces. */
|
||||
void GetBoundaryClosure(const Array<int> &bdr_attr_is_ess,
|
||||
Array<int> &bdr_vertices,
|
||||
Array<int> &bdr_edges, Array<int> &bdr_faces) override;
|
||||
@@ -252,8 +254,9 @@ protected: // interface for ParMesh
|
||||
friend class ParMesh;
|
||||
|
||||
/** For compatibility with conforming code in ParMesh and ParFESpace.
|
||||
Initializes shared structures in ParMesh: gtopo, shared_*, group_s*, s*_l*.
|
||||
The ParMesh then acts as a parallel mesh cut along the NC interfaces. */
|
||||
Initializes shared structures in ParMesh: gtopo, shared_*, group_s*,
|
||||
s*_l*. The ParMesh then acts as a parallel mesh cut along the NC
|
||||
interfaces. */
|
||||
void GetConformingSharedStructures(class ParMesh &pmesh);
|
||||
|
||||
/** Populate face neighbor members of ParMesh from the ghost layer, without
|
||||
@@ -519,8 +522,9 @@ protected: // implementation
|
||||
owners, keeping the ghost layer up to date. Used by Rebalance() and
|
||||
Derefine(). 'target_elements' is the number of elements this rank
|
||||
is supposed to own after the exchange. If this number is not known
|
||||
a priori, the parameter can be set to -1, but more expensive communication
|
||||
(synchronous sends and a barrier) will be used in that case. */
|
||||
a priori, the parameter can be set to -1, but more expensive
|
||||
communication (synchronous sends and a barrier) will be used in that
|
||||
case. */
|
||||
void RedistributeElements(Array<int> &new_ranks, int target_elements,
|
||||
bool record_comm);
|
||||
|
||||
|
||||
+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
|
||||
|
||||
@@ -31,7 +31,7 @@ SubMesh SubMesh::CreateFromBoundary(const Mesh &parent,
|
||||
SubMesh::SubMesh(const Mesh &parent, From from,
|
||||
Array<int> attributes) : parent_(parent), from_(from), attributes_(attributes)
|
||||
{
|
||||
if (Nonconforming())
|
||||
if (parent.Nonconforming())
|
||||
{
|
||||
MFEM_ABORT("SubMesh does not support non-conforming meshes");
|
||||
}
|
||||
@@ -193,8 +193,6 @@ SubMesh::SubMesh(const Mesh &parent, From from,
|
||||
Finalize();
|
||||
}
|
||||
|
||||
SubMesh::~SubMesh() {}
|
||||
|
||||
void SubMesh::Transfer(const GridFunction &src, GridFunction &dst)
|
||||
{
|
||||
TransferMap map(src, dst);
|
||||
|
||||
@@ -174,8 +174,6 @@ public:
|
||||
return dynamic_cast<const SubMesh *>(m) != nullptr;
|
||||
}
|
||||
|
||||
~SubMesh();
|
||||
|
||||
private:
|
||||
/// Private constructor
|
||||
SubMesh(const Mesh &parent, From from, Array<int> attributes);
|
||||
|
||||
@@ -174,7 +174,8 @@ void BuildVdofToVdofMap(const FiniteElementSpace& subfes,
|
||||
Array<int> sub_vdofs;
|
||||
subfes.GetElementVDofs(i, sub_vdofs);
|
||||
|
||||
MFEM_ASSERT(parent_vdofs.Size() == sub_vdofs.Size(), "internal error");
|
||||
MFEM_ASSERT(parent_vdofs.Size() == sub_vdofs.Size(),
|
||||
"elem " << i << ' ' << parent_vdofs.Size() << ' ' << sub_vdofs.Size());
|
||||
for (int j = 0; j < parent_vdofs.Size(); j++)
|
||||
{
|
||||
real_t sub_sign = 1.0;
|
||||
|
||||
@@ -92,10 +92,13 @@ TransferMap::TransferMap(const GridFunction &src,
|
||||
|
||||
if (!root_fes_reset)
|
||||
{
|
||||
const FiniteElementCollection *src_fec = src.FESpace()->FEColl();
|
||||
const FiniteElementCollection *dst_fec = dst.FESpace()->FEColl();
|
||||
auto *root_fec = src_sm_dim == parent_dim ? src_fec : dst_fec;
|
||||
|
||||
root_fes_.reset(new FiniteElementSpace(
|
||||
*src.FESpace(),
|
||||
const_cast<Mesh *>(
|
||||
SubMeshUtils::GetRootParent(*src_sm))));
|
||||
SubMeshUtils::GetRootParent(*src_sm)), root_fec));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/adjoint/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/autodiff/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
# Include defaults.mk to get XLINKER
|
||||
DEFAULTS_MK = $(MFEM_DIR)/config/defaults.mk
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/common/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
# Default target
|
||||
all: lib-common
|
||||
|
||||
@@ -42,42 +42,42 @@ set(DPG_COMMON_FILES
|
||||
add_mfem_miniapp(diffusion-dpg
|
||||
MAIN diffusion.cpp
|
||||
${DPG_COMMON_FILES}
|
||||
LIBRARIES mfem mfem-common)
|
||||
LIBRARIES mfem-common)
|
||||
|
||||
add_mfem_miniapp(convection-diffusion-dpg
|
||||
MAIN convection-diffusion.cpp
|
||||
${DPG_COMMON_FILES}
|
||||
LIBRARIES mfem mfem-common )
|
||||
LIBRARIES mfem-common)
|
||||
|
||||
add_mfem_miniapp(acoustics-dpg
|
||||
MAIN acoustics.cpp
|
||||
${DPG_COMMON_FILES}
|
||||
LIBRARIES mfem mfem-common)
|
||||
LIBRARIES mfem-common)
|
||||
|
||||
add_mfem_miniapp(maxwell-dpg
|
||||
MAIN maxwell.cpp
|
||||
${DPG_COMMON_FILES}
|
||||
LIBRARIES mfem mfem-common)
|
||||
LIBRARIES mfem-common)
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
add_mfem_miniapp(pdiffusion-dpg
|
||||
MAIN pdiffusion.cpp
|
||||
${DPG_COMMON_FILES}
|
||||
LIBRARIES mfem mfem-common)
|
||||
LIBRARIES mfem-common)
|
||||
|
||||
add_mfem_miniapp(pconvection-diffusion-dpg
|
||||
MAIN pconvection-diffusion.cpp
|
||||
${DPG_COMMON_FILES}
|
||||
LIBRARIES mfem mfem-common)
|
||||
LIBRARIES mfem-common)
|
||||
|
||||
add_mfem_miniapp(pacoustics-dpg
|
||||
MAIN pacoustics.cpp
|
||||
${DPG_COMMON_FILES}
|
||||
LIBRARIES mfem mfem-common)
|
||||
LIBRARIES mfem-common)
|
||||
|
||||
add_mfem_miniapp(pmaxwell-dpg
|
||||
MAIN pmaxwell.cpp
|
||||
${DPG_COMMON_FILES}
|
||||
LIBRARIES mfem mfem-common)
|
||||
LIBRARIES mfem-common)
|
||||
endif ()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
MFEM_INSTALL_DIR ?= ../../mfem
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/dpg/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
CONFIG_MK = $(or $(wildcard $(MFEM_BUILD_DIR)/config/config.mk),\
|
||||
$(wildcard $(MFEM_INSTALL_DIR)/share/mfem/config.mk))
|
||||
|
||||
# Include defaults.mk to get XLINKER
|
||||
DEFAULTS_MK = $(MFEM_DIR)/config/defaults.mk
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
// Compile with: make maxwell
|
||||
//
|
||||
// Sample runs
|
||||
// maxwell -m ../../data/inline-tri.mesh -ref 4 -o 1 -rnum 1.0
|
||||
// maxwell -m ../../data/amr-quad.mesh -ref 3 -o 2 -rnum 1.6 -sc
|
||||
// maxwell -m ../../data/inline-quad.mesh -ref 2 -o 3 -rnum 4.2 -sc
|
||||
// maxwell -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
|
||||
// maxwell -m ../../data/inline-tri.mesh -ref 4 -o 1 -rnum 1.0
|
||||
// maxwell -m ../../data/amr-quad.mesh -ref 3 -o 2 -rnum 1.6 -sc
|
||||
// maxwell -m ../../data/inline-quad.mesh -ref 2 -o 3 -rnum 4.2 -sc
|
||||
// maxwell -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve
|
||||
|
||||
+11
-11
@@ -15,19 +15,19 @@
|
||||
//
|
||||
// sample runs
|
||||
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/star.mesh -sref 1 -pref 2 -rnum 1.9 -sc -prob 0
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 1 -pref 2 -rnum 5.2 -sc -prob 1
|
||||
// mpirun -np 4 pacoustics -o 4 -m ../../data/inline-tri.mesh -sref 1 -pref 2 -rnum 7.1 -sc -prob 1
|
||||
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 1.9 -sc -prob 0
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 2 -pref 1 -rnum 7.1 -sc -prob 2
|
||||
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 4.1 -sc -prob 2
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 7.1 -sc -prob 3
|
||||
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 10.1 -sc -prob 4
|
||||
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 12.1 -sc -prob 5
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/star.mesh -sref 1 -pref 2 -rnum 1.9 -sc -prob 0
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 1 -pref 2 -rnum 5.2 -sc -prob 1
|
||||
// mpirun -np 4 pacoustics -o 4 -m ../../data/inline-tri.mesh -sref 1 -pref 2 -rnum 7.1 -sc -prob 1
|
||||
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 1.9 -sc -prob 0
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 2 -pref 1 -rnum 7.1 -sc -prob 2
|
||||
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 4.1 -sc -prob 2
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 7.1 -sc -prob 3
|
||||
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 10.1 -sc -prob 4
|
||||
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 12.1 -sc -prob 5
|
||||
|
||||
// AMR runs
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 7 -theta 0.75 -rnum 10.1 -sc -prob 3
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 12 -theta 0.75 -rnum 20.1 -sc -prob 3
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 7 -theta 0.75 -rnum 10.1 -sc -prob 3
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 12 -theta 0.75 -rnum 20.1 -sc -prob 3
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user