Compare commits
421
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb62afa894 | ||
|
|
b3aeabd735 | ||
|
|
b7fbc8fce5 | ||
|
|
d771e5558a | ||
|
|
99212f8f0f | ||
|
|
70f97c79ed | ||
|
|
70e63b63bf | ||
|
|
92a0a7bc6c | ||
|
|
8640fa27af | ||
|
|
d3d25bb7e8 | ||
|
|
c46ef27c22 | ||
|
|
fdda4aaee8 | ||
|
|
8291390811 | ||
|
|
97800df5c5 | ||
|
|
2764af6227 | ||
|
|
6e315bb836 | ||
|
|
7759b6a0ef | ||
|
|
41f29f7e74 | ||
|
|
cee3e13d69 | ||
|
|
f4b1db61c8 | ||
|
|
89e0dbf127 | ||
|
|
b44c1846e9 | ||
|
|
1ef5c38cae | ||
|
|
2bb58958c9 | ||
|
|
22c5d7fc60 | ||
|
|
585a5645c0 | ||
|
|
f0b022e548 | ||
|
|
c6943f3072 | ||
|
|
4e44aa64a8 | ||
|
|
4ffea76cff | ||
|
|
645243afbe | ||
|
|
3631f93e20 | ||
|
|
37828f3de2 | ||
|
|
dcda408fd6 | ||
|
|
28a01f0395 | ||
|
|
b686bf1bdf | ||
|
|
70cbc94f20 | ||
|
|
6ed5221432 | ||
|
|
7d8ebcd33d | ||
|
|
d53bfa7b1d | ||
|
|
f29b1a3019 | ||
|
|
95017b2924 | ||
|
|
744aa63b80 | ||
|
|
ef1541fc5f | ||
|
|
84c977b3a7 | ||
|
|
cf98a85d67 | ||
|
|
74c87589f1 | ||
|
|
7604bbd03a | ||
|
|
59ab891f79 | ||
|
|
7a4d323b8c | ||
|
|
4b6f491e44 | ||
|
|
88a9b67749 | ||
|
|
4257d0584a | ||
|
|
34cdbd8388 | ||
|
|
7b1ac42629 | ||
|
|
c8fefb9022 | ||
|
|
0358eeb870 | ||
|
|
c281ba5e63 | ||
|
|
c773578cfe | ||
|
|
62ba4dd55a | ||
|
|
10c8c7a028 | ||
|
|
b8ff3df628 | ||
|
|
f14669ae67 | ||
|
|
2dca9fc4e0 | ||
|
|
fc5c88af62 | ||
|
|
7d29e739ec | ||
|
|
3eb87f6d42 | ||
|
|
552bd17416 | ||
|
|
ac78f39d70 | ||
|
|
0832fda199 | ||
|
|
24b4e21407 | ||
|
|
05cccec7b7 | ||
|
|
c602e55b9f | ||
|
|
e4a649ca56 | ||
|
|
c4de483f85 | ||
|
|
49bfcf627a | ||
|
|
ae26979ee4 | ||
|
|
9276e884e4 | ||
|
|
6f0a8d356f | ||
|
|
898b68ff99 | ||
|
|
f0a057a1d1 | ||
|
|
d3fd4b8022 | ||
|
|
03afd2edf0 | ||
|
|
894779246f | ||
|
|
1f7800109c | ||
|
|
ad04dea26d | ||
|
|
f7f709a529 | ||
|
|
fd32cfa477 | ||
|
|
d4cc1c03ad | ||
|
|
0a37aef4d6 | ||
|
|
bf5fffd7c5 | ||
|
|
07c9965aa4 | ||
|
|
70e5ae0f70 | ||
|
|
09489a318f | ||
|
|
d13ad22587 | ||
|
|
d9d3f0e4ea | ||
|
|
17a2eafbaf | ||
|
|
d1c4057431 | ||
|
|
58c48b961a | ||
|
|
799cc16dc5 | ||
|
|
cecc93bf61 | ||
|
|
bffaf743ec | ||
|
|
2759a40066 | ||
|
|
727eafe373 | ||
|
|
bfe605e0ff | ||
|
|
a2991c670b | ||
|
|
c602df9dbc | ||
|
|
5f7c204d3b | ||
|
|
813bfb5e99 | ||
|
|
7352ccf301 | ||
|
|
5909a99b3e | ||
|
|
a2ca2b9575 | ||
|
|
0ba4c9d442 | ||
|
|
5da714b61e | ||
|
|
a6df874f9c | ||
|
|
2dc13c14dc | ||
|
|
2c449b4c9d | ||
|
|
0939dac591 | ||
|
|
2c95eff3ad | ||
|
|
7ff5718488 | ||
|
|
55c3321c3b | ||
|
|
0cdf29a4bc | ||
|
|
f7dcf85cbe | ||
|
|
39b9767258 | ||
|
|
2bb8d88e16 | ||
|
|
279c6d07e5 | ||
|
|
91b7440c7e | ||
|
|
a37a3a94ce | ||
|
|
16f0f58fcd | ||
|
|
d51a6a3483 | ||
|
|
471c574dc6 | ||
|
|
018fb9ac05 | ||
|
|
e1b8ab362c | ||
|
|
00d2f19dec | ||
|
|
40d0b61939 | ||
|
|
0c6f96c2eb | ||
|
|
6e552c3f90 | ||
|
|
26c681313e | ||
|
|
9379a8971a | ||
|
|
175317c04d | ||
|
|
56a9107e7c | ||
|
|
b84e8a5793 | ||
|
|
041e3b99fd | ||
|
|
b9cf225e13 | ||
|
|
daca8cfd6c | ||
|
|
d5697799c8 | ||
|
|
e57c5e0fec | ||
|
|
aecfbff2e8 | ||
|
|
5f07e2155a | ||
|
|
802f213873 | ||
|
|
d036fd8b1f | ||
|
|
79d7c5c682 | ||
|
|
36ac1adb3b | ||
|
|
7c9fe7b560 | ||
|
|
d97454370c | ||
|
|
cb79110ef9 | ||
|
|
9c91e44feb | ||
|
|
0acbd90ac4 | ||
|
|
13be84efdb | ||
|
|
f867b645ab | ||
|
|
27077f2f0a | ||
|
|
095f9a2aee | ||
|
|
492a28b227 | ||
|
|
c4eb458e03 | ||
|
|
f80a520f31 | ||
|
|
7af6ed945d | ||
|
|
c15c3d8f78 | ||
|
|
fab68704d2 | ||
|
|
acd9de7cee | ||
|
|
6a2b798acd | ||
|
|
8caaabda21 | ||
|
|
aa1233f47a | ||
|
|
0ac144c992 | ||
|
|
67ae86557a | ||
|
|
3ddc31337e | ||
|
|
930c058704 | ||
|
|
4f0826fb6f | ||
|
|
af9496be2e | ||
|
|
0f817acd30 | ||
|
|
efef5b1eff | ||
|
|
7fdc80e073 | ||
|
|
f9dc31959d | ||
|
|
56507bb395 | ||
|
|
0903dd01e9 | ||
|
|
2eab58b853 | ||
|
|
c1663093c0 | ||
|
|
0e87cac48e | ||
|
|
4a9eed99b4 | ||
|
|
f10c1824c1 | ||
|
|
891364e5ff | ||
|
|
c42906a395 | ||
|
|
e074506faf | ||
|
|
670f4799d7 | ||
|
|
04eddb884c | ||
|
|
e87b54a057 | ||
|
|
57c3853fb6 | ||
|
|
08f5abc6b2 | ||
|
|
2daac8eef4 | ||
|
|
735d0d41b8 | ||
|
|
3642dc3a57 | ||
|
|
0bf9d144f9 | ||
|
|
4de4256085 | ||
|
|
f589bdeb27 | ||
|
|
b3cdfdea49 | ||
|
|
1aa4f62937 | ||
|
|
900a020610 | ||
|
|
ab4a76022b | ||
|
|
a6caeff9d6 | ||
|
|
649209dc2b | ||
|
|
3e56ffab7c | ||
|
|
06f49ed5c2 | ||
|
|
207716e0f3 | ||
|
|
49d328403d | ||
|
|
aa10bc7966 | ||
|
|
c7a6ab3c89 | ||
|
|
e068e21672 | ||
|
|
9f7ddad73c | ||
|
|
a40a1f899d | ||
|
|
cd2236d018 | ||
|
|
cc66b2ef89 | ||
|
|
b4b5373697 | ||
|
|
ceb34240df | ||
|
|
dab908a49c | ||
|
|
223c47fae2 | ||
|
|
f6ed30852b | ||
|
|
dc5c975a88 | ||
|
|
6a881ae708 | ||
|
|
279938afe5 | ||
|
|
75db215d3f | ||
|
|
a00f5a7aa3 | ||
|
|
85f450e7d0 | ||
|
|
f40ec9f0d2 | ||
|
|
a3403c3f3a | ||
|
|
9745e7668e | ||
|
|
5b97514b1f | ||
|
|
be02b9a457 | ||
|
|
7739c00cf9 | ||
|
|
3019a29b9f | ||
|
|
176a029bc7 | ||
|
|
3913c81855 | ||
|
|
6fcdfd7d41 | ||
|
|
a57fd02a4c | ||
|
|
3b54ae451e | ||
|
|
4b26c2c11d | ||
|
|
01d7657e7b | ||
|
|
75abc3e063 | ||
|
|
77a038ab44 | ||
|
|
afb8a5faa2 | ||
|
|
2ae97ff2da | ||
|
|
2b712207c6 | ||
|
|
71bc6b548a | ||
|
|
2930c1477f | ||
|
|
3c498bd4a9 | ||
|
|
2136283065 | ||
|
|
24d58dd47f | ||
|
|
2d10510a15 | ||
|
|
26a525844b | ||
|
|
eed4c06fb7 | ||
|
|
36da88f98f | ||
|
|
ca276a9a1b | ||
|
|
a80ec31887 | ||
|
|
a8925a8d58 | ||
|
|
9257c0d177 | ||
|
|
6b763d59db | ||
|
|
76962605ed | ||
|
|
1ab1091e19 | ||
|
|
49daadcd84 | ||
|
|
9cbf128f18 | ||
|
|
436bb9b070 | ||
|
|
ca50d0db07 | ||
|
|
70e4b4a781 | ||
|
|
fed561d5ba | ||
|
|
a99b9869c0 | ||
|
|
4f3f81fef6 | ||
|
|
c88387694b | ||
|
|
1c0c3054fa | ||
|
|
d0f04b0168 | ||
|
|
527564ab94 | ||
|
|
2a798d7e1b | ||
|
|
0ff0f704b9 | ||
|
|
723362b610 | ||
|
|
bf7843fc32 | ||
|
|
73a7ebf5f3 | ||
|
|
b4655e6409 | ||
|
|
ce0788c104 | ||
|
|
955446c9f7 | ||
|
|
b3bb0ea404 | ||
|
|
2d4b956b48 | ||
|
|
f966445355 | ||
|
|
c0ebddedbe | ||
|
|
ee6d162d47 | ||
|
|
b529164f3a | ||
|
|
af3f6a8b7d | ||
|
|
134436f064 | ||
|
|
a690135d15 | ||
|
|
abd79fc6fa | ||
|
|
510498a3e6 | ||
|
|
55dccdf598 | ||
|
|
54580450d3 | ||
|
|
2dc947ff91 | ||
|
|
792c50518e | ||
|
|
400c31435c | ||
|
|
c46e60321a | ||
|
|
072c4ad387 | ||
|
|
ba68b03aeb | ||
|
|
fb10506117 | ||
|
|
1d667ea546 | ||
|
|
8660563901 | ||
|
|
29f6d09c4e | ||
|
|
991b452a42 | ||
|
|
2a642ba5c7 | ||
|
|
7621999979 | ||
|
|
004449150a | ||
|
|
3e719dfaf6 | ||
|
|
fa9fce971f | ||
|
|
fac83d44b6 | ||
|
|
2b9bfdcfa1 | ||
|
|
7ccf354afb | ||
|
|
e57f0a0905 | ||
|
|
2e391ee3ef | ||
|
|
a4330ec239 | ||
|
|
b5335e6e62 | ||
|
|
ee35dcd356 | ||
|
|
8efba0c8ec | ||
|
|
46a8e8d4b8 | ||
|
|
cbbf157690 | ||
|
|
1cfd42cc7d | ||
|
|
8ff06039bd | ||
|
|
38b3168eae | ||
|
|
43fc2ecc82 | ||
|
|
0b389f2da6 | ||
|
|
749ba058fd | ||
|
|
4cbf65ceba | ||
|
|
cf7d5e8e47 | ||
|
|
f7455fdfb3 | ||
|
|
98929f5465 | ||
|
|
4be20db30b | ||
|
|
da93ab2ed4 | ||
|
|
a909cf4986 | ||
|
|
a5df0b44d7 | ||
|
|
8d640a6a29 | ||
|
|
4b779f9b59 | ||
|
|
b5e5bedb58 | ||
|
|
4b97cb3a36 | ||
|
|
25412a3400 | ||
|
|
325cc85ad4 | ||
|
|
8e3217e8a4 | ||
|
|
9457d1246f | ||
|
|
5761a2d249 | ||
|
|
4cb9531d6a | ||
|
|
79c16ef58e | ||
|
|
95454a1733 | ||
|
|
4c2d7c9275 | ||
|
|
de15b99c40 | ||
|
|
00d84e0920 | ||
|
|
212cd6d5fc | ||
|
|
2cc1f18bc9 | ||
|
|
32482904a9 | ||
|
|
be18a4992c | ||
|
|
95370a906d | ||
|
|
aec2c7b832 | ||
|
|
e52d6d7530 | ||
|
|
a1720fd6e3 | ||
|
|
895caad872 | ||
|
|
d53566acbc | ||
|
|
9c41cd5f34 | ||
|
|
b28277027e | ||
|
|
3c191f6815 | ||
|
|
40056535c1 | ||
|
|
bc7203e720 | ||
|
|
9dc26d68f8 | ||
|
|
6dec38360f | ||
|
|
59a4ab5ada | ||
|
|
861829db28 | ||
|
|
2453f6f20c | ||
|
|
a9775ee6ab | ||
|
|
057ab87d30 | ||
|
|
c0f65a8c01 | ||
|
|
d2fcc358ad | ||
|
|
c049453773 | ||
|
|
e4b95d2666 | ||
|
|
02d8d0a0a5 | ||
|
|
48e6cd8b01 | ||
|
|
f00ea139a9 | ||
|
|
d08f0790ea | ||
|
|
6671a77e34 | ||
|
|
1cbbde8fb6 | ||
|
|
f958b9660b | ||
|
|
dbba00715c | ||
|
|
3b1a43de1a | ||
|
|
af6cf29b85 | ||
|
|
28d2d44de1 | ||
|
|
dbb15ab25d | ||
|
|
6ab9b9f1e6 | ||
|
|
9bdded3450 | ||
|
|
d7661bd5ef | ||
|
|
250b62f1e6 | ||
|
|
e70cc67bc1 | ||
|
|
e2c7458cc6 | ||
|
|
75aee31101 | ||
|
|
5b4cf4265b | ||
|
|
a4ffe6caa3 | ||
|
|
a315c900f9 | ||
|
|
258f83b2ca | ||
|
|
14051159d0 | ||
|
|
b3ee631aa6 | ||
|
|
daf2fdecec | ||
|
|
d3a0d0a181 | ||
|
|
f31d8747f9 | ||
|
|
cf45b90266 | ||
|
|
dd7db993bc | ||
|
|
b31d805597 | ||
|
|
07853b9c62 | ||
|
|
eb677b8581 | ||
|
|
49a31c0cf7 | ||
|
|
ba9b251007 | ||
|
|
5ce2fa9ab9 | ||
|
|
78c93de6ce | ||
|
|
3d4aa157cb | ||
|
|
a7f1c177c5 | ||
|
|
2d4e3cf77e |
+9
-8
@@ -175,7 +175,6 @@ miniapps/meshing/mesh-optimizer
|
||||
miniapps/meshing/pmesh-optimizer
|
||||
miniapps/meshing/minimal-surface
|
||||
miniapps/meshing/pminimal-surface
|
||||
miniapps/meshing/polar-nc
|
||||
|
||||
miniapps/meshing/mobius-strip.mesh
|
||||
miniapps/meshing/klein-bottle.mesh
|
||||
@@ -188,7 +187,6 @@ miniapps/meshing/extruder.mesh
|
||||
miniapps/meshing/trimmer.mesh
|
||||
miniapps/meshing/optimized*
|
||||
miniapps/meshing/perturbed*
|
||||
miniapps/meshing/polar-nc.mesh
|
||||
|
||||
miniapps/performance/ex1
|
||||
miniapps/performance/ex1p
|
||||
@@ -235,7 +233,6 @@ miniapps/nurbs/mode_*
|
||||
miniapps/nurbs/Example1*
|
||||
|
||||
miniapps/gslib/field-diff
|
||||
miniapps/gslib/field-interp
|
||||
miniapps/gslib/findpts
|
||||
miniapps/gslib/pfindpts
|
||||
|
||||
@@ -256,16 +253,20 @@ tests/unit/unit_tests
|
||||
tests/unit/punit_tests
|
||||
tests/unit/sedov_tests_*
|
||||
tests/unit/psedov_tests_*
|
||||
tests/unit/tmop_tests_*
|
||||
tests/unit/ptmop_tests_*
|
||||
tests/unit/cube.mesh
|
||||
tests/unit/star.mesh
|
||||
tests/unit/blade.mesh
|
||||
tests/unit/square01.mesh
|
||||
tests/unit/toroid-hex.mesh
|
||||
tests/unit/beam-hex-nurbs.mesh
|
||||
tests/unit/square-disc-nurbs.mesh
|
||||
|
||||
# Test script output
|
||||
tests/scripts/*.err
|
||||
tests/scripts/*.out
|
||||
tests/scripts/*.msg
|
||||
|
||||
# Other tests
|
||||
tests/convergence/rates
|
||||
tests/convergence/prates
|
||||
tests/par-mesh-format/ex1p
|
||||
|
||||
# VPATH builds
|
||||
build-*/*
|
||||
|
||||
+1
-17
@@ -71,8 +71,6 @@ stages:
|
||||
- build
|
||||
- test
|
||||
- deallocate
|
||||
- lassen_build
|
||||
- lassen_test
|
||||
- baseline_check
|
||||
- baseline_publish
|
||||
|
||||
@@ -81,11 +79,7 @@ stages:
|
||||
# TODO: updating tests and tpls is not necessary anymore since pipelines are
|
||||
# now using unique directories so repo are never shared with another pipeline.
|
||||
# This is not memory efficient (we keep a lot of data), hence this reminder.
|
||||
# Setup
|
||||
setup:
|
||||
tags:
|
||||
- shell
|
||||
- quartz
|
||||
.setup:
|
||||
stage: setup
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
@@ -106,15 +100,6 @@ setup:
|
||||
before_script:
|
||||
- module load gcc/6.1.0
|
||||
|
||||
# On lassen
|
||||
.with_gcc_8_3_1:
|
||||
variables:
|
||||
TOOLCHAIN: gcc_8_3_1
|
||||
CXX: g++
|
||||
CC: gcc
|
||||
before_script:
|
||||
- module load gcc/8.3.1
|
||||
|
||||
.with_gcc_4_9_3:
|
||||
variables:
|
||||
TOOLCHAIN: gcc_4_9_3
|
||||
@@ -305,4 +290,3 @@ setup:
|
||||
# The list on jobs is defined in machine-specific files.
|
||||
include:
|
||||
- local: .gitlab/quartz.yml
|
||||
- local: .gitlab/lassen.yml
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
# Copyright (c) 2010-2020, 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.
|
||||
|
||||
# GitLab pipelines configurations for the Lassen machine at LLNL
|
||||
|
||||
.on_lassen:
|
||||
tags:
|
||||
- shell
|
||||
- lassen
|
||||
variables:
|
||||
PLAT: lassen
|
||||
|
||||
# Build MFEM
|
||||
build_mfem_ser_lassen:
|
||||
extends: [.with_gcc_8_3_1, .on_lassen]
|
||||
needs: [setup]
|
||||
stage: lassen_build
|
||||
script:
|
||||
- mkdir -p ${BUILD_PATH}
|
||||
- cp -r ${CI_PROJECT_DIR} ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser
|
||||
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser
|
||||
- lalloc 1 -W 5 -q pdebug make -j cuda CUDA_ARCH=sm_70
|
||||
|
||||
build_mfem_debug_ser_lassen:
|
||||
extends: [.with_gcc_8_3_1, .on_lassen]
|
||||
needs: [setup]
|
||||
stage: lassen_build
|
||||
script:
|
||||
- mkdir -p ${BUILD_PATH}
|
||||
- cp -r ${CI_PROJECT_DIR} ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser_debug
|
||||
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser_debug
|
||||
- lalloc 1 -W 5 -q pdebug make -j cuda MFEM_DEBUG="YES" CUDA_ARCH=sm_70
|
||||
|
||||
# Sanity check
|
||||
sanitycheck_mfem_ser_lassen:
|
||||
extends: [.with_gcc_8_3_1, .on_lassen]
|
||||
stage: lassen_test
|
||||
needs: [build_mfem_ser_lassen]
|
||||
script:
|
||||
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser
|
||||
- lalloc 1 -W 15 -q pdebug make -j test
|
||||
|
||||
sanitycheck_mfem_debug_ser_lassen:
|
||||
extends: [.with_gcc_8_3_1, .on_lassen]
|
||||
stage: lassen_test
|
||||
needs: [build_mfem_debug_ser_lassen]
|
||||
script:
|
||||
- cd ${BUILD_PATH}/${CI_PROJECT_NAME}_lassen_ser_debug
|
||||
- lalloc 1 -W 30 -q pdebug make -j test
|
||||
@@ -22,6 +22,10 @@
|
||||
MAKE_PAR: 6
|
||||
BASELINE_PAR: 18
|
||||
|
||||
# Setup
|
||||
setup_quartz:
|
||||
extends: [.setup, .on_quartz]
|
||||
|
||||
# Allocate
|
||||
allocate_quartz:
|
||||
variables:
|
||||
|
||||
@@ -16,12 +16,7 @@ Meshing improvements
|
||||
- The graph linear ordering library Gecko, previously an external dependency, is
|
||||
now included directly in MFEM. As a result, Mesh::GetGeckoElementOrdering is
|
||||
always available. The interface has also been improved, see for example the
|
||||
Mesh Explorer miniapp.
|
||||
|
||||
- Improved Gmsh reader (version 2.2), which now supports both high-order and
|
||||
periodic meshes. Segments, triangles, quadrilaterals, and tetrahedra are
|
||||
supported up to order 10. Wedges and hexahedra are supported up to order 9.
|
||||
For sample periodic meshes, see the periodic*.msh files in the data directory.
|
||||
mesh-explorer miniapp.
|
||||
|
||||
- Added support for finite difference-based gradient and Hessian approximation
|
||||
in the TMOP mesh optimization algorithms. This improves the accuracy of the
|
||||
@@ -32,17 +27,15 @@ Meshing improvements
|
||||
the user to specify different discrete functions for controlling the
|
||||
size, aspect-ratio, orientation, and skew of elements in the mesh.
|
||||
|
||||
- Added TMOP capability for approximate tangential mesh relaxation. Added
|
||||
support and examples for using TMOP on mixed meshes.
|
||||
- Added TMOP capability for approximate tangential mesh relaxation.
|
||||
|
||||
- Added support for reading periodic meshes in Gmsh format (version 2.2). See
|
||||
for example the periodic-annulus-sector and periodic-torus-sector files in
|
||||
the data directory.
|
||||
|
||||
- Added complete action of the TMOP Integrator to account for the spatial
|
||||
derivatives of discrete and analytic targets.
|
||||
|
||||
- Added support for initialization of (serial) non-conforming meshes. Hanging
|
||||
nodes can be marked with Mesh::AddVertexParents when building the mesh with
|
||||
the "init" constructor. The usage is demonstrated in a new meshing miniapp
|
||||
(polar-nc) which generates meshes that are non-conforming from the start.
|
||||
|
||||
Performance improvements
|
||||
------------------------
|
||||
- Added support for explicit vectorization in the high-performance templated
|
||||
@@ -57,6 +50,11 @@ Performance improvements
|
||||
Improved GPU capabilities
|
||||
-------------------------
|
||||
- Added support for Chebyshev accelerated polynomial smoother on GPU.
|
||||
- The TMOP mesh optimization algorithms were extended to GPU:
|
||||
- QualityMetric #1, #2 and #7 are available in 2D, #302, #303 and #321 in 3D
|
||||
- Both AnalyticAdaptTC and DiscreteAdaptTC TargetConstructor are available
|
||||
- Kernels for normalization and limiting have been added
|
||||
- The AdvectorCG now also support AssemblyLevel::PARTIAL
|
||||
|
||||
- Optimized AMD/HIP kernel support.
|
||||
|
||||
@@ -65,14 +63,8 @@ Improved GPU capabilities
|
||||
compute a global sparse matrix. All integrators supported by element assembly
|
||||
are also supported by full assembly. See the '-fa' option in Example 9.
|
||||
|
||||
- Added CUDA support for sparse matrix-vector multiplication with cuSPARSE.
|
||||
|
||||
- Added support for BlockOperator on GPU. See the updated Example 5.
|
||||
|
||||
- Added partial assembly and GPU support for complex operators, including the
|
||||
classes ComplexOperator, [Par]ComplexGridFunction, [Par]ComplexLinearForm, and
|
||||
[Par]SesquilinearForm. See the updated Example 22.
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
- Added support for matrix-free interpolation and restriction operators between
|
||||
@@ -101,14 +93,6 @@ Discretization improvements
|
||||
|
||||
- Added support face integrals on the boundaries of NURBS meshes.
|
||||
|
||||
- Added support for interpolation of functions in L2, H(div) and H(curl)
|
||||
spaces using GSLIB-FindPoints.
|
||||
|
||||
- Added support for computing asymptotic error estimates and convergence rates
|
||||
for the whole de Rham sequence based on the new class ConvergenceStudy and new
|
||||
member methods in GridFunction and ParGridFunction. See the rates.cpp file in
|
||||
the tests/convergence directory for sample usage.
|
||||
|
||||
Linear and nonlinear solvers
|
||||
----------------------------
|
||||
- Added power method to iteratively estimate the largest eigenvalue and the
|
||||
@@ -134,12 +118,6 @@ Linear and nonlinear solvers
|
||||
|
||||
- Added support for the SLEPc eigensolver package.
|
||||
|
||||
- Added partially assembled convergent diagonal preconditioner for adaptively
|
||||
refined meshes (i.e. non-conforming finite element spaces), see Example 6/6p.
|
||||
|
||||
- Added an interface to the Intel MKL Parallel Direct Sparse Solver for
|
||||
Clusters. An example usage of the interface is shown in Example 11p.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- Added a new example, Example 25/25p, to demonstrate the use of a Perfectly
|
||||
@@ -176,9 +154,6 @@ New and updated examples and miniapps
|
||||
- Added a new meshing miniapp, Minimal Surface, which solves Plateau's problem:
|
||||
the Dirichlet problem for the minimal surface equation.
|
||||
|
||||
- Added a new meshing miniapp, Polar NC, which demonstrates the construction of
|
||||
polar non-conforming meshes.
|
||||
|
||||
- Added partial assembly support to Example 4/4p and Example 5/5p, with diagonal
|
||||
preconditioning.
|
||||
|
||||
@@ -193,47 +168,28 @@ New and updated examples and miniapps
|
||||
mesh based on element attributes. Any newly exposed boundary elements are
|
||||
assigned attribute numbers related to the trimmed element attributes.
|
||||
|
||||
- Added a new miniapp (field-interp) that demonstrates transfer of grid function
|
||||
between different meshes using GSLIB-FindPoints.
|
||||
|
||||
- Added diagonal preconditioner in Example 6/6p for partial assembly with AMR.
|
||||
|
||||
- Added device support in Example 5/5p.
|
||||
|
||||
- Added partial assembly and device support to Example 22/22p, with diagonal
|
||||
preconditioning.
|
||||
|
||||
- Added the option to plot a function in Mesh Explorer.
|
||||
|
||||
Improved testing
|
||||
----------------
|
||||
- Upgraded the Catch unit test framework from version 1.6.1 to version 2.13.0.
|
||||
|
||||
- Added a GitLab pipeline that automates PR testing on supercomputing systems
|
||||
and Linux clusters at Lawrence Livermore National Lab (LLNL). This can be
|
||||
triggered only by LLNL developers, see .gitlab-ci.yml, the .gitlab directory
|
||||
and the updated CONTRIBUTING.md file.
|
||||
|
||||
- Added testing of the parallel mesh format in tests/par-mesh-format.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- Added support for ADIOS2 for parallel I/O with ParaView visualization. The
|
||||
classes adios2stream and ADIOS2DataCollection are introduced in mfem as the
|
||||
interfaces to generate ADIOS2 Binary Pack (BP4) directory datasets for the
|
||||
entire spatial and temporal node data. Cell centered data is accessible by
|
||||
ADIOS2 data readers (e.g. Python), but currently not yet implement as of
|
||||
ParaView v5.8.1. In addition, ADIOS2 allows for setting a user-defined number
|
||||
of data substreams/subfiles at scale. See examples 5, 9, 12, 16.
|
||||
entire spatial and temporal data. In addition, ADIOS2 allows for setting a
|
||||
user-defined number of data substreams/subfiles. See examples 5, 9, 12, 16.
|
||||
|
||||
- The integration order used in the ComputeLpError and ComputeElementLpError
|
||||
methods of class GridFunction has been increased.
|
||||
|
||||
- Various other simplifications, extensions, and bugfixes in the code.
|
||||
|
||||
- Renamed "Backend::DEBUG" to "Backend::DEBUG_DEVICE" to avoid conflicts,
|
||||
as DEBUG is sometimes used as a macro.
|
||||
|
||||
|
||||
Version 4.1, released on March 10, 2020
|
||||
=======================================
|
||||
|
||||
+17
-38
@@ -89,38 +89,8 @@ enable_language(CXX)
|
||||
if (MFEM_USE_CUDA)
|
||||
# MFEM_USE_CUDA requires CMake 3.8 or newer (for direct CUDA support)
|
||||
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||
# Use ${CMAKE_CXX_COMPILER} as the cuda host compiler.
|
||||
if (NOT CMAKE_CUDA_HOST_COMPILER)
|
||||
set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
enable_language(CUDA)
|
||||
set(CMAKE_CUDA_STANDARD 11)
|
||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CUDA_EXTENSIONS OFF)
|
||||
set(CUDA_FLAGS "--expt-extended-lambda")
|
||||
if (CMAKE_VERSION VERSION_LESS 3.18.0)
|
||||
set(CUDA_FLAGS "-arch=${CUDA_ARCH} ${CUDA_FLAGS}")
|
||||
elseif (NOT CMAKE_CUDA_ARCHITECTURES)
|
||||
string(REGEX REPLACE "^sm_" "" ARCH_NUMBER "${CUDA_ARCH}")
|
||||
if ("${CUDA_ARCH}" STREQUAL "sm_${ARCH_NUMBER}")
|
||||
set(CMAKE_CUDA_ARCHITECTURES "${ARCH_NUMBER}")
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown CUDA_ARCH: ${CUDA_ARCH}")
|
||||
endif()
|
||||
else()
|
||||
set(CUDA_ARCH "CMAKE_CUDA_ARCHITECTURES: ${CMAKE_CUDA_ARCHITECTURES}")
|
||||
endif()
|
||||
message(STATUS "Using CUDA architecture: ${CUDA_ARCH}")
|
||||
if (CMAKE_VERSION VERSION_LESS 3.12.0)
|
||||
# CMake versions 3.8 and 3.9 require this to work; 3.10 and 3.11 are not
|
||||
# tested and may not actually need this (but should be ok to keep).
|
||||
set(CUDA_FLAGS "-ccbin=${CMAKE_CXX_COMPILER} ${CUDA_FLAGS}")
|
||||
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
set(CMAKE_CUDA_FLAGS "${CUDA_FLAGS}" CACHE STRING
|
||||
"CUDA flags set for MFEM" FORCE)
|
||||
set(CUSPARSE_FOUND TRUE)
|
||||
set(CUSPARSE_LIBRARIES "cusparse")
|
||||
endif()
|
||||
|
||||
if (XSDK_ENABLE_C)
|
||||
@@ -326,6 +296,22 @@ if (MFEM_USE_HIOP)
|
||||
# find_package updates HIOP_FOUND, HIOP_INCLUDE_DIRS, HIOP_LIBRARIES
|
||||
endif()
|
||||
|
||||
# CUDA
|
||||
if (MFEM_USE_CUDA)
|
||||
set(CMAKE_CUDA_STANDARD 11)
|
||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CUDA_EXTENSIONS OFF)
|
||||
set(CMAKE_CUDA_FLAGS "-arch=${CUDA_ARCH} --expt-extended-lambda"
|
||||
CACHE STRING "CUDA flags set for MFEM" FORCE)
|
||||
if (MFEM_USE_MPI)
|
||||
set(CUDA_CCBIN_COMPILER ${MPI_CXX_COMPILER})
|
||||
else()
|
||||
set(CUDA_CCBIN_COMPILER ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
string(APPEND CMAKE_CUDA_FLAGS " -ccbin ${CUDA_CCBIN_COMPILER}")
|
||||
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CUDA_CCBIN_COMPILER})
|
||||
endif()
|
||||
|
||||
# OCCA
|
||||
if (MFEM_USE_OCCA)
|
||||
find_package(OCCA REQUIRED)
|
||||
@@ -346,12 +332,6 @@ if (MFEM_USE_ADIOS2)
|
||||
find_package(ADIOS2 REQUIRED)
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_MKL_CPARDISO)
|
||||
if (MFEM_USE_MPI)
|
||||
find_package(MKL_CPARDISO REQUIRED MKL_SEQUENTIAL MKL_LP64 MKL_MPI_WRAPPER)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# MFEM_TIMER_TYPE
|
||||
if (NOT DEFINED MFEM_TIMER_TYPE)
|
||||
if (APPLE)
|
||||
@@ -377,8 +357,7 @@ endif()
|
||||
# be before SuiteSparse.
|
||||
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
|
||||
SLEPC MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
|
||||
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2
|
||||
CUSPARSE MKL_CPARDISO)
|
||||
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2)
|
||||
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
|
||||
set(TPL_LIBRARIES "")
|
||||
set(TPL_INCLUDE_DIRS "")
|
||||
|
||||
@@ -486,13 +486,6 @@ MFEM_USE_CEED = YES/NO
|
||||
library for performant high-order operator evaluation developed by the Center
|
||||
for Efficient Exascale Discretizations in the Exascale Computing Project.
|
||||
|
||||
MFEM_USE_MKL_CPARDISO = YES/NO
|
||||
Enables the interface to the Intel MKL Parallel Direct Sparse Solver for
|
||||
Clusters. Make sure to set the correct values for MKL_MPI_WRAPPER and
|
||||
MKL_LIBRARY_SUBDIR as shown in defaults.mk. If you configure MFEM with
|
||||
MFEM_USE_LAPACK=YES, verify that the MKL LAPACK libraries are used. The
|
||||
OpenMP capabilities are disabled at link time.
|
||||
|
||||
MFEM_BUILD_TAG = (any value)
|
||||
An optional tag to characterize the build. Exported to config/config.mk.
|
||||
Can be used to identify the MFEM build from other makefiles.
|
||||
@@ -670,7 +663,7 @@ The specific libraries and their options are:
|
||||
URL: https://github.com/CEED/libCEED
|
||||
https://ceed.exascaleproject.org/libceed
|
||||
Options: CEED_DIR, CEED_OPT, CEED_LIB.
|
||||
Versions: libCEED > 0.6, git-hash bdfed75.
|
||||
Versions: libCEED >= 0.6, git-hash a970f63.
|
||||
|
||||
- RAJA (optional), used when MFEM_USE_RAJA = YES.
|
||||
Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported.
|
||||
|
||||
@@ -156,7 +156,4 @@
|
||||
// library.
|
||||
#cmakedefine MFEM_USE_SIMMETRIX
|
||||
|
||||
// Enable interface to the MKL CPardiso library.
|
||||
#cmakedefine MFEM_USE_MKL_CPARDISO
|
||||
|
||||
#endif // MFEM_CONFIG_HEADER
|
||||
|
||||
@@ -38,19 +38,7 @@ if(NOT ADIOS2_FOUND)
|
||||
endif()
|
||||
|
||||
find_path(ADIOS2_INCLUDE_DIR adios2.h ${ADIOS2_INCLUDE_OPTS})
|
||||
|
||||
# adios2 version 2.5.0
|
||||
find_library(ADIOS2_LIBRARY NAMES adios2 ${ADIOS2_LIBRARY_OPTS})
|
||||
|
||||
# adios2 version 2.6.0 and onwards
|
||||
if(NOT ADIOS2_LIBRARY)
|
||||
find_library(ADIOS2_CXX11_MPI_LIBRARY NAMES adios2_cxx11_mpi ${ADIOS2_LIBRARY_OPTS})
|
||||
find_library(ADIOS2_CXX11_LIBRARY NAMES adios2_cxx11 ${ADIOS2_LIBRARY_OPTS})
|
||||
set(ADIOS2_LIBRARY ${ADIOS2_CXX11_MPI_LIBRARY} ${ADIOS2_CXX11_LIBRARY})
|
||||
if(MFEM_USE_MPI)
|
||||
add_definitions(-DADIOS2_USE_MPI)
|
||||
endif()
|
||||
endif()
|
||||
find_library(ADIOS2_LIBRARY NAMES adios2 ${ADIOS2_LIBRARY_OPTS})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ADIOS2
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
# Copyright (c) 2010-2020, 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.
|
||||
|
||||
# Defines the following variables:
|
||||
# - MKL_CPARDISO_FOUND
|
||||
# - MKL_CPARDISO_LIBRARIES
|
||||
# - MKL_CPARDISO_INCLUDE_DIRS
|
||||
|
||||
if(NOT MKL_MPI_WRAPPER_LIB)
|
||||
message(FATAL_ERROR "MKL CPardiso enabled but no MKL MPI Wrapper lib specified")
|
||||
endif()
|
||||
|
||||
if(NOT MKL_LIBRARY_DIR)
|
||||
message(WARNING "Using default MKL library path. Double check the variable MKL_LIBRARY_DIR")
|
||||
set(MKL_LIBRARY_DIR "lib")
|
||||
endif()
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(MKL_CPARDISO MKL_CPARDISO
|
||||
MKL_CPARDISO_DIR "include" mkl_cluster_sparse_solver.h ${MKL_LIBRARY_DIR} mkl_core
|
||||
"Paths to headers required by MKL CPardiso." "Libraries required by MKL CPARDISO."
|
||||
ADD_COMPONENT MKL_LP64 "include" "" ${MKL_LIBRARY_DIR} mkl_intel_lp64
|
||||
ADD_COMPONENT MKL_SEQUENTIAL "include" "" ${MKL_LIBRARY_DIR} mkl_sequential
|
||||
ADD_COMPONENT MKL_MPI_WRAPPER "include" "" ${MKL_LIBRARY_DIR} ${MKL_MPI_WRAPPER_LIB}
|
||||
CHECK_BUILD MKL_CPARDISO_VERSION_OK TRUE
|
||||
"
|
||||
#include <mpi.h>
|
||||
#include <mkl.h>
|
||||
#include <mkl_cluster_sparse_solver.h>
|
||||
int main (void)
|
||||
{
|
||||
MKL_INT n = 5;
|
||||
MKL_INT ia[6] = { 1, 4, 6, 9, 12, 14};
|
||||
MKL_INT ja[13] = { 1, 2, 4, /* index of non-zeros in 1 row*/
|
||||
1, 2, /* index of non-zeros in 2 row*/
|
||||
3, 4, 5, /* index of non-zeros in 3 row*/
|
||||
1, 3, 4, /* index of non-zeros in 4 row*/
|
||||
2, 5 /* index of non-zeros in 5 row*/
|
||||
};
|
||||
double a[13] = {
|
||||
1.0, -1.0, /*0*/ -3.0, /*0*/
|
||||
-2.0, 5.0, /*0*/ /*0*/ /*0*/
|
||||
/*0*/ 4.0, 6.0, 4.0, /*0*/
|
||||
-4.0, /*0*/ 2.0, 7.0, /*0*/
|
||||
/*0*/ 8.0, /*0*/ /*0*/ -5.0
|
||||
};
|
||||
|
||||
MKL_INT mtype = 11; /* set matrix type to \"real unsymmetric matrix\" */
|
||||
MKL_INT nrhs = 1; /* Number of right hand sides. */
|
||||
double b[5], x[5], bs[5], res, res0; /* RHS and solution vectors. */
|
||||
|
||||
/* Internal solver memory pointer pt
|
||||
* 32-bit: int pt[64] or void *pt[64];
|
||||
* 64-bit: long int pt[64] or void *pt[64]; */
|
||||
void *pt[64] = { 0 };
|
||||
|
||||
/* Cluster Sparse Solver control parameters. */
|
||||
MKL_INT iparm[64] = { 0 };
|
||||
MKL_INT maxfct, mnum, phase, msglvl, error;
|
||||
|
||||
/* Auxiliary variables. */
|
||||
double ddum; /* Double dummy */
|
||||
MKL_INT idum; /* Integer dummy. */
|
||||
MKL_INT i, j;
|
||||
int mpi_stat = 0;
|
||||
int argc = 0;
|
||||
int comm, rank;
|
||||
char* uplo;
|
||||
char** argv;
|
||||
|
||||
mpi_stat = MPI_Init( &argc, &argv );
|
||||
mpi_stat = MPI_Comm_rank( MPI_COMM_WORLD, &rank );
|
||||
comm = MPI_Comm_c2f( MPI_COMM_WORLD );
|
||||
|
||||
iparm[ 0] = 1; /* Solver default parameters overriden with provided by iparm */
|
||||
iparm[ 1] = 2; /* Use METIS for fill-in reordering */
|
||||
iparm[ 5] = 0; /* Write solution into x */
|
||||
iparm[ 7] = 2; /* Max number of iterative refinement steps */
|
||||
iparm[ 9] = 13; /* Perturb the pivot elements with 1E-13 */
|
||||
iparm[10] = 1; /* Use nonsymmetric permutation and scaling MPS */
|
||||
iparm[12] = 1; /* Switch on Maximum Weighted Matching algorithm (default for non-symmetric) */
|
||||
iparm[17] = -1; /* Output: Number of nonzeros in the factor LU */
|
||||
iparm[18] = -1; /* Output: Mflops for LU factorization */
|
||||
iparm[26] = 1; /* Check input data for correctness */
|
||||
iparm[39] = 0; /* Input: matrix/rhs/solution stored on master */
|
||||
maxfct = 1; /* Maximum number of numerical factorizations. */
|
||||
mnum = 1; /* Which factorization to use. */
|
||||
msglvl = 1; /* Print statistical information in file */
|
||||
error = 0; /* Initialize error flag */
|
||||
|
||||
phase = 11;
|
||||
cluster_sparse_solver ( pt, &maxfct, &mnum, &mtype, &phase,
|
||||
&n, a, ia, ja, &idum, &nrhs, iparm, &msglvl, &ddum, &ddum, &comm, &error );
|
||||
|
||||
mpi_stat = MPI_Finalize();
|
||||
return error;
|
||||
}
|
||||
")
|
||||
@@ -128,15 +128,7 @@ function(add_mfem_miniapp MFEM_EXE_NAME)
|
||||
if (MFEM_USE_CUDA)
|
||||
set_property(SOURCE ${MAIN_LIST} ${EXTRA_SOURCES_LIST}
|
||||
PROPERTY LANGUAGE CUDA)
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
|
||||
list(TRANSFORM EXTRA_OPTIONS_LIST PREPEND "-Xcompiler=")
|
||||
else()
|
||||
set(LIST_)
|
||||
foreach(item IN LISTS EXTRA_OPTIONS_LIST)
|
||||
list(APPEND LIST_ "-Xcompiler=${item}")
|
||||
endforeach()
|
||||
set(EXTRA_OPTIONS_LIST ${LIST_})
|
||||
endif()
|
||||
list(TRANSFORM EXTRA_OPTIONS_LIST PREPEND "-Xcompiler=")
|
||||
endif()
|
||||
|
||||
# Actually add the executable
|
||||
|
||||
@@ -42,15 +42,9 @@
|
||||
#ifdef MFEM_USE_SUPERLU
|
||||
#error Building with SuperLU_DIST (MFEM_USE_SUPERLU=YES) requires MPI (MFEM_USE_MPI=YES)
|
||||
#endif
|
||||
#ifdef MFEM_USE_MUMPS
|
||||
#error Building with MUMPS (MFEM_USE_MUMPS=YES) requires MPI (MFEM_USE_MPI=YES)
|
||||
#endif
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
#error Building with STRUMPACK (MFEM_USE_STRUMPACK=YES) requires MPI (MFEM_USE_MPI=YES)
|
||||
#endif
|
||||
#ifdef MFEM_USE_MKL_CPARDISO
|
||||
#error Building with MKL CPARDISO (MFEM_USE_MKL_CPARDISO=YES) requires MPI (MFEM_USE_MPI=YES)
|
||||
#endif
|
||||
#ifdef MFEM_USE_PETSC
|
||||
#error Building with PETSc (MFEM_USE_PETSC=YES) requires MPI (MFEM_USE_MPI=YES)
|
||||
#endif
|
||||
|
||||
@@ -94,10 +94,6 @@
|
||||
// Enable MFEM functionality based on the SuperLU library.
|
||||
// #define MFEM_USE_SUPERLU
|
||||
|
||||
// Enable MFEM functionality based on the MUMPS library.
|
||||
// #define MFEM_USE_MUMPS
|
||||
// #define MFEM_MUMPS_VERSION @MFEM_MUMPS_VERSION@
|
||||
|
||||
// Enable MFEM functionality based on the STRUMPACK library.
|
||||
// #define MFEM_USE_STRUMPACK
|
||||
|
||||
@@ -167,7 +163,4 @@
|
||||
// library.
|
||||
// #define MFEM_USE_SIMMETRIX
|
||||
|
||||
// Enable interface to the MKL CPardiso library.
|
||||
// #define MFEM_USE_MKL_CPARDISO
|
||||
|
||||
#endif // MFEM_CONFIG_HEADER
|
||||
|
||||
@@ -32,7 +32,6 @@ MFEM_USE_SUNDIALS = @MFEM_USE_SUNDIALS@
|
||||
MFEM_USE_MESQUITE = @MFEM_USE_MESQUITE@
|
||||
MFEM_USE_SUITESPARSE = @MFEM_USE_SUITESPARSE@
|
||||
MFEM_USE_SUPERLU = @MFEM_USE_SUPERLU@
|
||||
MFEM_USE_MUMPS = @MFEM_USE_MUMPS@
|
||||
MFEM_USE_STRUMPACK = @MFEM_USE_STRUMPACK@
|
||||
MFEM_USE_GINKGO = @MFEM_USE_GINKGO@
|
||||
MFEM_USE_GNUTLS = @MFEM_USE_GNUTLS@
|
||||
@@ -53,7 +52,6 @@ MFEM_USE_CEED = @MFEM_USE_CEED@
|
||||
MFEM_USE_UMPIRE = @MFEM_USE_UMPIRE@
|
||||
MFEM_USE_SIMD = @MFEM_USE_SIMD@
|
||||
MFEM_USE_ADIOS2 = @MFEM_USE_ADIOS2@
|
||||
MFEM_USE_MKL_CPARDISO = @MFEM_USE_MKL_CPARDISO@
|
||||
|
||||
# Compiler, compile options, and link options
|
||||
MFEM_CXX = @MFEM_CXX@
|
||||
|
||||
@@ -52,7 +52,6 @@ option(MFEM_USE_CEED "Enable CEED" OFF)
|
||||
option(MFEM_USE_UMPIRE "Enable Umpire" OFF)
|
||||
option(MFEM_USE_SIMD "Enable use of SIMD intrinsics" OFF)
|
||||
option(MFEM_USE_ADIOS2 "Enable ADIOS2" OFF)
|
||||
option(MFEM_USE_MKL_CPARDISO "Enable MKL CPardiso" OFF)
|
||||
|
||||
set(MFEM_MPI_NP 4 CACHE STRING "Number of processes used for MPI tests")
|
||||
|
||||
@@ -181,10 +180,6 @@ set(HIOP_DIR "${MFEM_DIR}/../hiop/install" CACHE STRING
|
||||
set(HIOP_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
|
||||
"Packages that HiOp depends on.")
|
||||
|
||||
set(MKL_CPARDISO_DIR "" CACHE STRING "MKL installation path.")
|
||||
set(MKL_MPI_WRAPPER_LIB "mkl_blacs_mpich_lp64" CACHE STRING "MKL MPI wrapper library")
|
||||
set(MKL_LIBRARY_DIR "" CACHE STRING "Custom library subdirectory")
|
||||
|
||||
set(OCCA_DIR "${MFEM_DIR}/../occa" CACHE PATH "Path to OCCA")
|
||||
set(RAJA_DIR "${MFEM_DIR}/../raja" CACHE PATH "Path to RAJA")
|
||||
set(CEED_DIR "${MFEM_DIR}/../libCEED" CACHE PATH "Path to libCEED")
|
||||
|
||||
+7
-17
@@ -120,7 +120,6 @@ MFEM_USE_SUNDIALS = NO
|
||||
MFEM_USE_MESQUITE = NO
|
||||
MFEM_USE_SUITESPARSE = NO
|
||||
MFEM_USE_SUPERLU = NO
|
||||
MFEM_USE_MUMPS = NO
|
||||
MFEM_USE_STRUMPACK = NO
|
||||
MFEM_USE_GINKGO = NO
|
||||
MFEM_USE_GNUTLS = NO
|
||||
@@ -139,9 +138,9 @@ MFEM_USE_RAJA = NO
|
||||
MFEM_USE_OCCA = NO
|
||||
MFEM_USE_CEED = NO
|
||||
MFEM_USE_UMPIRE = NO
|
||||
MFEM_USE_CAMP = NO
|
||||
MFEM_USE_SIMD = NO
|
||||
MFEM_USE_ADIOS2 = NO
|
||||
MFEM_USE_MKL_CPARDISO = NO
|
||||
|
||||
# Compile and link options for zlib.
|
||||
ZLIB_DIR =
|
||||
@@ -158,7 +157,7 @@ HYPRE_OPT = -I$(HYPRE_DIR)/include
|
||||
HYPRE_LIB = -L$(HYPRE_DIR)/lib -lHYPRE
|
||||
|
||||
# METIS library configuration
|
||||
ifeq ($(MFEM_USE_SUPERLU)$(MFEM_USE_STRUMPACK)$(MFEM_USE_MUMPS),NONONO)
|
||||
ifeq ($(MFEM_USE_SUPERLU)$(MFEM_USE_STRUMPACK),NONO)
|
||||
ifeq ($(MFEM_USE_METIS_5),NO)
|
||||
METIS_DIR = @MFEM_DIR@/../metis-4.0
|
||||
METIS_OPT =
|
||||
@@ -234,7 +233,7 @@ SCALAPACK_DIR = @MFEM_DIR@/../scalapack-2.0.2
|
||||
SCALAPACK_OPT = -I$(SCALAPACK_DIR)/SRC
|
||||
SCALAPACK_LIB = -L$(SCALAPACK_DIR)/lib -lscalapack $(LAPACK_LIB)
|
||||
|
||||
# MPI Fortran library, needed e.g. by STRUMPACK or MUMPS
|
||||
# MPI Fortran library, needed e.g. by STRUMPACK
|
||||
# MPICH:
|
||||
MPI_FORTRAN_LIB = -lmpifort
|
||||
# OpenMPI:
|
||||
@@ -242,11 +241,6 @@ MPI_FORTRAN_LIB = -lmpifort
|
||||
# Additional Fortan library:
|
||||
# MPI_FORTRAN_LIB += -lgfortran
|
||||
|
||||
# MUMPS library configuration
|
||||
MUMPS_DIR =
|
||||
MUMPS_OPT = -I$(MUMPS_DIR)/include
|
||||
MUMPS_LIB = -Wl,-rpath,$(MUMPS_DIR)/lib -L$(MUMPS_DIR)/lib -ldmumps -lmumps_common -lpord $(SCALAPACK_LIB) $(LAPACK_LIB) $(MPI_FORTRAN_LIB)
|
||||
|
||||
# STRUMPACK library configuration
|
||||
STRUMPACK_DIR = @MFEM_DIR@/../STRUMPACK-build
|
||||
STRUMPACK_OPT = -I$(STRUMPACK_DIR)/include $(SCOTCH_OPT)
|
||||
@@ -379,14 +373,10 @@ UMPIRE_DIR = @MFEM_DIR@/../umpire
|
||||
UMPIRE_OPT = -I$(UMPIRE_DIR)/include
|
||||
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -lumpire
|
||||
|
||||
# MKL CPardiso library configuration
|
||||
MKL_CPARDISO_DIR ?=
|
||||
MKL_MPI_WRAPPER ?= mkl_blacs_mpich_lp64
|
||||
MKL_LIBRARY_SUBDIR ?= lib
|
||||
MKL_CPARDISO_OPT = -I$(MKL_CPARDISO_DIR)/include
|
||||
MKL_CPARDISO_LIB = -Wl,-rpath,$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR)\
|
||||
-L$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR) -l$(MKL_MPI_WRAPPER)\
|
||||
-lmkl_intel_lp64 -lmkl_sequential -lmkl_core
|
||||
# CAMP library configuration
|
||||
CAMP_DIR = @MFEM_DIR@/../camp
|
||||
CAMP_OPT = -I$(CAMP_DIR)/include
|
||||
CAMP_LIB = -L$(CAMP_DIR)/lib
|
||||
|
||||
# If YES, enable some informational messages
|
||||
VERBOSE = NO
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "dmumps_c.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
// Macros to expand a macro as a string
|
||||
#define STR_EXPAND(s) #s
|
||||
#define STR(s) STR_EXPAND(s)
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef MUMPS_VERSION
|
||||
const char *ptr = STR(MUMPS_VERSION);
|
||||
std::string s(ptr);
|
||||
s.erase(std::remove(s.begin(), s.end(), '"'), s.end());
|
||||
s.erase(std::remove(s.begin(), s.end(), '.'), s.end());
|
||||
std::cout << s << "\n";
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
+2
-19
@@ -42,10 +42,6 @@ GHV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(HYPRE_OPT))
|
||||
SMX = $(if $(MFEM_USE_PUMI:NO=),MFEM_USE_SIMMETRIX)
|
||||
SMX_PATH = $(PUMI_DIR)/include/gmi_sim.h
|
||||
SMX_FILE = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(SMX_PATH))
|
||||
MUMPS = $(MFEM_USE_MUMPS:NO=)
|
||||
GMV_CXX ?= $(MFEM_CXX)
|
||||
GMV = get_mumps_version
|
||||
GMV_FLAGS = $(subst @MFEM_DIR@,$(if $(MFEM_DIR),$(MFEM_DIR),..),$(MUMPS_OPT))
|
||||
|
||||
$(GHV): $(SRC)$(GHV).cpp
|
||||
$(call mfem-info, Determining HYPRE version ...)
|
||||
@@ -54,13 +50,6 @@ $(GHV).out: $(GHV)
|
||||
./$(GHV) > $(GHV).out
|
||||
.INTERMEDIATE: $(GHV) $(GHV).out
|
||||
|
||||
$(GMV): $(SRC)$(GMV).cpp
|
||||
$(call mfem-info, Determining MUMPS version ...)
|
||||
$(GMV_CXX) ${GMV_FLAGS} $(SRC)$(GMV).cpp -o $(GMV)
|
||||
$(GMV).out: $(GMV)
|
||||
./$(GMV) > $(GMV).out
|
||||
.INTERMEDIATE: $(GMV) $(GMV).out
|
||||
|
||||
get-hypre-version: $(GHV).out
|
||||
$(eval MFEM_HYPRE_VERSION:=$(shell cat $(GHV).out))
|
||||
$(if $(MFEM_HYPRE_VERSION),$(eval export MFEM_HYPRE_VERSION)\
|
||||
@@ -73,16 +62,10 @@ check-smx:
|
||||
$(call mfem-info, MFEM_USE_SIMMETRIX = $(MFEM_USE_SIMMETRIX))
|
||||
$(eval export MFEM_USE_SIMMETRIX)
|
||||
|
||||
get-mumps-version: $(GMV).out
|
||||
$(eval MFEM_MUMPS_VERSION:=$(shell cat $(GMV).out))
|
||||
$(if $(MFEM_MUMPS_VERSION),$(eval export MFEM_MUMPS_VERSION)\
|
||||
$(info MUMPS version: $(MFEM_MUMPS_VERSION)),\
|
||||
$(error Unable to determine MUMPS version))
|
||||
|
||||
header: $(if $(MPI),get-hypre-version,) $(if $(SMX),check-smx,) $(if $(MUMPS),get-mumps-version,)
|
||||
header: $(if $(MPI),get-hypre-version,) $(if $(SMX),check-smx)
|
||||
$(call mfem-info, Writing $(CONFIG_HPP) ...)
|
||||
@set -- && \
|
||||
for def in $${MFEM_DEFINES} $(if $(MPI),MFEM_HYPRE_VERSION) $(SMX) $(if $(MUMPS),MFEM_MUMPS_VERSION); do \
|
||||
for def in $${MFEM_DEFINES} $(if $(MPI),MFEM_HYPRE_VERSION) $(SMX); do \
|
||||
eval var=\$$$$def && \
|
||||
if [ "NO" != "$${var}" ]; then \
|
||||
set -- "$$@" -e "s|// \(#define $${def} \)|\1|" && \
|
||||
|
||||
+7
-50
@@ -78,14 +78,6 @@ groups_parallel=(
|
||||
"miniapps/electromagnetics"
|
||||
"joule.cpp"'
|
||||
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
|
||||
'"convergence"
|
||||
"Convergence tests:"
|
||||
"tests/convergence"
|
||||
"diffusion.cpp"'
|
||||
'"par-mesh-format"
|
||||
"Parallel mesh tests:"
|
||||
"tests/par-mesh-format"
|
||||
"ex1p.cpp"'
|
||||
)
|
||||
# All groups serial + parallel runs mixed in the same group:
|
||||
groups_all=(
|
||||
@@ -115,14 +107,6 @@ groups_all=(
|
||||
"miniapps/electromagnetics"
|
||||
"joule.cpp"'
|
||||
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
|
||||
'"convergence"
|
||||
"Convergence tests:"
|
||||
"tests/convergence"
|
||||
"diffusion.cpp"'
|
||||
'"par-mesh-format"
|
||||
"Parallel mesh tests:"
|
||||
"tests/par-mesh-format"
|
||||
"ex1p.cpp"'
|
||||
)
|
||||
make_all="all"
|
||||
base_timeformat=$'real: %3Rs user: %3Us sys: %3Ss %%cpu: %P'
|
||||
@@ -396,15 +380,10 @@ function timed_run()
|
||||
# This function is used to execute the sample runs
|
||||
function go()
|
||||
{
|
||||
# Strip leading and trailing spaces from $1 and store the result in cmd_line
|
||||
shopt -s extglob
|
||||
local cmd_line="${1##+( )}"
|
||||
cmd_line="${cmd_line%%+( )}"
|
||||
shopt -u extglob
|
||||
eval local cmd=(${cmd_line})
|
||||
local cmd=("$@")
|
||||
local res=""
|
||||
echo $sep
|
||||
echo "<${group}>" "${cmd_line}"
|
||||
echo "<${group}>" "${cmd[@]}"
|
||||
echo $sep
|
||||
if [ "${timing}" == "yes" ]; then
|
||||
timed_run "${cmd[@]}"
|
||||
@@ -416,15 +395,15 @@ function go()
|
||||
else
|
||||
res="${red}FAILED${none}"
|
||||
fi
|
||||
printf "[${res}] <${group}> ${cmd_line}\n"
|
||||
printf "[${res}] <${group}> ${cmd[*]}\n"
|
||||
if [ "${timing}" == "yes" ]; then
|
||||
printf "Run time: %s\n" "${timer}"
|
||||
timer=(${timer})
|
||||
timer="${timer[1]}"
|
||||
printf -v line "[$res](%8s) ${cmd_line}" "$timer"
|
||||
printf -v line "[$res](%8s) ${cmd[*]}" "$timer"
|
||||
summary=("${summary[@]}" "$line")
|
||||
else
|
||||
summary=("${summary[@]}" "[${res}] ${cmd_line}")
|
||||
summary=("${summary[@]}" "[${res}] ${cmd[*]}")
|
||||
fi
|
||||
echo $sep
|
||||
}
|
||||
@@ -459,7 +438,7 @@ function go_group()
|
||||
fi
|
||||
for run in "${runs[@]}"; do
|
||||
if [ "${run}" == "" ]; then continue; fi
|
||||
eval go \"\${run_prefix} \${run} \${run_suffix}\" $output
|
||||
eval go \${run_prefix} \${run} \${run_suffix} $output
|
||||
done
|
||||
done
|
||||
${make} clean-exec
|
||||
@@ -525,7 +504,7 @@ function echo_run()
|
||||
{
|
||||
echo " $@"
|
||||
{ echo " $@"; echo "$sep";
|
||||
eval "$@"
|
||||
"$@"
|
||||
echo "$sep"; } >> "$echo_log" 2>&1
|
||||
}
|
||||
|
||||
@@ -545,28 +524,6 @@ function build_all()
|
||||
echo_run ${make} config ${mfem_config} || exit 1
|
||||
echo_run ${make} ${make_j} || exit 1
|
||||
echo_run ${make} ${make_all} ${make_j} || exit 1
|
||||
# Build groups in directories other than the directories built by 'make all':
|
||||
for group_params in "${groups[@]}"; do
|
||||
eval params=(${group_params})
|
||||
group_dir="${params[2]}"
|
||||
case "$group_dir" in
|
||||
(examples*|miniapps*)
|
||||
# Built by 'make all'
|
||||
;;
|
||||
(*)
|
||||
if [ "${mfem_dir}" != "${mfem_build_dir}" ]; then
|
||||
echo_run mkdir -p "${group_dir}" || exit 1
|
||||
echo_run cd "${group_dir}" || exit 1
|
||||
echo_run cp -af "${mfem_dir}/${group_dir}/makefile" . || exit 1
|
||||
else
|
||||
echo_run cd "${group_dir}" || exit 1
|
||||
fi
|
||||
echo_run ${make} clean || exit 1
|
||||
echo_run ${make} MFEM_DIR="${mfem_dir}" ${make_j} || exit 1
|
||||
echo_run cd "${mfem_build_dir}" || exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Function that runs all sample runs, given by the array variable "groups".
|
||||
|
||||
@@ -1,38 +1,13 @@
|
||||
SetFactory("OpenCASCADE");
|
||||
|
||||
// Select periodic mesh by setting this to either 0 - standard, 1 - periodic
|
||||
periodic = 1;
|
||||
|
||||
// Set the geometry order (1, 2, ..., 9)
|
||||
order = 3;
|
||||
|
||||
// Set the element type (3 - triangles, 4 - quadrilaterals)
|
||||
type = 3;
|
||||
|
||||
// Number of radial elements
|
||||
nrad = 2;
|
||||
|
||||
// Number of azimuthal elements on inner arc
|
||||
nazm1 = 3;
|
||||
|
||||
// Number of azimuthal elements on outer arc
|
||||
nazm2 = 5;
|
||||
|
||||
// Note: Using type = 4 with nazm1 != nazm2 can lead to mixed meshes
|
||||
// containing both triangles and quadrilaterals.
|
||||
|
||||
// Inner and outer radii
|
||||
R1 = 1.0;
|
||||
R2 = 2.0;
|
||||
|
||||
// Angular size of the sector
|
||||
Phi = Pi/3.0;
|
||||
|
||||
Point(1) = {0.0, 0, 0, 1.0};
|
||||
Point(2) = {R1, 0, 0, 1.0};
|
||||
Point(3) = {R2, 0, 0, 1.0};
|
||||
Point(4) = {R1*Cos(Phi), R1*Sin(Phi), 0, 1.0};
|
||||
Point(5) = {R2*Cos(Phi), R2*Sin(Phi), 0, 1.0};
|
||||
Point(4) = {R1*Cos(Pi/3), R1*Sin(Pi/3), 0, 1.0};
|
||||
Point(5) = {R2*Cos(Pi/3), R2*Sin(Pi/3), 0, 1.0};
|
||||
Line(1) = {2, 3};
|
||||
Line(2) = {4, 5};
|
||||
Circle(3) = {2, 1, 4};
|
||||
@@ -40,23 +15,13 @@ Circle(4) = {3, 1, 5};
|
||||
Curve Loop(5) = {1, 4, -2, -3};
|
||||
Plane Surface(1) = {5};
|
||||
|
||||
Transfinite Curve{1} = nrad+1;
|
||||
Transfinite Curve{2} = nrad+1;
|
||||
Transfinite Curve{3} = nazm1+1;
|
||||
Transfinite Curve{4} = nazm2+1;
|
||||
|
||||
If (nazm1 == nazm2)
|
||||
Transfinite Surface{1};
|
||||
EndIf
|
||||
|
||||
If (type == 4)
|
||||
Recombine Surface {1};
|
||||
EndIf
|
||||
Transfinite Curve{1} = 7;
|
||||
Transfinite Curve{2} = 7;
|
||||
Transfinite Curve{3} = 4;
|
||||
Transfinite Curve{4} = 10;
|
||||
|
||||
// Set a rotation periodicity constraint:
|
||||
If (periodic)
|
||||
Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Phi};
|
||||
EndIf
|
||||
Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Pi/3};
|
||||
|
||||
// Tag surfaces and volumes with positive integers
|
||||
Physical Curve(1) = {3};
|
||||
@@ -65,22 +30,8 @@ Physical Curve(3) = {1};
|
||||
Physical Curve(4) = {2};
|
||||
Physical Surface(1) = {1};
|
||||
|
||||
// Optimize the high-order mesh
|
||||
// See https://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eHighOrderOptimize
|
||||
// Mesh.ElementOrder = order;
|
||||
// Mesh.HighOrderOptimize = 1;
|
||||
|
||||
// Generate 2D mesh
|
||||
Mesh 2;
|
||||
SetOrder order;
|
||||
Mesh.MshFileVersion = 2.2;
|
||||
|
||||
// Check the element quality (the Plugin may be called AnalyseCurvedMesh)
|
||||
// Plugin(AnalyseMeshQuality).JacobianDeterminant = 1;
|
||||
// Plugin(AnalyseMeshQuality).Run;
|
||||
|
||||
If (periodic)
|
||||
Save Sprintf("periodic-annulus-sector-t%01g-o%01g.msh", type, order);
|
||||
Else
|
||||
Save Sprintf("annulus-sector-t%01g-o%01g.msh", type, order);
|
||||
EndIf
|
||||
Save "periodic-annulus-sector.msh";
|
||||
|
||||
+161
-168
@@ -2,191 +2,184 @@ $MeshFormat
|
||||
2.2 0 8
|
||||
$EndMeshFormat
|
||||
$Nodes
|
||||
136
|
||||
55
|
||||
1 1 0 0
|
||||
2 2 0 0
|
||||
3 0.5000000000000001 0.8660254037844386 0
|
||||
4 1 1.732050807568877 0
|
||||
5 1.5 0 0
|
||||
6 1.166666666666667 0 0
|
||||
7 1.333333333333333 0 0
|
||||
5 1.166666666666667 0 0
|
||||
6 1.333333333333333 0 0
|
||||
7 1.5 0 0
|
||||
8 1.666666666666667 0 0
|
||||
9 1.833333333333333 0 0
|
||||
10 0.7500000000000002 1.299038105676658 0
|
||||
11 0.5833333333333335 1.010362971081845 0
|
||||
12 0.6666666666666667 1.154700538379251 0
|
||||
10 0.5833333333333335 1.010362971081845 0
|
||||
11 0.6666666666666667 1.154700538379251 0
|
||||
12 0.7500000000000002 1.299038105676658 0
|
||||
13 0.8333333333333335 1.443375672974064 0
|
||||
14 0.9166666666666669 1.587713240271471 0
|
||||
15 0.9396926207859085 0.3420201433256683 0
|
||||
16 0.7660444431189786 0.6427876096865386 0
|
||||
17 0.993238357741943 0.1160929141252301 0
|
||||
18 0.9730448705798238 0.2306158707424401 0
|
||||
19 0.8936326403234125 0.4487991802004617 0
|
||||
20 0.8354878114129367 0.5495089780708056 0
|
||||
21 0.6862416378687343 0.7273736415730481 0
|
||||
22 0.597158591702787 0.8021231927550432 0
|
||||
23 1.956295201467611 0.4158233816355181 0
|
||||
24 1.827090915285202 0.8134732861515996 0
|
||||
25 1.618033988749896 1.175570504584944 0
|
||||
26 1.338261212717719 1.486289650954786 0
|
||||
27 1.995128100519648 0.1395129474882505 0
|
||||
28 1.980536137483141 0.278346201920131 0
|
||||
29 1.922523391876638 0.551274711633998 0
|
||||
30 1.879385241571817 0.6840402866513373 0
|
||||
31 1.765895185717855 0.9389431255717802 0
|
||||
32 1.696096192312853 1.059838528466408 0
|
||||
33 1.532088886237958 1.285575219373077 0
|
||||
34 1.438679600677305 1.389316740917992 0
|
||||
35 1.231322950651319 1.576021507213442 0
|
||||
36 1.118385806941496 1.658075145110082 0
|
||||
37 1.162276263405681 0.6710405135499813 0
|
||||
38 1.248615852873337 1.079531485311822 0
|
||||
39 1.559209616901855 0.5415673055003691 0
|
||||
40 1.478306597054007 0.8535007117539289 0
|
||||
41 0.9210953433941653 0.9653302893212266 0
|
||||
42 1.296548225291847 0.3150268220262836 0
|
||||
43 1.055002035226811 1.358510675893086 0
|
||||
44 1.704005774249187 0.2344032256041583 0
|
||||
45 0.6403651144647218 0.8991270322967013 0
|
||||
46 0.7807302289294435 0.9322286608089638 0
|
||||
47 0.864063562262777 1.07656622810637 0
|
||||
48 0.8070317811313885 1.187802166891514 0
|
||||
49 0.7236984477980553 1.043464599594108 0
|
||||
50 1.432182741763949 0.1050089406754279 0
|
||||
51 1.364365483527898 0.2100178813508558 0
|
||||
52 1.197698816861231 0.2100178813508558 0
|
||||
53 1.098849408430616 0.1050089406754279 0
|
||||
54 1.265516075097282 0.1050089406754278 0
|
||||
55 0.8177280765440409 0.7503018362314346 0
|
||||
56 0.869411709969103 0.8578160627763305 0
|
||||
57 0.7348318576552288 0.8316090412164392 0
|
||||
58 1.177596357123201 0.3240245957927452 0
|
||||
59 1.058644488954555 0.3330223695592067 0
|
||||
60 1.087610484537871 0.2205785356313179 0
|
||||
61 1.267619707955123 0.7318605796179638 0
|
||||
62 1.372963152504565 0.7926806456859463 0
|
||||
63 1.40174301566045 0.9288443029398934 0
|
||||
64 1.325179434266893 1.004187894125858 0
|
||||
65 1.219835989717452 0.9433678280578752 0
|
||||
66 1.191056126561566 0.8072041708039283 0
|
||||
67 1.296399571111008 0.8680242368719107 0
|
||||
68 1.532241943619239 0.645545107584889 0
|
||||
69 1.505274270336623 0.7495229096694089 0
|
||||
70 1.294587381237739 0.6278827775334439 0
|
||||
71 1.426898499069797 0.5847250415169065 0
|
||||
72 1.399930825787181 0.6887028436014264 0
|
||||
73 1.139442349713613 1.041464419981624 0
|
||||
74 1.030268846553889 1.003397354651425 0
|
||||
75 1.001488983398004 0.8672336973974781 0
|
||||
76 1.081882623401843 0.7691371054737297 0
|
||||
77 1.110662486557728 0.9053007627276766 0
|
||||
78 1.207033584034403 0.5523692830420821 0
|
||||
79 1.251790904663125 0.4336980525341829 0
|
||||
80 1.384102022495183 0.3905403165176455 0
|
||||
81 1.471655819698519 0.4660538110090073 0
|
||||
82 1.339344701866461 0.5092115470255447 0
|
||||
83 1.73779714915742 0.7228379592678562 0
|
||||
84 1.648503383029637 0.6322026323841127 0
|
||||
85 1.691571478423774 0.4996526642120855 0
|
||||
86 1.823933339945692 0.4577380229238018 0
|
||||
87 1.787039416783436 0.5922941012619014 0
|
||||
88 1.308379426102925 1.350703595740465 0
|
||||
89 1.278497639488131 1.215117540526144 0
|
||||
90 1.371755231498856 1.111544491736196 0
|
||||
91 1.494894610124376 1.14355749816057 0
|
||||
92 1.4064614465962 1.25147448186763 0
|
||||
93 1.013887168325833 0.451693600067106 0
|
||||
94 1.088081715865757 0.5613670568085436 0
|
||||
95 1.03019898997678 0.6616228789288338 0
|
||||
96 0.8981217165478794 0.6522052443076862 0
|
||||
97 0.9637989050473432 0.5564495572737495 0
|
||||
98 1.432367408277627 0.2881522898855752 0
|
||||
99 1.568186591263407 0.2612777577448668 0
|
||||
100 1.655740388466743 0.3367912522362286 0
|
||||
101 1.607475002684299 0.4391792788682989 0
|
||||
102 1.519921205480963 0.3636657843769371 0
|
||||
103 1.184077913657828 1.17252454883891 0
|
||||
104 1.119539974442319 1.265517612365998 0
|
||||
105 1.010366471282595 1.2274505470358 0
|
||||
106 0.9657309073383804 1.096390418178513 0
|
||||
107 1.074904410498104 1.134457483508712 0
|
||||
108 1.901335258083062 0.07813440853471942 0
|
||||
109 1.802670516166124 0.1562688170694388 0
|
||||
110 1.636003849499458 0.156268817069439 0
|
||||
111 1.568001924749729 0.07813440853471942 0
|
||||
112 1.734668591416396 0.07813440853471944 0
|
||||
113 0.8516673450756037 1.318862295748801 0
|
||||
114 0.9533346901512071 1.338686485820944 0
|
||||
115 1.03666802348454 1.48302405311835 0
|
||||
116 1.01833401174227 1.607537430343614 0
|
||||
117 0.9350006784089369 1.463199863046207 0
|
||||
118 1.710829475874804 0.8268157613523761 0
|
||||
119 1.594568036464405 0.8401582365531526 0
|
||||
120 1.621535709747021 0.7361804344686326 0
|
||||
121 1.52488239428597 0.9608573093642675 0
|
||||
122 1.571458191517933 1.068213906974606 0
|
||||
123 1.448318812892413 1.036200900550232 0
|
||||
124 0.908699126206992 1.207626356963657 0
|
||||
125 1.500184666513678 0.1831433492101474 0
|
||||
126 1.646765991694905 0.9507607885973723 0
|
||||
127 0.9498053499729417 0.7597194708525821 0
|
||||
128 1.132839036494479 0.4426958263006443 0
|
||||
129 1.149421761057113 1.40110366758032 0
|
||||
130 1.243841486887416 1.443696659267553 0
|
||||
131 1.134903597606542 1.530869109405537 0
|
||||
132 1.872198725728137 0.3553499962917315 0
|
||||
133 1.788102249988661 0.2948766109479449 0
|
||||
134 1.893223337417325 0.2174207916708467 0
|
||||
135 1.213959700272622 1.308110604053232 0
|
||||
136 1.739836864206217 0.3972646375800152 0
|
||||
17 1.986476715483886 0.2321858282504602 0
|
||||
18 1.946089741159648 0.4612317414848793 0
|
||||
19 1.879385241571817 0.6840402866513365 0
|
||||
20 1.787265280646825 0.8975983604009234 0
|
||||
21 1.670975622825874 1.09901795614161 0
|
||||
22 1.532088886237958 1.285575219373077 0
|
||||
23 1.372483275737469 1.454747283146095 0
|
||||
24 1.194317183405575 1.604246385510085 0
|
||||
25 1.425989114816062 0.1915326920916892 0
|
||||
26 0.8788667344146573 1.13917645290495 0
|
||||
27 1.630372059110754 0.7154531062316609 0
|
||||
28 1.436395769298814 1.053728612482506 0
|
||||
29 1.081023776188756 0.6241293681829633 0
|
||||
30 1.168737372335971 1.428012728596308 0
|
||||
31 1.821063986059922 0.298149890497067 0
|
||||
32 1.234707097211386 0.3469796339295647 0
|
||||
33 1.377747393186519 0.6200150626754309 0
|
||||
34 1.457047681210906 0.3890895843559762 0
|
||||
35 0.917846726184522 0.8957978954532204 0
|
||||
36 1.218335619030348 0.9017812086952638 0
|
||||
37 1.066623110765233 1.061857005744772 0
|
||||
38 1.587029716281926 0.1355955181472859 0
|
||||
39 1.744445799211916 0.1441515753740107 0
|
||||
40 1.25 0.1443375672974065 0
|
||||
41 1.453660070628011 0.8435769396609902 0
|
||||
42 1.741367044061892 0.499612708014486 0
|
||||
43 1.30550638526547 1.257610469847477 0
|
||||
44 1.118213276932792 0.1666674689105279 0
|
||||
45 0.9109440214958271 1.306610291787315 0
|
||||
46 0.9970618258753989 1.438658589955562 0
|
||||
47 0.7499999999999998 1.010362971081845 0
|
||||
48 0.7034449005273667 0.8850673702175776 0
|
||||
49 1.605449512513618 0.9269067082200894 0
|
||||
50 1.561654019115059 0.5298592532912715 0
|
||||
51 1.229782222487711 1.096820457143683 0
|
||||
52 1.617066998712459 0.3090202662210922 0
|
||||
53 1.079645953234324 1.246963713711438 0
|
||||
54 1.877063966817811 0.1348974588243076 0
|
||||
55 1.055356609656722 1.558136350380461 0
|
||||
$EndNodes
|
||||
$Elements
|
||||
38
|
||||
1 26 2 3 1 1 5 6 7
|
||||
2 26 2 3 1 5 2 8 9
|
||||
3 26 2 4 2 3 10 11 12
|
||||
4 26 2 4 2 10 4 13 14
|
||||
5 26 2 1 3 1 15 17 18
|
||||
6 26 2 1 3 15 16 19 20
|
||||
7 26 2 1 3 16 3 21 22
|
||||
8 26 2 2 4 2 23 27 28
|
||||
9 26 2 2 4 23 24 29 30
|
||||
10 26 2 2 4 24 25 31 32
|
||||
11 26 2 2 4 25 26 33 34
|
||||
12 26 2 2 4 26 4 35 36
|
||||
13 21 2 1 1 3 41 10 45 46 47 48 12 11 49
|
||||
14 21 2 1 1 5 42 1 50 51 52 53 6 7 54
|
||||
15 21 2 1 1 16 41 3 55 56 46 45 22 21 57
|
||||
16 21 2 1 1 1 42 15 53 52 58 59 18 17 60
|
||||
17 21 2 1 1 37 40 38 61 62 63 64 65 66 67
|
||||
18 21 2 1 1 39 40 37 68 69 62 61 70 71 72
|
||||
19 21 2 1 1 38 41 37 73 74 75 76 66 65 77
|
||||
20 21 2 1 1 37 42 39 78 79 80 81 71 70 82
|
||||
21 21 2 1 1 24 39 23 83 84 85 86 29 30 87
|
||||
22 21 2 1 1 26 38 25 88 89 90 91 33 34 92
|
||||
23 21 2 1 1 15 37 16 93 94 95 96 20 19 97
|
||||
24 21 2 1 1 42 44 39 98 99 100 101 81 80 102
|
||||
25 21 2 1 1 38 43 41 103 104 105 106 74 73 107
|
||||
26 21 2 1 1 2 44 5 108 109 110 111 8 9 112
|
||||
27 21 2 1 1 10 43 4 113 114 115 116 14 13 117
|
||||
28 21 2 1 1 24 40 39 118 119 69 68 84 83 120
|
||||
29 21 2 1 1 38 40 25 64 63 121 122 91 90 123
|
||||
30 21 2 1 1 41 43 10 106 105 114 113 48 47 124
|
||||
31 21 2 1 1 5 44 42 111 110 99 98 51 50 125
|
||||
32 21 2 1 1 25 40 24 122 121 119 118 31 32 126
|
||||
33 21 2 1 1 37 41 16 76 75 56 55 96 95 127
|
||||
34 21 2 1 1 15 42 37 59 58 79 78 94 93 128
|
||||
35 21 2 1 1 4 43 26 116 115 129 130 35 36 131
|
||||
36 21 2 1 1 23 44 2 132 133 109 108 27 28 134
|
||||
37 21 2 1 1 26 43 38 130 129 104 103 89 88 135
|
||||
38 21 2 1 1 39 44 23 101 100 133 132 86 85 136
|
||||
108
|
||||
1 1 2 3 1 1 5
|
||||
2 1 2 3 1 5 6
|
||||
3 1 2 3 1 6 7
|
||||
4 1 2 3 1 7 8
|
||||
5 1 2 3 1 8 9
|
||||
6 1 2 3 1 9 2
|
||||
7 1 2 4 2 3 10
|
||||
8 1 2 4 2 10 11
|
||||
9 1 2 4 2 11 12
|
||||
10 1 2 4 2 12 13
|
||||
11 1 2 4 2 13 14
|
||||
12 1 2 4 2 14 4
|
||||
13 1 2 1 3 1 15
|
||||
14 1 2 1 3 15 16
|
||||
15 1 2 1 3 16 3
|
||||
16 1 2 2 4 2 17
|
||||
17 1 2 2 4 17 18
|
||||
18 1 2 2 4 18 19
|
||||
19 1 2 2 4 19 20
|
||||
20 1 2 2 4 20 21
|
||||
21 1 2 2 4 21 22
|
||||
22 1 2 2 4 22 23
|
||||
23 1 2 2 4 23 24
|
||||
24 1 2 2 4 24 4
|
||||
25 2 2 1 1 32 40 25
|
||||
26 2 2 1 1 25 34 32
|
||||
27 2 2 1 1 33 41 36
|
||||
28 2 2 1 1 38 52 25
|
||||
29 2 2 1 1 33 36 29
|
||||
30 2 2 1 1 26 47 35
|
||||
31 2 2 1 1 35 37 26
|
||||
32 2 2 1 1 25 52 34
|
||||
33 2 2 1 1 32 44 40
|
||||
34 2 2 1 1 15 32 29
|
||||
35 2 2 1 1 15 29 16
|
||||
36 2 2 1 1 36 41 28
|
||||
37 2 2 1 1 32 33 29
|
||||
38 2 2 1 1 50 52 42
|
||||
39 2 2 1 1 32 34 33
|
||||
40 2 2 1 1 42 52 31
|
||||
41 2 2 1 1 43 53 51
|
||||
42 2 2 1 1 27 41 33
|
||||
43 2 2 1 1 26 53 45
|
||||
44 2 2 1 1 18 31 17
|
||||
45 2 2 1 1 29 35 16
|
||||
46 2 2 1 1 29 36 35
|
||||
47 2 2 1 1 24 30 23
|
||||
48 2 2 1 1 30 53 43
|
||||
49 2 2 1 1 17 54 2
|
||||
50 2 2 1 1 4 55 24
|
||||
51 2 2 1 1 28 51 36
|
||||
52 2 2 1 1 47 48 35
|
||||
53 2 2 1 1 36 37 35
|
||||
54 2 2 1 1 37 53 26
|
||||
55 2 2 1 1 22 28 21
|
||||
56 2 2 1 1 20 27 19
|
||||
57 2 2 1 1 33 50 27
|
||||
58 2 2 1 1 15 44 32
|
||||
59 2 2 1 1 18 42 31
|
||||
60 2 2 1 1 30 43 23
|
||||
61 2 2 1 1 35 48 16
|
||||
62 2 2 1 1 31 54 17
|
||||
63 2 2 1 1 9 39 8
|
||||
64 2 2 1 1 8 38 7
|
||||
65 2 2 1 1 7 25 6
|
||||
66 2 2 1 1 22 43 28
|
||||
67 2 2 1 1 23 43 22
|
||||
68 2 2 1 1 39 54 31
|
||||
69 2 2 1 1 19 42 18
|
||||
70 2 2 1 1 24 55 30
|
||||
71 2 2 1 1 27 42 19
|
||||
72 2 2 1 1 13 46 14
|
||||
73 2 2 1 1 51 53 37
|
||||
74 2 2 1 1 39 52 38
|
||||
75 2 2 1 1 6 40 5
|
||||
76 2 2 1 1 34 52 50
|
||||
77 2 2 1 1 12 45 13
|
||||
78 2 2 1 1 30 55 46
|
||||
79 2 2 1 1 10 47 11
|
||||
80 2 2 1 1 8 39 38
|
||||
81 2 2 1 1 28 49 21
|
||||
82 2 2 1 1 7 38 25
|
||||
83 2 2 1 1 41 49 28
|
||||
84 2 2 1 1 20 49 27
|
||||
85 2 2 1 1 11 26 12
|
||||
86 2 2 1 1 27 49 41
|
||||
87 2 2 1 1 31 52 39
|
||||
88 2 2 1 1 25 40 6
|
||||
89 2 2 1 1 2 54 9
|
||||
90 2 2 1 1 14 55 4
|
||||
91 2 2 1 1 45 53 46
|
||||
92 2 2 1 1 45 46 13
|
||||
93 2 2 1 1 5 44 1
|
||||
94 2 2 1 1 21 49 20
|
||||
95 2 2 1 1 46 53 30
|
||||
96 2 2 1 1 3 48 10
|
||||
97 2 2 1 1 34 50 33
|
||||
98 2 2 1 1 36 51 37
|
||||
99 2 2 1 1 26 45 12
|
||||
100 2 2 1 1 11 47 26
|
||||
101 2 2 1 1 27 50 42
|
||||
102 2 2 1 1 40 44 5
|
||||
103 2 2 1 1 43 51 28
|
||||
104 2 2 1 1 10 48 47
|
||||
105 2 2 1 1 9 54 39
|
||||
106 2 2 1 1 46 55 14
|
||||
107 2 2 1 1 1 44 15
|
||||
108 2 2 1 1 16 48 3
|
||||
$EndElements
|
||||
$Periodic
|
||||
1
|
||||
1 1 2
|
||||
Affine 0.5000000000000001 0.8660254037844386 0 0 -0.8660254037844386 0.5000000000000001 0 0 0 0 1 0 0 0 0 1
|
||||
3
|
||||
7
|
||||
9 14
|
||||
6 11
|
||||
8 13
|
||||
5 10
|
||||
1 3
|
||||
7 12
|
||||
2 4
|
||||
1 3
|
||||
$EndPeriodic
|
||||
|
||||
+13
-129
@@ -1,141 +1,25 @@
|
||||
// Select periodic mesh by setting this to either 0 - standard, 1 - periodic
|
||||
periodic = 1;
|
||||
SetFactory("OpenCASCADE");
|
||||
|
||||
// Set the geometry order (1, 2, ..., 10 for tetrahedra or 9 for other types)
|
||||
order = 3;
|
||||
R = 1.5;
|
||||
r = 0.5;
|
||||
|
||||
// Set the element type (4 - tetrahedra, 6 - wedges, 8 - hexahedra)
|
||||
type = 8;
|
||||
Torus(1) = {0,0,0, R, r, Pi/3};
|
||||
|
||||
// Minor and major radii
|
||||
R1 = 1.0;
|
||||
R2 = 2.0;
|
||||
pts() = PointsOf{ Volume{1}; };
|
||||
|
||||
// Side length of interior square
|
||||
A1 = 0.8;
|
||||
|
||||
// Angular size of the sector
|
||||
Phi = Pi/3.0;
|
||||
|
||||
// Number of azimuthal elements
|
||||
nazm = 3;
|
||||
|
||||
// Number of elements around a quarter of the circle
|
||||
narc = 2;
|
||||
|
||||
// Number of elements between surface and interior square
|
||||
nshl = 1;
|
||||
|
||||
lc = 0.5;
|
||||
a1 = A1 / Sqrt(2.0);
|
||||
|
||||
Point(1) = {R2+R1, 0, 0, lc};
|
||||
Point(2) = {R2, 0, R1, lc};
|
||||
Point(3) = {R2-R1, 0, 0, lc};
|
||||
Point(4) = {R2, 0, -R1, lc};
|
||||
Point(5) = {R2, 0, 0, lc};
|
||||
Point(6) = {R2+a1, 0, 0, lc};
|
||||
Point(7) = {R2, 0, a1, lc};
|
||||
Point(8) = {R2-a1, 0, 0, lc};
|
||||
Point(9) = {R2, 0, -a1, lc};
|
||||
|
||||
Circle(1) = {1,5,2};
|
||||
Circle(2) = {2,5,3};
|
||||
Circle(3) = {3,5,4};
|
||||
Circle(4) = {4,5,1};
|
||||
|
||||
Line(5) = {6,1};
|
||||
Line(6) = {7,2};
|
||||
Line(7) = {8,3};
|
||||
Line(8) = {9,4};
|
||||
|
||||
Line(9) = {6, 7};
|
||||
Line(10) = {7, 8};
|
||||
Line(11) = {8, 9};
|
||||
Line(12) = {9, 6};
|
||||
|
||||
Line Loop(101) = {1, -6, -9, 5};
|
||||
Line Loop(102) = {2, -7, -10, 6};
|
||||
Line Loop(103) = {3, -8, -11, 7};
|
||||
Line Loop(104) = {4, -5, -12, 8};
|
||||
Line Loop(105) = {9, 10, 11, 12};
|
||||
|
||||
Plane Surface(201) = {101};
|
||||
Plane Surface(202) = {102};
|
||||
Plane Surface(203) = {103};
|
||||
Plane Surface(204) = {104};
|
||||
Plane Surface(205) = {105};
|
||||
|
||||
Transfinite Curve{1} = narc+1;
|
||||
Transfinite Curve{2} = narc+1;
|
||||
Transfinite Curve{3} = narc+1;
|
||||
Transfinite Curve{4} = narc+1;
|
||||
|
||||
Transfinite Curve{5} = nshl+1;
|
||||
Transfinite Curve{6} = nshl+1;
|
||||
Transfinite Curve{7} = nshl+1;
|
||||
Transfinite Curve{8} = nshl+1;
|
||||
|
||||
Transfinite Curve{9} = narc+1;
|
||||
Transfinite Curve{10} = narc+1;
|
||||
Transfinite Curve{11} = narc+1;
|
||||
Transfinite Curve{12} = narc+1;
|
||||
|
||||
If (type == 8)
|
||||
Recombine Surface {201};
|
||||
Recombine Surface {202};
|
||||
Recombine Surface {203};
|
||||
Recombine Surface {204};
|
||||
Recombine Surface {205};
|
||||
|
||||
Transfinite Surface {201} = {1,2,7,6};
|
||||
Transfinite Surface {202} = {2,3,8,7};
|
||||
Transfinite Surface {203} = {3,4,9,8};
|
||||
Transfinite Surface {204} = {4,1,6,9};
|
||||
Transfinite Surface {205} = {6,7,8,9};
|
||||
EndIf
|
||||
|
||||
If (type == 4)
|
||||
Extrude { {0,0,1} , {0,0,0} , Phi} {
|
||||
Surface{201,202,203,204,205}; Layers{nazm};
|
||||
}
|
||||
Else
|
||||
Extrude { {0,0,1} , {0,0,0} , Phi} {
|
||||
Surface{201,202,203,204,205}; Layers{nazm}; Recombine;
|
||||
}
|
||||
EndIf
|
||||
Characteristic Length{ pts() } = 0.25;
|
||||
|
||||
// Set a rotation periodicity constraint:
|
||||
If (periodic)
|
||||
Periodic Surface{227} = {201} Rotate{{0,0,1}, {0,0,0}, Phi};
|
||||
Periodic Surface{249} = {202} Rotate{{0,0,1}, {0,0,0}, Phi};
|
||||
Periodic Surface{271} = {203} Rotate{{0,0,1}, {0,0,0}, Phi};
|
||||
Periodic Surface{293} = {204} Rotate{{0,0,1}, {0,0,0}, Phi};
|
||||
Periodic Surface{315} = {205} Rotate{{0,0,1}, {0,0,0}, Phi};
|
||||
EndIf
|
||||
Periodic Surface{3} = {2} Rotate{{0,0,1}, {0,0,0}, Pi/3};
|
||||
|
||||
// Tag surfaces and volumes with positive integers
|
||||
Physical Surface(1) = {201,202,203,204,205};
|
||||
Physical Surface(2) = {227,249,271,293,315};
|
||||
Physical Surface(3) = {214,236,258,280};
|
||||
Physical Volume(1) = {1,2,3,4,5};
|
||||
|
||||
// Optimize the high-order mesh
|
||||
// See https://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eHighOrderOptimize
|
||||
// Mesh.ElementOrder = order;
|
||||
// Mesh.HighOrderOptimize = 1;
|
||||
Physical Surface(1) = {1};
|
||||
Physical Surface(2) = {2};
|
||||
Physical Surface(3) = {3};
|
||||
Physical Volume(1) = {1};
|
||||
|
||||
// Generate 3D mesh
|
||||
Mesh 3;
|
||||
SetOrder order;
|
||||
|
||||
Mesh.MshFileVersion = 2.2;
|
||||
|
||||
// Check the element quality (the Plugin may be called AnalyseCurvedMesh)
|
||||
// Plugin(AnalyseMeshQuality).JacobianDeterminant = 1;
|
||||
// Plugin(AnalyseMeshQuality).Run;
|
||||
|
||||
If (periodic)
|
||||
Save Sprintf("periodic-torus-sector-t%01g-o%01g.msh", type, order);
|
||||
Else
|
||||
Save Sprintf("torus-sector-t%01g-o%01g.msh", type, order);
|
||||
EndIf
|
||||
Save "periodic-torus-sector.msh";
|
||||
|
||||
+1046
-1344
File diff suppressed because it is too large
Load Diff
@@ -1,118 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
#
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
elements
|
||||
20
|
||||
1 3 0 1 6 5
|
||||
1 3 1 2 7 6
|
||||
1 3 2 3 8 7
|
||||
1 3 3 4 9 8
|
||||
1 3 5 6 11 10
|
||||
1 2 6 7 11
|
||||
1 2 7 12 11
|
||||
1 2 7 8 13
|
||||
1 2 7 13 12
|
||||
1 3 8 9 14 13
|
||||
1 3 10 11 16 15
|
||||
1 2 11 12 17
|
||||
1 2 11 17 16
|
||||
1 2 12 13 17
|
||||
1 2 13 18 17
|
||||
1 3 13 14 19 18
|
||||
1 3 15 16 21 20
|
||||
1 3 16 17 22 21
|
||||
1 3 17 18 23 22
|
||||
1 3 18 19 24 23
|
||||
|
||||
boundary
|
||||
16
|
||||
2 1 0 1
|
||||
2 1 1 2
|
||||
2 1 2 3
|
||||
2 1 3 4
|
||||
2 1 21 20
|
||||
2 1 22 21
|
||||
2 1 23 22
|
||||
2 1 24 23
|
||||
1 1 5 0
|
||||
1 1 10 5
|
||||
1 1 15 10
|
||||
1 1 20 15
|
||||
1 1 4 9
|
||||
1 1 9 14
|
||||
1 1 14 19
|
||||
1 1 19 24
|
||||
|
||||
vertices
|
||||
25
|
||||
|
||||
nodes
|
||||
FiniteElementSpace
|
||||
FiniteElementCollection: H1_2D_P1
|
||||
VDim: 2
|
||||
Ordering: 0
|
||||
|
||||
0
|
||||
0.25
|
||||
0.5
|
||||
0.75
|
||||
1
|
||||
0
|
||||
0.25
|
||||
0.5
|
||||
0.75
|
||||
1
|
||||
0
|
||||
0.25
|
||||
0.5
|
||||
0.75
|
||||
1
|
||||
0
|
||||
0.25
|
||||
0.5
|
||||
0.75
|
||||
1
|
||||
0
|
||||
0.25
|
||||
0.5
|
||||
0.75
|
||||
1
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0.25
|
||||
0.25
|
||||
0.25
|
||||
0.25
|
||||
0.25
|
||||
0.5
|
||||
0.5
|
||||
0.5
|
||||
0.5
|
||||
0.5
|
||||
0.75
|
||||
0.75
|
||||
0.75
|
||||
0.75
|
||||
0.75
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
@@ -144,12 +144,12 @@ namespace mfem {
|
||||
* - <a class="el" href="maxwell_8cpp_source.html">Maxwell</a>: simple transient full-wave electromagnetics simulation code
|
||||
* - <a class="el" href="joule_8cpp_source.html">Joule</a>: transient magnetics and Joule heating miniapp
|
||||
* - <a class="el" href="classmfem_1_1navier_1_1NavierSolver.html">Navier</a>: solve the transient incompressible Navier-Stokes equations
|
||||
* - <a class="el" href="mobius-strip_8cpp_source.html">Mobius Strip</a>: generate various Mobius strip-like meshes
|
||||
|
||||
* - <a class="el" href="mobius-strip_8cpp_source.html">Mobius Strip</a>: generate various Mobius strip-like meshes
|
||||
* - <a class="el" href="klein-bottle_8cpp_source.html">Klein Bottle</a>: generate three types of Klein bottle surfaces
|
||||
* - <a class="el" href="toroid_8cpp_source.html">Toroid</a>: generate simple toroidal meshes
|
||||
* - <a class="el" href="twist_8cpp_source.html">Twist</a>: generate simple periodic meshes
|
||||
* - <a class="el" href="minimal-surface_8cpp_source.html">Minimal Surface</a>: compute minimal surfaces, <a class="el" href="minimal-surface_8cpp_source.html">serial</a> and <a class="el" href="pminimal-surface_8cpp_source.html">parallel</a> versions
|
||||
* - <a class="el" href="polar-nc_8cpp_source.html">Polar NC</a>: generate polar non-conforming meshes
|
||||
* - <a class="el" href="shaper_8cpp_source.html">Shaper</a>: resolve material interfaces by mesh refinement
|
||||
* - <a class="el" href="extruder_8cpp_source.html">Extruder</a>: extrude a low-dimensional mesh into a higher dimension
|
||||
* - <a class="el" href="mesh-explorer_8cpp_source.html">Mesh Explorer</a>: visualize and manipulate meshes
|
||||
@@ -162,7 +162,6 @@ namespace mfem {
|
||||
* - <a class="el" href="lor-transfer_8cpp_source.html">LOR Transfer</a>: map functions between high-order and low-order refined spaces
|
||||
* - <a class="el" href="findpts_8cpp_source.html">Find Points</a>: evaluate grid function in physical space, <a class="el" href="findpts_8cpp_source.html">serial</a> and <a class="el" href="pfindpts_8cpp_source.html">parallel</a> versions
|
||||
* - <a class="el" href="field-diff_8cpp_source.html">Field Diff</a>: compare grid functions on different meshes
|
||||
* - <a class="el" href="field-interp_8cpp_source.html">Field Interp</a>: transfer a grid functions betwen meshes
|
||||
* - <a class="el" href="miniapps_2performance_2ex1_8cpp_source.html">HPC Example 1</a>: high-performance nodal H1 FEM for the Laplace problem
|
||||
* - <a class="el" href="miniapps_2performance_2ex1p_8cpp_source.html">HPC Example 1p</a>: high-performance parallel nodal H1 FEM for the Laplace problem
|
||||
*
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ html: $(DOXYGEN_CONF)
|
||||
@# Generate the html documentation
|
||||
@doxygen $(DOXYGEN_CONF)
|
||||
@echo "<meta http-equiv=\"REFRESH\" content=\"0;URL=CodeDocumentation/html/index.html\">" > CodeDocumentation.html
|
||||
@cat warnings.log 1>&2
|
||||
@cat warnings.log
|
||||
@# Generate the log of undocumented methods
|
||||
@( cat $(DOXYGEN_CONF) ; echo "GENERATE_HTML=NO" ; echo "EXTRACT_ALL=NO" ; echo "WARN_LOGFILE=undoc.log" ; echo "QUIET=YES" ) | doxygen - &> /dev/null
|
||||
|
||||
|
||||
+2
-20
@@ -72,7 +72,6 @@ int main(int argc, char *argv[])
|
||||
int seed = 75;
|
||||
bool slu_solver = false;
|
||||
bool sp_solver = false;
|
||||
bool pardiso_solver = false;
|
||||
bool visualization = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
@@ -96,14 +95,6 @@ int main(int argc, char *argv[])
|
||||
#ifdef MFEM_USE_STRUMPACK
|
||||
args.AddOption(&sp_solver, "-sp", "--strumpack", "-no-sp",
|
||||
"--no-strumpack", "Use the STRUMPACK Solver.");
|
||||
#endif
|
||||
#ifdef MFEM_USE_MKL_CPARDISO
|
||||
args.AddOption(&pardiso_solver,
|
||||
"-pardiso",
|
||||
"--pardiso",
|
||||
"-no-pardiso",
|
||||
"--no-pardiso",
|
||||
"Use the MKL Cluster Pardiso Solver.");
|
||||
#endif
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
@@ -245,7 +236,7 @@ int main(int argc, char *argv[])
|
||||
// preconditioner for A to be used within the solver. Set the matrices
|
||||
// which define the generalized eigenproblem A x = lambda M x.
|
||||
Solver * precond = NULL;
|
||||
if (!slu_solver && !sp_solver && !pardiso_solver)
|
||||
if (!slu_solver && !sp_solver)
|
||||
{
|
||||
HypreBoomerAMG * amg = new HypreBoomerAMG(*A);
|
||||
amg->SetPrintLevel(0);
|
||||
@@ -277,19 +268,10 @@ int main(int argc, char *argv[])
|
||||
strumpack->SetFromCommandLine();
|
||||
precond = strumpack;
|
||||
}
|
||||
#endif
|
||||
#ifdef MFEM_USE_MKL_CPARDISO
|
||||
if (pardiso_solver)
|
||||
{
|
||||
auto pardiso = new CPardisoSolver(A->GetComm());
|
||||
pardiso->SetMatrixType(CPardisoSolver::MatType::REAL_STRUCTURE_SYMMETRIC);
|
||||
pardiso->SetPrintLevel(1);
|
||||
pardiso->SetOperator(*A);
|
||||
precond = pardiso;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
HypreLOBPCG * lobpcg = new HypreLOBPCG(MPI_COMM_WORLD);
|
||||
lobpcg->SetNumModes(nev);
|
||||
lobpcg->SetRandomSeed(seed);
|
||||
|
||||
@@ -1,234 +0,0 @@
|
||||
// MFEM Example 1 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex1p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex1p -m ../data/square-disc.mesh
|
||||
//
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/inline-quad.mesh";
|
||||
int order = 1;
|
||||
bool static_cond = false;
|
||||
bool visualization = true;
|
||||
int sr = 1;
|
||||
int pr = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
args.AddOption(&sr, "-sr", "--serial_ref",
|
||||
"Number of serial refinements");
|
||||
args.AddOption(&pr, "-pr", "--parallel_ref",
|
||||
"Number of parallel refinements");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
MPI_Finalize();
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
// 4. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
int dim = mesh.Dimension();
|
||||
|
||||
// 5. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement. We choose
|
||||
// 'ref_levels' to be the largest number that gives a final mesh with no
|
||||
// more than 10,000 elements.
|
||||
{
|
||||
for (int l = 0; l < sr; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 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(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
{
|
||||
for (int l = 0; l < pr; l++)
|
||||
{
|
||||
pmesh.UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use continuous Lagrange finite elements of the specified order. If
|
||||
// order < 1, we instead use an isoparametric/isogeometric space.
|
||||
FiniteElementCollection *fec = new H1_FECollection(order, dim);
|
||||
ParFiniteElementSpace fespace(&pmesh, fec);
|
||||
HYPRE_Int size = fespace.GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 8. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes from the mesh as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (pmesh.bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 9. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system, which in this case is
|
||||
// (1,phi_i) where phi_i are the basis functions in fespace.
|
||||
ParLinearForm b(&fespace);
|
||||
ConstantCoefficient one(1.0);
|
||||
b.AddDomainIntegrator(new DomainLFIntegrator(one));
|
||||
b.Assemble();
|
||||
|
||||
// 10. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x with initial guess of zero,
|
||||
// which satisfies the boundary conditions.
|
||||
ParGridFunction x(&fespace);
|
||||
x = 0.0;
|
||||
|
||||
// 11. Set up the parallel bilinear form a(.,.) on the finite element space
|
||||
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
|
||||
// domain integrator.
|
||||
ParBilinearForm a(&fespace);
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
|
||||
if (static_cond) { a.EnableStaticCondensation(); }
|
||||
a.Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
|
||||
|
||||
// // 13. Solve the linear system A X = B.
|
||||
// // * With full assembly, use the BoomerAMG preconditioner from hypre.
|
||||
// // * With partial assembly, use Jacobi smoothing, for now.
|
||||
StopWatch chrono;
|
||||
chrono.Clear();
|
||||
chrono.Start();
|
||||
HypreBoomerAMG *prec = new HypreBoomerAMG;
|
||||
prec->SetPrintLevel(0);
|
||||
CGSolver cg(MPI_COMM_WORLD);
|
||||
cg.SetRelTol(1e-13);
|
||||
cg.SetMaxIter(2000);
|
||||
cg.SetPrintLevel(0);
|
||||
if (prec) { cg.SetPreconditioner(*prec); }
|
||||
cg.SetOperator(A);
|
||||
cg.Mult(B, X);
|
||||
delete prec;
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "PCG-AMG time: " << chrono.RealTime() << endl;
|
||||
}
|
||||
|
||||
chrono.Clear();
|
||||
chrono.Start();
|
||||
{
|
||||
MUMPSSolver MA;
|
||||
MA.SetMatrixSymType(0);
|
||||
MA.SetOperator(A);
|
||||
Vector Y(X.Size());
|
||||
MA.Mult(B,Y);
|
||||
Y-=X;
|
||||
cout << "Mumps Diff norm = " << Y.Norml2() << endl;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "mumps time: " << chrono.RealTime() << endl;
|
||||
}
|
||||
|
||||
chrono.Clear();
|
||||
chrono.Start();
|
||||
|
||||
{
|
||||
CPardisoSolver pardiso(A.GetComm());
|
||||
// pardiso.SetMatrixType(CPardisoSolver::MatType::REAL_STRUCTURE_SYMMETRIC);
|
||||
pardiso.SetMatrixType(CPardisoSolver::MatType::REAL_UNSYMMETRIC);
|
||||
pardiso.SetPrintLevel(0);
|
||||
pardiso.SetOperator(A);
|
||||
Vector Y(X.Size());
|
||||
pardiso.Mult(B, Y);
|
||||
Y-=X;
|
||||
cout << "Pardiso Diff norm = " << Y.Norml2() << endl;
|
||||
}
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "pardiso time: " << chrono.RealTime() << endl;
|
||||
}
|
||||
|
||||
{
|
||||
SuperLURowLocMatrix SA(A);
|
||||
SuperLUSolver superlu(MPI_COMM_WORLD);
|
||||
superlu.SetPrintStatistics(false);
|
||||
superlu.SetSymmetricPattern(false);
|
||||
superlu.SetColumnPermutation(superlu::PARMETIS);
|
||||
superlu.SetOperator(SA);
|
||||
Vector Y(X.Size());
|
||||
superlu.Mult(B, Y);
|
||||
Y-=X;
|
||||
cout << "Superlu Diff norm = " << Y.Norml2() << endl;
|
||||
}
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "superlu time: " << chrono.RealTime() << endl;
|
||||
}
|
||||
|
||||
a.RecoverFEMSolution(X, b, x);
|
||||
|
||||
// 16. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << pmesh << x << flush;
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
delete fec;
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
+21
-30
@@ -6,19 +6,17 @@
|
||||
// ex22 -m ../data/inline-tri.mesh -o 3
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3 -p 1
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3 -p 1 -pa
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3 -p 2
|
||||
// ex22 -m ../data/inline-tet.mesh -o 2
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 1
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2 -pa
|
||||
// ex22 -m ../data/star.mesh -r 1 -o 2 -sigma 10.0
|
||||
//
|
||||
// Device sample runs:
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3 -p 1 -pa -d cuda
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2 -pa -d cuda
|
||||
// ex22 -m ../data/star.mesh -r 1 -o 2 -sigma 10.0 -pa -d cuda
|
||||
// With partial assembly:
|
||||
// ex22 -m ../data/inline-quad.mesh -o 3 -p 1 -pa
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2 -pa
|
||||
// ex22 -m ../data/star.mesh -r 1 -o 2 -sigma 10.0 -pa
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define and
|
||||
// solve simple complex-valued linear systems. It implements three
|
||||
@@ -84,7 +82,6 @@ int main(int argc, char *argv[])
|
||||
bool herm_conv = true;
|
||||
bool exact_sol = true;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
@@ -117,8 +114,6 @@ int main(int argc, char *argv[])
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
@@ -148,18 +143,13 @@ int main(int argc, char *argv[])
|
||||
ComplexOperator::Convention conv =
|
||||
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
|
||||
|
||||
// 2. Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
device.Print();
|
||||
|
||||
// 3. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// 2. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes
|
||||
// with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 4. Refine the mesh to increase resolution. In this example we do
|
||||
// 3. Refine the mesh to increase resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement where the user specifies
|
||||
// the number of levels with the '-r' option.
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
@@ -167,7 +157,7 @@ int main(int argc, char *argv[])
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use continuous
|
||||
// 4. Define a finite element space on the mesh. Here we use continuous
|
||||
// Lagrange, Nedelec, or Raviart-Thomas finite elements of the specified
|
||||
// order.
|
||||
if (dim == 1 && prob != 0 )
|
||||
@@ -189,7 +179,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Number of finite element unknowns: " << fespace->GetTrueVSize()
|
||||
<< endl;
|
||||
|
||||
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined based on the type
|
||||
// of mesh and the problem type.
|
||||
Array<int> ess_tdof_list;
|
||||
@@ -201,12 +191,12 @@ int main(int argc, char *argv[])
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 7. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// the FEM linear system.
|
||||
ComplexLinearForm b(fespace, conv);
|
||||
b.Vector::operator=(0.0);
|
||||
|
||||
// 8. Define the solution vector u as a complex finite element grid function
|
||||
// 7. Define the solution vector u as a complex finite element grid function
|
||||
// corresponding to fespace. Initialize u with initial guess of 1+0i or
|
||||
// the exact solution if it is known.
|
||||
ComplexGridFunction u(fespace);
|
||||
@@ -228,6 +218,7 @@ int main(int argc, char *argv[])
|
||||
VectorConstantCoefficient zeroVecCoef(zeroVec);
|
||||
VectorConstantCoefficient oneVecCoef(oneVec);
|
||||
|
||||
u = 0.0;
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
@@ -280,7 +271,7 @@ int main(int argc, char *argv[])
|
||||
<< "window_title 'Exact: Imaginary Part'" << flush;
|
||||
}
|
||||
|
||||
// 9. Set up the sesquilinear form a(.,.) on the finite element space
|
||||
// 8. Set up the sesquilinear form a(.,.) on the finite element space
|
||||
// corresponding to the damped harmonic oscillator operator of the
|
||||
// appropriate type:
|
||||
//
|
||||
@@ -323,7 +314,7 @@ int main(int argc, char *argv[])
|
||||
default: break; // This should be unreachable
|
||||
}
|
||||
|
||||
// 9a. Set up the bilinear form for the preconditioner corresponding to the
|
||||
// 8a. Set up the bilinear form for the preconditioner corresponding to the
|
||||
// appropriate operator
|
||||
//
|
||||
// 0) A scalar H1 field
|
||||
@@ -358,9 +349,9 @@ int main(int argc, char *argv[])
|
||||
default: break; // This should be unreachable
|
||||
}
|
||||
|
||||
// 10. Assemble the form and the corresponding linear system, applying any
|
||||
// necessary transformations such as: assembly, eliminating boundary
|
||||
// conditions, conforming constraints for non-conforming AMR, etc.
|
||||
// 9. Assemble the form and the corresponding linear system, applying any
|
||||
// necessary transformations such as: assembly, eliminating boundary
|
||||
// conditions, conforming constraints for non-conforming AMR, etc.
|
||||
a->Assemble();
|
||||
pcOp->Assemble();
|
||||
|
||||
@@ -371,7 +362,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
cout << "Size of linear system: " << A->Width() << endl << endl;
|
||||
|
||||
// 11. Define and apply a GMRES solver for AU=B with a block diagonal
|
||||
// 10. Define and apply a GMRES solver for AU=B with a block diagonal
|
||||
// preconditioner based on the appropriate sparse smoother.
|
||||
{
|
||||
Array<int> blockOffsets;
|
||||
@@ -428,7 +419,7 @@ int main(int argc, char *argv[])
|
||||
gmres.Mult(B, U);
|
||||
}
|
||||
|
||||
// 12. Recover the solution as a finite element grid function and compute the
|
||||
// 11. Recover the solution as a finite element grid function and compute the
|
||||
// errors if the exact solution is known.
|
||||
a->RecoverFEMSolution(U, b, u);
|
||||
|
||||
@@ -460,7 +451,7 @@ int main(int argc, char *argv[])
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
// 13. Save the refined mesh and the solution. This output can be viewed
|
||||
// 12. Save the refined mesh and the solution. This output can be viewed
|
||||
// later using GLVis: "glvis -m mesh -g sol".
|
||||
{
|
||||
ofstream mesh_ofs("refined.mesh");
|
||||
@@ -475,7 +466,7 @@ int main(int argc, char *argv[])
|
||||
u.imag().Save(sol_i_ofs);
|
||||
}
|
||||
|
||||
// 14. Send the solution by socket to a GLVis server.
|
||||
// 13. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
@@ -534,7 +525,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 15. Free the used memory.
|
||||
// 14. Free the used memory.
|
||||
delete a;
|
||||
delete u_exact;
|
||||
delete pcOp;
|
||||
|
||||
+23
-31
@@ -7,18 +7,16 @@
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 3
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 3 -p 1
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 3 -p 2
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 1 -p 1 -pa
|
||||
// mpirun -np 4 ex22p -m ../data/inline-tet.mesh -o 2
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2 -p 1
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2 -p 2
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 1 -p 2 -pa
|
||||
// mpirun -np 4 ex22p -m ../data/star.mesh -o 2 -sigma 10.0
|
||||
//
|
||||
// Device sample runs:
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 1 -p 1 -pa -d cuda
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 1 -p 2 -pa -d cuda
|
||||
// mpirun -np 4 ex22p -m ../data/star.mesh -o 2 -sigma 10.0 -pa -d cuda
|
||||
// With partial assembly:
|
||||
// mpirun -np 4 ex22p -m ../data/inline-quad.mesh -o 1 -p 1 -pa
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 1 -p 2 -pa
|
||||
// mpirun -np 4 ex22p -m ../data/star.mesh -o 2 -sigma 10.0 -pa
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define and
|
||||
// solve simple complex-valued linear systems. It implements three
|
||||
@@ -48,6 +46,7 @@
|
||||
// We recommend viewing examples 1, 3 and 4 before viewing this
|
||||
// example.
|
||||
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@@ -91,7 +90,6 @@ int main(int argc, char *argv[])
|
||||
bool herm_conv = true;
|
||||
bool exact_sol = true;
|
||||
bool pa = false;
|
||||
const char *device_config = "cpu";
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
@@ -126,8 +124,6 @@ int main(int argc, char *argv[])
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
"--no-partial-assembly", "Enable Partial Assembly.");
|
||||
args.AddOption(&device_config, "-d", "--device",
|
||||
"Device configuration string, see Device::Configure().");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
@@ -164,24 +160,19 @@ int main(int argc, char *argv[])
|
||||
ComplexOperator::Convention conv =
|
||||
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
|
||||
|
||||
// 3. Enable hardware devices such as GPUs, and programming models such as
|
||||
// CUDA, OCCA, RAJA and OpenMP based on command line options.
|
||||
Device device(device_config);
|
||||
if (myid == 0) { device.Print(); }
|
||||
|
||||
// 4. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// 3. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 5. Refine the serial mesh on all processors to increase the resolution.
|
||||
// 4. Refine the serial mesh on all processors to increase the resolution.
|
||||
for (int l = 0; l < ser_ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// 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);
|
||||
@@ -191,7 +182,7 @@ int main(int argc, char *argv[])
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use continuous Lagrange, Nedelec, or Raviart-Thomas finite elements of
|
||||
// the specified order.
|
||||
if (dim == 1 && prob != 0 )
|
||||
@@ -219,7 +210,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 8. Determine the list of true (i.e. parallel conforming) essential
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// based on the type of mesh and the problem type.
|
||||
Array<int> ess_tdof_list;
|
||||
@@ -231,14 +222,14 @@ int main(int argc, char *argv[])
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 9. Set up the parallel linear form b(.) which corresponds to the
|
||||
// 8. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system.
|
||||
ParComplexLinearForm b(fespace, conv);
|
||||
b.Vector::operator=(0.0);
|
||||
|
||||
// 10. Define the solution vector u as a parallel complex finite element grid
|
||||
// function corresponding to fespace. Initialize u with initial guess of
|
||||
// 1+0i or the exact solution if it is known.
|
||||
// 9. Define the solution vector u as a parallel complex finite element grid
|
||||
// function corresponding to fespace. Initialize u with initial guess of
|
||||
// 1+0i or the exact solution if it is known.
|
||||
ParComplexGridFunction u(fespace);
|
||||
ParComplexGridFunction * u_exact = NULL;
|
||||
if (exact_sol) { u_exact = new ParComplexGridFunction(fespace); }
|
||||
@@ -258,6 +249,7 @@ int main(int argc, char *argv[])
|
||||
VectorConstantCoefficient zeroVecCoef(zeroVec);
|
||||
VectorConstantCoefficient oneVecCoef(oneVec);
|
||||
|
||||
u = 0.0;
|
||||
switch (prob)
|
||||
{
|
||||
case 0:
|
||||
@@ -312,7 +304,7 @@ int main(int argc, char *argv[])
|
||||
<< "window_title 'Exact: Imaginary Part'" << flush;
|
||||
}
|
||||
|
||||
// 11. Set up the parallel sesquilinear form a(.,.) on the finite element
|
||||
// 10. Set up the parallel sesquilinear form a(.,.) on the finite element
|
||||
// space corresponding to the damped harmonic oscillator operator of the
|
||||
// appropriate type:
|
||||
//
|
||||
@@ -355,7 +347,7 @@ int main(int argc, char *argv[])
|
||||
default: break; // This should be unreachable
|
||||
}
|
||||
|
||||
// 11a. Set up the parallel bilinear form for the preconditioner
|
||||
// 10a. Set up the parallel bilinear form for the preconditioner
|
||||
// corresponding to the appropriate operator
|
||||
//
|
||||
// 0) A scalar H1 field
|
||||
@@ -389,7 +381,7 @@ int main(int argc, char *argv[])
|
||||
default: break; // This should be unreachable
|
||||
}
|
||||
|
||||
// 12. Assemble the parallel bilinear form and the corresponding linear
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, etc.
|
||||
@@ -407,7 +399,7 @@ int main(int argc, char *argv[])
|
||||
<< 2 * fespace->GlobalTrueVSize() << endl << endl;
|
||||
}
|
||||
|
||||
// 13. Define and apply a parallel FGMRES solver for AU=B with a block
|
||||
// 12. Define and apply a parallel FGMRES solver for AU=B with a block
|
||||
// diagonal preconditioner based on the appropriate multigrid
|
||||
// preconditioner from hypre.
|
||||
{
|
||||
@@ -468,7 +460,7 @@ int main(int argc, char *argv[])
|
||||
fgmres.SetPrintLevel(1);
|
||||
fgmres.Mult(B, U);
|
||||
}
|
||||
// 14. Recover the parallel grid function corresponding to U. This is the
|
||||
// 13. Recover the parallel grid function corresponding to U. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(U, b, u);
|
||||
|
||||
@@ -503,7 +495,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 15. Save the refined mesh and the solution in parallel. This output can be
|
||||
// 14. Save the refined mesh and the solution in parallel. This output can be
|
||||
// viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
{
|
||||
ostringstream mesh_name, sol_r_name, sol_i_name;
|
||||
@@ -523,7 +515,7 @@ int main(int argc, char *argv[])
|
||||
u.imag().Save(sol_i_ofs);
|
||||
}
|
||||
|
||||
// 16. Send the solution by socket to a GLVis server.
|
||||
// 15. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
@@ -588,7 +580,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
// 16. Free the used memory.
|
||||
delete a;
|
||||
delete u_exact;
|
||||
delete pcOp;
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&prob, "-p", "--problem-type",
|
||||
"Choose between 0: grad, 1: curl, 2: div");
|
||||
"Choose between 0: H(Curl) or 1: H(Div)");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&prob, "-p", "--problem-type",
|
||||
"Choose between 0: grad, 1: curl, 2: div");
|
||||
"Choose between 0: H(Curl) or 1: H(Div)");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
|
||||
+53
-47
@@ -82,24 +82,24 @@ public:
|
||||
};
|
||||
|
||||
// Class for returning the PML coefficients of the bilinear form
|
||||
class PMLDiagMatrixCoefficient : public VectorCoefficient
|
||||
class PMLMatrixCoefficient : public MatrixCoefficient
|
||||
{
|
||||
private:
|
||||
CartesianPML * pml = nullptr;
|
||||
void (*Function)(const Vector &, CartesianPML * , Vector &);
|
||||
void (*Function)(const Vector &, CartesianPML * , DenseMatrix &);
|
||||
public:
|
||||
PMLDiagMatrixCoefficient(int dim, void(*F)(const Vector &, CartesianPML *,
|
||||
Vector &),
|
||||
CartesianPML * pml_)
|
||||
: VectorCoefficient(dim), pml(pml_), Function(F)
|
||||
PMLMatrixCoefficient(int dim, void(*F)(const Vector &, CartesianPML *,
|
||||
DenseMatrix &),
|
||||
CartesianPML * pml_)
|
||||
: MatrixCoefficient(dim), pml(pml_), Function(F)
|
||||
{}
|
||||
virtual void Eval(Vector &K, ElementTransformation &T,
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
double x[3];
|
||||
Vector transip(x, 3);
|
||||
T.Transform(ip, transip);
|
||||
K.SetSize(vdim);
|
||||
K.SetSize(height, width);
|
||||
(*Function)(transip, pml, K);
|
||||
}
|
||||
};
|
||||
@@ -116,13 +116,13 @@ void source(const Vector &x, Vector & f);
|
||||
|
||||
// Functions for computing the necessary coefficients after PML stretching.
|
||||
// J is the Jacobian matrix of the stretching function
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector &D);
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
|
||||
Array2D<double> comp_domain_bdr;
|
||||
Array2D<double> domain_bdr;
|
||||
@@ -365,19 +365,19 @@ int main(int argc, char *argv[])
|
||||
a.AddDomainIntegrator(new VectorFEMassIntegrator(restr_omeg),NULL);
|
||||
|
||||
int cdim = (dim == 2) ? 1 : dim;
|
||||
PMLDiagMatrixCoefficient pml_c1_Re(cdim,detJ_inv_JT_J_Re, pml);
|
||||
PMLDiagMatrixCoefficient pml_c1_Im(cdim,detJ_inv_JT_J_Im, pml);
|
||||
ScalarVectorProductCoefficient c1_Re(muinv,pml_c1_Re);
|
||||
ScalarVectorProductCoefficient c1_Im(muinv,pml_c1_Im);
|
||||
VectorRestrictedCoefficient restr_c1_Re(c1_Re,attrPML);
|
||||
VectorRestrictedCoefficient restr_c1_Im(c1_Im,attrPML);
|
||||
PMLMatrixCoefficient pml_c1_Re(cdim,detJ_inv_JT_J_Re, pml);
|
||||
PMLMatrixCoefficient pml_c1_Im(cdim,detJ_inv_JT_J_Im, pml);
|
||||
ScalarMatrixProductCoefficient c1_Re(muinv,pml_c1_Re);
|
||||
ScalarMatrixProductCoefficient c1_Im(muinv,pml_c1_Im);
|
||||
MatrixRestrictedCoefficient restr_c1_Re(c1_Re,attrPML);
|
||||
MatrixRestrictedCoefficient restr_c1_Im(c1_Im,attrPML);
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c2_Re(dim, detJ_JT_J_inv_Re,pml);
|
||||
PMLDiagMatrixCoefficient pml_c2_Im(dim, detJ_JT_J_inv_Im,pml);
|
||||
ScalarVectorProductCoefficient c2_Re(omeg,pml_c2_Re);
|
||||
ScalarVectorProductCoefficient c2_Im(omeg,pml_c2_Im);
|
||||
VectorRestrictedCoefficient restr_c2_Re(c2_Re,attrPML);
|
||||
VectorRestrictedCoefficient restr_c2_Im(c2_Im,attrPML);
|
||||
PMLMatrixCoefficient pml_c2_Re(dim, detJ_JT_J_inv_Re,pml);
|
||||
PMLMatrixCoefficient pml_c2_Im(dim, detJ_JT_J_inv_Im,pml);
|
||||
ScalarMatrixProductCoefficient c2_Re(omeg,pml_c2_Re);
|
||||
ScalarMatrixProductCoefficient c2_Im(omeg,pml_c2_Im);
|
||||
MatrixRestrictedCoefficient restr_c2_Re(c2_Re,attrPML);
|
||||
MatrixRestrictedCoefficient restr_c2_Im(c2_Im,attrPML);
|
||||
|
||||
// Integrators inside the PML region
|
||||
a.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_Re),
|
||||
@@ -419,13 +419,13 @@ int main(int argc, char *argv[])
|
||||
prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_muinv));
|
||||
prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_absomeg));
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c1_abs(cdim,detJ_inv_JT_J_abs, pml);
|
||||
ScalarVectorProductCoefficient c1_abs(muinv,pml_c1_abs);
|
||||
VectorRestrictedCoefficient restr_c1_abs(c1_abs,attrPML);
|
||||
PMLMatrixCoefficient pml_c1_abs(cdim,detJ_inv_JT_J_abs, pml);
|
||||
ScalarMatrixProductCoefficient c1_abs(muinv,pml_c1_abs);
|
||||
MatrixRestrictedCoefficient restr_c1_abs(c1_abs,attrPML);
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c2_abs(dim, detJ_JT_J_inv_abs,pml);
|
||||
ScalarVectorProductCoefficient c2_abs(absomeg,pml_c2_abs);
|
||||
VectorRestrictedCoefficient restr_c2_abs(c2_abs,attrPML);
|
||||
PMLMatrixCoefficient pml_c2_abs(dim, detJ_JT_J_inv_abs,pml);
|
||||
ScalarMatrixProductCoefficient c2_abs(absomeg,pml_c2_abs);
|
||||
MatrixRestrictedCoefficient restr_c2_abs(c2_abs,attrPML);
|
||||
|
||||
prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_abs));
|
||||
prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_abs));
|
||||
@@ -763,7 +763,7 @@ void E_bdr_data_Im(const Vector &x, Vector &E)
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det(1.0, 0.0);
|
||||
@@ -774,13 +774,14 @@ void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (det / pow(dxs[i], 2)).real();
|
||||
M(i, i) = (det / pow(dxs[i], 2)).real();
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -791,13 +792,14 @@ void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (det / pow(dxs[i], 2)).imag();
|
||||
M(i, i) = (det / pow(dxs[i], 2)).imag();
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -808,13 +810,14 @@ void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = abs(det / pow(dxs[i], 2));
|
||||
M(i, i) = abs(det / pow(dxs[i], 2));
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det(1.0, 0.0);
|
||||
@@ -828,18 +831,19 @@ void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
// in the 2D case the coefficient is scalar 1/det(J)
|
||||
if (dim == 2)
|
||||
{
|
||||
D = (1.0 / det).real();
|
||||
M = (1.0 / det).real();
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (pow(dxs[i], 2) / det).real();
|
||||
M(i, i) = (pow(dxs[i], 2) / det).real();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -852,18 +856,19 @@ void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
D = (1.0 / det).imag();
|
||||
M = (1.0 / det).imag();
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (pow(dxs[i], 2) / det).imag();
|
||||
M(i, i) = (pow(dxs[i], 2) / det).imag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -876,13 +881,14 @@ void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector &D)
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
D = abs(1.0 / det);
|
||||
M = abs(1.0 / det);
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = abs(pow(dxs[i], 2) / det);
|
||||
M(i, i) = abs(pow(dxs[i], 2) / det);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+53
-47
@@ -82,24 +82,24 @@ public:
|
||||
};
|
||||
|
||||
// Class for returning the PML coefficients of the bilinear form
|
||||
class PMLDiagMatrixCoefficient : public VectorCoefficient
|
||||
class PMLMatrixCoefficient : public MatrixCoefficient
|
||||
{
|
||||
private:
|
||||
CartesianPML * pml = nullptr;
|
||||
void (*Function)(const Vector &, CartesianPML * , Vector &);
|
||||
void (*Function)(const Vector &, CartesianPML * , DenseMatrix &);
|
||||
public:
|
||||
PMLDiagMatrixCoefficient(int dim, void(*F)(const Vector &, CartesianPML *,
|
||||
Vector &),
|
||||
CartesianPML * pml_)
|
||||
: VectorCoefficient(dim), pml(pml_), Function(F)
|
||||
PMLMatrixCoefficient(int dim, void(*F)(const Vector &, CartesianPML *,
|
||||
DenseMatrix &),
|
||||
CartesianPML * pml_)
|
||||
: MatrixCoefficient(dim), pml(pml_), Function(F)
|
||||
{}
|
||||
virtual void Eval(Vector &K, ElementTransformation &T,
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
double x[3];
|
||||
Vector transip(x, 3);
|
||||
T.Transform(ip, transip);
|
||||
K.SetSize(vdim);
|
||||
K.SetSize(height, width);
|
||||
(*Function)(transip, pml, K);
|
||||
}
|
||||
};
|
||||
@@ -116,13 +116,13 @@ void source(const Vector &x, Vector & f);
|
||||
|
||||
// Functions for computing the necessary coefficients after PML stretching.
|
||||
// J is the Jacobian matrix of the stretching function
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector & D);
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M);
|
||||
|
||||
Array2D<double> comp_domain_bdr;
|
||||
Array2D<double> domain_bdr;
|
||||
@@ -393,19 +393,19 @@ int main(int argc, char *argv[])
|
||||
a.AddDomainIntegrator(new VectorFEMassIntegrator(restr_omeg),NULL);
|
||||
|
||||
int cdim = (dim == 2) ? 1 : dim;
|
||||
PMLDiagMatrixCoefficient pml_c1_Re(cdim,detJ_inv_JT_J_Re, pml);
|
||||
PMLDiagMatrixCoefficient pml_c1_Im(cdim,detJ_inv_JT_J_Im, pml);
|
||||
ScalarVectorProductCoefficient c1_Re(muinv,pml_c1_Re);
|
||||
ScalarVectorProductCoefficient c1_Im(muinv,pml_c1_Im);
|
||||
VectorRestrictedCoefficient restr_c1_Re(c1_Re,attrPML);
|
||||
VectorRestrictedCoefficient restr_c1_Im(c1_Im,attrPML);
|
||||
PMLMatrixCoefficient pml_c1_Re(cdim,detJ_inv_JT_J_Re, pml);
|
||||
PMLMatrixCoefficient pml_c1_Im(cdim,detJ_inv_JT_J_Im, pml);
|
||||
ScalarMatrixProductCoefficient c1_Re(muinv,pml_c1_Re);
|
||||
ScalarMatrixProductCoefficient c1_Im(muinv,pml_c1_Im);
|
||||
MatrixRestrictedCoefficient restr_c1_Re(c1_Re,attrPML);
|
||||
MatrixRestrictedCoefficient restr_c1_Im(c1_Im,attrPML);
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c2_Re(dim, detJ_JT_J_inv_Re,pml);
|
||||
PMLDiagMatrixCoefficient pml_c2_Im(dim, detJ_JT_J_inv_Im,pml);
|
||||
ScalarVectorProductCoefficient c2_Re(omeg,pml_c2_Re);
|
||||
ScalarVectorProductCoefficient c2_Im(omeg,pml_c2_Im);
|
||||
VectorRestrictedCoefficient restr_c2_Re(c2_Re,attrPML);
|
||||
VectorRestrictedCoefficient restr_c2_Im(c2_Im,attrPML);
|
||||
PMLMatrixCoefficient pml_c2_Re(dim, detJ_JT_J_inv_Re,pml);
|
||||
PMLMatrixCoefficient pml_c2_Im(dim, detJ_JT_J_inv_Im,pml);
|
||||
ScalarMatrixProductCoefficient c2_Re(omeg,pml_c2_Re);
|
||||
ScalarMatrixProductCoefficient c2_Im(omeg,pml_c2_Im);
|
||||
MatrixRestrictedCoefficient restr_c2_Re(c2_Re,attrPML);
|
||||
MatrixRestrictedCoefficient restr_c2_Im(c2_Im,attrPML);
|
||||
|
||||
// Integrators inside the PML region
|
||||
a.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_Re),
|
||||
@@ -453,13 +453,13 @@ int main(int argc, char *argv[])
|
||||
prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_muinv));
|
||||
prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_absomeg));
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c1_abs(cdim,detJ_inv_JT_J_abs, pml);
|
||||
ScalarVectorProductCoefficient c1_abs(muinv,pml_c1_abs);
|
||||
VectorRestrictedCoefficient restr_c1_abs(c1_abs,attrPML);
|
||||
PMLMatrixCoefficient pml_c1_abs(cdim,detJ_inv_JT_J_abs, pml);
|
||||
ScalarMatrixProductCoefficient c1_abs(muinv,pml_c1_abs);
|
||||
MatrixRestrictedCoefficient restr_c1_abs(c1_abs,attrPML);
|
||||
|
||||
PMLDiagMatrixCoefficient pml_c2_abs(dim, detJ_JT_J_inv_abs,pml);
|
||||
ScalarVectorProductCoefficient c2_abs(absomeg,pml_c2_abs);
|
||||
VectorRestrictedCoefficient restr_c2_abs(c2_abs,attrPML);
|
||||
PMLMatrixCoefficient pml_c2_abs(dim, detJ_JT_J_inv_abs,pml);
|
||||
ScalarMatrixProductCoefficient c2_abs(absomeg,pml_c2_abs);
|
||||
MatrixRestrictedCoefficient restr_c2_abs(c2_abs,attrPML);
|
||||
|
||||
prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_abs));
|
||||
prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_abs));
|
||||
@@ -819,7 +819,7 @@ void E_bdr_data_Im(const Vector &x, Vector &E)
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det(1.0, 0.0);
|
||||
@@ -830,13 +830,14 @@ void detJ_JT_J_inv_Re(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (det / pow(dxs[i], 2)).real();
|
||||
M(i, i) = (det / pow(dxs[i], 2)).real();
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -847,13 +848,14 @@ void detJ_JT_J_inv_Im(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (det / pow(dxs[i], 2)).imag();
|
||||
M(i, i) = (det / pow(dxs[i], 2)).imag();
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -864,13 +866,14 @@ void detJ_JT_J_inv_abs(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
det *= dxs[i];
|
||||
}
|
||||
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = abs(det / pow(dxs[i], 2));
|
||||
M(i, i) = abs(det / pow(dxs[i], 2));
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det(1.0, 0.0);
|
||||
@@ -884,18 +887,19 @@ void detJ_inv_JT_J_Re(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
// in the 2D case the coefficient is scalar 1/det(J)
|
||||
if (dim == 2)
|
||||
{
|
||||
D = (1.0 / det).real();
|
||||
M = (1.0 / det).real();
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (pow(dxs[i], 2) / det).real();
|
||||
M(i, i) = (pow(dxs[i], 2) / det).real();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -908,18 +912,19 @@ void detJ_inv_JT_J_Im(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
D = (1.0 / det).imag();
|
||||
M = (1.0 / det).imag();
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = (pow(dxs[i], 2) / det).imag();
|
||||
M(i, i) = (pow(dxs[i], 2) / det).imag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, DenseMatrix &M)
|
||||
{
|
||||
vector<complex<double>> dxs(dim);
|
||||
complex<double> det = 1.0;
|
||||
@@ -932,13 +937,14 @@ void detJ_inv_JT_J_abs(const Vector &x, CartesianPML * pml, Vector & D)
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
D = abs(1.0 / det);
|
||||
M = abs(1.0 / det);
|
||||
}
|
||||
else
|
||||
{
|
||||
M = 0.0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
D(i) = abs(pow(dxs[i], 2) / det);
|
||||
M(i, i) = abs(pow(dxs[i], 2) / det);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-12
@@ -60,7 +60,6 @@ int main(int argc, char *argv[])
|
||||
bool static_cond = false;
|
||||
bool visualization = 1;
|
||||
bool amg_elast = 0;
|
||||
bool reorder_space = false;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
@@ -76,8 +75,6 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&reorder_space, "-nodes", "--by-nodes", "-vdim", "--by-vdim",
|
||||
"Use byNODES ordering of vector space instead of byVDIM");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
@@ -159,14 +156,7 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
{
|
||||
fec = new H1_FECollection(order, dim);
|
||||
if (reorder_space)
|
||||
{
|
||||
fespace = new ParFiniteElementSpace(pmesh, fec, dim, Ordering::byNODES);
|
||||
}
|
||||
else
|
||||
{
|
||||
fespace = new ParFiniteElementSpace(pmesh, fec, dim, Ordering::byVDIM);
|
||||
}
|
||||
fespace = new ParFiniteElementSpace(pmesh, fec, dim, Ordering::byVDIM);
|
||||
}
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
@@ -259,7 +249,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
amg->SetSystemsOptions(dim, reorder_space);
|
||||
amg->SetSystemsOptions(dim);
|
||||
}
|
||||
HyprePCG *pcg = new HyprePCG(A);
|
||||
pcg->SetTol(1e-8);
|
||||
|
||||
+3
-8
@@ -108,11 +108,7 @@ int main(int argc, char *argv[])
|
||||
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
|
||||
// problem yet, this will be done in the main loop.
|
||||
BilinearForm a(&fespace);
|
||||
if (pa)
|
||||
{
|
||||
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
a.SetDiagonalPolicy(Operator::DIAG_ONE);
|
||||
}
|
||||
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
LinearForm b(&fespace);
|
||||
|
||||
ConstantCoefficient one(1.0);
|
||||
@@ -203,10 +199,9 @@ int main(int argc, char *argv[])
|
||||
umf_solver.Mult(B, X);
|
||||
#endif
|
||||
}
|
||||
else // Diagonal preconditioning in partial assembly mode.
|
||||
else // No preconditioning for now in partial assembly mode.
|
||||
{
|
||||
OperatorJacobiSmoother M(a, ess_tdof_list);
|
||||
PCG(*A, M, B, X, 3, 2000, 1e-12, 0.0);
|
||||
CG(*A, B, X, 3, 2000, 1e-12, 0.0);
|
||||
}
|
||||
|
||||
// 18. After solving the linear system, reconstruct the solution as a
|
||||
|
||||
+6
-19
@@ -129,11 +129,7 @@ int main(int argc, char *argv[])
|
||||
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
|
||||
// problem yet, this will be done in the main loop.
|
||||
ParBilinearForm a(&fespace);
|
||||
if (pa)
|
||||
{
|
||||
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
a.SetDiagonalPolicy(Operator::DIAG_ONE);
|
||||
}
|
||||
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
ParLinearForm b(&fespace);
|
||||
|
||||
ConstantCoefficient one(1.0);
|
||||
@@ -224,26 +220,17 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 17. Solve the linear system A X = B.
|
||||
// * With full assembly, use the BoomerAMG preconditioner from hypre.
|
||||
// * With partial assembly, use a diagonal preconditioner.
|
||||
Solver *M = NULL;
|
||||
if (pa)
|
||||
{
|
||||
M = new OperatorJacobiSmoother(a, ess_tdof_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
HypreBoomerAMG *amg = new HypreBoomerAMG;
|
||||
amg->SetPrintLevel(0);
|
||||
M = amg;
|
||||
}
|
||||
// * With partial assembly, use no preconditioner, for now.
|
||||
HypreBoomerAMG *amg = NULL;
|
||||
if (!pa) { amg = new HypreBoomerAMG; amg->SetPrintLevel(0); }
|
||||
CGSolver cg(MPI_COMM_WORLD);
|
||||
cg.SetRelTol(1e-6);
|
||||
cg.SetMaxIter(2000);
|
||||
cg.SetPrintLevel(3); // print the first and the last iterations only
|
||||
cg.SetPreconditioner(*M);
|
||||
if (amg) { cg.SetPreconditioner(*amg); }
|
||||
cg.SetOperator(*A);
|
||||
cg.Mult(B, X);
|
||||
delete M;
|
||||
delete amg;
|
||||
|
||||
// 18. Switch back to the host and extract the parallel grid function
|
||||
// corresponding to the finite element approximation X. This is the
|
||||
|
||||
@@ -119,11 +119,6 @@ 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-superlu: ex11p
|
||||
@$(call mfem-test,$<, $(RUN_MPI), MKL_CPARDISO example,--pardiso)
|
||||
test-par-YES: ex11p-test-pardiso
|
||||
endif
|
||||
|
||||
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
|
||||
|
||||
|
||||
+37
-2
@@ -31,7 +31,6 @@ set(SRCS
|
||||
bilininteg_vecmass.cpp
|
||||
coefficient.cpp
|
||||
complex_fem.cpp
|
||||
convergence.cpp
|
||||
datacollection.cpp
|
||||
eltrans.cpp
|
||||
estimators.cpp
|
||||
@@ -51,10 +50,43 @@ set(SRCS
|
||||
fespacehierarchy.cpp
|
||||
nonlininteg_vectorconvection.cpp
|
||||
quadinterpolator.cpp
|
||||
quadinterpolator_det.cpp
|
||||
quadinterpolator_eval_by_nodes.cpp
|
||||
quadinterpolator_eval_by_vdim.cpp
|
||||
quadinterpolator_grad_by_nodes.cpp
|
||||
quadinterpolator_grad_by_vdim.cpp
|
||||
quadinterpolator_grad_phys_by_nodes.cpp
|
||||
quadinterpolator_grad_phys_by_vdim.cpp
|
||||
quadinterpolator_face.cpp
|
||||
restriction.cpp
|
||||
staticcond.cpp
|
||||
tmop.cpp
|
||||
tmop_pa.cpp
|
||||
tmop_pa_h2d.cpp
|
||||
tmop_pa_h2d_c0.cpp
|
||||
tmop_pa_h2m.cpp
|
||||
tmop_pa_h2m_c0.cpp
|
||||
tmop_pa_h2s.cpp
|
||||
tmop_pa_h2s_c0.cpp
|
||||
tmop_pa_h3d.cpp
|
||||
tmop_pa_h3d_c0.cpp
|
||||
tmop_pa_h3m.cpp
|
||||
tmop_pa_h3m_c0.cpp
|
||||
tmop_pa_h3s.cpp
|
||||
tmop_pa_h3s_c0.cpp
|
||||
tmop_pa_jp2.cpp
|
||||
tmop_pa_jp3.cpp
|
||||
tmop_pa_jt2_tc.cpp
|
||||
tmop_pa_jt3_datc.cpp
|
||||
tmop_pa_jt3_tc.cpp
|
||||
tmop_pa_p2.cpp
|
||||
tmop_pa_p2_c0.cpp
|
||||
tmop_pa_p3.cpp
|
||||
tmop_pa_p3_c0.cpp
|
||||
tmop_pa_w2.cpp
|
||||
tmop_pa_w2_c0.cpp
|
||||
tmop_pa_w3.cpp
|
||||
tmop_pa_w3_c0.cpp
|
||||
tmop_tools.cpp
|
||||
gslib.cpp
|
||||
transfer.cpp
|
||||
@@ -66,7 +98,6 @@ set(HDRS
|
||||
bilininteg.hpp
|
||||
coefficient.hpp
|
||||
complex_fem.hpp
|
||||
convergence.hpp
|
||||
datacollection.hpp
|
||||
eltrans.hpp
|
||||
estimators.hpp
|
||||
@@ -85,7 +116,10 @@ set(HDRS
|
||||
nonlinearform_ext.hpp
|
||||
nonlininteg.hpp
|
||||
quadinterpolator.hpp
|
||||
quadinterpolator_eval.hpp
|
||||
quadinterpolator_face.hpp
|
||||
quadinterpolator_grad.hpp
|
||||
quadinterpolator_grad_phys.hpp
|
||||
restriction.hpp
|
||||
fespacehierarchy.hpp
|
||||
staticcond.hpp
|
||||
@@ -98,6 +132,7 @@ set(HDRS
|
||||
tfespace.hpp
|
||||
tintrules.hpp
|
||||
tmop.hpp
|
||||
tmop_pa.hpp
|
||||
tmop_tools.hpp
|
||||
gslib.hpp
|
||||
transfer.hpp
|
||||
|
||||
@@ -627,33 +627,6 @@ void BilinearForm::AssembleDiagonal(Vector &diag) const
|
||||
MFEM_ASSERT(diag.Size() == fes->GetTrueVSize(),
|
||||
"Vector for holding diagonal has wrong size!");
|
||||
const Operator *P = fes->GetProlongationMatrix();
|
||||
// For an AMR mesh, a convergent diagonal is assembled with |P^T| d_e,
|
||||
// where |P^T| has the entry-wise absolute values of the conforming
|
||||
// prolongation transpose operator.
|
||||
if (P && !fes->Conforming())
|
||||
{
|
||||
Vector local_diag(P->Height());
|
||||
ext->AssembleDiagonal(local_diag);
|
||||
const SparseMatrix *SP = dynamic_cast<const SparseMatrix*>(P);
|
||||
#ifdef MFEM_USE_MPI
|
||||
const HypreParMatrix *HP = dynamic_cast<const HypreParMatrix*>(P);
|
||||
#endif
|
||||
if (SP)
|
||||
{
|
||||
SP->AbsMultTranspose(local_diag, diag);
|
||||
}
|
||||
#ifdef MFEM_USE_MPI
|
||||
else if (HP)
|
||||
{
|
||||
HP->AbsMultTranspose(1.0, local_diag, 0.0, diag);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Prolongation matrix has unexpected type.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!IsIdentityProlongation(P))
|
||||
{
|
||||
Vector local_diag(P->Height());
|
||||
|
||||
@@ -96,9 +96,6 @@ void PABilinearFormExtension::Assemble()
|
||||
integrators[i]->AssemblePA(*a->FESpace());
|
||||
}
|
||||
|
||||
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
|
||||
"Partial assembly does not support AddBoundaryIntegrator yet.");
|
||||
|
||||
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
|
||||
const int intFaceIntegratorCount = intFaceIntegrators.Size();
|
||||
for (int i = 0; i < intFaceIntegratorCount; ++i)
|
||||
@@ -310,21 +307,19 @@ void EABilinearFormExtension::Assemble()
|
||||
|
||||
ea_data.SetSize(ne*elemDofs*elemDofs, Device::GetMemoryType());
|
||||
ea_data.UseDevice(true);
|
||||
ea_data = 0.0;
|
||||
|
||||
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
|
||||
const int integratorCount = integrators.Size();
|
||||
for (int i = 0; i < integratorCount; ++i)
|
||||
{
|
||||
integrators[i]->AssembleEA(*a->FESpace(), ea_data, i);
|
||||
integrators[i]->AssembleEA(*a->FESpace(), ea_data);
|
||||
}
|
||||
|
||||
faceDofs = trialFes ->
|
||||
GetTraceElement(0, trialFes->GetMesh()->GetFaceBaseGeometry(0)) ->
|
||||
GetDof();
|
||||
|
||||
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
|
||||
"Element assembly does not support AddBoundaryIntegrator yet.");
|
||||
|
||||
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
|
||||
const int intFaceIntegratorCount = intFaceIntegrators.Size();
|
||||
if (intFaceIntegratorCount>0)
|
||||
@@ -332,13 +327,14 @@ void EABilinearFormExtension::Assemble()
|
||||
nf_int = trialFes->GetNFbyType(FaceType::Interior);
|
||||
ea_data_int.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
|
||||
ea_data_ext.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
|
||||
ea_data_int = 0.0;
|
||||
ea_data_ext = 0.0;
|
||||
}
|
||||
for (int i = 0; i < intFaceIntegratorCount; ++i)
|
||||
{
|
||||
intFaceIntegrators[i]->AssembleEAInteriorFaces(*a->FESpace(),
|
||||
ea_data_int,
|
||||
ea_data_ext,
|
||||
i);
|
||||
ea_data_ext);
|
||||
}
|
||||
|
||||
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
|
||||
@@ -351,7 +347,7 @@ void EABilinearFormExtension::Assemble()
|
||||
}
|
||||
for (int i = 0; i < boundFaceIntegratorCount; ++i)
|
||||
{
|
||||
bdrFaceIntegrators[i]->AssembleEABoundaryFaces(*a->FESpace(),ea_data_bdr,i);
|
||||
bdrFaceIntegrators[i]->AssembleEABoundaryFaces(*a->FESpace(),ea_data_bdr);
|
||||
}
|
||||
|
||||
if (factorize_face_terms && int_face_restrict_lex)
|
||||
@@ -798,12 +794,6 @@ void PAMixedBilinearFormExtension::Assemble()
|
||||
{
|
||||
integrators[i]->AssemblePA(*trialFes, *testFes);
|
||||
}
|
||||
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
|
||||
"Partial assembly does not support AddBoundaryIntegrator yet.");
|
||||
MFEM_VERIFY(a->GetTFBFI()->Size() == 0,
|
||||
"Partial assembly does not support AddTraceFaceIntegrator yet.");
|
||||
MFEM_VERIFY(a->GetBTFBFI()->Size() == 0,
|
||||
"Partial assembly does not support AddBdrTraceFaceIntegrator yet.");
|
||||
}
|
||||
|
||||
void PAMixedBilinearFormExtension::Update()
|
||||
|
||||
+3
-14
@@ -52,8 +52,7 @@ void BilinearFormIntegrator::AssembleDiagonalPA(Vector &)
|
||||
}
|
||||
|
||||
void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
Vector &emat,
|
||||
const bool add)
|
||||
Vector &emat)
|
||||
{
|
||||
mfem_error ("BilinearFormIntegrator::AssembleEA(...)\n"
|
||||
" is not implemented for this class.");
|
||||
@@ -62,8 +61,7 @@ void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
|
||||
&fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add)
|
||||
Vector &ea_data_ext)
|
||||
{
|
||||
mfem_error ("BilinearFormIntegrator::AssembleEAInteriorFaces(...)\n"
|
||||
" is not implemented for this class.");
|
||||
@@ -71,8 +69,7 @@ void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
|
||||
|
||||
void BilinearFormIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace
|
||||
&fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add)
|
||||
Vector &ea_data_bdr)
|
||||
{
|
||||
mfem_error ("BilinearFormIntegrator::AssembleEABoundaryFaces(...)\n"
|
||||
" is not implemented for this class.");
|
||||
@@ -1525,7 +1522,6 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
double w;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector D;
|
||||
DenseMatrix curlshape(nd,dimc), curlshape_dFt(nd,dimc), M;
|
||||
#else
|
||||
curlshape.SetSize(nd,dimc);
|
||||
@@ -1533,7 +1529,6 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
#endif
|
||||
elmat.SetSize(nd);
|
||||
if (MQ) { M.SetSize(dimc); }
|
||||
if (DQ) { D.SetSize(dimc); }
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
@@ -1577,12 +1572,6 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
Mult(curlshape_dFt, M, curlshape);
|
||||
AddMultABt(curlshape, curlshape_dFt, elmat);
|
||||
}
|
||||
else if (DQ)
|
||||
{
|
||||
DQ->Eval(D, Trans, ip);
|
||||
D *= w;
|
||||
AddMultADAt(curlshape_dFt, D, elmat);
|
||||
}
|
||||
else if (Q)
|
||||
{
|
||||
w *= Q->Eval(Trans, ip);
|
||||
|
||||
+17
-47
@@ -20,13 +20,6 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// Local maximum size of dofs and quads in 1D
|
||||
constexpr int HCURL_MAX_D1D = 5;
|
||||
constexpr int HCURL_MAX_Q1D = 6;
|
||||
|
||||
constexpr int HDIV_MAX_D1D = 5;
|
||||
constexpr int HDIV_MAX_Q1D = 6;
|
||||
|
||||
/// Abstract base class BilinearFormIntegrator
|
||||
class BilinearFormIntegrator : public NonlinearFormIntegrator
|
||||
{
|
||||
@@ -86,10 +79,9 @@ public:
|
||||
virtual void AddMultTransposePA(const Vector &x, Vector &y) const;
|
||||
|
||||
/// Method defining element assembly.
|
||||
/** The result of the element assembly is added to the @a emat Vector if
|
||||
@a add is true. Otherwise, if @a add is false, we set @a emat. */
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
|
||||
const bool add = true);
|
||||
/** The result of the element assembly is added and stored in the @a emat
|
||||
Vector. */
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
||||
/** Used with BilinearFormIntegrators that have different spaces. */
|
||||
// virtual void AssembleEA(const FiniteElementSpace &trial_fes,
|
||||
// const FiniteElementSpace &test_fes,
|
||||
@@ -97,12 +89,10 @@ public:
|
||||
|
||||
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add = true);
|
||||
Vector &ea_data_ext);
|
||||
|
||||
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add = true);
|
||||
Vector &ea_data_bdr);
|
||||
|
||||
/// Given a particular Finite Element computes the element matrix elmat.
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
@@ -265,17 +255,14 @@ public:
|
||||
bfi->AddMultTransposePA(x, y);
|
||||
}
|
||||
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
|
||||
const bool add);
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
||||
|
||||
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add);
|
||||
Vector &ea_data_ext);
|
||||
|
||||
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add);
|
||||
Vector &ea_data_bdr);
|
||||
|
||||
virtual ~TransposeIntegrator() { if (own_bfi) { delete bfi; } }
|
||||
};
|
||||
@@ -1958,8 +1945,7 @@ public:
|
||||
|
||||
virtual void AssemblePA(const FiniteElementSpace &fes);
|
||||
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
|
||||
const bool add);
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
||||
|
||||
virtual void AssembleDiagonalPA(Vector &diag);
|
||||
|
||||
@@ -2034,8 +2020,7 @@ public:
|
||||
|
||||
virtual void AssemblePA(const FiniteElementSpace &fes);
|
||||
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
|
||||
const bool add);
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
||||
|
||||
virtual void AssembleDiagonalPA(Vector &diag);
|
||||
|
||||
@@ -2091,8 +2076,7 @@ public:
|
||||
|
||||
virtual void AssemblePA(const FiniteElementSpace&);
|
||||
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
|
||||
const bool add);
|
||||
virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat);
|
||||
|
||||
virtual void AddMultPA(const Vector&, Vector&) const;
|
||||
|
||||
@@ -2309,14 +2293,12 @@ class CurlCurlIntegrator: public BilinearFormIntegrator
|
||||
private:
|
||||
Vector vec, pointflux;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
Vector D;
|
||||
DenseMatrix curlshape, curlshape_dFt, M;
|
||||
DenseMatrix vshape, projcurl;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
VectorCoefficient *DQ;
|
||||
MatrixCoefficient *MQ;
|
||||
|
||||
// PA extension
|
||||
@@ -2325,17 +2307,12 @@ protected:
|
||||
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
|
||||
const GeometricFactors *geom; ///< Not owned
|
||||
int dim, ne, nq, dofs1D, quad1D;
|
||||
bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient
|
||||
|
||||
public:
|
||||
CurlCurlIntegrator() { Q = NULL; DQ = NULL; MQ = NULL; }
|
||||
CurlCurlIntegrator() { Q = NULL; MQ = NULL; }
|
||||
/// Construct a bilinear form integrator for Nedelec elements
|
||||
CurlCurlIntegrator(Coefficient &q, const IntegrationRule *ir = NULL) :
|
||||
BilinearFormIntegrator(ir), Q(&q) { DQ = NULL; MQ = NULL; }
|
||||
CurlCurlIntegrator(VectorCoefficient &dq, const IntegrationRule *ir = NULL) :
|
||||
BilinearFormIntegrator(ir), DQ(&dq) { Q = NULL; MQ = NULL; }
|
||||
CurlCurlIntegrator(MatrixCoefficient &mq, const IntegrationRule *ir = NULL) :
|
||||
BilinearFormIntegrator(ir), MQ(&mq) { Q = NULL; DQ = NULL; }
|
||||
CurlCurlIntegrator(Coefficient &q) : Q(&q) { MQ = NULL; }
|
||||
CurlCurlIntegrator(MatrixCoefficient &m) : MQ(&m) { Q = NULL; }
|
||||
|
||||
/* Given a particular Finite Element, compute the
|
||||
element curl-curl matrix elmat */
|
||||
@@ -2413,11 +2390,8 @@ protected:
|
||||
Vector pa_data;
|
||||
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
|
||||
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
|
||||
const DofToQuad *mapsOtest; ///< Not owned. DOF-to-quad map, open.
|
||||
const DofToQuad *mapsCtest; ///< Not owned. DOF-to-quad map, closed.
|
||||
const GeometricFactors *geom; ///< Not owned
|
||||
int dim, ne, nq, dofs1D, dofs1Dtest, quad1D, trial_fetype, test_fetype;
|
||||
bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient
|
||||
int dim, ne, nq, dofs1D, quad1D, fetype;
|
||||
|
||||
public:
|
||||
VectorFEMassIntegrator() { Init(NULL, NULL, NULL); }
|
||||
@@ -2438,8 +2412,6 @@ public:
|
||||
|
||||
using BilinearFormIntegrator::AssemblePA;
|
||||
virtual void AssemblePA(const FiniteElementSpace &fes);
|
||||
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
const FiniteElementSpace &test_fes);
|
||||
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
||||
virtual void AssembleDiagonalPA(Vector& diag);
|
||||
};
|
||||
@@ -2669,12 +2641,10 @@ public:
|
||||
|
||||
virtual void AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add);
|
||||
Vector &ea_data_ext);
|
||||
|
||||
virtual void AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add);
|
||||
Vector &ea_data_bdr);
|
||||
|
||||
static const IntegrationRule &GetRule(Geometry::Type geom, int order,
|
||||
FaceElementTransformations &T);
|
||||
|
||||
@@ -22,7 +22,6 @@ static void EAConvectionAssemble1D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -55,14 +54,7 @@ static void EAConvectionAssemble1D(const int NE,
|
||||
{
|
||||
val += r_Bj[k1] * D(k1, e) * r_Gi[k1];
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, j1, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, j1, e) = val;
|
||||
}
|
||||
A(i1, j1, e) += val;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -74,7 +66,6 @@ static void EAConvectionAssemble2D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -130,14 +121,7 @@ static void EAConvectionAssemble2D(const int NE,
|
||||
* r_B[k1][j1]* r_B[k2][j2];
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, i2, j1, j2, e) = val;
|
||||
}
|
||||
A(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,7 +135,6 @@ static void EAConvectionAssemble3D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -208,14 +191,7 @@ static void EAConvectionAssemble3D(const int NE,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, i2, i3, j1, j2, j3, e) = val;
|
||||
}
|
||||
A(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,8 +202,7 @@ static void EAConvectionAssemble3D(const int NE,
|
||||
}
|
||||
|
||||
void ConvectionIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
Vector &ea_data,
|
||||
const bool add)
|
||||
Vector &ea_data)
|
||||
{
|
||||
AssemblePA(fes);
|
||||
const int ne = fes.GetMesh()->GetNE();
|
||||
@@ -237,47 +212,44 @@ void ConvectionIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EAConvectionAssemble1D<2,2>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x33: return EAConvectionAssemble1D<3,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x44: return EAConvectionAssemble1D<4,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x55: return EAConvectionAssemble1D<5,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x66: return EAConvectionAssemble1D<6,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x77: return EAConvectionAssemble1D<7,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x88: return EAConvectionAssemble1D<8,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x99: return EAConvectionAssemble1D<9,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EAConvectionAssemble1D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EAConvectionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
|
||||
case 0x33: return EAConvectionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x44: return EAConvectionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x55: return EAConvectionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x66: return EAConvectionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x77: return EAConvectionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x88: return EAConvectionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x99: return EAConvectionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EAConvectionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EAConvectionAssemble2D<2,2>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x33: return EAConvectionAssemble2D<3,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x44: return EAConvectionAssemble2D<4,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x55: return EAConvectionAssemble2D<5,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x66: return EAConvectionAssemble2D<6,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x77: return EAConvectionAssemble2D<7,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x88: return EAConvectionAssemble2D<8,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x99: return EAConvectionAssemble2D<9,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EAConvectionAssemble2D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EAConvectionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
|
||||
case 0x33: return EAConvectionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x44: return EAConvectionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x55: return EAConvectionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x66: return EAConvectionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x77: return EAConvectionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x88: return EAConvectionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x99: return EAConvectionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EAConvectionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x23: return EAConvectionAssemble3D<2,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x34: return EAConvectionAssemble3D<3,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x45: return EAConvectionAssemble3D<4,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x56: return EAConvectionAssemble3D<5,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x67: return EAConvectionAssemble3D<6,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x78: return EAConvectionAssemble3D<7,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x89: return EAConvectionAssemble3D<8,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EAConvectionAssemble3D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x23: return EAConvectionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x34: return EAConvectionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x45: return EAConvectionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x56: return EAConvectionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x67: return EAConvectionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x78: return EAConvectionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x89: return EAConvectionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EAConvectionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
#include "bilininteg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
|
||||
#include "restriction.hpp"
|
||||
#include "tmop_pa.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mfem
|
||||
@@ -68,47 +72,53 @@ static void PAConvectionSetup3D(const int Q1D,
|
||||
const double alpha,
|
||||
Vector &op)
|
||||
{
|
||||
const int NQ = Q1D*Q1D*Q1D;
|
||||
auto W = w.Read();
|
||||
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
|
||||
const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
|
||||
const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
|
||||
const bool const_v = vel.Size() == 3;
|
||||
auto V =
|
||||
const_v ? Reshape(vel.Read(), 3,1,1) : Reshape(vel.Read(), 3,NQ,NE);
|
||||
auto y = Reshape(op.Write(), NQ, 3, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
const auto V = const_v ?
|
||||
Reshape(vel.Read(), 3,1,1,1,1) :
|
||||
Reshape(vel.Read(), 3,Q1D,Q1D,Q1D,NE);
|
||||
auto y = Reshape(op.Write(), Q1D,Q1D,Q1D,3,NE);
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J31 = J(q,2,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double J32 = J(q,2,1,e);
|
||||
const double J13 = J(q,0,2,e);
|
||||
const double J23 = J(q,1,2,e);
|
||||
const double J33 = J(q,2,2,e);
|
||||
const double w = alpha * W[q];
|
||||
const double v0 = const_v ? V(0,0,0) : V(0,q,e);
|
||||
const double v1 = const_v ? V(1,0,0) : V(1,q,e);
|
||||
const double v2 = const_v ? V(2,0,0) : V(2,q,e);
|
||||
const double wx = w * v0;
|
||||
const double wy = w * v1;
|
||||
const double wz = w * v2;
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
const double A12 = (J32 * J13) - (J12 * J33);
|
||||
const double A13 = (J12 * J23) - (J22 * J13);
|
||||
const double A21 = (J31 * J23) - (J21 * J33);
|
||||
const double A22 = (J11 * J33) - (J13 * J31);
|
||||
const double A23 = (J21 * J13) - (J11 * J23);
|
||||
const double A31 = (J21 * J32) - (J31 * J22);
|
||||
const double A32 = (J31 * J12) - (J11 * J32);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
// q . J^{-1} = q . adj(J)
|
||||
y(q,0,e) = wx * A11 + wy * A12 + wz * A13;
|
||||
y(q,1,e) = wx * A21 + wy * A22 + wz * A23;
|
||||
y(q,2,e) = wx * A31 + wy * A32 + wz * A33;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
const double J11 = J(qx,qy,qz,0,0,e);
|
||||
const double J12 = J(qx,qy,qz,0,1,e);
|
||||
const double J13 = J(qx,qy,qz,0,2,e);
|
||||
const double J21 = J(qx,qy,qz,1,0,e);
|
||||
const double J22 = J(qx,qy,qz,1,1,e);
|
||||
const double J23 = J(qx,qy,qz,1,2,e);
|
||||
const double J31 = J(qx,qy,qz,2,0,e);
|
||||
const double J32 = J(qx,qy,qz,2,1,e);
|
||||
const double J33 = J(qx,qy,qz,2,2,e);
|
||||
const double w = alpha * W(qx,qy,qz);
|
||||
const double v0 = const_v ? V(0,0,0,0,0) : V(0,qx,qy,qz,e);
|
||||
const double v1 = const_v ? V(1,0,0,0,0) : V(1,qx,qy,qz,e);
|
||||
const double v2 = const_v ? V(2,0,0,0,0) : V(2,qx,qy,qz,e);
|
||||
const double wx = w * v0;
|
||||
const double wy = w * v1;
|
||||
const double wz = w * v2;
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
const double A12 = (J32 * J13) - (J12 * J33);
|
||||
const double A13 = (J12 * J23) - (J22 * J13);
|
||||
const double A21 = (J31 * J23) - (J21 * J33);
|
||||
const double A22 = (J11 * J33) - (J13 * J31);
|
||||
const double A23 = (J21 * J13) - (J11 * J23);
|
||||
const double A31 = (J21 * J32) - (J31 * J22);
|
||||
const double A32 = (J31 * J12) - (J11 * J32);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
// q . J^{-1} = q . adj(J)
|
||||
y(qx,qy,qz,0,e) = wx * A11 + wy * A12 + wz * A13;
|
||||
y(qx,qy,qz,1,e) = wx * A21 + wy * A22 + wz * A23;
|
||||
y(qx,qy,qz,2,e) = wx * A31 + wy * A32 + wz * A33;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -184,8 +194,8 @@ void PAConvectionApply2D(const int ne,
|
||||
Gu[dy][qx] = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double x = u[dy][dx];
|
||||
Bu[dy][qx] += bx * x;
|
||||
Gu[dy][qx] += gx * x;
|
||||
@@ -202,8 +212,8 @@ void PAConvectionApply2D(const int ne,
|
||||
BGu[qy][qx] = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
GBu[qy][qx] += gx * Bu[dy][qx];
|
||||
BGu[qy][qx] += bx * Gu[dy][qx];
|
||||
}
|
||||
@@ -232,7 +242,7 @@ void PAConvectionApply2D(const int ne,
|
||||
BDGu[dy][qx] = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double w = Bt(dy,qy);
|
||||
const double w = Bt(dy,qy);
|
||||
BDGu[dy][qx] += w * DGu[qy][qx];
|
||||
}
|
||||
}
|
||||
@@ -244,7 +254,7 @@ void PAConvectionApply2D(const int ne,
|
||||
double BBDGu = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double w = Bt(dx,qx);
|
||||
const double w = Bt(dx,qx);
|
||||
BBDGu += w * BDGu[dy][qx];
|
||||
}
|
||||
y(dx,dy,e) += BBDGu;
|
||||
@@ -310,7 +320,7 @@ void SmemPAConvectionApply2D(const int ne,
|
||||
{
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double x = u[tidz][dy][dx];
|
||||
const double x = u[tidz][dy][dx];
|
||||
Bu[tidz][dy][qx] += bx * x;
|
||||
Gu[tidz][dy][qx] += gx * x;
|
||||
}
|
||||
@@ -327,8 +337,8 @@ void SmemPAConvectionApply2D(const int ne,
|
||||
BGu[tidz][qy][qx] = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
GBu[tidz][qy][qx] += gx * Bu[tidz][dy][qx];
|
||||
BGu[tidz][qy][qx] += bx * Gu[tidz][dy][qx];
|
||||
}
|
||||
@@ -359,7 +369,7 @@ void SmemPAConvectionApply2D(const int ne,
|
||||
BDGu[tidz][dy][qx] = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double w = Bt(dy,qy);
|
||||
const double w = Bt(dy,qy);
|
||||
BDGu[tidz][dy][qx] += w * DGu[tidz][qy][qx];
|
||||
}
|
||||
}
|
||||
@@ -372,7 +382,7 @@ void SmemPAConvectionApply2D(const int ne,
|
||||
double BBDGu = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double w = Bt(dx,qx);
|
||||
const double w = Bt(dx,qx);
|
||||
BBDGu += w * BDGu[tidz][dy][qx];
|
||||
}
|
||||
y(dx,dy,e) += BBDGu;
|
||||
@@ -436,8 +446,8 @@ void PAConvectionApply3D(const int ne,
|
||||
Gu[dz][dy][qx] = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double x = u[dz][dy][dx];
|
||||
Bu[dz][dy][qx] += bx * x;
|
||||
Gu[dz][dy][qx] += gx * x;
|
||||
@@ -459,8 +469,8 @@ void PAConvectionApply3D(const int ne,
|
||||
BGu[dz][qy][qx] = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
BBu[dz][qy][qx] += bx * Bu[dz][dy][qx];
|
||||
GBu[dz][qy][qx] += gx * Bu[dz][dy][qx];
|
||||
BGu[dz][qy][qx] += bx * Gu[dz][dy][qx];
|
||||
@@ -482,8 +492,8 @@ void PAConvectionApply3D(const int ne,
|
||||
BBGu[qz][qy][qx] = 0.0;
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
const double bx = B(qz,dz);
|
||||
const double gx = G(qz,dz);
|
||||
const double bx = B(qz,dz);
|
||||
const double gx = G(qz,dz);
|
||||
GBBu[qz][qy][qx] += gx * BBu[dz][qy][qx];
|
||||
BGBu[qz][qy][qx] += bx * GBu[dz][qy][qx];
|
||||
BBGu[qz][qy][qx] += bx * BGu[dz][qy][qx];
|
||||
@@ -521,7 +531,7 @@ void PAConvectionApply3D(const int ne,
|
||||
BDGu[dz][qy][qx] = 0.0;
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const double w = Bt(dz,qz);
|
||||
const double w = Bt(dz,qz);
|
||||
BDGu[dz][qy][qx] += w * DGu[qz][qy][qx];
|
||||
}
|
||||
}
|
||||
@@ -537,7 +547,7 @@ void PAConvectionApply3D(const int ne,
|
||||
BBDGu[dz][dy][qx] = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double w = Bt(dy,qy);
|
||||
const double w = Bt(dy,qy);
|
||||
BBDGu[dz][dy][qx] += w * BDGu[dz][qy][qx];
|
||||
}
|
||||
}
|
||||
@@ -552,7 +562,7 @@ void PAConvectionApply3D(const int ne,
|
||||
double BBBDGu = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double w = Bt(dx,qx);
|
||||
const double w = Bt(dx,qx);
|
||||
BBBDGu += w * BBDGu[dz][dy][qx];
|
||||
}
|
||||
y(dx,dy,dz,e) += BBBDGu;
|
||||
@@ -625,8 +635,8 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double Gu_ = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double bx = B(qx,dx);
|
||||
const double gx = G(qx,dx);
|
||||
const double x = u[dz][dy][dx];
|
||||
Bu_ += bx * x;
|
||||
Gu_ += gx * x;
|
||||
@@ -651,8 +661,8 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double BGu_ = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
const double bx = B(qy,dy);
|
||||
const double gx = G(qy,dy);
|
||||
BBu_ += bx * Bu[dz][dy][qx];
|
||||
GBu_ += gx * Bu[dz][dy][qx];
|
||||
BGu_ += bx * Gu[dz][dy][qx];
|
||||
@@ -678,8 +688,8 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double BBGu_ = 0.0;
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
const double bx = B(qz,dz);
|
||||
const double gx = G(qz,dz);
|
||||
const double bx = B(qz,dz);
|
||||
const double gx = G(qz,dz);
|
||||
GBBu_ += gx * BBu[dz][qy][qx];
|
||||
BGBu_ += bx * GBu[dz][qy][qx];
|
||||
BBGu_ += bx * BGu[dz][qy][qx];
|
||||
@@ -721,7 +731,7 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double BDGu_ = 0.0;
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const double w = Bt(dz,qz);
|
||||
const double w = Bt(dz,qz);
|
||||
BDGu_ += w * DGu[qz][qy][qx];
|
||||
}
|
||||
BDGu[dz][qy][qx] = BDGu_;
|
||||
@@ -739,7 +749,7 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double BBDGu_ = 0.0;
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double w = Bt(dy,qy);
|
||||
const double w = Bt(dy,qy);
|
||||
BBDGu_ += w * BDGu[dz][qy][qx];
|
||||
}
|
||||
BBDGu[dz][dy][qx] = BBDGu_;
|
||||
@@ -756,7 +766,7 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
double BBBDGu = 0.0;
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double w = Bt(dx,qx);
|
||||
const double w = Bt(dx,qx);
|
||||
BBBDGu += w * BBDGu[dz][dy][qx];
|
||||
}
|
||||
y(dx,dy,dz,e) = BBBDGu;
|
||||
@@ -766,6 +776,117 @@ void SmemPAConvectionApply3D(const int ne,
|
||||
});
|
||||
}
|
||||
|
||||
template<int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0, int T_MAX = 0>
|
||||
static void QEvalVGF2D(const int NE,
|
||||
const double *b_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 1,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto X = Reshape(x_, D1D, D1D, VDIM, NE);
|
||||
auto C = Reshape(y_, VDIM, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, 1,
|
||||
{
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
mfem::kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
|
||||
MFEM_SHARED double DD[NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[NBZ][MQ1*MQ1];
|
||||
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
mfem::kernels::LoadX<MD1,NBZ>(e,D1D,c,X,DD);
|
||||
mfem::kernels::EvalX<MD1,MQ1,NBZ>(D1D,Q1D,B,DD,DQ);
|
||||
mfem::kernels::EvalY<MD1,MQ1,NBZ>(D1D,Q1D,B,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
double G;
|
||||
mfem::kernels::PullEval<MQ1,NBZ>(qx,qy,QQ,G);
|
||||
C(c,qx,qy,e) = G;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0, int T_MAX = 0>
|
||||
static void QEvalVGF3D(const int NE,
|
||||
const double *b_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 1,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto X = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
|
||||
auto C = Reshape(y_, VDIM, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : T_MAX;
|
||||
|
||||
MFEM_SHARED double B[MQ1*MD1];
|
||||
mfem::kernels::LoadB<MD1,MQ1>(D1D,Q1D,b,B);
|
||||
|
||||
MFEM_SHARED double DDD[MD1*MD1*MD1];
|
||||
MFEM_SHARED double DDQ[MD1*MD1*MQ1];
|
||||
MFEM_SHARED double DQQ[MD1*MQ1*MQ1];
|
||||
MFEM_SHARED double QQQ[MQ1*MQ1*MQ1];
|
||||
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
mfem::kernels::LoadX<MD1>(e,D1D,c,X,DDD);
|
||||
mfem::kernels::EvalX<MD1,MQ1>(D1D,Q1D,B,DDD,DDQ);
|
||||
mfem::kernels::EvalY<MD1,MQ1>(D1D,Q1D,B,DDQ,DQQ);
|
||||
mfem::kernels::EvalZ<MD1,MQ1>(D1D,Q1D,B,DQQ,QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
double G;
|
||||
mfem::kernels::PullEval<MQ1>(qx,qy,qz,QQQ,G);
|
||||
C(c,qx,qy,qz,e) = G;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
// Assumes tensor-product elements
|
||||
@@ -778,16 +899,90 @@ void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
const int nq = ir->GetNPoints();
|
||||
dim = mesh->Dimension();
|
||||
ne = fes.GetNE();
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
|
||||
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
const MemoryType temp_type = Device::GetDeviceMemoryType() == MemoryType::DEVICE_UMPIRE
|
||||
? MemoryType::DEVICE_UMPIRE_2 : Device::GetDeviceMemoryType();
|
||||
#else
|
||||
const MemoryType temp_type = Device::GetDeviceMemoryType();
|
||||
#endif
|
||||
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mode, temp_type);
|
||||
maps = &el.GetDofToQuad(*ir, mode);
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
|
||||
pa_data.SetSize(symmDims * nq * ne, temp_type);
|
||||
Vector vel;
|
||||
if (VectorConstantCoefficient *cQ = dynamic_cast<VectorConstantCoefficient*>(Q))
|
||||
if (VectorConstantCoefficient *cQ =
|
||||
dynamic_cast<VectorConstantCoefficient*>(Q))
|
||||
{
|
||||
vel = cQ->GetVec();
|
||||
}
|
||||
else if (VectorGridFunctionCoefficient *vgfQ =
|
||||
dynamic_cast<VectorGridFunctionCoefficient*>(Q))
|
||||
{
|
||||
Vector xe;
|
||||
vel.SetSize(dim * nq * ne, temp_type);
|
||||
|
||||
const GridFunction *gf = vgfQ->GetGridFunction();
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
const FiniteElementSpace &gf_fes = *gf->FESpace();
|
||||
|
||||
const int vdim = gf_fes.GetVDim();
|
||||
const Operator *R = gf_fes.GetElementRestriction(ordering);
|
||||
const FiniteElement &el_gf = *gf_fes.GetFE(0);
|
||||
const DofToQuad *maps_gf = &el_gf.GetDofToQuad(*ir, mode);
|
||||
const int D1D = maps_gf->ndof;
|
||||
const int Q1D = maps_gf->nqpt;
|
||||
|
||||
MFEM_VERIFY(R,"");
|
||||
MFEM_VERIFY(vdim == dim, "");
|
||||
MFEM_VERIFY(dim==2 || dim==3,"");
|
||||
|
||||
xe.SetSize(R->Height(), Device::GetMemoryType());
|
||||
xe.UseDevice(true);
|
||||
R->Mult(*gf, xe);
|
||||
|
||||
const auto B = maps_gf->B.Read();
|
||||
const auto x = xe.Read();
|
||||
auto y = vel.Write();
|
||||
|
||||
const int id = (D1D << 4 ) | Q1D;
|
||||
if (dim == 2)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x22: QEvalVGF2D<2,2,2>(ne,B,x,y); break;
|
||||
case 0x33: QEvalVGF2D<2,3,3>(ne,B,x,y); break;
|
||||
case 0x34: QEvalVGF2D<2,3,4>(ne,B,x,y); break;
|
||||
default:
|
||||
{
|
||||
constexpr int MAX_DQ = 8;
|
||||
MFEM_VERIFY(D1D <= MAX_DQ, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_DQ, "");
|
||||
QEvalVGF2D<0,0,0,MAX_DQ>(ne,B,x,y,vdim,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0x23: QEvalVGF3D<3,2,3>(ne,B,x,y); break;
|
||||
case 0x34: QEvalVGF3D<3,3,4>(ne,B,x,y); break;
|
||||
case 0x35: QEvalVGF3D<3,3,5>(ne,B,x,y); break;
|
||||
case 0x46: QEvalVGF3D<3,4,6>(ne,B,x,y); break;
|
||||
case 0x48: QEvalVGF3D<3,4,8>(ne,B,x,y); break;
|
||||
default:
|
||||
{
|
||||
constexpr int MAX_DQ = 6;
|
||||
MFEM_VERIFY(D1D <= MAX_DQ, "");
|
||||
MFEM_VERIFY(Q1D <= MAX_DQ, "");
|
||||
QEvalVGF3D<0,0,0,MAX_DQ>(ne,B,x,y,vdim,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (VectorQuadratureFunctionCoefficient* cQ =
|
||||
dynamic_cast<VectorQuadratureFunctionCoefficient*>(Q))
|
||||
{
|
||||
@@ -841,9 +1036,12 @@ static void PAConvectionApply(const int dim,
|
||||
switch ((D1D << 4 ) | Q1D)
|
||||
{
|
||||
case 0x22: return SmemPAConvectionApply2D<2,2,8>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x33: return SmemPAConvectionApply2D<3,3,3>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x44: return SmemPAConvectionApply2D<4,4,2>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x33: return SmemPAConvectionApply2D<3,3,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x34: return SmemPAConvectionApply2D<3,4,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x44: return SmemPAConvectionApply2D<4,4,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x46: return SmemPAConvectionApply2D<4,6,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x55: return SmemPAConvectionApply2D<5,5,2>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x58: return SmemPAConvectionApply2D<5,8,2>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x66: return SmemPAConvectionApply2D<6,6,1>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x77: return SmemPAConvectionApply2D<7,7,1>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x88: return SmemPAConvectionApply2D<8,8,1>(NE,B,G,Bt,Gt,op,x,y);
|
||||
@@ -856,8 +1054,12 @@ static void PAConvectionApply(const int dim,
|
||||
switch ((D1D << 4 ) | Q1D)
|
||||
{
|
||||
case 0x23: return SmemPAConvectionApply3D<2,3>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x24: return SmemPAConvectionApply3D<2,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x26: return SmemPAConvectionApply3D<2,6>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x34: return SmemPAConvectionApply3D<3,4>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x35: return SmemPAConvectionApply3D<3,5>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x45: return SmemPAConvectionApply3D<4,5>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x48: return SmemPAConvectionApply3D<4,8>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x56: return SmemPAConvectionApply3D<5,6>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x67: return SmemPAConvectionApply3D<6,7>(NE,B,G,Bt,Gt,op,x,y);
|
||||
case 0x78: return SmemPAConvectionApply3D<7,8>(NE,B,G,Bt,Gt,op,x,y);
|
||||
|
||||
+55
-114
@@ -20,8 +20,7 @@ static void EADGTraceAssemble1DInt(const int NF,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata_int,
|
||||
Vector &eadata_ext,
|
||||
const bool add)
|
||||
Vector &eadata_ext)
|
||||
{
|
||||
auto D = Reshape(padata.Read(), 2, 2, NF);
|
||||
auto A_int = Reshape(eadata_int.ReadWrite(), 2, NF);
|
||||
@@ -33,41 +32,23 @@ static void EADGTraceAssemble1DInt(const int NF,
|
||||
val_ext10 = D(1, 0, f);
|
||||
val_ext01 = D(0, 1, f);
|
||||
val_int1 = D(1, 1, f);
|
||||
if (add)
|
||||
{
|
||||
A_int(0, f) += val_int0;
|
||||
A_int(1, f) += val_int1;
|
||||
A_ext(0, f) += val_ext01;
|
||||
A_ext(1, f) += val_ext10;
|
||||
}
|
||||
else
|
||||
{
|
||||
A_int(0, f) = val_int0;
|
||||
A_int(1, f) = val_int1;
|
||||
A_ext(0, f) = val_ext01;
|
||||
A_ext(1, f) = val_ext10;
|
||||
}
|
||||
A_int(0, f) += val_int0;
|
||||
A_int(1, f) += val_int1;
|
||||
A_ext(0, f) += val_ext01;
|
||||
A_ext(1, f) += val_ext10;
|
||||
});
|
||||
}
|
||||
|
||||
static void EADGTraceAssemble1DBdr(const int NF,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata_bdr,
|
||||
const bool add)
|
||||
Vector &eadata_bdr)
|
||||
{
|
||||
auto D = Reshape(padata.Read(), 2, 2, NF);
|
||||
auto A_bdr = Reshape(eadata_bdr.ReadWrite(), NF);
|
||||
MFEM_FORALL(f, NF,
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
A_bdr(f) += D(0, 0, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
A_bdr(f) = D(0, 0, f);
|
||||
}
|
||||
A_bdr(f) += D(0, 0, f);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,7 +58,6 @@ static void EADGTraceAssemble2DInt(const int NF,
|
||||
const Vector &padata,
|
||||
Vector &eadata_int,
|
||||
Vector &eadata_ext,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -108,20 +88,10 @@ static void EADGTraceAssemble2DInt(const int NF,
|
||||
val_ext10 += B(k1,i1) * B(k1,j1) * D(k1, 1, 0, f);
|
||||
val_int1 += B(k1,i1) * B(k1,j1) * D(k1, 1, 1, f);
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A_int(i1, j1, 0, f) += val_int0;
|
||||
A_int(i1, j1, 1, f) += val_int1;
|
||||
A_ext(i1, j1, 0, f) += val_ext01;
|
||||
A_ext(i1, j1, 1, f) += val_ext10;
|
||||
}
|
||||
else
|
||||
{
|
||||
A_int(i1, j1, 0, f) = val_int0;
|
||||
A_int(i1, j1, 1, f) = val_int1;
|
||||
A_ext(i1, j1, 0, f) = val_ext01;
|
||||
A_ext(i1, j1, 1, f) = val_ext10;
|
||||
}
|
||||
A_int(i1, j1, 0, f) += val_int0;
|
||||
A_int(i1, j1, 1, f) += val_int1;
|
||||
A_ext(i1, j1, 0, f) += val_ext01;
|
||||
A_ext(i1, j1, 1, f) += val_ext10;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -132,7 +102,6 @@ static void EADGTraceAssemble2DBdr(const int NF,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata_bdr,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -156,14 +125,7 @@ static void EADGTraceAssemble2DBdr(const int NF,
|
||||
{
|
||||
val_bdr += B(k1,i1) * B(k1,j1) * D(k1, 0, 0, f);
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A_bdr(i1, j1, f) += val_bdr;
|
||||
}
|
||||
else
|
||||
{
|
||||
A_bdr(i1, j1, f) = val_bdr;
|
||||
}
|
||||
A_bdr(i1, j1, f) += val_bdr;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -175,7 +137,6 @@ static void EADGTraceAssemble3DInt(const int NF,
|
||||
const Vector &padata,
|
||||
Vector &eadata_int,
|
||||
Vector &eadata_ext,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -246,20 +207,10 @@ static void EADGTraceAssemble3DInt(const int NF,
|
||||
* s_D[k1][k2][1][0];
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A_int(i1, i2, j1, j2, 0, f) += val_int0;
|
||||
A_int(i1, i2, j1, j2, 1, f) += val_int1;
|
||||
A_ext(i1, i2, j1, j2, 0, f) += val_ext01;
|
||||
A_ext(i1, i2, j1, j2, 1, f) += val_ext10;
|
||||
}
|
||||
else
|
||||
{
|
||||
A_int(i1, i2, j1, j2, 0, f) = val_int0;
|
||||
A_int(i1, i2, j1, j2, 1, f) = val_int1;
|
||||
A_ext(i1, i2, j1, j2, 0, f) = val_ext01;
|
||||
A_ext(i1, i2, j1, j2, 1, f) = val_ext10;
|
||||
}
|
||||
A_int(i1, i2, j1, j2, 0, f) += val_int0;
|
||||
A_int(i1, i2, j1, j2, 1, f) += val_int1;
|
||||
A_ext(i1, i2, j1, j2, 0, f) += val_ext01;
|
||||
A_ext(i1, i2, j1, j2, 1, f) += val_ext10;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -272,7 +223,6 @@ static void EADGTraceAssemble3DBdr(const int NF,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata_bdr,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -330,14 +280,7 @@ static void EADGTraceAssemble3DBdr(const int NF,
|
||||
* s_D[k1][k2][0][0];
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A_bdr(i1, i2, j1, j2, f) += val_bdr;
|
||||
}
|
||||
else
|
||||
{
|
||||
A_bdr(i1, i2, j1, j2, f) = val_bdr;
|
||||
}
|
||||
A_bdr(i1, i2, j1, j2, f) += val_bdr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,8 +290,7 @@ static void EADGTraceAssemble3DBdr(const int NF,
|
||||
|
||||
void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add)
|
||||
Vector &ea_data_ext)
|
||||
{
|
||||
SetupPA(fes, FaceType::Interior);
|
||||
nf = fes.GetNFbyType(FaceType::Interior);
|
||||
@@ -356,7 +298,7 @@ void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
const Array<double> &B = maps->B;
|
||||
if (dim == 1)
|
||||
{
|
||||
return EADGTraceAssemble1DInt(nf,B,pa_data,ea_data_int,ea_data_ext,add);
|
||||
return EADGTraceAssemble1DInt(nf,B,pa_data,ea_data_int,ea_data_ext);
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
@@ -364,31 +306,31 @@ void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
{
|
||||
case 0x22:
|
||||
return EADGTraceAssemble2DInt<2,2>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x33:
|
||||
return EADGTraceAssemble2DInt<3,3>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x44:
|
||||
return EADGTraceAssemble2DInt<4,4>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x55:
|
||||
return EADGTraceAssemble2DInt<5,5>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x66:
|
||||
return EADGTraceAssemble2DInt<6,6>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x77:
|
||||
return EADGTraceAssemble2DInt<7,7>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x88:
|
||||
return EADGTraceAssemble2DInt<8,8>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x99:
|
||||
return EADGTraceAssemble2DInt<9,9>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
default:
|
||||
return EADGTraceAssemble2DInt(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add,dofs1D,quad1D);
|
||||
ea_data_ext,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
@@ -397,36 +339,35 @@ void DGTraceIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
{
|
||||
case 0x23:
|
||||
return EADGTraceAssemble3DInt<2,3>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x34:
|
||||
return EADGTraceAssemble3DInt<3,4>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x45:
|
||||
return EADGTraceAssemble3DInt<4,5>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x56:
|
||||
return EADGTraceAssemble3DInt<5,6>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x67:
|
||||
return EADGTraceAssemble3DInt<6,7>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x78:
|
||||
return EADGTraceAssemble3DInt<7,8>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
case 0x89:
|
||||
return EADGTraceAssemble3DInt<8,9>(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add);
|
||||
ea_data_ext);
|
||||
default:
|
||||
return EADGTraceAssemble3DInt(nf,B,pa_data,ea_data_int,
|
||||
ea_data_ext,add,dofs1D,quad1D);
|
||||
ea_data_ext,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
}
|
||||
|
||||
void DGTraceIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add)
|
||||
Vector &ea_data_bdr)
|
||||
{
|
||||
SetupPA(fes, FaceType::Boundary);
|
||||
nf = fes.GetNFbyType(FaceType::Boundary);
|
||||
@@ -434,37 +375,37 @@ void DGTraceIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
const Array<double> &B = maps->B;
|
||||
if (dim == 1)
|
||||
{
|
||||
return EADGTraceAssemble1DBdr(nf,B,pa_data,ea_data_bdr,add);
|
||||
return EADGTraceAssemble1DBdr(nf,B,pa_data,ea_data_bdr);
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EADGTraceAssemble2DBdr<2,2>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x33: return EADGTraceAssemble2DBdr<3,3>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x44: return EADGTraceAssemble2DBdr<4,4>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x55: return EADGTraceAssemble2DBdr<5,5>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x66: return EADGTraceAssemble2DBdr<6,6>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x77: return EADGTraceAssemble2DBdr<7,7>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x88: return EADGTraceAssemble2DBdr<8,8>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x99: return EADGTraceAssemble2DBdr<9,9>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x22: return EADGTraceAssemble2DBdr<2,2>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x33: return EADGTraceAssemble2DBdr<3,3>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x44: return EADGTraceAssemble2DBdr<4,4>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x55: return EADGTraceAssemble2DBdr<5,5>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x66: return EADGTraceAssemble2DBdr<6,6>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x77: return EADGTraceAssemble2DBdr<7,7>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x88: return EADGTraceAssemble2DBdr<8,8>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x99: return EADGTraceAssemble2DBdr<9,9>(nf,B,pa_data,ea_data_bdr);
|
||||
default:
|
||||
return EADGTraceAssemble2DBdr(nf,B,pa_data,ea_data_bdr,add,dofs1D,quad1D);
|
||||
return EADGTraceAssemble2DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x23: return EADGTraceAssemble3DBdr<2,3>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x34: return EADGTraceAssemble3DBdr<3,4>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x45: return EADGTraceAssemble3DBdr<4,5>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x56: return EADGTraceAssemble3DBdr<5,6>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x67: return EADGTraceAssemble3DBdr<6,7>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x78: return EADGTraceAssemble3DBdr<7,8>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x89: return EADGTraceAssemble3DBdr<8,9>(nf,B,pa_data,ea_data_bdr,add);
|
||||
case 0x23: return EADGTraceAssemble3DBdr<2,3>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x34: return EADGTraceAssemble3DBdr<3,4>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x45: return EADGTraceAssemble3DBdr<4,5>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x56: return EADGTraceAssemble3DBdr<5,6>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x67: return EADGTraceAssemble3DBdr<6,7>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x78: return EADGTraceAssemble3DBdr<7,8>(nf,B,pa_data,ea_data_bdr);
|
||||
case 0x89: return EADGTraceAssemble3DBdr<8,9>(nf,B,pa_data,ea_data_bdr);
|
||||
default:
|
||||
return EADGTraceAssemble3DBdr(nf,B,pa_data,ea_data_bdr,add,dofs1D,quad1D);
|
||||
return EADGTraceAssemble3DBdr(nf,B,pa_data,ea_data_bdr,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
|
||||
@@ -22,7 +22,6 @@ static void EADiffusionAssemble1D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -54,14 +53,7 @@ static void EADiffusionAssemble1D(const int NE,
|
||||
{
|
||||
val += r_Gj[k1] * D(k1, e) * r_Gi[k1];
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, j1, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, j1, e) = val;
|
||||
}
|
||||
A(i1, j1, e) += val;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -73,7 +65,6 @@ static void EADiffusionAssemble2D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -129,14 +120,7 @@ static void EADiffusionAssemble2D(const int NE,
|
||||
+ gbi * D11 * gbj;
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, i2, j1, j2, e) = val;
|
||||
}
|
||||
A(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,11 +130,10 @@ static void EADiffusionAssemble2D(const int NE,
|
||||
|
||||
template<int T_D1D = 0, int T_Q1D = 0>
|
||||
static void EADiffusionAssemble3D(const int NE,
|
||||
const Array<double> &b,
|
||||
const Array<double> &g,
|
||||
const Array<double> &b,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -225,14 +208,7 @@ static void EADiffusionAssemble3D(const int NE,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
A(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
A(i1, i2, i3, j1, j2, j3, e) = val;
|
||||
}
|
||||
A(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,8 +219,7 @@ static void EADiffusionAssemble3D(const int NE,
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
Vector &ea_data,
|
||||
const bool add)
|
||||
Vector &ea_data)
|
||||
{
|
||||
AssemblePA(fes);
|
||||
const int ne = fes.GetMesh()->GetNE();
|
||||
@@ -254,47 +229,44 @@ void DiffusionIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EADiffusionAssemble1D<2,2>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x33: return EADiffusionAssemble1D<3,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x44: return EADiffusionAssemble1D<4,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x55: return EADiffusionAssemble1D<5,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x66: return EADiffusionAssemble1D<6,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x77: return EADiffusionAssemble1D<7,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x88: return EADiffusionAssemble1D<8,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x99: return EADiffusionAssemble1D<9,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EADiffusionAssemble1D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EADiffusionAssemble1D<2,2>(ne,B,G,pa_data,ea_data);
|
||||
case 0x33: return EADiffusionAssemble1D<3,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x44: return EADiffusionAssemble1D<4,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x55: return EADiffusionAssemble1D<5,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x66: return EADiffusionAssemble1D<6,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x77: return EADiffusionAssemble1D<7,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x88: return EADiffusionAssemble1D<8,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x99: return EADiffusionAssemble1D<9,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EADiffusionAssemble1D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EADiffusionAssemble2D<2,2>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x33: return EADiffusionAssemble2D<3,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x44: return EADiffusionAssemble2D<4,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x55: return EADiffusionAssemble2D<5,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x66: return EADiffusionAssemble2D<6,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x77: return EADiffusionAssemble2D<7,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x88: return EADiffusionAssemble2D<8,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x99: return EADiffusionAssemble2D<9,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EADiffusionAssemble2D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EADiffusionAssemble2D<2,2>(ne,B,G,pa_data,ea_data);
|
||||
case 0x33: return EADiffusionAssemble2D<3,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x44: return EADiffusionAssemble2D<4,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x55: return EADiffusionAssemble2D<5,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x66: return EADiffusionAssemble2D<6,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x77: return EADiffusionAssemble2D<7,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x88: return EADiffusionAssemble2D<8,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x99: return EADiffusionAssemble2D<9,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EADiffusionAssemble2D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x23: return EADiffusionAssemble3D<2,3>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x34: return EADiffusionAssemble3D<3,4>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x45: return EADiffusionAssemble3D<4,5>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x56: return EADiffusionAssemble3D<5,6>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x67: return EADiffusionAssemble3D<6,7>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x78: return EADiffusionAssemble3D<7,8>(ne,B,G,pa_data,ea_data,add);
|
||||
case 0x89: return EADiffusionAssemble3D<8,9>(ne,B,G,pa_data,ea_data,add);
|
||||
default: return EADiffusionAssemble3D(ne,B,G,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x23: return EADiffusionAssemble3D<2,3>(ne,B,G,pa_data,ea_data);
|
||||
case 0x34: return EADiffusionAssemble3D<3,4>(ne,B,G,pa_data,ea_data);
|
||||
case 0x45: return EADiffusionAssemble3D<4,5>(ne,B,G,pa_data,ea_data);
|
||||
case 0x56: return EADiffusionAssemble3D<5,6>(ne,B,G,pa_data,ea_data);
|
||||
case 0x67: return EADiffusionAssemble3D<6,7>(ne,B,G,pa_data,ea_data);
|
||||
case 0x78: return EADiffusionAssemble3D<7,8>(ne,B,G,pa_data,ea_data);
|
||||
case 0x89: return EADiffusionAssemble3D<8,9>(ne,B,G,pa_data,ea_data);
|
||||
default: return EADiffusionAssemble3D(ne,B,G,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
|
||||
@@ -96,28 +96,26 @@ void PADiffusionSetup2D<2>(const int Q1D,
|
||||
const Vector &c,
|
||||
Vector &d)
|
||||
{
|
||||
const int NQ = Q1D*Q1D;
|
||||
const bool const_c = c.Size() == 1;
|
||||
const auto W = Reshape(w.Read(), Q1D,Q1D);
|
||||
const auto J = Reshape(j.Read(), Q1D,Q1D,2,2,NE);
|
||||
const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
|
||||
Reshape(c.Read(), Q1D,Q1D,NE);
|
||||
auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
|
||||
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
|
||||
auto W = w.Read();
|
||||
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
|
||||
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
|
||||
auto D = Reshape(d.Write(), NQ, 3, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
const double J11 = J(qx,qy,0,0,e);
|
||||
const double J21 = J(qx,qy,1,0,e);
|
||||
const double J12 = J(qx,qy,0,1,e);
|
||||
const double J22 = J(qx,qy,1,1,e);
|
||||
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
|
||||
const double c_detJ = W(qx,qy) * coeff / ((J11*J22)-(J21*J12));
|
||||
D(qx,qy,0,e) = c_detJ * (J12*J12 + J22*J22); // 1,1
|
||||
D(qx,qy,1,e) = -c_detJ * (J12*J11 + J22*J21); // 1,2
|
||||
D(qx,qy,2,e) = c_detJ * (J11*J11 + J21*J21); // 2,2
|
||||
}
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
const double c_detJ = W[q] * coeff / ((J11*J22)-(J21*J12));
|
||||
D(q,0,e) = c_detJ * (J12*J12 + J22*J22); // 1,1
|
||||
D(q,1,e) = -c_detJ * (J12*J11 + J22*J21); // 1,2
|
||||
D(q,2,e) = c_detJ * (J11*J11 + J21*J21); // 2,2
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -133,35 +131,33 @@ void PADiffusionSetup2D<3>(const int Q1D,
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
constexpr int SDIM = 3;
|
||||
const int NQ = Q1D*Q1D;
|
||||
const bool const_c = c.Size() == 1;
|
||||
const auto W = Reshape(w.Read(), Q1D,Q1D);
|
||||
const auto J = Reshape(j.Read(), Q1D,Q1D,SDIM,DIM,NE);
|
||||
const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
|
||||
Reshape(c.Read(), Q1D,Q1D,NE);
|
||||
auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
|
||||
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
|
||||
|
||||
auto W = w.Read();
|
||||
auto J = Reshape(j.Read(), NQ, SDIM, DIM, NE);
|
||||
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
|
||||
auto D = Reshape(d.Write(), NQ, 3, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
const double wq = W(qx,qy);
|
||||
const double J11 = J(qx,qy,0,0,e);
|
||||
const double J21 = J(qx,qy,1,0,e);
|
||||
const double J31 = J(qx,qy,2,0,e);
|
||||
const double J12 = J(qx,qy,0,1,e);
|
||||
const double J22 = J(qx,qy,1,1,e);
|
||||
const double J32 = J(qx,qy,2,1,e);
|
||||
const double E = J11*J11 + J21*J21 + J31*J31;
|
||||
const double G = J12*J12 + J22*J22 + J32*J32;
|
||||
const double F = J11*J12 + J21*J22 + J31*J32;
|
||||
const double iw = 1.0 / sqrt(E*G - F*F);
|
||||
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
|
||||
const double alpha = wq * coeff * iw;
|
||||
D(qx,qy,0,e) = alpha * G; // 1,1
|
||||
D(qx,qy,1,e) = -alpha * F; // 1,2
|
||||
D(qx,qy,2,e) = alpha * E; // 2,2
|
||||
}
|
||||
const double wq = W[q];
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J31 = J(q,2,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double J32 = J(q,2,1,e);
|
||||
const double E = J11*J11 + J21*J21 + J31*J31;
|
||||
const double G = J12*J12 + J22*J22 + J32*J32;
|
||||
const double F = J11*J12 + J21*J22 + J31*J32;
|
||||
const double iw = 1.0 / sqrt(E*G - F*F);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
const double alpha = wq * coeff * iw;
|
||||
D(q,0,e) = alpha * G; // 1,1
|
||||
D(q,1,e) = -alpha * F; // 1,2
|
||||
D(q,2,e) = alpha * E; // 2,2
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -286,9 +282,10 @@ void DiffusionIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
const int nq = ir->GetNPoints();
|
||||
dim = mesh->Dimension();
|
||||
ne = fes.GetNE();
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
|
||||
const DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mode);
|
||||
const int sdim = mesh->SpaceDimension();
|
||||
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
maps = &el.GetDofToQuad(*ir, mode);
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
pa_data.SetSize(symmDims * nq * ne, Device::GetDeviceMemoryType());
|
||||
@@ -743,6 +740,7 @@ static void PADiffusionAssembleDiagonal(const int dim,
|
||||
case 0x23: return SmemPADiffusionDiagonal3D<2,3>(NE,B,G,D,Y);
|
||||
case 0x34: return SmemPADiffusionDiagonal3D<3,4>(NE,B,G,D,Y);
|
||||
case 0x45: return SmemPADiffusionDiagonal3D<4,5>(NE,B,G,D,Y);
|
||||
case 0x46: return SmemPADiffusionDiagonal3D<4,6>(NE,B,G,D,Y);
|
||||
case 0x56: return SmemPADiffusionDiagonal3D<5,6>(NE,B,G,D,Y);
|
||||
case 0x67: return SmemPADiffusionDiagonal3D<6,7>(NE,B,G,D,Y);
|
||||
case 0x78: return SmemPADiffusionDiagonal3D<7,8>(NE,B,G,D,Y);
|
||||
@@ -1680,7 +1678,7 @@ static void PADiffusionApply(const int dim,
|
||||
MFEM_ABORT("OCCA PADiffusionApply unknown kernel!");
|
||||
}
|
||||
#endif // MFEM_USE_OCCA
|
||||
const int ID = (D1D << 4) | Q1D;
|
||||
const int ID = (D1D << 4 ) | Q1D;
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
@@ -1703,6 +1701,7 @@ static void PADiffusionApply(const int dim,
|
||||
switch (ID)
|
||||
{
|
||||
case 0x23: return SmemPADiffusionApply3D<2,3>(NE,B,G,D,X,Y);
|
||||
case 0x24: return SmemPADiffusionApply3D<2,4>(NE,B,G,D,X,Y);
|
||||
case 0x34: return SmemPADiffusionApply3D<3,4>(NE,B,G,D,X,Y);
|
||||
case 0x45: return SmemPADiffusionApply3D<4,5>(NE,B,G,D,X,Y);
|
||||
case 0x46: return SmemPADiffusionApply3D<4,6>(NE,B,G,D,X,Y);
|
||||
|
||||
+348
-2088
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,11 @@ using namespace std;
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// Local maximum size of dofs and quads in 1D
|
||||
constexpr int HDIV_MAX_D1D = 5;
|
||||
constexpr int HDIV_MAX_Q1D = 6;
|
||||
|
||||
|
||||
// PA H(div) Mass Assemble 2D kernel
|
||||
void PAHdivSetup2D(const int Q1D,
|
||||
const int NE,
|
||||
|
||||
+30
-58
@@ -21,7 +21,6 @@ static void EAMassAssemble1D(const int NE,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -53,14 +52,7 @@ static void EAMassAssemble1D(const int NE,
|
||||
{
|
||||
val += r_Bi[k1] * r_Bj[k1] * D(k1, e);
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
M(i1, j1, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
M(i1, j1, e) = val;
|
||||
}
|
||||
M(i1, j1, e) += val;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -71,7 +63,6 @@ static void EAMassAssemble2D(const int NE,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -123,14 +114,7 @@ static void EAMassAssemble2D(const int NE,
|
||||
* s_D[k1][k2];
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
M(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
M(i1, i2, j1, j2, e) = val;
|
||||
}
|
||||
M(i1, i2, j1, j2, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,7 +127,6 @@ static void EAMassAssemble3D(const int NE,
|
||||
const Array<double> &basis,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const bool add,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
@@ -206,14 +189,7 @@ static void EAMassAssemble3D(const int NE,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
M(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
else
|
||||
{
|
||||
M(i1, i2, i3, j1, j2, j3, e) = val;
|
||||
}
|
||||
M(i1, i2, i3, j1, j2, j3, e) += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,8 +200,7 @@ static void EAMassAssemble3D(const int NE,
|
||||
}
|
||||
|
||||
void MassIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
Vector &ea_data,
|
||||
const bool add)
|
||||
Vector &ea_data)
|
||||
{
|
||||
AssemblePA(fes);
|
||||
const int ne = fes.GetMesh()->GetNE();
|
||||
@@ -234,47 +209,44 @@ void MassIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EAMassAssemble1D<2,2>(ne,B,pa_data,ea_data,add);
|
||||
case 0x33: return EAMassAssemble1D<3,3>(ne,B,pa_data,ea_data,add);
|
||||
case 0x44: return EAMassAssemble1D<4,4>(ne,B,pa_data,ea_data,add);
|
||||
case 0x55: return EAMassAssemble1D<5,5>(ne,B,pa_data,ea_data,add);
|
||||
case 0x66: return EAMassAssemble1D<6,6>(ne,B,pa_data,ea_data,add);
|
||||
case 0x77: return EAMassAssemble1D<7,7>(ne,B,pa_data,ea_data,add);
|
||||
case 0x88: return EAMassAssemble1D<8,8>(ne,B,pa_data,ea_data,add);
|
||||
case 0x99: return EAMassAssemble1D<9,9>(ne,B,pa_data,ea_data,add);
|
||||
default: return EAMassAssemble1D(ne,B,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EAMassAssemble1D<2,2>(ne,B,pa_data,ea_data);
|
||||
case 0x33: return EAMassAssemble1D<3,3>(ne,B,pa_data,ea_data);
|
||||
case 0x44: return EAMassAssemble1D<4,4>(ne,B,pa_data,ea_data);
|
||||
case 0x55: return EAMassAssemble1D<5,5>(ne,B,pa_data,ea_data);
|
||||
case 0x66: return EAMassAssemble1D<6,6>(ne,B,pa_data,ea_data);
|
||||
case 0x77: return EAMassAssemble1D<7,7>(ne,B,pa_data,ea_data);
|
||||
case 0x88: return EAMassAssemble1D<8,8>(ne,B,pa_data,ea_data);
|
||||
case 0x99: return EAMassAssemble1D<9,9>(ne,B,pa_data,ea_data);
|
||||
default: return EAMassAssemble1D(ne,B,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 2)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x22: return EAMassAssemble2D<2,2>(ne,B,pa_data,ea_data,add);
|
||||
case 0x33: return EAMassAssemble2D<3,3>(ne,B,pa_data,ea_data,add);
|
||||
case 0x44: return EAMassAssemble2D<4,4>(ne,B,pa_data,ea_data,add);
|
||||
case 0x55: return EAMassAssemble2D<5,5>(ne,B,pa_data,ea_data,add);
|
||||
case 0x66: return EAMassAssemble2D<6,6>(ne,B,pa_data,ea_data,add);
|
||||
case 0x77: return EAMassAssemble2D<7,7>(ne,B,pa_data,ea_data,add);
|
||||
case 0x88: return EAMassAssemble2D<8,8>(ne,B,pa_data,ea_data,add);
|
||||
case 0x99: return EAMassAssemble2D<9,9>(ne,B,pa_data,ea_data,add);
|
||||
default: return EAMassAssemble2D(ne,B,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x22: return EAMassAssemble2D<2,2>(ne,B,pa_data,ea_data);
|
||||
case 0x33: return EAMassAssemble2D<3,3>(ne,B,pa_data,ea_data);
|
||||
case 0x44: return EAMassAssemble2D<4,4>(ne,B,pa_data,ea_data);
|
||||
case 0x55: return EAMassAssemble2D<5,5>(ne,B,pa_data,ea_data);
|
||||
case 0x66: return EAMassAssemble2D<6,6>(ne,B,pa_data,ea_data);
|
||||
case 0x77: return EAMassAssemble2D<7,7>(ne,B,pa_data,ea_data);
|
||||
case 0x88: return EAMassAssemble2D<8,8>(ne,B,pa_data,ea_data);
|
||||
case 0x99: return EAMassAssemble2D<9,9>(ne,B,pa_data,ea_data);
|
||||
default: return EAMassAssemble2D(ne,B,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
switch ((dofs1D << 4 ) | quad1D)
|
||||
{
|
||||
case 0x23: return EAMassAssemble3D<2,3>(ne,B,pa_data,ea_data,add);
|
||||
case 0x34: return EAMassAssemble3D<3,4>(ne,B,pa_data,ea_data,add);
|
||||
case 0x45: return EAMassAssemble3D<4,5>(ne,B,pa_data,ea_data,add);
|
||||
case 0x56: return EAMassAssemble3D<5,6>(ne,B,pa_data,ea_data,add);
|
||||
case 0x67: return EAMassAssemble3D<6,7>(ne,B,pa_data,ea_data,add);
|
||||
case 0x78: return EAMassAssemble3D<7,8>(ne,B,pa_data,ea_data,add);
|
||||
case 0x89: return EAMassAssemble3D<8,9>(ne,B,pa_data,ea_data,add);
|
||||
default: return EAMassAssemble3D(ne,B,pa_data,ea_data,add,
|
||||
dofs1D,quad1D);
|
||||
case 0x23: return EAMassAssemble3D<2,3>(ne,B,pa_data,ea_data);
|
||||
case 0x34: return EAMassAssemble3D<3,4>(ne,B,pa_data,ea_data);
|
||||
case 0x45: return EAMassAssemble3D<4,5>(ne,B,pa_data,ea_data);
|
||||
case 0x56: return EAMassAssemble3D<5,6>(ne,B,pa_data,ea_data);
|
||||
case 0x67: return EAMassAssemble3D<6,7>(ne,B,pa_data,ea_data);
|
||||
case 0x78: return EAMassAssemble3D<7,8>(ne,B,pa_data,ea_data);
|
||||
case 0x89: return EAMassAssemble3D<8,9>(ne,B,pa_data,ea_data);
|
||||
default: return EAMassAssemble3D(ne,B,pa_data,ea_data,dofs1D,quad1D);
|
||||
}
|
||||
}
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
|
||||
+69
-41
@@ -25,6 +25,7 @@ namespace mfem
|
||||
|
||||
void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
{
|
||||
|
||||
// Assuming the same element type
|
||||
fespace = &fes;
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
@@ -45,22 +46,38 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
dim = mesh->Dimension();
|
||||
ne = fes.GetMesh()->GetNE();
|
||||
nq = ir->GetNPoints();
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::COORDINATES |
|
||||
GeometricFactors::JACOBIANS);
|
||||
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const DofToQuad::Mode mode = DofToQuad::TENSOR;
|
||||
const int flags = GeometricFactors::JACOBIANS |
|
||||
GeometricFactors::COORDINATES;
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
const MemoryType temp_type = Device::GetDeviceMemoryType() == MemoryType::DEVICE_UMPIRE
|
||||
? MemoryType::DEVICE_UMPIRE_2 : Device::GetDeviceMemoryType();
|
||||
#else
|
||||
const MemoryType temp_type = Device::GetDeviceMemoryType();
|
||||
#endif
|
||||
geom = mesh->GetGeometricFactors(*ir, flags, mode, temp_type);
|
||||
maps = &el.GetDofToQuad(*ir, mode);
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
pa_data.SetSize(ne*nq, Device::GetDeviceMemoryType());
|
||||
Vector coeff;
|
||||
Vector *coeff{nullptr};
|
||||
bool own_coeff{true};
|
||||
if (Q == nullptr)
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = 1.0;
|
||||
coeff = new Vector;
|
||||
coeff->SetSize(1);
|
||||
(*coeff)(0) = 1.0;
|
||||
}
|
||||
else if (ConstantCoefficient* cQ = dynamic_cast<ConstantCoefficient*>(Q))
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = cQ->constant;
|
||||
coeff = new Vector;
|
||||
coeff->SetSize(1);
|
||||
(*coeff)(0) = cQ->constant;
|
||||
}
|
||||
else if (QuadratureCoefficient* cQ = dynamic_cast<QuadratureCoefficient*>(Q))
|
||||
{
|
||||
coeff = cQ->Data();
|
||||
own_coeff = false;
|
||||
}
|
||||
else if (QuadratureFunctionCoefficient* cQ =
|
||||
dynamic_cast<QuadratureFunctionCoefficient*>(Q))
|
||||
@@ -73,12 +90,13 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
"IntegrationRule used within integrator and in"
|
||||
" QuadratureFunction appear to be different");
|
||||
qFun.Read();
|
||||
coeff.MakeRef(const_cast<QuadratureFunction &>(qFun),0);
|
||||
coeff->MakeRef(const_cast<QuadratureFunction &>(qFun),0);
|
||||
}
|
||||
else
|
||||
{
|
||||
coeff.SetSize(nq * ne);
|
||||
auto C = Reshape(coeff.HostWrite(), nq, ne);
|
||||
coeff = new Vector;
|
||||
coeff->SetSize(nq * ne);
|
||||
auto C = Reshape(coeff->HostWrite(), nq, ne);
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
ElementTransformation& T = *fes.GetElementTransformation(e);
|
||||
@@ -92,27 +110,24 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
if (dim==2)
|
||||
{
|
||||
const int NE = ne;
|
||||
const int Q1D = quad1D;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
|
||||
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,2,2,NE);
|
||||
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1) :
|
||||
Reshape(coeff.Read(), Q1D,Q1D,NE);
|
||||
auto v = Reshape(pa_data.Write(), Q1D,Q1D, NE);
|
||||
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
|
||||
const int NQ = nq;
|
||||
const bool const_c = coeff->Size() == 1;
|
||||
auto w = ir->GetWeights().Read();
|
||||
auto J = Reshape(geom->J.Read(), NQ,2,2,NE);
|
||||
auto C =
|
||||
const_c ? Reshape(coeff->Read(), 1,1) : Reshape(coeff->Read(), NQ,NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
const double J11 = J(qx,qy,0,0,e);
|
||||
const double J12 = J(qx,qy,1,0,e);
|
||||
const double J21 = J(qx,qy,0,1,e);
|
||||
const double J22 = J(qx,qy,1,1,e);
|
||||
const double detJ = (J11*J22)-(J21*J12);
|
||||
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
|
||||
v(qx,qy,e) = W(qx,qy) * coeff * detJ;
|
||||
}
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J12 = J(q,1,0,e);
|
||||
const double J21 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double detJ = (J11*J22)-(J21*J12);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
v(q,e) = w[q] * coeff * detJ;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -120,12 +135,13 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
{
|
||||
const int NE = ne;
|
||||
const int Q1D = quad1D;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D,Q1D);
|
||||
const bool const_c = coeff->Size() == 1;
|
||||
const auto W = Reshape(ir->GetWeights().Read(),Q1D,Q1D,Q1D);
|
||||
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,Q1D,3,3,NE);
|
||||
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1,1) :
|
||||
Reshape(coeff.Read(), Q1D,Q1D,Q1D,NE);
|
||||
auto v = Reshape(pa_data.Write(), Q1D,Q1D,Q1D,NE);
|
||||
const auto C = const_c ?
|
||||
Reshape(coeff->Read(), 1,1,1,1) :
|
||||
Reshape(coeff->Read(), Q1D,Q1D,Q1D,NE);
|
||||
auto V = Reshape(pa_data.Write(), Q1D,Q1D,Q1D,NE);
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
@@ -135,24 +151,26 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
const double J11 = J(qx,qy,qz,0,0,e);
|
||||
const double J21 = J(qx,qy,qz,1,0,e);
|
||||
const double J31 = J(qx,qy,qz,2,0,e);
|
||||
const double J12 = J(qx,qy,qz,0,1,e);
|
||||
const double J22 = J(qx,qy,qz,1,1,e);
|
||||
const double J32 = J(qx,qy,qz,2,1,e);
|
||||
const double J13 = J(qx,qy,qz,0,2,e);
|
||||
const double J21 = J(qx,qy,qz,1,0,e);
|
||||
const double J22 = J(qx,qy,qz,1,1,e);
|
||||
const double J23 = J(qx,qy,qz,1,2,e);
|
||||
const double J31 = J(qx,qy,qz,2,0,e);
|
||||
const double J32 = J(qx,qy,qz,2,1,e);
|
||||
const double J33 = J(qx,qy,qz,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double coeff = const_c ? C(0,0,0,0) : C(qx,qy,qz,e);
|
||||
v(qx,qy,qz,e) = W(qx,qy,qz) * coeff * detJ;
|
||||
V(qx,qy,qz,e) = W(qx,qy,qz) * coeff * detJ;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (own_coeff) { delete coeff; }
|
||||
}
|
||||
|
||||
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
@@ -454,8 +472,12 @@ static void PAMassAssembleDiagonal(const int dim, const int D1D,
|
||||
switch ((D1D << 4 ) | Q1D)
|
||||
{
|
||||
case 0x23: return SmemPAMassAssembleDiagonal3D<2,3>(NE,B,D,Y);
|
||||
case 0x24: return SmemPAMassAssembleDiagonal3D<2,4>(NE,B,D,Y);
|
||||
case 0x26: return SmemPAMassAssembleDiagonal3D<2,6>(NE,B,D,Y);
|
||||
case 0x34: return SmemPAMassAssembleDiagonal3D<3,4>(NE,B,D,Y);
|
||||
case 0x35: return SmemPAMassAssembleDiagonal3D<3,5>(NE,B,D,Y);
|
||||
case 0x45: return SmemPAMassAssembleDiagonal3D<4,5>(NE,B,D,Y);
|
||||
case 0x48: return SmemPAMassAssembleDiagonal3D<4,8>(NE,B,D,Y);
|
||||
case 0x56: return SmemPAMassAssembleDiagonal3D<5,6>(NE,B,D,Y);
|
||||
case 0x67: return SmemPAMassAssembleDiagonal3D<6,7>(NE,B,D,Y);
|
||||
case 0x78: return SmemPAMassAssembleDiagonal3D<7,8>(NE,B,D,Y);
|
||||
@@ -1189,10 +1211,13 @@ static void PAMassApply(const int dim,
|
||||
case 0x24: return SmemPAMassApply2D<2,4,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x33: return SmemPAMassApply2D<3,3,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x34: return SmemPAMassApply2D<3,4,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x35: return SmemPAMassApply2D<3,5,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x36: return SmemPAMassApply2D<3,6,16>(NE,B,Bt,D,X,Y);
|
||||
case 0x44: return SmemPAMassApply2D<4,4,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x46: return SmemPAMassApply2D<4,6,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x48: return SmemPAMassApply2D<4,8,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x55: return SmemPAMassApply2D<5,5,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x57: return SmemPAMassApply2D<5,7,8>(NE,B,Bt,D,X,Y);
|
||||
case 0x58: return SmemPAMassApply2D<5,8,2>(NE,B,Bt,D,X,Y);
|
||||
case 0x66: return SmemPAMassApply2D<6,6,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x77: return SmemPAMassApply2D<7,7,4>(NE,B,Bt,D,X,Y);
|
||||
@@ -1200,6 +1225,7 @@ static void PAMassApply(const int dim,
|
||||
case 0x99: return SmemPAMassApply2D<9,9,2>(NE,B,Bt,D,X,Y);
|
||||
default: return PAMassApply2D(NE,B,Bt,D,X,Y,D1D,Q1D);
|
||||
}
|
||||
mfem::out << "Unknown 2D kernel 0x" << std::hex << id << std::endl;
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
@@ -1208,7 +1234,9 @@ static void PAMassApply(const int dim,
|
||||
case 0x23: return SmemPAMassApply3D<2,3>(NE,B,Bt,D,X,Y);
|
||||
case 0x24: return SmemPAMassApply3D<2,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x34: return SmemPAMassApply3D<3,4>(NE,B,Bt,D,X,Y);
|
||||
case 0x35: return SmemPAMassApply3D<3,5>(NE,B,Bt,D,X,Y);
|
||||
case 0x36: return SmemPAMassApply3D<3,6>(NE,B,Bt,D,X,Y);
|
||||
case 0x37: return SmemPAMassApply3D<3,7>(NE,B,Bt,D,X,Y);
|
||||
case 0x45: return SmemPAMassApply3D<4,5>(NE,B,Bt,D,X,Y);
|
||||
case 0x46: return SmemPAMassApply3D<4,6>(NE,B,Bt,D,X,Y);
|
||||
case 0x48: return SmemPAMassApply3D<4,8>(NE,B,Bt,D,X,Y);
|
||||
@@ -1220,8 +1248,8 @@ static void PAMassApply(const int dim,
|
||||
case 0x9A: return SmemPAMassApply3D<9,10>(NE,B,Bt,D,X,Y);
|
||||
default: return PAMassApply3D(NE,B,Bt,D,X,Y,D1D,Q1D);
|
||||
}
|
||||
mfem::out << "Unknown 3D kernel 0x" << std::hex << id << std::endl;
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
}
|
||||
|
||||
|
||||
+56
-139
@@ -16,171 +16,88 @@ namespace mfem
|
||||
{
|
||||
|
||||
void TransposeIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
Vector &ea_data, const bool add)
|
||||
Vector &ea_data)
|
||||
{
|
||||
if (add)
|
||||
Vector ea_data_tmp(ea_data.Size());
|
||||
ea_data_tmp = 0.0;
|
||||
bfi->AssembleEA(fes, ea_data_tmp);
|
||||
const int ne = fes.GetNE();
|
||||
if (ne == 0) { return; }
|
||||
const int dofs = fes.GetFE(0)->GetDof();
|
||||
auto A = Reshape(ea_data_tmp.Write(), dofs, dofs, ne);
|
||||
auto AT = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
|
||||
MFEM_FORALL(e, ne,
|
||||
{
|
||||
Vector ea_data_tmp(ea_data.Size());
|
||||
bfi->AssembleEA(fes, ea_data_tmp, false);
|
||||
const int ne = fes.GetNE();
|
||||
if (ne == 0) { return; }
|
||||
const int dofs = fes.GetFE(0)->GetDof();
|
||||
auto A = Reshape(ea_data_tmp.Read(), dofs, dofs, ne);
|
||||
auto AT = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
|
||||
MFEM_FORALL(e, ne,
|
||||
for (int i = 0; i < dofs; i++)
|
||||
{
|
||||
for (int i = 0; i < dofs; i++)
|
||||
for (int j = 0; j < dofs; j++)
|
||||
{
|
||||
for (int j = 0; j < dofs; j++)
|
||||
{
|
||||
const double a = A(i, j, e);
|
||||
AT(j, i, e) += a;
|
||||
}
|
||||
const double a = A(i, j, e);
|
||||
AT(j, i, e) += a;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
bfi->AssembleEA(fes, ea_data, false);
|
||||
const int ne = fes.GetNE();
|
||||
if (ne == 0) { return; }
|
||||
const int dofs = fes.GetFE(0)->GetDof();
|
||||
auto A = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
|
||||
MFEM_FORALL(e, ne,
|
||||
{
|
||||
for (int i = 0; i < dofs; i++)
|
||||
{
|
||||
for (int j = i+1; j < dofs; j++)
|
||||
{
|
||||
const double aij = A(i, j, e);
|
||||
const double aji = A(j, i, e);
|
||||
A(j, i, e) = aij;
|
||||
A(i, j, e) = aji;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_int,
|
||||
Vector &ea_data_ext,
|
||||
const bool add)
|
||||
Vector &ea_data_ext)
|
||||
{
|
||||
const int nf = fes.GetNFbyType(FaceType::Interior);
|
||||
if (nf == 0) { return; }
|
||||
if (add)
|
||||
Vector ea_data_int_tmp(ea_data_int.Size());
|
||||
Vector ea_data_ext_tmp(ea_data_ext.Size());
|
||||
ea_data_int_tmp = 0.0;
|
||||
ea_data_ext_tmp = 0.0;
|
||||
bfi->AssembleEAInteriorFaces(fes, ea_data_int_tmp, ea_data_ext_tmp);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_int = Reshape(ea_data_int_tmp.Read(), faceDofs, faceDofs, 2, nf);
|
||||
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
|
||||
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
auto AT_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
{
|
||||
Vector ea_data_int_tmp(ea_data_int.Size());
|
||||
Vector ea_data_ext_tmp(ea_data_ext.Size());
|
||||
bfi->AssembleEAInteriorFaces(fes, ea_data_int_tmp, ea_data_ext_tmp, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_int = Reshape(ea_data_int_tmp.Read(), faceDofs, faceDofs, 2, nf);
|
||||
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
|
||||
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
auto AT_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
{
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
for (int j = 0; j < faceDofs; j++)
|
||||
{
|
||||
for (int j = 0; j < faceDofs; j++)
|
||||
{
|
||||
const double a_int0 = A_int(i, j, 0, f);
|
||||
const double a_int1 = A_int(i, j, 1, f);
|
||||
const double a_ext0 = A_ext(i, j, 0, f);
|
||||
const double a_ext1 = A_ext(i, j, 1, f);
|
||||
AT_int(j, i, 0, f) += a_int0;
|
||||
AT_int(j, i, 1, f) += a_int1;
|
||||
AT_ext(j, i, 0, f) += a_ext1;
|
||||
AT_ext(j, i, 1, f) += a_ext0;
|
||||
}
|
||||
const double a_int0 = A_int(i, j, 0, f);
|
||||
const double a_int1 = A_int(i, j, 1, f);
|
||||
const double a_ext0 = A_ext(i, j, 0, f);
|
||||
const double a_ext1 = A_ext(i, j, 1, f);
|
||||
AT_int(j, i, 0, f) += a_int0;
|
||||
AT_int(j, i, 1, f) += a_int1;
|
||||
AT_ext(j, i, 0, f) += a_ext1;
|
||||
AT_ext(j, i, 1, f) += a_ext0;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
bfi->AssembleEAInteriorFaces(fes, ea_data_int, ea_data_ext, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
auto A_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
{
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
{
|
||||
for (int j = i+1; j < faceDofs; j++)
|
||||
{
|
||||
const double aij_int0 = A_int(i, j, 0, f);
|
||||
const double aij_int1 = A_int(i, j, 1, f);
|
||||
const double aji_int0 = A_int(j, i, 0, f);
|
||||
const double aji_int1 = A_int(j, i, 1, f);
|
||||
A_int(j, i, 0, f) = aij_int0;
|
||||
A_int(j, i, 1, f) = aij_int1;
|
||||
A_int(i, j, 0, f) = aji_int0;
|
||||
A_int(i, j, 1, f) = aji_int1;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
{
|
||||
for (int j = 0; j < faceDofs; j++)
|
||||
{
|
||||
const double aij_ext0 = A_ext(i, j, 0, f);
|
||||
const double aji_ext1 = A_ext(j, i, 1, f);
|
||||
A_ext(j, i, 1, f) = aij_ext0;
|
||||
A_ext(i, j, 0, f) = aji_ext1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
Vector &ea_data_bdr,
|
||||
const bool add)
|
||||
Vector &ea_data_bdr)
|
||||
{
|
||||
const int nf = fes.GetNFbyType(FaceType::Boundary);
|
||||
if (nf == 0) { return; }
|
||||
if (add)
|
||||
Vector ea_data_bdr_tmp(ea_data_bdr.Size());
|
||||
ea_data_bdr_tmp = 0.0;
|
||||
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr_tmp);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
|
||||
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
{
|
||||
Vector ea_data_bdr_tmp(ea_data_bdr.Size());
|
||||
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr_tmp, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
|
||||
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
{
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
for (int j = 0; j < faceDofs; j++)
|
||||
{
|
||||
for (int j = 0; j < faceDofs; j++)
|
||||
{
|
||||
const double a_bdr = A_bdr(i, j, f);
|
||||
AT_bdr(j, i, f) += a_bdr;
|
||||
}
|
||||
const double a_bdr = A_bdr(i, j, f);
|
||||
AT_bdr(j, i, f) += a_bdr;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceBaseGeometry(0))->GetDof();
|
||||
auto A_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
|
||||
MFEM_FORALL(f, nf,
|
||||
{
|
||||
for (int i = 0; i < faceDofs; i++)
|
||||
{
|
||||
for (int j = i+1; j < faceDofs; j++)
|
||||
{
|
||||
const double aij_bdr = A_bdr(i, j, f);
|
||||
const double aji_bdr = A_bdr(j, i, f);
|
||||
A_bdr(j, i, f) = aij_bdr;
|
||||
A_bdr(i, j, f) = aji_bdr;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+73
-811
File diff suppressed because it is too large
Load Diff
+8
-25
@@ -12,6 +12,7 @@
|
||||
// Implementation of Coefficient class
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
@@ -21,6 +22,13 @@ namespace mfem
|
||||
|
||||
using namespace std;
|
||||
|
||||
double QuadratureCoefficient::Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
auto coeff = mfem::Reshape(qData->HostRead(), nip, NE);
|
||||
return coeff(ip.index, T.ElementNo);
|
||||
}
|
||||
|
||||
double PWConstCoefficient::Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
@@ -319,31 +327,6 @@ void MatrixFunctionCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
}
|
||||
}
|
||||
|
||||
void MatrixFunctionCoefficient::EvalSymmetric(Vector &K,
|
||||
ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
MFEM_VERIFY(symmetric && height == width && height < 4 && SymmFunction,
|
||||
"MatrixFunctionCoefficient is not symmetric");
|
||||
|
||||
double x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
K.SetSize((width * (width + 1)) / 2); // 1x1: 1, 2x2: 3, 3x3: 6
|
||||
|
||||
if (SymmFunction)
|
||||
{
|
||||
(*SymmFunction)(transip, K);
|
||||
}
|
||||
|
||||
if (Q)
|
||||
{
|
||||
K *= Q->Eval(T, ip, GetTime());
|
||||
}
|
||||
}
|
||||
|
||||
MatrixArrayCoefficient::MatrixArrayCoefficient (int dim)
|
||||
: MatrixCoefficient (dim)
|
||||
{
|
||||
|
||||
+29
-34
@@ -87,6 +87,33 @@ public:
|
||||
{ return (constant); }
|
||||
};
|
||||
|
||||
|
||||
/// class for quadrature coefficient
|
||||
class QuadratureCoefficient : public Coefficient
|
||||
{
|
||||
|
||||
private:
|
||||
const int nip;
|
||||
const int NE;
|
||||
public:
|
||||
Vector *qData{nullptr};
|
||||
|
||||
//Set external data
|
||||
QuadratureCoefficient(Vector *Data, int in_nip, int in_NE)
|
||||
: qData(Data), nip(in_nip), NE(in_NE)
|
||||
{ }
|
||||
|
||||
virtual double Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
Vector *Data()
|
||||
{
|
||||
return qData;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// class for piecewise constant coefficient
|
||||
/** @brief A piecewise constant coefficient with the constants keyed
|
||||
off the element attribute numbers. */
|
||||
class PWConstCoefficient : public Coefficient
|
||||
@@ -695,16 +722,13 @@ class MatrixCoefficient
|
||||
protected:
|
||||
int height, width;
|
||||
double time;
|
||||
bool symmetric;
|
||||
|
||||
public:
|
||||
/// Construct a dim x dim matrix coefficient.
|
||||
explicit MatrixCoefficient(int dim, bool symm=false)
|
||||
{ height = width = dim; time = 0.; symmetric = symm; }
|
||||
explicit MatrixCoefficient(int dim) { height = width = dim; time = 0.; }
|
||||
|
||||
/// Construct a h x w matrix coefficient.
|
||||
MatrixCoefficient(int h, int w, bool symm=false) :
|
||||
height(h), width(w), time(0.), symmetric(symm) { }
|
||||
MatrixCoefficient(int h, int w) : height(h), width(w), time(0.) { }
|
||||
|
||||
/// Set the time for time dependent coefficients
|
||||
void SetTime(double t) { time = t; }
|
||||
@@ -721,9 +745,6 @@ public:
|
||||
/// For backward compatibility get the width of the matrix.
|
||||
int GetVDim() const { return width; }
|
||||
|
||||
void SetSymmetric(bool s) { symmetric = s; }
|
||||
bool IsSymmetric() const { return symmetric; }
|
||||
|
||||
/** @brief Evaluate the matrix coefficient in the element described by @a T
|
||||
at the point @a ip, storing the result in @a K. */
|
||||
/** @note When this method is called, the caller must make sure that the
|
||||
@@ -732,15 +753,6 @@ public:
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip) = 0;
|
||||
|
||||
/** @brief Evaluate the upper triangular entries of the matrix coefficient
|
||||
in the symmetric case, similarly to Eval. Matrix entry (i,j) is stored
|
||||
in K[j - i + os_i] for 0 <= i <= j < width, os_0 = 0,
|
||||
os_{i+1} = os_i + width - i. That is, K = {M(0,0), ..., M(0,w-1),
|
||||
M(1,1), ..., M(1,w-1), ..., M(w-1,w-1) with w = width. */
|
||||
virtual void EvalSymmetric(Vector &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{ mfem_error("MatrixCoefficient::EvalSymmetric"); }
|
||||
|
||||
virtual ~MatrixCoefficient() { }
|
||||
};
|
||||
|
||||
@@ -768,7 +780,6 @@ class MatrixFunctionCoefficient : public MatrixCoefficient
|
||||
{
|
||||
private:
|
||||
void (*Function)(const Vector &, DenseMatrix &);
|
||||
void (*SymmFunction)(const Vector &, Vector &);
|
||||
void (*TDFunction)(const Vector &, double, DenseMatrix &);
|
||||
Coefficient *Q;
|
||||
DenseMatrix mat;
|
||||
@@ -806,26 +817,10 @@ public:
|
||||
mat.SetSize(0);
|
||||
}
|
||||
|
||||
/// Construct a symmetric square matrix coefficient from a C-function
|
||||
/// defining a vector function used by EvalSymmetric
|
||||
MatrixFunctionCoefficient(int dim, void (*F)(const Vector &, Vector &),
|
||||
Coefficient *q = NULL)
|
||||
: MatrixCoefficient(dim, true), Q(q)
|
||||
{
|
||||
SymmFunction = F;
|
||||
Function = NULL;
|
||||
TDFunction = NULL;
|
||||
mat.SetSize(0);
|
||||
}
|
||||
|
||||
/// Evaluate the matrix coefficient at @a ip.
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
/// Evaluate the symmetric matrix coefficient at @a ip.
|
||||
virtual void EvalSymmetric(Vector &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
virtual ~MatrixFunctionCoefficient() { }
|
||||
};
|
||||
|
||||
|
||||
+155
-322
@@ -10,7 +10,6 @@
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "complex_fem.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -20,21 +19,16 @@ namespace mfem
|
||||
ComplexGridFunction::ComplexGridFunction(FiniteElementSpace *fes)
|
||||
: Vector(2*(fes->GetVSize()))
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
gfr = new GridFunction();
|
||||
gfr->MakeRef(fes, *this, 0);
|
||||
|
||||
gfi = new GridFunction();
|
||||
gfi->MakeRef(fes, *this, fes->GetVSize());
|
||||
gfr = new GridFunction(fes, data);
|
||||
gfi = new GridFunction(fes, &data[fes->GetVSize()]);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexGridFunction::Update()
|
||||
{
|
||||
FiniteElementSpace *fes = gfr->FESpace();
|
||||
const int vsize = fes->GetVSize();
|
||||
FiniteElementSpace * fes = gfr->FESpace();
|
||||
|
||||
int vsize = fes->GetVSize();
|
||||
|
||||
const Operator *T = fes->GetUpdateOperator();
|
||||
if (T)
|
||||
@@ -46,36 +40,30 @@ ComplexGridFunction::Update()
|
||||
|
||||
// Our data array now contains old data as well as being the wrong size so
|
||||
// reallocate it.
|
||||
UseDevice(true);
|
||||
this->SetSize(2 * vsize);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
// Create temporary vectors which point to the new data array
|
||||
Vector gf_r; gf_r.MakeRef(*this, 0, vsize);
|
||||
Vector gf_i; gf_i.MakeRef(*this, vsize, vsize);
|
||||
Vector gf_r(data, vsize);
|
||||
Vector gf_i((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
// Copy the updated GridFunctions into the new data array
|
||||
gf_r = *gfr;
|
||||
gf_i = *gfi;
|
||||
gf_r.SyncAliasMemory(*this);
|
||||
gf_i.SyncAliasMemory(*this);
|
||||
|
||||
// Replace the individual data arrays with pointers into the new data
|
||||
// array
|
||||
gfr->MakeRef(*this, 0, vsize);
|
||||
gfi->MakeRef(*this, vsize, vsize);
|
||||
gfr->NewDataAndSize(data, vsize);
|
||||
gfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The existing data will not be transferred to the new GridFunctions so
|
||||
// delete it and allocate a new array
|
||||
UseDevice(true);
|
||||
// delete it a allocate a new array
|
||||
this->SetSize(2 * vsize);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
// Point the individual GridFunctions to the new data array
|
||||
gfr->MakeRef(*this, 0, vsize);
|
||||
gfi->MakeRef(*this, vsize, vsize);
|
||||
gfr->NewDataAndSize(data, vsize);
|
||||
gfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
// These updates will only set the proper 'sequence' value within the
|
||||
// individual GridFunction objects because their sizes are already correct
|
||||
@@ -88,24 +76,16 @@ void
|
||||
ComplexGridFunction::ProjectCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff)
|
||||
{
|
||||
gfr->SyncMemory(*this);
|
||||
gfi->SyncMemory(*this);
|
||||
gfr->ProjectCoefficient(real_coeff);
|
||||
gfi->ProjectCoefficient(imag_coeff);
|
||||
gfr->SyncAliasMemory(*this);
|
||||
gfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexGridFunction::ProjectCoefficient(VectorCoefficient &real_vcoeff,
|
||||
VectorCoefficient &imag_vcoeff)
|
||||
{
|
||||
gfr->SyncMemory(*this);
|
||||
gfi->SyncMemory(*this);
|
||||
gfr->ProjectCoefficient(real_vcoeff);
|
||||
gfi->ProjectCoefficient(imag_vcoeff);
|
||||
gfr->SyncAliasMemory(*this);
|
||||
gfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -113,12 +93,8 @@ ComplexGridFunction::ProjectBdrCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
gfr->SyncMemory(*this);
|
||||
gfi->SyncMemory(*this);
|
||||
gfr->ProjectBdrCoefficient(real_coeff, attr);
|
||||
gfi->ProjectBdrCoefficient(imag_coeff, attr);
|
||||
gfr->SyncAliasMemory(*this);
|
||||
gfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -126,12 +102,8 @@ ComplexGridFunction::ProjectBdrCoefficientNormal(VectorCoefficient &real_vcoeff,
|
||||
VectorCoefficient &imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
gfr->SyncMemory(*this);
|
||||
gfi->SyncMemory(*this);
|
||||
gfr->ProjectBdrCoefficientNormal(real_vcoeff, attr);
|
||||
gfi->ProjectBdrCoefficientNormal(imag_vcoeff, attr);
|
||||
gfr->SyncAliasMemory(*this);
|
||||
gfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -141,28 +113,18 @@ ComplexGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient
|
||||
&imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
gfr->SyncMemory(*this);
|
||||
gfi->SyncMemory(*this);
|
||||
gfr->ProjectBdrCoefficientTangent(real_vcoeff, attr);
|
||||
gfi->ProjectBdrCoefficientTangent(imag_vcoeff, attr);
|
||||
gfr->SyncAliasMemory(*this);
|
||||
gfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
|
||||
ComplexLinearForm::ComplexLinearForm(FiniteElementSpace *fes,
|
||||
ComplexLinearForm::ComplexLinearForm(FiniteElementSpace *f,
|
||||
ComplexOperator::Convention convention)
|
||||
: Vector(2*(fes->GetVSize())),
|
||||
: Vector(2*(f->GetVSize())),
|
||||
conv(convention)
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
lfr = new LinearForm();
|
||||
lfr->MakeRef(fes, *this, 0);
|
||||
|
||||
lfi = new LinearForm();
|
||||
lfi->MakeRef(fes, *this, fes->GetVSize());
|
||||
lfr = new LinearForm(f, data);
|
||||
lfi = new LinearForm(f, &data[f->GetVSize()]);
|
||||
}
|
||||
|
||||
ComplexLinearForm::ComplexLinearForm(FiniteElementSpace *fes,
|
||||
@@ -171,14 +133,8 @@ ComplexLinearForm::ComplexLinearForm(FiniteElementSpace *fes,
|
||||
: Vector(2*(fes->GetVSize())),
|
||||
conv(convention)
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
lfr = new LinearForm(fes, lf_r);
|
||||
lfi = new LinearForm(fes, lf_i);
|
||||
|
||||
lfr->MakeRef(fes, *this, 0);
|
||||
lfi->MakeRef(fes, *this, fes->GetVSize());
|
||||
lfr = new LinearForm(fes, lf_r); lfr->SetData(data);
|
||||
lfi = new LinearForm(fes, lf_i); lfi->SetData(&data[fes->GetVSize()]);
|
||||
}
|
||||
|
||||
ComplexLinearForm::~ComplexLinearForm()
|
||||
@@ -233,43 +189,42 @@ void
|
||||
ComplexLinearForm::Update()
|
||||
{
|
||||
FiniteElementSpace *fes = lfr->FESpace();
|
||||
|
||||
this->Update(fes);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexLinearForm::Update(FiniteElementSpace *fes)
|
||||
{
|
||||
UseDevice(true);
|
||||
SetSize(2 * fes->GetVSize());
|
||||
this->Vector::operator=(0.0);
|
||||
int vsize = fes->GetVSize();
|
||||
SetSize(2 * vsize);
|
||||
|
||||
lfr->MakeRef(fes, *this, 0);
|
||||
lfi->MakeRef(fes, *this, fes->GetVSize());
|
||||
Vector vlfr(data, vsize);
|
||||
Vector vlfi((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
lfr->Update(fes, vlfr, 0);
|
||||
lfi->Update(fes, vlfi, 0);
|
||||
}
|
||||
|
||||
void
|
||||
ComplexLinearForm::Assemble()
|
||||
{
|
||||
lfr->SyncMemory(*this);
|
||||
lfi->SyncMemory(*this);
|
||||
lfr->Assemble();
|
||||
lfi->Assemble();
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC) { *lfi *= -1.0; }
|
||||
lfr->SyncAliasMemory(*this);
|
||||
lfi->SyncAliasMemory(*this);
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
|
||||
{
|
||||
*lfi *= -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
complex<double>
|
||||
ComplexLinearForm::operator()(const ComplexGridFunction &gf) const
|
||||
{
|
||||
double s = (conv == ComplexOperator::HERMITIAN) ? 1.0 : -1.0;
|
||||
lfr->SyncMemory(*this);
|
||||
lfi->SyncMemory(*this);
|
||||
double s = (conv == ComplexOperator::HERMITIAN)?1.0:-1.0;
|
||||
return complex<double>((*lfr)(gf.real()) - s * (*lfi)(gf.imag()),
|
||||
(*lfr)(gf.imag()) + s * (*lfi)(gf.real()));
|
||||
}
|
||||
|
||||
|
||||
bool SesquilinearForm::RealInteg()
|
||||
{
|
||||
int nint = blfr->GetFBFI()->Size() + blfr->GetDBFI()->Size() +
|
||||
@@ -386,45 +341,34 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
Vector &X, Vector &B,
|
||||
int ci)
|
||||
{
|
||||
FiniteElementSpace *fes = blfr->FESpace();
|
||||
const int vsize = fes->GetVSize();
|
||||
FiniteElementSpace * fes = blfr->FESpace();
|
||||
int vsize = fes->GetVSize();
|
||||
|
||||
// Allocate temporary vector
|
||||
Vector b_0;
|
||||
b_0.UseDevice(true);
|
||||
b_0.SetSize(vsize);
|
||||
b_0 = 0.0;
|
||||
// Allocate temporary vectors
|
||||
Vector b_0(vsize); b_0 = 0.0;
|
||||
|
||||
// Extract the real and imaginary parts of the input vectors
|
||||
MFEM_ASSERT(x.Size() == 2 * vsize, "Input GridFunction of incorrect size!");
|
||||
x.Read();
|
||||
Vector x_r; x_r.MakeRef(x, 0, vsize);
|
||||
Vector x_i; x_i.MakeRef(x, vsize, vsize);
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
MFEM_ASSERT(b.Size() == 2 * vsize, "Input LinearForm of incorrect size!");
|
||||
b.Read();
|
||||
Vector b_r; b_r.MakeRef(b, 0, vsize);
|
||||
Vector b_i; b_i.MakeRef(b, vsize, vsize);
|
||||
Vector b_r(b.GetData(), vsize);
|
||||
Vector b_i(&(b.GetData())[vsize], vsize);
|
||||
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC) { b_i *= -1.0; }
|
||||
|
||||
const int tvsize = fes->GetTrueVSize();
|
||||
int tvsize = fes->GetTrueVSize();
|
||||
OperatorHandle A_r, A_i;
|
||||
|
||||
X.UseDevice(true);
|
||||
X.SetSize(2 * tvsize);
|
||||
X = 0.0;
|
||||
|
||||
B.UseDevice(true);
|
||||
B.SetSize(2 * tvsize);
|
||||
B = 0.0;
|
||||
|
||||
Vector X_r; X_r.MakeRef(X, 0, tvsize);
|
||||
Vector X_i; X_i.MakeRef(X, tvsize, tvsize);
|
||||
Vector B_r; B_r.MakeRef(B, 0, tvsize);
|
||||
Vector B_i; B_i.MakeRef(B, tvsize, tvsize);
|
||||
|
||||
Vector X_0, B_0;
|
||||
Vector X_0(tvsize), B_0(tvsize);
|
||||
Vector X_r(X.GetData(),tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
Vector B_r(B.GetData(), tvsize);
|
||||
Vector B_i(&(B.GetData())[tvsize], tvsize);
|
||||
|
||||
if (RealInteg())
|
||||
{
|
||||
@@ -474,18 +418,13 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
// conform with standard essential BC treatment
|
||||
if (A_i.Is<ConstrainedOperator>())
|
||||
{
|
||||
const int n = ess_tdof_list.Size();
|
||||
auto d_B_r = B_r.Write();
|
||||
auto d_B_i = B_i.Write();
|
||||
auto d_X_r = X_r.Read();
|
||||
auto d_X_i = X_i.Read();
|
||||
auto d_idx = ess_tdof_list.Read();
|
||||
MFEM_FORALL(i, n,
|
||||
int n = ess_tdof_list.Size();
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
const int j = d_idx[i];
|
||||
d_B_r[j] = d_X_r[j];
|
||||
d_B_i[j] = d_X_i[j];
|
||||
});
|
||||
int j = ess_tdof_list[k];
|
||||
B_r(j) = X_r(j);
|
||||
B_i(j) = X_i(j);
|
||||
}
|
||||
A_i.As<ConstrainedOperator>()->SetDiagonalPolicy
|
||||
(mfem::Operator::DiagonalPolicy::DIAG_ZERO);
|
||||
}
|
||||
@@ -497,16 +436,6 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
b_i *= -1.0;
|
||||
}
|
||||
|
||||
x_r.SyncAliasMemory(x);
|
||||
x_i.SyncAliasMemory(x);
|
||||
b_r.SyncAliasMemory(b);
|
||||
b_i.SyncAliasMemory(b);
|
||||
|
||||
X_r.SyncAliasMemory(X);
|
||||
X_i.SyncAliasMemory(X);
|
||||
B_r.SyncAliasMemory(B);
|
||||
B_i.SyncAliasMemory(B);
|
||||
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
if ( A_r.Type() == Operator::MFEM_SPARSEMAT ||
|
||||
@@ -599,32 +528,29 @@ void
|
||||
SesquilinearForm::RecoverFEMSolution(const Vector &X, const Vector &b,
|
||||
Vector &x)
|
||||
{
|
||||
FiniteElementSpace *fes = blfr->FESpace();
|
||||
FiniteElementSpace * fes = blfr->FESpace();
|
||||
|
||||
const SparseMatrix *P = fes->GetConformingProlongation();
|
||||
|
||||
int vsize = fes->GetVSize();
|
||||
int tvsize = X.Size() / 2;
|
||||
|
||||
Vector X_r(X.GetData(), tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
if (!P)
|
||||
{
|
||||
x = X;
|
||||
return;
|
||||
}
|
||||
|
||||
const int vsize = fes->GetVSize();
|
||||
const int tvsize = X.Size() / 2;
|
||||
|
||||
X.Read();
|
||||
Vector X_r; X_r.MakeRef(const_cast<Vector&>(X), 0, tvsize);
|
||||
Vector X_i; X_i.MakeRef(const_cast<Vector&>(X), tvsize, tvsize);
|
||||
|
||||
x.Write();
|
||||
Vector x_r; x_r.MakeRef(x, 0, vsize);
|
||||
Vector x_i; x_i.MakeRef(x, vsize, vsize);
|
||||
|
||||
// Apply conforming prolongation
|
||||
P->Mult(X_r, x_r);
|
||||
P->Mult(X_i, x_i);
|
||||
|
||||
x_r.SyncAliasMemory(x);
|
||||
x_i.SyncAliasMemory(x);
|
||||
else
|
||||
{
|
||||
// Apply conforming prolongation
|
||||
P->Mult(X_r, x_r);
|
||||
P->Mult(X_i, x_i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -640,21 +566,16 @@ SesquilinearForm::Update(FiniteElementSpace *nfes)
|
||||
ParComplexGridFunction::ParComplexGridFunction(ParFiniteElementSpace *pfes)
|
||||
: Vector(2*(pfes->GetVSize()))
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
pgfr = new ParGridFunction();
|
||||
pgfr->MakeRef(pfes, *this, 0);
|
||||
|
||||
pgfi = new ParGridFunction();
|
||||
pgfi->MakeRef(pfes, *this, pfes->GetVSize());
|
||||
pgfr = new ParGridFunction(pfes, data);
|
||||
pgfi = new ParGridFunction(pfes, (data) ? &data[pfes->GetVSize()]:data);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::Update()
|
||||
{
|
||||
ParFiniteElementSpace *pfes = pgfr->ParFESpace();
|
||||
const int vsize = pfes->GetVSize();
|
||||
ParFiniteElementSpace * pfes = pgfr->ParFESpace();
|
||||
|
||||
int vsize = pfes->GetVSize();
|
||||
|
||||
const Operator *T = pfes->GetUpdateOperator();
|
||||
if (T)
|
||||
@@ -666,34 +587,30 @@ ParComplexGridFunction::Update()
|
||||
|
||||
// Our data array now contains old data as well as being the wrong size so
|
||||
// reallocate it.
|
||||
UseDevice(true);
|
||||
this->SetSize(2 * vsize);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
// Create temporary vectors which point to the new data array
|
||||
Vector gf_r; gf_r.MakeRef(*this, 0, vsize);
|
||||
Vector gf_i; gf_i.MakeRef(*this, vsize, vsize);
|
||||
Vector gf_r(data, vsize);
|
||||
Vector gf_i((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
// Copy the updated GridFunctions into the new data array
|
||||
gf_r = *pgfr; gf_r.SyncAliasMemory(*this);
|
||||
gf_i = *pgfi; gf_i.SyncAliasMemory(*this);
|
||||
gf_r = *pgfr;
|
||||
gf_i = *pgfi;
|
||||
|
||||
// Replace the individual data arrays with pointers into the new data
|
||||
// array
|
||||
pgfr->MakeRef(*this, 0, vsize);
|
||||
pgfi->MakeRef(*this, vsize, vsize);
|
||||
pgfr->NewDataAndSize(data, vsize);
|
||||
pgfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The existing data will not be transferred to the new GridFunctions so
|
||||
// delete it and allocate a new array
|
||||
UseDevice(true);
|
||||
// delete it a allocate a new array
|
||||
this->SetSize(2 * vsize);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
// Point the individual GridFunctions to the new data array
|
||||
pgfr->MakeRef(*this, 0, vsize);
|
||||
pgfi->MakeRef(*this, vsize, vsize);
|
||||
pgfr->NewDataAndSize(data, vsize);
|
||||
pgfi->NewDataAndSize((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
// These updates will only set the proper 'sequence' value within the
|
||||
// individual GridFunction objects because their sizes are already correct
|
||||
@@ -706,24 +623,16 @@ void
|
||||
ParComplexGridFunction::ProjectCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff)
|
||||
{
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ProjectCoefficient(real_coeff);
|
||||
pgfi->ProjectCoefficient(imag_coeff);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::ProjectCoefficient(VectorCoefficient &real_vcoeff,
|
||||
VectorCoefficient &imag_vcoeff)
|
||||
{
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ProjectCoefficient(real_vcoeff);
|
||||
pgfi->ProjectCoefficient(imag_vcoeff);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -731,12 +640,8 @@ ParComplexGridFunction::ProjectBdrCoefficient(Coefficient &real_coeff,
|
||||
Coefficient &imag_coeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ProjectBdrCoefficient(real_coeff, attr);
|
||||
pgfi->ProjectBdrCoefficient(imag_coeff, attr);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -746,12 +651,8 @@ ParComplexGridFunction::ProjectBdrCoefficientNormal(VectorCoefficient
|
||||
&imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ProjectBdrCoefficientNormal(real_vcoeff, attr);
|
||||
pgfi->ProjectBdrCoefficientNormal(imag_vcoeff, attr);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -761,51 +662,36 @@ ParComplexGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient
|
||||
&imag_vcoeff,
|
||||
Array<int> &attr)
|
||||
{
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ProjectBdrCoefficientTangent(real_vcoeff, attr);
|
||||
pgfi->ProjectBdrCoefficientTangent(imag_vcoeff, attr);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::Distribute(const Vector *tv)
|
||||
{
|
||||
ParFiniteElementSpace *pfes = pgfr->ParFESpace();
|
||||
const int tvsize = pfes->GetTrueVSize();
|
||||
ParFiniteElementSpace * pfes = pgfr->ParFESpace();
|
||||
HYPRE_Int size = pfes->GetTrueVSize();
|
||||
|
||||
tv->Read();
|
||||
Vector tvr; tvr.MakeRef(const_cast<Vector&>(*tv), 0, tvsize);
|
||||
Vector tvi; tvi.MakeRef(const_cast<Vector&>(*tv), tvsize, tvsize);
|
||||
double * tvd = tv->GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi((tvd) ? &tvd[size] : tvd, size);
|
||||
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->Distribute(tvr);
|
||||
pgfi->Distribute(tvi);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexGridFunction::ParallelProject(Vector &tv) const
|
||||
{
|
||||
ParFiniteElementSpace *pfes = pgfr->ParFESpace();
|
||||
const int tvsize = pfes->GetTrueVSize();
|
||||
ParFiniteElementSpace * pfes = pgfr->ParFESpace();
|
||||
HYPRE_Int size = pfes->GetTrueVSize();
|
||||
|
||||
tv.Write();
|
||||
Vector tvr; tvr.MakeRef(tv, 0, tvsize);
|
||||
Vector tvi; tvi.MakeRef(tv, tvsize, tvsize);
|
||||
double * tvd = tv.GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi((tvd) ? &tvd[size] : tvd, size);
|
||||
|
||||
pgfr->SyncMemory(*this);
|
||||
pgfi->SyncMemory(*this);
|
||||
pgfr->ParallelProject(tvr);
|
||||
pgfi->ParallelProject(tvi);
|
||||
pgfr->SyncAliasMemory(*this);
|
||||
pgfi->SyncAliasMemory(*this);
|
||||
|
||||
tvr.SyncAliasMemory(tv);
|
||||
tvi.SyncAliasMemory(tv);
|
||||
}
|
||||
|
||||
|
||||
@@ -815,16 +701,10 @@ ParComplexLinearForm::ParComplexLinearForm(ParFiniteElementSpace *pfes,
|
||||
: Vector(2*(pfes->GetVSize())),
|
||||
conv(convention)
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
plfr = new ParLinearForm(pfes, data);
|
||||
plfi = new ParLinearForm(pfes, (data) ? &data[pfes->GetVSize()]:data);
|
||||
|
||||
plfr = new ParLinearForm();
|
||||
plfr->MakeRef(pfes, *this, 0);
|
||||
|
||||
plfi = new ParLinearForm();
|
||||
plfi->MakeRef(pfes, *this, pfes->GetVSize());
|
||||
|
||||
HYPRE_Int *tdof_offsets_fes = pfes->GetTrueDofOffsets();
|
||||
HYPRE_Int * tdof_offsets_fes = pfes->GetTrueDofOffsets();
|
||||
|
||||
int n = (HYPRE_AssumedPartitionCheck()) ? 2 : pfes->GetNRanks();
|
||||
tdof_offsets = new HYPRE_Int[n+1];
|
||||
@@ -844,16 +724,12 @@ ParComplexLinearForm::ParComplexLinearForm(ParFiniteElementSpace *pfes,
|
||||
: Vector(2*(pfes->GetVSize())),
|
||||
conv(convention)
|
||||
{
|
||||
UseDevice(true);
|
||||
this->Vector::operator=(0.0);
|
||||
|
||||
plfr = new ParLinearForm(pfes, plf_r);
|
||||
plfr->SetData(data);
|
||||
plfi = new ParLinearForm(pfes, plf_i);
|
||||
plfi->SetData((data) ? &data[pfes->GetVSize()]:data);
|
||||
|
||||
plfr->MakeRef(pfes, *this, 0);
|
||||
plfi->MakeRef(pfes, *this, pfes->GetVSize());
|
||||
|
||||
HYPRE_Int *tdof_offsets_fes = pfes->GetTrueDofOffsets();
|
||||
HYPRE_Int * tdof_offsets_fes = pfes->GetTrueDofOffsets();
|
||||
|
||||
int n = (HYPRE_AssumedPartitionCheck()) ? 2 : pfes->GetNRanks();
|
||||
tdof_offsets = new HYPRE_Int[n+1];
|
||||
@@ -916,71 +792,58 @@ ParComplexLinearForm::AddBdrFaceIntegrator(LinearFormIntegrator *lfi_real,
|
||||
void
|
||||
ParComplexLinearForm::Update(ParFiniteElementSpace *pf)
|
||||
{
|
||||
ParFiniteElementSpace *pfes = (pf != NULL) ? pf : plfr->ParFESpace();
|
||||
ParFiniteElementSpace *pfes = (pf!=NULL)?pf:plfr->ParFESpace();
|
||||
int vsize = pfes->GetVSize();
|
||||
SetSize(2 * vsize);
|
||||
|
||||
UseDevice(true);
|
||||
SetSize(2 * pfes->GetVSize());
|
||||
this->Vector::operator=(0.0);
|
||||
Vector vplfr(data, vsize);
|
||||
Vector vplfi((data) ? &data[vsize] : data, vsize);
|
||||
|
||||
plfr->MakeRef(pfes, *this, 0);
|
||||
plfi->MakeRef(pfes, *this, pfes->GetVSize());
|
||||
plfr->Update(pfes, vplfr, 0);
|
||||
plfi->Update(pfes, vplfi, 0);
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexLinearForm::Assemble()
|
||||
{
|
||||
plfr->SyncMemory(*this);
|
||||
plfi->SyncMemory(*this);
|
||||
plfr->Assemble();
|
||||
plfi->Assemble();
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC) { *plfi *= -1.0; }
|
||||
plfr->SyncAliasMemory(*this);
|
||||
plfi->SyncAliasMemory(*this);
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
|
||||
{
|
||||
*plfi *= -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParComplexLinearForm::ParallelAssemble(Vector &tv)
|
||||
{
|
||||
const int tvsize = plfr->ParFESpace()->GetTrueVSize();
|
||||
HYPRE_Int size = plfr->ParFESpace()->GetTrueVSize();
|
||||
|
||||
tv.Write();
|
||||
Vector tvr; tvr.MakeRef(tv, 0, tvsize);
|
||||
Vector tvi; tvi.MakeRef(tv, tvsize, tvsize);
|
||||
double * tvd = tv.GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi((tvd) ? &tvd[size] : tvd, size);
|
||||
|
||||
plfr->SyncMemory(*this);
|
||||
plfi->SyncMemory(*this);
|
||||
plfr->ParallelAssemble(tvr);
|
||||
plfi->ParallelAssemble(tvi);
|
||||
plfr->SyncAliasMemory(*this);
|
||||
plfi->SyncAliasMemory(*this);
|
||||
|
||||
tvr.SyncAliasMemory(tv);
|
||||
tvi.SyncAliasMemory(tv);
|
||||
}
|
||||
|
||||
HypreParVector *
|
||||
ParComplexLinearForm::ParallelAssemble()
|
||||
{
|
||||
const ParFiniteElementSpace *pfes = plfr->ParFESpace();
|
||||
const int tvsize = pfes->GetTrueVSize();
|
||||
const ParFiniteElementSpace * pfes = plfr->ParFESpace();
|
||||
|
||||
HypreParVector *tv = new HypreParVector(pfes->GetComm(),
|
||||
2*(pfes->GlobalTrueVSize()),
|
||||
tdof_offsets);
|
||||
HypreParVector * tv = new HypreParVector(pfes->GetComm(),
|
||||
2*(pfes->GlobalTrueVSize()),
|
||||
tdof_offsets);
|
||||
|
||||
tv->Write();
|
||||
Vector tvr; tvr.MakeRef(*tv, 0, tvsize);
|
||||
Vector tvi; tvi.MakeRef(*tv, tvsize, tvsize);
|
||||
HYPRE_Int size = pfes->GetTrueVSize();
|
||||
|
||||
double * tvd = tv->GetData();
|
||||
Vector tvr(tvd, size);
|
||||
Vector tvi((tvd) ? &tvd[size] : tvd, size);
|
||||
|
||||
plfr->SyncMemory(*this);
|
||||
plfi->SyncMemory(*this);
|
||||
plfr->ParallelAssemble(tvr);
|
||||
plfi->ParallelAssemble(tvi);
|
||||
plfr->SyncAliasMemory(*this);
|
||||
plfi->SyncAliasMemory(*this);
|
||||
|
||||
tvr.SyncAliasMemory(*tv);
|
||||
tvi.SyncAliasMemory(*tv);
|
||||
|
||||
return tv;
|
||||
}
|
||||
@@ -988,14 +851,13 @@ ParComplexLinearForm::ParallelAssemble()
|
||||
complex<double>
|
||||
ParComplexLinearForm::operator()(const ParComplexGridFunction &gf) const
|
||||
{
|
||||
plfr->SyncMemory(*this);
|
||||
plfi->SyncMemory(*this);
|
||||
double s = (conv == ComplexOperator::HERMITIAN) ? 1.0 : -1.0;
|
||||
double s = (conv == ComplexOperator::HERMITIAN)?1.0:-1.0;
|
||||
return complex<double>((*plfr)(gf.real()) - s * (*plfi)(gf.imag()),
|
||||
(*plfr)(gf.imag()) + s * (*plfi)(gf.real()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ParSesquilinearForm::RealInteg()
|
||||
{
|
||||
int nint = pblfr->GetFBFI()->Size() + pblfr->GetDBFI()->Size() +
|
||||
@@ -1102,6 +964,7 @@ ParSesquilinearForm::ParallelAssemble()
|
||||
return new ComplexHypreParMatrix(pblfr->ParallelAssemble(),
|
||||
pblfi->ParallelAssemble(),
|
||||
true, true, conv);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1111,45 +974,35 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
Vector &X, Vector &B,
|
||||
int ci)
|
||||
{
|
||||
ParFiniteElementSpace *pfes = pblfr->ParFESpace();
|
||||
const int vsize = pfes->GetVSize();
|
||||
ParFiniteElementSpace * pfes = pblfr->ParFESpace();
|
||||
int vsize = pfes->GetVSize();
|
||||
|
||||
// Allocate temporary vector
|
||||
Vector b_0;
|
||||
b_0.UseDevice(true);
|
||||
b_0.SetSize(vsize);
|
||||
b_0 = 0.0;
|
||||
// Allocate temporary vectors
|
||||
Vector b_0(vsize); b_0 = 0.0;
|
||||
|
||||
// Extract the real and imaginary parts of the input vectors
|
||||
MFEM_ASSERT(x.Size() == 2 * vsize, "Input GridFunction of incorrect size!");
|
||||
x.Read();
|
||||
Vector x_r; x_r.MakeRef(x, 0, vsize);
|
||||
Vector x_i; x_i.MakeRef(x, vsize, vsize);
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
MFEM_ASSERT(b.Size() == 2 * vsize, "Input LinearForm of incorrect size!");
|
||||
b.Read();
|
||||
Vector b_r; b_r.MakeRef(b, 0, vsize);
|
||||
Vector b_i; b_i.MakeRef(b, vsize, vsize);
|
||||
Vector b_r(b.GetData(), vsize);
|
||||
Vector b_i(&(b.GetData())[vsize], vsize);
|
||||
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC) { b_i *= -1.0; }
|
||||
|
||||
const int tvsize = pfes->GetTrueVSize();
|
||||
int tvsize = pfes->GetTrueVSize();
|
||||
|
||||
OperatorHandle A_r, A_i;
|
||||
|
||||
X.UseDevice(true);
|
||||
X.SetSize(2 * tvsize);
|
||||
X = 0.0;
|
||||
|
||||
B.UseDevice(true);
|
||||
B.SetSize(2 * tvsize);
|
||||
B = 0.0;
|
||||
|
||||
Vector X_r; X_r.MakeRef(X, 0, tvsize);
|
||||
Vector X_i; X_i.MakeRef(X, tvsize, tvsize);
|
||||
Vector B_r; B_r.MakeRef(B, 0, tvsize);
|
||||
Vector B_i; B_i.MakeRef(B, tvsize, tvsize);
|
||||
|
||||
Vector X_0, B_0;
|
||||
Vector X_0(tvsize), B_0(tvsize);
|
||||
Vector X_r(X.GetData(),tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
Vector B_r(B.GetData(), tvsize);
|
||||
Vector B_i(&(B.GetData())[tvsize], tvsize);
|
||||
|
||||
if (RealInteg())
|
||||
{
|
||||
@@ -1189,29 +1042,24 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
|
||||
if (RealInteg() && ImagInteg())
|
||||
{
|
||||
int n = ess_tdof_list.Size();
|
||||
// Modify RHS to conform with standard essential BC treatment
|
||||
const int n = ess_tdof_list.Size();
|
||||
auto d_B_r = B_r.Write();
|
||||
auto d_B_i = B_i.Write();
|
||||
auto d_X_r = X_r.Read();
|
||||
auto d_X_i = X_i.Read();
|
||||
auto d_idx = ess_tdof_list.Read();
|
||||
MFEM_FORALL(i, n,
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
const int j = d_idx[i];
|
||||
d_B_r[j] = d_X_r[j];
|
||||
d_B_i[j] = d_X_i[j];
|
||||
});
|
||||
int j=ess_tdof_list[k];
|
||||
B_r(j) = X_r(j);
|
||||
B_i(j) = X_i(j);
|
||||
}
|
||||
// Modify offdiagonal blocks (imaginary parts of the matrix) to conform
|
||||
// with standard essential BC treatment
|
||||
if (A_i.Type() == Operator::Hypre_ParCSR)
|
||||
if ( A_i.Type() == Operator::Hypre_ParCSR )
|
||||
{
|
||||
HypreParMatrix * Ah;
|
||||
A_i.Get(Ah);
|
||||
hypre_ParCSRMatrix *Aih = *Ah;
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
const int j = ess_tdof_list[k];
|
||||
int j = ess_tdof_list[k];
|
||||
Aih->diag->data[Aih->diag->i[j]] = 0.0;
|
||||
}
|
||||
}
|
||||
@@ -1228,16 +1076,6 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
b_i *= -1.0;
|
||||
}
|
||||
|
||||
x_r.SyncAliasMemory(x);
|
||||
x_i.SyncAliasMemory(x);
|
||||
b_r.SyncAliasMemory(b);
|
||||
b_i.SyncAliasMemory(b);
|
||||
|
||||
X_r.SyncAliasMemory(X);
|
||||
X_i.SyncAliasMemory(X);
|
||||
B_r.SyncAliasMemory(B);
|
||||
B_i.SyncAliasMemory(B);
|
||||
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
if ( A_r.Type() == Operator::Hypre_ParCSR ||
|
||||
@@ -1337,27 +1175,22 @@ void
|
||||
ParSesquilinearForm::RecoverFEMSolution(const Vector &X, const Vector &b,
|
||||
Vector &x)
|
||||
{
|
||||
ParFiniteElementSpace *pfes = pblfr->ParFESpace();
|
||||
ParFiniteElementSpace * pfes = pblfr->ParFESpace();
|
||||
|
||||
const Operator &P = *pfes->GetProlongationMatrix();
|
||||
|
||||
const int vsize = pfes->GetVSize();
|
||||
const int tvsize = X.Size() / 2;
|
||||
int vsize = pfes->GetVSize();
|
||||
int tvsize = X.Size() / 2;
|
||||
|
||||
X.Read();
|
||||
Vector X_r; X_r.MakeRef(const_cast<Vector&>(X), 0, tvsize);
|
||||
Vector X_i; X_i.MakeRef(const_cast<Vector&>(X), tvsize, tvsize);
|
||||
Vector X_r(X.GetData(), tvsize);
|
||||
Vector X_i(&(X.GetData())[tvsize], tvsize);
|
||||
|
||||
x.Write();
|
||||
Vector x_r; x_r.MakeRef(x, 0, vsize);
|
||||
Vector x_i; x_i.MakeRef(x, vsize, vsize);
|
||||
Vector x_r(x.GetData(), vsize);
|
||||
Vector x_i(&(x.GetData())[vsize], vsize);
|
||||
|
||||
// Apply conforming prolongation
|
||||
P.Mult(X_r, x_r);
|
||||
P.Mult(X_i, x_i);
|
||||
|
||||
x_r.SyncAliasMemory(x);
|
||||
x_i.SyncAliasMemory(x);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+11
-44
@@ -38,8 +38,8 @@ protected:
|
||||
void Destroy() { delete gfr; delete gfi; }
|
||||
|
||||
public:
|
||||
/** @brief Construct a ComplexGridFunction associated with the
|
||||
FiniteElementSpace @a *f. */
|
||||
/* @brief Construct a ComplexGridFunction associated with the
|
||||
FiniteElementSpace @a *f. */
|
||||
ComplexGridFunction(FiniteElementSpace *f);
|
||||
|
||||
void Update();
|
||||
@@ -71,14 +71,6 @@ public:
|
||||
const GridFunction & real() const { return *gfr; }
|
||||
const GridFunction & imag() const { return *gfi; }
|
||||
|
||||
/// Update the memory location of the real and imaginary GridFunction @a gfr
|
||||
/// and @a gfi to match the ComplexGridFunction.
|
||||
void Sync() { gfr->SyncMemory(*this); gfi->SyncMemory(*this); }
|
||||
|
||||
/// Update the alias memory location of the real and imaginary GridFunction
|
||||
/// @a gfr and @a gfi to match the ComplexGridFunction.
|
||||
void SyncAlias() { gfr->SyncAliasMemory(*this); gfi->SyncAliasMemory(*this); }
|
||||
|
||||
/// Destroys the grid function.
|
||||
virtual ~ComplexGridFunction() { Destroy(); }
|
||||
|
||||
@@ -107,8 +99,8 @@ public:
|
||||
ComplexOperator::Convention
|
||||
convention = ComplexOperator::HERMITIAN);
|
||||
|
||||
/** @brief Create a ComplexLinearForm on the FiniteElementSpace @a fes, using
|
||||
the same integrators as the LinearForms @a lf_r (real) and @a lf_i (imag).
|
||||
/** @brief Create a ComplexLinearForm on the FiniteElementSpace @a f, using
|
||||
the same integrators as the LinearForms @a lfr (real) and @a lfi (imag) .
|
||||
|
||||
The pointer @a fes is not owned by the newly constructed object.
|
||||
|
||||
@@ -165,14 +157,6 @@ public:
|
||||
const LinearForm & real() const { return *lfr; }
|
||||
const LinearForm & imag() const { return *lfi; }
|
||||
|
||||
/// Update the memory location of the real and imaginary LinearForm @a lfr
|
||||
/// and @a lfi to match the ComplexLinearForm.
|
||||
void Sync() { lfr->SyncMemory(*this); lfi->SyncMemory(*this); }
|
||||
|
||||
/// Update the alias memory location of the real and imaginary LinearForm @a
|
||||
/// lfr and @a lfi to match the ComplexLinearForm.
|
||||
void SyncAlias() { lfr->SyncAliasMemory(*this); lfi->SyncAliasMemory(*this); }
|
||||
|
||||
void Update();
|
||||
void Update(FiniteElementSpace *f);
|
||||
|
||||
@@ -211,8 +195,8 @@ private:
|
||||
BilinearForm *blfr;
|
||||
BilinearForm *blfi;
|
||||
|
||||
/* These methods check if the real/imag parts of the sesquilinear form are
|
||||
not empty */
|
||||
/* These methods check if the real/imag parts of the sesqulinear form are not
|
||||
empty */
|
||||
bool RealInteg();
|
||||
bool ImagInteg();
|
||||
|
||||
@@ -220,7 +204,7 @@ public:
|
||||
SesquilinearForm(FiniteElementSpace *fes,
|
||||
ComplexOperator::Convention
|
||||
convention = ComplexOperator::HERMITIAN);
|
||||
/** @brief Create a SesquilinearForm on the FiniteElementSpace @a fes, using
|
||||
/** @brief Create a SesquilinearForm on the FiniteElementSpace @a f, using
|
||||
the same integrators as the BilinearForms @a bfr and @a bfi .
|
||||
|
||||
The pointer @a fes is not owned by the newly constructed object.
|
||||
@@ -339,8 +323,8 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
/** @brief Construct a ParComplexGridFunction associated with the
|
||||
ParFiniteElementSpace @a *pf. */
|
||||
/* @brief Construct a ParComplexGridFunction associated with the
|
||||
ParFiniteElementSpace @a *f. */
|
||||
ParComplexGridFunction(ParFiniteElementSpace *pf);
|
||||
|
||||
void Update();
|
||||
@@ -381,15 +365,6 @@ public:
|
||||
const ParGridFunction & real() const { return *pgfr; }
|
||||
const ParGridFunction & imag() const { return *pgfi; }
|
||||
|
||||
/// Update the memory location of the real and imaginary ParGridFunction @a
|
||||
/// pgfr and @a pgfi to match the ParComplexGridFunction.
|
||||
void Sync() { pgfr->SyncMemory(*this); pgfi->SyncMemory(*this); }
|
||||
|
||||
/// Update the alias memory location of the real and imaginary
|
||||
/// ParGridFunction @a pgfr and @a pgfi to match the ParComplexGridFunction.
|
||||
void SyncAlias() { pgfr->SyncAliasMemory(*this); pgfi->SyncAliasMemory(*this); }
|
||||
|
||||
|
||||
virtual double ComputeL2Error(Coefficient &exsolr, Coefficient &exsoli,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
@@ -441,8 +416,8 @@ public:
|
||||
convention = ComplexOperator::HERMITIAN);
|
||||
|
||||
/** @brief Create a ParComplexLinearForm on the ParFiniteElementSpace @a pf,
|
||||
using the same integrators as the LinearForms @a plf_r (real) and
|
||||
@a plf_i (imag).
|
||||
using the same integrators as the LinearForms @a plfr (real) and @a plfi
|
||||
(imag) .
|
||||
|
||||
The pointer @a fes is not owned by the newly constructed object.
|
||||
|
||||
@@ -500,14 +475,6 @@ public:
|
||||
const ParLinearForm & real() const { return *plfr; }
|
||||
const ParLinearForm & imag() const { return *plfi; }
|
||||
|
||||
/// Update the memory location of the real and imaginary ParLinearForm @a lfr
|
||||
/// and @a lfi to match the ParComplexLinearForm.
|
||||
void Sync() { plfr->SyncMemory(*this); plfi->SyncMemory(*this); }
|
||||
|
||||
/// Update the alias memory location of the real and imaginary ParLinearForm
|
||||
/// @a plfr and @a plfi to match the ParComplexLinearForm.
|
||||
void SyncAlias() { plfr->SyncAliasMemory(*this); plfi->SyncAliasMemory(*this); }
|
||||
|
||||
void Update(ParFiniteElementSpace *pf = NULL);
|
||||
|
||||
/// Assembles the linear form i.e. sums over all domain/bdr integrators.
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
#include "convergence.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
void ConvergenceStudy::Reset()
|
||||
{
|
||||
counter=0;
|
||||
dcounter=0;
|
||||
fcounter=0;
|
||||
cont_type=-1;
|
||||
print_flag=1;
|
||||
L2Errors.SetSize(0);
|
||||
L2Rates.SetSize(0);
|
||||
DErrors.SetSize(0);
|
||||
DRates.SetSize(0);
|
||||
EnErrors.SetSize(0);
|
||||
EnRates.SetSize(0);
|
||||
DGFaceErrors.SetSize(0);
|
||||
DGFaceRates.SetSize(0);
|
||||
ndofs.SetSize(0);
|
||||
}
|
||||
|
||||
double ConvergenceStudy::GetNorm(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *vector_u)
|
||||
{
|
||||
bool norm_set = false;
|
||||
double norm=0.0;
|
||||
int order = gf->FESpace()->GetOrder(0);
|
||||
int order_quad = std::max(2, 2*order+1);
|
||||
const IntegrationRule *irs[Geometry::NumGeom];
|
||||
for (int i=0; i < Geometry::NumGeom; ++i)
|
||||
{
|
||||
irs[i] = &(IntRules.Get(i, order_quad));
|
||||
}
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParGridFunction *pgf = dynamic_cast<ParGridFunction *>(gf);
|
||||
if (pgf)
|
||||
{
|
||||
ParMesh *pmesh = pgf->ParFESpace()->GetParMesh();
|
||||
if (scalar_u)
|
||||
{
|
||||
norm = ComputeGlobalLpNorm(2.0,*scalar_u,*pmesh,irs);
|
||||
}
|
||||
else if (vector_u)
|
||||
{
|
||||
norm = ComputeGlobalLpNorm(2.0,*vector_u,*pmesh,irs);
|
||||
}
|
||||
norm_set = true;
|
||||
}
|
||||
#endif
|
||||
if (!norm_set)
|
||||
{
|
||||
Mesh *mesh = gf->FESpace()->GetMesh();
|
||||
if (scalar_u)
|
||||
{
|
||||
norm = ComputeLpNorm(2.0,*scalar_u,*mesh,irs);
|
||||
}
|
||||
else if (vector_u)
|
||||
{
|
||||
norm = ComputeLpNorm(2.0,*vector_u,*mesh,irs);
|
||||
}
|
||||
}
|
||||
return norm;
|
||||
}
|
||||
|
||||
void ConvergenceStudy::AddL2Error(GridFunction *gf,
|
||||
Coefficient *scalar_u, VectorCoefficient *vector_u)
|
||||
{
|
||||
int tdofs=0;
|
||||
#ifdef MFEM_USE_MPI
|
||||
ParGridFunction *pgf = dynamic_cast<ParGridFunction *>(gf);
|
||||
if (pgf)
|
||||
{
|
||||
MPI_Comm comm = pgf->ParFESpace()->GetComm();
|
||||
int rank;
|
||||
MPI_Comm_rank(comm, &rank);
|
||||
print_flag = 0;
|
||||
if (rank==0) { print_flag = 1; }
|
||||
tdofs = pgf->ParFESpace()->GlobalTrueVSize();
|
||||
}
|
||||
#endif
|
||||
if (!tdofs) { tdofs = gf->FESpace()->GetTrueVSize(); }
|
||||
ndofs.Append(tdofs);
|
||||
double L2Err;
|
||||
if (scalar_u)
|
||||
{
|
||||
L2Err = gf->ComputeL2Error(*scalar_u);
|
||||
CoeffNorm = GetNorm(gf,scalar_u,nullptr);
|
||||
}
|
||||
else if (vector_u)
|
||||
{
|
||||
L2Err = gf->ComputeL2Error(*vector_u);
|
||||
CoeffNorm = GetNorm(gf,nullptr,vector_u);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Exact Solution Coefficient pointer is NULL");
|
||||
}
|
||||
L2Errors.Append(L2Err);
|
||||
// Compute the rate of convergence by:
|
||||
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
|
||||
double val = (counter) ? log(L2Errors[counter-1]/L2Err)/log(2.0) : 0.0;
|
||||
L2Rates.Append(val);
|
||||
counter++;
|
||||
}
|
||||
|
||||
void ConvergenceStudy::AddGf(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *grad,
|
||||
Coefficient *ell_coeff, double Nu)
|
||||
{
|
||||
cont_type = gf->FESpace()->FEColl()->GetContType();
|
||||
|
||||
MFEM_VERIFY((cont_type == mfem::FiniteElementCollection::CONTINUOUS) ||
|
||||
(cont_type == mfem::FiniteElementCollection::DISCONTINUOUS),
|
||||
"This constructor is intended for H1 or L2 Elements")
|
||||
|
||||
AddL2Error(gf,scalar_u, nullptr);
|
||||
|
||||
if (grad)
|
||||
{
|
||||
double GradErr = gf->ComputeGradError(grad);
|
||||
DErrors.Append(GradErr);
|
||||
double err = sqrt(L2Errors[counter-1]*L2Errors[counter-1]+GradErr*GradErr);
|
||||
EnErrors.Append(err);
|
||||
// Compute the rate of convergence by:
|
||||
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
|
||||
double val = (dcounter) ? log(DErrors[dcounter-1]/GradErr)/log(2.0) : 0.0;
|
||||
double eval = (dcounter) ? log(EnErrors[dcounter-1]/err)/log(2.0) : 0.0;
|
||||
DRates.Append(val);
|
||||
EnRates.Append(eval);
|
||||
CoeffDNorm = GetNorm(gf,nullptr,grad);
|
||||
dcounter++;
|
||||
MFEM_VERIFY(counter == dcounter,
|
||||
"Number of added solutions and derivatives do not match")
|
||||
}
|
||||
|
||||
if (cont_type == mfem::FiniteElementCollection::DISCONTINUOUS && ell_coeff)
|
||||
{
|
||||
double DGErr = gf->ComputeDGFaceJumpError(scalar_u,ell_coeff,Nu);
|
||||
DGFaceErrors.Append(DGErr);
|
||||
// Compute the rate of convergence by:
|
||||
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
|
||||
double val=(fcounter) ? log(DGFaceErrors[fcounter-1]/DGErr)/log(2.0):0.;
|
||||
DGFaceRates.Append(val);
|
||||
fcounter++;
|
||||
MFEM_VERIFY(fcounter == counter, "Number of added solutions mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
void ConvergenceStudy::AddGf(GridFunction *gf, VectorCoefficient *vector_u,
|
||||
VectorCoefficient *curl, Coefficient *div)
|
||||
{
|
||||
cont_type = gf->FESpace()->FEColl()->GetContType();
|
||||
|
||||
AddL2Error(gf,nullptr,vector_u);
|
||||
double DErr = 0.0;
|
||||
bool derivative = false;
|
||||
if (curl)
|
||||
{
|
||||
DErr = gf->ComputeCurlError(curl);
|
||||
CoeffDNorm = GetNorm(gf,nullptr,curl);
|
||||
derivative = true;
|
||||
}
|
||||
else if (div)
|
||||
{
|
||||
DErr = gf->ComputeDivError(div);
|
||||
// update coefficient norm
|
||||
CoeffDNorm = GetNorm(gf,div,nullptr);
|
||||
derivative = true;
|
||||
}
|
||||
if (derivative)
|
||||
{
|
||||
double err = sqrt(L2Errors[counter-1]*L2Errors[counter-1] + DErr*DErr);
|
||||
DErrors.Append(DErr);
|
||||
EnErrors.Append(err);
|
||||
// Compute the rate of convergence by:
|
||||
// rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
|
||||
double val = (dcounter) ? log(DErrors[dcounter-1]/DErr)/log(2.0) : 0.0;
|
||||
double eval = (dcounter) ? log(EnErrors[dcounter-1]/err)/log(2.0) : 0.0;
|
||||
DRates.Append(val);
|
||||
EnRates.Append(eval);
|
||||
dcounter++;
|
||||
MFEM_VERIFY(counter == dcounter,
|
||||
"Number of added solutions and derivatives do not match")
|
||||
}
|
||||
}
|
||||
|
||||
void ConvergenceStudy::Print(bool relative, std::ostream &out)
|
||||
{
|
||||
if (print_flag)
|
||||
{
|
||||
std::string title = (relative) ? "Relative " : "Absolute ";
|
||||
out << "\n";
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << std::setw(21) << title << "L2 Error " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13) << "Error ";
|
||||
out << std::setw(15) << "Rate " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::setprecision(4);
|
||||
double d = (relative) ? CoeffNorm : 1.0;
|
||||
for (int i =0; i<counter; i++)
|
||||
{
|
||||
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
|
||||
<< std::scientific << L2Errors[i]/d << std::setw(13)
|
||||
<< std::fixed << L2Rates[i] << "\n";
|
||||
}
|
||||
out << "\n";
|
||||
if (dcounter == counter)
|
||||
{
|
||||
std::string dname;
|
||||
switch (cont_type)
|
||||
{
|
||||
case 0: dname = "Grad"; break;
|
||||
case 1: dname = "Curl"; break;
|
||||
case 2: dname = "Div"; break;
|
||||
case 3: dname = "DG Grad"; break;
|
||||
default: break;
|
||||
}
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << std::setw(21) << title << dname << " Error " << "\n";
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << std::right<<std::setw(11)<< "DOFs "<< std::setw(13) << "Error";
|
||||
out << std::setw(15) << "Rate " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::setprecision(4);
|
||||
d = (relative) ? CoeffDNorm : 1.0;
|
||||
for (int i =0; i<dcounter; i++)
|
||||
{
|
||||
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
|
||||
<< std::scientific << DErrors[i]/d << std::setw(13)
|
||||
<< std::fixed << DRates[i] << "\n";
|
||||
}
|
||||
out << "\n";
|
||||
switch (cont_type)
|
||||
{
|
||||
case 0: dname = "H1"; break;
|
||||
case 1: dname = "H(Curl)"; break;
|
||||
case 2: dname = "H(Div)"; break;
|
||||
case 3: dname = "DG H1"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (dcounter)
|
||||
{
|
||||
d = (relative) ?
|
||||
sqrt(CoeffNorm*CoeffNorm + CoeffDNorm*CoeffDNorm):1.0;
|
||||
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << std::setw(21) << title << dname << " Error " << "\n";
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13);
|
||||
out << "Error ";
|
||||
out << std::setw(15) << "Rate " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::setprecision(4);
|
||||
for (int i =0; i<dcounter; i++)
|
||||
{
|
||||
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
|
||||
<< std::scientific << EnErrors[i]/d << std::setw(13)
|
||||
<< std::fixed << EnRates[i] << "\n";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
if (cont_type == 3 && fcounter)
|
||||
{
|
||||
out << " -------------------------------------------" << "\n";
|
||||
out << " DG Face Jump Error " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13);
|
||||
out << "Error ";
|
||||
out << std::setw(15) << "Rate " << "\n";
|
||||
out << " -------------------------------------------"
|
||||
<< "\n";
|
||||
out << std::setprecision(4);
|
||||
for (int i =0; i<fcounter; i++)
|
||||
{
|
||||
out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
|
||||
<< std::scientific << DGFaceErrors[i] << std::setw(13)
|
||||
<< std::fixed << DGFaceRates[i] << "\n";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,149 +0,0 @@
|
||||
// Copyright (c) 2010-2020, 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_CONVERGENCE
|
||||
#define MFEM_CONVERGENCE
|
||||
|
||||
#include "../linalg/linalg.hpp"
|
||||
#include "gridfunc.hpp"
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include "pgridfunc.hpp"
|
||||
#endif
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/** @brief Class to compute error and convergence rates.
|
||||
It supports H1, H(curl) (ND elements), H(div) (RT elements) and L2 (DG).
|
||||
|
||||
For "smooth enough" solutions the Galerkin error measured in the appropriate
|
||||
norm satisfies || u - u_h || ~ h^k
|
||||
|
||||
Here, k is called the asymptotic rate of convergence
|
||||
|
||||
For successive uniform h-refinements the rate can be estimated by
|
||||
k = log(||u - u_h|| / ||u - u_{h/2}||)/log(2)
|
||||
*/
|
||||
class ConvergenceStudy
|
||||
{
|
||||
private:
|
||||
// counters for solutions/derivatives
|
||||
int counter=0;
|
||||
int dcounter=0;
|
||||
int fcounter=0;
|
||||
|
||||
// space continuity type
|
||||
int cont_type=-1;
|
||||
|
||||
// printing flag for helpful for MPI calls
|
||||
int print_flag=1;
|
||||
|
||||
// exact solution and derivatives
|
||||
double CoeffNorm;
|
||||
double CoeffDNorm;
|
||||
|
||||
// Arrays to store error/rates
|
||||
Array<double> L2Errors, DGFaceErrors, DErrors, EnErrors;
|
||||
Array<double> L2Rates, DGFaceRates, DRates, EnRates;
|
||||
Array<int> ndofs;
|
||||
|
||||
void AddL2Error(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *vector_u);
|
||||
void AddGf(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *grad=nullptr,
|
||||
Coefficient *ell_coeff=nullptr, double Nu=1.0);
|
||||
void AddGf(GridFunction *gf, VectorCoefficient *vector_u,
|
||||
VectorCoefficient *curl, Coefficient *div);
|
||||
// returns the L2-norm of scalar_u or vector_u
|
||||
double GetNorm(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *vector_u);
|
||||
|
||||
public:
|
||||
|
||||
/// Clear any internal data
|
||||
void Reset();
|
||||
|
||||
/// Add L2 GridFunction, the exact solution and possibly its gradient and/or
|
||||
/// DG face jumps parameters
|
||||
void AddL2GridFunction(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *grad=nullptr,
|
||||
Coefficient *ell_coeff=nullptr, double Nu=1.0)
|
||||
{
|
||||
AddGf(gf, scalar_u, grad, ell_coeff, Nu);
|
||||
}
|
||||
|
||||
/// Add H1 GridFunction, the exact solution and possibly its gradient
|
||||
void AddH1GridFunction(GridFunction *gf, Coefficient *scalar_u,
|
||||
VectorCoefficient *grad=nullptr)
|
||||
{
|
||||
AddGf(gf, scalar_u, grad);
|
||||
}
|
||||
|
||||
/// Add H(curl) GridFunction, the exact solution and possibly its curl
|
||||
void AddHcurlGridFunction(GridFunction *gf, VectorCoefficient *vector_u,
|
||||
VectorCoefficient *curl=nullptr)
|
||||
{
|
||||
AddGf(gf, vector_u, curl, nullptr);
|
||||
}
|
||||
|
||||
/// Add H(div) GridFunction, the exact solution and possibly its div
|
||||
void AddHdivGridFunction(GridFunction *gf, VectorCoefficient *vector_u,
|
||||
Coefficient *div=nullptr)
|
||||
{
|
||||
AddGf(gf,vector_u, nullptr, div);
|
||||
}
|
||||
|
||||
/// Get the L2 error at step n
|
||||
double GetL2Error(int n)
|
||||
{
|
||||
MFEM_VERIFY( n <= counter,"Step out of bounds")
|
||||
return L2Errors[n];
|
||||
}
|
||||
|
||||
/// Get all L2 errors
|
||||
void GetL2Errors(Array<double> & L2Errors_)
|
||||
{
|
||||
L2Errors_ = L2Errors;
|
||||
}
|
||||
|
||||
/// Get the Grad/Curl/Div error at step n
|
||||
double GetDError(int n)
|
||||
{
|
||||
MFEM_VERIFY(n <= dcounter,"Step out of bounds")
|
||||
return DErrors[n];
|
||||
}
|
||||
|
||||
/// Get all Grad/Curl/Div errors
|
||||
void GetDErrors(Array<double> & DErrors_)
|
||||
{
|
||||
DErrors_ = DErrors;
|
||||
}
|
||||
|
||||
/// Get the DGFaceJumps error at step n
|
||||
double GetDGFaceJumpsError(int n)
|
||||
{
|
||||
MFEM_VERIFY(n<= fcounter,"Step out of bounds")
|
||||
return DGFaceErrors[n];
|
||||
}
|
||||
|
||||
/// Get all DGFaceJumps errors
|
||||
void GetDGFaceJumpsErrors(Array<double> & DGFaceErrors_)
|
||||
{
|
||||
DGFaceErrors_ = DGFaceErrors;
|
||||
}
|
||||
|
||||
/// Print rates and errors
|
||||
void Print(bool relative = false, std::ostream &out = mfem::out);
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_CONVERGENCE
|
||||
@@ -563,8 +563,6 @@ void VisItDataCollection::LoadVisItRootFile(const std::string& root_name)
|
||||
|
||||
void VisItDataCollection::LoadMesh()
|
||||
{
|
||||
// GetMeshFileName() uses 'serial', so we need to set it in advance.
|
||||
serial = (format == SERIAL_FORMAT);
|
||||
std::string mesh_fname = GetMeshFileName();
|
||||
named_ifgzstream file(mesh_fname);
|
||||
// TODO: in parallel, check for errors on all processors
|
||||
|
||||
+3
-17
@@ -77,9 +77,6 @@ public:
|
||||
|
||||
ElementTransformation();
|
||||
|
||||
/** @brief Force the reevaluation of the Jacobian in the next call. */
|
||||
void Reset() { EvalState = 0; }
|
||||
|
||||
/** @brief Set the integration point @a ip that weights and Jacobians will
|
||||
be evaluated at. */
|
||||
void SetIntPoint(const IntegrationPoint *ip)
|
||||
@@ -360,17 +357,9 @@ private:
|
||||
// Evaluate the Hessian of the transformation at the IntPoint and store it
|
||||
// in d2Fdx2.
|
||||
virtual const DenseMatrix &EvalHessian();
|
||||
|
||||
public:
|
||||
IsoparametricTransformation() : FElem(NULL) {}
|
||||
|
||||
/// Set the element that will be used to compute the transformations
|
||||
void SetFE(const FiniteElement *FE)
|
||||
{
|
||||
MFEM_ASSERT(FE != NULL, "Must provide a valid FiniteElement object!");
|
||||
EvalState = (FE != FElem) ? 0 : EvalState;
|
||||
FElem = FE; geom = FE->GetGeomType();
|
||||
}
|
||||
void SetFE(const FiniteElement *FE) { FElem = FE; geom = FE->GetGeomType(); }
|
||||
|
||||
/// Get the current element used to compute the transformations
|
||||
const FiniteElement* GetFE() const { return FElem; }
|
||||
@@ -385,15 +374,12 @@ public:
|
||||
the column-vector of all basis functions evaluated at \f$ \hat x \f$ .
|
||||
The columns of @a P represent the control points in physical space
|
||||
defining the transformation. */
|
||||
void SetPointMat(const DenseMatrix &pm) { PointMat = pm; EvalState = 0; }
|
||||
void SetPointMat(const DenseMatrix &pm) { PointMat = pm; }
|
||||
|
||||
/// Return the stored point matrix.
|
||||
const DenseMatrix &GetPointMat() const { return PointMat; }
|
||||
|
||||
/// @brief Write access to the stored point matrix. Use with caution.
|
||||
/** If the point matrix is altered using this member function the Reset
|
||||
function should also be called to force the reevaluation of the
|
||||
Jacobian, etc.. */
|
||||
/// Write access to the stored point matrix. Use with caution.
|
||||
DenseMatrix &GetPointMat() { return PointMat; }
|
||||
|
||||
/// Set the FiniteElement Geometry for the reference elements being used.
|
||||
|
||||
-203
@@ -139,12 +139,6 @@ void FiniteElement::Project (
|
||||
mfem_error ("FiniteElement::Project (...) (vector) is not overloaded !");
|
||||
}
|
||||
|
||||
void FiniteElement::ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{
|
||||
mfem_error ("FiniteElement::ProjectFromNodes() (vector) is not overloaded!");
|
||||
}
|
||||
|
||||
void FiniteElement::ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{
|
||||
@@ -931,23 +925,6 @@ void VectorFiniteElement::Project_RT(
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::Project_RT(
|
||||
const double *nk, const Array<int> &d2n,
|
||||
Vector &vc, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
const int sdim = Trans.GetSpaceDim();
|
||||
const bool square_J = (dim == sdim);
|
||||
|
||||
for (int k = 0; k < dof; k++)
|
||||
{
|
||||
Trans.SetIntPoint(&Nodes.IntPoint(k));
|
||||
// dof_k = nk^t adj(J) xk
|
||||
Vector vk(vc.GetData()+k*sdim, sdim);
|
||||
dofs(k) = Trans.AdjugateJacobian().InnerProduct(vk, nk + d2n[k]*dim);
|
||||
if (!square_J) { dofs(k) /= Trans.Weight(); }
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::ProjectMatrixCoefficient_RT(
|
||||
const double *nk, const Array<int> &d2n,
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
@@ -1124,19 +1101,6 @@ void VectorFiniteElement::Project_ND(
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::Project_ND(
|
||||
const double *tk, const Array<int> &d2t,
|
||||
Vector &vc, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
for (int k = 0; k < dof; k++)
|
||||
{
|
||||
Trans.SetIntPoint(&Nodes.IntPoint(k));
|
||||
Vector vk(vc.GetData()+k*dim, dim);
|
||||
// dof_k = xk^t J tk
|
||||
dofs(k) = Trans.Jacobian().InnerProduct(tk + d2t[k]*dim, vk);
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::ProjectMatrixCoefficient_ND(
|
||||
const double *tk, const Array<int> &d2t,
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
@@ -7070,95 +7034,6 @@ void Poly_1D::Basis::Eval(const double y, Vector &u, Vector &d) const
|
||||
}
|
||||
}
|
||||
|
||||
void Poly_1D::Basis::Eval(const double y, Vector &u, Vector &d,
|
||||
Vector &d2) const
|
||||
{
|
||||
MFEM_VERIFY(etype == Barycentric,
|
||||
"Basis::Eval with second order derivatives not implemented for"
|
||||
" etype = " << etype);
|
||||
switch (etype)
|
||||
{
|
||||
case ChangeOfBasis:
|
||||
{
|
||||
CalcBasis(Ai.Width() - 1, y, x, w);
|
||||
Ai.Mult(x, u);
|
||||
Ai.Mult(w, d);
|
||||
// set d2 (not implemented yet)
|
||||
break;
|
||||
}
|
||||
case Barycentric:
|
||||
{
|
||||
int i, k, p = x.Size() - 1;
|
||||
double l, lp, lp2, lk, sk, si, sk2;
|
||||
|
||||
if (p == 0)
|
||||
{
|
||||
u(0) = 1.0;
|
||||
d(0) = 0.0;
|
||||
d2(0) = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
lk = 1.0;
|
||||
for (k = 0; k < p; k++)
|
||||
{
|
||||
if (y >= (x(k) + x(k+1))/2)
|
||||
{
|
||||
lk *= y - x(k);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = k+1; i <= p; i++)
|
||||
{
|
||||
lk *= y - x(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
l = lk * (y - x(k));
|
||||
|
||||
sk = 0.0;
|
||||
sk2 = 0.0;
|
||||
for (i = 0; i < k; i++)
|
||||
{
|
||||
si = 1.0/(y - x(i));
|
||||
sk += si;
|
||||
sk2 -= si * si;
|
||||
u(i) = l * si * w(i);
|
||||
}
|
||||
u(k) = lk * w(k);
|
||||
for (i++; i <= p; i++)
|
||||
{
|
||||
si = 1.0/(y - x(i));
|
||||
sk += si;
|
||||
sk2 -= si * si;
|
||||
u(i) = l * si * w(i);
|
||||
}
|
||||
lp = l * sk + lk;
|
||||
lp2 = lp * sk + l * sk2 + sk * lk;
|
||||
|
||||
for (i = 0; i < k; i++)
|
||||
{
|
||||
d(i) = (lp * w(i) - u(i))/(y - x(i));
|
||||
d2(i) = (lp2 * w(i) - 2 * d(i))/(y - x(i));
|
||||
}
|
||||
d(k) = sk * u(k);
|
||||
d2(k) = sk2 * u(k) + sk * d(k);
|
||||
for (i++; i <= p; i++)
|
||||
{
|
||||
d(i) = (lp * w(i) - u(i))/(y - x(i));
|
||||
d2(i) = (lp2 * w(i) - 2 * d(i))/(y - x(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Positive:
|
||||
CalcBernstein(x.Size() - 1, y, u, d);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
const int *Poly_1D::Binom(const int p)
|
||||
{
|
||||
if (binom.NumCols() <= p)
|
||||
@@ -7714,7 +7589,6 @@ H1_SegmentElement::H1_SegmentElement(const int p, const int btype)
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
shape_x.SetSize(p+1);
|
||||
dshape_x.SetSize(p+1);
|
||||
d2shape_x.SetSize(p+1);
|
||||
#endif
|
||||
|
||||
Nodes.IntPoint(0).x = cp[0];
|
||||
@@ -7763,25 +7637,6 @@ void H1_SegmentElement::CalcDShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
void H1_SegmentElement::CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p+1), dshape_x(p+1), d2shape_x(p+1);
|
||||
#endif
|
||||
|
||||
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
|
||||
|
||||
Hessian(0,0) = d2shape_x(0);
|
||||
Hessian(1,0) = d2shape_x(p);
|
||||
for (int i = 1; i < p; i++)
|
||||
{
|
||||
Hessian(i+1,0) = d2shape_x(i);
|
||||
}
|
||||
}
|
||||
|
||||
void H1_SegmentElement::ProjectDelta(int vertex, Vector &dofs) const
|
||||
{
|
||||
const int p = order;
|
||||
@@ -7822,8 +7677,6 @@ H1_QuadrilateralElement::H1_QuadrilateralElement(const int p, const int btype)
|
||||
shape_y.SetSize(p1);
|
||||
dshape_x.SetSize(p1);
|
||||
dshape_y.SetSize(p1);
|
||||
d2shape_x.SetSize(p1);
|
||||
d2shape_y.SetSize(p1);
|
||||
#endif
|
||||
|
||||
int o = 0;
|
||||
@@ -7877,30 +7730,6 @@ void H1_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
void H1_QuadrilateralElement::CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1),
|
||||
d2shape_x(p+1), d2shape_y(p+1);
|
||||
#endif
|
||||
|
||||
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
|
||||
basis1d.Eval(ip.y, shape_y, dshape_y, d2shape_y);
|
||||
|
||||
for (int o = 0, j = 0; j <= p; j++)
|
||||
{
|
||||
for (int i = 0; i <= p; i++)
|
||||
{
|
||||
Hessian(dof_map[o],0) = d2shape_x(i)* shape_y(j);
|
||||
Hessian(dof_map[o],1) = dshape_x(i)* dshape_y(j);
|
||||
Hessian(dof_map[o],2) = shape_x(i)*d2shape_y(j); o++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void H1_QuadrilateralElement::ProjectDelta(int vertex, Vector &dofs) const
|
||||
{
|
||||
const int p = order;
|
||||
@@ -7964,9 +7793,6 @@ H1_HexahedronElement::H1_HexahedronElement(const int p, const int btype)
|
||||
dshape_x.SetSize(p1);
|
||||
dshape_y.SetSize(p1);
|
||||
dshape_z.SetSize(p1);
|
||||
d2shape_x.SetSize(p1);
|
||||
d2shape_y.SetSize(p1);
|
||||
d2shape_z.SetSize(p1);
|
||||
#endif
|
||||
|
||||
int o = 0;
|
||||
@@ -8023,35 +7849,6 @@ void H1_HexahedronElement::CalcDShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
void H1_HexahedronElement::CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p+1), shape_y(p+1), shape_z(p+1);
|
||||
Vector dshape_x(p+1), dshape_y(p+1), dshape_z(p+1);
|
||||
Vector d2shape_x(p+1), d2shape_y(p+1), ds2hape_z(p+1);
|
||||
#endif
|
||||
|
||||
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
|
||||
basis1d.Eval(ip.y, shape_y, dshape_y, d2shape_y);
|
||||
basis1d.Eval(ip.z, shape_z, dshape_z, d2shape_z);
|
||||
|
||||
for (int o = 0, k = 0; k <= p; k++)
|
||||
for (int j = 0; j <= p; j++)
|
||||
for (int i = 0; i <= p; i++)
|
||||
{
|
||||
Hessian(dof_map[o],0) = d2shape_x(i)* shape_y(j)* shape_z(k);
|
||||
Hessian(dof_map[o],1) = dshape_x(i)* dshape_y(j)* shape_z(k);
|
||||
Hessian(dof_map[o],2) = dshape_x(i)* shape_y(j)* dshape_z(k);
|
||||
Hessian(dof_map[o],3) = shape_x(i)*d2shape_y(j)* shape_z(k);
|
||||
Hessian(dof_map[o],4) = shape_x(i)* dshape_y(j)* dshape_z(k);
|
||||
Hessian(dof_map[o],5) = shape_x(i)* shape_y(j)*d2shape_z(k);
|
||||
o++;
|
||||
}
|
||||
}
|
||||
|
||||
void H1_HexahedronElement::ProjectDelta(int vertex, Vector &dofs) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
+10
-60
@@ -446,7 +446,7 @@ public:
|
||||
/** 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.*/
|
||||
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;
|
||||
|
||||
@@ -504,21 +504,14 @@ public:
|
||||
/** @brief Given a coefficient and a transformation, compute its projection
|
||||
(approximation) in the local finite dimensional space in terms
|
||||
of the degrees of freedom. */
|
||||
virtual void Project(Coefficient &coeff,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
virtual void Project (Coefficient &coeff,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
/** @brief Given a vector coefficient and a transformation, compute its
|
||||
projection (approximation) in the local finite dimensional space
|
||||
in terms of the degrees of freedom. (VectorFiniteElements) */
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
/** @brief Given a vector of values at the finite element nodes and a
|
||||
transformation, compute its projection (approximation) in the local
|
||||
finite dimensional space in terms of the degrees of freedom. Valid for
|
||||
VectorFiniteElements. */
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
/** @brief Given a matrix coefficient and a transformation, compute an
|
||||
approximation ("projection") in the local finite dimensional space in
|
||||
@@ -804,12 +797,7 @@ protected:
|
||||
VectorCoefficient &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const;
|
||||
|
||||
/// Projects the vector of values given at FE nodes to RT space
|
||||
void Project_RT(const double *nk, const Array<int> &d2n,
|
||||
Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const;
|
||||
|
||||
/// Project the rows of the matrix coefficient in an RT space
|
||||
// project the rows of the matrix coefficient in an RT space
|
||||
void ProjectMatrixCoefficient_RT(
|
||||
const double *nk, const Array<int> &d2n,
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
|
||||
@@ -837,12 +825,7 @@ protected:
|
||||
VectorCoefficient &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const;
|
||||
|
||||
/// Projects the vector of values given at FE nodes to ND space
|
||||
void Project_ND(const double *tk, const Array<int> &d2t,
|
||||
Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const;
|
||||
|
||||
/// Project the rows of the matrix coefficient in an ND space
|
||||
/// project the rows of the matrix coefficient in an ND space
|
||||
void ProjectMatrixCoefficient_ND(
|
||||
const double *tk, const Array<int> &d2t,
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
|
||||
@@ -1867,7 +1850,6 @@ public:
|
||||
Basis(const int p, const double *nodes, EvalType etype = Barycentric);
|
||||
void Eval(const double x, Vector &u) const;
|
||||
void Eval(const double x, Vector &u, Vector &d) const;
|
||||
void Eval(const double x, Vector &u, Vector &d, Vector &d2) const;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -2118,7 +2100,7 @@ class H1_SegmentElement : public NodalTensorFiniteElement
|
||||
{
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, dshape_x, d2shape_x;
|
||||
mutable Vector shape_x, dshape_x;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -2127,8 +2109,6 @@ public:
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
};
|
||||
|
||||
@@ -2138,7 +2118,7 @@ class H1_QuadrilateralElement : public NodalTensorFiniteElement
|
||||
{
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
|
||||
mutable Vector shape_x, shape_y, dshape_x, dshape_y;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -2148,8 +2128,6 @@ public:
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
};
|
||||
|
||||
@@ -2159,8 +2137,7 @@ class H1_HexahedronElement : public NodalTensorFiniteElement
|
||||
{
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z,
|
||||
d2shape_x, d2shape_y, d2shape_z;
|
||||
mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -2169,8 +2146,6 @@ public:
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
};
|
||||
|
||||
@@ -2706,9 +2681,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
|
||||
@@ -2767,9 +2739,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
|
||||
@@ -2821,9 +2790,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
|
||||
@@ -2881,9 +2847,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
|
||||
@@ -2943,10 +2906,6 @@ public:
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
|
||||
@@ -3006,9 +2965,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
|
||||
@@ -3060,9 +3016,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
|
||||
@@ -3119,9 +3072,6 @@ public:
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "eltrans.hpp"
|
||||
#include "coefficient.hpp"
|
||||
#include "complex_fem.hpp"
|
||||
#include "convergence.hpp"
|
||||
#include "lininteg.hpp"
|
||||
#include "nonlininteg.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
|
||||
+6
-9
@@ -440,7 +440,6 @@ void FiniteElementSpace::MarkerToList(const Array<int> &marker,
|
||||
if (marker[i]) { num_marked++; }
|
||||
}
|
||||
list.SetSize(0);
|
||||
list.HostWrite();
|
||||
list.Reserve(num_marked);
|
||||
for (int i = 0; i < marker.Size(); i++)
|
||||
{
|
||||
@@ -452,9 +451,7 @@ void FiniteElementSpace::MarkerToList(const Array<int> &marker,
|
||||
void FiniteElementSpace::ListToMarker(const Array<int> &list, int marker_size,
|
||||
Array<int> &marker, int mark_val)
|
||||
{
|
||||
list.HostRead(); // make sure we can read the array on host
|
||||
marker.SetSize(marker_size);
|
||||
marker.HostWrite();
|
||||
marker = 0;
|
||||
for (int i = 0; i < list.Size(); i++)
|
||||
{
|
||||
@@ -947,7 +944,7 @@ const Operator *FiniteElementSpace::GetFaceRestriction(
|
||||
}
|
||||
|
||||
const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
|
||||
const IntegrationRule &ir) const
|
||||
const IntegrationRule &ir, const DofToQuad::Mode mode) const
|
||||
{
|
||||
for (int i = 0; i < E2Q_array.Size(); i++)
|
||||
{
|
||||
@@ -955,13 +952,13 @@ const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
|
||||
if (qi->IntRule == &ir) { return qi; }
|
||||
}
|
||||
|
||||
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, ir);
|
||||
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, ir, mode);
|
||||
E2Q_array.Append(qi);
|
||||
return qi;
|
||||
}
|
||||
|
||||
const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
|
||||
const QuadratureSpace &qs) const
|
||||
const QuadratureSpace &qs, const DofToQuad::Mode mode) const
|
||||
{
|
||||
for (int i = 0; i < E2Q_array.Size(); i++)
|
||||
{
|
||||
@@ -969,7 +966,7 @@ const QuadratureInterpolator *FiniteElementSpace::GetQuadratureInterpolator(
|
||||
if (qi->qspace == &qs) { return qi; }
|
||||
}
|
||||
|
||||
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, qs);
|
||||
QuadratureInterpolator *qi = new QuadratureInterpolator(*this, qs, mode);
|
||||
E2Q_array.Append(qi);
|
||||
return qi;
|
||||
}
|
||||
@@ -986,8 +983,8 @@ const FaceQuadratureInterpolator
|
||||
if (qi->IntRule == &ir) { return qi; }
|
||||
}
|
||||
|
||||
FaceQuadratureInterpolator *qi = new FaceQuadratureInterpolator(*this, ir,
|
||||
type);
|
||||
FaceQuadratureInterpolator *qi =
|
||||
new FaceQuadratureInterpolator(*this, ir, type);
|
||||
E2IFQ_array.Append(qi);
|
||||
return qi;
|
||||
}
|
||||
|
||||
+2
-2
@@ -367,7 +367,7 @@ public:
|
||||
All elements will use the same IntegrationRule, @a ir as the target
|
||||
quadrature points. */
|
||||
const QuadratureInterpolator *GetQuadratureInterpolator(
|
||||
const IntegrationRule &ir) const;
|
||||
const IntegrationRule &ir, const DofToQuad::Mode = DofToQuad::FULL) const;
|
||||
|
||||
/** @brief Return a QuadratureInterpolator that interpolates E-vectors to
|
||||
quadrature point values and/or derivatives (Q-vectors). */
|
||||
@@ -378,7 +378,7 @@ public:
|
||||
The target quadrature points in the elements are described by the given
|
||||
QuadratureSpace, @a qs. */
|
||||
const QuadratureInterpolator *GetQuadratureInterpolator(
|
||||
const QuadratureSpace &qs) const;
|
||||
const QuadratureSpace &qs, const DofToQuad::Mode = DofToQuad::FULL) const;
|
||||
|
||||
/** @brief Return a FaceQuadratureInterpolator that interpolates E-vectors to
|
||||
quadrature point values and/or derivatives (Q-vectors). */
|
||||
|
||||
+126
-247
@@ -199,7 +199,8 @@ void GridFunction::MakeRef(FiniteElementSpace *f, Vector &v, int v_offset)
|
||||
if (f != fes) { Destroy(); }
|
||||
fes = f;
|
||||
v.UseDevice(true);
|
||||
this->Vector::MakeRef(v, v_offset, fes->GetVSize());
|
||||
NewMemoryAndSize(Memory<double>(v.GetMemory(), v_offset, fes->GetVSize()),
|
||||
fes->GetVSize(), true);
|
||||
sequence = fes->GetSequence();
|
||||
}
|
||||
|
||||
@@ -1833,19 +1834,6 @@ void GridFunction::ImposeBounds(int i, const Vector &weights,
|
||||
ImposeBounds(i, weights, minv, maxv);
|
||||
}
|
||||
|
||||
void GridFunction::RestrictConforming()
|
||||
{
|
||||
const SparseMatrix *R = fes->GetRestrictionMatrix();
|
||||
const Operator *P = fes->GetProlongationMatrix();
|
||||
|
||||
if (P && R)
|
||||
{
|
||||
Vector tmp(R->Height());
|
||||
R->Mult(*this, tmp);
|
||||
P->Mult(tmp, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void GridFunction::GetNodalValues(Vector &nval, int vdim) const
|
||||
{
|
||||
int i, j;
|
||||
@@ -2614,7 +2602,11 @@ double GridFunction::ComputeL2Error(
|
||||
}
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
if (error < 0.0)
|
||||
{
|
||||
return -sqrt(-error);
|
||||
}
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeL2Error(
|
||||
@@ -2655,199 +2647,94 @@ double GridFunction::ComputeL2Error(
|
||||
}
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeGradError(VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
double error = 0.0;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *Tr;
|
||||
Array<int> dofs;
|
||||
Vector grad;
|
||||
int intorder;
|
||||
int dim = fes->GetMesh()->SpaceDimension();
|
||||
Vector vec(dim);
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
if (error < 0.0)
|
||||
{
|
||||
fe = fes->GetFE(i);
|
||||
Tr = fes->GetElementTransformation(i);
|
||||
intorder = 2*fe->GetOrder() + 3; // <--------
|
||||
const IntegrationRule *ir;
|
||||
if (irs)
|
||||
{
|
||||
ir = irs[fe->GetGeomType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
fes->GetElementDofs(i, dofs);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
Tr->SetIntPoint(&ip);
|
||||
GetGradient(*Tr,grad);
|
||||
exgrad->Eval(vec,*Tr,ip);
|
||||
vec-=grad;
|
||||
error += ip.weight * Tr->Weight() * (vec * vec);
|
||||
}
|
||||
return -sqrt(-error);
|
||||
}
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeCurlError(VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[]) const
|
||||
double GridFunction::ComputeH1Error(
|
||||
Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
Coefficient *ell_coeff, double Nu, int norm_type) const
|
||||
{
|
||||
double error = 0.0;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *Tr;
|
||||
Array<int> dofs;
|
||||
Vector curl;
|
||||
int intorder;
|
||||
int dim = fes->GetMesh()->SpaceDimension();
|
||||
int n = (dim == 3) ? dim : 1;
|
||||
Vector vec(n);
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
fe = fes->GetFE(i);
|
||||
Tr = fes->GetElementTransformation(i);
|
||||
intorder = 2*fe->GetOrder() + 3;
|
||||
const IntegrationRule *ir;
|
||||
if (irs)
|
||||
{
|
||||
ir = irs[fe->GetGeomType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
fes->GetElementDofs(i, dofs);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
Tr->SetIntPoint(&ip);
|
||||
GetCurl(*Tr,curl);
|
||||
excurl->Eval(vec,*Tr,ip);
|
||||
vec-=curl;
|
||||
error += ip.weight * Tr->Weight() * ( vec * vec );
|
||||
}
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeDivError(
|
||||
Coefficient *exdiv, const IntegrationRule *irs[]) const
|
||||
{
|
||||
double error = 0.0, a;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *Tr;
|
||||
Array<int> dofs;
|
||||
int intorder;
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
fe = fes->GetFE(i);
|
||||
Tr = fes->GetElementTransformation(i);
|
||||
intorder = 2*fe->GetOrder() + 3;
|
||||
const IntegrationRule *ir;
|
||||
if (irs)
|
||||
{
|
||||
ir = irs[fe->GetGeomType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
fes->GetElementDofs(i, dofs);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
Tr->SetIntPoint (&ip);
|
||||
a = GetDivergence(*Tr) - exdiv->Eval(*Tr, ip);
|
||||
error += ip.weight * Tr->Weight() * a * a;
|
||||
}
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
Coefficient *ell_coeff, double Nu,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
int fdof, dim, intorder, k;
|
||||
// assuming vdim is 1
|
||||
int i, fdof, dim, intorder, j, k;
|
||||
Mesh *mesh;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *transf;
|
||||
FaceElementTransformations *face_elem_transf;
|
||||
Vector shape, el_dofs, err_val, ell_coeff_val;
|
||||
Vector e_grad, a_grad, shape, el_dofs, err_val, ell_coeff_val;
|
||||
DenseMatrix dshape, dshapet, Jinv;
|
||||
Array<int> vdofs;
|
||||
IntegrationPoint eip;
|
||||
double error = 0.0;
|
||||
|
||||
mesh = fes->GetMesh();
|
||||
dim = mesh->Dimension();
|
||||
e_grad.SetSize(dim);
|
||||
a_grad.SetSize(dim);
|
||||
Jinv.SetSize(dim);
|
||||
|
||||
for (int i = 0; i < mesh->GetNumFaces(); i++)
|
||||
{
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 5);
|
||||
int i1 = face_elem_transf->Elem1No;
|
||||
int i2 = face_elem_transf->Elem2No;
|
||||
intorder = fes->GetFE(i1)->GetOrder();
|
||||
if (i2 >= 0)
|
||||
if ( (k = fes->GetFE(i2)->GetOrder()) > intorder )
|
||||
{
|
||||
intorder = k;
|
||||
}
|
||||
intorder = 2 * intorder; // <-------------
|
||||
const IntegrationRule *ir;
|
||||
if (irs)
|
||||
if (norm_type & 1)
|
||||
for (i = 0; i < mesh->GetNE(); i++)
|
||||
{
|
||||
ir = irs[face_elem_transf->GetGeometryType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(face_elem_transf->GetGeometryType(), intorder));
|
||||
}
|
||||
err_val.SetSize(ir->GetNPoints());
|
||||
ell_coeff_val.SetSize(ir->GetNPoints());
|
||||
// side 1
|
||||
transf = face_elem_transf->Elem1;
|
||||
fe = fes->GetFE(i1);
|
||||
fdof = fe->GetDof();
|
||||
fes->GetElementVDofs(i1, vdofs);
|
||||
shape.SetSize(fdof);
|
||||
el_dofs.SetSize(fdof);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = (*this)(vdofs[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1-vdofs[k]);
|
||||
}
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
face_elem_transf->Loc1.Transform(ir->IntPoint(j), eip);
|
||||
fe->CalcShape(eip, shape);
|
||||
transf->SetIntPoint(&eip);
|
||||
ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
|
||||
err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
|
||||
}
|
||||
if (i2 >= 0)
|
||||
{
|
||||
// side 2
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 10);
|
||||
transf = face_elem_transf->Elem2;
|
||||
fe = fes->GetFE(i2);
|
||||
fe = fes->GetFE(i);
|
||||
fdof = fe->GetDof();
|
||||
fes->GetElementVDofs(i2, vdofs);
|
||||
transf = mesh->GetElementTransformation(i);
|
||||
el_dofs.SetSize(fdof);
|
||||
dshape.SetSize(fdof, dim);
|
||||
dshapet.SetSize(fdof, dim);
|
||||
intorder = 2 * fe->GetOrder(); // <----------
|
||||
const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), intorder);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = (*this)(vdofs[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1-vdofs[k]);
|
||||
}
|
||||
for (j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(j);
|
||||
fe->CalcDShape(ip, dshape);
|
||||
transf->SetIntPoint(&ip);
|
||||
exgrad->Eval(e_grad, *transf, ip);
|
||||
CalcInverse(transf->Jacobian(), Jinv);
|
||||
Mult(dshape, Jinv, dshapet);
|
||||
dshapet.MultTranspose(el_dofs, a_grad);
|
||||
e_grad -= a_grad;
|
||||
error += (ip.weight * transf->Weight() *
|
||||
ell_coeff->Eval(*transf, ip) *
|
||||
(e_grad * e_grad));
|
||||
}
|
||||
}
|
||||
|
||||
if (norm_type & 2)
|
||||
for (i = 0; i < mesh->GetNFaces(); i++)
|
||||
{
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 5);
|
||||
int i1 = face_elem_transf->Elem1No;
|
||||
int i2 = face_elem_transf->Elem2No;
|
||||
intorder = fes->GetFE(i1)->GetOrder();
|
||||
if (i2 >= 0)
|
||||
if ( (k = fes->GetFE(i2)->GetOrder()) > intorder )
|
||||
{
|
||||
intorder = k;
|
||||
}
|
||||
intorder = 2 * intorder; // <-------------
|
||||
const IntegrationRule &ir =
|
||||
IntRules.Get(face_elem_transf->GetGeometryType(), intorder);
|
||||
err_val.SetSize(ir.GetNPoints());
|
||||
ell_coeff_val.SetSize(ir.GetNPoints());
|
||||
// side 1
|
||||
transf = face_elem_transf->Elem1;
|
||||
fe = fes->GetFE(i1);
|
||||
fdof = fe->GetDof();
|
||||
fes->GetElementVDofs(i1, vdofs);
|
||||
shape.SetSize(fdof);
|
||||
el_dofs.SetSize(fdof);
|
||||
for (k = 0; k < fdof; k++)
|
||||
@@ -2859,69 +2746,60 @@ double GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1-vdofs[k]);
|
||||
}
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
for (j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
face_elem_transf->Loc2.Transform(ir->IntPoint(j), eip);
|
||||
face_elem_transf->Loc1.Transform(ir.IntPoint(j), eip);
|
||||
fe->CalcShape(eip, shape);
|
||||
transf->SetIntPoint(&eip);
|
||||
ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
|
||||
ell_coeff_val(j) *= 0.5;
|
||||
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
|
||||
ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
|
||||
err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
|
||||
}
|
||||
if (i2 >= 0)
|
||||
{
|
||||
// side 2
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 10);
|
||||
transf = face_elem_transf->Elem2;
|
||||
fe = fes->GetFE(i2);
|
||||
fdof = fe->GetDof();
|
||||
fes->GetElementVDofs(i2, vdofs);
|
||||
shape.SetSize(fdof);
|
||||
el_dofs.SetSize(fdof);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = (*this)(vdofs[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1-vdofs[k]);
|
||||
}
|
||||
for (j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
face_elem_transf->Loc2.Transform(ir.IntPoint(j), eip);
|
||||
fe->CalcShape(eip, shape);
|
||||
transf->SetIntPoint(&eip);
|
||||
ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
|
||||
ell_coeff_val(j) *= 0.5;
|
||||
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
|
||||
}
|
||||
}
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
|
||||
transf = face_elem_transf;
|
||||
for (j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
error += (ip.weight * Nu * ell_coeff_val(j) *
|
||||
pow(transf->Weight(), 1.0-1.0/(dim-1)) *
|
||||
err_val(j) * err_val(j));
|
||||
}
|
||||
}
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
|
||||
transf = face_elem_transf;
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
error += (ip.weight * Nu * ell_coeff_val(j) *
|
||||
pow(transf->Weight(), 1.0-1.0/(dim-1)) *
|
||||
err_val(j) * err_val(j));
|
||||
}
|
||||
|
||||
if (error < 0.0)
|
||||
{
|
||||
return -sqrt(-error);
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeH1Error(Coefficient *exsol,
|
||||
VectorCoefficient *exgrad,
|
||||
Coefficient *ell_coef, double Nu,
|
||||
int norm_type) const
|
||||
{
|
||||
double error1 = 0.0;
|
||||
double error2 = 0.0;
|
||||
if (norm_type & 1) { error1 = GridFunction::ComputeGradError(exgrad); }
|
||||
if (norm_type & 2) { error2 = GridFunction::ComputeDGFaceJumpError(exsol,ell_coef,Nu); }
|
||||
|
||||
return sqrt(error1 * error1 + error2 * error2);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeH1Error(Coefficient *exsol,
|
||||
VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,irs);
|
||||
double GradError = ComputeGradError(exgrad,irs);
|
||||
return sqrt(L2error*L2error + GradError*GradError);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeHDivError(VectorCoefficient *exsol,
|
||||
Coefficient *exdiv,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,NULL,irs);
|
||||
double DivError = ComputeDivError(exdiv,irs);
|
||||
return sqrt(L2error*L2error + DivError*DivError);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeHCurlError(VectorCoefficient *exsol,
|
||||
VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,NULL,irs);
|
||||
double CurlError = ComputeCurlError(excurl,irs);
|
||||
return sqrt(L2error*L2error + CurlError*CurlError);
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
double GridFunction::ComputeMaxError(
|
||||
@@ -2977,6 +2855,7 @@ double GridFunction::ComputeMaxError(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -334,11 +334,6 @@ public:
|
||||
void ImposeBounds(int i, const Vector &weights,
|
||||
double _min = 0.0, double _max = infinity());
|
||||
|
||||
/** On a non-conforming mesh, make sure the function lies in the conforming
|
||||
space by multiplying with R and then with P, the conforming restriction
|
||||
and prolongation matrices of the space, respectively. */
|
||||
void RestrictConforming();
|
||||
|
||||
/** @brief Project the @a src GridFunction to @a this GridFunction, both of
|
||||
which must be on the same mesh. */
|
||||
/** The current implementation assumes that all elements use the same
|
||||
@@ -427,7 +422,6 @@ public:
|
||||
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
|
||||
Array<int> &bdr_attr);
|
||||
|
||||
|
||||
virtual double ComputeL2Error(Coefficient &exsol,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{ return ComputeLpError(2.0, exsol, NULL, irs); }
|
||||
@@ -439,50 +433,10 @@ public:
|
||||
const IntegrationRule *irs[] = NULL,
|
||||
Array<int> *elems = NULL) const;
|
||||
|
||||
/// Returns ||grad u_ex - grad u_h||_L2 for H1 or L2 elements
|
||||
virtual double ComputeGradError(VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns ||curl u_ex - curl u_h||_L2 for ND elements
|
||||
virtual double ComputeCurlError(VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns ||div u_ex - div u_h||_L2 for RT elements
|
||||
virtual double ComputeDivError(Coefficient *exdiv,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns the Face Jumps error for L2 elements
|
||||
virtual double ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
Coefficient *ell_coeff,
|
||||
double Nu,
|
||||
const IntegrationRule *irs[] = NULL)
|
||||
const;
|
||||
|
||||
/** This method is kept for backward compatibility.
|
||||
|
||||
Returns either the H1-seminorm, or the DG face jumps error, or both
|
||||
depending on norm_type = 1, 2, 3. Additional arguments for the DG face
|
||||
jumps norm: ell_coeff: mesh-depended coefficient (weight) Nu: scalar
|
||||
constant weight */
|
||||
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
Coefficient *ell_coef, double Nu,
|
||||
int norm_type) const;
|
||||
|
||||
/// Returns the error measured in H1-norm for H1 elements or in "broken"
|
||||
/// H1-norm for L2 elements
|
||||
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns the error measured in H(div)-norm for RT elements
|
||||
virtual double ComputeHDivError(VectorCoefficient *exsol,
|
||||
Coefficient *exdiv,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns the error measured in H(curl)-norm for ND elements
|
||||
virtual double ComputeHCurlError(VectorCoefficient *exsol,
|
||||
VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
virtual double ComputeMaxError(Coefficient &exsol,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
|
||||
+86
-403
@@ -29,13 +29,10 @@ namespace mfem
|
||||
{
|
||||
|
||||
FindPointsGSLIB::FindPointsGSLIB()
|
||||
: mesh(NULL), meshsplit(NULL), ir_simplex(NULL),
|
||||
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
|
||||
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
|
||||
avgtype(AvgType::ARITHMETIC)
|
||||
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
|
||||
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
|
||||
{
|
||||
gsl_comm = new comm;
|
||||
cr = new crystal;
|
||||
#ifdef MFEM_USE_MPI
|
||||
int initialized;
|
||||
MPI_Initialized(&initialized);
|
||||
@@ -50,20 +47,15 @@ FindPointsGSLIB::FindPointsGSLIB()
|
||||
FindPointsGSLIB::~FindPointsGSLIB()
|
||||
{
|
||||
delete gsl_comm;
|
||||
delete cr;
|
||||
delete ir_simplex;
|
||||
delete meshsplit;
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
FindPointsGSLIB::FindPointsGSLIB(MPI_Comm _comm)
|
||||
: mesh(NULL), meshsplit(NULL), ir_simplex(NULL),
|
||||
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
|
||||
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
|
||||
avgtype(AvgType::ARITHMETIC)
|
||||
: mesh(NULL), ir_simplex(NULL), fdata2D(NULL), fdata3D(NULL),
|
||||
dim(-1), gsl_mesh(), gsl_ref(), gsl_dist(), setupflag(false)
|
||||
{
|
||||
gsl_comm = new comm;
|
||||
cr = new crystal;
|
||||
comm_init(gsl_comm, _comm);
|
||||
}
|
||||
#endif
|
||||
@@ -78,7 +70,6 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
|
||||
// call FreeData if FindPointsGSLIB::Setup has been called already
|
||||
if (setupflag) { FreeData(); }
|
||||
|
||||
crystal_init(cr, gsl_comm);
|
||||
mesh = &m;
|
||||
dim = mesh->Dimension();
|
||||
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
|
||||
@@ -122,16 +113,14 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
|
||||
setupflag = true;
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::FindPoints(const Vector &point_pos)
|
||||
void FindPointsGSLIB::FindPoints(const Vector &point_pos,
|
||||
Array<unsigned int> &codes,
|
||||
Array<unsigned int> &proc_ids,
|
||||
Array<unsigned int> &elem_ids,
|
||||
Vector &ref_pos, Vector &dist)
|
||||
{
|
||||
MFEM_VERIFY(setupflag, "Use FindPointsGSLIB::Setup before finding points.");
|
||||
points_cnt = point_pos.Size() / dim;
|
||||
gsl_code.SetSize(points_cnt);
|
||||
gsl_proc.SetSize(points_cnt);
|
||||
gsl_elem.SetSize(points_cnt);
|
||||
gsl_ref.SetSize(points_cnt * dim);
|
||||
gsl_dist.SetSize(points_cnt);
|
||||
|
||||
const int points_cnt = point_pos.Size() / dim;
|
||||
if (dim == 2)
|
||||
{
|
||||
const double *xv_base[2];
|
||||
@@ -140,11 +129,11 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos)
|
||||
unsigned xv_stride[2];
|
||||
xv_stride[0] = sizeof(double);
|
||||
xv_stride[1] = sizeof(double);
|
||||
findpts_2(gsl_code.GetData(), sizeof(unsigned int),
|
||||
gsl_proc.GetData(), sizeof(unsigned int),
|
||||
gsl_elem.GetData(), sizeof(unsigned int),
|
||||
gsl_ref.GetData(), sizeof(double) * dim,
|
||||
gsl_dist.GetData(), sizeof(double),
|
||||
findpts_2(codes.GetData(), sizeof(unsigned int),
|
||||
proc_ids.GetData(), sizeof(unsigned int),
|
||||
elem_ids.GetData(), sizeof(unsigned int),
|
||||
ref_pos.GetData(), sizeof(double) * dim,
|
||||
dist.GetData(), sizeof(double),
|
||||
xv_base, xv_stride, points_cnt, fdata2D);
|
||||
}
|
||||
else
|
||||
@@ -157,27 +146,25 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos)
|
||||
xv_stride[0] = sizeof(double);
|
||||
xv_stride[1] = sizeof(double);
|
||||
xv_stride[2] = sizeof(double);
|
||||
findpts_3(gsl_code.GetData(), sizeof(unsigned int),
|
||||
gsl_proc.GetData(), sizeof(unsigned int),
|
||||
gsl_elem.GetData(), sizeof(unsigned int),
|
||||
gsl_ref.GetData(), sizeof(double) * dim,
|
||||
gsl_dist.GetData(), sizeof(double),
|
||||
findpts_3(codes.GetData(), sizeof(unsigned int),
|
||||
proc_ids.GetData(), sizeof(unsigned int),
|
||||
elem_ids.GetData(), sizeof(unsigned int),
|
||||
ref_pos.GetData(), sizeof(double) * dim,
|
||||
dist.GetData(), sizeof(double),
|
||||
xv_base, xv_stride, points_cnt, fdata3D);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the element number and reference position to 0 for points not found
|
||||
for (int i = 0; i < points_cnt; i++)
|
||||
{
|
||||
if (gsl_code[i] == 2)
|
||||
{
|
||||
gsl_elem[i] = 0;
|
||||
for (int d = 0; d < dim; d++) { gsl_ref(i*dim + d) = -1.; }
|
||||
}
|
||||
}
|
||||
void FindPointsGSLIB::FindPoints(const Vector &point_pos)
|
||||
{
|
||||
const int points_cnt = point_pos.Size() / dim;
|
||||
gsl_code.SetSize(points_cnt);
|
||||
gsl_proc.SetSize(points_cnt);
|
||||
gsl_elem.SetSize(points_cnt);
|
||||
gsl_ref.SetSize(points_cnt * dim);
|
||||
gsl_dist.SetSize(points_cnt);
|
||||
|
||||
// Map element number for simplices, and ref_pos from [-1,1] to [0,1] for
|
||||
// both simplices and quads.
|
||||
MapRefPosAndElemIndices();
|
||||
FindPoints(point_pos, gsl_code, gsl_proc, gsl_elem, gsl_ref, gsl_dist);
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::FindPoints(Mesh &m, const Vector &point_pos,
|
||||
@@ -191,24 +178,72 @@ void FindPointsGSLIB::FindPoints(Mesh &m, const Vector &point_pos,
|
||||
FindPoints(point_pos);
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::Interpolate(Array<unsigned int> &codes,
|
||||
Array<unsigned int> &proc_ids,
|
||||
Array<unsigned int> &elem_ids,
|
||||
Vector &ref_pos, const GridFunction &field_in,
|
||||
Vector &field_out)
|
||||
{
|
||||
|
||||
FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
|
||||
GridFunction field_in_scalar(&ind_fes);
|
||||
Vector node_vals;
|
||||
|
||||
const int ncomp = field_in.FESpace()->GetVDim(),
|
||||
points_fld = field_in.Size() / ncomp,
|
||||
points_cnt = codes.Size();
|
||||
field_out.SetSize(points_cnt*ncomp);
|
||||
|
||||
for (int i = 0; i < ncomp; i++)
|
||||
{
|
||||
const int dataptrin = i*points_fld,
|
||||
dataptrout = i*points_cnt;
|
||||
field_in_scalar.NewDataAndSize(field_in.GetData()+dataptrin, points_fld);
|
||||
GetNodeValues(field_in_scalar, node_vals);
|
||||
|
||||
if (dim==2)
|
||||
{
|
||||
findpts_eval_2(field_out.GetData()+dataptrout, sizeof(double),
|
||||
codes.GetData(), sizeof(unsigned int),
|
||||
proc_ids.GetData(), sizeof(unsigned int),
|
||||
elem_ids.GetData(), sizeof(unsigned int),
|
||||
ref_pos.GetData(), sizeof(double) * dim,
|
||||
points_cnt, node_vals.GetData(), fdata2D);
|
||||
}
|
||||
else
|
||||
{
|
||||
findpts_eval_3(field_out.GetData()+dataptrout, sizeof(double),
|
||||
codes.GetData(), sizeof(unsigned int),
|
||||
proc_ids.GetData(), sizeof(unsigned int),
|
||||
elem_ids.GetData(), sizeof(unsigned int),
|
||||
ref_pos.GetData(), sizeof(double) * dim,
|
||||
points_cnt, node_vals.GetData(), fdata3D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
|
||||
Vector &field_out)
|
||||
{
|
||||
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::Interpolate(const Vector &point_pos,
|
||||
const GridFunction &field_in, Vector &field_out)
|
||||
{
|
||||
FindPoints(point_pos);
|
||||
Interpolate(field_in, field_out);
|
||||
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::Interpolate(Mesh &m, const Vector &point_pos,
|
||||
const GridFunction &field_in, Vector &field_out)
|
||||
{
|
||||
FindPoints(m, point_pos);
|
||||
Interpolate(field_in, field_out);
|
||||
Interpolate(gsl_code, gsl_proc, gsl_elem, gsl_ref, field_in, field_out);
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::FreeData()
|
||||
{
|
||||
if (!setupflag) { return; }
|
||||
crystal_free(cr);
|
||||
if (dim == 2)
|
||||
{
|
||||
findpts_free_2(fdata2D);
|
||||
@@ -217,13 +252,13 @@ void FindPointsGSLIB::FreeData()
|
||||
{
|
||||
findpts_free_3(fdata3D);
|
||||
}
|
||||
setupflag = false;
|
||||
gsl_code.DeleteAll();
|
||||
gsl_proc.DeleteAll();
|
||||
gsl_elem.DeleteAll();
|
||||
gsl_mesh.Destroy();
|
||||
gsl_ref.Destroy();
|
||||
gsl_dist.Destroy();
|
||||
setupflag = false;
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::GetNodeValues(const GridFunction &gf_in,
|
||||
@@ -323,8 +358,9 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
|
||||
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
|
||||
const Geometry::Type gt = fe->GetGeomType();
|
||||
const GridFunction *nodes = mesh->GetNodes();
|
||||
Mesh *meshsplit = NULL;
|
||||
const int NE = mesh->GetNE();
|
||||
int NEsplit = 0;
|
||||
int NEsplit = -1;
|
||||
|
||||
// Split the reference element into a reference submesh of quads or hexes.
|
||||
if (gt == Geometry::TRIANGLE)
|
||||
@@ -480,361 +516,8 @@ void FindPointsGSLIB::GetSimplexNodalCoordinates()
|
||||
pt_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::MapRefPosAndElemIndices()
|
||||
{
|
||||
gsl_mfem_ref = gsl_ref;
|
||||
gsl_mfem_elem = gsl_elem;
|
||||
const FiniteElement *fe = mesh->GetNodalFESpace()->GetFE(0);
|
||||
const Geometry::Type gt = fe->GetGeomType();
|
||||
int NEsplit = 0;
|
||||
|
||||
gsl_mfem_ref -= -1.; // map [-1, 1] to
|
||||
gsl_mfem_ref *= 0.5; // [0, 1]
|
||||
if (gt == Geometry::SQUARE || gt == Geometry::CUBE) { return; }
|
||||
|
||||
H1_FECollection feclin(1, dim);
|
||||
FiniteElementSpace nodal_fes_lin(meshsplit, &feclin, dim);
|
||||
GridFunction gf_lin(&nodal_fes_lin);
|
||||
|
||||
if (gt == Geometry::TRIANGLE)
|
||||
{
|
||||
const double quad_v[7][2] =
|
||||
{
|
||||
{0, 0}, {0.5, 0}, {1, 0}, {0, 0.5},
|
||||
{1./3., 1./3.}, {0.5, 0.5}, {0, 1}
|
||||
};
|
||||
for (int k = 0; k < dim; k++)
|
||||
{
|
||||
for (int j = 0; j < gf_lin.Size()/dim; j++)
|
||||
{
|
||||
gf_lin(j+k*gf_lin.Size()/dim) = quad_v[j][k];
|
||||
}
|
||||
}
|
||||
NEsplit = 3;
|
||||
}
|
||||
else if (gt == Geometry::TETRAHEDRON)
|
||||
{
|
||||
const double hex_v[15][3] =
|
||||
{
|
||||
{0, 0, 0.}, {1, 0., 0.}, {0., 1., 0.}, {0, 0., 1.},
|
||||
{0.5, 0., 0.}, {0.5, 0.5, 0.}, {0., 0.5, 0.},
|
||||
{0., 0., 0.5}, {0.5, 0., 0.5}, {0., 0.5, 0.5},
|
||||
{1./3., 0., 1./3.}, {1./3., 1./3., 1./3.}, {0, 1./3., 1./3.},
|
||||
{1./3., 1./3., 0}, {0.25, 0.25, 0.25}
|
||||
};
|
||||
for (int k = 0; k < dim; k++)
|
||||
{
|
||||
for (int j = 0; j < gf_lin.Size()/dim; j++)
|
||||
{
|
||||
gf_lin(j+k*gf_lin.Size()/dim) = hex_v[j][k];
|
||||
}
|
||||
}
|
||||
NEsplit = 4;
|
||||
}
|
||||
else if (gt == Geometry::PRISM)
|
||||
{
|
||||
const double hex_v[14][3] =
|
||||
{
|
||||
{0, 0, 0}, {0.5, 0, 0}, {1, 0, 0}, {0, 0.5, 0},
|
||||
{1./3., 1./3., 0}, {0.5, 0.5, 0}, {0, 1, 0},
|
||||
{0, 0, 1}, {0.5, 0, 1}, {1, 0, 1}, {0, 0.5, 1},
|
||||
{1./3., 1./3., 1}, {0.5, 0.5, 1}, {0, 1, 1}
|
||||
};
|
||||
for (int k = 0; k < dim; k++)
|
||||
{
|
||||
for (int j = 0; j < gf_lin.Size()/dim; j++)
|
||||
{
|
||||
gf_lin(j+k*gf_lin.Size()/dim) = hex_v[j][k];
|
||||
}
|
||||
}
|
||||
NEsplit = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Element type not currently supported.");
|
||||
}
|
||||
|
||||
// Simplices are split into quads/hexes for GSLIB. For MFEM, we need to find
|
||||
// the original element number and map the rst from micro to macro element.
|
||||
for (int i = 0; i < points_cnt; i++)
|
||||
{
|
||||
if (gsl_code[i] == 2) { continue; }
|
||||
int local_elem = gsl_elem[i]%NEsplit;
|
||||
gsl_mfem_elem[i] = (gsl_elem[i] - local_elem)/NEsplit; // macro element number
|
||||
|
||||
IntegrationPoint ip;
|
||||
Vector mfem_ref(gsl_mfem_ref.GetData()+i*dim, dim);
|
||||
ip.Set2(mfem_ref.GetData());
|
||||
if (dim == 3) { ip.z = mfem_ref(2); }
|
||||
gf_lin.GetVectorValue(local_elem, ip, mfem_ref); // map to rst of macro element
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::Interpolate(const GridFunction &field_in,
|
||||
Vector &field_out)
|
||||
{
|
||||
const int gf_order = field_in.FESpace()->GetFE(0)->GetOrder(),
|
||||
mesh_order = mesh->GetNodalFESpace()->GetFE(0)->GetOrder();
|
||||
|
||||
const FiniteElementCollection *fec_in = field_in.FESpace()->FEColl();
|
||||
const H1_FECollection *fec_h1 = dynamic_cast<const H1_FECollection *>(fec_in);
|
||||
const L2_FECollection *fec_l2 = dynamic_cast<const L2_FECollection *>(fec_in);
|
||||
|
||||
if (fec_h1 && gf_order == mesh_order &&
|
||||
fec_h1->GetBasisType() == BasisType::GaussLobatto)
|
||||
{
|
||||
InterpolateH1(field_in, field_out);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
InterpolateGeneral(field_in, field_out);
|
||||
if (!fec_l2 || avgtype == AvgType::NONE) { return; }
|
||||
}
|
||||
|
||||
// For points on element borders, project the L2 GridFunction to H1 and
|
||||
// re-interpolate.
|
||||
if (fec_l2)
|
||||
{
|
||||
Array<int> indl2;
|
||||
for (int i = 0; i < points_cnt; i++)
|
||||
{
|
||||
if (gsl_code[i] == 1) { indl2.Append(i); }
|
||||
}
|
||||
if (indl2.Size() == 0) { return; } // no points on element borders
|
||||
|
||||
Vector field_out_l2(field_out.Size());
|
||||
VectorGridFunctionCoefficient field_in_dg(&field_in);
|
||||
int gf_order_h1 = std::max(gf_order, 1); // H1 should be at least order 1
|
||||
H1_FECollection fec(gf_order_h1, dim);
|
||||
const int ncomp = field_in.FESpace()->GetVDim();
|
||||
FiniteElementSpace fes(mesh, &fec, ncomp);
|
||||
GridFunction field_in_h1(&fes);
|
||||
|
||||
if (avgtype == AvgType::ARITHMETIC)
|
||||
{
|
||||
field_in_h1.ProjectDiscCoefficient(field_in_dg, GridFunction::ARITHMETIC);
|
||||
}
|
||||
else if (avgtype == AvgType::HARMONIC)
|
||||
{
|
||||
field_in_h1.ProjectDiscCoefficient(field_in_dg, GridFunction::HARMONIC);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Invalid averaging type.");
|
||||
}
|
||||
|
||||
if (gf_order_h1 == mesh_order) // basis is GaussLobatto by default
|
||||
{
|
||||
InterpolateH1(field_in_h1, field_out_l2);
|
||||
}
|
||||
else
|
||||
{
|
||||
InterpolateGeneral(field_in_h1, field_out_l2);
|
||||
}
|
||||
|
||||
// Copy interpolated values for the points on element border
|
||||
for (int j = 0; j < ncomp; j++)
|
||||
{
|
||||
for (int i = 0; i < indl2.Size(); i++)
|
||||
{
|
||||
int idx = indl2[i] + j*points_cnt;
|
||||
field_out(idx) = field_out_l2(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::InterpolateH1(const GridFunction &field_in,
|
||||
Vector &field_out)
|
||||
{
|
||||
FiniteElementSpace ind_fes(mesh, field_in.FESpace()->FEColl());
|
||||
GridFunction field_in_scalar(&ind_fes);
|
||||
Vector node_vals;
|
||||
|
||||
const int ncomp = field_in.FESpace()->GetVDim(),
|
||||
points_fld = field_in.Size() / ncomp,
|
||||
points_cnt = gsl_code.Size();
|
||||
|
||||
field_out.SetSize(points_cnt*ncomp);
|
||||
field_out = default_interp_value;
|
||||
|
||||
for (int i = 0; i < ncomp; i++)
|
||||
{
|
||||
const int dataptrin = i*points_fld,
|
||||
dataptrout = i*points_cnt;
|
||||
field_in_scalar.NewDataAndSize(field_in.GetData()+dataptrin, points_fld);
|
||||
GetNodeValues(field_in_scalar, node_vals);
|
||||
|
||||
if (dim==2)
|
||||
{
|
||||
findpts_eval_2(field_out.GetData()+dataptrout, sizeof(double),
|
||||
gsl_code.GetData(), sizeof(unsigned int),
|
||||
gsl_proc.GetData(), sizeof(unsigned int),
|
||||
gsl_elem.GetData(), sizeof(unsigned int),
|
||||
gsl_ref.GetData(), sizeof(double) * dim,
|
||||
points_cnt, node_vals.GetData(), fdata2D);
|
||||
}
|
||||
else
|
||||
{
|
||||
findpts_eval_3(field_out.GetData()+dataptrout, sizeof(double),
|
||||
gsl_code.GetData(), sizeof(unsigned int),
|
||||
gsl_proc.GetData(), sizeof(unsigned int),
|
||||
gsl_elem.GetData(), sizeof(unsigned int),
|
||||
gsl_ref.GetData(), sizeof(double) * dim,
|
||||
points_cnt, node_vals.GetData(), fdata3D);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::InterpolateGeneral(const GridFunction &field_in,
|
||||
Vector &field_out)
|
||||
{
|
||||
int ncomp = field_in.VectorDim(),
|
||||
nptorig = points_cnt,
|
||||
npt = points_cnt;
|
||||
|
||||
field_out.SetSize(points_cnt*ncomp);
|
||||
field_out = default_interp_value;
|
||||
|
||||
if (gsl_comm->np == 1) // serial
|
||||
{
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
if (gsl_code[index] == 2) { continue; }
|
||||
IntegrationPoint ip;
|
||||
ip.Set2(gsl_mfem_ref.GetData()+index*dim);
|
||||
if (dim == 3) { ip.z = gsl_mfem_ref(index*dim + 2); }
|
||||
Vector localval(ncomp);
|
||||
field_in.GetVectorValue(gsl_mfem_elem[index], ip, localval);
|
||||
for (int i = 0; i < ncomp; i++)
|
||||
{
|
||||
field_out(index + i*npt) = localval(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // parallel
|
||||
{
|
||||
// Determine number of points to be sent
|
||||
int nptsend = 0;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
if (gsl_code[index] != 2) { nptsend +=1; }
|
||||
}
|
||||
|
||||
// Pack data to send via crystal router
|
||||
struct array *outpt = new array;
|
||||
struct out_pt { double r[3], ival; uint index, el, proc; };
|
||||
struct out_pt *pt;
|
||||
array_init(struct out_pt, outpt, nptsend);
|
||||
outpt->n=nptsend;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
if (gsl_code[index] == 2) { continue; }
|
||||
for (int d = 0; d < dim; ++d) { pt->r[d]= gsl_mfem_ref(index*dim + d); }
|
||||
pt->index = index;
|
||||
pt->proc = gsl_proc[index];
|
||||
pt->el = gsl_mfem_elem[index];
|
||||
++pt;
|
||||
}
|
||||
|
||||
// Transfer data to target MPI ranks
|
||||
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
|
||||
|
||||
if (ncomp == 1)
|
||||
{
|
||||
// Interpolate the grid function
|
||||
npt = outpt->n;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
IntegrationPoint ip;
|
||||
ip.Set3(&pt->r[0]);
|
||||
pt->ival = field_in.GetValue(pt->el, ip, 1);
|
||||
++pt;
|
||||
}
|
||||
|
||||
// Transfer data back to source MPI rank
|
||||
sarray_transfer(struct out_pt, outpt, proc, 1, cr);
|
||||
npt = outpt->n;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
field_out(pt->index) = pt->ival;
|
||||
++pt;
|
||||
}
|
||||
array_free(outpt);
|
||||
delete outpt;
|
||||
}
|
||||
else // ncomp > 1
|
||||
{
|
||||
// Interpolate data and store in a Vector
|
||||
npt = outpt->n;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
Vector vec_int_vals(npt*ncomp);
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
IntegrationPoint ip;
|
||||
ip.Set3(&pt->r[0]);
|
||||
Vector localval(vec_int_vals.GetData()+index*ncomp, ncomp);
|
||||
field_in.GetVectorValue(pt->el, ip, localval);
|
||||
++pt;
|
||||
}
|
||||
|
||||
// Save index and proc data in a struct
|
||||
struct array *savpt = new array;
|
||||
struct sav_pt { uint index, proc; };
|
||||
struct sav_pt *spt;
|
||||
array_init(struct sav_pt, savpt, npt);
|
||||
savpt->n=npt;
|
||||
spt = (struct sav_pt *)savpt->ptr;
|
||||
pt = (struct out_pt *)outpt->ptr;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
spt->index = pt->index;
|
||||
spt->proc = pt->proc;
|
||||
++pt; ++spt;
|
||||
}
|
||||
|
||||
array_free(outpt);
|
||||
delete outpt;
|
||||
|
||||
// Copy data from save struct to send struct and send component wise
|
||||
struct array *sendpt = new array;
|
||||
struct send_pt { double ival; uint index, proc; };
|
||||
struct send_pt *sdpt;
|
||||
for (int j = 0; j < ncomp; j++)
|
||||
{
|
||||
array_init(struct send_pt, sendpt, npt);
|
||||
sendpt->n=npt;
|
||||
spt = (struct sav_pt *)savpt->ptr;
|
||||
sdpt = (struct send_pt *)sendpt->ptr;
|
||||
for (int index = 0; index < npt; index++)
|
||||
{
|
||||
sdpt->index = spt->index;
|
||||
sdpt->proc = spt->proc;
|
||||
sdpt->ival = vec_int_vals(j + index*ncomp);
|
||||
++sdpt; ++spt;
|
||||
}
|
||||
|
||||
sarray_transfer(struct send_pt, sendpt, proc, 1, cr);
|
||||
sdpt = (struct send_pt *)sendpt->ptr;
|
||||
for (int index = 0; index < nptorig; index++)
|
||||
{
|
||||
int idx = sdpt->index + j*nptorig;
|
||||
field_out(idx) = sdpt->ival;
|
||||
++sdpt;
|
||||
}
|
||||
array_free(sendpt);
|
||||
}
|
||||
array_free(savpt);
|
||||
delete sendpt;
|
||||
delete savpt;
|
||||
} // ncomp > 1
|
||||
} // parallel
|
||||
delete meshsplit;
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+45
-93
@@ -20,66 +20,28 @@
|
||||
struct comm;
|
||||
struct findpts_data_2;
|
||||
struct findpts_data_3;
|
||||
struct array;
|
||||
struct crystal;
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/** \brief FindPointsGSLIB can robustly evaluate a GridFunction on an arbitrary
|
||||
* collection of points. There are three key functions in FindPointsGSLIB:
|
||||
*
|
||||
* 1. Setup - constructs the internal data structures of gslib.
|
||||
*
|
||||
* 2. FindPoints - for any given arbitrary set of points in physical space,
|
||||
* gslib finds the element number, MPI rank, and the reference space
|
||||
* coordinates inside the element that each point is located in. gslib also
|
||||
* returns a code that indicates whether the point was found inside an
|
||||
* element, on element border, or not found in the domain.
|
||||
*
|
||||
* 3. Interpolate - Interpolates any grid function at the points found using 2.
|
||||
*
|
||||
* FindPointsGSLIB provides interface to use these functions individually or
|
||||
* using a single call.
|
||||
*/
|
||||
class FindPointsGSLIB
|
||||
{
|
||||
public:
|
||||
enum AvgType {NONE, ARITHMETIC, HARMONIC}; // Average type for L2 functions
|
||||
|
||||
protected:
|
||||
Mesh *mesh, *meshsplit;
|
||||
IntegrationRule *ir_simplex; // IntegrationRule to split quads/hex -> simplex
|
||||
struct findpts_data_2 *fdata2D; // gslib's internal data
|
||||
struct findpts_data_3 *fdata3D; // gslib's internal data
|
||||
struct crystal *cr; // gslib's internal data
|
||||
struct comm *gsl_comm; // gslib's internal data
|
||||
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
|
||||
double default_interp_value; // used for points that are not found in the mesh
|
||||
AvgType avgtype; // average type used for L2 functions
|
||||
Mesh *mesh;
|
||||
IntegrationRule *ir_simplex;
|
||||
struct findpts_data_2 *fdata2D;
|
||||
struct findpts_data_3 *fdata3D;
|
||||
int dim;
|
||||
Array<unsigned int> gsl_code, gsl_proc, gsl_elem;
|
||||
Vector gsl_mesh, gsl_ref, gsl_dist;
|
||||
bool setupflag;
|
||||
|
||||
struct comm *gsl_comm;
|
||||
|
||||
/// Get GridFunction from MFEM format to GSLIB format
|
||||
void GetNodeValues(const GridFunction &gf_in, Vector &node_vals);
|
||||
/// Get nodal coordinates from mesh to the format expected by GSLIB for quads
|
||||
/// and hexes
|
||||
void GetQuadHexNodalCoordinates();
|
||||
/// Convert simplices to quad/hexes and then get nodal coordinates for each
|
||||
/// split element into format expected by GSLIB
|
||||
void GetSimplexNodalCoordinates();
|
||||
|
||||
/// Use GSLIB for communication and interpolation
|
||||
void InterpolateH1(const GridFunction &field_in, Vector &field_out);
|
||||
/// Uses GSLIB Crystal Router for communication followed by MFEM's
|
||||
/// interpolation functions
|
||||
void InterpolateGeneral(const GridFunction &field_in, Vector &field_out);
|
||||
/// Map {r,s,t} coordinates from [-1,1] to [0,1] for MFEM. For simplices mesh
|
||||
/// find the original element number (that was split into micro quads/hexes
|
||||
/// by GetSimplexNodalCoordinates())
|
||||
void MapRefPosAndElemIndices();
|
||||
|
||||
public:
|
||||
FindPointsGSLIB();
|
||||
|
||||
@@ -102,37 +64,45 @@ 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. These positions
|
||||
must by ordered by nodes: (XXX...,YYY...,ZZZ).
|
||||
This function populates the following member variables:
|
||||
#gsl_code Return codes for each point: inside element (0),
|
||||
element boundary (1), not found (2).
|
||||
#gsl_proc MPI proc ids where the points were found.
|
||||
#gsl_elem Element ids where the points were found.
|
||||
Defaults to 0 for points that were not found.
|
||||
#gsl_mfem_elem Element ids corresponding to MFEM-mesh where the points
|
||||
were found. #gsl_mfem_elem != #gsl_elem for simplices
|
||||
Defaults to 0 for points that were not found.
|
||||
#gsl_ref Reference coordinates of the found point.
|
||||
Ordered by vdim (XYZ,XYZ,XYZ...). Defaults to -1 for
|
||||
points that were not found. Note: the gslib reference
|
||||
frame is [-1,1].
|
||||
#gsl_mfem_ref Reference coordinates #gsl_ref mapped to [0,1].
|
||||
Defaults to 0 for points that were not found.
|
||||
#gsl_dist Distance between the sought and the found point
|
||||
in physical space. */
|
||||
/** Searches positions given in physical space by @a point_pos. All output
|
||||
Arrays and Vectors are expected to have the correct size.
|
||||
|
||||
@param[in] point_pos Positions to be found. Must by ordered by nodes
|
||||
(XXX...,YYY...,ZZZ).
|
||||
@param[out] codes Return codes for each point: inside element (0),
|
||||
element boundary (1), not found (2).
|
||||
@param[out] proc_ids MPI proc ids where the points were found.
|
||||
@param[out] elem_ids Element ids where the points were found.
|
||||
@param[out] ref_pos Reference coordinates of the found point. Ordered
|
||||
by vdim (XYZ,XYZ,XYZ...).
|
||||
Note: the gslib reference frame is [-1,1].
|
||||
@param[out] dist Distance between the sought and the found point
|
||||
in physical space. */
|
||||
void FindPoints(const Vector &point_pos, Array<unsigned int> &codes,
|
||||
Array<unsigned int> &proc_ids, Array<unsigned int> &elem_ids,
|
||||
Vector &ref_pos, Vector &dist);
|
||||
void FindPoints(const Vector &point_pos);
|
||||
/// Setup FindPoints and search positions
|
||||
void FindPoints(Mesh &m, const Vector &point_pos, const double bb_t = 0.1,
|
||||
const double newt_tol = 1.0e-12, const int npt_max = 256);
|
||||
|
||||
/** Interpolation of field values at prescribed reference space positions.
|
||||
|
||||
@param[in] codes Return codes for each point: inside element (0),
|
||||
element boundary (1), not found (2).
|
||||
@param[in] proc_ids MPI proc ids where the points were found.
|
||||
@param[in] elem_ids Element ids where the points were found.
|
||||
@param[in] ref_pos Reference coordinates of the found point. Ordered
|
||||
by vdim (XYZ,XYZ,XYZ...).
|
||||
Note: the gslib reference frame is [-1,1].
|
||||
@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
|
||||
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. */
|
||||
@param[out] field_out Interpolated values. */
|
||||
void Interpolate(Array<unsigned int> &codes, Array<unsigned int> &proc_ids,
|
||||
Array<unsigned int> &elem_ids, Vector &ref_pos,
|
||||
const GridFunction &field_in, Vector &field_out);
|
||||
void Interpolate(const GridFunction &field_in, Vector &field_out);
|
||||
/** Search positions and interpolate */
|
||||
void Interpolate(const Vector &point_pos, const GridFunction &field_in,
|
||||
@@ -141,45 +111,27 @@ public:
|
||||
void Interpolate(Mesh &m, const Vector &point_pos,
|
||||
const GridFunction &field_in, Vector &field_out);
|
||||
|
||||
/// Average type to be used for L2 functions in-case a point is located at
|
||||
/// an element boundary where the function might be multi-valued.
|
||||
void SetL2AvgType(AvgType avgtype_) { avgtype = avgtype_; }
|
||||
|
||||
/// Set the default interpolation value for points that are not found in the
|
||||
/// mesh.
|
||||
void SetDefaultInterpolationValue(double interp_value_)
|
||||
{
|
||||
default_interp_value = interp_value_;
|
||||
}
|
||||
|
||||
/** Cleans up memory allocated internally by gslib.
|
||||
Note that in parallel, this must be called before MPI_Finalize(), as it
|
||||
calls MPI_Comm_free() for internal gslib communicators. */
|
||||
Note that in parallel, this must be called before MPI_Finalize(), as
|
||||
it calls MPI_Comm_free() for internal gslib communicators. */
|
||||
void FreeData();
|
||||
|
||||
/// Return code for each point searched by FindPoints: inside element (0), on
|
||||
/// element boundary (1), or not found (2).
|
||||
const Array<unsigned int> &GetCode() const { return gsl_code; }
|
||||
/// Return element number for each point found by FindPoints.
|
||||
const Array<unsigned int> &GetElem() const { return gsl_mfem_elem; }
|
||||
const Array<unsigned int> &GetElem() const { return gsl_elem; }
|
||||
/// Return MPI rank on which each point was found by FindPoints.
|
||||
const Array<unsigned int> &GetProc() const { return gsl_proc; }
|
||||
/// Return reference coordinates for each point found by FindPoints.
|
||||
const Vector &GetReferencePosition() const { return gsl_mfem_ref; }
|
||||
const Vector &GetReferencePosition() const { return gsl_ref; }
|
||||
/// Return distance Distance between the sought and the found point
|
||||
/// in physical space, for each point found by FindPoints.
|
||||
const Vector &GetDist() const { return gsl_dist; }
|
||||
|
||||
/// Return element number for each point found by FindPoints corresponding to
|
||||
/// GSLIB mesh. gsl_mfem_elem != gsl_elem for mesh with simplices.
|
||||
const Array<unsigned int> &GetGSLIBElem() const { return gsl_elem; }
|
||||
/// Return reference coordinates in [-1,1] (internal range in GSLIB) for each
|
||||
/// point found by FindPoints.
|
||||
const Vector &GetGSLIBReferencePosition() const { return gsl_ref; }
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_USE_GSLIB
|
||||
#endif //MFEM_USE_GSLIB
|
||||
|
||||
#endif // MFEM_GSLIB
|
||||
#endif //MFEM_GSLIB guard
|
||||
|
||||
+1465
File diff suppressed because it is too large
Load Diff
+25
-149
@@ -35,9 +35,6 @@ extern Ceed ceed;
|
||||
|
||||
std::string ceed_path;
|
||||
|
||||
extern CeedBasisMap ceed_basis_map;
|
||||
extern CeedRestrMap ceed_restr_map;
|
||||
|
||||
}
|
||||
|
||||
void InitCeedCoeff(Coefficient* Q, CeedData* ptr)
|
||||
@@ -84,9 +81,10 @@ static CeedElemTopology GetCeedTopology(Geometry::Type geom)
|
||||
}
|
||||
}
|
||||
|
||||
static void InitCeedNonTensorBasis(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedBasis *basis)
|
||||
static void InitCeedNonTensorBasisAndRestriction(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedBasis *basis,
|
||||
CeedElemRestriction *restr)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
@@ -99,73 +97,7 @@ static void InitCeedNonTensorBasis(const FiniteElementSpace &fes,
|
||||
Vector qweight(Q);
|
||||
Vector shape_i(P);
|
||||
DenseMatrix grad_i(P, dim);
|
||||
const Table &el_dof = fes.GetElementToDofTable();
|
||||
Array<int> tp_el_dof(el_dof.Size_of_connections());
|
||||
const TensorBasisElement * tfe =
|
||||
dynamic_cast<const TensorBasisElement *>(fe);
|
||||
if (tfe) // Lexicographic ordering using dof_map
|
||||
{
|
||||
const Array<int>& dof_map = tfe->GetDofMap();
|
||||
for (int i = 0; i < Q; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
qref(0,i) = ip.x;
|
||||
if (dim>1) { qref(1,i) = ip.y; }
|
||||
if (dim>2) { qref(2,i) = ip.z; }
|
||||
qweight(i) = ip.weight;
|
||||
fe->CalcShape(ip, shape_i);
|
||||
fe->CalcDShape(ip, grad_i);
|
||||
for (int j = 0; j < P; j++)
|
||||
{
|
||||
shape(j, i) = shape_i(dof_map[j]);
|
||||
for (int d = 0; d < dim; ++d)
|
||||
{
|
||||
grad(j+i*P+d*Q*P) = grad_i(dof_map[j], d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Native ordering
|
||||
{
|
||||
for (int i = 0; i < Q; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
qref(0,i) = ip.x;
|
||||
if (dim>1) { qref(1,i) = ip.y; }
|
||||
if (dim>2) { qref(2,i) = ip.z; }
|
||||
qweight(i) = ip.weight;
|
||||
fe->CalcShape(ip, shape_i);
|
||||
fe->CalcDShape(ip, grad_i);
|
||||
for (int j = 0; j < P; j++)
|
||||
{
|
||||
shape(j, i) = shape_i(j);
|
||||
for (int d = 0; d < dim; ++d)
|
||||
{
|
||||
grad(j+i*P+d*Q*P) = grad_i(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CeedBasisCreateH1(ceed, GetCeedTopology(fe->GetGeomType()), fes.GetVDim(),
|
||||
fe->GetDof(), ir.GetNPoints(), shape.GetData(),
|
||||
grad.GetData(), qref.GetData(), qweight.GetData(), basis);
|
||||
}
|
||||
|
||||
static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedElemRestriction *restr)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
const int dim = mesh->Dimension();
|
||||
const int P = fe->GetDof();
|
||||
const int Q = ir.GetNPoints();
|
||||
DenseMatrix shape(P, Q);
|
||||
Vector grad(P*dim*Q);
|
||||
DenseMatrix qref(dim, Q);
|
||||
Vector qweight(Q);
|
||||
Vector shape_i(P);
|
||||
DenseMatrix grad_i(P, dim);
|
||||
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
|
||||
const Table &el_dof = fes.GetElementToDofTable();
|
||||
Array<int> tp_el_dof(el_dof.Size_of_connections());
|
||||
@@ -192,6 +124,7 @@ static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < mesh->GetNE(); i++)
|
||||
{
|
||||
const int el_offset = fe->GetDof() * i;
|
||||
@@ -229,6 +162,7 @@ static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int e = 0; e < mesh->GetNE(); e++)
|
||||
{
|
||||
for (int i = 0; i < P; i++)
|
||||
@@ -244,15 +178,19 @@ static void InitCeedNonTensorRestriction(const FiniteElementSpace &fes,
|
||||
}
|
||||
}
|
||||
}
|
||||
CeedBasisCreateH1(ceed, GetCeedTopology(fe->GetGeomType()), fes.GetVDim(),
|
||||
fe->GetDof(), ir.GetNPoints(), shape.GetData(),
|
||||
grad.GetData(), qref.GetData(), qweight.GetData(), basis);
|
||||
CeedElemRestrictionCreate(ceed, mesh->GetNE(), fe->GetDof(), fes.GetVDim(),
|
||||
compstride, (fes.GetVDim())*(fes.GetNDofs()),
|
||||
CEED_MEM_HOST, CEED_COPY_VALUES,
|
||||
tp_el_dof.GetData(), restr);
|
||||
}
|
||||
|
||||
static void InitCeedTensorBasis(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedBasis *basis)
|
||||
static void InitCeedTensorBasisAndRestriction(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedBasis *basis,
|
||||
CeedElemRestriction *restr)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
@@ -260,6 +198,7 @@ static void InitCeedTensorBasis(const FiniteElementSpace &fes,
|
||||
const TensorBasisElement * tfe =
|
||||
dynamic_cast<const TensorBasisElement *>(fe);
|
||||
MFEM_VERIFY(tfe, "invalid FE");
|
||||
const Array<int>& dof_map = tfe->GetDofMap();
|
||||
const FiniteElement *fe1d =
|
||||
fes.FEColl()->FiniteElementForGeometry(Geometry::SEGMENT);
|
||||
DenseMatrix shape1d(fe1d->GetDof(), ir.GetNPoints());
|
||||
@@ -288,28 +227,6 @@ static void InitCeedTensorBasis(const FiniteElementSpace &fes,
|
||||
ir.GetNPoints(), shape1d.GetData(),
|
||||
grad1d.GetData(), qref1d.GetData(),
|
||||
qweight1d.GetData(), basis);
|
||||
}
|
||||
|
||||
static void InitCeedTensorRestriction(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedElemRestriction *restr)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
const TensorBasisElement * tfe =
|
||||
dynamic_cast<const TensorBasisElement *>(fe);
|
||||
MFEM_VERIFY(tfe, "invalid FE");
|
||||
const Array<int>& dof_map = tfe->GetDofMap();
|
||||
const FiniteElement *fe1d =
|
||||
fes.FEColl()->FiniteElementForGeometry(Geometry::SEGMENT);
|
||||
DenseMatrix shape1d(fe1d->GetDof(), ir.GetNPoints());
|
||||
DenseMatrix grad1d(fe1d->GetDof(), ir.GetNPoints());
|
||||
Vector qref1d(ir.GetNPoints()), qweight1d(ir.GetNPoints());
|
||||
Vector shape_i(shape1d.Height());
|
||||
DenseMatrix grad_i(grad1d.Height(), 1);
|
||||
const H1_SegmentElement *h1_fe1d =
|
||||
dynamic_cast<const H1_SegmentElement *>(fe1d);
|
||||
MFEM_VERIFY(h1_fe1d, "invalid FE");
|
||||
|
||||
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
|
||||
const Table &el_dof = fes.GetElementToDofTable();
|
||||
@@ -341,52 +258,14 @@ void InitCeedBasisAndRestriction(const FiniteElementSpace &fes,
|
||||
Ceed ceed, CeedBasis *basis,
|
||||
CeedElemRestriction *restr)
|
||||
{
|
||||
// Check for FES -> basis, restriction in hash tables
|
||||
const Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
const int P = fe->GetDof();
|
||||
const int Q = irm.GetNPoints();
|
||||
const int nelem = mesh->GetNE();
|
||||
const int ncomp = fes.GetVDim();
|
||||
CeedBasisKey basis_key(&fes, &irm, ncomp, P, Q);
|
||||
auto basis_itr = internal::ceed_basis_map.find(basis_key);
|
||||
CeedRestrKey restr_key(&fes, nelem, P, ncomp);
|
||||
auto restr_itr = internal::ceed_restr_map.find(restr_key);
|
||||
|
||||
// Init or retreive key values
|
||||
if (basis_itr == internal::ceed_basis_map.end())
|
||||
if (UsesTensorBasis(fes))
|
||||
{
|
||||
if (UsesTensorBasis(fes))
|
||||
{
|
||||
const IntegrationRule &ir = IntRules.Get(Geometry::SEGMENT, irm.GetOrder());
|
||||
InitCeedTensorBasis(fes, ir, ceed, basis);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitCeedNonTensorBasis(fes, irm, ceed, basis);
|
||||
}
|
||||
internal::ceed_basis_map[basis_key] = *basis;
|
||||
const IntegrationRule &ir = IntRules.Get(Geometry::SEGMENT, irm.GetOrder());
|
||||
InitCeedTensorBasisAndRestriction(fes, ir, ceed, basis, restr);
|
||||
}
|
||||
else
|
||||
{
|
||||
*basis = basis_itr->second;
|
||||
}
|
||||
if (restr_itr == internal::ceed_restr_map.end())
|
||||
{
|
||||
if (UsesTensorBasis(fes))
|
||||
{
|
||||
const IntegrationRule &ir = IntRules.Get(Geometry::SEGMENT, irm.GetOrder());
|
||||
InitCeedTensorRestriction(fes, ir, ceed, restr);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitCeedNonTensorRestriction(fes, irm, ceed, restr);
|
||||
}
|
||||
internal::ceed_restr_map[restr_key] = *restr;
|
||||
}
|
||||
else
|
||||
{
|
||||
*restr = restr_itr->second;
|
||||
InitCeedNonTensorBasisAndRestriction(fes, irm, ceed, basis, restr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,8 +327,8 @@ void CeedPAAssemble(const CeedPAOperator& op,
|
||||
CeedVectorCreate(ceed, nelem * nqpts * qdatasize, &ceedData.rho);
|
||||
|
||||
// Context data to be passed to the 'f_build_diff' Q-function.
|
||||
ceedData.build_ctx_data.dim = mesh->Dimension();
|
||||
ceedData.build_ctx_data.space_dim = mesh->SpaceDimension();
|
||||
ceedData.build_ctx.dim = mesh->Dimension();
|
||||
ceedData.build_ctx.space_dim = mesh->SpaceDimension();
|
||||
|
||||
std::string qf_file = GetCeedPath() + op.header;
|
||||
std::string qf;
|
||||
@@ -463,7 +342,7 @@ void CeedPAAssemble(const CeedPAOperator& op,
|
||||
CeedQFunctionCreateInterior(ceed, 1, op.const_qf,
|
||||
qf.c_str(),
|
||||
&ceedData.build_qfunc);
|
||||
ceedData.build_ctx_data.coeff = ((CeedConstCoeff*)ceedData.coeff)->val;
|
||||
ceedData.build_ctx.coeff = ((CeedConstCoeff*)ceedData.coeff)->val;
|
||||
break;
|
||||
case CeedCoeff::Grid:
|
||||
qf = qf_file + op.grid_func;
|
||||
@@ -479,12 +358,8 @@ void CeedPAAssemble(const CeedPAOperator& op,
|
||||
CeedQFunctionAddInput(ceedData.build_qfunc, "weights", 1, CEED_EVAL_WEIGHT);
|
||||
CeedQFunctionAddOutput(ceedData.build_qfunc, "qdata", qdatasize,
|
||||
CEED_EVAL_NONE);
|
||||
|
||||
CeedQFunctionContextCreate(ceed, &ceedData.build_ctx);
|
||||
CeedQFunctionContextSetData(ceedData.build_ctx, CEED_MEM_HOST, CEED_USE_POINTER,
|
||||
sizeof(ceedData.build_ctx_data),
|
||||
&ceedData.build_ctx_data);
|
||||
CeedQFunctionSetContext(ceedData.build_qfunc, ceedData.build_ctx);
|
||||
CeedQFunctionSetContext(ceedData.build_qfunc, &ceedData.build_ctx,
|
||||
sizeof(ceedData.build_ctx));
|
||||
|
||||
// Create the operator that builds the quadrature data for the operator.
|
||||
CeedOperatorCreate(ceed, ceedData.build_qfunc, NULL, NULL,
|
||||
@@ -524,7 +399,8 @@ void CeedPAAssemble(const CeedPAOperator& op,
|
||||
CeedQFunctionAddInput(ceedData.apply_qfunc, "qdata", qdatasize,
|
||||
CEED_EVAL_NONE);
|
||||
CeedQFunctionAddOutput(ceedData.apply_qfunc, "v", dimV, op.test_op);
|
||||
CeedQFunctionSetContext(ceedData.apply_qfunc, ceedData.build_ctx);
|
||||
CeedQFunctionSetContext(ceedData.apply_qfunc, &ceedData.build_ctx,
|
||||
sizeof(ceedData.build_ctx));
|
||||
|
||||
// Create the diff operator.
|
||||
CeedOperatorCreate(ceed, ceedData.apply_qfunc, NULL, NULL, &ceedData.oper);
|
||||
|
||||
+8
-46
@@ -18,9 +18,6 @@
|
||||
#include "../../general/device.hpp"
|
||||
#include "../../linalg/vector.hpp"
|
||||
#include <ceed.h>
|
||||
#include <ceed-hash.h>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -30,47 +27,7 @@ class GridFunction;
|
||||
class IntegrationRule;
|
||||
class Coefficient;
|
||||
|
||||
// Hash table for CeedBasis
|
||||
using CeedBasisKey =
|
||||
std::tuple<const FiniteElementSpace*, const IntegrationRule*, int, int, int>;
|
||||
struct CeedBasisHash
|
||||
{
|
||||
std::size_t operator()(const CeedBasisKey& k) const
|
||||
{
|
||||
return CeedHashCombine(CeedHashCombine(CeedHashInt(
|
||||
reinterpret_cast<CeedHash64_t>(std::get<0>(k))),
|
||||
CeedHashInt(
|
||||
reinterpret_cast<CeedHash64_t>(std::get<1>(k)))),
|
||||
CeedHashCombine(CeedHashCombine(CeedHashInt(std::get<2>(k)),
|
||||
CeedHashInt(std::get<3>(k))),
|
||||
CeedHashInt(std::get<4>(k))));
|
||||
}
|
||||
};
|
||||
using CeedBasisMap =
|
||||
std::unordered_map<const CeedBasisKey, CeedBasis, CeedBasisHash>;
|
||||
|
||||
// Hash table for CeedElemRestriction
|
||||
using CeedRestrKey = std::tuple<const FiniteElementSpace*, int, int, int>;
|
||||
struct CeedRestrHash
|
||||
{
|
||||
std::size_t operator()(const CeedRestrKey& k) const
|
||||
{
|
||||
return CeedHashCombine(CeedHashCombine(CeedHashInt(
|
||||
reinterpret_cast<CeedHash64_t>(std::get<0>(k))),
|
||||
CeedHashInt(std::get<1>(k))),
|
||||
CeedHashCombine(CeedHashInt(std::get<2>(k)),
|
||||
CeedHashInt(std::get<3>(k))));
|
||||
}
|
||||
};
|
||||
using CeedRestrMap =
|
||||
std::unordered_map<const CeedRestrKey, CeedElemRestriction, CeedRestrHash>;
|
||||
|
||||
namespace internal
|
||||
{
|
||||
extern Ceed ceed; // defined in device.cpp
|
||||
extern CeedBasisMap basis_map;
|
||||
extern CeedRestrMap restr_map;
|
||||
}
|
||||
namespace internal { extern Ceed ceed; } // defined in device.cpp
|
||||
|
||||
/// A structure used to pass additional data to f_build_diff and f_apply_diff
|
||||
struct BuildContext { CeedInt dim, space_dim; CeedScalar coeff; };
|
||||
@@ -99,8 +56,7 @@ struct CeedData
|
||||
CeedVector node_coords, rho;
|
||||
CeedCoeff coeff_type;
|
||||
void* coeff;
|
||||
CeedQFunctionContext build_ctx;
|
||||
BuildContext build_ctx_data;
|
||||
BuildContext build_ctx;
|
||||
|
||||
CeedVector u, v;
|
||||
|
||||
@@ -108,6 +64,10 @@ struct CeedData
|
||||
{
|
||||
CeedOperatorDestroy(&build_oper);
|
||||
CeedOperatorDestroy(&oper);
|
||||
CeedBasisDestroy(&basis);
|
||||
CeedBasisDestroy(&mesh_basis);
|
||||
CeedElemRestrictionDestroy(&restr);
|
||||
CeedElemRestrictionDestroy(&mesh_restr);
|
||||
CeedElemRestrictionDestroy(&restr_i);
|
||||
CeedElemRestrictionDestroy(&mesh_restr_i);
|
||||
CeedQFunctionDestroy(&apply_qfunc);
|
||||
@@ -117,6 +77,8 @@ struct CeedData
|
||||
if (coeff_type==CeedCoeff::Grid)
|
||||
{
|
||||
CeedGridCoeff* c = (CeedGridCoeff*)coeff;
|
||||
CeedBasisDestroy(&c->basis);
|
||||
CeedElemRestrictionDestroy(&c->restr);
|
||||
CeedVectorDestroy(&c->coeffVector);
|
||||
delete c;
|
||||
}
|
||||
|
||||
@@ -204,14 +204,6 @@ void LinearForm::Update(FiniteElementSpace *f, Vector &v, int v_offset)
|
||||
ResetDeltaLocations();
|
||||
}
|
||||
|
||||
void LinearForm::MakeRef(FiniteElementSpace *f, Vector &v, int v_offset)
|
||||
{
|
||||
MFEM_ASSERT(v.Size() >= v_offset + f->GetVSize(), "");
|
||||
fes = f;
|
||||
v.UseDevice(true);
|
||||
this->Vector::MakeRef(v, v_offset, fes->GetVSize());
|
||||
}
|
||||
|
||||
void LinearForm::AssembleDelta()
|
||||
{
|
||||
if (dlfi_delta.Size() == 0) { return; }
|
||||
|
||||
+1
-11
@@ -26,7 +26,7 @@ protected:
|
||||
/// FE space on which the LinearForm lives. Not owned.
|
||||
FiniteElementSpace *fes;
|
||||
|
||||
/** @brief Indicates the LinearFormIntegrator%s stored in #dlfi, #dlfi_delta,
|
||||
/** @brief Indicates the LinerFormIntegrator%s stored in #dlfi, #dlfi_delta,
|
||||
#blfi, and #flfi are owned by another LinearForm. */
|
||||
int extern_lfs;
|
||||
|
||||
@@ -175,16 +175,6 @@ public:
|
||||
@note This method does not perform assembly. */
|
||||
void Update(FiniteElementSpace *f, Vector &v, int v_offset);
|
||||
|
||||
/** @brief Make the LinearForm reference external data on a new
|
||||
FiniteElementSpace. */
|
||||
/** This method changes the FiniteElementSpace associated with the LinearForm
|
||||
@a *f and sets the data of the Vector @a v (plus the @a v_offset) as
|
||||
external data in the LinearForm.
|
||||
|
||||
@note This version of the method will also perform bounds checks when the
|
||||
build option MFEM_DEBUG is enabled. */
|
||||
virtual void MakeRef(FiniteElementSpace *f, Vector &v, int v_offset);
|
||||
|
||||
/// Return the action of the LinearForm as a linear mapping.
|
||||
/** Linear forms are linear functionals which map GridFunctions to
|
||||
the real numbers. This method performs this mapping which in
|
||||
|
||||
+39
-6
@@ -457,8 +457,20 @@ void VectorFEDomainLFCurlIntegrator::AssembleRHSElementVect(
|
||||
|
||||
Tr.SetIntPoint (&ip);
|
||||
el.CalcPhysCurlShape(Tr, curlshape);
|
||||
QF->Eval(vec, Tr, ip);
|
||||
|
||||
switch (spaceDim)
|
||||
{
|
||||
case 3:
|
||||
MFEM_VERIFY(QF, "VectorFunctionCoefficient not provided");
|
||||
QF->Eval(vec, Tr, ip);
|
||||
break;
|
||||
case 2:
|
||||
MFEM_VERIFY(Q, "FunctionCoefficient (Scalar) not provided");
|
||||
vec[0] = Q->Eval(Tr, ip);
|
||||
break;
|
||||
default:
|
||||
break; // This should be unreachable
|
||||
}
|
||||
vec *= ip.weight * Tr.Weight();
|
||||
curlshape.AddMult (vec, elvect);
|
||||
}
|
||||
@@ -468,17 +480,38 @@ void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect(
|
||||
const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
|
||||
{
|
||||
int spaceDim = Trans.GetSpaceDim();
|
||||
MFEM_ASSERT(vec_delta != NULL,
|
||||
"coefficient must be VectorDeltaCoefficient");
|
||||
switch (spaceDim)
|
||||
{
|
||||
case 3:
|
||||
MFEM_ASSERT(vec_delta != NULL,
|
||||
"coefficient must be VectorDeltaCoefficient");
|
||||
break;
|
||||
case 2:
|
||||
MFEM_ASSERT(delta != NULL,
|
||||
"coefficient must be DeltaCoefficient");
|
||||
break;
|
||||
default:
|
||||
break; // This should be unreachable
|
||||
}
|
||||
int dof = fe.GetDof();
|
||||
int n=(spaceDim == 3)? spaceDim : 1;
|
||||
vec.SetSize(n);
|
||||
curlshape.SetSize(dof, n);
|
||||
elvect.SetSize(dof);
|
||||
fe.CalcPhysCurlShape(Trans, curlshape);
|
||||
|
||||
vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint());
|
||||
curlshape.Mult(vec, elvect);
|
||||
switch (spaceDim)
|
||||
{
|
||||
case 3:
|
||||
vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint());
|
||||
curlshape.Mult(vec, elvect);
|
||||
break;
|
||||
case 2:
|
||||
curlshape.GetColumn(0,elvect);
|
||||
elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
|
||||
break;
|
||||
default:
|
||||
break; // This should be unreachable
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect(
|
||||
|
||||
@@ -284,6 +284,7 @@ class VectorFEDomainLFCurlIntegrator : public DeltaLFIntegrator
|
||||
{
|
||||
private:
|
||||
VectorCoefficient *QF=nullptr;
|
||||
Coefficient *Q=nullptr;
|
||||
DenseMatrix curlshape;
|
||||
Vector vec;
|
||||
|
||||
@@ -291,6 +292,8 @@ public:
|
||||
/// Constructs the domain integrator (Q, curl v)
|
||||
VectorFEDomainLFCurlIntegrator(VectorCoefficient &F)
|
||||
: DeltaLFIntegrator(F), QF(&F) { }
|
||||
VectorFEDomainLFCurlIntegrator(Coefficient &F)
|
||||
: DeltaLFIntegrator(F), Q(&F) { }
|
||||
|
||||
virtual void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
|
||||
+52
-3
@@ -10,6 +10,7 @@
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -27,7 +28,7 @@ void NonlinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
|
||||
// This is the default behavior.
|
||||
break;
|
||||
case AssemblyLevel::PARTIAL:
|
||||
ext = new PANonlinearFormExtension(this);
|
||||
ext = new PANonlinearForm(this);
|
||||
break;
|
||||
default:
|
||||
mfem_error("Unknown assembly level for this form.");
|
||||
@@ -80,6 +81,13 @@ void NonlinearForm::SetEssentialVDofs(const Array<int> &ess_vdofs_list)
|
||||
|
||||
double NonlinearForm::GetGridFunctionEnergy(const Vector &x) const
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
MFEM_VERIFY(!fnfi.Size(), "Interior faces terms not yet implemented!");
|
||||
MFEM_VERIFY(!bfnfi.Size(), "Boundary face terms not yet implemented!");
|
||||
return ext->GetGridFunctionEnergy(x);
|
||||
}
|
||||
|
||||
Array<int> vdofs;
|
||||
Vector el_x;
|
||||
const FiniteElement *fe;
|
||||
@@ -138,6 +146,14 @@ void NonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
if (ext)
|
||||
{
|
||||
ext->Mult(px, py);
|
||||
if (Serial())
|
||||
{
|
||||
if (cP) { cP->MultTranspose(py, y); }
|
||||
const int N = ess_tdof_list.Size();
|
||||
const auto tdof = ess_tdof_list.Read();
|
||||
auto Y = y.ReadWrite();
|
||||
MFEM_FORALL(i, N, Y[tdof[i]] = 0.0; );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -264,7 +280,16 @@ Operator &NonlinearForm::GetGradient(const Vector &x) const
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
MFEM_ABORT("Not yet implemented!");
|
||||
Operator &grad = ext->GetGradient(Prolongate(x));
|
||||
hGrad.Reset(&grad, false);
|
||||
if (Serial())
|
||||
{
|
||||
Operator *Gop;
|
||||
if (cP) { hGrad.Reset(new RAPOperator(*cP, grad, *cP)); }
|
||||
hGrad.Ptr()->Operator::FormSystemOperator(ess_tdof_list, Gop);
|
||||
hGrad.Reset(Gop);
|
||||
}
|
||||
return *hGrad.Ptr();
|
||||
}
|
||||
|
||||
const int skip_zeros = 0;
|
||||
@@ -426,7 +451,31 @@ void NonlinearForm::Update()
|
||||
|
||||
void NonlinearForm::Setup()
|
||||
{
|
||||
if (ext) { return ext->AssemblePA(); }
|
||||
if (ext) { return ext->Setup(); }
|
||||
}
|
||||
|
||||
void NonlinearForm::AssembleGradientDiagonal(Vector &diag) const
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
MFEM_ASSERT(diag.Size() == fes->GetTrueVSize(),
|
||||
"Vector for holding diagonal has wrong size!");
|
||||
const Operator *P = fes->GetProlongationMatrix();
|
||||
if (!IsIdentityProlongation(P))
|
||||
{
|
||||
Vector local_diag(P->Height());
|
||||
ext->AssembleGradientDiagonal(local_diag);
|
||||
P->MultTranspose(local_diag, diag);
|
||||
}
|
||||
else
|
||||
{
|
||||
ext->AssembleGradientDiagonal(diag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Not implemented. Can be obtained through GetGradient().");
|
||||
}
|
||||
}
|
||||
|
||||
NonlinearForm::~NonlinearForm()
|
||||
|
||||
@@ -45,6 +45,7 @@ protected:
|
||||
Array<Array<int>*> bfnfi_marker; // not owned
|
||||
|
||||
mutable SparseMatrix *Grad, *cGrad; // owned
|
||||
mutable OperatorHandle hGrad;
|
||||
|
||||
/// A list of all essential true dofs
|
||||
Array<int> ess_tdof_list;
|
||||
@@ -165,6 +166,15 @@ public:
|
||||
/// Setup the NonlinearForm
|
||||
virtual void Setup();
|
||||
|
||||
/** @brief Assemble the diagonal of the gradient into diag
|
||||
|
||||
For adaptively refined meshes, this returns P^T d_e, where d_e is the
|
||||
locally assembled diagonal on each element and P^T is the transpose of
|
||||
the conforming prolongation. In general this is not the correct diagonal
|
||||
for an AMR mesh. */
|
||||
void AssembleGradientDiagonal(Vector &diag) const;
|
||||
|
||||
|
||||
/// Get the finite element space prolongation matrix
|
||||
virtual const Operator *GetProlongation() const { return P; }
|
||||
/// Get the finite element space restriction matrix
|
||||
|
||||
+79
-40
@@ -13,62 +13,101 @@
|
||||
// PABilinearFormExtension and MFBilinearFormExtension.
|
||||
|
||||
#include "nonlinearform.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
NonlinearFormExtension::NonlinearFormExtension(NonlinearForm *form)
|
||||
: Operator(form->FESpace()->GetTrueVSize()), n(form)
|
||||
NonlinearFormExtension::NonlinearFormExtension(const NonlinearForm *nlf)
|
||||
: Operator(nlf->FESpace()->GetTrueVSize()), nlf(nlf) { }
|
||||
|
||||
PANonlinearForm::PANonlinearForm(NonlinearForm *nlf):
|
||||
NonlinearFormExtension(nlf),
|
||||
x_grad(NULL),
|
||||
fes(*nlf->FESpace()),
|
||||
dnfi(*nlf->GetDNFI()),
|
||||
R(fes.GetElementRestriction(ElementDofOrdering::LEXICOGRAPHIC))
|
||||
{
|
||||
// empty
|
||||
MFEM_VERIFY(R, "Not yet implemented!");
|
||||
xe.SetSize(R->Height(), Device::GetMemoryType());
|
||||
ye.SetSize(R->Height(), Device::GetMemoryType());
|
||||
ye.UseDevice(true);
|
||||
}
|
||||
|
||||
PANonlinearFormExtension::PANonlinearFormExtension(NonlinearForm *form):
|
||||
NonlinearFormExtension(form), fes(*form->FESpace())
|
||||
double PANonlinearForm::GetGridFunctionEnergy(const Vector &x) const
|
||||
{
|
||||
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
|
||||
elem_restrict_lex = fes.GetElementRestriction(ordering);
|
||||
if (elem_restrict_lex)
|
||||
double energy = 0.0;
|
||||
|
||||
R->Mult(x, xe);
|
||||
for (int i = 0; i < dnfi.Size(); i++)
|
||||
{
|
||||
localX.SetSize(elem_restrict_lex->Height(), Device::GetMemoryType());
|
||||
localY.SetSize(elem_restrict_lex->Height(), Device::GetMemoryType());
|
||||
localY.UseDevice(true); // ensure 'localY = 0.0' is done on device
|
||||
energy += dnfi[i]->GetGridFunctionEnergyPA(xe);
|
||||
}
|
||||
return energy;
|
||||
}
|
||||
|
||||
void PANonlinearFormExtension::AssemblePA()
|
||||
void PANonlinearForm::Setup()
|
||||
{
|
||||
Array<NonlinearFormIntegrator*> &integrators = *n->GetDNFI();
|
||||
const int Ni = integrators.Size();
|
||||
for (int i = 0; i < Ni; ++i)
|
||||
{
|
||||
integrators[i]->AssemblePA(*n->FESpace());
|
||||
}
|
||||
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AssemblePA(fes); }
|
||||
}
|
||||
|
||||
void PANonlinearFormExtension::Mult(const Vector &x, Vector &y) const
|
||||
void PANonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
Array<NonlinearFormIntegrator*> &integrators = *n->GetDNFI();
|
||||
const int iSz = integrators.Size();
|
||||
if (elem_restrict_lex)
|
||||
{
|
||||
elem_restrict_lex->Mult(x, localX);
|
||||
localY = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
integrators[i]->AddMultPA(localX, localY);
|
||||
}
|
||||
elem_restrict_lex->MultTranspose(localY, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
y.UseDevice(true); // typically this is a large vector, so store on device
|
||||
y = 0.0;
|
||||
for (int i = 0; i < iSz; ++i)
|
||||
{
|
||||
integrators[i]->AddMultPA(x, y);
|
||||
}
|
||||
}
|
||||
ye = 0.0;
|
||||
R->Mult(x, xe);
|
||||
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AddMultPA(xe, ye); }
|
||||
R->MultTranspose(ye, y);
|
||||
}
|
||||
|
||||
void PANonlinearForm::AssembleGradientDiagonal(Vector &diag) const
|
||||
{
|
||||
MFEM_VERIFY(x_grad, "GetGradient() has not been called");
|
||||
R->Mult(*x_grad, xe);
|
||||
|
||||
ye = 0.0;
|
||||
for (int i = 0; i < dnfi.Size(); ++i)
|
||||
{
|
||||
dnfi[i]->AssembleGradientDiagonalPA(xe, ye);
|
||||
}
|
||||
R->MultTranspose(ye, diag);
|
||||
}
|
||||
|
||||
Operator &PANonlinearForm::GetGradient(const Vector &x) const
|
||||
{
|
||||
// Store the last x that was used to compute the gradient.
|
||||
x_grad = &x;
|
||||
|
||||
Grad.Reset(new PANonlinearForm::Gradient(x, *this));
|
||||
return *Grad.Ptr();
|
||||
}
|
||||
|
||||
PANonlinearForm::Gradient::Gradient(const Vector &x, const PANonlinearForm &e):
|
||||
Operator(e.fes.GetVSize()), R(e.R), dnfi(e.dnfi)
|
||||
{
|
||||
ge.UseDevice(true);
|
||||
ge.SetSize(R->Height(), Device::GetMemoryType());
|
||||
R->Mult(x, ge);
|
||||
|
||||
xe.UseDevice(true);
|
||||
xe.SetSize(R->Height(), Device::GetMemoryType());
|
||||
|
||||
ye.UseDevice(true);
|
||||
ye.SetSize(R->Height(), Device::GetMemoryType());
|
||||
|
||||
ze.UseDevice(true);
|
||||
ze.SetSize(R->Height(), Device::GetMemoryType());
|
||||
|
||||
// Do we still need to do this?
|
||||
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AssemblePA(e.fes); }
|
||||
}
|
||||
|
||||
void PANonlinearForm::Gradient::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
ze = x;
|
||||
ye = 0.0;
|
||||
R->Mult(ze, xe);
|
||||
for (int i = 0; i < dnfi.Size(); ++i) { dnfi[i]->AddMultGradPA(ge, xe, ye); }
|
||||
R->MultTranspose(ye, y);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+42
-10
@@ -17,28 +17,60 @@
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
class NonlinearForm;
|
||||
|
||||
class NonlinearForm;
|
||||
class NonlinearFormIntegrator;
|
||||
|
||||
/** @brief Class extending the NonlinearForm class to support the different
|
||||
AssemblyLevel%s. */
|
||||
class NonlinearFormExtension : public Operator
|
||||
{
|
||||
protected:
|
||||
NonlinearForm *n; ///< Not owned
|
||||
const NonlinearForm *nlf;
|
||||
public:
|
||||
NonlinearFormExtension(NonlinearForm *form);
|
||||
virtual void AssemblePA() = 0;
|
||||
NonlinearFormExtension(const NonlinearForm*);
|
||||
virtual void Setup() = 0;
|
||||
virtual Operator &GetGradient(const Vector&) const = 0;
|
||||
virtual double GetGridFunctionEnergy(const Vector &x) const = 0;
|
||||
virtual void AssembleGradientDiagonal(Vector &diag) const
|
||||
{
|
||||
MFEM_ABORT("Not implemented for this assembly level!");
|
||||
}
|
||||
};
|
||||
|
||||
class PANonlinearForm;
|
||||
|
||||
|
||||
/// Data and methods for partially-assembled nonlinear forms
|
||||
class PANonlinearFormExtension : public NonlinearFormExtension
|
||||
class PANonlinearForm : public NonlinearFormExtension
|
||||
{
|
||||
private:
|
||||
class Gradient : public Operator
|
||||
{
|
||||
protected:
|
||||
const Operator *R;
|
||||
mutable Vector ge, xe, ye, ze;
|
||||
const Array<NonlinearFormIntegrator*> &dnfi;
|
||||
public:
|
||||
Gradient(const Vector &x, const PANonlinearForm &ext);
|
||||
virtual void Mult(const Vector &x, Vector &y) const;
|
||||
};
|
||||
|
||||
protected:
|
||||
const FiniteElementSpace &fes; // Not owned
|
||||
mutable Vector localX, localY;
|
||||
const Operator *elem_restrict_lex; // Not owned
|
||||
mutable Vector xe, ye;
|
||||
mutable const Vector *x_grad;
|
||||
mutable OperatorHandle Grad;
|
||||
const FiniteElementSpace &fes;
|
||||
const Array<NonlinearFormIntegrator*> &dnfi;
|
||||
const Operator *R;
|
||||
|
||||
public:
|
||||
PANonlinearFormExtension(NonlinearForm*);
|
||||
void AssemblePA();
|
||||
PANonlinearForm(NonlinearForm *nlf);
|
||||
void Setup();
|
||||
void Mult(const Vector &x, Vector &y) const;
|
||||
Operator &GetGradient(const Vector &x) const;
|
||||
double GetGridFunctionEnergy(const Vector &x) const;
|
||||
void AssembleGradientDiagonal(Vector &diag) const;
|
||||
};
|
||||
}
|
||||
#endif // NONLINEARFORM_EXT_HPP
|
||||
|
||||
@@ -15,6 +15,13 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
double NonlinearFormIntegrator::GetGridFunctionEnergyPA(const Vector &x) const
|
||||
{
|
||||
mfem_error ("NonlinearFormIntegrator::GetGridFunctionEnergyPA(...)\n"
|
||||
" is not implemented for this class.");
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void NonlinearFormIntegrator::AssemblePA(const FiniteElementSpace&)
|
||||
{
|
||||
mfem_error ("NonlinearFormIntegrator::AssemblePA(...)\n"
|
||||
@@ -34,6 +41,20 @@ void NonlinearFormIntegrator::AddMultPA(const Vector &, Vector &) const
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void NonlinearFormIntegrator::AddMultGradPA(const Vector&,
|
||||
const Vector&, Vector&) const
|
||||
{
|
||||
mfem_error ("NonlinearFormIntegrator::AddMultGradPA(...)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void NonlinearFormIntegrator::AssembleGradientDiagonalPA(const mfem::Vector &x,
|
||||
mfem::Vector &diag) const
|
||||
{
|
||||
mfem_error ("NonlinearFormIntegrator::AssembleDiagonalPA(...)\n"
|
||||
" is not implemented for this class.");
|
||||
}
|
||||
|
||||
void NonlinearFormIntegrator::AssembleElementVector(
|
||||
const FiniteElement &el, ElementTransformation &Tr,
|
||||
const Vector &elfun, Vector &elvect)
|
||||
|
||||
@@ -68,6 +68,9 @@ public:
|
||||
ElementTransformation &Tr,
|
||||
const Vector &elfun);
|
||||
|
||||
/// Compute the local energy with partial assembly.
|
||||
virtual double GetGridFunctionEnergyPA(const Vector &x) const;
|
||||
|
||||
/// Method defining partial assembly.
|
||||
/** The result of the partial assembly is stored internally so that it can be
|
||||
used later in the methods AddMultPA(). */
|
||||
@@ -88,6 +91,12 @@ public:
|
||||
called. */
|
||||
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
||||
|
||||
/// Method for partially assembled gradient action.
|
||||
virtual void AddMultGradPA(const Vector &g,
|
||||
const Vector &x, Vector &y) const;
|
||||
|
||||
virtual void AssembleGradientDiagonalPA(const Vector &x, Vector &diag) const;
|
||||
|
||||
virtual ~NonlinearFormIntegrator() { }
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -3147,7 +3147,7 @@ static void SetSubVector(const int N,
|
||||
const Array<int> &indices,
|
||||
const Vector &in, Vector &out)
|
||||
{
|
||||
auto y = out.Write();
|
||||
auto y = out.ReadWrite();
|
||||
const auto x = in.Read();
|
||||
const auto I = indices.Read();
|
||||
MFEM_FORALL(i, N, y[I[i]] = x[i];);
|
||||
@@ -3234,7 +3234,7 @@ static void AddSubVector(const int num_unique_dst_indices,
|
||||
const Vector &src,
|
||||
Vector &dst)
|
||||
{
|
||||
auto y = dst.Write();
|
||||
auto y = dst.ReadWrite();
|
||||
const auto x = src.Read();
|
||||
const auto DST_I = unique_dst_indices.Read();
|
||||
const auto SRC_O = unique_to_src_offsets.Read();
|
||||
|
||||
+5
-165
@@ -655,167 +655,6 @@ void ParGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
|
||||
#endif
|
||||
}
|
||||
|
||||
double ParGridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
Coefficient *ell_coeff,
|
||||
double Nu,
|
||||
const IntegrationRule *irs[]) const
|
||||
{
|
||||
const_cast<ParGridFunction *>(this)->ExchangeFaceNbrData();
|
||||
|
||||
int fdof, dim, intorder, k;
|
||||
ElementTransformation *transf;
|
||||
Vector shape, el_dofs, err_val, ell_coeff_val;
|
||||
Array<int> vdofs;
|
||||
IntegrationPoint eip;
|
||||
double error = 0.0;
|
||||
|
||||
ParMesh *mesh = pfes->GetParMesh();
|
||||
dim = mesh->Dimension();
|
||||
|
||||
std::map<int,int> local_to_shared;
|
||||
for (int i = 0; i < mesh->GetNSharedFaces(); ++i)
|
||||
{
|
||||
int i_local = mesh->GetSharedFace(i);
|
||||
local_to_shared[i_local] = i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mesh->GetNumFaces(); i++)
|
||||
{
|
||||
double shared_face_factor = 1.0;
|
||||
bool shared_face = false;
|
||||
int iel1, iel2, info1, info2;
|
||||
mesh->GetFaceElements(i, &iel1, &iel2);
|
||||
mesh->GetFaceInfos(i, &info1, &info2);
|
||||
|
||||
intorder = fes->GetFE(iel1)->GetOrder();
|
||||
|
||||
FaceElementTransformations *face_elem_transf;
|
||||
const FiniteElement *fe1, *fe2;
|
||||
if (info2 >= 0 && iel2 < 0)
|
||||
{
|
||||
int ishared = local_to_shared[i];
|
||||
face_elem_transf = mesh->GetSharedFaceTransformations(ishared);
|
||||
iel2 = face_elem_transf->Elem2No - mesh->GetNE();
|
||||
fe2 = pfes->GetFaceNbrFE(iel2);
|
||||
if ( (k = fe2->GetOrder()) > intorder )
|
||||
{
|
||||
intorder = k;
|
||||
}
|
||||
shared_face = true;
|
||||
shared_face_factor = 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i);
|
||||
|
||||
if (iel2 >= 0)
|
||||
{
|
||||
fe2 = pfes->GetFE(iel2);
|
||||
if ( (k = fe2->GetOrder()) > intorder )
|
||||
{
|
||||
intorder = k;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fe2 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
intorder = 2 * intorder; // <-------------
|
||||
const IntegrationRule *ir;
|
||||
if (irs)
|
||||
{
|
||||
ir = irs[face_elem_transf->GetGeometryType()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &(IntRules.Get(face_elem_transf->GetGeometryType(), intorder));
|
||||
}
|
||||
err_val.SetSize(ir->GetNPoints());
|
||||
ell_coeff_val.SetSize(ir->GetNPoints());
|
||||
// side 1
|
||||
transf = face_elem_transf->Elem1;
|
||||
fe1 = fes->GetFE(iel1);
|
||||
fdof = fe1->GetDof();
|
||||
fes->GetElementVDofs(iel1, vdofs);
|
||||
shape.SetSize(fdof);
|
||||
el_dofs.SetSize(fdof);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = (*this)(vdofs[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1-vdofs[k]);
|
||||
}
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
face_elem_transf->Loc1.Transform(ir->IntPoint(j), eip);
|
||||
fe1->CalcShape(eip, shape);
|
||||
transf->SetIntPoint(&eip);
|
||||
ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
|
||||
err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
|
||||
}
|
||||
if (fe2 != NULL)
|
||||
{
|
||||
// side 2
|
||||
transf = face_elem_transf->Elem2;
|
||||
fdof = fe2->GetDof();
|
||||
shape.SetSize(fdof);
|
||||
el_dofs.SetSize(fdof);
|
||||
if (shared_face)
|
||||
{
|
||||
pfes->GetFaceNbrElementVDofs(iel2, vdofs);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = face_nbr_data[vdofs[k]];
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - face_nbr_data[-1-vdofs[k]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pfes->GetElementVDofs(iel2, vdofs);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
el_dofs(k) = (*this)(vdofs[k]);
|
||||
}
|
||||
else
|
||||
{
|
||||
el_dofs(k) = - (*this)(-1 - vdofs[k]);
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
face_elem_transf->Loc2.Transform(ir->IntPoint(j), eip);
|
||||
fe2->CalcShape(eip, shape);
|
||||
transf->SetIntPoint(&eip);
|
||||
ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
|
||||
ell_coeff_val(j) *= 0.5;
|
||||
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
|
||||
}
|
||||
}
|
||||
transf = face_elem_transf;
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
error += shared_face_factor*(ip.weight * Nu * ell_coeff_val(j) *
|
||||
pow(transf->Weight(), 1.0-1.0/(dim-1)) *
|
||||
err_val(j) * err_val(j));
|
||||
}
|
||||
}
|
||||
|
||||
error = (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
return GlobalLpNorm(2.0, error, pfes->GetComm());
|
||||
}
|
||||
|
||||
void ParGridFunction::Save(std::ostream &out) const
|
||||
{
|
||||
double *data_ = const_cast<double*>(HostRead());
|
||||
@@ -872,9 +711,9 @@ void ParGridFunction::SaveAsOne(std::ostream &out)
|
||||
int *nfdofs = new int[NRanks];
|
||||
int *nrdofs = new int[NRanks];
|
||||
|
||||
double * h_data = const_cast<double *>(this->HostRead());
|
||||
HostReadWrite();
|
||||
values[0] = data;
|
||||
|
||||
values[0] = h_data;
|
||||
nv[0] = pfes -> GetVSize();
|
||||
nvdofs[0] = pfes -> GetNVDofs();
|
||||
nedofs[0] = pfes -> GetNEDofs();
|
||||
@@ -975,7 +814,7 @@ void ParGridFunction::SaveAsOne(std::ostream &out)
|
||||
MPI_Send(&nvdofs[0], 1, MPI_INT, 0, 456, MyComm);
|
||||
MPI_Send(&nedofs[0], 1, MPI_INT, 0, 457, MyComm);
|
||||
MPI_Send(&nfdofs[0], 1, MPI_INT, 0, 458, MyComm);
|
||||
MPI_Send(h_data, nv[0], MPI_DOUBLE, 0, 460, MyComm);
|
||||
MPI_Send(data, nv[0], MPI_DOUBLE, 0, 460, MyComm);
|
||||
}
|
||||
|
||||
delete [] values;
|
||||
@@ -1021,6 +860,7 @@ double GlobalLpNorm(const double p, double loc_norm, MPI_Comm comm)
|
||||
return glob_norm;
|
||||
}
|
||||
|
||||
|
||||
void ParGridFunction::ComputeFlux(
|
||||
BilinearFormIntegrator &blfi,
|
||||
GridFunction &flux, bool wcoef, int subdomain)
|
||||
@@ -1161,6 +1001,6 @@ double L2ZZErrorEstimator(BilinearFormIntegrator &flux_integrator,
|
||||
return pow(glob_error, 1.0/norm_p);
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
}
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
@@ -283,77 +283,6 @@ public:
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns ||grad u_ex - grad u_h||_L2 for H1 or L2 elements
|
||||
virtual double ComputeGradError(VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0, GridFunction::ComputeGradError(exgrad,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns ||curl u_ex - curl u_h||_L2 for ND elements
|
||||
virtual double ComputeCurlError(VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0, GridFunction::ComputeCurlError(excurl,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns ||div u_ex - div u_h||_L2 for RT elements
|
||||
virtual double ComputeDivError(Coefficient *exdiv,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0, GridFunction::ComputeDivError(exdiv,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns the Face Jumps error for L2 elements
|
||||
virtual double ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
Coefficient *ell_coeff,
|
||||
double Nu,
|
||||
const IntegrationRule *irs[]=NULL)
|
||||
const;
|
||||
|
||||
/// Returns either the H1-seminorm or the DG Face Jumps error or both
|
||||
/// depending on norm_type = 1, 2, 3
|
||||
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
Coefficient *ell_coef, double Nu,
|
||||
int norm_type) const
|
||||
{
|
||||
return GlobalLpNorm(2.0,
|
||||
GridFunction::ComputeH1Error(exsol,exgrad,ell_coef,
|
||||
Nu, norm_type),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns the error measured in H1-norm for H1 elements or in "broken"
|
||||
/// H1-norm for L2 elements
|
||||
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0, GridFunction::ComputeH1Error(exsol,exgrad,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns the error measured H(div)-norm for RT elements
|
||||
virtual double ComputeHDivError(VectorCoefficient *exsol,
|
||||
Coefficient *exdiv,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0, GridFunction::ComputeHDivError(exsol,exdiv,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
/// Returns the error measured H(curl)-norm for ND elements
|
||||
virtual double ComputeHCurlError(VectorCoefficient *exsol,
|
||||
VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return GlobalLpNorm(2.0,
|
||||
GridFunction::ComputeHCurlError(exsol,excurl,irs),
|
||||
pfes->GetComm());
|
||||
}
|
||||
|
||||
virtual double ComputeMaxError(Coefficient *exsol[],
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
|
||||
+1
-13
@@ -21,6 +21,7 @@ namespace mfem
|
||||
void ParLinearForm::Update(ParFiniteElementSpace *pf)
|
||||
{
|
||||
if (pf) { pfes = pf; }
|
||||
|
||||
LinearForm::Update(pfes);
|
||||
}
|
||||
|
||||
@@ -30,19 +31,6 @@ void ParLinearForm::Update(ParFiniteElementSpace *pf, Vector &v, int v_offset)
|
||||
LinearForm::Update(pf,v,v_offset);
|
||||
}
|
||||
|
||||
void ParLinearForm::MakeRef(FiniteElementSpace *f, Vector &v, int v_offset)
|
||||
{
|
||||
LinearForm::MakeRef(f, v, v_offset);
|
||||
pfes = dynamic_cast<ParFiniteElementSpace*>(f);
|
||||
MFEM_ASSERT(pfes != NULL, "not a ParFiniteElementSpace");
|
||||
}
|
||||
|
||||
void ParLinearForm::MakeRef(ParFiniteElementSpace *pf, Vector &v, int v_offset)
|
||||
{
|
||||
LinearForm::MakeRef(pf, v, v_offset);
|
||||
pfes = pf;
|
||||
}
|
||||
|
||||
void ParLinearForm::ParallelAssemble(Vector &tv)
|
||||
{
|
||||
const Operator* prolong = pfes->GetProlongationMatrix();
|
||||
|
||||
+4
-25
@@ -92,27 +92,6 @@ public:
|
||||
@note This method does not perform assembly. */
|
||||
void Update(ParFiniteElementSpace *pf, Vector &v, int v_offset);
|
||||
|
||||
|
||||
/** @brief Make the ParLinearForm reference external data on a new
|
||||
FiniteElementSpace. */
|
||||
/** This method changes the FiniteElementSpace associated with the
|
||||
ParLinearForm to @a *f and sets the data of the Vector @a v (plus the @a
|
||||
v_offset) as external data in the ParLinearForm.
|
||||
|
||||
@note This version of the method will also perform bounds checks when the
|
||||
build option MFEM_DEBUG is enabled. */
|
||||
virtual void MakeRef(FiniteElementSpace *f, Vector &v, int v_offset);
|
||||
|
||||
/** @brief Make the ParLinearForm reference external data on a new
|
||||
ParFiniteElementSpace. */
|
||||
/** This method changes the ParFiniteElementSpace associated with the
|
||||
ParLinearForm to @a *pf and sets the data of the Vector @a v (plus the @a
|
||||
v_offset) as external data in the ParLinearForm.
|
||||
|
||||
@note This version of the method will also perform bounds checks when the
|
||||
build option MFEM_DEBUG is enabled. */
|
||||
void MakeRef(ParFiniteElementSpace *pf, Vector &v, int v_offset);
|
||||
|
||||
/// Assemble the vector on the true dofs, i.e. P^t v.
|
||||
void ParallelAssemble(Vector &tv);
|
||||
|
||||
@@ -120,10 +99,10 @@ public:
|
||||
HypreParVector *ParallelAssemble();
|
||||
|
||||
/// Return the action of the ParLinearForm as a linear mapping.
|
||||
/** Linear forms are linear functionals which map ParGridFunction%s to the
|
||||
real numbers. This method performs this mapping which in this case is
|
||||
equivalent as an inner product of the ParLinearForm and
|
||||
ParGridFunction. */
|
||||
/** Linear forms are linear functionals which map ParGridFunction%s to
|
||||
the real numbers. This method performs this mapping which in
|
||||
this case is equivalent as an inner product of the ParLinearForm
|
||||
and ParGridFunction. */
|
||||
double operator()(const ParGridFunction &gf) const
|
||||
{
|
||||
return InnerProduct(pfes->GetComm(), *this, gf);
|
||||
|
||||
+16
-9
@@ -14,6 +14,7 @@
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -49,6 +50,7 @@ void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
|
||||
if (fnfi.Size())
|
||||
{
|
||||
MFEM_VERIFY(!NonlinearForm::ext,"");
|
||||
// Terms over shared interior faces in parallel.
|
||||
ParFiniteElementSpace *pfes = ParFESpace();
|
||||
ParMesh *pmesh = pfes->GetParMesh();
|
||||
@@ -86,15 +88,16 @@ void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
|
||||
|
||||
P->MultTranspose(aux2, y);
|
||||
|
||||
y.HostReadWrite();
|
||||
for (int i = 0; i < ess_tdof_list.Size(); i++)
|
||||
{
|
||||
y(ess_tdof_list[i]) = 0.0;
|
||||
}
|
||||
const int N = ess_tdof_list.Size();
|
||||
const auto idx = ess_tdof_list.Read();
|
||||
auto Y = y.ReadWrite();
|
||||
MFEM_FORALL(i, N, Y[idx[i]] = 0.0; );
|
||||
}
|
||||
|
||||
const SparseMatrix &ParNonlinearForm::GetLocalGradient(const Vector &x) const
|
||||
{
|
||||
if (NonlinearForm::ext) { MFEM_ABORT("Not yet implemented!"); }
|
||||
|
||||
NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.
|
||||
|
||||
return *Grad;
|
||||
@@ -104,16 +107,20 @@ Operator &ParNonlinearForm::GetGradient(const Vector &x) const
|
||||
{
|
||||
ParFiniteElementSpace *pfes = ParFESpace();
|
||||
|
||||
pGrad.Clear();
|
||||
Operator &grad = NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.
|
||||
|
||||
NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.
|
||||
pGrad.Clear();
|
||||
|
||||
OperatorHandle dA(pGrad.Type()), Ph(pGrad.Type());
|
||||
|
||||
if (fnfi.Size() == 0)
|
||||
{
|
||||
dA.MakeSquareBlockDiag(pfes->GetComm(), pfes->GlobalVSize(),
|
||||
pfes->GetDofOffsets(), Grad);
|
||||
if (NonlinearForm::ext) { dA.Reset(&grad, false); }
|
||||
else
|
||||
{
|
||||
dA.MakeSquareBlockDiag(pfes->GetComm(), pfes->GlobalVSize(),
|
||||
pfes->GetDofOffsets(), Grad);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+406
-1137
File diff suppressed because it is too large
Load Diff
+33
-15
@@ -41,10 +41,11 @@ protected:
|
||||
const FiniteElementSpace *fespace; ///< Not owned
|
||||
const QuadratureSpace *qspace; ///< Not owned
|
||||
const IntegrationRule *IntRule; ///< Not owned
|
||||
|
||||
mutable QVectorLayout q_layout; ///< Output Q-vector layout
|
||||
mutable bool use_tensor_products; ///< Tensor product evaluation mmode
|
||||
|
||||
mutable bool use_tensor_products;
|
||||
|
||||
public:
|
||||
static const int MAX_NQ2D = 100;
|
||||
static const int MAX_ND2D = 100;
|
||||
static const int MAX_VDIM2D = 3;
|
||||
@@ -53,7 +54,6 @@ protected:
|
||||
static const int MAX_ND3D = 1000;
|
||||
static const int MAX_VDIM3D = 3;
|
||||
|
||||
public:
|
||||
enum EvalFlags
|
||||
{
|
||||
VALUES = 1 << 0, ///< Evaluate the values at quadrature points
|
||||
@@ -61,21 +61,28 @@ public:
|
||||
/** @brief Assuming the derivative at quadrature points form a matrix,
|
||||
this flag can be used to compute and store their determinants. This
|
||||
flag can only be used in Mult(). */
|
||||
DETERMINANTS = 1 << 2
|
||||
DETERMINANTS = 1 << 2,
|
||||
PHYSICAL_DERIVATIVES = 1 << 3 ///< Evaluate the physical derivatives
|
||||
};
|
||||
|
||||
QuadratureInterpolator(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir);
|
||||
const IntegrationRule &ir,
|
||||
const bool use_tensor_products = false);
|
||||
|
||||
QuadratureInterpolator(const FiniteElementSpace &fes,
|
||||
const QuadratureSpace &qs);
|
||||
const QuadratureSpace &qs,
|
||||
const bool use_tensor_products = false);
|
||||
|
||||
/** @brief Disable the use of tensor product evaluations, for tensor-product
|
||||
elements, e.g. quads and hexes. */
|
||||
/** Currently, tensor product evaluations are not implemented and this method
|
||||
has no effect. */
|
||||
void DisableTensorProducts(bool disable = true) const
|
||||
{ use_tensor_products = !disable; }
|
||||
void DisableTensorProducts() const { use_tensor_products = false; }
|
||||
|
||||
/** @brief Enable the use of tensor product evaluations, for tensor-product
|
||||
elements, e.g. quads and hexes. */
|
||||
void EnableTensorProducts() const { use_tensor_products = true; }
|
||||
|
||||
/** @brief Query the current evaluation mode. */
|
||||
bool UseTensorProducts() const { return use_tensor_products; }
|
||||
|
||||
/** @brief Query the current output Q-vector layout. The default value is
|
||||
QVectorLayout::byNODES. */
|
||||
@@ -83,8 +90,7 @@ public:
|
||||
|
||||
/** @brief Set the desired output Q-vector layout. The default value is
|
||||
QVectorLayout::byNODES. */
|
||||
void SetOutputLayout(QVectorLayout out_layout) const
|
||||
{ q_layout = out_layout; }
|
||||
void SetOutputLayout(QVectorLayout layout) const { q_layout = layout; }
|
||||
|
||||
/// Interpolate the E-vector @a e_vec to quadrature points.
|
||||
/** The @a eval_flags are a bitwise mask of constants from the EvalFlags
|
||||
@@ -99,26 +105,36 @@ public:
|
||||
Vector &q_val, Vector &q_der, Vector &q_det) const;
|
||||
|
||||
/// Interpolate the values of the E-vector @a e_vec at quadrature points.
|
||||
template <QVectorLayout>
|
||||
void Values(const Vector &e_vec, Vector &q_val) const;
|
||||
void Values(const Vector &e_vec, Vector &q_val) const;
|
||||
|
||||
/** @brief Interpolate the derivatives of the E-vector @a e_vec at quadrature
|
||||
points. */
|
||||
template <QVectorLayout>
|
||||
void Derivatives(const Vector &e_vec, Vector &q_der) const;
|
||||
void Derivatives(const Vector &e_vec, Vector &q_der) const;
|
||||
|
||||
/** @brief Interpolate the derivatives in physical space of the E-vector
|
||||
@a e_vec at quadrature points. */
|
||||
template <QVectorLayout>
|
||||
void PhysDerivatives(const Vector &e_vec, Vector &q_der) const;
|
||||
void PhysDerivatives(const Vector &e_vec, Vector &q_der) const;
|
||||
|
||||
/// Compute the determinant of the E-vector @a e_vec at quadrature points.
|
||||
void Determinants(const Vector &e_vec, Vector &q_det) const;
|
||||
|
||||
/// Perform the transpose operation of Mult(). (TODO)
|
||||
void MultTranspose(unsigned eval_flags, const Vector &q_val,
|
||||
const Vector &q_der, Vector &e_vec) const;
|
||||
|
||||
// Compute kernels follow (cannot be private or protected with nvcc)
|
||||
|
||||
/// Template compute kernel for 2D.
|
||||
template<const int T_VDIM = 0, const int T_ND = 0, const int T_NQ = 0>
|
||||
static void Eval2D(const int NE,
|
||||
static void Mult2D(const int NE,
|
||||
const int vdim,
|
||||
const QVectorLayout q_layout,
|
||||
const GeometricFactors *geom,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val,
|
||||
@@ -128,8 +144,10 @@ public:
|
||||
|
||||
/// Template compute kernel for 3D.
|
||||
template<const int T_VDIM = 0, const int T_ND = 0, const int T_NQ = 0>
|
||||
static void Eval3D(const int NE,
|
||||
static void Mult3D(const int NE,
|
||||
const int vdim,
|
||||
const QVectorLayout q_layout,
|
||||
const GeometricFactors *geom,
|
||||
const DofToQuad &maps,
|
||||
const Vector &e_vec,
|
||||
Vector &q_val,
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "tmop_pa.hpp"
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
#include "../fem/kernels.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<int T_D1D = 0, int T_Q1D = 0, int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Det2D(const int NE,
|
||||
const double *b,
|
||||
const double *g,
|
||||
const double *x,
|
||||
double *y,
|
||||
const int vdim = 1,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
constexpr int NBZ = 1;
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto B = Reshape(b, Q1D, D1D);
|
||||
const auto G = Reshape(g, Q1D, D1D);
|
||||
const auto X = Reshape(x, D1D, D1D, DIM, NE);
|
||||
auto Y = Reshape(y, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
constexpr int NBZ = 1;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double XY[2][NBZ][MD1*MD1];
|
||||
MFEM_SHARED double DQ[4][NBZ][MD1*MQ1];
|
||||
MFEM_SHARED double QQ[4][NBZ][MQ1*MQ1];
|
||||
|
||||
kernels::LoadX<MD1,NBZ>(e,D1D,X,XY);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,B,G,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1,NBZ>(D1D,Q1D,BG,XY,DQ);
|
||||
kernels::GradY<MD1,MQ1,NBZ>(D1D,Q1D,BG,DQ,QQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double J[4];
|
||||
kernels::PullGrad<MQ1,NBZ>(qx,qy,QQ,J);
|
||||
Y(qx,qy,e) = kernels::Det<2>(J);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<int T_D1D = 0, int T_Q1D = 0, int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Det3D(const int NE,
|
||||
const double *b,
|
||||
const double *g,
|
||||
const double *x,
|
||||
double *y,
|
||||
const int vdim = 1,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
constexpr int DIM = 3;
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
|
||||
const auto B = Reshape(b, Q1D, D1D);
|
||||
const auto G = Reshape(g, Q1D, D1D);
|
||||
const auto X = Reshape(x, D1D, D1D, D1D, DIM, NE);
|
||||
auto Y = Reshape(y, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MDQ = MQ1 > MD1 ? MQ1 : MD1;
|
||||
|
||||
MFEM_SHARED double BG[2][MQ1*MD1];
|
||||
MFEM_SHARED double sm0[9][MDQ*MDQ*MDQ];
|
||||
MFEM_SHARED double sm1[9][MDQ*MDQ*MDQ];
|
||||
|
||||
double (*DDD)[MD1*MD1*MD1] = (double (*)[MD1*MD1*MD1]) (sm0);
|
||||
double (*DDQ)[MD1*MD1*MQ1] = (double (*)[MD1*MD1*MQ1]) (sm1);
|
||||
double (*DQQ)[MD1*MQ1*MQ1] = (double (*)[MD1*MQ1*MQ1]) (sm0);
|
||||
double (*QQQ)[MQ1*MQ1*MQ1] = (double (*)[MQ1*MQ1*MQ1]) (sm1);
|
||||
|
||||
kernels::LoadX<MD1>(e,D1D,X,DDD);
|
||||
kernels::LoadBG<MD1,MQ1>(D1D,Q1D,B,G,BG);
|
||||
|
||||
kernels::GradX<MD1,MQ1>(D1D,Q1D,BG,DDD,DDQ);
|
||||
kernels::GradY<MD1,MQ1>(D1D,Q1D,BG,DDQ,DQQ);
|
||||
kernels::GradZ<MD1,MQ1>(D1D,Q1D,BG,DQQ,QQQ);
|
||||
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double J[9];
|
||||
kernels::PullGrad<MQ1>(qx,qy,qz, QQQ, J);
|
||||
Y(qx,qy,qz,e) = kernels::Det<3>(J);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void QuadratureInterpolator::Determinants(const Vector &e_vec,
|
||||
Vector &q_det) const
|
||||
{
|
||||
if (use_tensor_products)
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const double *B = maps.B.Read();
|
||||
const double *G = maps.G.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_det.Write();
|
||||
|
||||
const int id = (dim<<12) | (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0x2222: return Det2D<2,2>(NE,B,G,X,Y);
|
||||
case 0x2223: return Det2D<2,3>(NE,B,G,X,Y);
|
||||
case 0x2224: return Det2D<2,4>(NE,B,G,X,Y);
|
||||
case 0x2226: return Det2D<2,6>(NE,B,G,X,Y);
|
||||
case 0x2234: return Det2D<3,4>(NE,B,G,X,Y);
|
||||
case 0x2236: return Det2D<3,6>(NE,B,G,X,Y);
|
||||
case 0x2244: return Det2D<4,4>(NE,B,G,X,Y);
|
||||
case 0x2246: return Det2D<4,6>(NE,B,G,X,Y);
|
||||
case 0x2256: return Det2D<5,6>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3324: return Det3D<2,4>(NE,B,G,X,Y);
|
||||
case 0x3333: return Det3D<3,3>(NE,B,G,X,Y);
|
||||
case 0x3335: return Det3D<3,5>(NE,B,G,X,Y);
|
||||
case 0x3336: return Det3D<3,6>(NE,B,G,X,Y);
|
||||
//case 0x3348: return Det3D<4,8>(NE,B,G,X,Y);
|
||||
|
||||
default:
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
constexpr int MD1 = 8;
|
||||
constexpr int MQ1 = 8;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
return Det2D<0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D);
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
constexpr int MD1 = 6;
|
||||
constexpr int MQ1 = 6;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
return Det3D<0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
MFEM_ABORT("Kernel " << std::hex << id << std::dec << " not supported yet");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector empty;
|
||||
Mult(e_vec, DETERMINANTS, empty, empty, q_det);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -0,0 +1,233 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<QVectorLayout Q_LAYOUT,
|
||||
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
|
||||
int T_NBZ = 1, int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Eval2D(const int NE,
|
||||
const double *b_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
|
||||
Reshape(y_, Q1D, Q1D, VDIM, NE):
|
||||
Reshape(y_, VDIM, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
|
||||
MFEM_SHARED double s_B[MQ1*MD1];
|
||||
DeviceTensor<2,double> B(s_B, Q1D, D1D);
|
||||
|
||||
MFEM_SHARED double s_DD[NBZ][MD1*MD1];
|
||||
DeviceTensor<2,double> DD((double*)(s_DD+tidz), MD1, MD1);
|
||||
|
||||
MFEM_SHARED double s_DQ[NBZ][MD1*MQ1];
|
||||
DeviceTensor<2,double> DQ((double*)(s_DQ+tidz), MD1, MQ1);
|
||||
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B(q,d) = b(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
DD(dx,dy) = x(dx,dy,c,e);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
u += B(qx,dx) * DD(dx,dy);
|
||||
}
|
||||
DQ(dy,qx) = u;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
u += DQ(dy,qx) * B(qy,dy);
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM) { y(c,qx,qy,e) = u; }
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES) { y(qx,qy,c,e) = u; }
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<QVectorLayout Q_LAYOUT,
|
||||
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
|
||||
int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Eval3D(const int NE,
|
||||
const double *b_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
|
||||
Reshape(y_, Q1D, Q1D, Q1D, VDIM, NE):
|
||||
Reshape(y_, VDIM, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
|
||||
MFEM_SHARED double s_B[MQ1*MD1];
|
||||
DeviceTensor<2,double> B(s_B, Q1D, D1D);
|
||||
|
||||
MFEM_SHARED double sm0[MDQ*MDQ*MDQ];
|
||||
MFEM_SHARED double sm1[MDQ*MDQ*MDQ];
|
||||
DeviceTensor<3,double> DDD(sm0, MD1, MD1, MD1);
|
||||
DeviceTensor<3,double> DDQ(sm1, MD1, MD1, MQ1);
|
||||
DeviceTensor<3,double> DQQ(sm0, MD1, MQ1, MQ1);
|
||||
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B(q,d) = b(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
DDD(dx,dy,dz) = x(dx,dy,dz,c,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
u += B(qx,dx) * DDD(dx,dy,dz);
|
||||
}
|
||||
DDQ(dz,dy,qx) = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
u += DDQ(dz,dy,qx) * B(qy,dy);
|
||||
}
|
||||
DQQ(dz,qy,qx) = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
u += DQQ(dz,qy,qx) * B(qz,dz);
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM) { y(c,qx,qy,qz,e) = u; }
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES) { y(qx,qy,qz,c,e) = u; }
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "quadinterpolator_eval.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<>
|
||||
void QuadratureInterpolator::Values<QVectorLayout::byNODES>(
|
||||
const Vector &e_vec, Vector &q_val) const
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const double *B = maps.B.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_val.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byNODES;
|
||||
|
||||
const int id = (dim<<12) | (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0x2133: return Eval2D<L,1,3,3>(NE,B,X,Y);
|
||||
case 0x2124: return Eval2D<L,1,2,4>(NE,B,X,Y);
|
||||
case 0x2132: return Eval2D<L,1,3,2>(NE,B,X,Y);
|
||||
case 0x2134: return Eval2D<L,1,3,4>(NE,B,X,Y);
|
||||
case 0x2143: return Eval2D<L,1,4,3>(NE,B,X,Y);
|
||||
case 0x2144: return Eval2D<L,1,4,4>(NE,B,X,Y);
|
||||
|
||||
case 0x2222: return Eval2D<L,2,2,2>(NE,B,X,Y);
|
||||
case 0x2223: return Eval2D<L,2,2,3>(NE,B,X,Y);
|
||||
case 0x2224: return Eval2D<L,2,2,4>(NE,B,X,Y);
|
||||
case 0x2225: return Eval2D<L,2,2,5>(NE,B,X,Y);
|
||||
case 0x2226: return Eval2D<L,2,2,6>(NE,B,X,Y);
|
||||
case 0x2233: return Eval2D<L,2,3,3>(NE,B,X,Y);
|
||||
case 0x2234: return Eval2D<L,2,3,4>(NE,B,X,Y);
|
||||
case 0x2236: return Eval2D<L,2,3,6>(NE,B,X,Y);
|
||||
case 0x2243: return Eval2D<L,2,4,3>(NE,B,X,Y);
|
||||
case 0x2244: return Eval2D<L,2,4,4>(NE,B,X,Y);
|
||||
case 0x2245: return Eval2D<L,2,4,5>(NE,B,X,Y);
|
||||
case 0x2246: return Eval2D<L,2,4,6>(NE,B,X,Y);
|
||||
case 0x2247: return Eval2D<L,2,4,7>(NE,B,X,Y);
|
||||
case 0x2256: return Eval2D<L,2,5,6>(NE,B,X,Y);
|
||||
|
||||
case 0x3124: return Eval3D<L,1,2,4>(NE,B,X,Y);
|
||||
case 0x3133: return Eval3D<L,1,3,3>(NE,B,X,Y);
|
||||
case 0x3134: return Eval3D<L,1,3,4>(NE,B,X,Y);
|
||||
case 0x3136: return Eval3D<L,1,3,6>(NE,B,X,Y);
|
||||
case 0x3143: return Eval3D<L,1,4,3>(NE,B,X,Y);
|
||||
case 0x3144: return Eval3D<L,1,4,4>(NE,B,X,Y);
|
||||
case 0x3148: return Eval3D<L,1,4,8>(NE,B,X,Y);
|
||||
|
||||
case 0x3222: return Eval3D<L,2,2,2>(NE,B,X,Y);
|
||||
case 0x3223: return Eval3D<L,2,2,3>(NE,B,X,Y);
|
||||
case 0x3234: return Eval3D<L,2,3,4>(NE,B,X,Y);
|
||||
|
||||
case 0x3323: return Eval3D<L,3,2,3>(NE,B,X,Y);
|
||||
case 0x3324: return Eval3D<L,3,2,4>(NE,B,X,Y);
|
||||
case 0x3325: return Eval3D<L,3,2,5>(NE,B,X,Y);
|
||||
case 0x3326: return Eval3D<L,3,2,6>(NE,B,X,Y);
|
||||
case 0x3333: return Eval3D<L,3,3,3>(NE,B,X,Y);
|
||||
case 0x3334: return Eval3D<L,3,3,4>(NE,B,X,Y);
|
||||
case 0x3335: return Eval3D<L,3,3,5>(NE,B,X,Y);
|
||||
case 0x3336: return Eval3D<L,3,3,6>(NE,B,X,Y);
|
||||
case 0x3343: return Eval3D<L,3,4,3>(NE,B,X,Y);
|
||||
case 0x3344: return Eval3D<L,3,4,4>(NE,B,X,Y);
|
||||
case 0x3346: return Eval3D<L,3,4,6>(NE,B,X,Y);
|
||||
case 0x3347: return Eval3D<L,3,4,7>(NE,B,X,Y);
|
||||
case 0x3348: return Eval3D<L,3,4,8>(NE,B,X,Y);
|
||||
|
||||
default:
|
||||
{
|
||||
constexpr int MD1 = 8;
|
||||
constexpr int MQ1 = 8;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
if (dim == 2) { Eval2D<L,0,0,0,0,MD1,MQ1>(NE,B,X,Y,vdim,D1D,Q1D); }
|
||||
if (dim == 3) { Eval3D<L,0,0,0,MD1,MQ1>(NE,B,X,Y,vdim,D1D,Q1D); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "quadinterpolator_eval.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<>
|
||||
void QuadratureInterpolator::Values<QVectorLayout::byVDIM>(
|
||||
const Vector &e_vec, Vector &q_val) const
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const double *B = maps.B.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_val.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byVDIM;
|
||||
|
||||
const int id = (dim<<12) | (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0x2124: return Eval2D<L,1,2,4,8>(NE,B,X,Y);
|
||||
case 0x2136: return Eval2D<L,1,3,6,4>(NE,B,X,Y);
|
||||
case 0x2148: return Eval2D<L,1,4,8,2>(NE,B,X,Y);
|
||||
|
||||
case 0x2224: return Eval2D<L,2,2,4,8>(NE,B,X,Y);
|
||||
case 0x2234: return Eval2D<L,2,3,4,8>(NE,B,X,Y);
|
||||
case 0x2236: return Eval2D<L,2,3,6,4>(NE,B,X,Y);
|
||||
case 0x2248: return Eval2D<L,2,4,8,2>(NE,B,X,Y);
|
||||
|
||||
case 0x3124: return Eval3D<L,1,2,4>(NE,B,X,Y);
|
||||
case 0x3136: return Eval3D<L,1,3,6>(NE,B,X,Y);
|
||||
case 0x3148: return Eval3D<L,1,4,8>(NE,B,X,Y);
|
||||
|
||||
case 0x3324: return Eval3D<L,3,2,4>(NE,B,X,Y);
|
||||
case 0x3336: return Eval3D<L,3,3,6>(NE,B,X,Y);
|
||||
case 0x3348: return Eval3D<L,3,4,8>(NE,B,X,Y);
|
||||
|
||||
default:
|
||||
{
|
||||
constexpr int MD1 = 8;
|
||||
constexpr int MQ1 = 8;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
if (dim == 2) { Eval2D<L,0,0,0,0,MD1,MQ1>(NE,B,X,Y,vdim,D1D,Q1D); }
|
||||
if (dim == 3) { Eval3D<L,0,0,0,MD1,MQ1>(NE,B,X,Y,vdim,D1D,Q1D); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -495,8 +495,9 @@ void FaceQuadratureInterpolator::Mult(
|
||||
}
|
||||
}
|
||||
|
||||
void FaceQuadratureInterpolator::Values(
|
||||
const Vector &e_vec, Vector &q_val) const
|
||||
|
||||
void FaceQuadratureInterpolator::Values(const Vector &e_vec,
|
||||
Vector &q_val) const
|
||||
{
|
||||
Vector q_der, q_det, q_nor;
|
||||
Mult(e_vec, VALUES, q_val, q_der, q_det, q_nor);
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
#include "../linalg/kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<QVectorLayout Q_LAYOUT,
|
||||
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
|
||||
int T_NBZ = 1, int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Grad2D(const int NE,
|
||||
const double *b_,
|
||||
const double *g_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto g = Reshape(g_, Q1D, D1D);
|
||||
const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT ==QVectorLayout:: byNODES ?
|
||||
Reshape(y_, Q1D, Q1D, VDIM, 2, NE):
|
||||
Reshape(y_, VDIM, 2, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
MFEM_SHARED double s_B[MQ1*MD1];
|
||||
MFEM_SHARED double s_G[MQ1*MD1];
|
||||
DeviceTensor<2,double> B(s_B, Q1D, D1D);
|
||||
DeviceTensor<2,double> G(s_G, Q1D, D1D);
|
||||
|
||||
MFEM_SHARED double s_X[NBZ][MD1*MD1];
|
||||
DeviceTensor<2,double> X((double*)(s_X+tidz), MD1, MD1);
|
||||
|
||||
MFEM_SHARED double s_DQ[2][NBZ][MD1*MQ1];
|
||||
DeviceTensor<2,double> DQ0((double*)(s_DQ[0]+tidz), MD1, MQ1);
|
||||
DeviceTensor<2,double> DQ1((double*)(s_DQ[1]+tidz), MD1, MQ1);
|
||||
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B(q,d) = b(q,d);
|
||||
G(q,d) = g(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int c = 0; c < VDIM; ++c)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
X(dx,dy) = x(dx,dy,c,e);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double input = X(dx,dy);
|
||||
u += input * B(qx,dx);
|
||||
v += input * G(qx,dx);
|
||||
}
|
||||
DQ0(dy,qx) = u;
|
||||
DQ1(dy,qx) = v;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
u += DQ1(dy,qx) * B(qy,dy);
|
||||
v += DQ0(dy,qx) * G(qy,dy);
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES)
|
||||
{
|
||||
y(qx,qy,c,0,e) = u;
|
||||
y(qx,qy,c,1,e) = v;
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM)
|
||||
{
|
||||
y(c,0,qx,qy,e) = u;
|
||||
y(c,1,qx,qy,e) = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template<QVectorLayout Q_LAYOUT,
|
||||
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
|
||||
int MAX_D1D = 0, int MAX_Q1D = 0>
|
||||
static void Grad3D(const int NE,
|
||||
const double *b_,
|
||||
const double *g_,
|
||||
const double *x_,
|
||||
double *y_,
|
||||
const int vdim = 0,
|
||||
const int d1d = 0,
|
||||
const int q1d = 0)
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
|
||||
const auto b = Reshape(b_, Q1D, D1D);
|
||||
const auto g = Reshape(g_, Q1D, D1D);
|
||||
const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
|
||||
auto y = Q_LAYOUT ==QVectorLayout:: byNODES ?
|
||||
Reshape(y_, Q1D, Q1D, Q1D, VDIM, 3, NE):
|
||||
Reshape(y_, VDIM, 3, Q1D, Q1D, Q1D, NE);
|
||||
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
const int D1D = T_D1D ? T_D1D : d1d;
|
||||
const int Q1D = T_Q1D ? T_Q1D : q1d;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int MQ1 = T_Q1D ? T_Q1D : MAX_Q1D;
|
||||
constexpr int MD1 = T_D1D ? T_D1D : MAX_D1D;
|
||||
|
||||
const int tidz = MFEM_THREAD_ID(z);
|
||||
MFEM_SHARED double s_B[MQ1*MD1];
|
||||
MFEM_SHARED double s_G[MQ1*MD1];
|
||||
DeviceTensor<2,double> B(s_B, Q1D, D1D);
|
||||
DeviceTensor<2,double> G(s_G, Q1D, D1D);
|
||||
|
||||
MFEM_SHARED double sm0[3][MQ1*MQ1*MQ1];
|
||||
MFEM_SHARED double sm1[3][MQ1*MQ1*MQ1];
|
||||
DeviceTensor<3,double> X((double*)(sm0+2), MD1, MD1, MD1);
|
||||
DeviceTensor<3,double> DDQ0((double*)(sm0+0), MD1, MD1, MQ1);
|
||||
DeviceTensor<3,double> DDQ1((double*)(sm0+1), MD1, MD1, MQ1);
|
||||
DeviceTensor<3,double> DQQ0((double*)(sm1+0), MD1, MQ1, MQ1);
|
||||
DeviceTensor<3,double> DQQ1((double*)(sm1+1), MD1, MQ1, MQ1);
|
||||
DeviceTensor<3,double> DQQ2((double*)(sm1+2), MD1, MQ1, MQ1);
|
||||
|
||||
if (tidz == 0)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(d,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(q,x,Q1D)
|
||||
{
|
||||
B(q,d) = b(q,d);
|
||||
G(q,d) = g(q,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int c = 0; c < VDIM; ++c)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dx,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
X(dx,dy,dz) = x(dx,dy,dz,c,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(dy,y,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
for (int dx = 0; dx < D1D; ++dx)
|
||||
{
|
||||
const double input = X(dx,dy,dz);
|
||||
u += input * B(qx,dx);
|
||||
v += input * G(qx,dx);
|
||||
}
|
||||
DDQ0(dz,dy,qx) = u;
|
||||
DDQ1(dz,dy,qx) = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(dz,z,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
double w = 0.0;
|
||||
for (int dy = 0; dy < D1D; ++dy)
|
||||
{
|
||||
u += DDQ1(dz,dy,qx) * B(qy,dy);
|
||||
v += DDQ0(dz,dy,qx) * G(qy,dy);
|
||||
w += DDQ0(dz,dy,qx) * B(qy,dy);
|
||||
}
|
||||
DQQ0(dz,qy,qx) = u;
|
||||
DQQ1(dz,qy,qx) = v;
|
||||
DQQ2(dz,qy,qx) = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
double u = 0.0;
|
||||
double v = 0.0;
|
||||
double w = 0.0;
|
||||
for (int dz = 0; dz < D1D; ++dz)
|
||||
{
|
||||
u += DQQ0(dz,qy,qx) * B(qz,dz);
|
||||
v += DQQ1(dz,qy,qx) * B(qz,dz);
|
||||
w += DQQ2(dz,qy,qx) * G(qz,dz);
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byNODES)
|
||||
{
|
||||
y(qx,qy,qz,c,0,e) = u;
|
||||
y(qx,qy,qz,c,1,e) = v;
|
||||
y(qx,qy,qz,c,2,e) = w;
|
||||
}
|
||||
if (Q_LAYOUT == QVectorLayout::byVDIM)
|
||||
{
|
||||
y(c,0,qx,qy,qz,e) = u;
|
||||
y(c,1,qx,qy,qz,e) = v;
|
||||
y(c,2,qx,qy,qz,e) = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "quadinterpolator_grad.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<>
|
||||
void QuadratureInterpolator::Derivatives<QVectorLayout::byNODES>(
|
||||
const Vector &e_vec, Vector &q_der) const
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const double *B = maps.B.Read();
|
||||
const double *G = maps.G.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_der.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byNODES;
|
||||
|
||||
const int id = (dim<<12) | (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0x2133: return Grad2D<L,1,3,3,16>(NE,B,G,X,Y);
|
||||
case 0x2134: return Grad2D<L,1,3,4,16>(NE,B,G,X,Y);
|
||||
case 0x2143: return Grad2D<L,1,4,3,16>(NE,B,G,X,Y);
|
||||
case 0x2144: return Grad2D<L,1,4,4,16>(NE,B,G,X,Y);
|
||||
|
||||
case 0x2222: return Grad2D<L,2,2,2,16>(NE,B,G,X,Y);
|
||||
case 0x2223: return Grad2D<L,2,2,3,8>(NE,B,G,X,Y);
|
||||
case 0x2224: return Grad2D<L,2,2,4,4>(NE,B,G,X,Y);
|
||||
case 0x2225: return Grad2D<L,2,2,5,4>(NE,B,G,X,Y);
|
||||
case 0x2226: return Grad2D<L,2,2,6,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x2233: return Grad2D<L,2,3,3,2>(NE,B,G,X,Y);
|
||||
case 0x2234: return Grad2D<L,2,3,4,4>(NE,B,G,X,Y);
|
||||
case 0x2243: return Grad2D<L,2,4,3,4>(NE,B,G,X,Y);
|
||||
case 0x2236: return Grad2D<L,2,3,6,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x2244: return Grad2D<L,2,4,4,2>(NE,B,G,X,Y);
|
||||
case 0x2245: return Grad2D<L,2,4,5,2>(NE,B,G,X,Y);
|
||||
case 0x2246: return Grad2D<L,2,4,6,2>(NE,B,G,X,Y);
|
||||
case 0x2247: return Grad2D<L,2,4,7,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x2256: return Grad2D<L,2,5,6,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3124: return Grad3D<L,1,2,4>(NE,B,G,X,Y);
|
||||
case 0x3133: return Grad3D<L,1,3,3>(NE,B,G,X,Y);
|
||||
case 0x3134: return Grad3D<L,1,3,4>(NE,B,G,X,Y);
|
||||
case 0x3136: return Grad3D<L,1,3,6>(NE,B,G,X,Y);
|
||||
case 0x3144: return Grad3D<L,1,4,4>(NE,B,G,X,Y);
|
||||
case 0x3148: return Grad3D<L,1,4,8>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3323: return Grad3D<L,3,2,3>(NE,B,G,X,Y);
|
||||
case 0x3324: return Grad3D<L,3,2,4>(NE,B,G,X,Y);
|
||||
case 0x3325: return Grad3D<L,3,2,5>(NE,B,G,X,Y);
|
||||
case 0x3326: return Grad3D<L,3,2,6>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3333: return Grad3D<L,3,3,3>(NE,B,G,X,Y);
|
||||
case 0x3334: return Grad3D<L,3,3,4>(NE,B,G,X,Y);
|
||||
case 0x3335: return Grad3D<L,3,3,5>(NE,B,G,X,Y);
|
||||
case 0x3336: return Grad3D<L,3,3,6>(NE,B,G,X,Y);
|
||||
case 0x3344: return Grad3D<L,3,4,4>(NE,B,G,X,Y);
|
||||
case 0x3346: return Grad3D<L,3,4,6>(NE,B,G,X,Y);
|
||||
case 0x3347: return Grad3D<L,3,4,7>(NE,B,G,X,Y);
|
||||
case 0x3348: return Grad3D<L,3,4,8>(NE,B,G,X,Y);
|
||||
default:
|
||||
{
|
||||
constexpr int MD1 = 8;
|
||||
constexpr int MQ1 = 8;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
if (dim == 2)
|
||||
{
|
||||
return Grad2D<L,0,0,0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D);
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
return Grad3D<L,0,0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D);
|
||||
}
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "quadinterpolator.hpp"
|
||||
#include "quadinterpolator_grad.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
template<>
|
||||
void QuadratureInterpolator::Derivatives<QVectorLayout::byVDIM>(
|
||||
const Vector &e_vec, Vector &q_der) const
|
||||
{
|
||||
const int NE = fespace->GetNE();
|
||||
if (NE == 0) { return; }
|
||||
|
||||
const int vdim = fespace->GetVDim();
|
||||
const int dim = fespace->GetMesh()->Dimension();
|
||||
const FiniteElement *fe = fespace->GetFE(0);
|
||||
const IntegrationRule *ir =
|
||||
IntRule ? IntRule : &qspace->GetElementIntRule(0);
|
||||
const DofToQuad &maps = fe->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int D1D = maps.ndof;
|
||||
const int Q1D = maps.nqpt;
|
||||
const double *B = maps.B.Read();
|
||||
const double *G = maps.G.Read();
|
||||
const double *X = e_vec.Read();
|
||||
double *Y = q_der.Write();
|
||||
|
||||
constexpr QVectorLayout L = QVectorLayout::byVDIM;
|
||||
|
||||
const int id = (dim<<12) | (vdim<<8) | (D1D<<4) | Q1D;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0x2134: return Grad2D<L,1,3,4,8>(NE,B,G,X,Y);
|
||||
case 0x2146: return Grad2D<L,1,4,6,4>(NE,B,G,X,Y);
|
||||
case 0x2158: return Grad2D<L,1,5,8,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x2234: return Grad2D<L,2,3,4,8>(NE,B,G,X,Y);
|
||||
case 0x2246: return Grad2D<L,2,4,6,4>(NE,B,G,X,Y);
|
||||
case 0x2258: return Grad2D<L,2,5,8,2>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3134: return Grad3D<L,1,3,4>(NE,B,G,X,Y);
|
||||
case 0x3146: return Grad3D<L,1,4,6>(NE,B,G,X,Y);
|
||||
case 0x3158: return Grad3D<L,1,5,8>(NE,B,G,X,Y);
|
||||
|
||||
case 0x3334: return Grad3D<L,3,3,4>(NE,B,G,X,Y);
|
||||
case 0x3346: return Grad3D<L,3,4,6>(NE,B,G,X,Y);
|
||||
case 0x3358: return Grad3D<L,3,5,8>(NE,B,G,X,Y);
|
||||
default:
|
||||
{
|
||||
constexpr int MD1 = 8;
|
||||
constexpr int MQ1 = 8;
|
||||
MFEM_VERIFY(D1D <= MD1, "Orders higher than " << MD1-1
|
||||
<< " are not supported!");
|
||||
MFEM_VERIFY(Q1D <= MQ1, "Quadrature rules with more than "
|
||||
<< MQ1 << " 1D points are not supported!");
|
||||
if (dim == 2) { Grad2D<L,0,0,0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D); }
|
||||
if (dim == 3) { Grad3D<L,0,0,0,MD1,MQ1>(NE,B,G,X,Y,vdim,D1D,Q1D); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
mfem::out << "Unknown kernel 0x" << std::hex << id << std::endl;
|
||||
MFEM_ABORT("Kernel not supported yet");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user