Compare commits
245
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc39660801 | ||
|
|
a72cd6b7a8 | ||
|
|
bcc308b263 | ||
|
|
23b5e402e3 | ||
|
|
ee0dd42064 | ||
|
|
39a78ff3df | ||
|
|
20460cafda | ||
|
|
2f188e9fcf | ||
|
|
e772d71ecb | ||
|
|
d9c4cad220 | ||
|
|
0c572d4779 | ||
|
|
4320ad2272 | ||
|
|
5c09d2b4c9 | ||
|
|
65e75e271b | ||
|
|
f8e5fe77e6 | ||
|
|
4ff880f0cf | ||
|
|
a1f57a6375 | ||
|
|
5ffb605333 | ||
|
|
f8ea695e13 | ||
|
|
fe525828ab | ||
|
|
a275e75549 | ||
|
|
119451df1a | ||
|
|
c8801d0d27 | ||
|
|
ff993ffb1b | ||
|
|
69d96008ae | ||
|
|
72b0bdbcef | ||
|
|
ea5c466486 | ||
|
|
82bc4f058d | ||
|
|
c416dddeae | ||
|
|
7aa6e58d07 | ||
|
|
df01ea1554 | ||
|
|
563b8d455a | ||
|
|
e28ed04f52 | ||
|
|
1406569993 | ||
|
|
c5b77f1dca | ||
|
|
220b22f33b | ||
|
|
1789cb6d3f | ||
|
|
d1689afc84 | ||
|
|
023552d99f | ||
|
|
1f89a88844 | ||
|
|
d3d3b6b1c5 | ||
|
|
5a0414146c | ||
|
|
e90514c51f | ||
|
|
715175844d | ||
|
|
af73e58ffc | ||
|
|
534194bb74 | ||
|
|
13cccd6c66 | ||
|
|
06beca6d83 | ||
|
|
fb2b2f0067 | ||
|
|
9484091bce | ||
|
|
78706f96dc | ||
|
|
92e11e48f8 | ||
|
|
42102085ec | ||
|
|
4d95303bf3 | ||
|
|
1399f10675 | ||
|
|
d4b6deeeb7 | ||
|
|
93f7e778cd | ||
|
|
8c62969dc7 | ||
|
|
29ec82fcb9 | ||
|
|
1303b3e251 | ||
|
|
93940754a3 | ||
|
|
69541be811 | ||
|
|
5937a85546 | ||
|
|
5061dbd214 | ||
|
|
7ded5aae7a | ||
|
|
e110cd4554 | ||
|
|
e163306242 | ||
|
|
096c5f8db7 | ||
|
|
1b8e5e3717 | ||
|
|
61b394409b | ||
|
|
1698c06900 | ||
|
|
48e3de797c | ||
|
|
f7f20e8542 | ||
|
|
dd40e443c1 | ||
|
|
7ad3cd3509 | ||
|
|
371047e628 | ||
|
|
fd4bf50a71 | ||
|
|
fa89fbfc71 | ||
|
|
8805b1fd98 | ||
|
|
32d62a23a3 | ||
|
|
35300fa1b6 | ||
|
|
d5f46a61bc | ||
|
|
538ec0b33d | ||
|
|
2e8c7a1c07 | ||
|
|
c33a8cebb4 | ||
|
|
52162982a8 | ||
|
|
69c52e55bd | ||
|
|
23b0fa7e3c | ||
|
|
13504d6116 | ||
|
|
9aa6b00053 | ||
|
|
a059294d02 | ||
|
|
2e8750410e | ||
|
|
33635307cf | ||
|
|
75b1906749 | ||
|
|
271c63fbee | ||
|
|
ad37c6af78 | ||
|
|
64e61fdc3e | ||
|
|
ce74176355 | ||
|
|
6acba0c1f0 | ||
|
|
caa1e2c7ae | ||
|
|
e70e80da3f | ||
|
|
2c6d541745 | ||
|
|
a92e1600e3 | ||
|
|
f271e9d549 | ||
|
|
2f6eb8838f | ||
|
|
cbfbe68651 | ||
|
|
8358ce040b | ||
|
|
b4934a836c | ||
|
|
446eda52c7 | ||
|
|
0a3f8bdea5 | ||
|
|
b62e11cd34 | ||
|
|
61613ae1a5 | ||
|
|
4c9157bd30 | ||
|
|
21c3272e3f | ||
|
|
62c65660c8 | ||
|
|
16d20ff17f | ||
|
|
d3a98b2f01 | ||
|
|
83dfc2bb49 | ||
|
|
058590bb39 | ||
|
|
349ddfd954 | ||
|
|
6ac4a86a15 | ||
|
|
d729b1b9bf | ||
|
|
3bb1f7921b | ||
|
|
715c242f44 | ||
|
|
01fde3cecb | ||
|
|
6992c1daac | ||
|
|
95c2b08358 | ||
|
|
8bce1ab633 | ||
|
|
479c15a336 | ||
|
|
f858ed978d | ||
|
|
aa6b8c24bb | ||
|
|
0905576515 | ||
|
|
e401a26051 | ||
|
|
253eac37d2 | ||
|
|
f282c0c2c5 | ||
|
|
1922df6fd2 | ||
|
|
05cf37c8c1 | ||
|
|
b561b07712 | ||
|
|
a87373710d | ||
|
|
4ea2860257 | ||
|
|
d8ccf16b87 | ||
|
|
64ccaa8941 | ||
|
|
3937340ec3 | ||
|
|
c87fdf7e8b | ||
|
|
11b1d2a597 | ||
|
|
ff6fed8ee9 | ||
|
|
3b98856717 | ||
|
|
a598682d68 | ||
|
|
3bc57ff6ba | ||
|
|
5a6ef6e9e2 | ||
|
|
a1849e45a3 | ||
|
|
dec0dc4b4d | ||
|
|
daa8b6b844 | ||
|
|
bc43f6fbf1 | ||
|
|
2bf54066e9 | ||
|
|
7aa756bebb | ||
|
|
84eb2bee18 | ||
|
|
6c54854ddc | ||
|
|
c6922112d1 | ||
|
|
d4eeee31b5 | ||
|
|
2ab6da3489 | ||
|
|
c5c7acd5cf | ||
|
|
eaaa541a16 | ||
|
|
40a0fac667 | ||
|
|
4426e33e7e | ||
|
|
8754571ef0 | ||
|
|
cc79e6a1b9 | ||
|
|
4e5b88054d | ||
|
|
bdb6e5a046 | ||
|
|
e81e3f7a55 | ||
|
|
e53afac528 | ||
|
|
fb21cca26e | ||
|
|
91946fa48c | ||
|
|
eadf460df5 | ||
|
|
726ffb93b0 | ||
|
|
cffcc25cf1 | ||
|
|
2c1b05d448 | ||
|
|
1d758dbc66 | ||
|
|
792184cf2c | ||
|
|
e4b71fde61 | ||
|
|
a1e4b59ed9 | ||
|
|
5982c7624d | ||
|
|
8462d81c7c | ||
|
|
6e7429a889 | ||
|
|
949db3ccdb | ||
|
|
cb1cf8dfe7 | ||
|
|
e11b0cd409 | ||
|
|
5f74c1fa31 | ||
|
|
5bb90b84e3 | ||
|
|
7797741733 | ||
|
|
1030d3740f | ||
|
|
700a4aca47 | ||
|
|
1504729937 | ||
|
|
3ac57bb15a | ||
|
|
5e2f3f9490 | ||
|
|
f4f6ab0f56 | ||
|
|
2edddc5f9a | ||
|
|
9213f43286 | ||
|
|
1759f79026 | ||
|
|
5be88369ce | ||
|
|
3afef10951 | ||
|
|
ef6cadeaf2 | ||
|
|
d8a9ce16cc | ||
|
|
2c4a5300d1 | ||
|
|
9db0863ba9 | ||
|
|
2af7fe401e | ||
|
|
5299a2fed1 | ||
|
|
4e279ac6b4 | ||
|
|
33e13e1234 | ||
|
|
d177af97b3 | ||
|
|
a0dfd67635 | ||
|
|
bfb85c80b7 | ||
|
|
b68f43c223 | ||
|
|
649346bdce | ||
|
|
d2bba7e1bb | ||
|
|
999c1be8af | ||
|
|
452209bb27 | ||
|
|
38c9ba0b19 | ||
|
|
7764aee799 | ||
|
|
a9e0a32888 | ||
|
|
f52d05ff19 | ||
|
|
ef2fb0dfd2 | ||
|
|
a056c91c6a | ||
|
|
af8ec69446 | ||
|
|
116d7b3990 | ||
|
|
73a8e67efc | ||
|
|
3e5d06aa51 | ||
|
|
1224c30c06 | ||
|
|
534c0c5c3b | ||
|
|
c2c32d8f4c | ||
|
|
d9971e817f | ||
|
|
5e59345ee8 | ||
|
|
ab916272ed | ||
|
|
0384621463 | ||
|
|
66959f111e | ||
|
|
86332c87ee | ||
|
|
2799bbe8f7 | ||
|
|
aed21777fa | ||
|
|
0f86f7f249 | ||
|
|
684270f526 | ||
|
|
ae566f467e | ||
|
|
bd362b7612 | ||
|
|
995baf3b89 | ||
|
|
949e866845 | ||
|
|
47d8fd1622 |
@@ -141,7 +141,7 @@ jobs:
|
||||
|
||||
- name: get MPI (Windows)
|
||||
if: matrix.mpi == 'par' && matrix.os == 'windows-latest'
|
||||
uses: mpi4py/setup-mpi@v1.1.2
|
||||
uses: mpi4py/setup-mpi@v1.1.4
|
||||
|
||||
# Get Hypre through cache, or build it.
|
||||
# Install will only run on cache miss.
|
||||
|
||||
+11
@@ -131,6 +131,12 @@ examples/hiop/ex9-mesh.*
|
||||
examples/hiop/ex9-init.*
|
||||
examples/hiop/ex9-final.*
|
||||
|
||||
examples/ipopt/exContactBlockTL
|
||||
examples/ipopt/exContactBlockTL.mesh
|
||||
examples/ipopt/exContactBlockTL-mesh.*
|
||||
examples/ipopt/exContactBlockTL-init.*
|
||||
examples/ipopt/exContactBlockTL-final.*
|
||||
|
||||
examples/petsc/ex[1-69]p
|
||||
examples/petsc/ex1[0-1]p
|
||||
examples/petsc/mesh.*
|
||||
@@ -203,6 +209,7 @@ miniapps/meshing/mesh-explorer
|
||||
miniapps/meshing/shaper
|
||||
miniapps/meshing/extruder
|
||||
miniapps/meshing/trimmer
|
||||
miniapps/meshing/reflector
|
||||
miniapps/meshing/mesh-optimizer
|
||||
miniapps/meshing/pmesh-optimizer
|
||||
miniapps/meshing/minimal-surface
|
||||
@@ -214,9 +221,12 @@ miniapps/meshing/toroid-*.mesh
|
||||
miniapps/meshing/twist-*.mesh
|
||||
miniapps/meshing/mesh-explorer.mesh
|
||||
miniapps/meshing/partitioning.txt
|
||||
miniapps/meshing/mesh-explorer-visit*
|
||||
miniapps/meshing/mesh-explorer-paraview/
|
||||
miniapps/meshing/shaper.mesh
|
||||
miniapps/meshing/extruder.mesh
|
||||
miniapps/meshing/trimmer.mesh
|
||||
miniapps/meshing/reflected.mesh
|
||||
miniapps/meshing/optimized*
|
||||
miniapps/meshing/perturbed*
|
||||
miniapps/meshing/polar-nc.mesh
|
||||
@@ -276,6 +286,7 @@ miniapps/tools/convert-dc
|
||||
miniapps/tools/lor-transfer
|
||||
miniapps/tools/get-values
|
||||
miniapps/tools/check-tmop-metric
|
||||
miniapps/tools/tmop-metric-magnitude
|
||||
|
||||
miniapps/toys/automata
|
||||
miniapps/toys/life
|
||||
|
||||
@@ -93,7 +93,7 @@ report_baseline:
|
||||
git pull && \
|
||||
git add ${rundir} && \
|
||||
git commit -m "${msg}" && \
|
||||
git push origin master
|
||||
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
|
||||
else
|
||||
for file in ${rundir}/*; do
|
||||
echo "------------------------------"
|
||||
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2010-2022, 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.
|
||||
|
||||
# Try to push to the remote 5 times. If the push fails, and the local and remote
|
||||
# have diverged, then pull from the remote to merge changes, and try pushing
|
||||
# again. If some other failure happens
|
||||
for i in {1..5}; do
|
||||
git push origin master && exit 0
|
||||
# Wait for 20 seconds in case someone else is pushing to the remote
|
||||
# concurrently
|
||||
sleep 20
|
||||
# Fetch any updates from the remote
|
||||
git remote update
|
||||
# Get the latest commit on the local branch
|
||||
LOCAL=$(git rev-parse @)
|
||||
# Get the latest commit on the remote
|
||||
REMOTE=$(git rev-parse @{u})
|
||||
# Get the common ancestor
|
||||
BASE=$(git merge-base @ @{u})
|
||||
# Have the local and remote diverged?
|
||||
if [[ $LOCAL != $REMOTE && $LOCAL != $BASE && $REMOTE != $BASE ]]; then
|
||||
git pull
|
||||
if [[ $? == 0 ]]; then
|
||||
continue
|
||||
else
|
||||
exit 1 # Something else went wrong trying to pull
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit 1 # Did not succeed in 5 attempts
|
||||
@@ -32,7 +32,7 @@ if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
|
||||
git pull && \
|
||||
git add ${rundir} && \
|
||||
git commit -m "${msg}" && \
|
||||
git push origin master
|
||||
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
|
||||
else
|
||||
for file in ${rundir}/*; do
|
||||
echo "------------------------------"
|
||||
|
||||
@@ -29,7 +29,7 @@ if [[ "$AUTOTEST_COMMIT" != "NO" ]]; then
|
||||
git pull && \
|
||||
git add ${rundir} && \
|
||||
git commit -m "${msg}" && \
|
||||
git push origin master
|
||||
${CI_PROJECT_DIR}/.gitlab/scripts/git_try_to_push
|
||||
else
|
||||
for file in ${rundir}/*; do
|
||||
echo "------------------------------"
|
||||
|
||||
@@ -10,12 +10,23 @@
|
||||
|
||||
Version 4.5.1 (development)
|
||||
===========================
|
||||
- When using discontinuous (L2) spaces, use local (element-wise) L2 projection
|
||||
as the coarsening operator for non-conforming AMR meshes.
|
||||
|
||||
Meshing improvements
|
||||
--------------------
|
||||
- Added support for pyramids in non-conforming meshes. Currently only isotropic
|
||||
refinement is supported in this case.
|
||||
|
||||
- Updated logic in FindPointsGSLIB to ignore points found near (but outside) the
|
||||
domain boundary.
|
||||
|
||||
- Added support for pyramids in Gmsh meshes.
|
||||
|
||||
- Fixed a bug in TMOP metric 301.
|
||||
|
||||
- Added an option to auto-balance compound TMOP metrics.
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
- TBD
|
||||
@@ -27,7 +38,12 @@ Linear and nonlinear solvers
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- TBD
|
||||
- Added a new meshing miniapp, reflector, which reflects a high-order or NURBS
|
||||
hexahedral mesh about a plane.
|
||||
|
||||
- The mesh-explorer miniapp can now save mesh files in the VisIt or ParaView
|
||||
formats using the corresponding DataCollection objects. See option 'D' in the
|
||||
main menu.
|
||||
|
||||
Integrations, testing and documentation
|
||||
---------------------------------------
|
||||
@@ -100,6 +116,9 @@ Discretization improvements
|
||||
- Added a class CoefficientVector for efficient access of variable coefficient
|
||||
values at quadrature points (in particular for GPU/device kernels).
|
||||
|
||||
- Added support for GridFunction::GetGradients() and
|
||||
GriFunction::GetVectorGradient() on face-neighbor elements.
|
||||
|
||||
- Added WhiteGaussianNoiseDomainLFIntegrator: a LinearFormIntegrator class for
|
||||
spatial Gaussian white noise.
|
||||
|
||||
|
||||
+16
-4
@@ -134,8 +134,7 @@ if (MFEM_USE_CUDA)
|
||||
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(CMAKE_CUDA_FLAGS ${CMAKE_CUDA_FLAGS} ${CUDA_FLAGS})
|
||||
set(CUSPARSE_FOUND TRUE)
|
||||
set(CUSPARSE_LIBRARIES "cusparse")
|
||||
set(CUBLAS_FOUND TRUE)
|
||||
@@ -405,6 +404,15 @@ if (MFEM_USE_HIOP)
|
||||
# find_package updates HIOP_FOUND, HIOP_INCLUDE_DIRS, HIOP_LIBRARIES
|
||||
endif()
|
||||
|
||||
# IpOpt optimizer
|
||||
if (MFEM_USE_IPOPT)
|
||||
find_package(IPOPT REQUIRED)
|
||||
message(
|
||||
STATUS
|
||||
"IPOPT_INCLUDE_DIRS=${IPOPT_INCLUDE_DIRS}, IPOPT_LIBRARIES=${IPOPT_LIBRARIES}, IPOPT_DIR=${IPOPT_DIR}")
|
||||
# find_package updates IPOPT_FOUND, IPOPT_INCLUDE_DIRS, IPOPT_LIBRARIES
|
||||
endif()
|
||||
|
||||
# CoDiPack package
|
||||
if (MFEM_USE_CODIPACK)
|
||||
find_package(CODIPACK REQUIRED)
|
||||
@@ -500,7 +508,7 @@ find_package(Threads REQUIRED)
|
||||
# be before SuiteSparse.
|
||||
set(MFEM_TPLS OPENMP HYPRE LAPACK BLAS SuperLUDist STRUMPACK METIS SuiteSparse
|
||||
SUNDIALS PETSC SLEPC MUMPS AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB
|
||||
NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
|
||||
NETCDF MPFR PUMI HIOP IPOPT POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
|
||||
ADIOS2 CUBLAS CUSPARSE MKL_CPARDISO AMGX CALIPER CODIPACK BENCHMARK PARELAG
|
||||
MPI_CXX HIP HIPSPARSE MOONOLITH BLITZ ALGOIM ENZYME)
|
||||
|
||||
@@ -698,6 +706,8 @@ add_subdirectory(doc)
|
||||
message(STATUS "CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}")
|
||||
set(INSTALL_INCLUDE_DIR include
|
||||
CACHE PATH "Relative path for installing header files.")
|
||||
set(INSTALL_BIN_DIR bin
|
||||
CACHE PATH "Relative path for installing the binaries.")
|
||||
set(INSTALL_LIB_DIR lib
|
||||
CACHE PATH "Relative path for installing the library.")
|
||||
# other options: "share/mfem/cmake", "lib/mfem/cmake"
|
||||
@@ -716,7 +726,9 @@ set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME Development)
|
||||
# Install the library
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
EXPORT ${PROJECT_NAME_UC}Targets
|
||||
DESTINATION ${INSTALL_LIB_DIR})
|
||||
RUNTIME DESTINATION ${INSTALL_BIN_DIR}
|
||||
LIBRARY DESTINATION ${INSTALL_LIB_DIR}
|
||||
ARCHIVE DESTINATION ${INSTALL_LIB_DIR})
|
||||
|
||||
# Install the master headers
|
||||
foreach(Header mfem.hpp mfem-performance.hpp)
|
||||
|
||||
@@ -112,6 +112,7 @@ The MFEM source code has the following structure:
|
||||
│ ├── caliper
|
||||
│ ├── ginkgo
|
||||
│ ├── hiop
|
||||
│ ├── ipopt
|
||||
│ ├── jupyter
|
||||
│ ├── moonolith
|
||||
│ ├── petsc
|
||||
|
||||
@@ -471,6 +471,9 @@ MFEM_USE_HIOP = YES/NO
|
||||
Enable the usage of HiOp (https://github.com/LLNL/hiop) in MFEM. HiOp is an
|
||||
HPC solver for nonlinear optimization problems.
|
||||
|
||||
MFEM_USE_IPOPT = YES/NO
|
||||
Enable the usage of Ipopt in MFEM.
|
||||
|
||||
MFEM_USE_CODIPACK = YES/NO
|
||||
Enable automatic differentiation using the CoDiPack library.
|
||||
www.scicomp.uni-kl.de/codi/
|
||||
@@ -738,6 +741,11 @@ The specific libraries and their options are:
|
||||
Options: HIOP_OPT, HIOP_LIB.
|
||||
Versions: HIOP >= 0.4.6.
|
||||
|
||||
- Ipopt (optional), used when MFEM_USE_IPOPT = YES.
|
||||
URL: https://github.com/coin-or/Ipopt
|
||||
Options: IPOPT_OPT, IPOPT_LIB.
|
||||
Versions: IPOPT >= 3.14
|
||||
|
||||
- CoDiPack (optional), used with MFEM_USE_CODIPACK = YES
|
||||
URL: https://www.scicomp.uni-kl.de/codi/
|
||||
Options: CODIPACK_OPT
|
||||
@@ -972,6 +980,7 @@ MFEM_USE_MPFR
|
||||
MFEM_USE_ZLIB
|
||||
MFEM_USE_PUMI
|
||||
MFEM_USE_HIOP
|
||||
MFEM_USE_IPOPT
|
||||
MFEM_USE_CODIPACK
|
||||
MFEM_USE_ADFORWARD
|
||||
MFEM_USE_CUDA
|
||||
@@ -1035,6 +1044,7 @@ The CMake build system adds auto-detection for the following packages/libraries:
|
||||
- POSIXCLOCKS
|
||||
- PUMI
|
||||
- HIOP
|
||||
- IPOPT
|
||||
- CoDiPack
|
||||
- OCCA
|
||||
- RAJA
|
||||
|
||||
@@ -36,6 +36,7 @@ set(MFEM_USE_STRUMPACK @MFEM_USE_STRUMPACK@)
|
||||
set(MFEM_USE_GINKGO @MFEM_USE_GINKGO@)
|
||||
set(MFEM_USE_AMGX @MFEM_USE_AMGX@)
|
||||
set(MFEM_USE_HIOP @MFEM_USE_HIOP@)
|
||||
set(MFEM_USE_IPOPT @MFEM_USE_IPOPT@)
|
||||
set(MFEM_USE_GNUTLS @MFEM_USE_GNUTLS@)
|
||||
set(MFEM_USE_GSLIB @MFEM_USE_GSLIB@)
|
||||
set(MFEM_USE_NETCDF @MFEM_USE_NETCDF@)
|
||||
|
||||
@@ -131,6 +131,9 @@
|
||||
// Enable MFEM functionality based on the HiOp library
|
||||
#cmakedefine MFEM_USE_HIOP
|
||||
|
||||
// Enable MFEM functionality based on the Ipopt library
|
||||
#cmakedefine MFEM_USE_IPOPT
|
||||
|
||||
// Build the GPU/CUDA-enabled version of the MFEM library.
|
||||
// Requires a CUDA compiler (nvcc).
|
||||
#cmakedefine MFEM_USE_CUDA
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(Algoim ALGOIM ALGOIM_DIR
|
||||
"include" "algoim_quad.hpp"
|
||||
"include;src" "algoim_quad.hpp"
|
||||
"" ""
|
||||
"Paths to headers required by Algoim."
|
||||
"Libraries required by Algoim.")
|
||||
"Paths to headers required by Algoim."
|
||||
"Libraries required by Algoim.")
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Copyright (c) 2010-2022, 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.
|
||||
|
||||
# Sets the following variables:
|
||||
# - IPOPT_FOUND
|
||||
# - IPOPT_INCLUDE_DIRS
|
||||
# - IPOPT_LIBRARIES
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
mfem_find_package(IPOPT IPOPT IPOPT_DIR
|
||||
"include" "IpTNLP.hpp"
|
||||
"lib" "ipopt"
|
||||
"Paths to headers required by IPOPT."
|
||||
"Libraries required by IPOPT.")
|
||||
|
||||
@@ -869,7 +869,7 @@ function(mfem_export_mk_files)
|
||||
MFEM_USE_SUPERLU MFEM_USE_SUPERLU5 MFEM_USE_MUMPS MFEM_USE_STRUMPACK
|
||||
MFEM_USE_GINKGO MFEM_USE_AMGX MFEM_USE_GNUTLS MFEM_USE_NETCDF
|
||||
MFEM_USE_PETSC MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_FMS
|
||||
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA
|
||||
MFEM_USE_CONDUIT MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_IPOPT MFEM_USE_GSLIB MFEM_USE_CUDA
|
||||
MFEM_USE_HIP MFEM_USE_RAJA MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_CALIPER
|
||||
MFEM_USE_UMPIRE MFEM_USE_SIMD MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO
|
||||
MFEM_USE_ADFORWARD MFEM_USE_CODIPACK MFEM_USE_BENCHMARK MFEM_USE_PARELAG
|
||||
|
||||
@@ -141,6 +141,9 @@
|
||||
// Enable MFEM functionality based on the HIOP library.
|
||||
// #define MFEM_USE_HIOP
|
||||
|
||||
// Enable MFEM functionality based on the IPOPT library.
|
||||
// #define MFEM_USE_IPOPT
|
||||
|
||||
// Enable MFEM functionality based on the GSLIB library
|
||||
// #define MFEM_USE_GSLIB
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ MFEM_USE_FMS = @MFEM_USE_FMS@
|
||||
MFEM_USE_CONDUIT = @MFEM_USE_CONDUIT@
|
||||
MFEM_USE_PUMI = @MFEM_USE_PUMI@
|
||||
MFEM_USE_HIOP = @MFEM_USE_HIOP@
|
||||
MFEM_USE_IPOPT = @MFEM_USE_IPOPT@
|
||||
MFEM_USE_GSLIB = @MFEM_USE_GSLIB@
|
||||
MFEM_USE_CUDA = @MFEM_USE_CUDA@
|
||||
MFEM_USE_HIP = @MFEM_USE_HIP@
|
||||
|
||||
@@ -48,6 +48,7 @@ option(MFEM_USE_FMS "Enable FMS usage" OFF)
|
||||
option(MFEM_USE_CONDUIT "Enable Conduit usage" OFF)
|
||||
option(MFEM_USE_PUMI "Enable PUMI" OFF)
|
||||
option(MFEM_USE_HIOP "Enable HiOp" OFF)
|
||||
option(MFEM_USE_IPOPT "Enable Ipopt" OFF)
|
||||
option(MFEM_USE_CUDA "Enable CUDA" OFF)
|
||||
option(MFEM_USE_HIP "Enable HIP" OFF)
|
||||
option(MFEM_USE_OCCA "Enable OCCA" OFF)
|
||||
@@ -220,6 +221,10 @@ set(HIOP_DIR "${MFEM_DIR}/../hiop/install" CACHE STRING
|
||||
"Directory where HiOp is installed")
|
||||
set(HIOP_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
|
||||
"Packages that HiOp depends on.")
|
||||
set(IPOPT_DIR "${MFEM_DIR}/../ipopt/install" CACHE STRING
|
||||
"Directory where IpOpt is installed")
|
||||
set(IPOPT_REQUIRED_PACKAGES "BLAS" "LAPACK" CACHE STRING
|
||||
"Packages that IpOpt 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")
|
||||
@@ -232,7 +237,7 @@ set(UMPIRE_DIR "${MFEM_DIR}/../umpire" CACHE PATH "Path to Umpire")
|
||||
set(CALIPER_DIR "${MFEM_DIR}/../caliper" CACHE PATH "Path to Caliper")
|
||||
set(BLITZ_DIR "${MFEM_DIR}/../blitz" CACHE PATH "Path to Blitz")
|
||||
set(ALGOIM_DIR "${MFEM_DIR}/../algoim" CACHE PATH "Path to Algoim")
|
||||
set(ALGOIM_REQUIRED_PACKAGES "BLITZ" CACHE STRING
|
||||
set(Algoim_REQUIRED_PACKAGES "Blitz" CACHE STRING
|
||||
"Packages that ALGOIM depends on.")
|
||||
|
||||
set(BENCHMARK_DIR "${MFEM_DIR}/../google-benchmark" CACHE PATH
|
||||
|
||||
@@ -148,6 +148,7 @@ MFEM_USE_FMS = NO
|
||||
MFEM_USE_CONDUIT = NO
|
||||
MFEM_USE_PUMI = NO
|
||||
MFEM_USE_HIOP = NO
|
||||
MFEM_USE_IPOPT = NO
|
||||
MFEM_USE_GSLIB = NO
|
||||
MFEM_USE_CUDA = NO
|
||||
MFEM_USE_HIP = NO
|
||||
@@ -447,6 +448,11 @@ HIOP_DIR = @MFEM_DIR@/../hiop/install
|
||||
HIOP_OPT = -I$(HIOP_DIR)/include
|
||||
HIOP_LIB = -L$(HIOP_DIR)/lib -lhiop $(LAPACK_LIB)
|
||||
|
||||
# IPOPT
|
||||
IPOPT_DIR = @MFEM_DIR@/../ipopt/install
|
||||
IPOPT_OPT = -I$(IPOPT_DIR)/include
|
||||
IPOPT_LIB = -L$(IPOPT_DIR)/lib -lipopt $(LAPACK_LIB)
|
||||
|
||||
# CoDiPack
|
||||
CODIPACK_DIR = @MFEM_DIR@/../CoDiPack
|
||||
CODIPACK_OPT = -I$(CODIPACK_DIR)
|
||||
|
||||
@@ -58,6 +58,10 @@ groups_serial=(
|
||||
"HiOp examples:"
|
||||
"examples/hiop"
|
||||
"ex9.cpp"'
|
||||
'"ipopt"
|
||||
"IpOpt examples:"
|
||||
"examples/ipopt"
|
||||
"ex10.cpp"'
|
||||
'"pumi"
|
||||
"PUMI examples:"
|
||||
"examples/pumi"
|
||||
@@ -215,6 +219,10 @@ groups_all=(
|
||||
"HiOp examples:"
|
||||
"examples/hiop"
|
||||
"ex9.cpp ex9p.cpp"'
|
||||
'"ipopt"
|
||||
"IpOpt examples:"
|
||||
"examples/ipopt"
|
||||
"ex10.cpp"'
|
||||
'"pumi"
|
||||
"PUMI examples:"
|
||||
"examples/pumi"
|
||||
|
||||
@@ -785,6 +785,7 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
|
||||
@MFEM_SOURCE_DIR@/examples/caliper \
|
||||
@MFEM_SOURCE_DIR@/examples/ginkgo \
|
||||
@MFEM_SOURCE_DIR@/examples/hiop \
|
||||
@MFEM_SOURCE_DIR@/examples/ipopt \
|
||||
@MFEM_SOURCE_DIR@/examples/moonolith \
|
||||
@MFEM_SOURCE_DIR@/examples/petsc \
|
||||
@MFEM_SOURCE_DIR@/examples/pumi \
|
||||
|
||||
@@ -178,6 +178,11 @@ if (MFEM_USE_HIOP)
|
||||
add_subdirectory(hiop)
|
||||
endif()
|
||||
|
||||
# Include the examples/ipopt directory if IpOpt is enabled
|
||||
if (MFEM_USE_IPOPT)
|
||||
add_subdirectory(ipopt)
|
||||
endif()
|
||||
|
||||
# Include the examples/petsc directory if PETSc is enabled.
|
||||
if (MFEM_USE_PETSC)
|
||||
add_subdirectory(petsc)
|
||||
|
||||
@@ -0,0 +1,810 @@
|
||||
// Contact example
|
||||
//
|
||||
// Compile with: make contact
|
||||
//
|
||||
// Sample runs: ./contact -m1 block1.mesh -m2 block2.mesh -at "5 6 7 8"
|
||||
// Sample runs: ./contact -m1 block1_d.mesh -m2 block2_d.mesh -at "5 6 7 8"
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "nodepair.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
bool ifequalarray(const Array<int> a1, const Array<int> a2)
|
||||
{
|
||||
if (a1.Size()!=a2.Size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i=0; i<a1.Size(); i++)
|
||||
{
|
||||
if (a1[i] != a2[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void FindSurfaceToProject(Mesh& mesh, const int elem, int& cbdrface)
|
||||
{
|
||||
Array<int> attr;
|
||||
attr.Append(2);
|
||||
Array<int> faces;
|
||||
Array<int> ori;
|
||||
std::vector<Array<int> > facesVertices;
|
||||
std::vector<int > faceid;
|
||||
mesh.GetElementFaces(elem, faces, ori);
|
||||
int face = -1;
|
||||
for (int i=0; i<faces.Size(); i++)
|
||||
{
|
||||
face = faces[i];
|
||||
Array<int> faceVert;
|
||||
if (!mesh.FaceIsInterior(face)) // if on the boundary
|
||||
{
|
||||
mesh.GetFaceVertices(face, faceVert);
|
||||
faceVert.Sort();
|
||||
facesVertices.push_back(faceVert);
|
||||
faceid.push_back(face);
|
||||
}
|
||||
}
|
||||
int bdrface = facesVertices.size();
|
||||
|
||||
Array<int> bdryFaces;
|
||||
// This shoulnd't need to be rebuilt
|
||||
std::vector<Array<int> > bdryVerts;
|
||||
for (int b=0; b<mesh.GetNBE(); ++b)
|
||||
{
|
||||
if (attr.FindSorted(mesh.GetBdrAttribute(b)) >= 0) // found the contact surface
|
||||
{
|
||||
bdryFaces.Append(b);
|
||||
Array<int> vert;
|
||||
mesh.GetBdrElementVertices(b, vert);
|
||||
vert.Sort();
|
||||
bdryVerts.push_back(vert);
|
||||
}
|
||||
}
|
||||
|
||||
int bdrvert = bdryVerts.size();
|
||||
cbdrface = -1; // the face number of the contact surface element
|
||||
int count_cbdrface = 0; // the number of matching surfaces, used for checks
|
||||
|
||||
for (int i=0; i<bdrface; i++)
|
||||
{
|
||||
for (int j=0; j<bdrvert; j++)
|
||||
{
|
||||
if (ifequalarray(facesVertices[i], bdryVerts[j]))
|
||||
{
|
||||
cbdrface = faceid[i];
|
||||
count_cbdrface += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_VERIFY(count_cbdrface == 1,"projection surface not found");
|
||||
|
||||
};
|
||||
|
||||
Vector GetNormalVector(Mesh & mesh, const int elem, const double *ref,
|
||||
int & refFace, int & refNormal, bool & interior)
|
||||
{
|
||||
ElementTransformation *trans = mesh.GetElementTransformation(elem);
|
||||
const int dim = mesh.Dimension();
|
||||
const int spaceDim = trans->GetSpaceDim();
|
||||
|
||||
MFEM_VERIFY(spaceDim == 3, "");
|
||||
|
||||
Vector n(spaceDim);
|
||||
|
||||
IntegrationPoint ip;
|
||||
ip.Set(ref, dim);
|
||||
|
||||
trans->SetIntPoint(&ip);
|
||||
//CalcOrtho(trans->Jacobian(), n); // Works only for face transformations
|
||||
const DenseMatrix jac = trans->Jacobian();
|
||||
|
||||
int dimNormal = -1;
|
||||
int normalSide = -1;
|
||||
|
||||
const double tol = 1.0e-8;
|
||||
for (int i=0; i<dim; ++i)
|
||||
{
|
||||
const double d0 = std::abs(ref[i]);
|
||||
const double d1 = std::abs(ref[i] - 1.0);
|
||||
|
||||
const double d = std::min(d0, d1);
|
||||
// TODO: this works only for hexahedral meshes!
|
||||
|
||||
if (d < tol)
|
||||
{
|
||||
MFEM_VERIFY(dimNormal == -1, "");
|
||||
dimNormal = i;
|
||||
|
||||
if (d0 < tol)
|
||||
{
|
||||
normalSide = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
normalSide = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// closest point on the boundary
|
||||
if (dimNormal < 0 || normalSide < 0) // node is inside the element
|
||||
{
|
||||
interior = 1;
|
||||
Vector n(3);
|
||||
n = 0.0;
|
||||
return n;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(dimNormal >= 0 && normalSide >= 0, "");
|
||||
refNormal = dimNormal;
|
||||
|
||||
MFEM_VERIFY(dim == 3, "");
|
||||
|
||||
{
|
||||
// Find the reference face
|
||||
if (dimNormal == 0)
|
||||
{
|
||||
refFace = (normalSide == 1) ? 2 : 4;
|
||||
}
|
||||
else if (dimNormal == 1)
|
||||
{
|
||||
refFace = (normalSide == 1) ? 3 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
refFace = (normalSide == 1) ? 5 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Vector> tang(2);
|
||||
|
||||
int tangDir[2] = {-1, -1};
|
||||
{
|
||||
int t = 0;
|
||||
for (int i=0; i<dim; ++i)
|
||||
{
|
||||
if (i != dimNormal)
|
||||
{
|
||||
tangDir[t] = i;
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_VERIFY(t == 2, "");
|
||||
}
|
||||
|
||||
for (int i=0; i<2; ++i)
|
||||
{
|
||||
tang[i].SetSize(3);
|
||||
|
||||
Vector tangRef(3);
|
||||
tangRef = 0.0;
|
||||
tangRef[tangDir[i]] = 1.0;
|
||||
|
||||
jac.Mult(tangRef, tang[i]);
|
||||
}
|
||||
|
||||
Vector c(3); // Cross product
|
||||
|
||||
c[0] = (tang[0][1] * tang[1][2]) - (tang[0][2] * tang[1][1]);
|
||||
c[1] = (tang[0][2] * tang[1][0]) - (tang[0][0] * tang[1][2]);
|
||||
c[2] = (tang[0][0] * tang[1][1]) - (tang[0][1] * tang[1][0]);
|
||||
|
||||
c /= c.Norml2();
|
||||
|
||||
Vector nref(3);
|
||||
nref = 0.0;
|
||||
nref[dimNormal] = 1.0;
|
||||
|
||||
Vector ndir(3);
|
||||
jac.Mult(nref, ndir);
|
||||
|
||||
ndir /= ndir.Norml2();
|
||||
|
||||
const double dp = ndir * c;
|
||||
|
||||
// TODO: eliminate c?
|
||||
n = c;
|
||||
if (dp < 0.0)
|
||||
{
|
||||
n *= -1.0;
|
||||
}
|
||||
interior = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
// WARNING: global variable, just for this little example.
|
||||
std::array<std::array<int, 3>, 8> HEX_VERT =
|
||||
{
|
||||
{ {0,0,0},
|
||||
{1,0,0},
|
||||
{1,1,0},
|
||||
{0,1,0},
|
||||
{0,0,1},
|
||||
{1,0,1},
|
||||
{1,1,1},
|
||||
{0,1,1}
|
||||
}
|
||||
};
|
||||
|
||||
int GetHexVertex(int cdim, int c, int fa, int fb, Vector & refCrd)
|
||||
{
|
||||
int ref[3];
|
||||
ref[cdim] = c;
|
||||
ref[cdim == 0 ? 1 : 0] = fa;
|
||||
ref[cdim == 2 ? 1 : 2] = fb;
|
||||
|
||||
for (int i=0; i<3; ++i) { refCrd[i] = ref[i]; }
|
||||
|
||||
int refv = -1;
|
||||
|
||||
for (int i=0; i<8; ++i)
|
||||
{
|
||||
bool match = true;
|
||||
for (int j=0; j<3; ++j)
|
||||
{
|
||||
if (ref[j] != HEX_VERT[i][j]) { match = false; }
|
||||
}
|
||||
|
||||
if (match) { refv = i; }
|
||||
}
|
||||
|
||||
MFEM_VERIFY(refv >= 0, "");
|
||||
|
||||
return refv;
|
||||
}
|
||||
|
||||
// Coordinates in xyz are assumed to be ordered as [X, Y, Z]
|
||||
// where X is the list of x-coordinates for all points and so on.
|
||||
// conn: connectivity of the target surface elements
|
||||
// xi: surface reference cooridnates for the cloest point, involves a linear transformation from [0,1] to [-1,1]
|
||||
void FindPointsInMesh(Mesh & mesh, Vector const& xyz, Array<int>& conn,
|
||||
Vector& xi)
|
||||
{
|
||||
const int dim = mesh.Dimension();
|
||||
const int np = xyz.Size() / dim;
|
||||
|
||||
MFEM_VERIFY(np * dim == xyz.Size(), "");
|
||||
|
||||
mesh.EnsureNodes();
|
||||
|
||||
//FindPointsGSLIB finder(MPI_COMM_WORLD);
|
||||
FindPointsGSLIB finder;
|
||||
|
||||
finder.SetDistanceToleranceForPointsFoundOnBoundary(0.5);
|
||||
|
||||
const double bb_t = 0.5;
|
||||
finder.Setup(mesh, bb_t);
|
||||
|
||||
finder.FindPoints(xyz);
|
||||
|
||||
/// Return code for each point searched by FindPoints: inside element (0), on
|
||||
/// element boundary (1), or not found (2).
|
||||
Array<unsigned int> codes = finder.GetCode();
|
||||
|
||||
/// Return element number for each point found by FindPoints.
|
||||
Array<unsigned int> elems = finder.GetElem();
|
||||
|
||||
/// Return reference coordinates for each point found by FindPoints.
|
||||
Vector refcrd = finder.GetReferencePosition();
|
||||
|
||||
/// Return distance between the sought and the found point in physical space,
|
||||
/// for each point found by FindPoints.
|
||||
Vector dist = finder.GetDist();
|
||||
|
||||
MFEM_VERIFY(dist.Size() == np, "");
|
||||
MFEM_VERIFY(refcrd.Size() == np * dim, "");
|
||||
MFEM_VERIFY(elems.Size() == np, "");
|
||||
MFEM_VERIFY(codes.Size() == np, "");
|
||||
|
||||
bool allfound = true;
|
||||
for (auto code : codes)
|
||||
if (code == 2) { allfound = false; }
|
||||
|
||||
MFEM_VERIFY(allfound, "A point was not found");
|
||||
|
||||
cout << "Maximum distance of projected points: " << dist.Max() << endl;
|
||||
|
||||
// extract information
|
||||
for (int i=0; i<np; ++i)
|
||||
{
|
||||
/*cout << "Point " << i << ": (";
|
||||
for (int j=0; j<dim; ++j)
|
||||
{
|
||||
cout << xyz[i + (j*np)];
|
||||
if (j == dim-1) {cout << ")" << endl;}
|
||||
else{cout << ", ";}
|
||||
}*/
|
||||
//cout << " element: " << elems[i] << endl;
|
||||
//cout << " element " << elems[i] << " vertices:" << endl;
|
||||
//Array<int> vert;
|
||||
//mesh.GetElementVertices(elems[i], vert);
|
||||
//for (auto v : vert)
|
||||
//{
|
||||
// cout << " " << v << endl;
|
||||
//}
|
||||
|
||||
/*cout << " reference coordinates: (";
|
||||
for (int j=0; j<dim; ++j)
|
||||
{
|
||||
cout << refcrd[(i*dim) + j];
|
||||
if (j == dim-1)
|
||||
{
|
||||
cout << ")" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << ", ";
|
||||
}
|
||||
}*/
|
||||
|
||||
int refFace, refNormal, refNormalSide;
|
||||
bool is_interior = -1;
|
||||
Vector normal = GetNormalVector(mesh, elems[i], refcrd.GetData() + (i*dim),
|
||||
refFace, refNormal, is_interior);
|
||||
int phyFace;
|
||||
if (is_interior)
|
||||
{
|
||||
phyFace = -1; // the id of the face that has the closest point
|
||||
FindSurfaceToProject(mesh, elems[i], phyFace);
|
||||
|
||||
Array<int> cbdrVert;
|
||||
mesh.GetFaceVertices(phyFace, cbdrVert);
|
||||
Vector xs(dim);
|
||||
xs[0] = xyz[i + 0*np];
|
||||
xs[1] = xyz[i + 1*np];
|
||||
xs[2] = xyz[i + 2*np];
|
||||
Vector xi_tmp(dim-1);
|
||||
// get nodes!
|
||||
|
||||
GridFunction *nodes = mesh.GetNodes();
|
||||
DenseMatrix coords(4,3);
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
for (int j=0; j<3; j++)
|
||||
{
|
||||
coords(i,j) = (*nodes)[cbdrVert[i]*3+j];
|
||||
}
|
||||
}
|
||||
SlaveToMaster(coords, xs, xi_tmp);
|
||||
|
||||
for (int j=0; j<dim-1; ++j)
|
||||
{
|
||||
xi[i*(dim-1)+j] = xi_tmp[j];
|
||||
}
|
||||
// now get get the projection to the surface
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector faceRefCrd(dim-1);
|
||||
{
|
||||
int fd = 0;
|
||||
for (int j=0; j<dim; ++j)
|
||||
{
|
||||
if (j == refNormal)
|
||||
{
|
||||
refNormalSide = (refcrd[(i*dim) + j] > 0.5);
|
||||
}
|
||||
else
|
||||
{
|
||||
faceRefCrd[fd] = refcrd[(i*dim) + j];
|
||||
fd++;
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_VERIFY(fd == dim-1, "");
|
||||
}
|
||||
|
||||
for (int j=0; j<dim-1; ++j)
|
||||
{
|
||||
xi[i*(dim-1)+j] = faceRefCrd[j]*2.0 - 1.0;
|
||||
}
|
||||
//cout << " face reference coordinates: (";
|
||||
/*for (int j=0; j<dim-1; ++j)
|
||||
{
|
||||
cout << faceRefCrd[j];
|
||||
if (j == dim-2){cout << ")" << endl;}
|
||||
else{cout << ", ";}
|
||||
}*/
|
||||
}
|
||||
//cout << " normal vector: ";
|
||||
//normal.Print();
|
||||
|
||||
// ask, does this do anything?
|
||||
/*
|
||||
IntegrationPoint ip;
|
||||
ip.Set(refcrd.GetData() + (i*dim), dim);
|
||||
ElementTransformation *trans = mesh.GetElementTransformation(elems[i]);
|
||||
Vector phys(trans->GetSpaceDim());
|
||||
trans->Transform(ip, phys);
|
||||
cout << " physical coordinates: ";
|
||||
phys.Print();
|
||||
*/
|
||||
|
||||
// Get the element face
|
||||
Array<int> faces;
|
||||
Array<int> ori;
|
||||
int face;
|
||||
|
||||
if (is_interior)
|
||||
{
|
||||
face = phyFace;
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh.GetElementFaces(elems[i], faces, ori);
|
||||
face = faces[refFace];
|
||||
}
|
||||
|
||||
Array<int> faceVert;
|
||||
mesh.GetFaceVertices(face, faceVert);
|
||||
|
||||
//cout << " face " << face << " vertices:" << endl;
|
||||
//for (auto v : faceVert){ cout << " " << v << endl;}
|
||||
|
||||
for (int p=0; p<4; p++)
|
||||
{
|
||||
conn[4*i+p] = faceVert[p];
|
||||
}
|
||||
/*
|
||||
Vector ref(dim);
|
||||
|
||||
for (int p=0; p<2; ++p)
|
||||
for (int q=0; q<2; ++q)
|
||||
{
|
||||
const int refv = GetHexVertex(refNormal, refNormalSide, p, q, ref);
|
||||
cout << " face reference vertex (" << p << "," << q
|
||||
<< ") is global vertex " << vert[refv] << endl;
|
||||
|
||||
{
|
||||
// Sanity check
|
||||
ip.Set(ref.GetData(), dim);
|
||||
trans->Transform(ip, phys);
|
||||
for (int j=0; j<dim; ++j)
|
||||
{
|
||||
phys[j] -= mesh.GetVertex(vert[refv])[j];
|
||||
}
|
||||
phys.Print();
|
||||
cout<<vert[refv]<<endl;
|
||||
cout<<mesh.GetVertex(vert[refv])[0]<<endl;
|
||||
cout<<mesh.GetVertex(vert[refv])[1]<<endl;
|
||||
cout<<mesh.GetVertex(vert[refv])[2]<<endl;
|
||||
MFEM_VERIFY(phys.Norml2() < 1.0e-12, "Sanity check failed");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file1 = "block1.mesh";
|
||||
const char *mesh_file2 = "block2.mesh";
|
||||
|
||||
Array<int> attr;
|
||||
Array<int> m_attr;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file1, "-m1", "--mesh1",
|
||||
"First mesh file to use.");
|
||||
args.AddOption(&mesh_file2, "-m2", "--mesh2",
|
||||
"Second mesh file to use.");
|
||||
args.AddOption(&attr, "-at", "--attributes-surf",
|
||||
"Attributes of boundary faces on contact surface for mesh 2.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
Mesh mesh1(mesh_file1, 1, 1);
|
||||
Mesh mesh2(mesh_file2, 1, 1);
|
||||
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream mesh1a_sock(vishost, visport);
|
||||
mesh1a_sock.precision(8);
|
||||
mesh1a_sock << "mesh\n" << mesh1 << flush;
|
||||
socketstream mesh2a_sock(vishost, visport);
|
||||
mesh2a_sock.precision(8);
|
||||
mesh2a_sock << "mesh\n" << mesh2 << flush;
|
||||
}
|
||||
|
||||
const int dim = mesh1.Dimension();
|
||||
MFEM_VERIFY(dim == mesh2.Dimension(), "");
|
||||
|
||||
// boundary attribute 2 is the potential contact surface of nodes
|
||||
attr.Append(2);
|
||||
// boundary attribute 2 is the potential contact surface for master surface
|
||||
m_attr.Append(2);
|
||||
|
||||
// Define a finite element space on the mesh. Here we use vector finite
|
||||
// elements, i.e. dim copies of a scalar finite element space. The vector
|
||||
// dimension is specified by the last argument of the FiniteElementSpace
|
||||
// constructor.
|
||||
FiniteElementCollection *fec1;
|
||||
FiniteElementSpace *fespace1;
|
||||
fec1 = new H1_FECollection(1, dim);
|
||||
fespace1 = new FiniteElementSpace(&mesh1, fec1, dim, Ordering::byVDIM);
|
||||
cout << "Number of finite element unknowns for mesh1: "
|
||||
<< fespace1->GetTrueVSize() << endl;
|
||||
mesh1.SetNodalFESpace(fespace1);
|
||||
GridFunction nodes0 = *mesh1.GetNodes(); // undeformed mesh1 nodal grid function
|
||||
GridFunction *nodes1 = mesh1.GetNodes();
|
||||
|
||||
FiniteElementCollection *fec2 = new H1_FECollection(1, dim);
|
||||
FiniteElementSpace *fespace2 = new FiniteElementSpace(&mesh2, fec2, dim,
|
||||
Ordering::byVDIM);
|
||||
cout << "Number of finite element unknowns for mesh2: "
|
||||
<< fespace2->GetTrueVSize() << endl;
|
||||
|
||||
// degrees of freedom of both meshes
|
||||
int ndof_1 = fespace1->GetTrueVSize();
|
||||
int ndof_2 = fespace2->GetTrueVSize();
|
||||
int ndofs = ndof_1 + ndof_2;
|
||||
// number of nodes for each mesh
|
||||
int nnd_1 = mesh1.GetNV();
|
||||
int nnd_2 = mesh2.GetNV();
|
||||
int nnd = nnd_1 + nnd_2;
|
||||
// Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined by marking only
|
||||
// boundary attribute 1 from the mesh as essential and converting it to a
|
||||
// list of true dofs.
|
||||
Array<int> ess_tdof_list1, ess_bdr1(mesh1.bdr_attributes.Max());
|
||||
ess_bdr1 = 0;
|
||||
//ess_bdr1[0] = 1;
|
||||
// Not ready to be passed on yet
|
||||
// fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
|
||||
Array<int> ess_tdof_list2, ess_bdr2(mesh2.bdr_attributes.Max());
|
||||
ess_bdr2 = 0;
|
||||
//ess_bdr2[0] = 1;
|
||||
|
||||
// Define the displacement vector x as a finite element grid function
|
||||
// corresponding to fespace. GridFunction is a derived class of Vector.
|
||||
GridFunction x1(fespace1);
|
||||
x1 = 0.0;
|
||||
GridFunction x2(fespace2);
|
||||
x2 = 0.0;
|
||||
|
||||
// Generate force
|
||||
LinearForm *b1 = new LinearForm(fespace1);
|
||||
b1->Assemble();
|
||||
|
||||
LinearForm *b2 = new LinearForm(fespace2);
|
||||
b2->Assemble();
|
||||
|
||||
// Set up the bilinear form a(.,.) on the finite element space
|
||||
// corresponding to the linear elasticity integrator with piece-wise
|
||||
// constants coefficient lambda and mu.
|
||||
Vector lambda1(mesh1.attributes.Max());
|
||||
lambda1 = 57.6923076923;
|
||||
PWConstCoefficient lambda1_func(lambda1);
|
||||
Vector mu1(mesh1.attributes.Max());
|
||||
mu1 = 38.4615384615;
|
||||
PWConstCoefficient mu1_func(mu1);
|
||||
|
||||
BilinearForm *a1 = new BilinearForm(fespace1);
|
||||
a1->AddDomainIntegrator(new ElasticityIntegrator(lambda1_func,mu1_func));
|
||||
|
||||
Vector lambda2(mesh2.attributes.Max());
|
||||
lambda2 = 57.6923076923;
|
||||
PWConstCoefficient lambda2_func(lambda2);
|
||||
Vector mu2(mesh2.attributes.Max());
|
||||
mu2 = 38.4615384615;
|
||||
PWConstCoefficient mu2_func(mu2);
|
||||
|
||||
BilinearForm *a2 = new BilinearForm(fespace2);
|
||||
a2->AddDomainIntegrator(new ElasticityIntegrator(lambda2_func,mu2_func));
|
||||
|
||||
a1->Assemble();
|
||||
SparseMatrix A1;
|
||||
Vector B1, X1;
|
||||
a1->FormLinearSystem(ess_tdof_list1, x1, *b1, A1, X1, B1);
|
||||
|
||||
a2->Assemble();
|
||||
SparseMatrix A2;
|
||||
Vector B2, X2;
|
||||
a2->FormLinearSystem(ess_tdof_list2, x2, *b2, A2, X2, B2);
|
||||
|
||||
// Combine elasticity operator for two meshes into one.
|
||||
// Block Matrix
|
||||
SparseMatrix K(ndofs,ndofs);
|
||||
for (int i=0; i<A1.Height(); i++)
|
||||
{
|
||||
Array<int> col_tmp;
|
||||
Vector v_tmp;
|
||||
col_tmp = 0;
|
||||
v_tmp = 0.0;
|
||||
A1.GetRow(i, col_tmp, v_tmp);
|
||||
K.SetRow(i, col_tmp, v_tmp);
|
||||
}
|
||||
for (int i=0; i<A2.Height(); i++)
|
||||
{
|
||||
Array<int> col_tmp;
|
||||
Vector v_tmp;
|
||||
col_tmp = 0;
|
||||
v_tmp = 0.0;
|
||||
A2.GetRow(i, col_tmp, v_tmp);
|
||||
for (int j=0; j<col_tmp.Size(); j++)
|
||||
{
|
||||
col_tmp[j] += ndof_1;
|
||||
}
|
||||
K.SetRow(i+ndof_1, col_tmp, v_tmp); // mesh1 top left corner
|
||||
}
|
||||
|
||||
// Construct node to segment contact constraint.
|
||||
|
||||
attr.Sort();
|
||||
cout << "Boundary attributes for contact surface faces in mesh 2" << endl;
|
||||
for (auto a : attr) { cout << a << endl; }
|
||||
|
||||
Array<int> bdryFaces2; // TODO: remove this?
|
||||
|
||||
std::set<int> bdryVerts2;
|
||||
for (int b=0; b<mesh2.GetNBE(); ++b)
|
||||
{
|
||||
if (attr.FindSorted(mesh2.GetBdrAttribute(b)) >= 0)
|
||||
{
|
||||
bdryFaces2.Append(b);
|
||||
Array<int> vert;
|
||||
mesh2.GetBdrElementVertices(b, vert);
|
||||
for (auto v : vert)
|
||||
{
|
||||
bdryVerts2.insert(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int npoints = bdryVerts2.size();
|
||||
Array<int> s_conn(npoints); // connectivity of the second/slave mesh
|
||||
Vector xyz(dim * npoints);
|
||||
xyz = 0.0;
|
||||
|
||||
cout << "Boundary vertices for contact surface vertices in mesh 2" << endl;
|
||||
|
||||
// construct the nodal coordinates on mesh2 to be projected, including displacement
|
||||
int count = 0;
|
||||
for (auto v : bdryVerts2)
|
||||
{
|
||||
cout << v << ": " << mesh2.GetVertex(v)[0] << ", "
|
||||
<< mesh2.GetVertex(v)[1] << ", "
|
||||
<< mesh2.GetVertex(v)[2] << endl;
|
||||
|
||||
for (int i=0; i<dim; ++i)
|
||||
{
|
||||
xyz[count + (i * npoints)] = mesh2.GetVertex(v)[i] + x2[v*dim+i];
|
||||
}
|
||||
|
||||
s_conn[count] = v + nnd_1; // dof1 is the master
|
||||
count++;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(count == npoints, "");
|
||||
|
||||
// gap function
|
||||
Vector g(npoints*dim);
|
||||
g = -1.0;
|
||||
// segment reference coordinates of the closest point
|
||||
Vector m_xi(npoints*(dim-1));
|
||||
m_xi = -1.0;
|
||||
Vector xs(dim*npoints);
|
||||
xs = 0.0;
|
||||
for (int i=0; i<npoints; i++)
|
||||
{
|
||||
for (int j=0; j<dim; j++)
|
||||
{
|
||||
xs[i*dim+j] = xyz[i + (j*npoints)];
|
||||
}
|
||||
}
|
||||
|
||||
Array<int> m_conn(
|
||||
npoints*4); // only works for linear elements that have 4 vertices!
|
||||
DenseMatrix coordsm(npoints*4, dim);
|
||||
|
||||
// adding displacement to mesh1 using a fixed grid function from mesh1
|
||||
x1 = 1e-4; // x1 order: [xyz xyz... xyz]
|
||||
add(nodes0, x1, *nodes1);
|
||||
|
||||
FindPointsInMesh(mesh1, xyz, m_conn, m_xi);
|
||||
|
||||
for (int i=0; i<npoints; i++)
|
||||
{
|
||||
for (int j=0; j<4; j++)
|
||||
{
|
||||
for (int k=0; k<dim; k++)
|
||||
{
|
||||
coordsm(i*4+j,k) = mesh1.GetVertex(m_conn[i*4+j])[k]+x1[dim*m_conn[i*4+j]+k];
|
||||
}
|
||||
}
|
||||
}
|
||||
//coordsm.Print();
|
||||
SparseMatrix M(nnd,ndofs);
|
||||
std::vector<SparseMatrix> dM(nnd, SparseMatrix(ndofs,ndofs));
|
||||
|
||||
Assemble_Contact(nnd, npoints, ndofs, xs, m_xi, coordsm,
|
||||
s_conn, m_conn, g, M, dM);
|
||||
|
||||
std::set<int> dirbdryv2;
|
||||
for (int b=0; b<mesh2.GetNBE(); ++b)
|
||||
{
|
||||
if (mesh2.GetBdrAttribute(b) == 1)
|
||||
{
|
||||
Array<int> vert;
|
||||
mesh2.GetBdrElementVertices(b, vert);
|
||||
for (auto v : vert)
|
||||
{
|
||||
dirbdryv2.insert(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::set<int> dirbdryv1;
|
||||
for (int b=0; b<mesh1.GetNBE(); ++b)
|
||||
{
|
||||
if (mesh1.GetBdrAttribute(b) == 1)
|
||||
{
|
||||
Array<int> vert;
|
||||
mesh1.GetBdrElementVertices(b, vert);
|
||||
for (auto v : vert)
|
||||
{
|
||||
dirbdryv1.insert(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array<int> Dirichlet_dof;
|
||||
Array<double> Dirichlet_val;
|
||||
|
||||
for (auto v : dirbdryv2)
|
||||
{
|
||||
for (int i=0; i<dim; ++i)
|
||||
{
|
||||
Dirichlet_dof.Append(v*dim + i + ndof_1);
|
||||
Dirichlet_val.Append(0.);
|
||||
}
|
||||
}
|
||||
double delta = 0.1;
|
||||
for (auto v : dirbdryv1)
|
||||
{
|
||||
Dirichlet_dof.Append(v*dim + 0);
|
||||
Dirichlet_val.Append(delta);
|
||||
Dirichlet_dof.Append(v*dim + 1);
|
||||
Dirichlet_val.Append(0.);
|
||||
Dirichlet_dof.Append(v*dim + 2);
|
||||
Dirichlet_val.Append(0.);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream mesh1_sock(vishost, visport);
|
||||
mesh1_sock.precision(8);
|
||||
mesh1_sock << "mesh\n" << mesh1 << flush;
|
||||
socketstream mesh2_sock(vishost, visport);
|
||||
mesh2_sock.precision(8);
|
||||
mesh2_sock << "mesh\n" << mesh2 << flush;
|
||||
}
|
||||
|
||||
//M.Print();
|
||||
/*Vector eps(ndofs);
|
||||
Vector sol(ndofs); sol = 0.;
|
||||
for(int i=0;i<ndofs;i++) eps[i] = 1e-5 * i ;
|
||||
for(int i=0;i<9;i++)
|
||||
{
|
||||
cout<<i<<endl;
|
||||
dM[s_conn[i]].Mult(eps,sol);
|
||||
sol.Print();
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
-1621
File diff suppressed because it is too large
Load Diff
@@ -1,381 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
template <typename T>
|
||||
constexpr auto get_type_name() -> std::string_view
|
||||
{
|
||||
#if defined(__clang__)
|
||||
constexpr auto prefix = std::string_view {"[T = "};
|
||||
constexpr auto suffix = "]";
|
||||
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
|
||||
#elif defined(__GNUC__)
|
||||
constexpr auto prefix = std::string_view {"with T = "};
|
||||
constexpr auto suffix = "; ";
|
||||
constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
|
||||
#elif defined(_MSC_VER)
|
||||
constexpr auto prefix = std::string_view {"get_type_name<"};
|
||||
constexpr auto suffix = ">(void)";
|
||||
constexpr auto function = std::string_view{__FUNCSIG__};
|
||||
#else
|
||||
#error Unsupported compiler
|
||||
#endif
|
||||
|
||||
const auto start = function.find(prefix) + prefix.size();
|
||||
const auto end = function.find(suffix);
|
||||
const auto size = end - start;
|
||||
|
||||
return function.substr(start, size);
|
||||
}
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <mfem.hpp>
|
||||
#include <linalg/dtensor.hpp>
|
||||
#include "linalg/tensor.hpp"
|
||||
#include <linalg/kernels.hpp>
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
template <
|
||||
typename type,
|
||||
int rank = 1>
|
||||
class NDArray : public Array<type>
|
||||
{
|
||||
};
|
||||
|
||||
template <class F>
|
||||
struct FunctionSignature;
|
||||
|
||||
template <typename output_type, typename... input_types>
|
||||
struct FunctionSignature<output_type(input_types...)>
|
||||
{
|
||||
using return_type = output_type;
|
||||
using parameter_types = std::tuple<input_types...>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct create_function_signature;
|
||||
|
||||
template <typename output_type, typename T, typename... input_types>
|
||||
struct create_function_signature<output_type (T::*)(input_types...) const>
|
||||
{
|
||||
using type = FunctionSignature<output_type(input_types...)>;
|
||||
};
|
||||
|
||||
template <typename function_type, typename... input_types, typename output_type,
|
||||
typename... arg_types>
|
||||
void forall_impl(FunctionSignature<output_type(input_types...)>,
|
||||
const function_type &f, const int n, arg_types &...args)
|
||||
{
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
f(((typename std::remove_reference<input_types>::type
|
||||
*)(args.begin()))[i]...);
|
||||
};
|
||||
}
|
||||
|
||||
template <typename function_type, typename... arg_types>
|
||||
void forall(const function_type &f, const int n, arg_types &...args)
|
||||
{
|
||||
using function_signature_type = typename create_function_signature<
|
||||
decltype(&function_type::operator())>::type;
|
||||
forall_impl(function_signature_type{}, f, n, args...);
|
||||
}
|
||||
|
||||
template <typename... arg_types, typename... input_types>
|
||||
void forall(void (*f)(arg_types &...), const int n, input_types &...args)
|
||||
{
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
f(((typename std::remove_reference<arg_types>::type*)(args.begin()))[i]...);
|
||||
};
|
||||
}
|
||||
|
||||
template <
|
||||
typename output_type,
|
||||
typename... input_types>
|
||||
auto fwddiff(output_type (*f)(input_types...))
|
||||
{
|
||||
return [f](input_types... args, input_types... args2)
|
||||
{
|
||||
auto input_types_tuple = std::tuple<input_types...>(args...);
|
||||
auto shadow_input_types_tuple = std::tuple<input_types...>(args2...);
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<decltype(input_types_tuple), decltype(shadow_input_types_tuple)>,
|
||||
"input and shadow not equal");
|
||||
|
||||
// auto concatenated_types_tuple = std::tuple_cat(input_types_tuple,
|
||||
// shadow_input_types_tuple);
|
||||
|
||||
// std::cout << get_type_name<decltype(concatenated_types_tuple)>() << std::endl;
|
||||
|
||||
return __enzyme_fwddiff<output_type>(f, &args..., &args2...);
|
||||
};
|
||||
}
|
||||
|
||||
/// @return u_qp qp x vdim x elements
|
||||
void interpolate(const GridFunction &u, const IntegrationRule &ir, Vector &u_qp)
|
||||
{
|
||||
auto fes = u.FESpace();
|
||||
auto B = fes->GetQuadratureInterpolator(ir);
|
||||
B->SetOutputLayout(QVectorLayout::byVDIM);
|
||||
B->DisableTensorProducts();
|
||||
|
||||
auto R = fes->GetElementRestriction(ElementDofOrdering::NATIVE);
|
||||
Vector u_el(R->Height());
|
||||
R->Mult(u, u_el);
|
||||
|
||||
u_qp.SetSize(fes->GetVDim() *
|
||||
fes->GetMesh()->GetNE() *
|
||||
ir.GetNPoints());
|
||||
|
||||
B->Values(u_el, u_qp);
|
||||
}
|
||||
|
||||
void gradient_wrt_x(const GridFunction &u, const IntegrationRule &ir,
|
||||
Vector &grad_u_qp)
|
||||
{
|
||||
auto fes = u.FESpace();
|
||||
auto B = fes->GetQuadratureInterpolator(ir);
|
||||
B->SetOutputLayout(QVectorLayout::byVDIM);
|
||||
B->DisableTensorProducts();
|
||||
|
||||
auto R = fes->GetElementRestriction(ElementDofOrdering::NATIVE);
|
||||
Vector u_el(R->Height());
|
||||
R->Mult(u, u_el);
|
||||
|
||||
grad_u_qp.SetSize(
|
||||
fes->GetVDim() *
|
||||
fes->GetMesh()->Dimension() *
|
||||
fes->GetMesh()->GetNE() *
|
||||
ir.GetNPoints());
|
||||
|
||||
B->PhysDerivatives(u_el, grad_u_qp);
|
||||
|
||||
if (fes->GetVDim() > 1)
|
||||
{
|
||||
forall([&](const mfem::internal::tensor<double, 2, 2> &dudx,
|
||||
mfem::internal::tensor<double, 2, 2> &dudx_transpose)
|
||||
{
|
||||
dudx_transpose = transpose(dudx);
|
||||
}, ir.GetNPoints() * fes->GetMesh()->GetNE(), grad_u_qp, grad_u_qp);
|
||||
}
|
||||
}
|
||||
|
||||
void integrate_basis(Vector &s_qp, const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir, Vector &yi)
|
||||
{
|
||||
auto R = fes.GetElementRestriction(ElementDofOrdering::NATIVE);
|
||||
|
||||
auto mesh = fes.GetMesh();
|
||||
// const int dim = mesh->Dimension();
|
||||
const int num_el = mesh->GetNE();
|
||||
const int vdim = fes.GetVDim();
|
||||
const int num_qp = ir.GetNPoints();
|
||||
const int num_vdofs = R->Height() / num_el;
|
||||
const int num_dofs = num_vdofs / vdim;
|
||||
|
||||
if constexpr(false)
|
||||
{
|
||||
out << "#el: " << num_el << " vdim: " << vdim << " #qp: " << num_qp
|
||||
<< " #vdofs: " << num_vdofs << " #dofs: " << num_dofs << "\n";
|
||||
}
|
||||
|
||||
const GeometricFactors *geom = mesh->GetGeometricFactors(
|
||||
ir, GeometricFactors::JACOBIANS | GeometricFactors::DETERMINANTS);
|
||||
Vector yi_el(R->Height());
|
||||
yi_el = 0.0;
|
||||
auto Yi = Reshape(yi_el.Write(), num_dofs, vdim, num_el);
|
||||
auto C = Reshape(s_qp.ReadWrite(), vdim, num_qp, num_el);
|
||||
auto detJ = Reshape(geom->detJ.Read(), num_qp, num_el);
|
||||
for (int e = 0; e < num_el; e++)
|
||||
{
|
||||
const DofToQuad &maps = fes.GetFE(e)->GetDofToQuad(ir, DofToQuad::FULL);
|
||||
const auto Bt = Reshape(maps.Bt.Read(), num_dofs, num_qp);
|
||||
|
||||
for (int dof = 0; dof < num_dofs; dof++)
|
||||
{
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
{
|
||||
double s = 0.0;
|
||||
for (int qp = 0; qp < num_qp; qp++)
|
||||
{
|
||||
s += Bt(dof, qp) * C(vd, qp, e) * detJ(qp, e) * ir.GetWeights()[qp];
|
||||
}
|
||||
Yi(dof, vd, e) = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yi.SetSize(fes.GetVSize());
|
||||
R->MultTranspose(yi_el, yi);
|
||||
}
|
||||
|
||||
void integrate_basis_gradient(Vector &s_qp, const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir, Vector &yi,
|
||||
const Vector &element_jacobian_inverse)
|
||||
{
|
||||
auto R = fes.GetElementRestriction(ElementDofOrdering::NATIVE);
|
||||
|
||||
auto mesh = fes.GetMesh();
|
||||
const int dim = mesh->Dimension();
|
||||
const int num_el = mesh->GetNE();
|
||||
const int vdim = fes.GetVDim();
|
||||
const int num_qp = ir.GetNPoints();
|
||||
const int num_vdofs = R->Height() / num_el;
|
||||
const int num_dofs = num_vdofs / vdim;
|
||||
|
||||
const GeometricFactors *geom = mesh->GetGeometricFactors(
|
||||
ir, GeometricFactors::JACOBIANS | GeometricFactors::DETERMINANTS);
|
||||
|
||||
Vector yi_el(R->Height());
|
||||
auto Yi = Reshape(yi_el.Write(), num_dofs, vdim, num_el);
|
||||
|
||||
auto C = Reshape(s_qp.ReadWrite(), vdim, dim, num_qp, num_el);
|
||||
auto detJ = Reshape(geom->detJ.Read(), num_qp, num_el);
|
||||
auto JqpInv = Reshape(element_jacobian_inverse.Read(), num_qp, dim, dim,
|
||||
num_el);
|
||||
|
||||
CALI_CXX_MARK_LOOP_BEGIN(element_loop, "element_loop");
|
||||
for (int e = 0; e < num_el; e++)
|
||||
{
|
||||
CALI_CXX_MARK_LOOP_ITERATION(element_loop, e);
|
||||
const DofToQuad &maps = fes.GetFE(e)->GetDofToQuad(ir, DofToQuad::FULL);
|
||||
const auto Gt = Reshape(maps.Gt.Read(), num_dofs, num_qp, dim);
|
||||
|
||||
for (int dof = 0; dof < num_dofs; dof++)
|
||||
{
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
{
|
||||
double s = 0.0;
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int qp = 0; qp < num_qp; qp++)
|
||||
{
|
||||
const double JxW = detJ(qp, e) * ir.GetWeights()[qp];
|
||||
for (int k = 0; k < dim; k++)
|
||||
{
|
||||
s += Gt(dof, qp, d) * JqpInv(qp, d, k, e) * C(vd, k, qp, e) * JxW;
|
||||
}
|
||||
}
|
||||
}
|
||||
Yi(dof, vd, e) = s;
|
||||
}
|
||||
}
|
||||
|
||||
// for (int qp = 0; qp < num_qp; qp++)
|
||||
// {
|
||||
// const double JxW = detJ(qp, e) * ir.GetWeights()[qp];
|
||||
|
||||
// // Pullback Gradient into physical space
|
||||
// Vector dphidx_data(num_dofs * dim);
|
||||
// dphidx_data = 0.0;
|
||||
// auto dphidx = Reshape(dphidx_data.ReadWrite(), num_dofs, dim);
|
||||
// for (int d = 0; d < dim; d++)
|
||||
// {
|
||||
// for (int dof = 0; dof < num_dofs; dof++)
|
||||
// {
|
||||
// for (int k = 0; k < dim; k++)
|
||||
// {
|
||||
// dphidx(dof, d) += G(qp, k, dof) * JqpInv(qp, k, d, e);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// for (int vd = 0; vd < vdim; vd++)
|
||||
// {
|
||||
// for (int dof = 0; dof < num_dofs; dof++)
|
||||
// {
|
||||
// double s = 0;
|
||||
// for (int d = 0; d < dim; d++)
|
||||
// {
|
||||
// s += dphidx(dof, d) * C(vd, d, qp, e) * JxW;
|
||||
// }
|
||||
// Yi(dof, vd, e) = s;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
CALI_CXX_MARK_LOOP_END(element_loop);
|
||||
yi.SetSize(fes.GetVSize());
|
||||
R->MultTranspose(yi_el, yi);
|
||||
}
|
||||
|
||||
void interpolate_boundary(const GridFunction &u, const IntegrationRule &ir_face,
|
||||
Vector &u_qp)
|
||||
{
|
||||
auto fes = u.FESpace();
|
||||
auto B = fes->GetFaceQuadratureInterpolator(ir_face, FaceType::Boundary);
|
||||
B->SetOutputLayout(QVectorLayout::byVDIM);
|
||||
B->DisableTensorProducts();
|
||||
|
||||
auto R = fes->GetFaceRestriction(ElementDofOrdering::LEXICOGRAPHIC,
|
||||
FaceType::Boundary);
|
||||
Vector u_el(R->Height());
|
||||
R->Mult(u, u_el);
|
||||
|
||||
u_qp.SetSize(
|
||||
fes->GetVDim() *
|
||||
fes->GetMesh()->GetNBE() *
|
||||
ir_face.GetNPoints());
|
||||
|
||||
B->Values(u_el, u_qp);
|
||||
}
|
||||
|
||||
void integrate_basis_boundary(Vector &s_qp,
|
||||
const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir_face, Vector &yi)
|
||||
{
|
||||
const auto fe = fes.GetFaceElement(0);
|
||||
const auto tfe = dynamic_cast<const TensorBasisElement *>(fe);
|
||||
MFEM_VERIFY(tfe != nullptr, "FE not a TensorBasisElement");
|
||||
|
||||
auto R = fes.GetFaceRestriction(ElementDofOrdering::LEXICOGRAPHIC,
|
||||
FaceType::Boundary);
|
||||
|
||||
auto mesh = fes.GetMesh();
|
||||
// const int dim = mesh->Dimension();
|
||||
const int num_fel = mesh->GetNBE();
|
||||
// const int num_fel = mesh->GetNFaces();
|
||||
const int vdim = fes.GetVDim();
|
||||
const int num_qp = ir_face.GetNPoints();
|
||||
const int num_vdofs = R->Height() / num_fel;
|
||||
const int num_dofs = num_vdofs / vdim;
|
||||
|
||||
const FaceGeometricFactors *geom = mesh->GetFaceGeometricFactors(
|
||||
ir_face, FaceGeometricFactors::DETERMINANTS,
|
||||
FaceType::Boundary, s_qp.GetMemory().GetMemoryType());
|
||||
Vector yi_el(R->Height());
|
||||
yi_el = 0.0;
|
||||
auto Yi = Reshape(yi_el.Write(), num_dofs, vdim, num_fel);
|
||||
auto C = Reshape(s_qp.ReadWrite(), vdim, num_qp, num_fel);
|
||||
auto detJ = Reshape(geom->detJ.Read(), num_qp, num_fel);
|
||||
|
||||
const DofToQuad &maps = fe->GetDofToQuad(ir_face, DofToQuad::FULL);
|
||||
auto lex_to_native = tfe->GetDofMap();
|
||||
|
||||
for (int e = 0; e < num_fel; e++)
|
||||
{
|
||||
// const DofToQuad &maps = fes.GetBE(e)->GetDofToQuad(ir_face, DofToQuad::FULL);
|
||||
const auto Bt = Reshape(maps.Bt.Read(), num_dofs, num_qp);
|
||||
|
||||
for (int dof = 0; dof < num_dofs; dof++)
|
||||
{
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
{
|
||||
double s = 0.0;
|
||||
for (int qp = 0; qp < num_qp; qp++)
|
||||
{
|
||||
s += Bt(lex_to_native[dof], qp) * C(vd, qp, e)
|
||||
* detJ(qp, e) * ir_face.GetWeights()[qp];
|
||||
}
|
||||
Yi(dof, vd, e) = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yi.SetSize(fes.GetVSize());
|
||||
R->MultTranspose(yi_el, yi);
|
||||
}
|
||||
@@ -1,666 +0,0 @@
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "dfem.hpp"
|
||||
|
||||
#include "eigen-3.4.0/Eigen/Eigen"
|
||||
|
||||
using namespace mfem;
|
||||
using mfem::internal::tensor;
|
||||
using mfem::internal::dual;
|
||||
|
||||
class LambdaOperator : public Operator
|
||||
{
|
||||
public:
|
||||
LambdaOperator(int size,
|
||||
std::function<void(const Vector&, Vector&)> mult_f) :
|
||||
Operator(size),
|
||||
mult_f(mult_f)
|
||||
{}
|
||||
|
||||
void Mult(const Vector& X, Vector& Y) const
|
||||
{
|
||||
mult_f(X, Y);
|
||||
}
|
||||
|
||||
std::function<void(const Vector&, Vector&)> mult_f;
|
||||
};
|
||||
|
||||
class ADOperator : public Operator
|
||||
{
|
||||
public:
|
||||
ADOperator(int size) : Operator(size) {}
|
||||
virtual void GradientMult(const Vector &dX, Vector &Y) const = 0;
|
||||
virtual void AdjointMult(const Vector &L, Vector &Y) const = 0;
|
||||
};
|
||||
|
||||
class PLaplacianGradientOperator : public Operator
|
||||
{
|
||||
public:
|
||||
PLaplacianGradientOperator(ADOperator &op) :
|
||||
Operator(op.Height()), op(op) {}
|
||||
|
||||
void Mult(const Vector &x, Vector &y) const override
|
||||
{
|
||||
op.GradientMult(x, y);
|
||||
}
|
||||
|
||||
ADOperator &op;
|
||||
};
|
||||
|
||||
class PLaplacianAdjointOperator : public Operator
|
||||
{
|
||||
public:
|
||||
PLaplacianAdjointOperator(ADOperator &op) :
|
||||
Operator(op.Height()), op(op) {}
|
||||
|
||||
void Mult(const Vector &x, Vector &y) const override
|
||||
{
|
||||
op.AdjointMult(x, y);
|
||||
}
|
||||
|
||||
ADOperator &op;
|
||||
};
|
||||
|
||||
class PLaplacianOperator : public ADOperator
|
||||
{
|
||||
public:
|
||||
PLaplacianOperator(ParFiniteElementSpace &fes, ParGridFunction &u) :
|
||||
ADOperator(fes.GetTrueVSize()),
|
||||
mesh(fes.GetParMesh()),
|
||||
fes(fes),
|
||||
u(u.ParFESpace()),
|
||||
l(u.ParFESpace()),
|
||||
ir(const_cast<IntegrationRule &>(IntRules.Get(
|
||||
Element::QUADRILATERAL,
|
||||
2 * mesh->GetNodes()->FESpace()->GetOrder(0) + 1)))
|
||||
{
|
||||
Array<int> ess_bdr(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
|
||||
du.SetSpace(u.FESpace());
|
||||
x_lvec.SetSize(fes.GetProlongationMatrix()->Height());
|
||||
x_lvec = 0.0;
|
||||
y_lvec.SetSize(fes.GetProlongationMatrix()->Height());
|
||||
du_tvec.SetSize(fes.GetProlongationMatrix()->Width());
|
||||
l_tvec.SetSize(fes.GetProlongationMatrix()->Width());
|
||||
|
||||
gradient = new PLaplacianGradientOperator(*this);
|
||||
adjoint = new PLaplacianAdjointOperator(*this);
|
||||
}
|
||||
|
||||
void SetVolumeForcing(ParGridFunction &forcing)
|
||||
{
|
||||
volume_force = &forcing;
|
||||
}
|
||||
|
||||
// F(u, g) = (pow(norm(grad_u), 0.5 * (p - 2)) * grad u, grad phi) - (g, phi)
|
||||
void Mult(const Vector &x, Vector &y) const override
|
||||
{
|
||||
// T -> L
|
||||
fes.GetProlongationMatrix()->Mult(x, u);
|
||||
|
||||
// L -> Q
|
||||
|
||||
// [vdim, dim, num_qp, num_el]
|
||||
auto grad_u_qp = gradient_wrt_x(u, ir);
|
||||
|
||||
// Q -> Q
|
||||
auto plap = [](tensor<double, 2> grad_u)
|
||||
{
|
||||
// grad_u := [dudx dudy]
|
||||
const int p = 4;
|
||||
return (pow(norm(grad_u), 0.5 * (p - 2)) * grad_u);
|
||||
};
|
||||
|
||||
auto f_grad_u_qp = forall(plap, ir.GetNPoints() * mesh->GetNE(),
|
||||
grad_u_qp);
|
||||
|
||||
// Layout of f_grad_u_qp_flat has to be [vdim, dim, num_qp, num_el]
|
||||
Vector f_grad_u_qp_flat((double *)f_grad_u_qp.GetData(),
|
||||
1 * 2 * ir.GetNPoints() *
|
||||
mesh->GetNE());
|
||||
|
||||
Vector f_grad_u_grad_phi = integrate_basis_gradient(f_grad_u_qp_flat,
|
||||
fes,
|
||||
ir);
|
||||
|
||||
// - (g, phi)
|
||||
auto g_qp = interpolate(*volume_force, ir);
|
||||
Vector g_phi = integrate_basis(g_qp, fes, ir);
|
||||
f_grad_u_grad_phi -= g_phi;
|
||||
|
||||
// L -> T
|
||||
fes.GetProlongationMatrix()->MultTranspose(f_grad_u_grad_phi, y);
|
||||
|
||||
y.SetSubVector(ess_tdof_list, 0.0);
|
||||
}
|
||||
|
||||
// df/du
|
||||
Operator &GetGradient(const Vector &x) const override
|
||||
{
|
||||
// T -> L
|
||||
fes.GetProlongationMatrix()->Mult(x, state_lvec);
|
||||
return *gradient;
|
||||
}
|
||||
|
||||
// dX: current iterate
|
||||
// Y: dR/dU * dX
|
||||
void GradientMult(const Vector &X, Vector &Y) const override
|
||||
{
|
||||
// apply essential bcs
|
||||
du_tvec = X;
|
||||
du_tvec.SetSubVector(ess_tdof_list, 0.0);
|
||||
|
||||
du.SetFromTrueDofs(du_tvec);
|
||||
u = state_lvec;
|
||||
|
||||
auto grad_u_qp = gradient_wrt_x(u, ir);
|
||||
auto grad_du_qp = gradient_wrt_x(du, ir);
|
||||
|
||||
const int N = mesh->GetNE() * ir.GetNPoints();
|
||||
|
||||
auto plap2 = [](tensor<double, 2> &grad_u)
|
||||
{
|
||||
const int p = 4;
|
||||
return (pow(norm(grad_u), 0.5 * (p - 2)) * grad_u);
|
||||
};
|
||||
|
||||
auto flux_qp = forall([&, plap2](tensor<double,2> grad_u,
|
||||
tensor<double,2> grad_du)
|
||||
{
|
||||
return fwddiff(+plap2)(grad_u, grad_du);
|
||||
}, N, grad_u_qp, grad_du_qp);
|
||||
|
||||
// has to be [vdim, dim, num_qp, num_el]
|
||||
Vector flux_qp_flat((double *)flux_qp.GetData(), 1 * 2 * N);
|
||||
|
||||
Vector y = integrate_basis_gradient(flux_qp_flat, fes, ir);
|
||||
|
||||
// L-vector to T-vector
|
||||
fes.GetProlongationMatrix()->MultTranspose(y, Y);
|
||||
|
||||
// Re-assign the essential degrees of freedom on the final output vector.
|
||||
for (int i = 0; i < ess_tdof_list.Size(); i++)
|
||||
{
|
||||
Y[ess_tdof_list[i]] = X[ess_tdof_list[i]];
|
||||
}
|
||||
}
|
||||
|
||||
// (dF/dU)^t
|
||||
Operator &GetAdjoint(const Vector &u) const
|
||||
{
|
||||
// T -> L
|
||||
fes.GetProlongationMatrix()->Mult(u, state_lvec);
|
||||
return *adjoint;
|
||||
}
|
||||
|
||||
// dL: current iterate of adjoint state
|
||||
// Y: (dF/dU)^t * dL
|
||||
void AdjointMult(const Vector &dL, Vector &Y) const override
|
||||
{
|
||||
// apply essential bcs
|
||||
l_tvec = dL;
|
||||
l_tvec.SetSubVector(ess_tdof_list, 0.0);
|
||||
|
||||
l.SetFromTrueDofs(l_tvec);
|
||||
u = state_lvec;
|
||||
|
||||
auto grad_u_qp = gradient_wrt_x(u, ir);
|
||||
// L * B^t -> B * L
|
||||
auto grad_l_qp = gradient_wrt_x(l, ir);
|
||||
|
||||
const int N = mesh->GetNE() * ir.GetNPoints();
|
||||
|
||||
auto plap2 = [](tensor<double, 2> &grad_u, tensor<double, 2> &flux)
|
||||
{
|
||||
const int p = 4;
|
||||
flux = (pow(norm(grad_u), 0.5 * (p - 2)) * grad_u);
|
||||
};
|
||||
|
||||
auto ev_action_qp = forall([&, plap2](tensor<double,2> grad_u,
|
||||
tensor<double,2> grad_l)
|
||||
{
|
||||
tensor<double, 2> unused_output{};
|
||||
tensor<double, 2> dgrad_u{};
|
||||
// autodiff == reverse mode
|
||||
__enzyme_autodiff<tensor<double, 2>>(+plap2, &grad_u, &dgrad_u, &unused_output,
|
||||
&grad_l);
|
||||
return dgrad_u;
|
||||
}, N, grad_u_qp, grad_l_qp);
|
||||
|
||||
// has to be [vdim, dim, num_qp, num_el]
|
||||
Vector ev_action_qp_flat((double *)ev_action_qp.GetData(), 1 * 2 * N);
|
||||
Vector y = integrate_basis_gradient(ev_action_qp_flat, fes, ir);
|
||||
|
||||
// L-vector to T-vector
|
||||
fes.GetProlongationMatrix()->MultTranspose(y, Y);
|
||||
|
||||
// Re-assign the essential degrees of freedom on the final output vector.
|
||||
for (int i = 0; i < ess_tdof_list.Size(); i++)
|
||||
{
|
||||
Y[ess_tdof_list[i]] = dL[ess_tdof_list[i]];
|
||||
}
|
||||
}
|
||||
|
||||
// Compute adjoint state of the primal state u
|
||||
Vector ComputeAdjointState(const ParGridFunction &u)
|
||||
{
|
||||
Vector l_tdof(u.ParFESpace()->GetTrueVSize());
|
||||
l_tdof = 0.0; // ?
|
||||
l_tdof.SetSubVector(ess_tdof_list, 0.0);
|
||||
|
||||
// Get adjoint load
|
||||
auto rhs_tdof = ComputeDQoIDU(u);
|
||||
rhs_tdof.SetSubVector(ess_tdof_list, 0.0);
|
||||
|
||||
// Get Jacobian
|
||||
auto u_tdof = u.GetTrueDofs();
|
||||
Operator &J = GetAdjoint(*u_tdof);
|
||||
|
||||
std::ofstream myfile("adjoint.txt");
|
||||
J.PrintMatlab(myfile);
|
||||
myfile.close();
|
||||
|
||||
Operator &G = GetGradient(*u_tdof);
|
||||
std::ofstream myfile2("jacobian.txt");
|
||||
G.PrintMatlab(myfile2);
|
||||
myfile2.close();
|
||||
|
||||
GMRESSolver gmres(MPI_COMM_WORLD);
|
||||
gmres.SetRelTol(1e-12);
|
||||
gmres.SetMaxIter(2000);
|
||||
gmres.SetPrintLevel(0);
|
||||
gmres.SetOperator(J);
|
||||
|
||||
gmres.Mult(rhs_tdof, l_tdof);
|
||||
|
||||
delete u_tdof;
|
||||
return l_tdof;
|
||||
}
|
||||
|
||||
Vector ComputeDfDpTv(const ParGridFunction &v)
|
||||
{
|
||||
const int N = mesh->GetNE() * ir.GetNPoints();
|
||||
Vector dfdpTv(volume_force->ParFESpace()->GetTrueVSize());
|
||||
|
||||
LambdaOperator K(dfdpTv.Size(), [&](const Vector& v, Vector& dfdpTv)
|
||||
{
|
||||
Vector vv(v.Size());
|
||||
// apply essential bcs
|
||||
vv = v;
|
||||
vv.SetSubVector(ess_tdof_list, 0.0);
|
||||
|
||||
GridFunction v_gf(volume_force->FESpace());
|
||||
v_gf.SetFromTrueDofs(vv);
|
||||
|
||||
auto g_qp = interpolate(*volume_force, ir);
|
||||
auto v_qp = interpolate(v_gf, ir);
|
||||
|
||||
auto fg = [](double &g, double &f)
|
||||
{
|
||||
f = -g;
|
||||
};
|
||||
|
||||
auto ev_action_qp = forall([&, fg](double g, double v)
|
||||
{
|
||||
double unused_output = 0.0;
|
||||
double dg = 0.0;
|
||||
__enzyme_autodiff<double>(+fg, &g, &dg, &unused_output, &v);
|
||||
return dg;
|
||||
}, N, g_qp, v_qp);
|
||||
|
||||
Vector ev_action_qp_flat((double *)ev_action_qp.GetData(), N);
|
||||
Vector y = integrate_basis(ev_action_qp_flat, fes, ir);
|
||||
|
||||
// L-vector to T-vector
|
||||
fes.GetProlongationMatrix()->MultTranspose(y, dfdpTv);
|
||||
|
||||
// Re-assign the essential degrees of freedom on the final output vector.
|
||||
for (int i = 0; i < ess_tdof_list.Size(); i++)
|
||||
{
|
||||
dfdpTv[ess_tdof_list[i]] = v[ess_tdof_list[i]];
|
||||
}
|
||||
});
|
||||
|
||||
auto v_tdof = v.GetTrueDofs();
|
||||
K.Mult(*v_tdof, dfdpTv);
|
||||
|
||||
std::ofstream myfile("dfdp.txt");
|
||||
K.PrintMatlab(myfile);
|
||||
myfile.close();
|
||||
|
||||
delete v_tdof;
|
||||
return dfdpTv;
|
||||
}
|
||||
|
||||
double ComputeQoI(const ParGridFunction &u_gf)
|
||||
{
|
||||
const int N = mesh->GetNE() * ir.GetNPoints();
|
||||
|
||||
auto u_qp = interpolate(u_gf, ir);
|
||||
|
||||
auto qoi = [](double u)
|
||||
{
|
||||
return 0.5 * pow(u, 2.0);
|
||||
};
|
||||
|
||||
auto qoi_qp = forall(qoi, 2 * N, u_qp);
|
||||
Vector qoi_qp_flat((double *)qoi_qp.GetData(), 2 * N);
|
||||
|
||||
L2_FECollection l2_0(0, mesh->Dimension());
|
||||
ParFiniteElementSpace l2_0_fes(mesh, &l2_0);
|
||||
|
||||
auto qoi_value = integrate_basis(qoi_qp_flat, l2_0_fes, ir);
|
||||
|
||||
return qoi_value.Sum();
|
||||
}
|
||||
|
||||
Vector ComputeDQoIDU(const ParGridFunction &u_gf)
|
||||
{
|
||||
const int N = mesh->GetNE() * ir.GetNPoints();
|
||||
|
||||
auto u_qp = interpolate(u_gf, ir);
|
||||
Vector du_qp(u_qp);
|
||||
du_qp = 1.0;
|
||||
|
||||
auto qoi = [](double &u)
|
||||
{
|
||||
return 0.5 * pow(u, 2.0);
|
||||
};
|
||||
|
||||
auto dqoidu_qp = forall([&, qoi](double u, double du)
|
||||
{
|
||||
return fwddiff(+qoi)(u, du);
|
||||
}, N, u_qp, du_qp);
|
||||
|
||||
Vector dqoidu_qp_flat((double *)dqoidu_qp.GetData(), N);
|
||||
|
||||
auto dqoidu_qp_value = integrate_basis(dqoidu_qp_flat, *u_gf.FESpace(), ir);
|
||||
|
||||
Vector Y(u_gf.ParFESpace()->GetTrueVSize());
|
||||
u_gf.ParFESpace()->GetProlongationMatrix()->MultTranspose(dqoidu_qp_value, Y);
|
||||
|
||||
return Y;
|
||||
}
|
||||
|
||||
~PLaplacianOperator()
|
||||
{
|
||||
}
|
||||
|
||||
ParMesh *mesh;
|
||||
ParFiniteElementSpace &fes;
|
||||
mutable ParGridFunction u, du, l, *volume_force = nullptr;
|
||||
IntegrationRule &ir;
|
||||
Array<int> ess_tdof_list;
|
||||
mutable Vector x_lvec, y_lvec, state_lvec, du_tvec, l_tvec;
|
||||
|
||||
PLaplacianGradientOperator *gradient = nullptr;
|
||||
PLaplacianAdjointOperator *adjoint = nullptr;
|
||||
|
||||
bool enable_constant_du = false;
|
||||
};
|
||||
|
||||
void run_problem6()
|
||||
{
|
||||
const int dim = 2;
|
||||
|
||||
Mesh mesh = Mesh::MakeCartesian2D(8, 8, Element::QUADRILATERAL, false,
|
||||
2.0*M_PI,
|
||||
2.0*M_PI);
|
||||
mesh.EnsureNodes();
|
||||
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
|
||||
auto bdr_attributes = pmesh.bdr_attributes;
|
||||
|
||||
Array<int> ess_attr(bdr_attributes.Max());
|
||||
ess_attr = 1;
|
||||
|
||||
IntegrationRule ir = IntRules.Get(Element::QUADRILATERAL,
|
||||
2 * pmesh.GetNodes()->FESpace()->GetOrder(0) + 1);
|
||||
|
||||
H1_FECollection h1fec(2);
|
||||
ParFiniteElementSpace h1fes(&pmesh, &h1fec);
|
||||
|
||||
ParBilinearForm M(&h1fes);
|
||||
auto mass_integrator = new MassIntegrator;
|
||||
mass_integrator->SetIntegrationRule(IntRules.Get(
|
||||
Element::QUADRILATERAL,
|
||||
2 * pmesh.GetNodes()->FESpace()->GetOrder(0) + 1));
|
||||
M.AddDomainIntegrator(mass_integrator);
|
||||
M.Assemble();
|
||||
M.EliminateEssentialBC(ess_attr);
|
||||
M.Finalize();
|
||||
auto Mmat = M.ParallelAssemble();
|
||||
|
||||
std::ofstream myfile("mass.txt");
|
||||
Mmat->PrintMatlab(myfile);
|
||||
myfile.close();
|
||||
|
||||
ParGridFunction u(&h1fes), g(&h1fes);
|
||||
|
||||
PLaplacianOperator plap(h1fes, u);
|
||||
|
||||
auto coef_g = FunctionCoefficient([](const Vector &x)
|
||||
{
|
||||
return sin(x(0)) * sin(x(1));
|
||||
});
|
||||
g.ProjectCoefficient(coef_g);
|
||||
plap.SetVolumeForcing(g);
|
||||
|
||||
GMRESSolver gmres(MPI_COMM_WORLD);
|
||||
gmres.iterative_mode = false;
|
||||
gmres.SetRelTol(1e-8);
|
||||
gmres.SetMaxIter(10000);
|
||||
gmres.SetPrintLevel(0);
|
||||
|
||||
NewtonSolver newton(MPI_COMM_WORLD);
|
||||
newton.SetPreconditioner(gmres);
|
||||
newton.SetOperator(plap);
|
||||
newton.SetRelTol(1e-8);
|
||||
newton.SetAbsTol(1e-12);
|
||||
newton.SetMaxIter(100);
|
||||
newton.SetPrintLevel(0);
|
||||
|
||||
Vector zero;
|
||||
u.Randomize(1234);
|
||||
|
||||
ConstantCoefficient zero_coeff(0.0);
|
||||
u.ProjectBdrCoefficient(zero_coeff, bdr_attributes);
|
||||
|
||||
Vector *u_tdof = u.GetTrueDofs();
|
||||
newton.Mult(zero, *u_tdof);
|
||||
|
||||
u.SetFromTrueDofs(*u_tdof);
|
||||
|
||||
std::cout << "\nComputing adjoint state\n";
|
||||
auto adjoint_state_tdof = plap.ComputeAdjointState(u);
|
||||
|
||||
ParGridFunction adjoint_state(&h1fes);
|
||||
adjoint_state.SetFromTrueDofs(adjoint_state_tdof);
|
||||
|
||||
Vector dfdpTv = plap.ComputeDfDpTv(adjoint_state);
|
||||
|
||||
Vector dqoidp(dfdpTv);
|
||||
dqoidp.Neg();
|
||||
// adjoint_state.SetFromTrueDofs(dqoidp);
|
||||
// dqoidp.Print();
|
||||
|
||||
// FD test
|
||||
{
|
||||
std::cout << "FD TEST DQoIDu\n";
|
||||
|
||||
auto eval_f = [&](double h)
|
||||
{
|
||||
Vector dqoidu(g.Size());
|
||||
for (int i = 0; i < u.Size(); i++)
|
||||
{
|
||||
// Assign perturbation to input
|
||||
u(i) += h;
|
||||
dqoidu(i) = plap.ComputeQoI(u);
|
||||
|
||||
// Revert perturbation
|
||||
u(i) -= h;
|
||||
}
|
||||
|
||||
return dqoidu;
|
||||
};
|
||||
|
||||
double h = 1e-8;
|
||||
Vector fx = eval_f(0.0);
|
||||
Vector fxph = eval_f(h);
|
||||
fxph -= fx;
|
||||
fxph /= h;
|
||||
|
||||
auto dqoidu = plap.ComputeDQoIDU(u);
|
||||
|
||||
fxph -= dqoidu;
|
||||
std::cout << "|DQoIDU - FD_DQoIDU|_l2 = " << fxph.Norml2() << "\n";
|
||||
}
|
||||
|
||||
// FD test
|
||||
{
|
||||
std::cout << "FD TEST DfDp*v\n";
|
||||
|
||||
double h = 1e-8;
|
||||
Vector fx(dfdpTv), fxph(dfdpTv);
|
||||
|
||||
plap.Mult(*u_tdof, fx);
|
||||
|
||||
adjoint_state *= h;
|
||||
g += adjoint_state;
|
||||
plap.Mult(*u_tdof, fxph);
|
||||
g -= adjoint_state;
|
||||
adjoint_state /= h;
|
||||
|
||||
fxph -= fx;
|
||||
fxph /= h;
|
||||
|
||||
fxph -= dfdpTv;
|
||||
std::cout << "|DfDp*v - FD_DfDp*v|_l2 = " << fxph.Norml2() << "\n";
|
||||
}
|
||||
|
||||
// FD test
|
||||
{
|
||||
std::cout << "FD TEST DQoIDp (total derivative)\n";
|
||||
|
||||
auto eval_f = [&](double h)
|
||||
{
|
||||
Vector dqoidp(g.Size());
|
||||
for (int i = 0; i < u.Size(); i++)
|
||||
{
|
||||
// Assign perturbation to input
|
||||
g(i) += h;
|
||||
|
||||
// u.Randomize(1234);
|
||||
// u.ProjectBdrCoefficient(zero_coeff, ess_attr);
|
||||
// u.GetTrueDofs(*u_tdof);
|
||||
newton.Mult(zero, *u_tdof);
|
||||
u.SetFromTrueDofs(*u_tdof);
|
||||
dqoidp(i) = plap.ComputeQoI(u);
|
||||
|
||||
// Revert perturbation
|
||||
g(i) -= h;
|
||||
}
|
||||
|
||||
return dqoidp;
|
||||
};
|
||||
|
||||
double h = 1e-6;
|
||||
Vector fx = eval_f(0.0);
|
||||
Vector fxph = eval_f(h);
|
||||
fxph -= fx;
|
||||
fxph /= h;
|
||||
|
||||
fxph.SetSubVector(plap.ess_tdof_list, 0.0);
|
||||
|
||||
Vector dqoidp(g.Size());
|
||||
dqoidp = dfdpTv;
|
||||
dqoidp.Neg();
|
||||
|
||||
// fxph.Print(out, fxph.Size());
|
||||
// dqoidp.Print(out, dqoidp.Size());
|
||||
|
||||
fxph -= dqoidp;
|
||||
std::cout << "|DQoIDp - FD_DQoIDp|_l2 = " << fxph.Norml2() << "\n";
|
||||
}
|
||||
|
||||
// auto coef_f = FunctionCoefficient([](const Vector &x)
|
||||
// {
|
||||
// return 2.0;
|
||||
// });
|
||||
// u.ProjectCoefficient(coef_f);
|
||||
|
||||
// auto qoi = plap.ComputeQoI(u);
|
||||
// std::cout << "QoI = " << qoi << std::endl;
|
||||
|
||||
// auto dqoidu = plap.ComputeDQoIDU(u);
|
||||
// std::cout << "DQoIDU = " << std::endl;
|
||||
// // dqoidu.Print(std::cout, dqoidu.Size());
|
||||
|
||||
// ParLinearForm u_lf(&h1fes);
|
||||
// u_lf.AddDomainIntegrator(new DomainLFIntegrator(coef_f));
|
||||
// u_lf.Assemble();
|
||||
// Vector* u_lf_tdofs = u_lf.ParallelAssemble();
|
||||
// // u_lf_tdofs->Print(std::cout, u_lf_tdofs->Size());
|
||||
|
||||
// *u_lf_tdofs -= dqoidu;
|
||||
// std::cout << "||DQoIDU - EXACT||_L2 = " << u_lf_tdofs->Norml2() << std::endl;
|
||||
|
||||
char vishost[] = "128.15.198.77";
|
||||
int visport = 19916;
|
||||
{
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << Mpi::WorldSize() << " " << Mpi::WorldRank() << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << pmesh << u << std::flush;
|
||||
}
|
||||
{
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << Mpi::WorldSize() << " " << Mpi::WorldRank() << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << pmesh << adjoint_state << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
void run_problem6();
|
||||
void run_problem7();
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Mpi::Init();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
int problem_type = 0;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&problem_type, "-p", "--problem",
|
||||
"Problem to run");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(mfem::out);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(mfem::out);
|
||||
}
|
||||
|
||||
if (problem_type == 6)
|
||||
{
|
||||
run_problem6();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,350 +0,0 @@
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "dfem.hpp"
|
||||
|
||||
using namespace mfem;
|
||||
using mfem::internal::dual;
|
||||
using mfem::internal::tensor;
|
||||
|
||||
using namespace std;
|
||||
|
||||
int test_integrate_boundary()
|
||||
{
|
||||
int polynomial_order = 1;
|
||||
|
||||
Mesh mesh = Mesh::MakeCartesian2D(10, 2, Element::QUADRILATERAL, false, 0.0,
|
||||
2.0 * M_PI);
|
||||
mesh.EnsureNodes();
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
|
||||
H1_FECollection h1_fec(polynomial_order);
|
||||
ParFiniteElementSpace h1_fes(&pmesh, &h1_fec);
|
||||
|
||||
auto ir_face = const_cast<IntegrationRule *>(
|
||||
&IntRules.Get(mesh.GetBdrElementGeometry(0),
|
||||
3 * mesh.GetNodes()->FESpace()->GetElementOrder(0) + 1));
|
||||
|
||||
auto h1_prolongation = h1_fes.GetProlongationMatrix();
|
||||
|
||||
ParGridFunction boundary_load(&h1_fes);
|
||||
boundary_load = 0.0;
|
||||
|
||||
VectorFunctionCoefficient boundary_load_coeff(2, [](const Vector &x, Vector &u)
|
||||
{
|
||||
u(0) = 0.0;
|
||||
u(1) = 1.0;
|
||||
});
|
||||
|
||||
{
|
||||
Array<int> boundary_load_attr(pmesh.bdr_attributes.Max());
|
||||
boundary_load_attr = 0;
|
||||
boundary_load_attr[2] = 1;
|
||||
boundary_load.ProjectBdrCoefficient(boundary_load_coeff, boundary_load_attr);
|
||||
}
|
||||
|
||||
Vector boundary_load_qp;
|
||||
interpolate_boundary(boundary_load, *ir_face, boundary_load_qp);
|
||||
|
||||
auto foo = Reshape(boundary_load_qp.Read(), h1_fes.GetVDim(),
|
||||
ir_face->GetNPoints(), pmesh.GetNBE());
|
||||
|
||||
Vector vec(h1_fes.GetVDim());
|
||||
for (int e = 0; e < pmesh.GetNBE(); e++)
|
||||
{
|
||||
auto Tr = pmesh.GetBdrElementTransformation(e);
|
||||
|
||||
for (int qp = 0; qp < ir_face->GetNPoints(); qp++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir_face->IntPoint(qp);
|
||||
|
||||
Tr->SetIntPoint(&ip);
|
||||
|
||||
boundary_load_coeff.Eval(vec, *Tr, ip);
|
||||
|
||||
out << "(" << ip.x << "," << "y)" << " = " << vec(0) << " " << vec(1) << "\n";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void compute_element_jacobian_inverse(Mesh &mesh, IntegrationRule *ir,
|
||||
Vector &element_jacobian_inverse)
|
||||
{
|
||||
const int dim = mesh.Dimension();
|
||||
const int num_el = mesh.GetNE();
|
||||
const int num_qp = ir->GetNPoints();
|
||||
|
||||
element_jacobian_inverse.SetSize(num_qp * dim * dim * num_el);
|
||||
|
||||
// Cache inverse Jacobian on each quadrature point
|
||||
const GeometricFactors *geom = mesh.GetGeometricFactors(
|
||||
*ir, GeometricFactors::JACOBIANS);
|
||||
auto J = Reshape(geom->J.Read(), num_qp, dim, dim, num_el);
|
||||
auto Jinv = Reshape(element_jacobian_inverse.Write(), num_qp, dim, dim, num_el);
|
||||
DenseMatrix Jqp(dim, dim), JqpInv(dim, dim);
|
||||
for (int e = 0; e < num_el; e++)
|
||||
{
|
||||
for (int qp = 0; qp < num_qp; qp++)
|
||||
{
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
for (int j = 0; j < dim; j++)
|
||||
{
|
||||
Jqp(i, j) = J(qp, i, j, e);
|
||||
}
|
||||
}
|
||||
|
||||
CalcInverse(Jqp, JqpInv);
|
||||
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
for (int j = 0; j < dim; j++)
|
||||
{
|
||||
Jinv(qp, i, j, e) = JqpInv(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
std::string check_result(double norm, double rtol = 1e-12)
|
||||
{
|
||||
if (norm < rtol)
|
||||
{
|
||||
return "✅";
|
||||
}
|
||||
return "❌";
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
Mpi::Init();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
int dimension = 2;
|
||||
int polynomial_order = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&polynomial_order, "-o", "--order",
|
||||
"Finite element order (polynomial degree)");
|
||||
args.ParseCheck();
|
||||
|
||||
std::cout << "Polynomial order = " << polynomial_order << "\n";
|
||||
|
||||
FunctionCoefficient linear_scalar_coeff([&](const Vector &c)
|
||||
{
|
||||
double x = c(0), y = c(1);
|
||||
return 2.0 * x + x * y;
|
||||
});
|
||||
|
||||
VectorFunctionCoefficient dlinear_scalardx_coeff(dimension, [&](const Vector &c,
|
||||
Vector &u)
|
||||
{
|
||||
double x = c(0), y = c(1);
|
||||
u(0) = 2.0 + c(1);
|
||||
u(1) = c(0);
|
||||
});
|
||||
|
||||
FunctionCoefficient quadratic_coeff([&](const Vector &c)
|
||||
{
|
||||
double x = c(0), y = c(1);
|
||||
return 2.0*x*x + x*y*y;
|
||||
});
|
||||
|
||||
VectorFunctionCoefficient dquadraticdx_coeff(dimension, [&](const Vector &c,
|
||||
Vector &u)
|
||||
{
|
||||
double x = c(0), y = c(1);
|
||||
u(0) = 4.0*x+y*y,
|
||||
u(1) = 2.0*x*y;
|
||||
});
|
||||
|
||||
{
|
||||
Mesh mesh = Mesh::MakeCartesian2D(1, 1, Element::QUADRILATERAL, false, 1.0,
|
||||
1.0);
|
||||
mesh.EnsureNodes();
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
|
||||
H1_FECollection h1_fec(polynomial_order);
|
||||
ParFiniteElementSpace h1_fes(&pmesh, &h1_fec);
|
||||
ParFiniteElementSpace h1_vfes(&pmesh, &h1_fec, dimension, Ordering::byVDIM);
|
||||
|
||||
cout << "#dofs: " << h1_fes.GetVSize() << "\n\n";
|
||||
|
||||
auto ir = const_cast<IntegrationRule *>(
|
||||
&IntRules.Get(mesh.GetElementGeometry(0),
|
||||
2 * mesh.GetNodes()->FESpace()->GetElementOrder(0)));
|
||||
|
||||
Vector element_jacobian_inverse;
|
||||
compute_element_jacobian_inverse(mesh, ir, element_jacobian_inverse);
|
||||
|
||||
auto h1v_prolongation = h1_vfes.GetProlongationMatrix();
|
||||
|
||||
ParGridFunction u(&h1_fes), du(&h1_vfes), uv(&h1_vfes);
|
||||
u = 0.0, du = 0.0, uv = 0.0;
|
||||
|
||||
{
|
||||
cout << "scalar interpolation\n";
|
||||
Vector u_qp;
|
||||
u.ProjectCoefficient(linear_scalar_coeff);
|
||||
interpolate(u, *ir, u_qp);
|
||||
integrate_basis(u_qp, h1_fes, *ir, u);
|
||||
double integral = 0.0;
|
||||
for (int dof = 0; dof < h1_fes.GetVSize(); dof++)
|
||||
{
|
||||
integral += u(dof);
|
||||
}
|
||||
cout << "|I[u]dx - I[u_ex]dx| = " << abs(integral - 5.0/4.0) << "\n";
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
{
|
||||
cout << "weak gradient of scalar\n";
|
||||
Vector dudx_qp;
|
||||
u.ProjectCoefficient(linear_scalar_coeff);
|
||||
gradient_wrt_x(u, *ir, dudx_qp);
|
||||
integrate_basis(dudx_qp, h1_vfes, *ir, du);
|
||||
|
||||
Vector integral(2);
|
||||
for (int d = 0; d < du.FESpace()->GetVDim(); d++)
|
||||
{
|
||||
integral(d) = 0.0;
|
||||
for (int i = 0; i < du.FESpace()->GetNDofs(); i++)
|
||||
{
|
||||
int idx = Ordering::Map<Ordering::byVDIM>(
|
||||
du.FESpace()->GetNDofs(),
|
||||
du.FESpace()->GetVDim(),
|
||||
i,
|
||||
d);
|
||||
integral(d) += du(idx);
|
||||
}
|
||||
}
|
||||
cout << "|I[du]dx - I[du_ex]dx| = " << abs(integral(0) - 5.0/2.0) << "\n"
|
||||
<< "|I[du]dy - I[du_ex]dy| = " << abs(integral(1) - 1.0/2.0) << "\n";
|
||||
|
||||
ParLinearForm l(&h1_vfes);
|
||||
auto integrator = new VectorDomainLFIntegrator(dlinear_scalardx_coeff);
|
||||
integrator->SetIntRule(ir);
|
||||
l.AddDomainIntegrator(integrator);
|
||||
l.Assemble();
|
||||
du -= *l.ParallelAssemble();
|
||||
cout << "|du - du_form|_l2 = " << du.Norml2()
|
||||
<< check_result(du.Norml2()) << "\n";
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
{
|
||||
cout << "scalar diffusion, linear u\n";
|
||||
Vector dudx_qp, ru(h1_fes.GetVSize());
|
||||
u.ProjectCoefficient(linear_scalar_coeff);
|
||||
gradient_wrt_x(u, *ir, dudx_qp);
|
||||
integrate_basis_gradient(dudx_qp, h1_fes, *ir, ru,
|
||||
element_jacobian_inverse);
|
||||
|
||||
ParBilinearForm b(&h1_fes);
|
||||
auto integrator = new DiffusionIntegrator;
|
||||
integrator->SetIntRule(ir);
|
||||
b.AddDomainIntegrator(integrator);
|
||||
b.Assemble();
|
||||
b.Finalize();
|
||||
|
||||
ParGridFunction y(&h1_fes);
|
||||
b.Mult(u, y);
|
||||
|
||||
y -= ru;
|
||||
cout << "|r(u) - r(u)_form|_l2 = " << y.Norml2()
|
||||
<< check_result(y.Norml2()) << "\n";
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
{
|
||||
cout << "scalar diffusion, quadratic u\n";
|
||||
Vector dudx_qp, ru(h1_fes.GetVSize());
|
||||
u.ProjectCoefficient(quadratic_coeff);
|
||||
gradient_wrt_x(u, *ir, dudx_qp);
|
||||
integrate_basis_gradient(dudx_qp, h1_fes, *ir, ru,
|
||||
element_jacobian_inverse);
|
||||
|
||||
ParBilinearForm b(&h1_fes);
|
||||
auto integrator = new DiffusionIntegrator;
|
||||
integrator->SetIntRule(ir);
|
||||
b.AddDomainIntegrator(integrator);
|
||||
b.Assemble();
|
||||
b.Finalize();
|
||||
|
||||
ParGridFunction y(&h1_fes);
|
||||
b.Mult(u, y);
|
||||
|
||||
y -= ru;
|
||||
cout << "|r(u) - r(u)_form|_l2 = " << y.Norml2()
|
||||
<< check_result(y.Norml2()) << "\n";
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
{
|
||||
cout << "vector diffusion, linear u\n";
|
||||
Vector duvdx_qp, ru(h1_vfes.GetVSize());
|
||||
uv.ProjectCoefficient(dlinear_scalardx_coeff);
|
||||
gradient_wrt_x(uv, *ir, duvdx_qp);
|
||||
integrate_basis_gradient(duvdx_qp, h1_vfes, *ir, ru,
|
||||
element_jacobian_inverse);
|
||||
|
||||
ParBilinearForm b(&h1_vfes);
|
||||
auto integrator = new VectorDiffusionIntegrator;
|
||||
integrator->SetIntRule(ir);
|
||||
b.AddDomainIntegrator(integrator);
|
||||
b.Assemble();
|
||||
b.Finalize();
|
||||
|
||||
ParGridFunction y(&h1_vfes);
|
||||
b.Mult(uv, y);
|
||||
|
||||
y -= ru;
|
||||
cout << "|r(u) - r(u)_form|_l2 = " << y.Norml2()
|
||||
<< check_result(y.Norml2()) << "\n";
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
{
|
||||
cout << "vector diffusion, quadratic u\n";
|
||||
Vector duvdx_qp, ru(h1_vfes.GetVSize());
|
||||
uv.ProjectCoefficient(dquadraticdx_coeff);
|
||||
gradient_wrt_x(uv, *ir, duvdx_qp);
|
||||
integrate_basis_gradient(duvdx_qp, h1_vfes, *ir, ru,
|
||||
element_jacobian_inverse);
|
||||
|
||||
ParBilinearForm b(&h1_vfes);
|
||||
auto integrator = new VectorDiffusionIntegrator;
|
||||
integrator->SetIntRule(ir);
|
||||
b.AddDomainIntegrator(integrator);
|
||||
b.Assemble();
|
||||
b.Finalize();
|
||||
|
||||
ParGridFunction y(&h1_vfes);
|
||||
b.Mult(uv, y);
|
||||
|
||||
y -= ru;
|
||||
cout << "|r(u) - r(u)_form|_l2 = " << y.Norml2()
|
||||
<< check_result(y.Norml2()) << "\n";
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,900 +0,0 @@
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "dfem.hpp"
|
||||
|
||||
#include <caliper/cali.h>
|
||||
#include <caliper/cali-manager.h>
|
||||
|
||||
using namespace mfem;
|
||||
using mfem::internal::tensor;
|
||||
using mfem::internal::dual;
|
||||
using mfem::internal::make_tensor;
|
||||
|
||||
template <int dim>
|
||||
class AffineSolution
|
||||
{
|
||||
public:
|
||||
AffineSolution() : A(dim), b(dim)
|
||||
{
|
||||
// clang-format off
|
||||
A(0, 0) = 0.110791568544027; A(0, 1) = 0.230421268325901;
|
||||
A(1, 0) = 0.198344644470483; A(1, 1) = 0.060514559793513;
|
||||
if constexpr (dim == 3)
|
||||
{
|
||||
A(0, 2) = 0.15167673653354;
|
||||
A(1, 2) = 0.084137393813728;
|
||||
A(2, 0) = 0.011544253485023; A(2, 1) = 0.060942846497753;
|
||||
A(2, 2) = 0.186383473579596;
|
||||
}
|
||||
A *= 1e-2;
|
||||
|
||||
b(0) = 0.765645367640828;
|
||||
b(1) = 0.992487355850465;
|
||||
if constexpr (dim == 3)
|
||||
{
|
||||
b(2) = 0.162199373722092;
|
||||
}
|
||||
b *= 1e-2;
|
||||
//clang-format on
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief MFEM-style coefficient function corresponding to this solution
|
||||
*
|
||||
* @param X Coordinates of point in reference configuration at which solution is sought
|
||||
* @param u Exact solution evaluated at \p X
|
||||
*/
|
||||
void operator()(const mfem::Vector& X, mfem::Vector& u) const
|
||||
{
|
||||
A.Mult(X, u);
|
||||
u += b;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @brief Apply forcing that should produce this exact displacement
|
||||
// *
|
||||
// * Given the physics module, apply boundary conditions and a source
|
||||
// * term that are consistent with the exact solution. This is
|
||||
// * independent of the domain. The solution is imposed as an essential
|
||||
// * boundary condition on the parts of the boundary identified by \p
|
||||
// * essential_boundaries. On the complement of
|
||||
// * \p essential_boundaries, the traction corresponding to the exact
|
||||
// * solution is applied.
|
||||
// *
|
||||
// * @tparam p Polynomial degree of the finite element approximation
|
||||
// * @tparam Material Type of the material model used in the problem
|
||||
// *
|
||||
// * @param material Material model used in the problem
|
||||
// * @param sf The SolidMechanics module for the problem
|
||||
// * @param essential_boundaries Boundary attributes on which essential boundary conditions are desired
|
||||
// */
|
||||
// template <int p, typename Material>
|
||||
// void applyLoads(const Material& material, SolidMechanics<p, dim>& sf,
|
||||
// std::set<int> essential_boundaries) const
|
||||
// {
|
||||
// // essential BCs
|
||||
// auto ebc_func = [*this](const auto& X, auto& u) { this->operator()(X, u); };
|
||||
// sf.setDisplacementBCs(essential_boundaries, ebc_func);
|
||||
|
||||
// // natural BCs
|
||||
// typename Material::State state;
|
||||
// auto H = make_tensor<dim, dim>([&](int i, int j) { return A(i,j); });
|
||||
// tensor<double, dim, dim> sigma = material(state, H);
|
||||
// auto P = solid_mechanics::CauchyToPiola(sigma, H);
|
||||
// auto traction = [P](auto, auto n0, auto) { return dot(P, n0); };
|
||||
// sf.setPiolaTraction(traction);
|
||||
// }
|
||||
|
||||
private:
|
||||
/// Linear part of solution. Equivalently, the displacement gradient
|
||||
mfem::DenseMatrix A;
|
||||
/// Constant part of solution. Rigid mody displacement.
|
||||
mfem::Vector b;
|
||||
};
|
||||
|
||||
|
||||
class LambdaOperator : public Operator
|
||||
{
|
||||
public:
|
||||
LambdaOperator(int size,
|
||||
std::function<void(const Vector&, Vector&)> mult_f) :
|
||||
Operator(size),
|
||||
mult_f(mult_f)
|
||||
{}
|
||||
|
||||
void Mult(const Vector& X, Vector& Y) const
|
||||
{
|
||||
mult_f(X, Y);
|
||||
}
|
||||
|
||||
std::function<void(const Vector&, Vector&)> mult_f;
|
||||
};
|
||||
|
||||
class ADOperator : public Operator
|
||||
{
|
||||
public:
|
||||
ADOperator(int size = 0) : Operator(size) {}
|
||||
virtual void GradientMult(const Vector &dX, Vector &Y) const = 0;
|
||||
virtual void AdjointMult(const Vector &L, Vector &Y) const = 0;
|
||||
};
|
||||
|
||||
class ElasticityGradientOperator : public Operator
|
||||
{
|
||||
public:
|
||||
ElasticityGradientOperator(ADOperator &op) :
|
||||
Operator(op.Height()), op(op) {}
|
||||
|
||||
void Mult(const Vector &x, Vector &y) const override
|
||||
{
|
||||
op.GradientMult(x, y);
|
||||
}
|
||||
|
||||
ADOperator &op;
|
||||
};
|
||||
|
||||
void finite_stress_qf(const tensor<double, 2, 2> &dudx, tensor<double, 2, 2> &P)
|
||||
{
|
||||
double lambda, mu;
|
||||
{
|
||||
lambda = 1.25;
|
||||
mu = 1.0;
|
||||
}
|
||||
static constexpr auto I = mfem::internal::IsotropicIdentity<2>();
|
||||
auto F = dudx + I;
|
||||
auto E = 0.5 * (transpose(F) * F - I);
|
||||
// auto eps = sym(dudx);
|
||||
// auto dudx_squared = transpose(dudx) * dudx;
|
||||
// auto E = eps + 0.5 * dudx_squared;
|
||||
auto S = lambda * tr(E) * I + 2.0 * mu * E;
|
||||
P = F * S;
|
||||
};
|
||||
|
||||
// linear elastic
|
||||
void small_stress_qf(const tensor<double, 2, 2> &dudx,
|
||||
tensor<double, 2, 2> &P)
|
||||
{
|
||||
double lambda, mu;
|
||||
{
|
||||
lambda = 1.25;
|
||||
mu = 1.0;
|
||||
}
|
||||
static constexpr auto I = mfem::internal::IsotropicIdentity<2>();
|
||||
auto eps = sym(dudx);
|
||||
auto S = lambda * tr(eps) * I + 2.0 * mu * eps;
|
||||
P = S;
|
||||
};
|
||||
|
||||
template <auto quadrature_function>
|
||||
class ElasticityOperator : public ADOperator
|
||||
{
|
||||
public:
|
||||
ElasticityOperator(ParMesh &mesh, ParFiniteElementSpace &h1_fes, bool matfree,
|
||||
bool dump_matrices) :
|
||||
ADOperator(),
|
||||
mesh(mesh),
|
||||
dim(mesh.Dimension()),
|
||||
vdim(mesh.Dimension()),
|
||||
num_el(mesh.GetNE()),
|
||||
h1_fes(h1_fes),
|
||||
matfree(matfree),
|
||||
dump_matrices(dump_matrices)
|
||||
{
|
||||
this->height = h1_fes.GetTrueVSize();
|
||||
this->width = this->height;
|
||||
|
||||
ir = const_cast<IntegrationRule *>(
|
||||
&IntRules.Get(mesh.GetElementGeometry(0),
|
||||
2 * h1_fes.GetElementOrder(0)));
|
||||
|
||||
ir_face = const_cast<IntegrationRule *>(
|
||||
&IntRules.Get(mesh.GetBdrElementGeometry(0),
|
||||
2 * h1_fes.GetElementOrder(0)));
|
||||
|
||||
num_qp = ir->GetNPoints();
|
||||
|
||||
int global_tdof_size = h1_fes.GlobalTrueVSize();
|
||||
if (Mpi::Root())
|
||||
{
|
||||
out << "dim = " << mesh.Dimension() << "\n"
|
||||
<< "vdim = " << h1_fes.GetVDim() << "\n"
|
||||
<< "#dofs: " << global_tdof_size << "\n"
|
||||
<< "#qp in IntRule: " << num_qp << std::endl;
|
||||
}
|
||||
|
||||
h1_prolongation = h1_fes.GetProlongationMatrix();
|
||||
|
||||
u.SetSpace(&h1_fes);
|
||||
current_state.SetSpace(&h1_fes);
|
||||
current_iterate.SetSpace(&h1_fes);
|
||||
current_iterate_tvec.SetSize(h1_prolongation->Width());
|
||||
|
||||
body_force.SetSpace(&h1_fes);
|
||||
body_force = 0.0;
|
||||
|
||||
boundary_load.SetSpace(&h1_fes);
|
||||
boundary_load = 0.0;
|
||||
|
||||
// Layout has to be [vdim, dim, num_qp, num_el]
|
||||
P_dudx_qp.SetSize(dim * dim * num_qp * num_el);
|
||||
out_qp.SetSize(dim * dim * num_qp * num_el);
|
||||
|
||||
element_jacobian_inverse.SetSize(num_qp * dim * dim * num_el);
|
||||
|
||||
matfree_gradient = new ElasticityGradientOperator(*this);
|
||||
|
||||
// Cache inverse Jacobian on each quadrature point
|
||||
{
|
||||
const GeometricFactors *geom = mesh.GetGeometricFactors(
|
||||
*ir, GeometricFactors::JACOBIANS);
|
||||
auto J = Reshape(geom->J.Read(), num_qp, dim, dim, num_el);
|
||||
auto Jinv = Reshape(element_jacobian_inverse.Write(), num_qp, dim, dim, num_el);
|
||||
DenseMatrix Jqp(dim, dim), JqpInv(dim, dim);
|
||||
for (int e = 0; e < num_el; e++)
|
||||
{
|
||||
for (int qp = 0; qp < num_qp; qp++)
|
||||
{
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
for (int j = 0; j < dim; j++)
|
||||
{
|
||||
Jqp(i, j) = J(qp, i, j, e);
|
||||
}
|
||||
}
|
||||
|
||||
CalcInverse(Jqp, JqpInv);
|
||||
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
for (int j = 0; j < dim; j++)
|
||||
{
|
||||
Jinv(qp, i, j, e) = JqpInv(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mult(const Vector &X, Vector &Y) const override
|
||||
{
|
||||
CALI_MARK_BEGIN("ElasticityOperator::Mult");
|
||||
|
||||
h1_prolongation->Mult(X, u);
|
||||
|
||||
gradient_wrt_x(u, *ir, dudx_qp);
|
||||
|
||||
forall(quadrature_function, num_qp * num_el, dudx_qp, P_dudx_qp);
|
||||
|
||||
integrate_basis_gradient(P_dudx_qp,
|
||||
h1_fes,
|
||||
*ir, P_dudx_qp_dphi,
|
||||
element_jacobian_inverse);
|
||||
|
||||
if (enable_body_force)
|
||||
{
|
||||
interpolate(body_force, *ir, body_force_qp);
|
||||
integrate_basis(body_force_qp, h1_fes, *ir, body_force_phi);
|
||||
P_dudx_qp_dphi += body_force_phi;
|
||||
}
|
||||
if (enable_boundary_load)
|
||||
{
|
||||
interpolate_boundary(boundary_load, *ir_face, boundary_load_qp);
|
||||
integrate_basis_boundary(boundary_load_qp, h1_fes, *ir_face,
|
||||
boundary_load_phi);
|
||||
P_dudx_qp_dphi -= boundary_load_phi;
|
||||
}
|
||||
|
||||
h1_prolongation->MultTranspose(P_dudx_qp_dphi, Y);
|
||||
Y.SetSubVector(ess_tdof_list, 0.0);
|
||||
|
||||
CALI_MARK_END("ElasticityOperator::Mult");
|
||||
}
|
||||
|
||||
Operator &GetGradientNoBC(const Vector &x) const
|
||||
{
|
||||
assemble_with_bc = false;
|
||||
auto& op = GetGradient(x);
|
||||
assemble_with_bc = true;
|
||||
return op;
|
||||
}
|
||||
|
||||
Operator &GetGradient(const Vector &x) const override
|
||||
{
|
||||
// T -> L
|
||||
h1_fes.GetProlongationMatrix()->Mult(x, current_state);
|
||||
|
||||
// Cache dudx
|
||||
gradient_wrt_x(current_state, *ir, dudx_qp);
|
||||
|
||||
if (!matfree)
|
||||
{
|
||||
if (dump_matrices)
|
||||
{
|
||||
std::ofstream matfree_gradient_out("matfreeA.txt");
|
||||
matfree_gradient->PrintMatlab(matfree_gradient_out);
|
||||
matfree_gradient_out.close();
|
||||
}
|
||||
|
||||
Vector dPddudx_qp(dim * dim * dim * dim * num_qp * num_el);
|
||||
CALI_MARK_BEGIN("EnzymeAD Jacobian Assemble");
|
||||
forall([&](const tensor<double, 2, 2> &dudx,
|
||||
tensor<double, 2, 2, 2, 2> &dPddudx)
|
||||
{
|
||||
tensor<double, 2, 2> unused_output{};
|
||||
tensor<double, 2, 2> dir{};
|
||||
dPddudx = {};
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
for (int j = 0; j < dim; j++)
|
||||
{
|
||||
dir[i][j] = 1;
|
||||
__enzyme_autodiff<void>(+quadrature_function,
|
||||
enzyme_dup, &dudx, &(dPddudx[j][i]), // autodiff returns A^t
|
||||
enzyme_dupnoneed, &unused_output, &dir);
|
||||
dir[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}, num_qp * num_el, dudx_qp, dPddudx_qp);
|
||||
CALI_MARK_END("EnzymeAD Jacobian Assemble");
|
||||
|
||||
// Assemble processor local SparseMatrix
|
||||
SparseMatrix *mat = new SparseMatrix(h1_fes.GetVSize());
|
||||
{
|
||||
auto R = h1_fes.GetElementRestriction(ElementDofOrdering::NATIVE);
|
||||
const int dim = mesh.Dimension();
|
||||
const int num_el = mesh.GetNE();
|
||||
const int vdim = h1_fes.GetVDim();
|
||||
const int num_qp = ir->GetNPoints();
|
||||
const int num_vdofs = R->Height() / num_el;
|
||||
const int num_dofs = num_vdofs / vdim;
|
||||
|
||||
const GeometricFactors *geom = mesh.GetGeometricFactors(
|
||||
*ir, GeometricFactors::JACOBIANS | GeometricFactors::DETERMINANTS);
|
||||
auto detJ = Reshape(geom->detJ.Read(), num_qp, num_el);
|
||||
auto invJ = Reshape(element_jacobian_inverse.Read(), num_qp, dim, dim, num_el);
|
||||
|
||||
Vector A_l(num_dofs * dim * num_dofs * dim * num_el);
|
||||
A_l = 0.0;
|
||||
|
||||
auto A_e = Reshape(A_l.ReadWrite(), num_dofs, dim, num_dofs, dim, num_el);
|
||||
auto D = Reshape(dPddudx_qp.Read(), dim, dim, dim, dim, num_qp, num_el);
|
||||
|
||||
for (int e = 0; e < num_el; e++)
|
||||
{
|
||||
const DofToQuad &maps = h1_fes.GetFE(e)->GetDofToQuad(*ir, DofToQuad::FULL);
|
||||
const auto G = Reshape(maps.G.Read(), num_qp, dim, num_dofs);
|
||||
|
||||
for (int qp = 0; qp < num_qp; qp++)
|
||||
{
|
||||
const double JxW = detJ(qp, e) * ir->GetWeights()[qp];
|
||||
|
||||
// Pullback Gradient into physical space
|
||||
Vector dphidx_data(num_dofs * dim);
|
||||
dphidx_data = 0.0;
|
||||
auto dphidx = Reshape(dphidx_data.ReadWrite(), num_dofs, dim);
|
||||
for (int j = 0; j < num_dofs; j++)
|
||||
{
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
double s = 0.0;
|
||||
for (int k = 0; k < dim; k++)
|
||||
{
|
||||
s += G(qp, k, j) * invJ(qp, k, i, e);
|
||||
}
|
||||
dphidx(j, i) += s;
|
||||
}
|
||||
}
|
||||
|
||||
for (int q = 0; q < dim; q++)
|
||||
{
|
||||
for (int b = 0; b < num_dofs; b++)
|
||||
{
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
for (int a = 0; a < num_dofs; a++)
|
||||
{
|
||||
double s = 0.0;
|
||||
for (int l = 0; l < dim; l++)
|
||||
{
|
||||
for (int k = 0; k < dim; k++)
|
||||
{
|
||||
// dN^A/dX_k (D_ijkl dN^C/dX_l)
|
||||
s += dphidx(a,k) * D(i,k,q,l,qp,e) * dphidx(b,l);
|
||||
|
||||
// diagonal test
|
||||
// s += dphidx(a,k) * D(i,k,q,l,qp,e) * dphidx(a,l);
|
||||
}
|
||||
}
|
||||
A_e(a, i, b, q, e) += s * JxW;
|
||||
|
||||
// diagonal test
|
||||
// A_e(a, i, a, q, e) += s * JxW;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int e = 0; e < num_el; e++)
|
||||
{
|
||||
auto tmp = Reshape(A_l.ReadWrite(), num_dofs, dim, num_dofs, dim, num_el);
|
||||
DenseMatrix A_e(&tmp(0, 0, 0, 0, e), num_vdofs, num_vdofs);
|
||||
Array<int> vdofs;
|
||||
h1_fes.GetElementVDofs(e, vdofs);
|
||||
mat->AddSubMatrix(vdofs, vdofs, A_e, 1);
|
||||
}
|
||||
mat->Finalize();
|
||||
|
||||
auto tmp = new HypreParMatrix(h1_fes.GetComm(),
|
||||
h1_fes.GlobalVSize(),
|
||||
h1_fes.GetDofOffsets(),
|
||||
mat);
|
||||
delete Amat;
|
||||
Amat = RAP(tmp, h1_fes.Dof_TrueDof_Matrix());
|
||||
delete tmp;
|
||||
delete mat;
|
||||
|
||||
if (assemble_with_bc)
|
||||
{
|
||||
Amat->EliminateBC(ess_tdof_list, DiagonalPolicy::DIAG_ONE);
|
||||
}
|
||||
|
||||
if (dump_matrices)
|
||||
{
|
||||
std::ofstream assembled_jacobian_out("assembled_jacobian.txt");
|
||||
Amat->PrintMatlab(assembled_jacobian_out);
|
||||
assembled_jacobian_out.close();
|
||||
out << "exiting after writing jacobian matrices to disk...\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return *Amat;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return *matfree_gradient;
|
||||
}
|
||||
}
|
||||
|
||||
// X: current iterate
|
||||
// Y: dR/dU * X
|
||||
void GradientMult(const Vector &X, Vector &Y) const override
|
||||
{
|
||||
CALI_MARK_BEGIN("ElasticityOperator::GradientMult");
|
||||
|
||||
// apply essential bcs
|
||||
current_iterate_tvec = X;
|
||||
current_iterate_tvec.SetSubVector(ess_tdof_list, 0.0);
|
||||
current_iterate.SetFromTrueDofs(current_iterate_tvec);
|
||||
|
||||
gradient_wrt_x(current_iterate, *ir, ddudx_qp);
|
||||
|
||||
CALI_MARK_BEGIN("EnzymeAD MatVec");
|
||||
forall([](const tensor<double, 2, 2> &dudx,
|
||||
tensor<double, 2, 2> &ddudx,
|
||||
tensor<double, 2, 2> &out)
|
||||
{
|
||||
tensor<double, 2, 2> unused_output{};
|
||||
out = {};
|
||||
__enzyme_fwddiff<void>(+quadrature_function, &dudx, &ddudx,
|
||||
&unused_output, &out);
|
||||
}, num_qp * num_el, dudx_qp, ddudx_qp, out_qp);
|
||||
CALI_MARK_END("EnzymeAD MatVec");
|
||||
|
||||
CALI_MARK_BEGIN("integrate_basis_gradient");
|
||||
integrate_basis_gradient(out_qp, h1_fes, *ir, y, element_jacobian_inverse);
|
||||
CALI_MARK_END("integrate_basis_gradient");
|
||||
|
||||
// L-vector to T-vector
|
||||
h1_fes.GetProlongationMatrix()->MultTranspose(y, Y);
|
||||
|
||||
// Re-assign the essential degrees of freedom on the final output vector.
|
||||
for (int i = 0; i < ess_tdof_list.Size(); i++)
|
||||
{
|
||||
Y[ess_tdof_list[i]] = X[ess_tdof_list[i]];
|
||||
}
|
||||
|
||||
CALI_MARK_END("ElasticityOperator::GradientMult");
|
||||
}
|
||||
|
||||
// dL: current iterate of adjoint state
|
||||
// Y: (dF/dU)^t * dL
|
||||
void AdjointMult(const Vector &dL, Vector &Y) const override
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SetEssentialAttributes(const Array<int> attr)
|
||||
{
|
||||
h1_fes.GetEssentialTrueDofs(attr, ess_tdof_list);
|
||||
}
|
||||
|
||||
void SetPrescribedDisplacement(const Array<int> attr)
|
||||
{
|
||||
h1_fes.GetEssentialTrueDofs(attr, displaced_tdof_list);
|
||||
}
|
||||
|
||||
const Array<int> &GetPrescribedDisplacementTDofs()
|
||||
{
|
||||
return displaced_tdof_list;
|
||||
};
|
||||
|
||||
ParGridFunction* GetExternalLoad()
|
||||
{
|
||||
enable_boundary_load = true;
|
||||
return &boundary_load;
|
||||
}
|
||||
|
||||
ParGridFunction* GetBodyForce()
|
||||
{
|
||||
enable_body_force = true;
|
||||
return &body_force;
|
||||
}
|
||||
|
||||
ParMesh &mesh;
|
||||
const int dim;
|
||||
const int vdim;
|
||||
/// Number of elements in the mesh (rank local)
|
||||
int num_el;
|
||||
int num_qp = 0;
|
||||
/// H1 finite element space
|
||||
ParFiniteElementSpace &h1_fes;
|
||||
// Integration rule
|
||||
IntegrationRule *ir = nullptr, *ir_face = nullptr;
|
||||
const Operator *h1_element_restriction;
|
||||
const Operator *h1_prolongation;
|
||||
|
||||
mutable Vector element_jacobian_inverse;
|
||||
|
||||
Array<int> ess_tdof_list, displaced_tdof_list;
|
||||
|
||||
ParGridFunction body_force, boundary_load;
|
||||
mutable ParGridFunction u, current_state, current_iterate;
|
||||
mutable Vector current_iterate_tvec, dudx_qp, ddudx_qp,
|
||||
P_dudx_qp_dphi, body_force_qp, boundary_load_qp, body_force_phi,
|
||||
boundary_load_phi, y,
|
||||
P_dudx_qp, out_qp;
|
||||
|
||||
bool enable_boundary_load = false, enable_body_force = false;
|
||||
ElasticityGradientOperator *matfree_gradient = nullptr;
|
||||
|
||||
bool matfree;
|
||||
bool dump_matrices;
|
||||
mutable HypreParMatrix *Amat = nullptr;
|
||||
mutable bool assemble_with_bc = true;
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
Mpi::Init();
|
||||
// int num_procs = Mpi::WorldSize();
|
||||
// int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
bool visualization = false;
|
||||
int polynomial_degree = 1;
|
||||
int refinements = 0;
|
||||
int problem_type = 0;
|
||||
bool matfree = false;
|
||||
bool pmg = false;
|
||||
bool dump_matrices = false;
|
||||
const char *caliper_options = "";
|
||||
const char *mesh_file = "../data/beam-quad.mesh";
|
||||
|
||||
std::shared_ptr<VectorFunctionCoefficient> u_ex_coeff;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&polynomial_degree, "-o", "--order",
|
||||
"Finite element order (polynomial degree)");
|
||||
args.AddOption(&refinements, "-r", "--ref",
|
||||
"");
|
||||
args.AddOption(&problem_type, "-p", "--problem",
|
||||
"");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&matfree, "-matfree", "--matfree", "-no-matfree",
|
||||
"--no-matfree",
|
||||
"matrix free");
|
||||
args.AddOption(&pmg, "-pmg", "--pmg", "-no-pmg",
|
||||
"--no-pmg",
|
||||
"p-Multigrid");
|
||||
args.AddOption(&dump_matrices, "-dump_matrices", "--dump_matrices",
|
||||
"-no-dump_matrices",
|
||||
"--no-dump_matrices",
|
||||
"dump matrices");
|
||||
args.AddOption(&caliper_options, "-profile", "--profile", "caliper options");
|
||||
args.ParseCheck();
|
||||
|
||||
if (problem_type == 3)
|
||||
{
|
||||
// MFEM_ASSERT(strcmp("patch2D_quads.mesh", mesh_file) == 0,
|
||||
// "have to use patch2D_quads.mesh");
|
||||
}
|
||||
|
||||
cali::ConfigManager caliper_mgr;
|
||||
caliper_mgr.add(caliper_options);
|
||||
|
||||
caliper_mgr.start();
|
||||
CALI_MARK_FUNCTION_BEGIN;
|
||||
|
||||
Mesh mesh(mesh_file, 1, 1);
|
||||
mesh.EnsureNodes();
|
||||
int dim = mesh.Dimension();
|
||||
|
||||
for (int i = 0; i < refinements; i++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
int num_el_global = pmesh.GetGlobalNE();
|
||||
if (Mpi::Root())
|
||||
{
|
||||
out << "#elements: " << num_el_global << "\n";
|
||||
}
|
||||
|
||||
auto *fec = new H1_FECollection(1, dim);
|
||||
auto *coarse_fespace = new ParFiniteElementSpace(&pmesh, fec, dim);
|
||||
|
||||
Array<FiniteElementCollection*> collections;
|
||||
collections.Append(fec);
|
||||
auto* fespaces = new ParFiniteElementSpaceHierarchy(&pmesh, coarse_fespace,
|
||||
true, true);
|
||||
for (int level = 0; level < polynomial_degree; ++level)
|
||||
{
|
||||
collections.Append(new H1_FECollection((int)std::pow(2, level+1), dim));
|
||||
fespaces->AddOrderRefinedLevel(collections.Last(), dim);
|
||||
}
|
||||
|
||||
HYPRE_BigInt size = fespaces->GetFinestFESpace().GlobalTrueVSize();
|
||||
if (Mpi::Root())
|
||||
{
|
||||
cout << "#dofs: " << size << endl;
|
||||
}
|
||||
|
||||
ElasticityOperator<finite_stress_qf> hooke(pmesh,
|
||||
fespaces->GetFinestFESpace(), matfree,
|
||||
dump_matrices);
|
||||
|
||||
if (pmesh.bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_attr(pmesh.bdr_attributes.Max());
|
||||
if (problem_type == 0)
|
||||
{
|
||||
ess_attr = 0;
|
||||
}
|
||||
else if (problem_type == 1)
|
||||
{
|
||||
ess_attr = 1;
|
||||
}
|
||||
else if (problem_type == 2)
|
||||
{
|
||||
ess_attr = 0;
|
||||
ess_attr[0] = 1;
|
||||
}
|
||||
else if (problem_type == 3)
|
||||
{
|
||||
ess_attr = 1;
|
||||
}
|
||||
hooke.SetEssentialAttributes(ess_attr);
|
||||
int fixed_dofs_local = hooke.ess_tdof_list.Size();
|
||||
int fixed_dofs_global = 0;
|
||||
MPI_Allreduce(&fixed_dofs_local, &fixed_dofs_global, 1, MPI_INT, MPI_SUM,
|
||||
pmesh.GetComm());
|
||||
if (Mpi::Root())
|
||||
{
|
||||
out << "#fixed dofs: " << fixed_dofs_global << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (problem_type == 1)
|
||||
{
|
||||
// auto body_force = hooke.GetBodyForce();
|
||||
// VectorFunctionCoefficient coeff(2, [](const Vector &coords, Vector &u)
|
||||
// {
|
||||
// const double x = coords(0);
|
||||
// const double y = coords(1);
|
||||
|
||||
// const double a = 0.01, b = 0.05;
|
||||
|
||||
// const double nu = 0.3;
|
||||
// const double E = 1.0;
|
||||
// const double lambda = nu * E / ((1.0 + nu) * (1.0 - 2.0*nu));
|
||||
// const double mu = E / (2.0 * (1.0 + nu));
|
||||
|
||||
// u(0) = b * (2.0 * lambda + 2.0 * mu);
|
||||
// u(1) = a * (2.0 * lambda + 2.0 * mu);
|
||||
// });
|
||||
// body_force->ProjectCoefficient(coeff);
|
||||
}
|
||||
|
||||
ParGridFunction U_gf(&hooke.h1_fes), Ucmp_gf(&hooke.h1_fes);
|
||||
U_gf = 0.0;
|
||||
|
||||
auto boundary_load_ramp = [&](double ramp_scale = 1.0)
|
||||
{
|
||||
Array<int> boundary_load_attr(pmesh.bdr_attributes.Max());
|
||||
boundary_load_attr = 0;
|
||||
boundary_load_attr[1] = 1;
|
||||
|
||||
auto boundary_load = hooke.GetExternalLoad();
|
||||
VectorFunctionCoefficient boundary_load_coeff(2, [&](const Vector &, Vector &u)
|
||||
{
|
||||
u(0) = 0.0;
|
||||
u(1) = -1.0e-3 * ramp_scale;
|
||||
});
|
||||
boundary_load->ProjectBdrCoefficient(boundary_load_coeff, boundary_load_attr);
|
||||
};
|
||||
|
||||
AffineSolution<2> affine_solution;
|
||||
auto patch_test_boundary_load_ramp = [&](ParGridFunction &gf,
|
||||
double ramp_scale = 1.0)
|
||||
{
|
||||
u_ex_coeff =
|
||||
std::make_shared<VectorFunctionCoefficient>(2,[&](const Vector &coords,
|
||||
Vector &u)
|
||||
{
|
||||
affine_solution(coords, u);
|
||||
u *= ramp_scale;
|
||||
});
|
||||
|
||||
Array<int> mms_bdr(pmesh.bdr_attributes.Max());
|
||||
mms_bdr = 1;
|
||||
gf.ProjectBdrCoefficient(*u_ex_coeff, mms_bdr);
|
||||
};
|
||||
|
||||
if (problem_type == 1)
|
||||
{
|
||||
u_ex_coeff =
|
||||
std::make_shared<VectorFunctionCoefficient>(2,[](const Vector &coords,
|
||||
Vector &u)
|
||||
{
|
||||
const double x = coords(0);
|
||||
const double y = coords(1);
|
||||
const double a = 0.01, b = 0.05;
|
||||
|
||||
u(0) = a * (2.0 * x + y);
|
||||
u(1) = b * (x + 2.0 * y);
|
||||
});
|
||||
|
||||
Array<int> mms_bdr(pmesh.bdr_attributes.Max());
|
||||
mms_bdr = 1;
|
||||
U_gf.ProjectBdrCoefficient(*u_ex_coeff, mms_bdr);
|
||||
}
|
||||
|
||||
Vector U;
|
||||
U_gf.GetTrueDofs(U);
|
||||
|
||||
if (problem_type == 0)
|
||||
{
|
||||
VectorFunctionCoefficient ucoeff(dim, [&](const Vector &c, Vector &u)
|
||||
{
|
||||
const double x = c(0), y = c(1);
|
||||
u(0) = x*x;
|
||||
u(1) = y;
|
||||
u *= 0.01;
|
||||
});
|
||||
U_gf.ProjectCoefficient(ucoeff);
|
||||
U_gf.GetTrueDofs(U);
|
||||
out << "u: ";
|
||||
U.Print(out, U.Size());
|
||||
Vector R(U.Size());
|
||||
out << "r(u): ";
|
||||
hooke.Mult(U, R);
|
||||
// hooke.Mult(U, R);
|
||||
R.Print(out, U.Size());
|
||||
hooke.GetGradient(U);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
HypreBoomerAMG* amg = nullptr;
|
||||
Multigrid pmg_solver;
|
||||
|
||||
GMRESSolver gmres(MPI_COMM_WORLD);
|
||||
gmres.SetRelTol(1e-8);
|
||||
gmres.SetMaxIter(1000);
|
||||
gmres.SetPrintLevel(2);
|
||||
if (pmg)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!matfree)
|
||||
{
|
||||
amg = new HypreBoomerAMG;
|
||||
amg->SetPrintLevel(0);
|
||||
amg->SetElasticityOptions(&hooke.h1_fes);
|
||||
gmres.SetPreconditioner(*amg);
|
||||
}
|
||||
}
|
||||
|
||||
NewtonSolver newton(MPI_COMM_WORLD);
|
||||
newton.iterative_mode = true;
|
||||
newton.SetSolver(gmres);
|
||||
newton.SetOperator(hooke);
|
||||
newton.SetRelTol(1e-10);
|
||||
newton.SetMaxIter(50);
|
||||
newton.SetPrintLevel(1);
|
||||
|
||||
if (problem_type == 2)
|
||||
{
|
||||
boundary_load_ramp(1.0);
|
||||
|
||||
Vector zero;
|
||||
newton.Mult(zero, U);
|
||||
}
|
||||
else if (problem_type == 3)
|
||||
{
|
||||
patch_test_boundary_load_ramp(U_gf, 1.0);
|
||||
U_gf.GetTrueDofs(U);
|
||||
|
||||
Vector U_tmp(U), f_tmp(U);
|
||||
auto J = &hooke.GetGradientNoBC(U_tmp);
|
||||
|
||||
J->Mult(U_tmp, f_tmp);
|
||||
f_tmp *= -1.0;
|
||||
|
||||
ParGridFunction f_gf(U_gf);
|
||||
f_gf.Distribute(f_tmp);
|
||||
patch_test_boundary_load_ramp(f_gf, 1.0);
|
||||
f_gf.GetTrueDofs(f_tmp);
|
||||
|
||||
J = &hooke.GetGradient(U_tmp);
|
||||
|
||||
gmres.SetOperator(*J);
|
||||
gmres.Mult(f_tmp, U);
|
||||
|
||||
Vector zero;
|
||||
newton.Mult(zero, U);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector zero;
|
||||
newton.Mult(zero, U);
|
||||
}
|
||||
|
||||
U_gf.Distribute(U);
|
||||
|
||||
if (problem_type == 1 || problem_type == 3)
|
||||
{
|
||||
out << "||u - u_ex||_L2 = " << U_gf.ComputeL2Error(*u_ex_coeff) << "\n";
|
||||
}
|
||||
|
||||
CALI_MARK_FUNCTION_END;
|
||||
caliper_mgr.flush();
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
if (Mpi::Root())
|
||||
{
|
||||
cout << "writing viz files...\n";
|
||||
}
|
||||
ParaViewDataCollection paraview_dc("hooke", &pmesh);
|
||||
paraview_dc.SetPrefixPath("output");
|
||||
paraview_dc.SetLevelsOfDetail(polynomial_degree);
|
||||
paraview_dc.SetCycle(0);
|
||||
paraview_dc.SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc.SetHighOrderOutput(true);
|
||||
paraview_dc.SetTime(0.0); // set the time
|
||||
paraview_dc.RegisterField("displacement", &U_gf);
|
||||
if (problem_type == 1)
|
||||
{
|
||||
Ucmp_gf.ProjectCoefficient(*u_ex_coeff);
|
||||
Ucmp_gf -= U_gf;
|
||||
paraview_dc.RegisterField("displacement_cmp", &Ucmp_gf);
|
||||
}
|
||||
paraview_dc.Save();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
# Copyright (c) 2010-2022, 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.
|
||||
|
||||
set(IPOPT_EXAMPLES_SRCS)
|
||||
list(APPEND IPOPT_EXAMPLES_SRCS exContactBlockTL.cpp)
|
||||
|
||||
# Include the source directory where mfem.hpp and mfem-performance.hpp are.
|
||||
include_directories(BEFORE ${PROJECT_BINARY_DIR})
|
||||
|
||||
# Add "test_ipopt" target, see below.
|
||||
add_custom_target(test_ipopt
|
||||
${CMAKE_CTEST_COMMAND} -R ipopt USES_TERMINAL)
|
||||
|
||||
# Add one executable per cpp file, adding "ipopt_" as prefix. Sets
|
||||
# "test_ipopt" as a target that depends on the given examples.
|
||||
set(PFX ipopt_)
|
||||
add_mfem_examples(IPOPT_EXAMPLES_SRCS ${PFX} "" test_ipopt)
|
||||
|
||||
# Testing.
|
||||
# The IPOPT tests can be run separately using the target "test_ipopt"
|
||||
# which builds the examples and runs:
|
||||
# ctest -R ipopt
|
||||
|
||||
if (MFEM_ENABLE_TESTING)
|
||||
# Command line options for the tests.
|
||||
# Example 9:
|
||||
set(EXCONTACTBTL_COMMON_OPTS -m ../../data/periodic-segment.mesh -p 0 -dt 0.005)
|
||||
set(EXCONTACTBTL_TEST_OPTS ${EXCONTACTBTL_COMMON_OPTS} -r 2 )
|
||||
|
||||
# Add the tests: one test per source file.
|
||||
foreach(SRC_FILE ${IPOPT_EXAMPLES_SRCS})
|
||||
get_filename_component(SRC_FILENAME ${SRC_FILE} NAME)
|
||||
string(REPLACE ".cpp" "" TEST_NAME ${SRC_FILENAME})
|
||||
string(TOUPPER ${TEST_NAME} UP_TEST_NAME)
|
||||
set(TEST_NAME ${PFX}${TEST_NAME})
|
||||
|
||||
set(THIS_TEST_OPTIONS "-no-vis")
|
||||
list(APPEND THIS_TEST_OPTIONS ${${UP_TEST_NAME}_TEST_OPTS})
|
||||
# message(STATUS "Test ${TEST_NAME} options: ${THIS_TEST_OPTIONS}")
|
||||
|
||||
if (NOT (${TEST_NAME} MATCHES ".*p$"))
|
||||
add_test(NAME ${TEST_NAME}_ser
|
||||
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
|
||||
else()
|
||||
add_test(NAME ${TEST_NAME}_np=4
|
||||
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 4
|
||||
${MPIEXEC_PREFLAGS}
|
||||
$<TARGET_FILE:${TEST_NAME}> ${THIS_TEST_OPTIONS}
|
||||
${MPIEXEC_POSTFLAGS})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
@@ -0,0 +1,19 @@
|
||||
Finite Element Discretization Library
|
||||
__
|
||||
_ __ ___ / _| ___ _ __ ___
|
||||
| '_ ` _ \ | |_ / _ \| '_ ` _ \
|
||||
| | | | | || _|| __/| | | | | |
|
||||
|_| |_| |_||_| \___||_| |_| |_|
|
||||
|
||||
https://mfem.org
|
||||
|
||||
This directory contains modifications of the example codes that illustrate the
|
||||
use of MFEM for solving nonlinear constrained optimization problems, including
|
||||
features based on the IpOpt, a lightweight HPC solver for nonlinear optimization
|
||||
problems.
|
||||
|
||||
To use the Ipopt features, make sure that MFEM is configured with the option
|
||||
"MFEM_USE_IPOPT = YES", see the top-level INSTALL file for details.
|
||||
|
||||
We recommend comparing the original example codes with the corresponding files
|
||||
in the current directory.
|
||||
@@ -0,0 +1,103 @@
|
||||
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
|
||||
3
|
||||
|
||||
elements
|
||||
9
|
||||
1 5 0 1 3 2 8 9 11 10
|
||||
1 5 2 3 5 4 10 11 13 12
|
||||
1 5 4 5 7 6 12 13 15 14
|
||||
1 5 8 9 11 10 16 17 19 18
|
||||
1 5 10 11 13 12 18 19 21 20
|
||||
1 5 12 13 15 14 20 21 23 22
|
||||
1 5 16 17 19 18 24 25 27 26
|
||||
1 5 18 19 21 20 26 27 29 28
|
||||
1 5 20 21 23 22 28 29 31 30
|
||||
|
||||
|
||||
|
||||
# 0 nothing
|
||||
# 1 dirichlet bc
|
||||
# 2 contact
|
||||
boundary
|
||||
30
|
||||
0 3 1 0 2 3
|
||||
0 3 3 2 4 5
|
||||
0 3 5 4 6 7
|
||||
0 3 24 25 27 26
|
||||
0 3 26 27 29 28
|
||||
0 3 28 29 31 30
|
||||
1 3 2 0 8 10
|
||||
1 3 4 2 10 12
|
||||
1 3 6 4 12 14
|
||||
1 3 10 8 16 18
|
||||
1 3 12 10 18 20
|
||||
1 3 14 12 20 22
|
||||
1 3 18 16 24 26
|
||||
1 3 20 18 26 28
|
||||
1 3 22 20 28 30
|
||||
2 3 1 3 11 9
|
||||
2 3 3 5 13 11
|
||||
2 3 5 7 15 13
|
||||
2 3 9 11 19 17
|
||||
2 3 11 13 21 19
|
||||
2 3 13 15 23 21
|
||||
2 3 17 19 27 25
|
||||
2 3 19 21 29 27
|
||||
2 3 21 23 31 29
|
||||
0 3 8 0 1 9
|
||||
0 3 16 8 9 17
|
||||
0 3 24 16 17 25
|
||||
0 3 6 14 15 7
|
||||
0 3 14 22 23 15
|
||||
0 3 22 30 31 23
|
||||
|
||||
|
||||
vertices
|
||||
32
|
||||
3
|
||||
-1.0000 0 0
|
||||
0 0 0
|
||||
-1.0000 0.3333 0
|
||||
0 0.3333 0
|
||||
-1.0000 0.6667 0
|
||||
0 0.6667 0
|
||||
-1.0000 1.0000 0
|
||||
0 1.0000 0
|
||||
-1.0000 0 0.3333
|
||||
0 0 0.3333
|
||||
-1.0000 0.3333 0.3333
|
||||
0 0.3333 0.3333
|
||||
-1.0000 0.6667 0.3333
|
||||
0 0.6667 0.3333
|
||||
-1.0000 1.0000 0.3333
|
||||
0 1.0000 0.3333
|
||||
-1.0000 0 0.6667
|
||||
0 0 0.6667
|
||||
-1.0000 0.3333 0.6667
|
||||
0 0.3333 0.6667
|
||||
-1.0000 0.6667 0.6667
|
||||
0 0.6667 0.6667
|
||||
-1.0000 1.0000 0.6667
|
||||
0 1.0000 0.6667
|
||||
-1.0000 0 1.0000
|
||||
0 0 1.0000
|
||||
-1.0000 0.3333 1.0000
|
||||
0 0.3333 1.0000
|
||||
-1.0000 0.6667 1.0000
|
||||
0 0.6667 1.0000
|
||||
-1.0000 1.0000 1.0000
|
||||
0 1.0000 1.0000
|
||||
@@ -0,0 +1,68 @@
|
||||
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
|
||||
3
|
||||
|
||||
# 1 nothing
|
||||
elements
|
||||
4
|
||||
1 5 0 1 3 2 6 7 9 8
|
||||
1 5 2 3 5 4 8 9 11 10
|
||||
1 5 6 7 9 8 12 13 15 14
|
||||
1 5 8 9 11 10 14 15 17 16
|
||||
|
||||
# 0 nothing
|
||||
# 1 dirichlet bc
|
||||
# 2 contact
|
||||
boundary
|
||||
16
|
||||
0 3 1 0 2 3
|
||||
0 3 3 2 4 5
|
||||
0 3 12 13 15 14
|
||||
0 3 14 15 17 16
|
||||
2 3 2 0 6 8
|
||||
2 3 4 2 8 10
|
||||
2 3 8 6 12 14
|
||||
2 3 10 8 14 16
|
||||
1 3 1 3 9 7
|
||||
1 3 3 5 11 9
|
||||
1 3 7 9 15 13
|
||||
1 3 9 11 17 15
|
||||
0 3 6 0 1 7
|
||||
0 3 12 6 7 13
|
||||
0 3 4 10 11 5
|
||||
0 3 10 16 17 11
|
||||
|
||||
vertices
|
||||
18
|
||||
3
|
||||
0 0.2464 0.2464
|
||||
0.5071 0.2464 0.2464
|
||||
0 0.5000 0.2464
|
||||
0.5071 0.5000 0.2464
|
||||
0 0.7536 0.2464
|
||||
0.5071 0.7536 0.2464
|
||||
0 0.2464 0.5000
|
||||
0.5071 0.2464 0.5000
|
||||
0 0.5000 0.5000
|
||||
0.5071 0.5000 0.5000
|
||||
0 0.7536 0.5000
|
||||
0.5071 0.7536 0.5000
|
||||
0 0.2464 0.7536
|
||||
0.5071 0.2464 0.7536
|
||||
0 0.5000 0.7536
|
||||
0.5071 0.5000 0.7536
|
||||
0 0.7536 0.7536
|
||||
0.5071 0.7536 0.7536
|
||||
@@ -0,0 +1,742 @@
|
||||
// Contact example
|
||||
//
|
||||
// Compile with: make contact
|
||||
//
|
||||
// Sample runs: ./contact -m1 block1.mesh -m2 block2.mesh -at "5 6 7 8"
|
||||
// Sample runs: ./contact -m1 block1_d.mesh -m2 block2_d.mesh -at "5 6 7 8"
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "nodepair.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
bool ifequalarray(const Array<int> a1, const Array<int> a2)
|
||||
{
|
||||
if (a1.Size()!=a2.Size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i=0; i<a1.Size(); i++)
|
||||
{
|
||||
if (a1[i] != a2[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void FindSurfaceToProject(Mesh& mesh, const int elem, int& cbdrface)
|
||||
{
|
||||
Array<int> attr;
|
||||
attr.Append(2);
|
||||
Array<int> faces;
|
||||
Array<int> ori;
|
||||
std::vector<Array<int> > facesVertices;
|
||||
std::vector<int > faceid;
|
||||
mesh.GetElementFaces(elem, faces, ori);
|
||||
int face = -1;
|
||||
for (int i=0; i<faces.Size(); i++)
|
||||
{
|
||||
face = faces[i];
|
||||
Array<int> faceVert;
|
||||
if (!mesh.FaceIsInterior(face)) // if on the boundary
|
||||
{
|
||||
mesh.GetFaceVertices(face, faceVert);
|
||||
faceVert.Sort();
|
||||
facesVertices.push_back(faceVert);
|
||||
faceid.push_back(face);
|
||||
}
|
||||
}
|
||||
int bdrface = facesVertices.size();
|
||||
|
||||
Array<int> bdryFaces;
|
||||
// This shoulnd't need to be rebuilt
|
||||
std::vector<Array<int> > bdryVerts;
|
||||
for (int b=0; b<mesh.GetNBE(); ++b)
|
||||
{
|
||||
if (attr.FindSorted(mesh.GetBdrAttribute(b)) >= 0) // found the contact surface
|
||||
{
|
||||
bdryFaces.Append(b);
|
||||
Array<int> vert;
|
||||
mesh.GetBdrElementVertices(b, vert);
|
||||
vert.Sort();
|
||||
bdryVerts.push_back(vert);
|
||||
}
|
||||
}
|
||||
|
||||
int bdrvert = bdryVerts.size();
|
||||
cbdrface = -1; // the face number of the contact surface element
|
||||
int count_cbdrface = 0; // the number of matching surfaces, used for checks
|
||||
|
||||
for (int i=0; i<bdrface; i++)
|
||||
{
|
||||
for (int j=0; j<bdrvert; j++)
|
||||
{
|
||||
if (ifequalarray(facesVertices[i], bdryVerts[j]))
|
||||
{
|
||||
cbdrface = faceid[i];
|
||||
count_cbdrface += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
MFEM_VERIFY(count_cbdrface == 1,"projection surface not found");
|
||||
|
||||
};
|
||||
|
||||
Vector GetNormalVector(Mesh & mesh, const int elem, const double *ref,
|
||||
int & refFace, int & refNormal, bool & interior)
|
||||
{
|
||||
ElementTransformation *trans = mesh.GetElementTransformation(elem);
|
||||
const int dim = mesh.Dimension();
|
||||
const int spaceDim = trans->GetSpaceDim();
|
||||
|
||||
MFEM_VERIFY(spaceDim == 3, "");
|
||||
|
||||
Vector n(spaceDim);
|
||||
|
||||
IntegrationPoint ip;
|
||||
ip.Set(ref, dim);
|
||||
|
||||
trans->SetIntPoint(&ip);
|
||||
//CalcOrtho(trans->Jacobian(), n); // Works only for face transformations
|
||||
const DenseMatrix jac = trans->Jacobian();
|
||||
|
||||
int dimNormal = -1;
|
||||
int normalSide = -1;
|
||||
|
||||
const double tol = 1.0e-8;
|
||||
for (int i=0; i<dim; ++i)
|
||||
{
|
||||
const double d0 = std::abs(ref[i]);
|
||||
const double d1 = std::abs(ref[i] - 1.0);
|
||||
|
||||
const double d = std::min(d0, d1);
|
||||
// TODO: this works only for hexahedral meshes!
|
||||
|
||||
if (d < tol)
|
||||
{
|
||||
MFEM_VERIFY(dimNormal == -1, "");
|
||||
dimNormal = i;
|
||||
|
||||
if (d0 < tol)
|
||||
{
|
||||
normalSide = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
normalSide = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// closest point on the boundary
|
||||
if (dimNormal < 0 || normalSide < 0) // node is inside the element
|
||||
{
|
||||
interior = 1;
|
||||
Vector n(3);
|
||||
n = 0.0;
|
||||
return n;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(dimNormal >= 0 && normalSide >= 0, "");
|
||||
refNormal = dimNormal;
|
||||
|
||||
MFEM_VERIFY(dim == 3, "");
|
||||
|
||||
{
|
||||
// Find the reference face
|
||||
if (dimNormal == 0)
|
||||
{
|
||||
refFace = (normalSide == 1) ? 2 : 4;
|
||||
}
|
||||
else if (dimNormal == 1)
|
||||
{
|
||||
refFace = (normalSide == 1) ? 3 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
refFace = (normalSide == 1) ? 5 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Vector> tang(2);
|
||||
|
||||
int tangDir[2] = {-1, -1};
|
||||
{
|
||||
int t = 0;
|
||||
for (int i=0; i<dim; ++i)
|
||||
{
|
||||
if (i != dimNormal)
|
||||
{
|
||||
tangDir[t] = i;
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_VERIFY(t == 2, "");
|
||||
}
|
||||
|
||||
for (int i=0; i<2; ++i)
|
||||
{
|
||||
tang[i].SetSize(3);
|
||||
|
||||
Vector tangRef(3);
|
||||
tangRef = 0.0;
|
||||
tangRef[tangDir[i]] = 1.0;
|
||||
|
||||
jac.Mult(tangRef, tang[i]);
|
||||
}
|
||||
|
||||
Vector c(3); // Cross product
|
||||
|
||||
c[0] = (tang[0][1] * tang[1][2]) - (tang[0][2] * tang[1][1]);
|
||||
c[1] = (tang[0][2] * tang[1][0]) - (tang[0][0] * tang[1][2]);
|
||||
c[2] = (tang[0][0] * tang[1][1]) - (tang[0][1] * tang[1][0]);
|
||||
|
||||
c /= c.Norml2();
|
||||
|
||||
Vector nref(3);
|
||||
nref = 0.0;
|
||||
nref[dimNormal] = 1.0;
|
||||
|
||||
Vector ndir(3);
|
||||
jac.Mult(nref, ndir);
|
||||
|
||||
ndir /= ndir.Norml2();
|
||||
|
||||
const double dp = ndir * c;
|
||||
|
||||
// TODO: eliminate c?
|
||||
n = c;
|
||||
if (dp < 0.0)
|
||||
{
|
||||
n *= -1.0;
|
||||
}
|
||||
interior = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
// WARNING: global variable, just for this little example.
|
||||
std::array<std::array<int, 3>, 8> HEX_VERT =
|
||||
{
|
||||
{ {0,0,0},
|
||||
{1,0,0},
|
||||
{1,1,0},
|
||||
{0,1,0},
|
||||
{0,0,1},
|
||||
{1,0,1},
|
||||
{1,1,1},
|
||||
{0,1,1}
|
||||
}
|
||||
};
|
||||
|
||||
int GetHexVertex(int cdim, int c, int fa, int fb, Vector & refCrd)
|
||||
{
|
||||
int ref[3];
|
||||
ref[cdim] = c;
|
||||
ref[cdim == 0 ? 1 : 0] = fa;
|
||||
ref[cdim == 2 ? 1 : 2] = fb;
|
||||
|
||||
for (int i=0; i<3; ++i) { refCrd[i] = ref[i]; }
|
||||
|
||||
int refv = -1;
|
||||
|
||||
for (int i=0; i<8; ++i)
|
||||
{
|
||||
bool match = true;
|
||||
for (int j=0; j<3; ++j)
|
||||
{
|
||||
if (ref[j] != HEX_VERT[i][j]) { match = false; }
|
||||
}
|
||||
|
||||
if (match) { refv = i; }
|
||||
}
|
||||
|
||||
MFEM_VERIFY(refv >= 0, "");
|
||||
|
||||
return refv;
|
||||
}
|
||||
|
||||
// Coordinates in xyz are assumed to be ordered as [X, Y, Z]
|
||||
// where X is the list of x-coordinates for all points and so on.
|
||||
// conn: connectivity of the target surface elements
|
||||
// xi: surface reference cooridnates for the cloest point, involves a linear transformation from [0,1] to [-1,1]
|
||||
void FindPointsInMesh(Mesh & mesh, Vector const& xyz, Array<int>& conn,
|
||||
Vector& xi)
|
||||
{
|
||||
const int dim = mesh.Dimension();
|
||||
const int np = xyz.Size() / dim;
|
||||
|
||||
MFEM_VERIFY(np * dim == xyz.Size(), "");
|
||||
|
||||
mesh.EnsureNodes();
|
||||
|
||||
//FindPointsGSLIB finder(MPI_COMM_WORLD);
|
||||
FindPointsGSLIB finder;
|
||||
|
||||
finder.SetDistanceToleranceForPointsFoundOnBoundary(0.5);
|
||||
|
||||
const double bb_t = 0.5;
|
||||
finder.Setup(mesh, bb_t);
|
||||
|
||||
finder.FindPoints(xyz);
|
||||
|
||||
/// Return code for each point searched by FindPoints: inside element (0), on
|
||||
/// element boundary (1), or not found (2).
|
||||
Array<unsigned int> codes = finder.GetCode();
|
||||
|
||||
/// Return element number for each point found by FindPoints.
|
||||
Array<unsigned int> elems = finder.GetElem();
|
||||
|
||||
/// Return reference coordinates for each point found by FindPoints.
|
||||
Vector refcrd = finder.GetReferencePosition();
|
||||
|
||||
/// Return distance between the sought and the found point in physical space,
|
||||
/// for each point found by FindPoints.
|
||||
Vector dist = finder.GetDist();
|
||||
|
||||
MFEM_VERIFY(dist.Size() == np, "");
|
||||
MFEM_VERIFY(refcrd.Size() == np * dim, "");
|
||||
MFEM_VERIFY(elems.Size() == np, "");
|
||||
MFEM_VERIFY(codes.Size() == np, "");
|
||||
|
||||
bool allfound = true;
|
||||
for (auto code : codes)
|
||||
if (code == 2) { allfound = false; }
|
||||
|
||||
MFEM_VERIFY(allfound, "A point was not found");
|
||||
|
||||
cout << "Maximum distance of projected points: " << dist.Max() << endl;
|
||||
|
||||
// extract information
|
||||
for (int i=0; i<np; ++i)
|
||||
{
|
||||
cout << "Point " << i << ": (";
|
||||
for (int j=0; j<dim; ++j)
|
||||
{
|
||||
cout << xyz[i + (j*np)];
|
||||
if (j == dim-1) {cout << ")" << endl;}
|
||||
else {cout << ", ";}
|
||||
}
|
||||
//cout << " element: " << elems[i] << endl;
|
||||
//cout << " element " << elems[i] << " vertices:" << endl;
|
||||
//Array<int> vert;
|
||||
//mesh.GetElementVertices(elems[i], vert);
|
||||
//for (auto v : vert)
|
||||
//{
|
||||
// cout << " " << v << endl;
|
||||
//}
|
||||
|
||||
/*cout << " reference coordinates: (";
|
||||
for (int j=0; j<dim; ++j)
|
||||
{
|
||||
cout << refcrd[(i*dim) + j];
|
||||
if (j == dim-1)
|
||||
{
|
||||
cout << ")" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << ", ";
|
||||
}
|
||||
}*/
|
||||
|
||||
int refFace, refNormal, refNormalSide;
|
||||
bool is_interior = -1;
|
||||
Vector normal = GetNormalVector(mesh, elems[i], refcrd.GetData() + (i*dim),
|
||||
refFace, refNormal, is_interior);
|
||||
int phyFace;
|
||||
if (is_interior)
|
||||
{
|
||||
phyFace = -1; // the id of the face that has the closest point
|
||||
FindSurfaceToProject(mesh, elems[i], phyFace);
|
||||
|
||||
Array<int> cbdrVert;
|
||||
mesh.GetFaceVertices(phyFace, cbdrVert);
|
||||
Vector xs(dim);
|
||||
xs[0] = xyz[i + 0*np];
|
||||
xs[1] = xyz[i + 1*np];
|
||||
xs[2] = xyz[i + 2*np];
|
||||
Vector xi_tmp(dim-1);
|
||||
// get nodes!
|
||||
|
||||
GridFunction *nodes = mesh.GetNodes();
|
||||
DenseMatrix coords(4,3);
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
for (int j=0; j<3; j++)
|
||||
{
|
||||
coords(i,j) = (*nodes)[cbdrVert[i]*3+j];
|
||||
}
|
||||
}
|
||||
SlaveToMaster(coords, xs, xi_tmp);
|
||||
|
||||
for (int j=0; j<dim-1; ++j)
|
||||
{
|
||||
xi[i*(dim-1)+j] = xi_tmp[j];
|
||||
}
|
||||
// now get get the projection to the surface
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector faceRefCrd(dim-1);
|
||||
{
|
||||
int fd = 0;
|
||||
for (int j=0; j<dim; ++j)
|
||||
{
|
||||
if (j == refNormal)
|
||||
{
|
||||
refNormalSide = (refcrd[(i*dim) + j] > 0.5);
|
||||
}
|
||||
else
|
||||
{
|
||||
faceRefCrd[fd] = refcrd[(i*dim) + j];
|
||||
fd++;
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_VERIFY(fd == dim-1, "");
|
||||
}
|
||||
|
||||
for (int j=0; j<dim-1; ++j)
|
||||
{
|
||||
xi[i*(dim-1)+j] = faceRefCrd[j]*2.0 - 1.0;
|
||||
}
|
||||
//cout << " face reference coordinates: (";
|
||||
for (int j=0; j<dim-1; ++j)
|
||||
{
|
||||
cout << faceRefCrd[j];
|
||||
if (j == dim-2) {cout << ")" << endl;}
|
||||
else {cout << ", ";}
|
||||
}
|
||||
}
|
||||
//cout << " normal vector: ";
|
||||
//normal.Print();
|
||||
|
||||
// ask, does this do anything?
|
||||
/*
|
||||
IntegrationPoint ip;
|
||||
ip.Set(refcrd.GetData() + (i*dim), dim);
|
||||
ElementTransformation *trans = mesh.GetElementTransformation(elems[i]);
|
||||
Vector phys(trans->GetSpaceDim());
|
||||
trans->Transform(ip, phys);
|
||||
cout << " physical coordinates: ";
|
||||
phys.Print();
|
||||
*/
|
||||
|
||||
// Get the element face
|
||||
Array<int> faces;
|
||||
Array<int> ori;
|
||||
int face;
|
||||
|
||||
if (is_interior)
|
||||
{
|
||||
face = phyFace;
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh.GetElementFaces(elems[i], faces, ori);
|
||||
face = faces[refFace];
|
||||
}
|
||||
|
||||
Array<int> faceVert;
|
||||
mesh.GetFaceVertices(face, faceVert);
|
||||
|
||||
//cout << " face " << face << " vertices:" << endl;
|
||||
//for (auto v : faceVert){ cout << " " << v << endl;}
|
||||
|
||||
for (int p=0; p<4; p++)
|
||||
{
|
||||
conn[4*i+p] = faceVert[p];
|
||||
}
|
||||
/*
|
||||
Vector ref(dim);
|
||||
|
||||
for (int p=0; p<2; ++p)
|
||||
for (int q=0; q<2; ++q)
|
||||
{
|
||||
const int refv = GetHexVertex(refNormal, refNormalSide, p, q, ref);
|
||||
cout << " face reference vertex (" << p << "," << q
|
||||
<< ") is global vertex " << vert[refv] << endl;
|
||||
|
||||
{
|
||||
// Sanity check
|
||||
ip.Set(ref.GetData(), dim);
|
||||
trans->Transform(ip, phys);
|
||||
for (int j=0; j<dim; ++j)
|
||||
{
|
||||
phys[j] -= mesh.GetVertex(vert[refv])[j];
|
||||
}
|
||||
phys.Print();
|
||||
cout<<vert[refv]<<endl;
|
||||
cout<<mesh.GetVertex(vert[refv])[0]<<endl;
|
||||
cout<<mesh.GetVertex(vert[refv])[1]<<endl;
|
||||
cout<<mesh.GetVertex(vert[refv])[2]<<endl;
|
||||
MFEM_VERIFY(phys.Norml2() < 1.0e-12, "Sanity check failed");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file1 = "block1.mesh";
|
||||
const char *mesh_file2 = "block2.mesh";
|
||||
|
||||
Array<int> attr;
|
||||
Array<int> m_attr;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file1, "-m1", "--mesh1",
|
||||
"First mesh file to use.");
|
||||
args.AddOption(&mesh_file2, "-m2", "--mesh2",
|
||||
"Second mesh file to use.");
|
||||
args.AddOption(&attr, "-at", "--attributes-surf",
|
||||
"Attributes of boundary faces on contact surface for mesh 2.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
Mesh mesh1(mesh_file1, 1, 1);
|
||||
Mesh mesh2(mesh_file2, 1, 1);
|
||||
|
||||
const int dim = mesh1.Dimension();
|
||||
MFEM_VERIFY(dim == mesh2.Dimension(), "");
|
||||
|
||||
// boundary attribute 2 is the potential contact surface of nodes
|
||||
attr.Append(2);
|
||||
// boundary attribute 2 is the potential contact surface for master surface
|
||||
m_attr.Append(2);
|
||||
|
||||
// Define a finite element space on the mesh. Here we use vector finite
|
||||
// elements, i.e. dim copies of a scalar finite element space. The vector
|
||||
// dimension is specified by the last argument of the FiniteElementSpace
|
||||
// constructor.
|
||||
FiniteElementCollection *fec1;
|
||||
FiniteElementSpace *fespace1;
|
||||
fec1 = new H1_FECollection(1, dim);
|
||||
fespace1 = new FiniteElementSpace(&mesh1, fec1, dim, Ordering::byVDIM);
|
||||
cout << "Number of finite element unknowns for mesh1: "
|
||||
<< fespace1->GetTrueVSize() << endl;
|
||||
mesh1.SetNodalFESpace(fespace1);
|
||||
GridFunction nodes0 = *mesh1.GetNodes(); // undeformed mesh1 nodal grid function
|
||||
GridFunction *nodes1 = mesh1.GetNodes();
|
||||
|
||||
FiniteElementCollection *fec2 = new H1_FECollection(1, dim);
|
||||
FiniteElementSpace *fespace2 = new FiniteElementSpace(&mesh2, fec2, dim,
|
||||
Ordering::byVDIM);
|
||||
cout << "Number of finite element unknowns for mesh2: "
|
||||
<< fespace2->GetTrueVSize() << endl;
|
||||
|
||||
// degrees of freedom of both meshes
|
||||
int ndof_1 = fespace1->GetTrueVSize();
|
||||
int ndof_2 = fespace2->GetTrueVSize();
|
||||
int ndofs = ndof_1 + ndof_2;
|
||||
// number of nodes for each mesh
|
||||
int nnd_1 = mesh1.GetNV();
|
||||
int nnd_2 = mesh2.GetNV();
|
||||
int nnd = nnd_1 + nnd_2;
|
||||
// Determine the list of true (i.e. conforming) essential boundary dofs.
|
||||
// In this example, the boundary conditions are defined by marking only
|
||||
// boundary attribute 1 from the mesh as essential and converting it to a
|
||||
// list of true dofs.
|
||||
Array<int> ess_tdof_list1, ess_bdr1(mesh1.bdr_attributes.Max());
|
||||
cout<<mesh1.bdr_attributes.Max()<<endl;
|
||||
ess_bdr1 = 0;
|
||||
//ess_bdr1[0] = 1;
|
||||
// Not ready to be passed on yet
|
||||
// fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
|
||||
Array<int> ess_tdof_list2, ess_bdr2(mesh2.bdr_attributes.Max());
|
||||
ess_bdr2 = 0;
|
||||
//ess_bdr2[0] = 1;
|
||||
|
||||
// Define the displacement vector x as a finite element grid function
|
||||
// corresponding to fespace. GridFunction is a derived class of Vector.
|
||||
GridFunction x1(fespace1);
|
||||
x1 = 0.0;
|
||||
GridFunction x2(fespace2);
|
||||
x2 = 0.0;
|
||||
|
||||
// Generate force
|
||||
LinearForm *b1 = new LinearForm(fespace1);
|
||||
b1->Assemble();
|
||||
|
||||
LinearForm *b2 = new LinearForm(fespace2);
|
||||
b2->Assemble();
|
||||
|
||||
// Set up the bilinear form a(.,.) on the finite element space
|
||||
// corresponding to the linear elasticity integrator with piece-wise
|
||||
// constants coefficient lambda and mu.
|
||||
Vector lambda1(mesh1.attributes.Max());
|
||||
lambda1 = 57.6923076923;
|
||||
PWConstCoefficient lambda1_func(lambda1);
|
||||
Vector mu1(mesh1.attributes.Max());
|
||||
mu1 = 38.4615384615;
|
||||
PWConstCoefficient mu1_func(mu1);
|
||||
|
||||
BilinearForm *a1 = new BilinearForm(fespace1);
|
||||
a1->AddDomainIntegrator(new ElasticityIntegrator(lambda1_func,mu1_func));
|
||||
|
||||
Vector lambda2(mesh2.attributes.Max());
|
||||
lambda2 = 57.6923076923;
|
||||
PWConstCoefficient lambda2_func(lambda2);
|
||||
Vector mu2(mesh2.attributes.Max());
|
||||
mu2 = 38.4615384615;
|
||||
PWConstCoefficient mu2_func(mu2);
|
||||
|
||||
BilinearForm *a2 = new BilinearForm(fespace2);
|
||||
a2->AddDomainIntegrator(new ElasticityIntegrator(lambda2_func,mu2_func));
|
||||
|
||||
a1->Assemble();
|
||||
SparseMatrix A1;
|
||||
Vector B1, X1;
|
||||
a1->FormLinearSystem(ess_tdof_list1, x1, *b1, A1, X1, B1);
|
||||
|
||||
a2->Assemble();
|
||||
SparseMatrix A2;
|
||||
Vector B2, X2;
|
||||
a2->FormLinearSystem(ess_tdof_list2, x2, *b2, A2, X2, B2);
|
||||
|
||||
// Combine elasticity operator for two meshes into one.
|
||||
// Block Matrix
|
||||
SparseMatrix K(ndofs,ndofs);
|
||||
for (int i=0; i<A1.Height(); i++)
|
||||
{
|
||||
Array<int> col_tmp;
|
||||
Vector v_tmp;
|
||||
col_tmp = 0;
|
||||
v_tmp = 0.0;
|
||||
A1.GetRow(i, col_tmp, v_tmp);
|
||||
K.SetRow(i, col_tmp, v_tmp);
|
||||
}
|
||||
for (int i=0; i<A2.Height(); i++)
|
||||
{
|
||||
Array<int> col_tmp;
|
||||
Vector v_tmp;
|
||||
col_tmp = 0;
|
||||
v_tmp = 0.0;
|
||||
A2.GetRow(i, col_tmp, v_tmp);
|
||||
for (int j=0; j<col_tmp.Size(); j++)
|
||||
{
|
||||
col_tmp[j] += ndof_1;
|
||||
}
|
||||
K.SetRow(i+ndof_1, col_tmp, v_tmp); // mesh1 top left corner
|
||||
}
|
||||
|
||||
// Construct node to segment contact constraint.
|
||||
|
||||
attr.Sort();
|
||||
cout << "Boundary attributes for contact surface faces in mesh 2" << endl;
|
||||
for (auto a : attr)
|
||||
{
|
||||
cout << a << endl;
|
||||
}
|
||||
|
||||
Array<int> bdryFaces2; // TODO: remove this?
|
||||
|
||||
std::set<int> bdryVerts2;
|
||||
for (int b=0; b<mesh2.GetNBE(); ++b)
|
||||
{
|
||||
if (attr.FindSorted(mesh2.GetBdrAttribute(b)) >= 0)
|
||||
{
|
||||
bdryFaces2.Append(b);
|
||||
Array<int> vert;
|
||||
mesh2.GetBdrElementVertices(b, vert);
|
||||
for (auto v : vert)
|
||||
{
|
||||
bdryVerts2.insert(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int npoints = bdryVerts2.size();
|
||||
Array<int> s_conn(npoints); // connectivity of the second/slave mesh
|
||||
Vector xyz(dim * npoints);
|
||||
xyz = 0.0;
|
||||
|
||||
cout << "Boundary vertices for contact surface vertices in mesh 2" << endl;
|
||||
|
||||
// construct the nodal coordinates on mesh2 to be projected, including displacement
|
||||
int count = 0;
|
||||
for (auto v : bdryVerts2)
|
||||
{
|
||||
cout << v << ": " << mesh2.GetVertex(v)[0] << ", "
|
||||
<< mesh2.GetVertex(v)[1] << ", "
|
||||
<< mesh2.GetVertex(v)[2] << endl;
|
||||
|
||||
for (int i=0; i<dim; ++i)
|
||||
{
|
||||
xyz[count + (i * npoints)] = mesh2.GetVertex(v)[i] + x2[v*dim+i];
|
||||
}
|
||||
|
||||
s_conn[count] = v + nnd_1; // dof1 is the master
|
||||
count++;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(count == npoints, "");
|
||||
|
||||
// gap function
|
||||
Vector g(npoints*dim);
|
||||
g = -1.0;
|
||||
// segment reference coordinates of the closest point
|
||||
Vector m_xi(npoints*(dim-1));
|
||||
m_xi = -1.0;
|
||||
Vector xs(dim*npoints);
|
||||
xs = 0.0;
|
||||
for (int i=0; i<npoints; i++)
|
||||
{
|
||||
for (int j=0; j<dim; j++)
|
||||
{
|
||||
xs[i*dim+j] = xyz[i + (j*npoints)];
|
||||
}
|
||||
}
|
||||
|
||||
Array<int> m_conn(
|
||||
npoints*4); // only works for linear elements that have 4 vertices!
|
||||
DenseMatrix coordsm(npoints*4, dim);
|
||||
|
||||
// adding displacement to mesh1 using a fixed grid function from mesh1
|
||||
x1 = 1e-4; // x1 order: [xyz xyz... xyz]
|
||||
add(nodes0, x1, *nodes1);
|
||||
|
||||
FindPointsInMesh(mesh1, xyz, m_conn, m_xi);
|
||||
|
||||
for (int i=0; i<npoints; i++)
|
||||
{
|
||||
for (int j=0; j<4; j++)
|
||||
{
|
||||
for (int k=0; k<dim; k++)
|
||||
{
|
||||
coordsm(i*4+j,k) = mesh1.GetVertex(m_conn[i*4+j])[k]+x1[dim*m_conn[i*4+j]+k];
|
||||
}
|
||||
}
|
||||
}
|
||||
//coordsm.Print();
|
||||
SparseMatrix M(nnd,ndofs);
|
||||
std::vector<SparseMatrix> dM(nnd, SparseMatrix(ndofs,ndofs));
|
||||
|
||||
Assemble_Contact(nnd, npoints, ndofs, xs, m_xi, coordsm,
|
||||
s_conn, m_conn, g, M, dM);
|
||||
|
||||
//M.Print();
|
||||
/*Vector eps(ndofs);
|
||||
Vector sol(ndofs); sol = 0.;
|
||||
for(int i=0;i<ndofs;i++) eps[i] = 1e-5 * i ;
|
||||
for(int i=0;i<9;i++)
|
||||
{
|
||||
cout<<i<<endl;
|
||||
dM[s_conn[i]].Mult(eps,sol);
|
||||
sol.Print();
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,230 @@
|
||||
// Contact example
|
||||
//
|
||||
// Compile with: make exContactBlockTL
|
||||
//
|
||||
// Sample runs: ./exContactBlockTL -m1 block1.mesh -m2 block2.mesh -at "5 6 7 8"
|
||||
// Sample runs: ./exContactBlockTL -m1 block1_d.mesh -m2 block2_d.mesh -at "5 6 7 8"
|
||||
|
||||
#ifndef EXCONTACTBLOCKTL_HPP
|
||||
#define EXCONTACTBLOCKTL_HPP
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include "IpTNLP.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
using namespace Ipopt;
|
||||
|
||||
|
||||
class ExContactBlockTL: public TNLP
|
||||
{
|
||||
public:
|
||||
/** default constructor */
|
||||
ExContactBlockTL(int argc, char *argv[]);
|
||||
|
||||
/** default destructor */
|
||||
virtual ~ExContactBlockTL();
|
||||
|
||||
/**@name Overloaded from TNLP */
|
||||
/** Method to return some info about the nlp */
|
||||
virtual bool get_nlp_info(
|
||||
Index& n,
|
||||
Index& m,
|
||||
Index& nnz_jac_g,
|
||||
Index& nnz_h_lag,
|
||||
IndexStyleEnum& index_style
|
||||
);
|
||||
|
||||
/** Method to return the bounds for my problem */
|
||||
virtual bool get_bounds_info(
|
||||
Index n,
|
||||
Number* x_l,
|
||||
Number* x_u,
|
||||
Index m,
|
||||
Number* g_l,
|
||||
Number* g_u
|
||||
);
|
||||
|
||||
/** Method to return the starting point for the algorithm */
|
||||
virtual bool get_starting_point(
|
||||
Index n,
|
||||
bool init_x,
|
||||
Number* x,
|
||||
bool init_z,
|
||||
Number* z_L,
|
||||
Number* z_U,
|
||||
Index m,
|
||||
bool init_lambda,
|
||||
Number* lambda
|
||||
);
|
||||
|
||||
/** Method to return the objective value */
|
||||
virtual bool eval_f(
|
||||
Index n,
|
||||
const Number* x,
|
||||
bool new_x,
|
||||
Number& obj_value
|
||||
);
|
||||
|
||||
/** Method to return the gradient of the objective */
|
||||
virtual bool eval_grad_f(
|
||||
Index n,
|
||||
const Number* x,
|
||||
bool new_x,
|
||||
Number* grad_f
|
||||
);
|
||||
|
||||
/** Method to return the constraint residuals */
|
||||
virtual bool eval_g(
|
||||
Index n,
|
||||
const Number* x,
|
||||
bool new_x,
|
||||
Index m,
|
||||
Number* cons
|
||||
);
|
||||
|
||||
/** Method to return:
|
||||
* 1) The structure of the Jacobian (if "values" is NULL)
|
||||
* 2) The values of the Jacobian (if "values" is not NULL)
|
||||
*/
|
||||
virtual bool eval_jac_g(
|
||||
Index n,
|
||||
const Number* x,
|
||||
bool new_x,
|
||||
Index m,
|
||||
Index nele_jac,
|
||||
Index* iRow,
|
||||
Index* jCol,
|
||||
Number* values
|
||||
);
|
||||
|
||||
/** Method to return:
|
||||
* 1) The structure of the Hessian of the Lagrangian (if "values" is NULL)
|
||||
* 2) The values of the Hessian of the Lagrangian (if "values" is not NULL)
|
||||
*/
|
||||
virtual bool eval_h(
|
||||
Index n,
|
||||
const Number* x,
|
||||
bool new_x,
|
||||
Number obj_factor,
|
||||
Index m,
|
||||
const Number* lambda,
|
||||
bool new_lambda,
|
||||
Index nele_hess,
|
||||
Index* iRow,
|
||||
Index* jCol,
|
||||
Number* values
|
||||
);
|
||||
|
||||
/** This method is called when the algorithm is complete so the TNLP can store/write the solution */
|
||||
virtual void finalize_solution(
|
||||
SolverReturn status,
|
||||
Index n,
|
||||
const Number* x,
|
||||
const Number* z_L,
|
||||
const Number* z_U,
|
||||
Index m,
|
||||
const Number* g,
|
||||
const Number* lambda,
|
||||
Number obj_value,
|
||||
const IpoptData* ip_data,
|
||||
IpoptCalculatedQuantities* ip_cq
|
||||
);
|
||||
|
||||
private:
|
||||
void update_g();
|
||||
void update_jac();
|
||||
void update_hess();
|
||||
|
||||
private:
|
||||
/**@name Methods to block default compiler methods.
|
||||
*
|
||||
* The compiler automatically generates the following three methods.
|
||||
* Since the default compiler implementation is generally not what
|
||||
* you want (for all but the most simple classes), we usually
|
||||
* put the declarations of these methods in the private section
|
||||
* and never implement them. This prevents the compiler from
|
||||
* implementing an incorrect "default" behavior without us
|
||||
* knowing. (See Scott Meyers book, "Effective C++")
|
||||
*/
|
||||
ExContactBlockTL(
|
||||
const ExContactBlockTL&
|
||||
);
|
||||
|
||||
ExContactBlockTL& operator=(
|
||||
const ExContactBlockTL&
|
||||
);
|
||||
|
||||
Array<int> attr;
|
||||
Array<int> m_attr;
|
||||
Array<int> s_conn; // connectivity of the second/slave mesh
|
||||
std::string mesh_file1;
|
||||
std::string mesh_file2;
|
||||
Mesh* mesh1;
|
||||
Mesh* mesh2;
|
||||
FiniteElementCollection* fec1;
|
||||
FiniteElementCollection* fec2;
|
||||
FiniteElementSpace* fespace1;
|
||||
FiniteElementSpace* fespace2;
|
||||
Array<int> ess_tdof_list1;
|
||||
Array<int> ess_tdof_list2;
|
||||
GridFunction nodes0;
|
||||
GridFunction* nodes1;
|
||||
GridFunction* nodes2;
|
||||
GridFunction* x1;
|
||||
GridFunction* x2;
|
||||
LinearForm* b1;
|
||||
LinearForm* b2;
|
||||
PWConstCoefficient* lambda1_func;
|
||||
PWConstCoefficient* lambda2_func;
|
||||
PWConstCoefficient* mu1_func;
|
||||
PWConstCoefficient* mu2_func;
|
||||
BilinearForm* a1;
|
||||
BilinearForm* a2;
|
||||
|
||||
mfem::Vector lambda1;
|
||||
mfem::Vector lambda2;
|
||||
mfem::Vector mu1;
|
||||
mfem::Vector mu2;
|
||||
mfem::Vector xyz;
|
||||
|
||||
std::set<int> bdryVerts2;
|
||||
|
||||
int dim;
|
||||
// degrees of freedom of both meshes
|
||||
int ndof_1;
|
||||
int ndof_2;
|
||||
int ndofs;
|
||||
// number of nodes for each mesh
|
||||
int nnd_1;
|
||||
int nnd_2;
|
||||
int nnd;
|
||||
|
||||
int npoints;
|
||||
|
||||
SparseMatrix A1;
|
||||
mfem::Vector B1, X1;
|
||||
SparseMatrix A2;
|
||||
mfem::Vector B2, X2;
|
||||
|
||||
SparseMatrix* K;
|
||||
mfem::Vector g;
|
||||
mfem::Vector m_xi;
|
||||
mfem::Vector xs;
|
||||
|
||||
Array<int> m_conn; // only works for linear elements that have 4 vertices!
|
||||
DenseMatrix* coordsm;
|
||||
SparseMatrix* M;
|
||||
|
||||
std::vector<SparseMatrix>* dM;
|
||||
|
||||
Array<int> Dirichlet_dof;
|
||||
Array<double> Dirichlet_val;
|
||||
|
||||
public:
|
||||
Mesh * GetMesh1() {return mesh1;}
|
||||
Mesh * GetMesh2() {return mesh2;}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
# Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
|
||||
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
# LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
#
|
||||
# This file is part of the MFEM library. For more information and source code
|
||||
# availability visit https://mfem.org.
|
||||
#
|
||||
# MFEM is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/ipopt/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
SEQ_EXAMPLES = exContactBlockTL
|
||||
EXAMPLES = $(SEQ_EXAMPLES)
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .cpp .mk
|
||||
.PHONY: all clean clean-build clean-exec
|
||||
|
||||
# Remove built-in rule
|
||||
%: %.cpp
|
||||
|
||||
# Replace the default implicit rule for *.cpp files
|
||||
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
|
||||
|
||||
all: $(EXAMPLES)
|
||||
|
||||
ifeq ($(MFEM_USE_IPOPT),NO)
|
||||
$(EXAMPLES):
|
||||
$(error MFEM is not configured with IPOPT)
|
||||
endif
|
||||
|
||||
MFEM_TESTS = EXAMPLES
|
||||
include $(MFEM_TEST_MK)
|
||||
|
||||
# Testing: Parallel vs. serial runs
|
||||
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
|
||||
%-test-par: %
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel example)
|
||||
%-test-seq: %
|
||||
@$(call mfem-test,$<,, Serial example)
|
||||
|
||||
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
|
||||
|
||||
# Generate an error message if the MFEM library is not built and exit
|
||||
$(MFEM_LIB_FILE):
|
||||
$(error The MFEM library is not built)
|
||||
|
||||
clean: clean-build clean-exec
|
||||
|
||||
clean-build:
|
||||
rm -f *.o *~ $(SEQ_EXAMPLES)
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
clean-exec:
|
||||
@rm -f exContactBlockTL.mesh exContactBlockTL-mesh.* exContactBlockTL-init.* exContactBlockTL-final.* ExampleContactBlockTL*
|
||||
@@ -0,0 +1,888 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
void BasisEval(const Vector xi, Vector &N, DenseMatrix &dNdxi) // dNdxi is 2*4
|
||||
{
|
||||
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
|
||||
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
|
||||
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
|
||||
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
|
||||
|
||||
dNdxi(0,0) = 0.25*(-1+xi[1]);
|
||||
dNdxi(0,1) = 0.25*(1-xi[1]);
|
||||
dNdxi(0,2) = 0.25*(1+xi[1]);
|
||||
dNdxi(0,3) = 0.25*(-1-xi[1]);
|
||||
dNdxi(1,0) = 0.25*(-1+xi[0]);
|
||||
dNdxi(1,1) = 0.25*(-1-xi[0]);
|
||||
dNdxi(1,2) = 0.25*(1+xi[0]);
|
||||
dNdxi(1,3) = 0.25*(1-xi[0]);
|
||||
}
|
||||
|
||||
|
||||
void BasisEvalDerivs(const Vector xi, Vector& N, DenseMatrix& dNdxi,
|
||||
DenseMatrix& dN2dxi)
|
||||
{
|
||||
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
|
||||
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
|
||||
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
|
||||
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
|
||||
|
||||
dNdxi.SetSize(2,4); dNdxi = 0.0;
|
||||
dN2dxi.SetSize(3,4);
|
||||
dN2dxi = 0.0; // first row dxi2, second detadxi, third deta2
|
||||
|
||||
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,1) = 0.25*(1-xi[1]);
|
||||
dNdxi(0,2) = 0.25*(1+xi[1]); dNdxi(0,3) = 0.25*(-1-xi[1]);
|
||||
dNdxi(1,0) = 0.25*(-1+xi[0]); dNdxi(1,1) = 0.25*(-1-xi[0]);
|
||||
dNdxi(1,2) = 0.25*(1+xi[0]); dNdxi(1,3) = 0.25*(1-xi[0]);
|
||||
|
||||
dN2dxi(1,0) = 0.25; dN2dxi(1,1) = -0.25; dN2dxi(1,2) = 0.25;
|
||||
dN2dxi(1,3) = -0.25;
|
||||
}
|
||||
|
||||
// returns the vector and matrix form of the shape functions and its derivative
|
||||
void BasisVectorDerivs(const Vector xi, DenseMatrix& N, DenseMatrix& dNdxi,
|
||||
DenseMatrix& ddNdxi)
|
||||
{
|
||||
N.SetSize(3,12); N = 0.0;
|
||||
N(0,0) = 0.25*(1-xi[0])*(1-xi[1]); N(0,3) = 0.25*(1+xi[0])*(1-xi[1]);
|
||||
N(0,6) = 0.25*(1+xi[0])*(1+xi[1]); N(0,9) = 0.25*(1-xi[0])*(1+xi[1]);
|
||||
|
||||
N(1,1) = 0.25*(1-xi[0])*(1-xi[1]); N(1,4) = 0.25*(1+xi[0])*(1-xi[1]);
|
||||
N(1,7) = 0.25*(1+xi[0])*(1+xi[1]); N(1,10) = 0.25*(1-xi[0])*(1+xi[1]);
|
||||
|
||||
N(2,2) = 0.25*(1-xi[0])*(1-xi[1]); N(2,5) = 0.25*(1+xi[0])*(1-xi[1]);
|
||||
N(2,8) = 0.25*(1+xi[0])*(1+xi[1]); N(2,11) = 0.25*(1-xi[0])*(1+xi[1]);
|
||||
|
||||
dNdxi.SetSize(3*2, 3*4); dNdxi = 0.0;
|
||||
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,3) = 0.25*(1-xi[1]);
|
||||
dNdxi(0,6) = 0.25*(1+xi[1]); dNdxi(0,9) = 0.25*(-1-xi[1]);
|
||||
dNdxi(1,1) = 0.25*(-1+xi[1]); dNdxi(1,4) = 0.25*(1-xi[1]);
|
||||
dNdxi(1,7) = 0.25*(1+xi[1]); dNdxi(1,10) = 0.25*(-1-xi[1]);
|
||||
dNdxi(2,2) = 0.25*(-1+xi[1]); dNdxi(2,5) = 0.25*(1-xi[1]);
|
||||
dNdxi(2,8) = 0.25*(1+xi[1]); dNdxi(2,11) = 0.25*(-1-xi[1]);
|
||||
|
||||
dNdxi(3,0) = 0.25*(-1+xi[0]); dNdxi(3,3) = 0.25*(-1-xi[0]);
|
||||
dNdxi(3,6) = 0.25*(1+xi[0]); dNdxi(3,9) = 0.25*(1-xi[0]);
|
||||
dNdxi(4,1) = 0.25*(-1+xi[0]); dNdxi(4,4) = 0.25*(-1-xi[0]);
|
||||
dNdxi(4,7) = 0.25*(1+xi[0]); dNdxi(4,10) = 0.25*(1-xi[0]);
|
||||
dNdxi(5,2) = 0.25*(-1+xi[0]); dNdxi(5,5) = 0.25*(-1-xi[0]);
|
||||
dNdxi(5,8) = 0.25*(1+xi[0]); dNdxi(5,11) = 0.25*(1-xi[0]);
|
||||
|
||||
ddNdxi.SetSize(3*4, 3*4); ddNdxi = 0.0;
|
||||
ddNdxi(3,0) = 0.25; ddNdxi(3,3) = -0.25;
|
||||
ddNdxi(3,6) = 0.25; ddNdxi(3,9) = -0.25;
|
||||
ddNdxi(4,1) = 0.25; ddNdxi(4,4) = -0.25;
|
||||
ddNdxi(4,7) = 0.25; ddNdxi(4,10) = -0.25;
|
||||
ddNdxi(5,2) = 0.25; ddNdxi(5,5) = -0.25;
|
||||
ddNdxi(5,8) = 0.25; ddNdxi(5,11) = -0.25;
|
||||
|
||||
ddNdxi(6,0) = 0.25; ddNdxi(6,3) = -0.25;
|
||||
ddNdxi(6,6) = 0.25; ddNdxi(6,9) = -0.25;
|
||||
ddNdxi(7,1) = 0.25; ddNdxi(7,4) = -0.25;
|
||||
ddNdxi(7,7) = 0.25; ddNdxi(7,10) = -0.25;
|
||||
ddNdxi(8,2) = 0.25; ddNdxi(8,5) = -0.25;
|
||||
ddNdxi(8,8) = 0.25; ddNdxi(8,11) = -0.25;
|
||||
}
|
||||
|
||||
|
||||
void cross(const Vector a, const Vector b, Vector& c)
|
||||
{
|
||||
assert(a.Size()==3);
|
||||
c.SetSize(3);
|
||||
c[0] = a[1]*b[2] - a[2]*b[1];
|
||||
c[1] = -a[0]*b[2] + b[0]*a[2];
|
||||
c[2] = a[0]*b[1] - a[1]*b[0];
|
||||
|
||||
}
|
||||
// a outer b
|
||||
void outer(const Vector a, const Vector b, DenseMatrix& c)
|
||||
{
|
||||
int m = a.Size();
|
||||
int n = b.Size();
|
||||
assert(c.Height()==m);
|
||||
assert(c.Width() ==n);
|
||||
for (int i=0; i<m; i++)
|
||||
{
|
||||
for (int j=0; j<n; j++)
|
||||
{
|
||||
c(i,j) = a[i]*b[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
// dphidxi 2*4
|
||||
// coords 4*3
|
||||
void ComputeNormal(const DenseMatrix& dphidxi, const DenseMatrix& coords,
|
||||
Vector& normal, double& nnorm)
|
||||
{
|
||||
|
||||
DenseMatrix dxdxi(2,3);
|
||||
Mult(dphidxi, coords, dxdxi);
|
||||
Vector dxdxi1(3);
|
||||
Vector dxdxi2(3);
|
||||
|
||||
dxdxi.GetRow(0,dxdxi1);
|
||||
dxdxi.GetRow(1,dxdxi2);
|
||||
|
||||
cross(dxdxi1, dxdxi2, normal); // is there a cross product? no
|
||||
// VectorCrossProductCoefficient::Eval has hard-coded cross product
|
||||
nnorm = normal.Norml2( );
|
||||
normal /= nnorm;
|
||||
}
|
||||
|
||||
void SlaveToMaster(const DenseMatrix& m_coords, const Vector& s_x, Vector& xi)
|
||||
{
|
||||
bool converged = false;
|
||||
bool pt_on_elem = false;
|
||||
int dim = 3;
|
||||
xi.SetSize(dim-1);
|
||||
xi = 0.0;
|
||||
double r = 1e10;
|
||||
int max_iter = 15;
|
||||
double off_el_xi = 1e-2;
|
||||
double proj_newton_tol = 1e-13;
|
||||
double proj_max_gap = 0.5;
|
||||
Vector gap_v(dim);
|
||||
// warm start from linear solution
|
||||
|
||||
for (int it=0; it<max_iter; it++)
|
||||
{
|
||||
//cout<<it<<endl;
|
||||
Vector m_N(4);
|
||||
m_N = 0.;
|
||||
DenseMatrix m_dN(2,4);
|
||||
m_dN = 0.;
|
||||
DenseMatrix m_dN2(3,4);
|
||||
m_dN2 = 0.;
|
||||
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
|
||||
|
||||
Vector x_c(dim);
|
||||
m_coords.MultTranspose(m_N, x_c);
|
||||
|
||||
gap_v = s_x;
|
||||
gap_v -= x_c;
|
||||
|
||||
DenseMatrix m_dx(2,3);
|
||||
m_dx = 0.;
|
||||
Mult(m_dN, m_coords, m_dx);
|
||||
|
||||
Vector r(dim-1);
|
||||
r = 0.0;
|
||||
m_dx.Mult(gap_v, r);
|
||||
|
||||
if (r.Normlinf() < proj_newton_tol)
|
||||
{
|
||||
converged = true;
|
||||
break;
|
||||
}
|
||||
|
||||
DenseMatrix drdxi(dim-1,dim-1);
|
||||
drdxi = 0.;
|
||||
MultABt(m_dx, m_dx, drdxi); // m_dx * m_dx.T
|
||||
drdxi *= -1.0;
|
||||
|
||||
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
|
||||
Mult(m_dN2,m_coords, m_dx2);
|
||||
|
||||
//m_d2x = m_dN(:,:,2) * m_elem_coords(1:4,:); //m_dN(:,:,2) is 3*4
|
||||
for (int d=0; d<3; d++)
|
||||
{
|
||||
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
|
||||
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
|
||||
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
|
||||
|
||||
drdxi.Add(gap_v[d], Mtemp);
|
||||
}
|
||||
|
||||
//cond_num = rcond(drdxi); condition number?
|
||||
//drdxi.TestInversion();
|
||||
DenseMatrixInverse drdxi_inv(drdxi);
|
||||
Vector xi_tmp(dim-1);
|
||||
|
||||
drdxi_inv.Mult(r,xi_tmp);
|
||||
xi -= xi_tmp;
|
||||
}
|
||||
if (!converged)
|
||||
{
|
||||
xi = 0.0;
|
||||
}
|
||||
off_el_xi += 1 ; // tolerance of offset of xi outside [-1,1]
|
||||
|
||||
//cout<<gap_v.Norml2()<<" " <<xi.Normlinf()<<endl;
|
||||
if (gap_v.Norml2() < proj_max_gap && xi.Normlinf() <= off_el_xi)
|
||||
{
|
||||
pt_on_elem = true;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(pt_on_elem == true, "xi went out of bounds");
|
||||
MFEM_VERIFY(converged == true, "projection didn't converge");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// m_coords is expected to be 4 * 3
|
||||
void ComputeGapJacobian(const Vector x_s, const Vector xi,
|
||||
const DenseMatrix m_coords,
|
||||
double& gap, Vector& normal, Vector& dgdxm, Vector& dgdxs)
|
||||
{
|
||||
Vector m_N(4);
|
||||
DenseMatrix m_dN(2,4);
|
||||
DenseMatrix m_dN2(3,4);
|
||||
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
|
||||
|
||||
Vector x_c(3);
|
||||
m_coords.MultTranspose(m_N, x_c);
|
||||
|
||||
Vector gap_v(3); gap_v = 0.0;
|
||||
gap_v = x_s;
|
||||
gap_v -= x_c;
|
||||
|
||||
DenseMatrix m_dx(2,3);
|
||||
Mult(m_dN, m_coords, m_dx);
|
||||
|
||||
double nnorm = 0;
|
||||
ComputeNormal(m_dN, m_coords, normal, nnorm);
|
||||
|
||||
gap = gap_v * normal; // gap function value, dot product between vectors
|
||||
|
||||
//dr_dx = zeros(2,4,3); % nsegment, nodes in quad, ndim
|
||||
|
||||
DenseMatrix dr_dx_res1(4,3); dr_dx_res1 = 0.;
|
||||
DenseMatrix dr_dx_res2(4,3); dr_dx_res2 = 0.;
|
||||
|
||||
Vector m_dxrow1(3);
|
||||
m_dx.GetRow(0, m_dxrow1);
|
||||
outer(m_N, m_dxrow1, dr_dx_res1);// 4*1 times 1*3
|
||||
dr_dx_res1 *= -1.0;
|
||||
|
||||
Vector m_dxrow2(3);
|
||||
m_dx.GetRow(1, m_dxrow2);
|
||||
outer(m_N, m_dxrow2, dr_dx_res2);// 4*1 times 1*3
|
||||
dr_dx_res2 *= -1.0;
|
||||
|
||||
Vector m_dNrow1(4); m_dN.GetRow(0, m_dNrow1);
|
||||
Vector m_dNrow2(4); m_dN.GetRow(1, m_dNrow2);
|
||||
|
||||
DenseMatrix dr_dx_res1_tmp(4,3); dr_dx_res1_tmp = 0.;
|
||||
DenseMatrix dr_dx_res2_tmp(4,3); dr_dx_res2_tmp = 0.;
|
||||
outer(m_dNrow1, gap_v, dr_dx_res1_tmp);// 4*1 times 1*3
|
||||
outer(m_dNrow2, gap_v, dr_dx_res2_tmp);// 4*1 times 1*3
|
||||
|
||||
dr_dx_res1 += dr_dx_res1_tmp; // outer product in vector?
|
||||
dr_dx_res2 += dr_dx_res2_tmp;
|
||||
|
||||
|
||||
DenseMatrix K_dxidx1(2,2); // 2*2
|
||||
K_dxidx1 = 0.;
|
||||
MultABt(m_dx, m_dx, K_dxidx1); // m_dx * m_dx.T
|
||||
|
||||
Vector v_dxidx2(4);
|
||||
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
|
||||
|
||||
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
|
||||
|
||||
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
|
||||
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
|
||||
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
|
||||
// how to get 2nd order? multidimensional matrix?
|
||||
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
|
||||
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
|
||||
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
|
||||
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
|
||||
|
||||
DenseMatrix K_dxidx(2,2);
|
||||
K_dxidx -= K_dxidx1;
|
||||
K_dxidx += K_dxidx2;
|
||||
|
||||
// resize the vectors and matrices
|
||||
Vector dxidx(24); dxidx = 0.0;
|
||||
Vector drdx_r(24); drdx_r = 0.0;
|
||||
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
for (int j=0; j<3; j++)
|
||||
{
|
||||
drdx_r[4*j+i] = dr_dx_res1(i,j);
|
||||
drdx_r[4*j+i+12] = dr_dx_res2(i,j);
|
||||
|
||||
}
|
||||
}
|
||||
//drdx_r(1:4*3,1) = reshape(dr_dx_res(:,:,1),4*3,1);
|
||||
//drdx_r(4*3+1:2*4*3,1) = reshape(dr_dx_res(:,:,2),4*3,1);
|
||||
DenseMatrix drdx_K(24,24); drdx_K = 0.;
|
||||
for (int i =0; i<12; i++)
|
||||
{
|
||||
drdx_K(i,i) = K_dxidx(0,0);
|
||||
drdx_K(i,12+i) = K_dxidx(0,1);
|
||||
drdx_K(12+i,i) = K_dxidx(1,0);
|
||||
drdx_K(12+i,12+i) = K_dxidx(1,1);
|
||||
}
|
||||
|
||||
DenseMatrixInverse drdxK_inv(drdx_K);
|
||||
drdxK_inv.Mult(drdx_r,dxidx);
|
||||
// LinearSolve (drdx_K,drdx_r, dxidx) ; //???
|
||||
dxidx *= -1.0;
|
||||
|
||||
|
||||
|
||||
Vector drdxs_r(6);
|
||||
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
|
||||
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
|
||||
|
||||
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
drdxs_K(i,i) = K_dxidx(0,0);
|
||||
drdxs_K(i,3+i) = K_dxidx(0,1);
|
||||
drdxs_K(i+3,i) = K_dxidx(1,0);
|
||||
drdxs_K(i+3,i+3) = K_dxidx(1,1);
|
||||
}
|
||||
|
||||
Vector dxidxs(6); dxidxs = 0.0;
|
||||
DenseMatrixInverse drdxsK_inv(drdxs_K);
|
||||
drdxsK_inv.Mult(drdxs_r,dxidxs);
|
||||
dxidxs *= -1.0;
|
||||
//dxidxs = -drdxs_K\drdxs_r;
|
||||
|
||||
//dxidx = reshape(dxidx, 4,3,2); dxidxs = reshape(dxidxs, 1,3,2);
|
||||
|
||||
dgdxm.SetSize(12); dgdxm = 0.;
|
||||
DenseMatrix dgdxm_tmp(4,3);
|
||||
outer(m_N, normal,dgdxm_tmp);
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
for (int j=0; j<3; j++)
|
||||
{
|
||||
dgdxm[3*i+j] = -dgdxm_tmp(i,j);
|
||||
}
|
||||
}
|
||||
//dxidx_M = -m_dN(1:2,:,1) * (m_coords(1:4,:)*normal'); % this turns out to be 0
|
||||
|
||||
dgdxs.SetSize(3);
|
||||
dgdxs += normal;
|
||||
//dgdxs = dgdxs + dxidx_M(1) * dxidxs(:,:,1) + dxidx_M(2) * dxidxs(:,:,2);
|
||||
};
|
||||
|
||||
void ComputeGapHessian(const Vector x_s, const Vector xi,
|
||||
const DenseMatrix m_coords,
|
||||
DenseMatrix& dg2dx)
|
||||
{
|
||||
Vector m_N(4);
|
||||
DenseMatrix m_dN(2,4);
|
||||
DenseMatrix m_dN2(3,4);
|
||||
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
|
||||
|
||||
int dim = 3;
|
||||
int num_dofs1 = dim;
|
||||
int num_dofs2 = 4*dim;
|
||||
int num_dofs = num_dofs1 + num_dofs2;
|
||||
dg2dx.SetSize(num_dofs,num_dofs); dg2dx = 0.0;
|
||||
|
||||
Vector x_c(3);
|
||||
m_coords.MultTranspose(m_N,x_c);
|
||||
|
||||
Vector gap_v(3); gap_v = 0.0;
|
||||
gap_v = x_s;
|
||||
gap_v -= x_c;
|
||||
|
||||
DenseMatrix m_dx(2,3);
|
||||
Mult(m_dN, m_coords, m_dx);
|
||||
|
||||
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
|
||||
Mult(m_dN2,m_coords, m_dx2);
|
||||
double nnorm = 0.0;
|
||||
Vector normal(3); normal = 0.0;
|
||||
ComputeNormal(m_dN, m_coords, normal, nnorm);
|
||||
|
||||
double gap = gap_v * normal; // gap function value, dot product between vectors
|
||||
|
||||
DenseMatrix M(2,2); M = 0.0;
|
||||
MultABt(m_dx, m_dx, M);
|
||||
|
||||
DenseMatrix f(2, num_dofs2); f = 0.0;
|
||||
|
||||
for (int d=0; d<3; d++)
|
||||
{
|
||||
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
|
||||
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
|
||||
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
|
||||
|
||||
M.Add(-gap_v[d], Mtemp);
|
||||
|
||||
Vector m_dxcol(2); m_dx.GetColumn(d, m_dxcol);
|
||||
DenseMatrix ftmp(2,4);
|
||||
outer(m_dxcol, m_N, ftmp);
|
||||
ftmp *= -1;
|
||||
ftmp.Add( gap_v[d], m_dN); // 2*4
|
||||
|
||||
for (int j=0; j<4; j++)
|
||||
{
|
||||
assert(d+3*j<num_dofs2);
|
||||
f(0,d+j*3) = ftmp(0,j);
|
||||
f(1,d+j*3) = ftmp(1,j);
|
||||
}
|
||||
}
|
||||
//fprintf('hess dxidxm\n');
|
||||
DenseMatrixInverse Minv(M);
|
||||
DenseMatrix dxidxm(2,num_dofs2); dxidxm = 0.0;
|
||||
Minv.Mult(f, dxidxm);
|
||||
//LinearSolve??
|
||||
//dxidxm = M\f;
|
||||
|
||||
DenseMatrix nde2(2,2); nde2 = 0.0;
|
||||
DenseMatrix Nndx2(2,num_dofs2); Nndx2 = 0.0;
|
||||
|
||||
for (int d=0; d<3; d++)
|
||||
{
|
||||
DenseMatrix ndetmp(2,2); ndetmp = 0.0;
|
||||
ndetmp(0,0) = normal(d)*m_dx2(0,d); ndetmp(0,1) = normal(d)*m_dx2(1,d);
|
||||
ndetmp(1,0) = normal(d)*m_dx2(1,d); ndetmp(1,1) = normal(d)*m_dx2(2,d);
|
||||
|
||||
nde2 += ndetmp;
|
||||
|
||||
for (int j=0; j<4; j++)
|
||||
{
|
||||
assert(d+3*j<num_dofs2);
|
||||
Nndx2(0,d+j*3) = normal[d]*m_dN(0,j);
|
||||
Nndx2(1,d+j*3) = normal[d]*m_dN(1,j);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DenseMatrix Ndn(2,num_dofs2); Ndn = 0.0;
|
||||
Ndn += Nndx2;
|
||||
AddMult(nde2, dxidxm, Ndn);
|
||||
|
||||
|
||||
DenseMatrix M2(2,2); M2 = 0.0;
|
||||
MultABt(m_dx, m_dx, M2);
|
||||
DenseMatrixInverse M2inv(M2);
|
||||
DenseMatrix diag2(2,2); diag2(0,0) = 1.0; diag2(1,1) = 1.0;
|
||||
DenseMatrix m_con(2,2); m_con = 0.0;
|
||||
|
||||
M2inv.Mult(diag2, m_con);
|
||||
|
||||
DenseMatrix dg2dxm(num_dofs2, num_dofs2); dg2dxm = 0.0;
|
||||
|
||||
DenseMatrix dg2dxm_tmp(num_dofs2,2); dg2dxm_tmp = 0.0;
|
||||
MultAtB(Ndn, m_con, dg2dxm_tmp);
|
||||
Mult(dg2dxm_tmp, Ndn, dg2dxm);
|
||||
dg2dxm *= gap;
|
||||
|
||||
DenseMatrix dg2dxm_tmp2(num_dofs2,num_dofs2); dg2dxm_tmp2 = 0.0;
|
||||
MultAtB(Nndx2, dxidxm, dg2dxm_tmp2);
|
||||
dg2dxm.Add(-1.0, dg2dxm_tmp2);
|
||||
|
||||
dg2dxm_tmp = 0.0;
|
||||
MultAtB(dxidxm, nde2, dg2dxm_tmp);
|
||||
|
||||
AddMult_a(-1.0, dg2dxm_tmp, dxidxm, dg2dxm);
|
||||
|
||||
dg2dxm_tmp2 = 0.0;
|
||||
MultAtB(dxidxm, Nndx2, dg2dxm_tmp2);
|
||||
dg2dxm.Add(-1.0, dg2dxm_tmp2);
|
||||
|
||||
Vector v_dxidx2(4);
|
||||
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
|
||||
|
||||
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
|
||||
|
||||
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
|
||||
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
|
||||
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
|
||||
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
|
||||
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
|
||||
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
|
||||
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
|
||||
|
||||
DenseMatrix K_dxidx(2,2);
|
||||
K_dxidx -= M2;
|
||||
K_dxidx += K_dxidx2;
|
||||
|
||||
Vector drdxs_r(6);
|
||||
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
|
||||
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
|
||||
|
||||
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
drdxs_K(i,i) = K_dxidx(0,0);
|
||||
drdxs_K(i,3+i) = K_dxidx(0,1);
|
||||
drdxs_K(i+3,i) = K_dxidx(1,0);
|
||||
drdxs_K(i+3,i+3) = K_dxidx(1,1);
|
||||
}
|
||||
Vector dxidxs(6);
|
||||
|
||||
DenseMatrixInverse drdxsK_inv(drdxs_K);
|
||||
drdxsK_inv.Mult(drdxs_r,dxidxs);
|
||||
dxidxs *= -1.0;
|
||||
//dxidxs = -drdxs_K\drdxs_r;
|
||||
|
||||
DenseMatrix dxidxs_m(2,3); dxidxs_m = 0.0;
|
||||
dxidxs_m(0,0) = dxidxs[0]; dxidxs_m(0,1) = dxidxs[1]; dxidxs_m(0,2) = dxidxs[2];
|
||||
dxidxs_m(1,0) = dxidxs[3]; dxidxs_m(1,1) = dxidxs[4]; dxidxs_m(1,2) = dxidxs[5];
|
||||
|
||||
DenseMatrix dtao1dxs(3,3); dtao1dxs = 0.0;
|
||||
DenseMatrix dtao2dxs(3,3); dtao2dxs = 0.0;
|
||||
|
||||
Vector dxidxs_row1(3); dxidxs_row1 = 0.0; Vector dxidxs_row2(3);
|
||||
dxidxs_row2 = 0.0;
|
||||
Vector mdx2_row1(3); mdx2_row1 = 0.0; Vector mdx2_row2(3); mdx2_row2 = 0.0;
|
||||
Vector mdx2_row3(3); mdx2_row3 = 0.0;
|
||||
dxidxs_m.GetRow(0,dxidxs_row1);
|
||||
dxidxs_m.GetRow(1,dxidxs_row2);
|
||||
m_dx2.GetRow(0,mdx2_row1);
|
||||
m_dx2.GetRow(1,mdx2_row2);
|
||||
m_dx2.GetRow(2,mdx2_row3);
|
||||
|
||||
DenseMatrix dtaotmp(3,3); dtaotmp = 0.0;
|
||||
outer(mdx2_row1, dxidxs_row1,dtaotmp);
|
||||
dtao1dxs += dtaotmp; dtaotmp = 0.0;
|
||||
outer(mdx2_row2, dxidxs_row1,dtaotmp);
|
||||
dtao1dxs += dtaotmp; dtaotmp = 0.0;
|
||||
|
||||
outer(mdx2_row2, dxidxs_row2, dtaotmp);
|
||||
dtao2dxs += dtaotmp; dtaotmp = 0.0;
|
||||
outer(mdx2_row3, dxidxs_row2, dtaotmp);
|
||||
dtao2dxs += dtaotmp; dtaotmp = 0.0;
|
||||
|
||||
DenseMatrix dtaodxs(3,3); dtaodxs = 0.0; //tao = tao1 cross tao2
|
||||
|
||||
for (int d=0; d<3; d++)
|
||||
{
|
||||
Vector dtao1dxs_tmp(3); dtao1dxs_tmp = 0.0;
|
||||
dtao1dxs.GetColumn(d,dtao1dxs_tmp);
|
||||
Vector m_dxrow(3); m_dx.GetRow(1, m_dxrow);
|
||||
|
||||
Vector dtaodxs_tmp(3); dtaodxs_tmp = 0.0;
|
||||
cross(dtao1dxs_tmp, m_dxrow, dtaodxs_tmp);
|
||||
|
||||
Vector dtaodxs_tmp2(3); dtaodxs_tmp2 = 0.0;
|
||||
m_dx.GetRow(0, m_dxrow);
|
||||
dtao1dxs_tmp = 0.0; // reuse the same vector for dtao2
|
||||
dtao2dxs.GetColumn(d,dtao1dxs_tmp);
|
||||
cross(m_dxrow, dtao1dxs_tmp, dtaodxs_tmp2);
|
||||
|
||||
dtaodxs_tmp2 += dtaodxs_tmp;
|
||||
dtaodxs.SetCol(d, dtaodxs_tmp2);
|
||||
}
|
||||
|
||||
DenseMatrix dndxs(3,3); dndxs = 0.0; dndxs += dtaodxs; dndxs *= 1.0/nnorm;
|
||||
DenseMatrix dndxs_tmp(3,3); dndxs_tmp = 0.0;
|
||||
outer(normal, normal, dndxs_tmp);
|
||||
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxs, dndxs);
|
||||
|
||||
DenseMatrix dgvdxs(3,3); dgvdxs = 0.0;
|
||||
MultAtB(m_dx, dxidxs_m, dgvdxs);
|
||||
dgvdxs *= -1;
|
||||
for (int d=0; d<3; d++)
|
||||
{
|
||||
dgvdxs(d,d) += 1.0;
|
||||
}
|
||||
//dxidxs: 2*3
|
||||
|
||||
DenseMatrix dg2dxs(3,3); dg2dxs = 0.0;
|
||||
DenseMatrix dg2dxs_tmp(3,2); dg2dxs_tmp = 0.0;
|
||||
MultAtB(dxidxs_m, nde2, dg2dxs_tmp);
|
||||
AddMult_a(-1.0, dg2dxs_tmp, dxidxs_m, dg2dxs);
|
||||
DenseMatrix dg2dxs_tmp2(3,3); dg2dxs_tmp2 = 0.0;
|
||||
MultAtB(dgvdxs, dndxs, dg2dxs_tmp2);
|
||||
dg2dxs += dg2dxs_tmp2;
|
||||
dg2dxs_tmp2 = 0.0;
|
||||
MultAtB(dndxs, dndxs_tmp, dg2dxs_tmp2);
|
||||
AddMult(dg2dxs_tmp2, dgvdxs, dg2dxs);
|
||||
|
||||
DenseMatrix Ne(3,12), Be(6,12), dBe(12,12);
|
||||
BasisVectorDerivs(xi, Ne, Be, dBe);
|
||||
|
||||
DenseMatrix dtao1dxm(3,12); dtao1dxm.CopyRows(Be, 0, 2);
|
||||
DenseMatrix dtao2dxm(3,12); dtao2dxm.CopyRows(Be, 3, 5);
|
||||
|
||||
Vector m_coords_v(12);
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
for (int j=0; j<3; j++)
|
||||
{
|
||||
m_coords_v[i*3+j] = m_coords(i,j);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<2; i++)
|
||||
{
|
||||
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
|
||||
dxidxm.GetRow(i,dxidxm_tmp);
|
||||
|
||||
DenseMatrix dBe_tmp(3,12);
|
||||
dBe_tmp.CopyRows(dBe,i*3,(i+1)*3-1);
|
||||
|
||||
DenseMatrix dtaodxm_tmp(12,12); dtaodxm_tmp = 0.0;
|
||||
outer(m_coords_v, dxidxm_tmp, dtaodxm_tmp);
|
||||
AddMult(dBe_tmp, dtaodxm_tmp, dtao1dxm);
|
||||
|
||||
//dtao1dxm += dBe(:,:,i)*reshape(m_coords(1:4,:)',12,1)*reshape(dxidxm(i,:),1,12); % 3*12
|
||||
dBe_tmp = 0.0;
|
||||
dBe_tmp.CopyRows(dBe,(i+2)*3,(i+3)*3-1);
|
||||
AddMult(dBe_tmp, dtaodxm_tmp, dtao2dxm);
|
||||
|
||||
}
|
||||
|
||||
DenseMatrix dtaodxm(3,12); dtaodxm = 0.0;//tao = tao1 cross tao2
|
||||
|
||||
for (int d=0; d<12; d++)
|
||||
{
|
||||
Vector dtaodxm_tmp(3); dtaodxm_tmp = 0.0;
|
||||
Vector dtaodxm_tmp2(3); dtaodxm_tmp2 = 0.0;
|
||||
Vector tmp1(3); tmp1 = 0.0; dtao1dxm.GetColumn(d,tmp1);
|
||||
Vector m_dxrow2(3); m_dx.GetRow(1, m_dxrow2);
|
||||
Vector m_dxrow1(3); m_dx.GetRow(0, m_dxrow1);
|
||||
Vector tmp2(3); tmp2 = 0.0; dtao2dxm.GetColumn(d,tmp2);
|
||||
|
||||
cross(tmp1, m_dxrow2, dtaodxm_tmp);
|
||||
cross(m_dxrow1,tmp2, dtaodxm_tmp2);
|
||||
dtaodxm_tmp += dtaodxm_tmp2;
|
||||
|
||||
dtaodxm.SetCol(d, dtaodxm_tmp);
|
||||
}
|
||||
|
||||
DenseMatrix dndxm(3,12); dndxm = 0.0;
|
||||
dndxm += dtaodxm;
|
||||
dndxm *= 1.0/nnorm;
|
||||
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxm, dndxm); //dndxs_tmp = normal'*normal
|
||||
|
||||
DenseMatrix dgvdxm(3,12); dgvdxm = 0.0;
|
||||
dgvdxm -= Ne;
|
||||
|
||||
for (int i=0; i<2; i++)
|
||||
{
|
||||
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
|
||||
dxidxm.GetRow(i,dxidxm_tmp);
|
||||
|
||||
DenseMatrix Be_tmp(3,12);
|
||||
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
|
||||
|
||||
DenseMatrix dgvdxm_tmp(12,12); dgvdxm_tmp = 0.0;
|
||||
outer(m_coords_v, dxidxm_tmp, dgvdxm_tmp);
|
||||
AddMult_a(-1.0, Be_tmp, dgvdxm_tmp, dgvdxm);
|
||||
|
||||
}
|
||||
|
||||
DenseMatrix dg2dxsxm(3,12); dg2dxsxm = 0.0;
|
||||
DenseMatrix dg2dxsxm_tmp(3,3); dg2dxsxm_tmp = 0.0;
|
||||
MultAtB(dgvdxs, dndxm, dg2dxsxm);
|
||||
|
||||
MultAtB(dndxs, dndxs_tmp, dg2dxsxm_tmp);
|
||||
AddMult(dg2dxsxm_tmp, dgvdxm, dg2dxsxm); // += dndxs'*normal'*normal*dgvdxm;
|
||||
|
||||
DenseMatrix dgvdxsxmn(3,12); dgvdxsxmn = 0.0;
|
||||
DenseMatrix dgvdxsxmn_tmp(3,2); dgvdxsxmn_tmp = 0.0;
|
||||
MultAtB(dxidxs_m, nde2, dgvdxsxmn_tmp); //dxidxs_m: 2*3
|
||||
|
||||
AddMult_a(-1.0, dgvdxsxmn_tmp, dxidxm, dgvdxsxmn);
|
||||
|
||||
|
||||
for (int i =0; i<2; i++)
|
||||
{
|
||||
DenseMatrix Be_tmp(3,12);
|
||||
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
|
||||
|
||||
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
|
||||
DenseMatrix dgvdxsxmn_tmp2(3,3); dgvdxsxmn_tmp2 = 0.0;
|
||||
outer(dxidxs_row, normal, dgvdxsxmn_tmp2);
|
||||
AddMult_a(-1.0, dgvdxsxmn_tmp2, Be_tmp, dgvdxsxmn);
|
||||
}
|
||||
|
||||
dg2dxsxm += dgvdxsxmn;
|
||||
|
||||
DenseMatrix dg2dxmxs(12,3); dg2dxmxs = 0.0;
|
||||
DenseMatrix dg2dxmxs_tmp(12,3); dg2dxmxs_tmp = 0.0;
|
||||
MultAtB(dgvdxm, dndxs, dg2dxmxs);
|
||||
MultAtB(dndxm, dndxs_tmp, dg2dxmxs_tmp);
|
||||
AddMult(dg2dxmxs_tmp, dgvdxs, dg2dxmxs);
|
||||
|
||||
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
|
||||
DenseMatrix dgvdxmxsn_tmp(12,2); dgvdxmxsn_tmp = 0.0;
|
||||
|
||||
MultAtB(dxidxm, nde2, dgvdxmxsn_tmp);
|
||||
dgvdxmxsn_tmp *= -1.0;
|
||||
AddMult(dgvdxmxsn_tmp, dxidxs_m, dgvdxmxsn);
|
||||
|
||||
for (int i =0; i<2; i++)
|
||||
{
|
||||
DenseMatrix Be_tmp(3,12);
|
||||
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
|
||||
Be_tmp.Transpose(); // Be is now 12*3
|
||||
|
||||
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
|
||||
DenseMatrix dgvdxmxsn_tmp2(3,3); dgvdxmxsn_tmp2 = 0.0;
|
||||
outer(normal, dxidxs_row, dgvdxmxsn_tmp2);
|
||||
AddMult_a(-1.0, Be_tmp, dgvdxmxsn_tmp2, dgvdxmxsn);
|
||||
|
||||
}
|
||||
|
||||
dg2dxmxs += dgvdxmxsn;
|
||||
|
||||
dg2dx.CopyMN(dg2dxs, 0, 0);
|
||||
dg2dx.CopyMN(dg2dxm, 3, 3);
|
||||
dg2dx.CopyMN(dg2dxsxm, 0, 3);
|
||||
dg2dx.CopyMN(dg2dxmxs, 3, 0);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
void NodeSegConPairs(const Vector x1, const Vector xi2,
|
||||
const DenseMatrix coords2,
|
||||
double& node_g, Vector& node_dg, DenseMatrix& node_dg2)
|
||||
{
|
||||
double gap = 0.0;
|
||||
Vector normal(3); normal = 0.0;
|
||||
Vector dgdxm(12); dgdxm = 0.0;
|
||||
Vector dgdxs(3); dgdxs = 0.0;
|
||||
|
||||
ComputeGapJacobian(x1, xi2, coords2, gap, normal, dgdxm, dgdxs);
|
||||
node_g = gap;
|
||||
|
||||
node_dg.SetSize(12+3);
|
||||
for (int i=0; i<3; i++) { node_dg[i] = dgdxs[i]; }
|
||||
for (int i=0; i<12; i++) { node_dg[i+3] = dgdxm[i]; }
|
||||
|
||||
DenseMatrix dg2dx(15,15); dg2dx = 0.0;
|
||||
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
|
||||
ComputeGapHessian(x1, xi2, coords2, dg2dx);
|
||||
|
||||
node_dg2.SetSize(15,15);
|
||||
node_dg2 = dg2dx;
|
||||
|
||||
/*
|
||||
if(obj.space1.conns{e1}(i)==150) % for debugging purpose
|
||||
|
||||
v1 = 1:3;
|
||||
v2 = 1:12;
|
||||
%v1 = ones(1,3)
|
||||
%v2 = ones(1,12)
|
||||
v2 = reshape(v2,4,3);
|
||||
x1n1 = x1 + 0.01*v1;
|
||||
coords2n1 = coords2 + 0.001*v2;
|
||||
[xi2n1, gapv1, ~, ~] = SlaveToMaster(obj, coords2n1, x1n1);
|
||||
[gapn1, n1,dgdxmn1, dgdxsn1] = ComputeGapJacobian(obj, x1n1, xi2n1, coords2n1);
|
||||
x1n2 = x1 - 0.01*v1;
|
||||
coords2n2 = coords2 - 0.001*v2;
|
||||
[xi2n2, gapv2, ~, ~] = SlaveToMaster(obj, coords2n2, x1n2);
|
||||
[gapn2, n2,dgdxmn2, dgdxsn2] = ComputeGapJacobian(obj, x1n2, xi2n2, coords2n2);
|
||||
fprintf('fd\n');
|
||||
%gapv1-gapv2
|
||||
[dgdxsn1(:)',dgdxmn1(:)'] - [dgdxsn2(:)',dgdxmn2(:)']
|
||||
|
||||
%dgdxsn1-dgdxsn2
|
||||
fprintf('code\n');
|
||||
v2n = v2';
|
||||
%dg2dx(1:3,1:3)*0.04*ones(3,1)
|
||||
temp = zeros(12,3);
|
||||
for i = 1:4
|
||||
temp1 = dg2dx(3+(i-1)*3+1:3+i*3,1:3);
|
||||
temp((i-1)*3+1:i*3,:) = temp1';
|
||||
end
|
||||
temp2 = zeros(3,12);
|
||||
for i = 1:4
|
||||
temp3 = dg2dx(1:3,3+(i-1)*3+1:3+i*3);
|
||||
temp2(:,(i-1)*3+1:i*3) = temp3';
|
||||
end
|
||||
%dg2dx
|
||||
%dg2dx(4:end,1:3) = temp;
|
||||
%dg2dx(1:3,4:end) = temp2;
|
||||
%dgvdxm * 0.002*v2n(:)
|
||||
(dg2dx*[0.02*v1(:)',0.002*v2n(:)']')'
|
||||
%dg2dx(4:end,1:3)
|
||||
end*/
|
||||
|
||||
};
|
||||
|
||||
|
||||
// coordsm : (npoints*4, 3) use what class?
|
||||
// m_conn: (npoints*4)
|
||||
void Assemble_Contact(const int m, const int npoints, const int ndofs,
|
||||
const Vector x_s,
|
||||
const Vector xi, const DenseMatrix coordsm, const Array<int> s_conn,
|
||||
const Array<int> m_conn, Vector& g, SparseMatrix& M,
|
||||
std::vector<SparseMatrix>& dM)
|
||||
{
|
||||
int n = ndofs;
|
||||
int ndim = 3;
|
||||
|
||||
g.SetSize(m);
|
||||
g = 0.0;
|
||||
|
||||
//SparseMatrix M(m, n); // M needs to be the correct size
|
||||
|
||||
//dM.resize(m); // needs to clear?
|
||||
|
||||
double g_tmp = 0.;
|
||||
Vector dg(4*ndim+ndim);
|
||||
dg = 0.;
|
||||
DenseMatrix dg2(4*ndim+ndim,4*ndim+ndim);
|
||||
dg2 = 0.;
|
||||
|
||||
for (int i=0; i<npoints; i++)
|
||||
{
|
||||
Vector x1(ndim);
|
||||
x1[0] = x_s[i*ndim];
|
||||
x1[1] = x_s[i*ndim+1];
|
||||
x1[2] = x_s[i*ndim+2];
|
||||
|
||||
Vector xi2(ndim-1);
|
||||
xi2[0] = xi[i*(ndim-1)];
|
||||
xi2[1] = xi[i*(ndim-1)+1];
|
||||
|
||||
DenseMatrix coords2(4,3);
|
||||
coords2.CopyRows(coordsm, i*4,(i+1)*4-1);
|
||||
|
||||
//how to get coords2?
|
||||
dg = 0.0;
|
||||
dg2 = 0.;
|
||||
NodeSegConPairs(x1, xi2, coords2, g_tmp, dg, dg2);
|
||||
//x1.Print();
|
||||
//xi2.Print();
|
||||
//coords2.Print();
|
||||
g[s_conn[i]] = g_tmp; // should be unique
|
||||
Array<int> m_conn_i(4);
|
||||
m_conn.GetSubArray(4*i, 4, m_conn_i);
|
||||
|
||||
Array<int> node_conn(5);
|
||||
node_conn[0] = s_conn[i];
|
||||
for (int j=0; j<4; j++)
|
||||
{
|
||||
node_conn[j+1] = m_conn_i[j];
|
||||
}
|
||||
|
||||
Array<int> M_i_tmp(1);
|
||||
M_i_tmp[0] = s_conn[i];
|
||||
|
||||
//j_idx = (node_conn-1)*obj.disp_field.num_components +repmat((1:obj.disp_field.num_components)', 1, length(node_conn{i}));
|
||||
Array<int> j_idx(5*ndim); j_idx = 0;
|
||||
for (int j=0; j< 5; j++)
|
||||
{
|
||||
for (int k=0; k<ndim; k++)
|
||||
{
|
||||
j_idx[j*ndim+k] = node_conn[j]*ndim+k;
|
||||
}
|
||||
}
|
||||
DenseMatrix M_v_tmp(1, ndim*(4+1)); // SetData now?
|
||||
M_v_tmp.SetRow(0, dg);
|
||||
|
||||
M.AddSubMatrix(M_i_tmp, j_idx, M_v_tmp);
|
||||
|
||||
Array<int> dM_i(ndim*(4+1));
|
||||
Array<int> dM_j(ndim*(4+1));
|
||||
|
||||
for (int j=0; j< ndim*(4+1); j++)
|
||||
{
|
||||
dM_i[j] = j_idx[j];
|
||||
dM_j[j] = j_idx[j];
|
||||
}
|
||||
//dg2.Print();
|
||||
//dM[s_conn[i]].Print();
|
||||
dM[s_conn[i]].AddSubMatrix(dM_i,dM_j, dg2);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -46,6 +46,9 @@ endif
|
||||
ifeq ($(MFEM_USE_HIOP),YES)
|
||||
SUBDIRS += hiop
|
||||
endif
|
||||
ifeq ($(MFEM_USE_IPOPT),YES)
|
||||
SUBDIRS += ipopt
|
||||
endif
|
||||
ifeq ($(MFEM_USE_PETSC),YES)
|
||||
SUBDIRS += petsc
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,888 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
void BasisEval(const Vector xi, Vector &N, DenseMatrix &dNdxi) // dNdxi is 2*4
|
||||
{
|
||||
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
|
||||
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
|
||||
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
|
||||
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
|
||||
|
||||
dNdxi(0,0) = 0.25*(-1+xi[1]);
|
||||
dNdxi(0,1) = 0.25*(1-xi[1]);
|
||||
dNdxi(0,2) = 0.25*(1+xi[1]);
|
||||
dNdxi(0,3) = 0.25*(-1-xi[1]);
|
||||
dNdxi(1,0) = 0.25*(-1+xi[0]);
|
||||
dNdxi(1,1) = 0.25*(-1-xi[0]);
|
||||
dNdxi(1,2) = 0.25*(1+xi[0]);
|
||||
dNdxi(1,3) = 0.25*(1-xi[0]);
|
||||
}
|
||||
|
||||
|
||||
void BasisEvalDerivs(const Vector xi, Vector& N, DenseMatrix& dNdxi,
|
||||
DenseMatrix& dN2dxi)
|
||||
{
|
||||
N[0] = 0.25*(1-xi[0])*(1-xi[1]);
|
||||
N[1] = 0.25*(1+xi[0])*(1-xi[1]);
|
||||
N[2] = 0.25*(1+xi[0])*(1+xi[1]);
|
||||
N[3] = 0.25*(1-xi[0])*(1+xi[1]);
|
||||
|
||||
dNdxi.SetSize(2,4); dNdxi = 0.0;
|
||||
dN2dxi.SetSize(3,4);
|
||||
dN2dxi = 0.0; // first row dxi2, second detadxi, third deta2
|
||||
|
||||
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,1) = 0.25*(1-xi[1]);
|
||||
dNdxi(0,2) = 0.25*(1+xi[1]); dNdxi(0,3) = 0.25*(-1-xi[1]);
|
||||
dNdxi(1,0) = 0.25*(-1+xi[0]); dNdxi(1,1) = 0.25*(-1-xi[0]);
|
||||
dNdxi(1,2) = 0.25*(1+xi[0]); dNdxi(1,3) = 0.25*(1-xi[0]);
|
||||
|
||||
dN2dxi(1,0) = 0.25; dN2dxi(1,1) = -0.25; dN2dxi(1,2) = 0.25;
|
||||
dN2dxi(1,3) = -0.25;
|
||||
}
|
||||
|
||||
// returns the vector and matrix form of the shape functions and its derivative
|
||||
void BasisVectorDerivs(const Vector xi, DenseMatrix& N, DenseMatrix& dNdxi,
|
||||
DenseMatrix& ddNdxi)
|
||||
{
|
||||
N.SetSize(3,12); N = 0.0;
|
||||
N(0,0) = 0.25*(1-xi[0])*(1-xi[1]); N(0,3) = 0.25*(1+xi[0])*(1-xi[1]);
|
||||
N(0,6) = 0.25*(1+xi[0])*(1+xi[1]); N(0,9) = 0.25*(1-xi[0])*(1+xi[1]);
|
||||
|
||||
N(1,1) = 0.25*(1-xi[0])*(1-xi[1]); N(1,4) = 0.25*(1+xi[0])*(1-xi[1]);
|
||||
N(1,7) = 0.25*(1+xi[0])*(1+xi[1]); N(1,10) = 0.25*(1-xi[0])*(1+xi[1]);
|
||||
|
||||
N(2,2) = 0.25*(1-xi[0])*(1-xi[1]); N(2,5) = 0.25*(1+xi[0])*(1-xi[1]);
|
||||
N(2,8) = 0.25*(1+xi[0])*(1+xi[1]); N(2,11) = 0.25*(1-xi[0])*(1+xi[1]);
|
||||
|
||||
dNdxi.SetSize(3*2, 3*4); dNdxi = 0.0;
|
||||
dNdxi(0,0) = 0.25*(-1+xi[1]); dNdxi(0,3) = 0.25*(1-xi[1]);
|
||||
dNdxi(0,6) = 0.25*(1+xi[1]); dNdxi(0,9) = 0.25*(-1-xi[1]);
|
||||
dNdxi(1,1) = 0.25*(-1+xi[1]); dNdxi(1,4) = 0.25*(1-xi[1]);
|
||||
dNdxi(1,7) = 0.25*(1+xi[1]); dNdxi(1,10) = 0.25*(-1-xi[1]);
|
||||
dNdxi(2,2) = 0.25*(-1+xi[1]); dNdxi(2,5) = 0.25*(1-xi[1]);
|
||||
dNdxi(2,8) = 0.25*(1+xi[1]); dNdxi(2,11) = 0.25*(-1-xi[1]);
|
||||
|
||||
dNdxi(3,0) = 0.25*(-1+xi[0]); dNdxi(3,3) = 0.25*(-1-xi[0]);
|
||||
dNdxi(3,6) = 0.25*(1+xi[0]); dNdxi(3,9) = 0.25*(1-xi[0]);
|
||||
dNdxi(4,1) = 0.25*(-1+xi[0]); dNdxi(4,4) = 0.25*(-1-xi[0]);
|
||||
dNdxi(4,7) = 0.25*(1+xi[0]); dNdxi(4,10) = 0.25*(1-xi[0]);
|
||||
dNdxi(5,2) = 0.25*(-1+xi[0]); dNdxi(5,5) = 0.25*(-1-xi[0]);
|
||||
dNdxi(5,8) = 0.25*(1+xi[0]); dNdxi(5,11) = 0.25*(1-xi[0]);
|
||||
|
||||
ddNdxi.SetSize(3*4, 3*4); ddNdxi = 0.0;
|
||||
ddNdxi(3,0) = 0.25; ddNdxi(3,3) = -0.25;
|
||||
ddNdxi(3,6) = 0.25; ddNdxi(3,9) = -0.25;
|
||||
ddNdxi(4,1) = 0.25; ddNdxi(4,4) = -0.25;
|
||||
ddNdxi(4,7) = 0.25; ddNdxi(4,10) = -0.25;
|
||||
ddNdxi(5,2) = 0.25; ddNdxi(5,5) = -0.25;
|
||||
ddNdxi(5,8) = 0.25; ddNdxi(5,11) = -0.25;
|
||||
|
||||
ddNdxi(6,0) = 0.25; ddNdxi(6,3) = -0.25;
|
||||
ddNdxi(6,6) = 0.25; ddNdxi(6,9) = -0.25;
|
||||
ddNdxi(7,1) = 0.25; ddNdxi(7,4) = -0.25;
|
||||
ddNdxi(7,7) = 0.25; ddNdxi(7,10) = -0.25;
|
||||
ddNdxi(8,2) = 0.25; ddNdxi(8,5) = -0.25;
|
||||
ddNdxi(8,8) = 0.25; ddNdxi(8,11) = -0.25;
|
||||
}
|
||||
|
||||
|
||||
void cross(const Vector a, const Vector b, Vector& c)
|
||||
{
|
||||
assert(a.Size()==3);
|
||||
c.SetSize(3);
|
||||
c[0] = a[1]*b[2] - a[2]*b[1];
|
||||
c[1] = -a[0]*b[2] + b[0]*a[2];
|
||||
c[2] = a[0]*b[1] - a[1]*b[0];
|
||||
|
||||
}
|
||||
// a outer b
|
||||
void outer(const Vector a, const Vector b, DenseMatrix& c)
|
||||
{
|
||||
int m = a.Size();
|
||||
int n = b.Size();
|
||||
assert(c.Height()==m);
|
||||
assert(c.Width() ==n);
|
||||
for (int i=0; i<m; i++)
|
||||
{
|
||||
for (int j=0; j<n; j++)
|
||||
{
|
||||
c(i,j) = a[i]*b[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
// dphidxi 2*4
|
||||
// coords 4*3
|
||||
void ComputeNormal(const DenseMatrix& dphidxi, const DenseMatrix& coords,
|
||||
Vector& normal, double& nnorm)
|
||||
{
|
||||
|
||||
DenseMatrix dxdxi(2,3);
|
||||
Mult(dphidxi, coords, dxdxi);
|
||||
Vector dxdxi1(3);
|
||||
Vector dxdxi2(3);
|
||||
|
||||
dxdxi.GetRow(0,dxdxi1);
|
||||
dxdxi.GetRow(1,dxdxi2);
|
||||
|
||||
cross(dxdxi1, dxdxi2, normal); // is there a cross product? no
|
||||
// VectorCrossProductCoefficient::Eval has hard-coded cross product
|
||||
nnorm = normal.Norml2( );
|
||||
normal /= nnorm;
|
||||
}
|
||||
|
||||
void SlaveToMaster(const DenseMatrix& m_coords, const Vector& s_x, Vector& xi)
|
||||
{
|
||||
bool converged = false;
|
||||
bool pt_on_elem = false;
|
||||
int dim = 3;
|
||||
xi.SetSize(dim-1);
|
||||
xi = 0.0;
|
||||
double r = 1e10;
|
||||
int max_iter = 15;
|
||||
double off_el_xi = 1e-2;
|
||||
double proj_newton_tol = 1e-13;
|
||||
double proj_max_gap = 0.5;
|
||||
Vector gap_v(dim);
|
||||
// warm start from linear solution
|
||||
|
||||
for (int it=0; it<max_iter; it++)
|
||||
{
|
||||
//cout<<it<<endl;
|
||||
Vector m_N(4);
|
||||
m_N = 0.;
|
||||
DenseMatrix m_dN(2,4);
|
||||
m_dN = 0.;
|
||||
DenseMatrix m_dN2(3,4);
|
||||
m_dN2 = 0.;
|
||||
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
|
||||
|
||||
Vector x_c(dim);
|
||||
m_coords.MultTranspose(m_N, x_c);
|
||||
|
||||
gap_v = s_x;
|
||||
gap_v -= x_c;
|
||||
|
||||
DenseMatrix m_dx(2,3);
|
||||
m_dx = 0.;
|
||||
Mult(m_dN, m_coords, m_dx);
|
||||
|
||||
Vector r(dim-1);
|
||||
r = 0.0;
|
||||
m_dx.Mult(gap_v, r);
|
||||
|
||||
if (r.Normlinf() < proj_newton_tol)
|
||||
{
|
||||
converged = true;
|
||||
break;
|
||||
}
|
||||
|
||||
DenseMatrix drdxi(dim-1,dim-1);
|
||||
drdxi = 0.;
|
||||
MultABt(m_dx, m_dx, drdxi); // m_dx * m_dx.T
|
||||
drdxi *= -1.0;
|
||||
|
||||
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
|
||||
Mult(m_dN2,m_coords, m_dx2);
|
||||
|
||||
//m_d2x = m_dN(:,:,2) * m_elem_coords(1:4,:); //m_dN(:,:,2) is 3*4
|
||||
for (int d=0; d<3; d++)
|
||||
{
|
||||
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
|
||||
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
|
||||
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
|
||||
|
||||
drdxi.Add(gap_v[d], Mtemp);
|
||||
}
|
||||
|
||||
//cond_num = rcond(drdxi); condition number?
|
||||
//drdxi.TestInversion();
|
||||
DenseMatrixInverse drdxi_inv(drdxi);
|
||||
Vector xi_tmp(dim-1);
|
||||
|
||||
drdxi_inv.Mult(r,xi_tmp);
|
||||
xi -= xi_tmp;
|
||||
}
|
||||
if (!converged)
|
||||
{
|
||||
xi = 0.0;
|
||||
}
|
||||
off_el_xi += 1 ; // tolerance of offset of xi outside [-1,1]
|
||||
|
||||
//cout<<gap_v.Norml2()<<" " <<xi.Normlinf()<<endl;
|
||||
if (gap_v.Norml2() < proj_max_gap && xi.Normlinf() <= off_el_xi)
|
||||
{
|
||||
pt_on_elem = true;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(pt_on_elem == true, "xi went out of bounds");
|
||||
MFEM_VERIFY(converged == true, "projection didn't converge");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// m_coords is expected to be 4 * 3
|
||||
void ComputeGapJacobian(const Vector x_s, const Vector xi,
|
||||
const DenseMatrix m_coords,
|
||||
double& gap, Vector& normal, Vector& dgdxm, Vector& dgdxs)
|
||||
{
|
||||
Vector m_N(4);
|
||||
DenseMatrix m_dN(2,4);
|
||||
DenseMatrix m_dN2(3,4);
|
||||
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
|
||||
|
||||
Vector x_c(3);
|
||||
m_coords.MultTranspose(m_N, x_c);
|
||||
|
||||
Vector gap_v(3); gap_v = 0.0;
|
||||
gap_v = x_s;
|
||||
gap_v -= x_c;
|
||||
|
||||
DenseMatrix m_dx(2,3);
|
||||
Mult(m_dN, m_coords, m_dx);
|
||||
|
||||
double nnorm = 0;
|
||||
ComputeNormal(m_dN, m_coords, normal, nnorm);
|
||||
|
||||
gap = gap_v * normal; // gap function value, dot product between vectors
|
||||
|
||||
//dr_dx = zeros(2,4,3); % nsegment, nodes in quad, ndim
|
||||
|
||||
DenseMatrix dr_dx_res1(4,3); dr_dx_res1 = 0.;
|
||||
DenseMatrix dr_dx_res2(4,3); dr_dx_res2 = 0.;
|
||||
|
||||
Vector m_dxrow1(3);
|
||||
m_dx.GetRow(0, m_dxrow1);
|
||||
outer(m_N, m_dxrow1, dr_dx_res1);// 4*1 times 1*3
|
||||
dr_dx_res1 *= -1.0;
|
||||
|
||||
Vector m_dxrow2(3);
|
||||
m_dx.GetRow(1, m_dxrow2);
|
||||
outer(m_N, m_dxrow2, dr_dx_res2);// 4*1 times 1*3
|
||||
dr_dx_res2 *= -1.0;
|
||||
|
||||
Vector m_dNrow1(4); m_dN.GetRow(0, m_dNrow1);
|
||||
Vector m_dNrow2(4); m_dN.GetRow(1, m_dNrow2);
|
||||
|
||||
DenseMatrix dr_dx_res1_tmp(4,3); dr_dx_res1_tmp = 0.;
|
||||
DenseMatrix dr_dx_res2_tmp(4,3); dr_dx_res2_tmp = 0.;
|
||||
outer(m_dNrow1, gap_v, dr_dx_res1_tmp);// 4*1 times 1*3
|
||||
outer(m_dNrow2, gap_v, dr_dx_res2_tmp);// 4*1 times 1*3
|
||||
|
||||
dr_dx_res1 += dr_dx_res1_tmp; // outer product in vector?
|
||||
dr_dx_res2 += dr_dx_res2_tmp;
|
||||
|
||||
|
||||
DenseMatrix K_dxidx1(2,2); // 2*2
|
||||
K_dxidx1 = 0.;
|
||||
MultABt(m_dx, m_dx, K_dxidx1); // m_dx * m_dx.T
|
||||
|
||||
Vector v_dxidx2(4);
|
||||
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
|
||||
|
||||
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
|
||||
|
||||
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
|
||||
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
|
||||
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
|
||||
// how to get 2nd order? multidimensional matrix?
|
||||
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
|
||||
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
|
||||
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
|
||||
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
|
||||
|
||||
DenseMatrix K_dxidx(2,2);
|
||||
K_dxidx -= K_dxidx1;
|
||||
K_dxidx += K_dxidx2;
|
||||
|
||||
// resize the vectors and matrices
|
||||
Vector dxidx(24); dxidx = 0.0;
|
||||
Vector drdx_r(24); drdx_r = 0.0;
|
||||
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
for (int j=0; j<3; j++)
|
||||
{
|
||||
drdx_r[4*j+i] = dr_dx_res1(i,j);
|
||||
drdx_r[4*j+i+12] = dr_dx_res2(i,j);
|
||||
|
||||
}
|
||||
}
|
||||
//drdx_r(1:4*3,1) = reshape(dr_dx_res(:,:,1),4*3,1);
|
||||
//drdx_r(4*3+1:2*4*3,1) = reshape(dr_dx_res(:,:,2),4*3,1);
|
||||
DenseMatrix drdx_K(24,24); drdx_K = 0.;
|
||||
for (int i =0; i<12; i++)
|
||||
{
|
||||
drdx_K(i,i) = K_dxidx(0,0);
|
||||
drdx_K(i,12+i) = K_dxidx(0,1);
|
||||
drdx_K(12+i,i) = K_dxidx(1,0);
|
||||
drdx_K(12+i,12+i) = K_dxidx(1,1);
|
||||
}
|
||||
|
||||
DenseMatrixInverse drdxK_inv(drdx_K);
|
||||
drdxK_inv.Mult(drdx_r,dxidx);
|
||||
// LinearSolve (drdx_K,drdx_r, dxidx) ; //???
|
||||
dxidx *= -1.0;
|
||||
|
||||
|
||||
|
||||
Vector drdxs_r(6);
|
||||
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
|
||||
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
|
||||
|
||||
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
drdxs_K(i,i) = K_dxidx(0,0);
|
||||
drdxs_K(i,3+i) = K_dxidx(0,1);
|
||||
drdxs_K(i+3,i) = K_dxidx(1,0);
|
||||
drdxs_K(i+3,i+3) = K_dxidx(1,1);
|
||||
}
|
||||
|
||||
Vector dxidxs(6); dxidxs = 0.0;
|
||||
DenseMatrixInverse drdxsK_inv(drdxs_K);
|
||||
drdxsK_inv.Mult(drdxs_r,dxidxs);
|
||||
dxidxs *= -1.0;
|
||||
//dxidxs = -drdxs_K\drdxs_r;
|
||||
|
||||
//dxidx = reshape(dxidx, 4,3,2); dxidxs = reshape(dxidxs, 1,3,2);
|
||||
|
||||
dgdxm.SetSize(12); dgdxm = 0.;
|
||||
DenseMatrix dgdxm_tmp(4,3);
|
||||
outer(m_N, normal,dgdxm_tmp);
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
for (int j=0; j<3; j++)
|
||||
{
|
||||
dgdxm[3*i+j] = -dgdxm_tmp(i,j);
|
||||
}
|
||||
}
|
||||
//dxidx_M = -m_dN(1:2,:,1) * (m_coords(1:4,:)*normal'); % this turns out to be 0
|
||||
|
||||
dgdxs.SetSize(3);
|
||||
dgdxs += normal;
|
||||
//dgdxs = dgdxs + dxidx_M(1) * dxidxs(:,:,1) + dxidx_M(2) * dxidxs(:,:,2);
|
||||
};
|
||||
|
||||
void ComputeGapHessian(const Vector x_s, const Vector xi,
|
||||
const DenseMatrix m_coords,
|
||||
DenseMatrix& dg2dx)
|
||||
{
|
||||
Vector m_N(4);
|
||||
DenseMatrix m_dN(2,4);
|
||||
DenseMatrix m_dN2(3,4);
|
||||
BasisEvalDerivs(xi, m_N, m_dN, m_dN2);
|
||||
|
||||
int dim = 3;
|
||||
int num_dofs1 = dim;
|
||||
int num_dofs2 = 4*dim;
|
||||
int num_dofs = num_dofs1 + num_dofs2;
|
||||
dg2dx.SetSize(num_dofs,num_dofs); dg2dx = 0.0;
|
||||
|
||||
Vector x_c(3);
|
||||
m_coords.MultTranspose(m_N,x_c);
|
||||
|
||||
Vector gap_v(3); gap_v = 0.0;
|
||||
gap_v = x_s;
|
||||
gap_v -= x_c;
|
||||
|
||||
DenseMatrix m_dx(2,3);
|
||||
Mult(m_dN, m_coords, m_dx);
|
||||
|
||||
DenseMatrix m_dx2(3,3); m_dx2 = 0.0;
|
||||
Mult(m_dN2,m_coords, m_dx2);
|
||||
double nnorm = 0.0;
|
||||
Vector normal(3); normal = 0.0;
|
||||
ComputeNormal(m_dN, m_coords, normal, nnorm);
|
||||
|
||||
double gap = gap_v * normal; // gap function value, dot product between vectors
|
||||
|
||||
DenseMatrix M(2,2); M = 0.0;
|
||||
MultABt(m_dx, m_dx, M);
|
||||
|
||||
DenseMatrix f(2, num_dofs2); f = 0.0;
|
||||
|
||||
for (int d=0; d<3; d++)
|
||||
{
|
||||
DenseMatrix Mtemp(2,2); Mtemp = 0.0;
|
||||
Mtemp(0,0) = m_dx2(0,d); Mtemp(0,1) = m_dx2(1,d);
|
||||
Mtemp(1,0) = m_dx2(1,d); Mtemp(1,1) = m_dx2(2,d);
|
||||
|
||||
M.Add(-gap_v[d], Mtemp);
|
||||
|
||||
Vector m_dxcol(2); m_dx.GetColumn(d, m_dxcol);
|
||||
DenseMatrix ftmp(2,4);
|
||||
outer(m_dxcol, m_N, ftmp);
|
||||
ftmp *= -1;
|
||||
ftmp.Add( gap_v[d], m_dN); // 2*4
|
||||
|
||||
for (int j=0; j<4; j++)
|
||||
{
|
||||
assert(d+3*j<num_dofs2);
|
||||
f(0,d+j*3) = ftmp(0,j);
|
||||
f(1,d+j*3) = ftmp(1,j);
|
||||
}
|
||||
}
|
||||
//fprintf('hess dxidxm\n');
|
||||
DenseMatrixInverse Minv(M);
|
||||
DenseMatrix dxidxm(2,num_dofs2); dxidxm = 0.0;
|
||||
Minv.Mult(f, dxidxm);
|
||||
//LinearSolve??
|
||||
//dxidxm = M\f;
|
||||
|
||||
DenseMatrix nde2(2,2); nde2 = 0.0;
|
||||
DenseMatrix Nndx2(2,num_dofs2); Nndx2 = 0.0;
|
||||
|
||||
for (int d=0; d<3; d++)
|
||||
{
|
||||
DenseMatrix ndetmp(2,2); ndetmp = 0.0;
|
||||
ndetmp(0,0) = normal(d)*m_dx2(0,d); ndetmp(0,1) = normal(d)*m_dx2(1,d);
|
||||
ndetmp(1,0) = normal(d)*m_dx2(1,d); ndetmp(1,1) = normal(d)*m_dx2(2,d);
|
||||
|
||||
nde2 += ndetmp;
|
||||
|
||||
for (int j=0; j<4; j++)
|
||||
{
|
||||
assert(d+3*j<num_dofs2);
|
||||
Nndx2(0,d+j*3) = normal[d]*m_dN(0,j);
|
||||
Nndx2(1,d+j*3) = normal[d]*m_dN(1,j);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DenseMatrix Ndn(2,num_dofs2); Ndn = 0.0;
|
||||
Ndn += Nndx2;
|
||||
AddMult(nde2, dxidxm, Ndn);
|
||||
|
||||
|
||||
DenseMatrix M2(2,2); M2 = 0.0;
|
||||
MultABt(m_dx, m_dx, M2);
|
||||
DenseMatrixInverse M2inv(M2);
|
||||
DenseMatrix diag2(2,2); diag2(0,0) = 1.0; diag2(1,1) = 1.0;
|
||||
DenseMatrix m_con(2,2); m_con = 0.0;
|
||||
|
||||
M2inv.Mult(diag2, m_con);
|
||||
|
||||
DenseMatrix dg2dxm(num_dofs2, num_dofs2); dg2dxm = 0.0;
|
||||
|
||||
DenseMatrix dg2dxm_tmp(num_dofs2,2); dg2dxm_tmp = 0.0;
|
||||
MultAtB(Ndn, m_con, dg2dxm_tmp);
|
||||
Mult(dg2dxm_tmp, Ndn, dg2dxm);
|
||||
dg2dxm *= gap;
|
||||
|
||||
DenseMatrix dg2dxm_tmp2(num_dofs2,num_dofs2); dg2dxm_tmp2 = 0.0;
|
||||
MultAtB(Nndx2, dxidxm, dg2dxm_tmp2);
|
||||
dg2dxm.Add(-1.0, dg2dxm_tmp2);
|
||||
|
||||
dg2dxm_tmp = 0.0;
|
||||
MultAtB(dxidxm, nde2, dg2dxm_tmp);
|
||||
|
||||
AddMult_a(-1.0, dg2dxm_tmp, dxidxm, dg2dxm);
|
||||
|
||||
dg2dxm_tmp2 = 0.0;
|
||||
MultAtB(dxidxm, Nndx2, dg2dxm_tmp2);
|
||||
dg2dxm.Add(-1.0, dg2dxm_tmp2);
|
||||
|
||||
Vector v_dxidx2(4);
|
||||
m_coords.Mult(gap_v, v_dxidx2); // m_coords * gap_v; // 4*3 * 3 = 4
|
||||
|
||||
DenseMatrix K_dxidx2(2,2); K_dxidx2 = 0.0;
|
||||
|
||||
Vector m_dN2row1(4); m_dN2.GetRow(0, m_dN2row1);
|
||||
Vector m_dN2row2(4); m_dN2.GetRow(1, m_dN2row2);
|
||||
Vector m_dN2row3(4); m_dN2.GetRow(2, m_dN2row3);
|
||||
K_dxidx2(0,0) = m_dN2row1 * v_dxidx2; // how would 4*1 * 1*4 be computed?
|
||||
K_dxidx2(0,1) = m_dN2row2 * v_dxidx2;
|
||||
K_dxidx2(1,0) = m_dN2row2 * v_dxidx2;
|
||||
K_dxidx2(1,1) = m_dN2row3 * v_dxidx2;
|
||||
|
||||
DenseMatrix K_dxidx(2,2);
|
||||
K_dxidx -= M2;
|
||||
K_dxidx += K_dxidx2;
|
||||
|
||||
Vector drdxs_r(6);
|
||||
drdxs_r[0] = m_dx(0,0); drdxs_r[1] = m_dx(0,1); drdxs_r[2] = m_dx(0,2);
|
||||
drdxs_r[3] = m_dx(1,0); drdxs_r[4] = m_dx(1,1); drdxs_r[5] = m_dx(1,2);
|
||||
|
||||
DenseMatrix drdxs_K(6,6); drdxs_K = 0.;
|
||||
for (int i=0; i<3; i++)
|
||||
{
|
||||
drdxs_K(i,i) = K_dxidx(0,0);
|
||||
drdxs_K(i,3+i) = K_dxidx(0,1);
|
||||
drdxs_K(i+3,i) = K_dxidx(1,0);
|
||||
drdxs_K(i+3,i+3) = K_dxidx(1,1);
|
||||
}
|
||||
Vector dxidxs(6);
|
||||
|
||||
DenseMatrixInverse drdxsK_inv(drdxs_K);
|
||||
drdxsK_inv.Mult(drdxs_r,dxidxs);
|
||||
dxidxs *= -1.0;
|
||||
//dxidxs = -drdxs_K\drdxs_r;
|
||||
|
||||
DenseMatrix dxidxs_m(2,3); dxidxs_m = 0.0;
|
||||
dxidxs_m(0,0) = dxidxs[0]; dxidxs_m(0,1) = dxidxs[1]; dxidxs_m(0,2) = dxidxs[2];
|
||||
dxidxs_m(1,0) = dxidxs[3]; dxidxs_m(1,1) = dxidxs[4]; dxidxs_m(1,2) = dxidxs[5];
|
||||
|
||||
DenseMatrix dtao1dxs(3,3); dtao1dxs = 0.0;
|
||||
DenseMatrix dtao2dxs(3,3); dtao2dxs = 0.0;
|
||||
|
||||
Vector dxidxs_row1(3); dxidxs_row1 = 0.0; Vector dxidxs_row2(3);
|
||||
dxidxs_row2 = 0.0;
|
||||
Vector mdx2_row1(3); mdx2_row1 = 0.0; Vector mdx2_row2(3); mdx2_row2 = 0.0;
|
||||
Vector mdx2_row3(3); mdx2_row3 = 0.0;
|
||||
dxidxs_m.GetRow(0,dxidxs_row1);
|
||||
dxidxs_m.GetRow(1,dxidxs_row2);
|
||||
m_dx2.GetRow(0,mdx2_row1);
|
||||
m_dx2.GetRow(1,mdx2_row2);
|
||||
m_dx2.GetRow(2,mdx2_row3);
|
||||
|
||||
DenseMatrix dtaotmp(3,3); dtaotmp = 0.0;
|
||||
outer(mdx2_row1, dxidxs_row1,dtaotmp);
|
||||
dtao1dxs += dtaotmp; dtaotmp = 0.0;
|
||||
outer(mdx2_row2, dxidxs_row1,dtaotmp);
|
||||
dtao1dxs += dtaotmp; dtaotmp = 0.0;
|
||||
|
||||
outer(mdx2_row2, dxidxs_row2, dtaotmp);
|
||||
dtao2dxs += dtaotmp; dtaotmp = 0.0;
|
||||
outer(mdx2_row3, dxidxs_row2, dtaotmp);
|
||||
dtao2dxs += dtaotmp; dtaotmp = 0.0;
|
||||
|
||||
DenseMatrix dtaodxs(3,3); dtaodxs = 0.0; //tao = tao1 cross tao2
|
||||
|
||||
for (int d=0; d<3; d++)
|
||||
{
|
||||
Vector dtao1dxs_tmp(3); dtao1dxs_tmp = 0.0;
|
||||
dtao1dxs.GetColumn(d,dtao1dxs_tmp);
|
||||
Vector m_dxrow(3); m_dx.GetRow(1, m_dxrow);
|
||||
|
||||
Vector dtaodxs_tmp(3); dtaodxs_tmp = 0.0;
|
||||
cross(dtao1dxs_tmp, m_dxrow, dtaodxs_tmp);
|
||||
|
||||
Vector dtaodxs_tmp2(3); dtaodxs_tmp2 = 0.0;
|
||||
m_dx.GetRow(0, m_dxrow);
|
||||
dtao1dxs_tmp = 0.0; // reuse the same vector for dtao2
|
||||
dtao2dxs.GetColumn(d,dtao1dxs_tmp);
|
||||
cross(m_dxrow, dtao1dxs_tmp, dtaodxs_tmp2);
|
||||
|
||||
dtaodxs_tmp2 += dtaodxs_tmp;
|
||||
dtaodxs.SetCol(d, dtaodxs_tmp2);
|
||||
}
|
||||
|
||||
DenseMatrix dndxs(3,3); dndxs = 0.0; dndxs += dtaodxs; dndxs *= 1.0/nnorm;
|
||||
DenseMatrix dndxs_tmp(3,3); dndxs_tmp = 0.0;
|
||||
outer(normal, normal, dndxs_tmp);
|
||||
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxs, dndxs);
|
||||
|
||||
DenseMatrix dgvdxs(3,3); dgvdxs = 0.0;
|
||||
MultAtB(m_dx, dxidxs_m, dgvdxs);
|
||||
dgvdxs *= -1;
|
||||
for (int d=0; d<3; d++)
|
||||
{
|
||||
dgvdxs(d,d) += 1.0;
|
||||
}
|
||||
//dxidxs: 2*3
|
||||
|
||||
DenseMatrix dg2dxs(3,3); dg2dxs = 0.0;
|
||||
DenseMatrix dg2dxs_tmp(3,2); dg2dxs_tmp = 0.0;
|
||||
MultAtB(dxidxs_m, nde2, dg2dxs_tmp);
|
||||
AddMult_a(-1.0, dg2dxs_tmp, dxidxs_m, dg2dxs);
|
||||
DenseMatrix dg2dxs_tmp2(3,3); dg2dxs_tmp2 = 0.0;
|
||||
MultAtB(dgvdxs, dndxs, dg2dxs_tmp2);
|
||||
dg2dxs += dg2dxs_tmp2;
|
||||
dg2dxs_tmp2 = 0.0;
|
||||
MultAtB(dndxs, dndxs_tmp, dg2dxs_tmp2);
|
||||
AddMult(dg2dxs_tmp2, dgvdxs, dg2dxs);
|
||||
|
||||
DenseMatrix Ne(3,12), Be(6,12), dBe(12,12);
|
||||
BasisVectorDerivs(xi, Ne, Be, dBe);
|
||||
|
||||
DenseMatrix dtao1dxm(3,12); dtao1dxm.CopyRows(Be, 0, 2);
|
||||
DenseMatrix dtao2dxm(3,12); dtao2dxm.CopyRows(Be, 3, 5);
|
||||
|
||||
Vector m_coords_v(12);
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
for (int j=0; j<3; j++)
|
||||
{
|
||||
m_coords_v[i*3+j] = m_coords(i,j);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<2; i++)
|
||||
{
|
||||
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
|
||||
dxidxm.GetRow(i,dxidxm_tmp);
|
||||
|
||||
DenseMatrix dBe_tmp(3,12);
|
||||
dBe_tmp.CopyRows(dBe,i*3,(i+1)*3-1);
|
||||
|
||||
DenseMatrix dtaodxm_tmp(12,12); dtaodxm_tmp = 0.0;
|
||||
outer(m_coords_v, dxidxm_tmp, dtaodxm_tmp);
|
||||
AddMult(dBe_tmp, dtaodxm_tmp, dtao1dxm);
|
||||
|
||||
//dtao1dxm += dBe(:,:,i)*reshape(m_coords(1:4,:)',12,1)*reshape(dxidxm(i,:),1,12); % 3*12
|
||||
dBe_tmp = 0.0;
|
||||
dBe_tmp.CopyRows(dBe,(i+2)*3,(i+3)*3-1);
|
||||
AddMult(dBe_tmp, dtaodxm_tmp, dtao2dxm);
|
||||
|
||||
}
|
||||
|
||||
DenseMatrix dtaodxm(3,12); dtaodxm = 0.0;//tao = tao1 cross tao2
|
||||
|
||||
for (int d=0; d<12; d++)
|
||||
{
|
||||
Vector dtaodxm_tmp(3); dtaodxm_tmp = 0.0;
|
||||
Vector dtaodxm_tmp2(3); dtaodxm_tmp2 = 0.0;
|
||||
Vector tmp1(3); tmp1 = 0.0; dtao1dxm.GetColumn(d,tmp1);
|
||||
Vector m_dxrow2(3); m_dx.GetRow(1, m_dxrow2);
|
||||
Vector m_dxrow1(3); m_dx.GetRow(0, m_dxrow1);
|
||||
Vector tmp2(3); tmp2 = 0.0; dtao2dxm.GetColumn(d,tmp2);
|
||||
|
||||
cross(tmp1, m_dxrow2, dtaodxm_tmp);
|
||||
cross(m_dxrow1,tmp2, dtaodxm_tmp2);
|
||||
dtaodxm_tmp += dtaodxm_tmp2;
|
||||
|
||||
dtaodxm.SetCol(d, dtaodxm_tmp);
|
||||
}
|
||||
|
||||
DenseMatrix dndxm(3,12); dndxm = 0.0;
|
||||
dndxm += dtaodxm;
|
||||
dndxm *= 1.0/nnorm;
|
||||
AddMult_a(-1/nnorm, dndxs_tmp, dtaodxm, dndxm); //dndxs_tmp = normal'*normal
|
||||
|
||||
DenseMatrix dgvdxm(3,12); dgvdxm = 0.0;
|
||||
dgvdxm -= Ne;
|
||||
|
||||
for (int i=0; i<2; i++)
|
||||
{
|
||||
Vector dxidxm_tmp(num_dofs2); dxidxm_tmp = 0.0;
|
||||
dxidxm.GetRow(i,dxidxm_tmp);
|
||||
|
||||
DenseMatrix Be_tmp(3,12);
|
||||
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
|
||||
|
||||
DenseMatrix dgvdxm_tmp(12,12); dgvdxm_tmp = 0.0;
|
||||
outer(m_coords_v, dxidxm_tmp, dgvdxm_tmp);
|
||||
AddMult_a(-1.0, Be_tmp, dgvdxm_tmp, dgvdxm);
|
||||
|
||||
}
|
||||
|
||||
DenseMatrix dg2dxsxm(3,12); dg2dxsxm = 0.0;
|
||||
DenseMatrix dg2dxsxm_tmp(3,3); dg2dxsxm_tmp = 0.0;
|
||||
MultAtB(dgvdxs, dndxm, dg2dxsxm);
|
||||
|
||||
MultAtB(dndxs, dndxs_tmp, dg2dxsxm_tmp);
|
||||
AddMult(dg2dxsxm_tmp, dgvdxm, dg2dxsxm); // += dndxs'*normal'*normal*dgvdxm;
|
||||
|
||||
DenseMatrix dgvdxsxmn(3,12); dgvdxsxmn = 0.0;
|
||||
DenseMatrix dgvdxsxmn_tmp(3,2); dgvdxsxmn_tmp = 0.0;
|
||||
MultAtB(dxidxs_m, nde2, dgvdxsxmn_tmp); //dxidxs_m: 2*3
|
||||
|
||||
AddMult_a(-1.0, dgvdxsxmn_tmp, dxidxm, dgvdxsxmn);
|
||||
|
||||
|
||||
for (int i =0; i<2; i++)
|
||||
{
|
||||
DenseMatrix Be_tmp(3,12);
|
||||
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
|
||||
|
||||
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
|
||||
DenseMatrix dgvdxsxmn_tmp2(3,3); dgvdxsxmn_tmp2 = 0.0;
|
||||
outer(dxidxs_row, normal, dgvdxsxmn_tmp2);
|
||||
AddMult_a(-1.0, dgvdxsxmn_tmp2, Be_tmp, dgvdxsxmn);
|
||||
}
|
||||
|
||||
dg2dxsxm += dgvdxsxmn;
|
||||
|
||||
DenseMatrix dg2dxmxs(12,3); dg2dxmxs = 0.0;
|
||||
DenseMatrix dg2dxmxs_tmp(12,3); dg2dxmxs_tmp = 0.0;
|
||||
MultAtB(dgvdxm, dndxs, dg2dxmxs);
|
||||
MultAtB(dndxm, dndxs_tmp, dg2dxmxs_tmp);
|
||||
AddMult(dg2dxmxs_tmp, dgvdxs, dg2dxmxs);
|
||||
|
||||
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
|
||||
DenseMatrix dgvdxmxsn_tmp(12,2); dgvdxmxsn_tmp = 0.0;
|
||||
|
||||
MultAtB(dxidxm, nde2, dgvdxmxsn_tmp);
|
||||
dgvdxmxsn_tmp *= -1.0;
|
||||
AddMult(dgvdxmxsn_tmp, dxidxs_m, dgvdxmxsn);
|
||||
|
||||
for (int i =0; i<2; i++)
|
||||
{
|
||||
DenseMatrix Be_tmp(3,12);
|
||||
Be_tmp.CopyRows(Be,i*3,(i+1)*3-1);
|
||||
Be_tmp.Transpose(); // Be is now 12*3
|
||||
|
||||
Vector dxidxs_row(3); dxidxs_row = 0.0; dxidxs_m.GetRow(i,dxidxs_row);
|
||||
DenseMatrix dgvdxmxsn_tmp2(3,3); dgvdxmxsn_tmp2 = 0.0;
|
||||
outer(normal, dxidxs_row, dgvdxmxsn_tmp2);
|
||||
AddMult_a(-1.0, Be_tmp, dgvdxmxsn_tmp2, dgvdxmxsn);
|
||||
|
||||
}
|
||||
|
||||
dg2dxmxs += dgvdxmxsn;
|
||||
|
||||
dg2dx.CopyMN(dg2dxs, 0, 0);
|
||||
dg2dx.CopyMN(dg2dxm, 3, 3);
|
||||
dg2dx.CopyMN(dg2dxsxm, 0, 3);
|
||||
dg2dx.CopyMN(dg2dxmxs, 3, 0);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
void NodeSegConPairs(const Vector x1, const Vector xi2,
|
||||
const DenseMatrix coords2,
|
||||
double& node_g, Vector& node_dg, DenseMatrix& node_dg2)
|
||||
{
|
||||
double gap = 0.0;
|
||||
Vector normal(3); normal = 0.0;
|
||||
Vector dgdxm(12); dgdxm = 0.0;
|
||||
Vector dgdxs(3); dgdxs = 0.0;
|
||||
|
||||
ComputeGapJacobian(x1, xi2, coords2, gap, normal, dgdxm, dgdxs);
|
||||
node_g = gap;
|
||||
|
||||
node_dg.SetSize(12+3);
|
||||
for (int i=0; i<3; i++) { node_dg[i] = dgdxs[i]; }
|
||||
for (int i=0; i<12; i++) { node_dg[i+3] = dgdxm[i]; }
|
||||
|
||||
DenseMatrix dg2dx(15,15); dg2dx = 0.0;
|
||||
DenseMatrix dgvdxmxsn(12,3); dgvdxmxsn = 0.0;
|
||||
ComputeGapHessian(x1, xi2, coords2, dg2dx);
|
||||
|
||||
node_dg2.SetSize(15,15);
|
||||
node_dg2 = dg2dx;
|
||||
|
||||
/*
|
||||
if(obj.space1.conns{e1}(i)==150) % for debugging purpose
|
||||
|
||||
v1 = 1:3;
|
||||
v2 = 1:12;
|
||||
%v1 = ones(1,3)
|
||||
%v2 = ones(1,12)
|
||||
v2 = reshape(v2,4,3);
|
||||
x1n1 = x1 + 0.01*v1;
|
||||
coords2n1 = coords2 + 0.001*v2;
|
||||
[xi2n1, gapv1, ~, ~] = SlaveToMaster(obj, coords2n1, x1n1);
|
||||
[gapn1, n1,dgdxmn1, dgdxsn1] = ComputeGapJacobian(obj, x1n1, xi2n1, coords2n1);
|
||||
x1n2 = x1 - 0.01*v1;
|
||||
coords2n2 = coords2 - 0.001*v2;
|
||||
[xi2n2, gapv2, ~, ~] = SlaveToMaster(obj, coords2n2, x1n2);
|
||||
[gapn2, n2,dgdxmn2, dgdxsn2] = ComputeGapJacobian(obj, x1n2, xi2n2, coords2n2);
|
||||
fprintf('fd\n');
|
||||
%gapv1-gapv2
|
||||
[dgdxsn1(:)',dgdxmn1(:)'] - [dgdxsn2(:)',dgdxmn2(:)']
|
||||
|
||||
%dgdxsn1-dgdxsn2
|
||||
fprintf('code\n');
|
||||
v2n = v2';
|
||||
%dg2dx(1:3,1:3)*0.04*ones(3,1)
|
||||
temp = zeros(12,3);
|
||||
for i = 1:4
|
||||
temp1 = dg2dx(3+(i-1)*3+1:3+i*3,1:3);
|
||||
temp((i-1)*3+1:i*3,:) = temp1';
|
||||
end
|
||||
temp2 = zeros(3,12);
|
||||
for i = 1:4
|
||||
temp3 = dg2dx(1:3,3+(i-1)*3+1:3+i*3);
|
||||
temp2(:,(i-1)*3+1:i*3) = temp3';
|
||||
end
|
||||
%dg2dx
|
||||
%dg2dx(4:end,1:3) = temp;
|
||||
%dg2dx(1:3,4:end) = temp2;
|
||||
%dgvdxm * 0.002*v2n(:)
|
||||
(dg2dx*[0.02*v1(:)',0.002*v2n(:)']')'
|
||||
%dg2dx(4:end,1:3)
|
||||
end*/
|
||||
|
||||
};
|
||||
|
||||
|
||||
// coordsm : (npoints*4, 3) use what class?
|
||||
// m_conn: (npoints*4)
|
||||
void Assemble_Contact(const int m, const int npoints, const int ndofs,
|
||||
const Vector x_s,
|
||||
const Vector xi, const DenseMatrix coordsm, const Array<int> s_conn,
|
||||
const Array<int> m_conn, Vector& g, SparseMatrix& M,
|
||||
std::vector<SparseMatrix>& dM)
|
||||
{
|
||||
int n = ndofs;
|
||||
int ndim = 3;
|
||||
|
||||
g.SetSize(m);
|
||||
g = 0.0;
|
||||
|
||||
//SparseMatrix M(m, n); // M needs to be the correct size
|
||||
|
||||
//dM.resize(m); // needs to clear?
|
||||
|
||||
double g_tmp = 0.;
|
||||
Vector dg(4*ndim+ndim);
|
||||
dg = 0.;
|
||||
DenseMatrix dg2(4*ndim+ndim,4*ndim+ndim);
|
||||
dg2 = 0.;
|
||||
|
||||
for (int i=0; i<npoints; i++)
|
||||
{
|
||||
Vector x1(ndim);
|
||||
x1[0] = x_s[i*ndim];
|
||||
x1[1] = x_s[i*ndim+1];
|
||||
x1[2] = x_s[i*ndim+2];
|
||||
|
||||
Vector xi2(ndim-1);
|
||||
xi2[0] = xi[i*(ndim-1)];
|
||||
xi2[1] = xi[i*(ndim-1)+1];
|
||||
|
||||
DenseMatrix coords2(4,3);
|
||||
coords2.CopyRows(coordsm, i*4,(i+1)*4-1);
|
||||
|
||||
//how to get coords2?
|
||||
dg = 0.0;
|
||||
dg2 = 0.;
|
||||
NodeSegConPairs(x1, xi2, coords2, g_tmp, dg, dg2);
|
||||
//x1.Print();
|
||||
//xi2.Print();
|
||||
//coords2.Print();
|
||||
g[s_conn[i]] = g_tmp; // should be unique
|
||||
Array<int> m_conn_i(4);
|
||||
m_conn.GetSubArray(4*i, 4, m_conn_i);
|
||||
|
||||
Array<int> node_conn(5);
|
||||
node_conn[0] = s_conn[i];
|
||||
for (int j=0; j<4; j++)
|
||||
{
|
||||
node_conn[j+1] = m_conn_i[j];
|
||||
}
|
||||
|
||||
Array<int> M_i_tmp(1);
|
||||
M_i_tmp[0] = s_conn[i];
|
||||
|
||||
//j_idx = (node_conn-1)*obj.disp_field.num_components +repmat((1:obj.disp_field.num_components)', 1, length(node_conn{i}));
|
||||
Array<int> j_idx(5*ndim); j_idx = 0;
|
||||
for (int j=0; j< 5; j++)
|
||||
{
|
||||
for (int k=0; k<ndim; k++)
|
||||
{
|
||||
j_idx[j*ndim+k] = node_conn[j]*ndim+k;
|
||||
}
|
||||
}
|
||||
DenseMatrix M_v_tmp(1, ndim*(4+1)); // SetData now?
|
||||
M_v_tmp.SetRow(0, dg);
|
||||
|
||||
M.AddSubMatrix(M_i_tmp, j_idx, M_v_tmp);
|
||||
|
||||
Array<int> dM_i(ndim*(4+1));
|
||||
Array<int> dM_j(ndim*(4+1));
|
||||
|
||||
for (int j=0; j< ndim*(4+1); j++)
|
||||
{
|
||||
dM_i[j] = j_idx[j];
|
||||
dM_j[j] = j_idx[j];
|
||||
}
|
||||
//dg2.Print();
|
||||
//dM[s_conn[i]].Print();
|
||||
dM[s_conn[i]].AddSubMatrix(dM_i,dM_j, dg2);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,42 +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
|
||||
#
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
elements
|
||||
5
|
||||
1 3 0 1 5 4
|
||||
1 3 1 2 6 5
|
||||
1 3 2 3 7 6
|
||||
1 3 3 0 4 7
|
||||
1 3 4 5 6 7
|
||||
|
||||
boundary
|
||||
4
|
||||
1 1 3 0
|
||||
2 1 0 1
|
||||
3 1 1 2
|
||||
4 1 2 3
|
||||
|
||||
vertices
|
||||
8
|
||||
2
|
||||
0 0
|
||||
1 0
|
||||
1 1
|
||||
0 1
|
||||
0.25 0.3333333333333333
|
||||
0.6 0.25
|
||||
0.75 0.69
|
||||
0.3333333333333333 0.75
|
||||
@@ -56,8 +56,7 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
dim = mesh->Dimension();
|
||||
ne = fes.GetMesh()->GetNE();
|
||||
nq = ir->GetNPoints();
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::COORDINATES |
|
||||
GeometricFactors::JACOBIANS, mt);
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::DETERMINANTS, mt);
|
||||
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
@@ -74,7 +73,7 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
const bool by_val = map_type == FiniteElement::VALUE;
|
||||
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
|
||||
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,2,2,NE);
|
||||
const auto J = Reshape(geom->detJ.Read(), Q1D,Q1D,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);
|
||||
@@ -84,11 +83,7 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
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 detJ = J(qx,qy,e);
|
||||
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
|
||||
v(qx,qy,e) = W(qx,qy) * coeff * (by_val ? detJ : 1.0/detJ);
|
||||
}
|
||||
@@ -102,7 +97,7 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
const bool by_val = map_type == FiniteElement::VALUE;
|
||||
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 J = Reshape(geom->detJ.Read(), 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);
|
||||
@@ -114,18 +109,7 @@ void MassIntegrator::AssemblePA(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 J23 = J(qx,qy,qz,1,2,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 detJ = J(qx,qy,qz,e);
|
||||
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 * (by_val ? detJ : 1.0/detJ);
|
||||
}
|
||||
|
||||
@@ -1319,7 +1319,6 @@ public:
|
||||
virtual void Eval(DenseSymmetricMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip) = 0;
|
||||
|
||||
using MatrixCoefficient::Eval;
|
||||
/** @brief Evaluate the matrix coefficient in the element described by @a T
|
||||
at the point @a ip, storing the result as a dense matrix @a K. */
|
||||
/** This function allows the use of SymmetricMatrixCoefficient in situations
|
||||
@@ -1348,7 +1347,6 @@ public:
|
||||
///Construct using matrix @a m for the constant.
|
||||
SymmetricMatrixConstantCoefficient(const DenseSymmetricMatrix &m)
|
||||
: SymmetricMatrixCoefficient(m.Height()), mat(m) { }
|
||||
using MatrixCoefficient::Eval;
|
||||
using SymmetricMatrixCoefficient::Eval;
|
||||
/// Evaluate the matrix coefficient at @a ip.
|
||||
virtual void Eval(DenseSymmetricMatrix &M, ElementTransformation &T,
|
||||
@@ -1400,7 +1398,6 @@ public:
|
||||
/// Set the time for internally stored coefficients
|
||||
void SetTime(double t);
|
||||
|
||||
using MatrixCoefficient::Eval;
|
||||
using SymmetricMatrixCoefficient::Eval;
|
||||
/// Evaluate the matrix coefficient at @a ip.
|
||||
virtual void Eval(DenseSymmetricMatrix &K, ElementTransformation &T,
|
||||
|
||||
+20
-17
@@ -110,8 +110,8 @@ DataCollection::DataCollection(const std::string& collection_name, Mesh *mesh_)
|
||||
precision = precision_default;
|
||||
pad_digits_cycle = pad_digits_rank = pad_digits_default;
|
||||
format = SERIAL_FORMAT; // use serial mesh format
|
||||
compression = false;
|
||||
error = NO_ERROR;
|
||||
compression = 0;
|
||||
error = No_Error;
|
||||
}
|
||||
|
||||
void DataCollection::SetMesh(Mesh *new_mesh)
|
||||
@@ -494,7 +494,7 @@ void VisItDataCollection::Load(int cycle_)
|
||||
{
|
||||
DeleteAll();
|
||||
time_step = 0.0;
|
||||
error = NO_ERROR;
|
||||
error = No_Error;
|
||||
cycle = cycle_;
|
||||
std::string root_name = prefix_path + name + "_" +
|
||||
to_padded_string(cycle, pad_digits_cycle) +
|
||||
@@ -767,10 +767,13 @@ ParaViewDataCollection::ParaViewDataCollection(const std::string&
|
||||
high_order_output(false),
|
||||
restart_mode(false)
|
||||
{
|
||||
cycle = 0; // always include a valid cycle index in file names
|
||||
|
||||
compression_level = -1; // default zlib compression level, equivalent to 6
|
||||
#ifdef MFEM_USE_ZLIB
|
||||
compression = -1; // default zlib compression level, equivalent to 6
|
||||
compression = true; // if we have zlib, enable compression
|
||||
#else
|
||||
compression = 0;
|
||||
compression = false; // otherwise, disable compression
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -919,7 +922,7 @@ void ParaViewDataCollection::Save()
|
||||
{
|
||||
const std::string &field_name = qfield.first;
|
||||
std::ofstream os(vtu_prefix + GenerateVTUFileName(field_name, myid));
|
||||
qfield.second->SaveVTU(os, pv_data_format, compression);
|
||||
qfield.second->SaveVTU(os, pv_data_format, GetCompressionLevel());
|
||||
}
|
||||
|
||||
// MPI rank 0 also creates a "PVTU" file that points to all of the separately
|
||||
@@ -1033,13 +1036,13 @@ void ParaViewDataCollection::WritePVTUFooter(std::ostream &os,
|
||||
void ParaViewDataCollection::SaveDataVTU(std::ostream &os, int ref)
|
||||
{
|
||||
os << "<VTKFile type=\"UnstructuredGrid\"";
|
||||
if (compression != 0)
|
||||
if (GetCompressionLevel() != 0)
|
||||
{
|
||||
os << " compressor=\"vtkZLibDataCompressor\"";
|
||||
}
|
||||
os << " version=\"0.1\" byte_order=\"" << VTKByteOrder() << "\">\n";
|
||||
os << "<UnstructuredGrid>\n";
|
||||
mesh->PrintVTU(os,ref,pv_data_format,high_order_output,compression);
|
||||
mesh->PrintVTU(os,ref,pv_data_format,high_order_output,GetCompressionLevel());
|
||||
|
||||
// dump out the grid functions as point data
|
||||
os << "<PointData >\n";
|
||||
@@ -1103,7 +1106,7 @@ void ParaViewDataCollection::SaveGFieldVTU(std::ostream &os, int ref_,
|
||||
|
||||
if (IsBinaryFormat())
|
||||
{
|
||||
WriteVTKEncodedCompressed(os,buf.data(),buf.size(),compression);
|
||||
WriteVTKEncodedCompressed(os,buf.data(),buf.size(),GetCompressionLevel());
|
||||
os << '\n';
|
||||
}
|
||||
os << "</DataArray>" << std::endl;
|
||||
@@ -1128,18 +1131,13 @@ void ParaViewDataCollection::SetCompressionLevel(int compression_level_)
|
||||
{
|
||||
MFEM_ASSERT(compression_level_ >= -1 && compression_level_ <= 9,
|
||||
"Compression level must be between -1 and 9 (inclusive).");
|
||||
compression = compression_level_;
|
||||
compression_level = compression_level_;
|
||||
compression = compression_level_ != 0;
|
||||
}
|
||||
|
||||
void ParaViewDataCollection::SetCompression(bool compression_)
|
||||
{
|
||||
// If we are enabling compression, and it was disabled previously, use the
|
||||
// default compression level. Otherwise, leave the compression level
|
||||
// unchanged.
|
||||
if (compression_ && compression == 0)
|
||||
{
|
||||
SetCompressionLevel(-1);
|
||||
}
|
||||
compression = compression_;
|
||||
}
|
||||
|
||||
void ParaViewDataCollection::UseRestartMode(bool restart_mode_)
|
||||
@@ -1171,4 +1169,9 @@ const char *ParaViewDataCollection::GetDataTypeString() const
|
||||
}
|
||||
}
|
||||
|
||||
int ParaViewDataCollection::GetCompressionLevel() const
|
||||
{
|
||||
return compression ? compression_level : 0;
|
||||
}
|
||||
|
||||
} // end namespace MFEM
|
||||
|
||||
+36
-9
@@ -378,12 +378,24 @@ public:
|
||||
virtual ~DataCollection();
|
||||
|
||||
/// Errors returned by Error()
|
||||
enum { NO_ERROR = 0, READ_ERROR = 1, WRITE_ERROR = 2 };
|
||||
enum
|
||||
{
|
||||
// Workaround for use with headers that define NO_ERROR as a macro,
|
||||
// e.g. winerror.h (which is included by Windows.h):
|
||||
#ifndef NO_ERROR
|
||||
NO_ERROR = 0,
|
||||
#endif
|
||||
// Use the following identifier if NO_ERROR is defined as a macro,
|
||||
// e.g. winerror.h (which is included by Windows.h):
|
||||
No_Error = 0,
|
||||
READ_ERROR = 1,
|
||||
WRITE_ERROR = 2
|
||||
};
|
||||
|
||||
/// Get the current error state
|
||||
int Error() const { return error; }
|
||||
/// Reset the error state
|
||||
void ResetError(int err_state = NO_ERROR) { error = err_state; }
|
||||
void ResetError(int err_state = No_Error) { error = err_state; }
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
friend class ParMesh;
|
||||
@@ -495,6 +507,7 @@ class ParaViewDataCollection : public DataCollection
|
||||
{
|
||||
private:
|
||||
int levels_of_detail;
|
||||
int compression_level;
|
||||
std::fstream pvd_stream;
|
||||
VTKFormat pv_data_format;
|
||||
bool high_order_output;
|
||||
@@ -507,6 +520,9 @@ protected:
|
||||
void SaveGFieldVTU(std::ostream& out, int ref_, const FieldMapIterator& it);
|
||||
const char *GetDataFormatString() const;
|
||||
const char *GetDataTypeString() const;
|
||||
/// @brief If compression is enabled, return the compression level, otherwise
|
||||
/// return 0.
|
||||
int GetCompressionLevel() const;
|
||||
|
||||
std::string GenerateCollectionPath();
|
||||
std::string GenerateVTUFileName(const std::string &prefix, int rank);
|
||||
@@ -525,7 +541,7 @@ public:
|
||||
mfem::Mesh *mesh_ = NULL);
|
||||
|
||||
/// Set refinement levels - every element is uniformly split based on
|
||||
/// levels_of_detail_
|
||||
/// levels_of_detail_. The initial value is 1.
|
||||
void SetLevelsOfDetail(int levels_of_detail_);
|
||||
|
||||
/// Save the collection - the directory name is constructed based on the
|
||||
@@ -536,18 +552,27 @@ public:
|
||||
/// VTKFormat::ASCII, VTKFormat::BINARY, and VTKFormat::BINARY32.
|
||||
/// The ASCII and BINARY options output double precision data, whereas the
|
||||
/// BINARY32 option outputs single precision data.
|
||||
///
|
||||
/// The initial format is VTKFormat::BINARY.
|
||||
void SetDataFormat(VTKFormat fmt);
|
||||
|
||||
/// Set the zlib compression level. 0 indicates no compression, -1 indicates
|
||||
/// the default compression level. Otherwise, specify a number between 1 and
|
||||
/// 9, 1 being the fastest, and 9 being the best compression. Compression
|
||||
/// only takes effect if the output format is BINARY or BINARY32. MFEM must
|
||||
/// be compiled with MFEM_USE_ZLIB = YES.
|
||||
/// @brief Set the zlib compression level.
|
||||
///
|
||||
/// 0 indicates no compression, -1 indicates the default compression level.
|
||||
/// Otherwise, specify a number between 1 and 9, 1 being the fastest, and 9
|
||||
/// being the best compression. Compression only takes effect if the output
|
||||
/// format is BINARY or BINARY32. MFEM must be compiled with MFEM_USE_ZLIB =
|
||||
/// YES.
|
||||
///
|
||||
/// The initial compression level is 0 if MFEM is compiled with MFEM_USE_ZLIB
|
||||
/// turned off, and -1 otherwise.
|
||||
///
|
||||
/// Any nonzero compression level will enable compression.
|
||||
void SetCompressionLevel(int compression_level_);
|
||||
|
||||
/// Enable or disable zlib compression. If the input is true, use the default
|
||||
/// zlib compression level (unless the compression level has previously been
|
||||
/// set by calling SetCompressionLevel).
|
||||
/// set by calling SetCompressionLevel()).
|
||||
void SetCompression(bool compression_) override;
|
||||
|
||||
/// Returns true if the output format is BINARY or BINARY32, false if ASCII.
|
||||
@@ -560,6 +585,8 @@ public:
|
||||
/// Enable or disable restart mode. If restart is enabled, new writes will
|
||||
/// preserve timestep metadata for any solutions prior to the currently
|
||||
/// defined time.
|
||||
///
|
||||
/// Initially, restart mode is disabled.
|
||||
void UseRestartMode(bool restart_mode_);
|
||||
|
||||
/// Load the collection - not implemented in the ParaView writer
|
||||
|
||||
+220
-219
@@ -36,19 +36,19 @@ FiniteElement::FiniteElement(int D, Geometry::Type G,
|
||||
#endif
|
||||
}
|
||||
|
||||
void FiniteElement::CalcVShape (
|
||||
void FiniteElement::CalcVShape(
|
||||
const IntegrationPoint &ip, DenseMatrix &shape) const
|
||||
{
|
||||
MFEM_ABORT("method is not implemented for this class");
|
||||
}
|
||||
|
||||
void FiniteElement::CalcVShape (
|
||||
void FiniteElement::CalcVShape(
|
||||
ElementTransformation &Trans, DenseMatrix &shape) const
|
||||
{
|
||||
MFEM_ABORT("method is not implemented for this class");
|
||||
}
|
||||
|
||||
void FiniteElement::CalcDivShape (
|
||||
void FiniteElement::CalcDivShape(
|
||||
const IntegrationPoint &ip, Vector &divshape) const
|
||||
{
|
||||
MFEM_ABORT("method is not implemented for this class");
|
||||
@@ -97,14 +97,14 @@ void FiniteElement::GetFaceDofs(int face, int **dofs, int *ndofs) const
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
}
|
||||
|
||||
void FiniteElement::CalcHessian (const IntegrationPoint &ip,
|
||||
DenseMatrix &h) const
|
||||
void FiniteElement::CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &h) const
|
||||
{
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
}
|
||||
|
||||
void FiniteElement::GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
void FiniteElement::GetLocalInterpolation(ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
}
|
||||
@@ -122,13 +122,13 @@ void FiniteElement::GetTransferMatrix(const FiniteElement &fe,
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
}
|
||||
|
||||
void FiniteElement::Project (
|
||||
void FiniteElement::Project(
|
||||
Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
}
|
||||
|
||||
void FiniteElement::Project (
|
||||
void FiniteElement::Project(
|
||||
VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
@@ -137,7 +137,7 @@ void FiniteElement::Project (
|
||||
void FiniteElement::ProjectFromNodes(Vector &vc, ElementTransformation &Trans,
|
||||
Vector &dofs) const
|
||||
{
|
||||
mfem_error ("FiniteElement::ProjectFromNodes() (vector) is not overloaded!");
|
||||
mfem_error("FiniteElement::ProjectFromNodes() (vector) is not overloaded!");
|
||||
}
|
||||
|
||||
void FiniteElement::ProjectMatrixCoefficient(
|
||||
@@ -239,7 +239,6 @@ void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Assume a linear mapping
|
||||
void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
|
||||
Vector &Laplacian) const
|
||||
@@ -250,7 +249,7 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
|
||||
DenseMatrix Gij(dim,dim);
|
||||
Vector scale(size);
|
||||
|
||||
CalcHessian (Trans.GetIntPoint(), hess);
|
||||
CalcHessian(Trans.GetIntPoint(), hess);
|
||||
MultAAt(Trans.InverseJacobian(), Gij);
|
||||
|
||||
if (dim == 3)
|
||||
@@ -283,7 +282,6 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
|
||||
Laplacian[nd] += hess(nd,ii)*scale[ii];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
|
||||
@@ -363,11 +361,128 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
|
||||
Mult( hess, lhm, Hessian);
|
||||
}
|
||||
|
||||
const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &,
|
||||
DofToQuad::Mode) const
|
||||
const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_ABORT("method is not implemented for this element");
|
||||
return *dof2quad_array[0]; // suppress a warning
|
||||
MFEM_VERIFY(mode == DofToQuad::FULL, "invalid mode requested");
|
||||
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix vshape(dof, dim);
|
||||
#endif
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const int nqpt = ir.GetNPoints();
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = dof;
|
||||
d2q->nqpt = nqpt;
|
||||
if (range_type == SCALAR)
|
||||
{
|
||||
d2q->B.SetSize(nqpt*dof);
|
||||
d2q->Bt.SetSize(dof*nqpt);
|
||||
|
||||
Vector shape;
|
||||
vshape.GetColumnReference(0, shape);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcShape(ip, shape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = shape(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
d2q->B.SetSize(nqpt*dim*dof);
|
||||
d2q->Bt.SetSize(dof*nqpt*dim);
|
||||
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcVShape(ip, vshape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*(d+dim*j)] = d2q->Bt[j+dof*(i+nqpt*d)] = vshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (deriv_type)
|
||||
{
|
||||
case GRAD:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*dim*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt*dim);
|
||||
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcDShape(ip, vshape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt);
|
||||
|
||||
Vector divshape;
|
||||
vshape.GetColumnReference(0, divshape);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcDivShape(ip, divshape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+dof*i] = divshape(j);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CURL:
|
||||
{
|
||||
d2q->G.SetSize(nqpt*cdim*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt*cdim);
|
||||
|
||||
DenseMatrix curlshape(vshape.GetData(), dof, cdim); // cdim <= dim
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcCurlShape(ip, curlshape);
|
||||
for (int d = 0; d < cdim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = curlshape(j, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NONE:
|
||||
default:
|
||||
MFEM_ABORT("invalid finite element derivative type");
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
FiniteElement::~FiniteElement()
|
||||
@@ -379,16 +494,19 @@ FiniteElement::~FiniteElement()
|
||||
}
|
||||
|
||||
|
||||
void ScalarFiniteElement::NodalLocalInterpolation (
|
||||
void ScalarFiniteElement::NodalLocalInterpolation(
|
||||
ElementTransformation &Trans, DenseMatrix &I,
|
||||
const ScalarFiniteElement &fine_fe) const
|
||||
{
|
||||
double v[Geometry::MaxDim];
|
||||
Vector vv (v, dim);
|
||||
Vector vv(v, dim);
|
||||
IntegrationPoint f_ip;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector c_shape(dof);
|
||||
Vector shape(dof);
|
||||
#else
|
||||
Vector shape;
|
||||
vshape.GetColumnReference(0, shape);
|
||||
#endif
|
||||
|
||||
MFEM_ASSERT(map_type == fine_fe.GetMapType(), "");
|
||||
@@ -398,10 +516,10 @@ void ScalarFiniteElement::NodalLocalInterpolation (
|
||||
{
|
||||
Trans.Transform(fine_fe.Nodes.IntPoint(i), vv);
|
||||
f_ip.Set(v, dim);
|
||||
CalcShape(f_ip, c_shape);
|
||||
CalcShape(f_ip, shape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
if (fabs(I(i,j) = c_shape(j)) < 1.0e-12)
|
||||
if (fabs(I(i,j) = shape(j)) < 1.0e-12)
|
||||
{
|
||||
I(i,j) = 0.0;
|
||||
}
|
||||
@@ -422,7 +540,7 @@ void ScalarFiniteElement::ScalarLocalInterpolation(
|
||||
// General "interpolation", defined by L2 projection
|
||||
|
||||
double v[Geometry::MaxDim];
|
||||
Vector vv (v, dim);
|
||||
Vector vv(v, dim);
|
||||
IntegrationPoint f_ip;
|
||||
|
||||
const int fs = fine_fe.GetDof(), cs = this->GetDof();
|
||||
@@ -456,14 +574,13 @@ void ScalarFiniteElement::ScalarLocalInterpolation(
|
||||
}
|
||||
}
|
||||
|
||||
void ScalarFiniteElement::ScalarLocalRestriction(
|
||||
void ScalarFiniteElement::ScalarLocalL2Restriction(
|
||||
ElementTransformation &Trans, DenseMatrix &R,
|
||||
const ScalarFiniteElement &coarse_fe) const
|
||||
{
|
||||
// General "restriction", defined by L2 projection
|
||||
double v[Geometry::MaxDim];
|
||||
Vector vv (v, dim);
|
||||
IntegrationPoint f_ip;
|
||||
Vector vv(v, dim);
|
||||
|
||||
const int cs = coarse_fe.GetDof(), fs = this->GetDof();
|
||||
R.SetSize(cs, fs);
|
||||
@@ -472,16 +589,27 @@ void ScalarFiniteElement::ScalarLocalRestriction(
|
||||
const int ir_order = GetOrder() + coarse_fe.GetOrder();
|
||||
const IntegrationRule &ir = IntRules.Get(coarse_fe.GetGeomType(), ir_order);
|
||||
|
||||
// integrate coarse_mass in the coarse space
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
this->CalcShape(ip, fine_shape);
|
||||
Trans.Transform(ip, vv);
|
||||
f_ip.Set(v, dim);
|
||||
coarse_fe.CalcShape(f_ip, coarse_shape);
|
||||
const IntegrationPoint &c_ip = ir.IntPoint(i);
|
||||
coarse_fe.CalcShape(c_ip, coarse_shape);
|
||||
AddMult_a_VVt(c_ip.weight, coarse_shape, coarse_mass);
|
||||
}
|
||||
|
||||
AddMult_a_VVt(ip.weight, coarse_shape, coarse_mass);
|
||||
AddMult_a_VWt(ip.weight, coarse_shape, fine_shape, coarse_fine_mass);
|
||||
// integrate coarse_fine_mass in the fine space
|
||||
Trans.SetIntPoint(&Geometries.GetCenter(geom_type));
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &f_ip = ir.IntPoint(i);
|
||||
this->CalcShape(f_ip, fine_shape);
|
||||
Trans.Transform(f_ip, vv);
|
||||
|
||||
IntegrationPoint c_ip;
|
||||
c_ip.Set(v, dim);
|
||||
coarse_fe.CalcShape(c_ip, coarse_shape);
|
||||
AddMult_a_VWt(f_ip.weight*Trans.Weight(), coarse_shape, fine_shape,
|
||||
coarse_fine_mass);
|
||||
}
|
||||
|
||||
DenseMatrixInverse coarse_mass_inv(coarse_mass);
|
||||
@@ -494,95 +622,6 @@ void ScalarFiniteElement::ScalarLocalRestriction(
|
||||
R *= 1.0 / Trans.Weight();
|
||||
}
|
||||
}
|
||||
const DofToQuad &ScalarFiniteElement::GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode == DofToQuad::FULL, "invalid mode requested");
|
||||
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const int nqpt = ir.GetNPoints();
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = dof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*dof);
|
||||
d2q->Bt.SetSize(dof*nqpt);
|
||||
d2q->G.SetSize(nqpt*dim*dof);
|
||||
d2q->Gt.SetSize(dof*nqpt*dim);
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector c_shape(dof);
|
||||
DenseMatrix vshape(dof, dim);
|
||||
#endif
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
CalcShape(ip, c_shape);
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = c_shape(j);
|
||||
}
|
||||
CalcDShape(ip, vshape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
for (int j = 0; j < dof; j++)
|
||||
{
|
||||
d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
// protected method
|
||||
const DofToQuad &ScalarFiniteElement::GetTensorDofToQuad(
|
||||
const TensorBasisElement &tb,
|
||||
const IntegrationRule &ir, DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
|
||||
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const Poly_1D::Basis &basis_1d = tb.GetBasis1D();
|
||||
const int ndof = order + 1;
|
||||
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5);
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = ndof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*ndof);
|
||||
d2q->Bt.SetSize(ndof*nqpt);
|
||||
d2q->G.SetSize(nqpt*ndof);
|
||||
d2q->Gt.SetSize(ndof*nqpt);
|
||||
Vector val(ndof), grad(ndof);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
|
||||
// of the 1D rule.
|
||||
basis_1d.Eval(ir.IntPoint(i).x, val, grad);
|
||||
for (int j = 0; j < ndof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
|
||||
}
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
|
||||
void NodalFiniteElement::ProjectCurl_2D(
|
||||
const FiniteElement &fe, ElementTransformation &Trans,
|
||||
@@ -631,7 +670,10 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans,
|
||||
Vector pt(&ipt.x, dim);
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector c_shape(dof);
|
||||
Vector shape(dof);
|
||||
#else
|
||||
Vector shape;
|
||||
vshape.GetColumnReference(0, shape);
|
||||
#endif
|
||||
|
||||
Trans.SetIntPoint(&Nodes[0]);
|
||||
@@ -641,8 +683,8 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans,
|
||||
InvertLinearTrans(Trans, Nodes[j], pt);
|
||||
if (Geometries.CheckPoint(geom_type, ipt)) // do we need an epsilon here?
|
||||
{
|
||||
CalcShape(ipt, c_shape);
|
||||
R.SetRow(j, c_shape);
|
||||
CalcShape(ipt, shape);
|
||||
R.SetRow(j, shape);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -653,7 +695,7 @@ void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans,
|
||||
R.Threshold(1e-12);
|
||||
}
|
||||
|
||||
void NodalFiniteElement::Project (
|
||||
void NodalFiniteElement::Project(
|
||||
Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
for (int i = 0; i < dof; i++)
|
||||
@@ -662,7 +704,7 @@ void NodalFiniteElement::Project (
|
||||
// some coefficients expect that Trans.IntPoint is the same
|
||||
// as the second argument of Eval
|
||||
Trans.SetIntPoint(&ip);
|
||||
dofs(i) = coeff.Eval (Trans, ip);
|
||||
dofs(i) = coeff.Eval(Trans, ip);
|
||||
if (map_type == INTEGRAL)
|
||||
{
|
||||
dofs(i) *= Trans.Weight();
|
||||
@@ -670,7 +712,7 @@ void NodalFiniteElement::Project (
|
||||
}
|
||||
}
|
||||
|
||||
void NodalFiniteElement::Project (
|
||||
void NodalFiniteElement::Project(
|
||||
VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
|
||||
{
|
||||
MFEM_ASSERT(dofs.Size() == vc.GetVDim()*dof, "");
|
||||
@@ -849,18 +891,18 @@ VectorFiniteElement::VectorFiniteElement(int D, Geometry::Type G,
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcShape (
|
||||
void VectorFiniteElement::CalcShape(
|
||||
const IntegrationPoint &ip, Vector &shape ) const
|
||||
{
|
||||
mfem_error ("Error: Cannot use scalar CalcShape(...) function with\n"
|
||||
" VectorFiniteElements!");
|
||||
mfem_error("Error: Cannot use scalar CalcShape(...) function with\n"
|
||||
" VectorFiniteElements!");
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcDShape (
|
||||
void VectorFiniteElement::CalcDShape(
|
||||
const IntegrationPoint &ip, DenseMatrix &dshape ) const
|
||||
{
|
||||
mfem_error ("Error: Cannot use scalar CalcDShape(...) function with\n"
|
||||
" VectorFiniteElements!");
|
||||
mfem_error("Error: Cannot use scalar CalcDShape(...) function with\n"
|
||||
" VectorFiniteElements!");
|
||||
}
|
||||
|
||||
void VectorFiniteElement::SetDerivMembers()
|
||||
@@ -900,7 +942,7 @@ void VectorFiniteElement::SetDerivMembers()
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcVShape_RT (
|
||||
void VectorFiniteElement::CalcVShape_RT(
|
||||
ElementTransformation &Trans, DenseMatrix &shape) const
|
||||
{
|
||||
MFEM_ASSERT(map_type == H_DIV, "");
|
||||
@@ -912,7 +954,7 @@ void VectorFiniteElement::CalcVShape_RT (
|
||||
shape *= (1.0 / Trans.Weight());
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcVShape_ND (
|
||||
void VectorFiniteElement::CalcVShape_ND(
|
||||
ElementTransformation &Trans, DenseMatrix &shape) const
|
||||
{
|
||||
MFEM_ASSERT(map_type == H_CURL, "");
|
||||
@@ -2402,6 +2444,46 @@ TensorBasisElement::TensorBasisElement(const int dims, const int p,
|
||||
}
|
||||
}
|
||||
|
||||
const DofToQuad &TensorBasisElement::GetTensorDofToQuad(
|
||||
const FiniteElement &fe, const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode, const Poly_1D::Basis &basis, bool closed,
|
||||
Array<DofToQuad*> &dof2quad_array)
|
||||
{
|
||||
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
|
||||
|
||||
for (int i = 0; i < dof2quad_array.Size(); i++)
|
||||
{
|
||||
const DofToQuad &d2q = *dof2quad_array[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const int ndof = closed ? fe.GetOrder() + 1 : fe.GetOrder();
|
||||
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/fe.GetDim()) + 0.5);
|
||||
d2q->FE = &fe;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = ndof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*ndof);
|
||||
d2q->Bt.SetSize(ndof*nqpt);
|
||||
d2q->G.SetSize(nqpt*ndof);
|
||||
d2q->Gt.SetSize(ndof*nqpt);
|
||||
Vector val(ndof), grad(ndof);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
|
||||
// of the 1D rule.
|
||||
basis.Eval(ir.IntPoint(i).x, val, grad);
|
||||
for (int j = 0; j < ndof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
|
||||
}
|
||||
}
|
||||
dof2quad_array.Append(d2q);
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
NodalTensorFiniteElement::NodalTensorFiniteElement(const int dims,
|
||||
const int p,
|
||||
@@ -2436,8 +2518,7 @@ VectorTensorFiniteElement::VectorTensorFiniteElement(const int dims,
|
||||
const DofMapType dmtype)
|
||||
: VectorFiniteElement(dims, GetTensorProductGeometry(dims), d,
|
||||
p, M, FunctionSpace::Qk),
|
||||
TensorBasisElement(dims, p, VerifyNodal(cbtype), dmtype),
|
||||
cbasis1d(poly1d.GetBasis(p, VerifyClosed(cbtype))),
|
||||
TensorBasisElement(dims, p, VerifyNodal(VerifyClosed(cbtype)), dmtype),
|
||||
obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(obtype)))
|
||||
{
|
||||
MFEM_VERIFY(dims > 1, "Constructor for VectorTensorFiniteElement with both "
|
||||
@@ -2452,93 +2533,13 @@ VectorTensorFiniteElement::VectorTensorFiniteElement(const int dims,
|
||||
const DofMapType dmtype)
|
||||
: VectorFiniteElement(dims, GetTensorProductGeometry(dims), d,
|
||||
p, M, FunctionSpace::Pk),
|
||||
TensorBasisElement(dims, p, obtype, dmtype),
|
||||
cbasis1d(poly1d.GetBasis(p, VerifyOpen(obtype))),
|
||||
TensorBasisElement(dims, p, VerifyOpen(obtype), dmtype),
|
||||
obasis1d(poly1d.GetBasis(p, VerifyOpen(obtype)))
|
||||
{
|
||||
MFEM_VERIFY(dims == 1, "Constructor for VectorTensorFiniteElement without "
|
||||
"closed basis is only valid for 1D elements.");
|
||||
}
|
||||
|
||||
const DofToQuad &VectorTensorFiniteElement::GetDofToQuad(
|
||||
const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
|
||||
|
||||
return GetTensorDofToQuad(ir, mode, true);
|
||||
}
|
||||
|
||||
const DofToQuad &VectorTensorFiniteElement::GetDofToQuadOpen(
|
||||
const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
|
||||
|
||||
return GetTensorDofToQuad(ir, mode, false);
|
||||
}
|
||||
|
||||
const DofToQuad &VectorTensorFiniteElement::GetTensorDofToQuad(
|
||||
const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode,
|
||||
const bool closed) const
|
||||
{
|
||||
MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
|
||||
|
||||
for (int i = 0;
|
||||
i < (closed ? dof2quad_array.Size() : dof2quad_array_open.Size());
|
||||
i++)
|
||||
{
|
||||
const DofToQuad &d2q = closed ? *dof2quad_array[i] : *dof2quad_array_open[i];
|
||||
if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; }
|
||||
}
|
||||
|
||||
DofToQuad *d2q = new DofToQuad;
|
||||
const int ndof = closed ? order + 1 : order;
|
||||
const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5);
|
||||
d2q->FE = this;
|
||||
d2q->IntRule = &ir;
|
||||
d2q->mode = mode;
|
||||
d2q->ndof = ndof;
|
||||
d2q->nqpt = nqpt;
|
||||
d2q->B.SetSize(nqpt*ndof);
|
||||
d2q->Bt.SetSize(ndof*nqpt);
|
||||
d2q->G.SetSize(nqpt*ndof);
|
||||
d2q->Gt.SetSize(ndof*nqpt);
|
||||
Vector val(ndof), grad(ndof);
|
||||
for (int i = 0; i < nqpt; i++)
|
||||
{
|
||||
// The first 'nqpt' points in 'ir' have the same x-coordinates as those
|
||||
// of the 1D rule.
|
||||
|
||||
if (closed)
|
||||
{
|
||||
cbasis1d.Eval(ir.IntPoint(i).x, val, grad);
|
||||
}
|
||||
else
|
||||
{
|
||||
obasis1d.Eval(ir.IntPoint(i).x, val, grad);
|
||||
}
|
||||
|
||||
for (int j = 0; j < ndof; j++)
|
||||
{
|
||||
d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
|
||||
d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (closed)
|
||||
{
|
||||
dof2quad_array.Append(d2q);
|
||||
}
|
||||
else
|
||||
{
|
||||
dof2quad_array_open.Append(d2q);
|
||||
}
|
||||
|
||||
return *d2q;
|
||||
}
|
||||
|
||||
VectorTensorFiniteElement::~VectorTensorFiniteElement()
|
||||
{
|
||||
for (int i = 0; i < dof2quad_array_open.Size(); i++)
|
||||
|
||||
+68
-81
@@ -127,7 +127,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @brief Structure representing the matrices/tensors needed to evaluate (in
|
||||
reference space) the values, gradients, divergences, or curls of a
|
||||
FiniteElement at a the quadrature points of a given IntegrationRule. */
|
||||
@@ -157,8 +156,7 @@ public:
|
||||
dimensions using 1D number of quadrature points and degrees of
|
||||
freedom. */
|
||||
/** When representing a vector-valued FiniteElement, two DofToQuad objects
|
||||
are used to describe the "closed" and "open" 1D basis functions
|
||||
(TODO). */
|
||||
are used to describe the "closed" and "open" 1D basis functions. */
|
||||
TENSOR
|
||||
};
|
||||
|
||||
@@ -176,7 +174,7 @@ public:
|
||||
/// Basis functions evaluated at quadrature points.
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #nqpt x #ndof, for scalar elements, or
|
||||
- #nqpt x dim x #ndof, for vector elements, (TODO)
|
||||
- #nqpt x dim x #ndof, for vector elements,
|
||||
|
||||
where
|
||||
|
||||
@@ -187,15 +185,15 @@ public:
|
||||
/// Transpose of #B.
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #ndof x #nqpt, for scalar elements, or
|
||||
- #ndof x #nqpt x dim, for vector elements (TODO). */
|
||||
- #ndof x #nqpt x dim, for vector elements. */
|
||||
Array<double> Bt;
|
||||
|
||||
/** @brief Gradients/divergences/curls of basis functions evaluated at
|
||||
quadrature points. */
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #nqpt x dim x #ndof, for scalar elements, or
|
||||
- #nqpt x #ndof, for H(div) vector elements (TODO), or
|
||||
- #nqpt x cdim x #ndof, for H(curl) vector elements (TODO),
|
||||
- #nqpt x #ndof, for H(div) vector elements, or
|
||||
- #nqpt x cdim x #ndof, for H(curl) vector elements,
|
||||
|
||||
where
|
||||
|
||||
@@ -208,12 +206,11 @@ public:
|
||||
/// Transpose of #G.
|
||||
/** The storage layout is column-major with dimensions:
|
||||
- #ndof x #nqpt x dim, for scalar elements, or
|
||||
- #ndof x #nqpt, for H(div) vector elements (TODO), or
|
||||
- #ndof x #nqpt x cdim, for H(curl) vector elements (TODO). */
|
||||
- #ndof x #nqpt, for H(div) vector elements, or
|
||||
- #ndof x #nqpt x cdim, for H(curl) vector elements. */
|
||||
Array<double> Gt;
|
||||
};
|
||||
|
||||
|
||||
/// Describes the function space on each element
|
||||
class FunctionSpace
|
||||
{
|
||||
@@ -247,7 +244,7 @@ protected:
|
||||
mutable int orders[Geometry::MaxDim]; ///< Anisotropic orders
|
||||
IntegrationRule Nodes;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable DenseMatrix vshape; // Dof x VDim
|
||||
mutable DenseMatrix vshape; // Dof x Dim
|
||||
#endif
|
||||
/// Container for all DofToQuad objects created by the FiniteElement.
|
||||
/** Multiple DofToQuad objects may be needed when different quadrature rules
|
||||
@@ -350,7 +347,6 @@ public:
|
||||
H_DIV, H_CURL}. */
|
||||
int GetMapType() const { return map_type; }
|
||||
|
||||
|
||||
/** @brief Returns the FiniteElement::DerivType of the element describing the
|
||||
spatial derivative method implemented, one of {NONE, GRAD,
|
||||
DIV, CURL}. */
|
||||
@@ -457,8 +453,8 @@ public:
|
||||
part of the Hessian of one shape function.
|
||||
The order in 2D is {u_xx, u_xy, u_yy}.
|
||||
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
|
||||
virtual void CalcHessian (const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
|
||||
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
|
||||
element in reference space at the given point @a ip. */
|
||||
@@ -579,6 +575,7 @@ public:
|
||||
/** See the documentation for DofToQuad for more details. */
|
||||
virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const;
|
||||
|
||||
/// Deconstruct the FiniteElement
|
||||
virtual ~FiniteElement();
|
||||
|
||||
@@ -625,16 +622,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @brief Class for finite elements with basis functions
|
||||
that return scalar values. */
|
||||
class ScalarFiniteElement : public FiniteElement
|
||||
{
|
||||
protected:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector c_shape;
|
||||
#endif
|
||||
|
||||
static const ScalarFiniteElement &CheckScalarFE(const FiniteElement &fe)
|
||||
{
|
||||
MFEM_VERIFY(fe.GetRangeType() == SCALAR,
|
||||
@@ -642,10 +634,6 @@ protected:
|
||||
return static_cast<const ScalarFiniteElement &>(fe);
|
||||
}
|
||||
|
||||
const DofToQuad &GetTensorDofToQuad(const class TensorBasisElement &tb,
|
||||
const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const;
|
||||
|
||||
public:
|
||||
/** @brief Construct ScalarFiniteElement with given
|
||||
@param D Reference space dimension
|
||||
@@ -656,13 +644,8 @@ public:
|
||||
*/
|
||||
ScalarFiniteElement(int D, Geometry::Type G, int Do, int O,
|
||||
int F = FunctionSpace::Pk)
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
: FiniteElement(D, G, Do, O, F)
|
||||
{ deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; }
|
||||
#else
|
||||
: FiniteElement(D, G, Do, O, F), c_shape(dof)
|
||||
{ deriv_type = GRAD; deriv_range_type = VECTOR; deriv_map_type = H_CURL; }
|
||||
#endif
|
||||
|
||||
/** @brief Set the FiniteElement::MapType of the element to either VALUE or
|
||||
INTEGRAL. Also sets the FiniteElement::DerivType to GRAD if the
|
||||
@@ -674,7 +657,6 @@ public:
|
||||
deriv_type = (M == VALUE) ? GRAD : NONE;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Get the matrix @a I that defines nodal interpolation
|
||||
@a between this element and the refined element @a fine_fe. */
|
||||
void NodalLocalInterpolation(ElementTransformation &Trans,
|
||||
@@ -695,15 +677,11 @@ public:
|
||||
/** If the "fine" elements cannot represent all basis functions of the
|
||||
"coarse" element, then boundary values from different sub-elements are
|
||||
generally different. */
|
||||
void ScalarLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R,
|
||||
const ScalarFiniteElement &coarse_fe) const;
|
||||
|
||||
virtual const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const;
|
||||
void ScalarLocalL2Restriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R,
|
||||
const ScalarFiniteElement &coarse_fe) const;
|
||||
};
|
||||
|
||||
|
||||
/// Class for standard nodal finite elements.
|
||||
class NodalFiniteElement : public ScalarFiniteElement
|
||||
{
|
||||
@@ -725,38 +703,38 @@ public:
|
||||
int F = FunctionSpace::Pk)
|
||||
: ScalarFiniteElement(D, G, Do, O, F) { }
|
||||
|
||||
virtual void GetLocalInterpolation(ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
void GetLocalInterpolation(ElementTransformation &Trans,
|
||||
DenseMatrix &I) const override
|
||||
{ NodalLocalInterpolation(Trans, I, *this); }
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const;
|
||||
void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const override;
|
||||
|
||||
virtual void GetTransferMatrix(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
void GetTransferMatrix(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const override
|
||||
{ CheckScalarFE(fe).NodalLocalInterpolation(Trans, I, *this); }
|
||||
|
||||
virtual void Project (Coefficient &coeff,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
void Project(Coefficient &coeff,
|
||||
ElementTransformation &Trans, Vector &dofs) const override;
|
||||
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const override;
|
||||
|
||||
// (mc.height x mc.width) @ DOFs -> (Dof x mc.width x mc.height) in dofs
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const;
|
||||
void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const override;
|
||||
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const override;
|
||||
|
||||
virtual void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const override;
|
||||
|
||||
virtual void ProjectDiv(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &div) const;
|
||||
void ProjectDiv(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &div) const override;
|
||||
|
||||
/** @brief Get an Array<int> that maps lexicographically ordered indices to
|
||||
the indices of the respective nodes/dofs/basis functions.
|
||||
@@ -790,12 +768,12 @@ class VectorFiniteElement : public FiniteElement
|
||||
// Hide the scalar functions CalcShape and CalcDShape.
|
||||
private:
|
||||
/// Overrides the scalar CalcShape function to print an error.
|
||||
virtual void CalcShape(const IntegrationPoint &ip,
|
||||
Vector &shape) const;
|
||||
void CalcShape(const IntegrationPoint &ip,
|
||||
Vector &shape) const override;
|
||||
|
||||
/// Overrides the scalar CalcDShape function to print an error.
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const override;
|
||||
|
||||
protected:
|
||||
bool is_nodal;
|
||||
@@ -954,11 +932,10 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
VectorFiniteElement (int D, Geometry::Type G, int Do, int O, int M,
|
||||
int F = FunctionSpace::Pk);
|
||||
VectorFiniteElement(int D, Geometry::Type G, int Do, int O, int M,
|
||||
int F = FunctionSpace::Pk);
|
||||
};
|
||||
|
||||
|
||||
/// @brief Class for computing 1D special polynomials and their associated basis
|
||||
/// functions
|
||||
class Poly_1D
|
||||
@@ -1179,7 +1156,6 @@ public:
|
||||
|
||||
extern Poly_1D poly1d;
|
||||
|
||||
|
||||
/// An element defined as an ND tensor product of 1D elements on a segment,
|
||||
/// square, or cube
|
||||
class TensorBasisElement
|
||||
@@ -1203,7 +1179,7 @@ public:
|
||||
|
||||
int GetBasisType() const { return b_type; }
|
||||
|
||||
const Poly_1D::Basis& GetBasis1D() const { return basis1d; }
|
||||
const Poly_1D::Basis &GetBasis1D() const { return basis1d; }
|
||||
|
||||
/** @brief Get an Array<int> that maps lexicographically ordered indices to
|
||||
the indices of the respective nodes/dofs/basis functions. If the dofs are
|
||||
@@ -1235,6 +1211,11 @@ public:
|
||||
default: MFEM_ABORT("invalid dimension: " << dim); return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static const DofToQuad &GetTensorDofToQuad(
|
||||
const FiniteElement &fe, const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode, const Poly_1D::Basis &basis, bool closed,
|
||||
Array<DofToQuad*> &dof2quad_array);
|
||||
};
|
||||
|
||||
class NodalTensorFiniteElement : public NodalFiniteElement,
|
||||
@@ -1245,18 +1226,18 @@ public:
|
||||
const DofMapType dmtype);
|
||||
|
||||
const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const
|
||||
DofToQuad::Mode mode) const override
|
||||
{
|
||||
return (mode == DofToQuad::FULL) ?
|
||||
ScalarFiniteElement::GetDofToQuad(ir, mode) :
|
||||
ScalarFiniteElement::GetTensorDofToQuad(*this, ir, mode);
|
||||
FiniteElement::GetDofToQuad(ir, mode) :
|
||||
GetTensorDofToQuad(*this, ir, mode, basis1d, true, dof2quad_array);
|
||||
}
|
||||
|
||||
virtual void SetMapType(const int map_type_);
|
||||
void SetMapType(const int map_type_) override;
|
||||
|
||||
virtual void GetTransferMatrix(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
void GetTransferMatrix(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const override
|
||||
{
|
||||
if (basis1d.IsIntegratedType())
|
||||
{
|
||||
@@ -1276,7 +1257,7 @@ private:
|
||||
mutable Array<DofToQuad*> dof2quad_array_open;
|
||||
|
||||
protected:
|
||||
Poly_1D::Basis &cbasis1d, &obasis1d;
|
||||
Poly_1D::Basis &obasis1d;
|
||||
|
||||
public:
|
||||
VectorTensorFiniteElement(const int dims, const int d, const int p,
|
||||
@@ -1289,16 +1270,22 @@ public:
|
||||
const DofMapType dmtype);
|
||||
|
||||
const DofToQuad &GetDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const;
|
||||
DofToQuad::Mode mode) const override
|
||||
{
|
||||
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
|
||||
return GetTensorDofToQuad(*this, ir, mode, basis1d, true,
|
||||
dof2quad_array);
|
||||
}
|
||||
|
||||
const DofToQuad &GetDofToQuadOpen(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode) const;
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested");
|
||||
return GetTensorDofToQuad(*this, ir, mode, obasis1d, false,
|
||||
dof2quad_array_open);
|
||||
}
|
||||
|
||||
const DofToQuad &GetTensorDofToQuad(const IntegrationRule &ir,
|
||||
DofToQuad::Mode mode,
|
||||
const bool closed) const;
|
||||
|
||||
~VectorTensorFiniteElement();
|
||||
virtual ~VectorTensorFiniteElement();
|
||||
};
|
||||
|
||||
void InvertLinearTrans(ElementTransformation &trans,
|
||||
|
||||
@@ -32,6 +32,11 @@ public:
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ ScalarLocalL2Restriction(Trans, R, *this); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -55,6 +60,11 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const
|
||||
{ ProjectCurl_2D(fe, Trans, curl); }
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ ScalarLocalL2Restriction(Trans, R, *this); }
|
||||
|
||||
using FiniteElement::Project;
|
||||
virtual void ProjectDiv(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
@@ -80,6 +90,11 @@ public:
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ ScalarLocalL2Restriction(Trans, R, *this); }
|
||||
|
||||
using FiniteElement::Project;
|
||||
virtual void ProjectDiv(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
@@ -111,6 +126,11 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const
|
||||
{ ProjectCurl_2D(fe, Trans, curl); }
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ ScalarLocalL2Restriction(Trans, R, *this); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -133,6 +153,11 @@ public:
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ ScalarLocalL2Restriction(Trans, R, *this); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
+15
-15
@@ -321,9 +321,9 @@ void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector dshape_cx(p + 1), dshape_cy(p + 1), dshape_cz(p + 1);
|
||||
#endif
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
basis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
|
||||
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
|
||||
@@ -331,9 +331,9 @@ void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
|
||||
}
|
||||
else
|
||||
{
|
||||
cbasis1d.Eval(ip.x, shape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy);
|
||||
cbasis1d.Eval(ip.z, shape_cz);
|
||||
basis1d.Eval(ip.x, shape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy);
|
||||
basis1d.Eval(ip.z, shape_cz);
|
||||
obasis1d.Eval(ip.x, shape_ox);
|
||||
obasis1d.Eval(ip.y, shape_oy);
|
||||
obasis1d.Eval(ip.z, shape_oz);
|
||||
@@ -407,9 +407,9 @@ void ND_HexahedronElement::CalcCurlShape(const IntegrationPoint &ip,
|
||||
Vector dshape_cx(p + 1), dshape_cy(p + 1), dshape_cz(p + 1);
|
||||
#endif
|
||||
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
basis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
if (obasis1d.IsIntegratedType())
|
||||
{
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
@@ -665,16 +665,16 @@ void ND_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip,
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector dshape_cx(p + 1), dshape_cy(p + 1);
|
||||
#endif
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
|
||||
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
|
||||
}
|
||||
else
|
||||
{
|
||||
cbasis1d.Eval(ip.x, shape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy);
|
||||
basis1d.Eval(ip.x, shape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy);
|
||||
obasis1d.Eval(ip.x, shape_ox);
|
||||
obasis1d.Eval(ip.y, shape_oy);
|
||||
}
|
||||
@@ -724,8 +724,8 @@ void ND_QuadrilateralElement::CalcCurlShape(const IntegrationPoint &ip,
|
||||
Vector dshape_cx(p + 1), dshape_cy(p + 1);
|
||||
#endif
|
||||
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
if (obasis1d.IsIntegratedType())
|
||||
{
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "fe_pos.hpp"
|
||||
#include "../bilininteg.hpp"
|
||||
#include "../lininteg.hpp"
|
||||
#include "../coefficient.hpp"
|
||||
|
||||
namespace mfem
|
||||
|
||||
+3
-3
@@ -40,7 +40,7 @@ public:
|
||||
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ ScalarLocalRestriction(Trans, R, *this); }
|
||||
{ ScalarLocalL2Restriction(Trans, R, *this); }
|
||||
|
||||
virtual void GetTransferMatrix(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
@@ -73,8 +73,8 @@ public:
|
||||
DofToQuad::Mode mode) const
|
||||
{
|
||||
return (mode == DofToQuad::FULL) ?
|
||||
ScalarFiniteElement::GetDofToQuad(ir, mode) :
|
||||
ScalarFiniteElement::GetTensorDofToQuad(*this, ir, mode);
|
||||
FiniteElement::GetDofToQuad(ir, mode) :
|
||||
GetTensorDofToQuad(*this, ir, mode, basis1d, true, dof2quad_array);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+15
-15
@@ -152,16 +152,16 @@ void RT_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip,
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector dshape_cx(pp1 + 1), dshape_cy(pp1 + 1);
|
||||
#endif
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
|
||||
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
|
||||
}
|
||||
else
|
||||
{
|
||||
cbasis1d.Eval(ip.x, shape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy);
|
||||
basis1d.Eval(ip.x, shape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy);
|
||||
obasis1d.Eval(ip.x, shape_ox);
|
||||
obasis1d.Eval(ip.y, shape_oy);
|
||||
}
|
||||
@@ -209,8 +209,8 @@ void RT_QuadrilateralElement::CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector dshape_cx(pp1 + 1), dshape_cy(pp1 + 1);
|
||||
#endif
|
||||
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
if (obasis1d.IsIntegratedType())
|
||||
{
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
@@ -482,9 +482,9 @@ void RT_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector dshape_cx(pp1 + 1), dshape_cy(pp1 + 1), dshape_cz(pp1 + 1);
|
||||
#endif
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
basis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
obasis1d.EvalIntegrated(dshape_cx, shape_ox);
|
||||
obasis1d.EvalIntegrated(dshape_cy, shape_oy);
|
||||
@@ -492,9 +492,9 @@ void RT_HexahedronElement::CalcVShape(const IntegrationPoint &ip,
|
||||
}
|
||||
else
|
||||
{
|
||||
cbasis1d.Eval(ip.x, shape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy);
|
||||
cbasis1d.Eval(ip.z, shape_cz);
|
||||
basis1d.Eval(ip.x, shape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy);
|
||||
basis1d.Eval(ip.z, shape_cz);
|
||||
obasis1d.Eval(ip.x, shape_ox);
|
||||
obasis1d.Eval(ip.y, shape_oy);
|
||||
obasis1d.Eval(ip.z, shape_oz);
|
||||
@@ -568,9 +568,9 @@ void RT_HexahedronElement::CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector dshape_cx(pp1 + 1), dshape_cy(pp1 + 1), dshape_cz(pp1 + 1);
|
||||
#endif
|
||||
|
||||
cbasis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
cbasis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
cbasis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
basis1d.Eval(ip.x, shape_cx, dshape_cx);
|
||||
basis1d.Eval(ip.y, shape_cy, dshape_cy);
|
||||
basis1d.Eval(ip.z, shape_cz, dshape_cz);
|
||||
if (obasis1d.IsIntegratedType())
|
||||
{
|
||||
obasis1d.ScaleIntegrated(false);
|
||||
|
||||
+36
-6
@@ -25,15 +25,16 @@ using namespace std;
|
||||
const FiniteElement *
|
||||
FiniteElementCollection::FiniteElementForDim(int dim) const
|
||||
{
|
||||
ErrorMode save_error_mode = error_mode;
|
||||
error_mode = RETURN_NULL;
|
||||
const FiniteElement *fe = nullptr;
|
||||
for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
|
||||
{
|
||||
const FiniteElement *fe = FiniteElementForGeometry((Geometry::Type)g);
|
||||
if (fe != NULL)
|
||||
{
|
||||
return fe;
|
||||
}
|
||||
fe = FiniteElementForGeometry((Geometry::Type)g);
|
||||
if (fe != nullptr) { break; }
|
||||
}
|
||||
return NULL;
|
||||
error_mode = save_error_mode;
|
||||
return fe;
|
||||
}
|
||||
|
||||
int FiniteElementCollection::GetRangeType(int dim) const
|
||||
@@ -643,6 +644,7 @@ LinearFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PYRAMID: return &PyramidFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("LinearFECollection: unknown geometry type.");
|
||||
}
|
||||
return &SegmentFE; // Make some compilers happy
|
||||
@@ -686,6 +688,7 @@ QuadraticFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("QuadraticFECollection: unknown geometry type.");
|
||||
}
|
||||
return &SegmentFE; // Make some compilers happy
|
||||
@@ -726,6 +729,7 @@ QuadraticPosFECollection::FiniteElementForGeometry(
|
||||
case Geometry::SEGMENT: return &SegmentFE;
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("QuadraticPosFECollection: unknown geometry type.");
|
||||
}
|
||||
return NULL; // Make some compilers happy
|
||||
@@ -766,6 +770,7 @@ CubicFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("CubicFECollection: unknown geometry type.");
|
||||
}
|
||||
return &SegmentFE; // Make some compilers happy
|
||||
@@ -832,6 +837,7 @@ CrouzeixRaviartFECollection::FiniteElementForGeometry(
|
||||
case Geometry::TRIANGLE: return &TriangleFE;
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("CrouzeixRaviartFECollection: unknown geometry type.");
|
||||
}
|
||||
return &SegmentFE; // Make some compilers happy
|
||||
@@ -869,6 +875,7 @@ RT0_2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TRIANGLE: return &TriangleFE;
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("RT0_2DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &SegmentFE; // Make some compilers happy
|
||||
@@ -911,6 +918,7 @@ RT1_2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TRIANGLE: return &TriangleFE;
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("RT1_2DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &SegmentFE; // Make some compilers happy
|
||||
@@ -952,6 +960,7 @@ RT2_2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TRIANGLE: return &TriangleFE;
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("RT2_2DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &SegmentFE; // Make some compilers happy
|
||||
@@ -993,6 +1002,7 @@ Const2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TRIANGLE: return &TriangleFE;
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("Const2DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &TriangleFE; // Make some compilers happy
|
||||
@@ -1028,6 +1038,7 @@ LinearDiscont2DFECollection::FiniteElementForGeometry(
|
||||
case Geometry::TRIANGLE: return &TriangleFE;
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("LinearDiscont2DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &TriangleFE; // Make some compilers happy
|
||||
@@ -1063,6 +1074,7 @@ GaussLinearDiscont2DFECollection::FiniteElementForGeometry(
|
||||
case Geometry::TRIANGLE: return &TriangleFE;
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("GaussLinearDiscont2DFECollection:"
|
||||
" unknown geometry type.");
|
||||
}
|
||||
@@ -1097,6 +1109,7 @@ P1OnQuadFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
if (GeomType != Geometry::SQUARE)
|
||||
{
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("P1OnQuadFECollection: unknown geometry type.");
|
||||
}
|
||||
return &QuadrilateralFE;
|
||||
@@ -1131,6 +1144,7 @@ QuadraticDiscont2DFECollection::FiniteElementForGeometry(
|
||||
case Geometry::TRIANGLE: return &TriangleFE;
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("QuadraticDiscont2DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &TriangleFE; // Make some compilers happy
|
||||
@@ -1166,6 +1180,7 @@ QuadraticPosDiscont2DFECollection::FiniteElementForGeometry(
|
||||
{
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("QuadraticPosDiscont2DFECollection: unknown geometry type.");
|
||||
}
|
||||
return NULL; // Make some compilers happy
|
||||
@@ -1196,6 +1211,7 @@ const
|
||||
case Geometry::TRIANGLE: return &TriangleFE;
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("GaussQuadraticDiscont2DFECollection:"
|
||||
" unknown geometry type.");
|
||||
}
|
||||
@@ -1234,6 +1250,7 @@ CubicDiscont2DFECollection::FiniteElementForGeometry(
|
||||
case Geometry::TRIANGLE: return &TriangleFE;
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("CubicDiscont2DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &TriangleFE; // Make some compilers happy
|
||||
@@ -1271,6 +1288,7 @@ LinearNonConf3DFECollection::FiniteElementForGeometry(
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("LinearNonConf3DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &TriangleFE; // Make some compilers happy
|
||||
@@ -1311,6 +1329,7 @@ Const3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PYRAMID: return &PyramidFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("Const3DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &TetrahedronFE; // Make some compilers happy
|
||||
@@ -1352,6 +1371,7 @@ LinearDiscont3DFECollection::FiniteElementForGeometry(
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("LinearDiscont3DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &TetrahedronFE; // Make some compilers happy
|
||||
@@ -1391,6 +1411,7 @@ QuadraticDiscont3DFECollection::FiniteElementForGeometry(
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("QuadraticDiscont3DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &TetrahedronFE; // Make some compilers happy
|
||||
@@ -1432,6 +1453,7 @@ RefinedLinearFECollection::FiniteElementForGeometry(
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("RefinedLinearFECollection: unknown geometry type.");
|
||||
}
|
||||
return &SegmentFE; // Make some compilers happy
|
||||
@@ -1472,6 +1494,7 @@ ND1_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PYRAMID: return &PyramidFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("ND1_3DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &HexahedronFE; // Make some compilers happy
|
||||
@@ -1521,6 +1544,7 @@ RT0_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PYRAMID: return &PyramidFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("RT0_3DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &HexahedronFE; // Make some compilers happy
|
||||
@@ -1570,6 +1594,7 @@ RT1_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
case Geometry::CUBE: return &HexahedronFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("RT1_3DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &HexahedronFE; // Make some compilers happy
|
||||
@@ -1931,6 +1956,7 @@ H1_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
MFEM_ABORT("H1 Pyramid basis functions are not yet supported "
|
||||
"for order > 1.");
|
||||
return NULL;
|
||||
@@ -2311,6 +2337,7 @@ L2_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
MFEM_ABORT("L2 Pyramid basis functions are not yet supported "
|
||||
"for order > 0.");
|
||||
return NULL;
|
||||
@@ -2566,6 +2593,7 @@ RT_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
MFEM_ABORT("RT Pyramid basis functions are not yet supported "
|
||||
"for order > 0.");
|
||||
return NULL;
|
||||
@@ -2851,6 +2879,7 @@ ND_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
MFEM_ABORT("ND Pyramid basis functions are not yet supported "
|
||||
"for order > 1.");
|
||||
return NULL;
|
||||
@@ -3453,6 +3482,7 @@ NURBSFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::SQUARE: return QuadrilateralFE;
|
||||
case Geometry::CUBE: return ParallelepipedFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("NURBSFECollection: unknown geometry type.");
|
||||
}
|
||||
return SegmentFE; // Make some compilers happy
|
||||
|
||||
@@ -233,6 +233,19 @@ protected:
|
||||
void InitVarOrder(int p) const;
|
||||
|
||||
mutable Array<FiniteElementCollection*> var_orders;
|
||||
|
||||
/// How to treat errors in FiniteElementForGeometry() calls.
|
||||
enum ErrorMode
|
||||
{
|
||||
RETURN_NULL, ///< Return NULL on errors
|
||||
RAISE_MFEM_ERROR /**< Raise an MFEM error (default in base class).
|
||||
Sub-classes can ignore this and return NULL. */
|
||||
};
|
||||
|
||||
/// How to treat errors in FiniteElementForGeometry() calls.
|
||||
/** The typical error in derived classes is that no FiniteElement is defined
|
||||
for the given Geometry, or the input is not a valid Geometry. */
|
||||
mutable ErrorMode error_mode = RAISE_MFEM_ERROR;
|
||||
};
|
||||
|
||||
/// Arbitrary order H1-conforming (continuous) finite elements.
|
||||
|
||||
+9
-7
@@ -2056,10 +2056,7 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
|
||||
GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
|
||||
}
|
||||
|
||||
SparseMatrix *R = (elem_geoms.Size() != 1)
|
||||
? new SparseMatrix(ndofs*vdim, old_ndofs*vdim) // variable row size
|
||||
: new SparseMatrix(ndofs*vdim, old_ndofs*vdim,
|
||||
localR[elem_geoms[0]].SizeI());
|
||||
SparseMatrix *R = new SparseMatrix(ndofs*vdim, old_ndofs*vdim);
|
||||
|
||||
Array<int> mark(R->Height());
|
||||
mark = 0;
|
||||
@@ -2069,6 +2066,7 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
|
||||
|
||||
MFEM_ASSERT(dtrans.embeddings.Size() == old_elem_dof->Size(), "");
|
||||
|
||||
bool is_dg = FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS;
|
||||
int num_marked = 0;
|
||||
for (int k = 0; k < dtrans.embeddings.Size(); k++)
|
||||
{
|
||||
@@ -2091,10 +2089,11 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
|
||||
int r = DofToVDof(dofs[i], vd);
|
||||
int m = (r >= 0) ? r : (-1 - r);
|
||||
|
||||
if (!mark[m])
|
||||
if (is_dg || !mark[m])
|
||||
{
|
||||
lR.GetRow(i, row);
|
||||
R->SetRow(r, old_vdofs, row);
|
||||
|
||||
mark[m] = 1;
|
||||
num_marked++;
|
||||
}
|
||||
@@ -2102,8 +2101,11 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_VERIFY(num_marked == R->Height(),
|
||||
"internal error: not all rows of R were set.");
|
||||
if (!is_dg)
|
||||
{
|
||||
MFEM_VERIFY(num_marked == R->Height(),
|
||||
"internal error: not all rows of R were set.");
|
||||
}
|
||||
|
||||
R->Finalize(); // no-op if fixed width
|
||||
return R;
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
/// Construct an empty finite element space hierarchy. This is useful if the
|
||||
/// hierarchy is constructed by coarsening a fine space, rather than refining
|
||||
/// a coarse space.
|
||||
FiniteElementSpaceHierarchy() { }
|
||||
FiniteElementSpaceHierarchy() = default;
|
||||
|
||||
/// @brief Constructs a space hierarchy with the given mesh and space on the
|
||||
/// coarsest level.
|
||||
@@ -91,6 +91,7 @@ public:
|
||||
class ParFiniteElementSpaceHierarchy : public FiniteElementSpaceHierarchy
|
||||
{
|
||||
public:
|
||||
ParFiniteElementSpaceHierarchy() = default;
|
||||
/// @brief Constructs a parallel space hierarchy with the given mesh and spaces
|
||||
/// on level zero.
|
||||
/** The ownership of the mesh and space may be transferred to the
|
||||
|
||||
+5
-17
@@ -1441,21 +1441,13 @@ void GridFunction::GetDerivative(int comp, int der_comp, GridFunction &der)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GridFunction::GetVectorGradientHat(
|
||||
ElementTransformation &T, DenseMatrix &gh) const
|
||||
{
|
||||
int elNo = T.ElementNo;
|
||||
const FiniteElement *FElem = fes->GetFE(elNo);
|
||||
const FiniteElement *FElem = fes->GetFE(T.ElementNo);
|
||||
int dim = FElem->GetDim(), dof = FElem->GetDof();
|
||||
Array<int> vdofs;
|
||||
DofTransformation * doftrans = fes->GetElementVDofs(elNo, vdofs);
|
||||
Vector loc_data;
|
||||
GetSubVector(vdofs, loc_data);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
}
|
||||
GetElementDofValues(T.ElementNo, loc_data);
|
||||
// assuming scalar FE
|
||||
int vdim = fes->GetVDim();
|
||||
DenseMatrix dshape(dof, dim);
|
||||
@@ -1660,6 +1652,7 @@ void GridFunction::GetGradient(ElementTransformation &T, Vector &grad) const
|
||||
const FiniteElement *fe = fes->GetFE(T.ElementNo);
|
||||
MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
|
||||
"invalid FE map type");
|
||||
MFEM_ASSERT(fes->GetVDim() == 1, "Defined for scalar functions.");
|
||||
int spaceDim = fes->GetMesh()->SpaceDimension();
|
||||
int dim = fe->GetDim(), dof = fe->GetDof();
|
||||
DenseMatrix dshape(dof, dim);
|
||||
@@ -1728,13 +1721,8 @@ void GridFunction::GetGradients(ElementTransformation &tr,
|
||||
MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type");
|
||||
DenseMatrix dshape(fe->GetDof(), fe->GetDim());
|
||||
Vector lval, gh(fe->GetDim()), gcol;
|
||||
Array<int> dofs;
|
||||
DofTransformation * doftrans = fes->GetElementDofs(elNo, dofs);
|
||||
GetSubVector(dofs, lval);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(lval);
|
||||
}
|
||||
|
||||
GetElementDofValues(tr.ElementNo, lval);
|
||||
grad.SetSize(fe->GetDim(), ir.GetNPoints());
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
{
|
||||
|
||||
+17
-2
@@ -48,8 +48,6 @@ protected:
|
||||
|
||||
void SaveSTLTri(std::ostream &out, double p1[], double p2[], double p3[]);
|
||||
|
||||
void GetVectorGradientHat(ElementTransformation &T, DenseMatrix &gh) const;
|
||||
|
||||
// Project the delta coefficient without scaling and return the (local)
|
||||
// integral of the projection.
|
||||
void ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff,
|
||||
@@ -329,17 +327,34 @@ public:
|
||||
|
||||
void GetCurl(ElementTransformation &tr, Vector &curl) const;
|
||||
|
||||
/** @brief Gradient of a scalar function at a quadrature point.
|
||||
|
||||
@note It is assumed that the IntegrationPoint of interest has been
|
||||
specified by ElementTransformation::SetIntPoint() before calling
|
||||
GetGradient().
|
||||
|
||||
@note Can be used from a ParGridFunction when @a tr is an
|
||||
ElementTransformation of a face-neighbor element and face-neighbor data
|
||||
has been exchanged. */
|
||||
void GetGradient(ElementTransformation &tr, Vector &grad) const;
|
||||
|
||||
/// Extension of GetGradient(...) for a collection of IntegrationPoints.
|
||||
void GetGradients(ElementTransformation &tr, const IntegrationRule &ir,
|
||||
DenseMatrix &grad) const;
|
||||
|
||||
/// Extension of GetGradient(...) for a collection of IntegrationPoints.
|
||||
void GetGradients(const int elem, const IntegrationRule &ir,
|
||||
DenseMatrix &grad) const
|
||||
{ GetGradients(*fes->GetElementTransformation(elem), ir, grad); }
|
||||
|
||||
/** @brief Compute the vector gradient with respect to the physical element
|
||||
variable. */
|
||||
void GetVectorGradient(ElementTransformation &tr, DenseMatrix &grad) const;
|
||||
|
||||
/** @brief Compute the vector gradient with respect to the reference element
|
||||
variable. */
|
||||
void GetVectorGradientHat(ElementTransformation &T, DenseMatrix &gh) const;
|
||||
|
||||
/** Compute \f$ (\int_{\Omega} (*this) \psi_i)/(\int_{\Omega} \psi_i) \f$,
|
||||
where \f$ \psi_i \f$ are the basis functions for the FE space of avgs.
|
||||
Both FE spaces should be scalar and on the same mesh. */
|
||||
|
||||
+10
-6
@@ -37,7 +37,7 @@ FindPointsGSLIB::FindPointsGSLIB()
|
||||
fec_map_lin(NULL),
|
||||
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
|
||||
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
|
||||
avgtype(AvgType::ARITHMETIC)
|
||||
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
|
||||
{
|
||||
mesh_split.SetSize(4);
|
||||
ir_split.SetSize(4);
|
||||
@@ -84,7 +84,7 @@ FindPointsGSLIB::FindPointsGSLIB(MPI_Comm comm_)
|
||||
fec_map_lin(NULL),
|
||||
fdata2D(NULL), fdata3D(NULL), cr(NULL), gsl_comm(NULL),
|
||||
dim(-1), points_cnt(0), setupflag(false), default_interp_value(0),
|
||||
avgtype(AvgType::ARITHMETIC)
|
||||
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
|
||||
{
|
||||
mesh_split.SetSize(4);
|
||||
ir_split.SetSize(4);
|
||||
@@ -223,10 +223,12 @@ void FindPointsGSLIB::FindPoints(const Vector &point_pos,
|
||||
// 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)
|
||||
if (gsl_code[i] == 2 ||
|
||||
(gsl_code[i] == 1 && gsl_dist(i) > bdr_tol))
|
||||
{
|
||||
gsl_elem[i] = 0;
|
||||
for (int d = 0; d < dim; d++) { gsl_ref(i*dim + d) = -1.; }
|
||||
gsl_code[i] = 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,7 +573,7 @@ void FindPointsGSLIB::GetNodalValues(const GridFunction *gf_in,
|
||||
const int pts_el = std::pow(dof_1D, dim);
|
||||
const int pts_cnt = NE_split_total * pts_el;
|
||||
node_vals.SetSize(vdim * pts_cnt);
|
||||
node_vals *= 0;
|
||||
node_vals = 0.0;
|
||||
|
||||
int gsl_mesh_pt_index = 0;
|
||||
|
||||
@@ -1153,7 +1155,7 @@ void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
|
||||
distfint.SetSize(pts_cnt);
|
||||
if (!gfmax)
|
||||
{
|
||||
distfint = 0.;
|
||||
distfint = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1248,10 +1250,12 @@ void OversetFindPointsGSLIB::FindPoints(const Vector &point_pos,
|
||||
// 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)
|
||||
if (gsl_code[i] == 2 ||
|
||||
(gsl_code[i] == 1 && gsl_dist(i) > bdr_tol))
|
||||
{
|
||||
gsl_elem[i] = 0;
|
||||
for (int d = 0; d < dim; d++) { gsl_ref(i*dim + d) = -1.; }
|
||||
gsl_code[i] = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,11 @@ namespace mfem
|
||||
* 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.
|
||||
* For points returned as found on `element border`, the point is either
|
||||
* on an element edge/face or near the domain boundary, and gslib also
|
||||
* returns a distance to the border. Points near (but outside) the domain
|
||||
* boundary must then be marked as not found using the distance returned
|
||||
* by gslib.
|
||||
*
|
||||
* 3. Interpolate - Interpolates any grid function at the points found using 2.
|
||||
*
|
||||
@@ -70,6 +75,8 @@ protected:
|
||||
Array<int> split_element_map;
|
||||
Array<int> split_element_index;
|
||||
int NE_split_total;
|
||||
// Tolerance to ignore points just outside elements at the boundary.
|
||||
double bdr_tol;
|
||||
|
||||
/// Use GSLIB for communication and interpolation
|
||||
virtual void InterpolateH1(const GridFunction &field_in, Vector &field_out);
|
||||
@@ -181,6 +188,14 @@ public:
|
||||
default_interp_value = interp_value_;
|
||||
}
|
||||
|
||||
/// Set the tolerance for detecting points outside the 'curvilinear' boundary
|
||||
/// that gslib may return as found on the boundary. Points found on boundary
|
||||
/// with distance greater than @ bdr_tol are marked as not found.
|
||||
virtual void SetDistanceToleranceForPointsFoundOnBoundary(double bdr_tol_)
|
||||
{
|
||||
bdr_tol = bdr_tol_;
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
|
||||
@@ -347,14 +347,12 @@ ParallelEliminateEssentialBC(const Array<int> &bdr_attr_is_ess,
|
||||
void ParBilinearForm::TrueAddMult(const Vector &x, Vector &y, const double a)
|
||||
const
|
||||
{
|
||||
if (Xaux.ParFESpace() != pfes)
|
||||
{
|
||||
Xaux.SetSpace(pfes);
|
||||
Yaux.SetSpace(pfes);
|
||||
Ytmp.SetSize(pfes->GetTrueVSize());
|
||||
}
|
||||
const Operator *P = pfes->GetProlongationMatrix();
|
||||
Xaux.SetSize(P->Height());
|
||||
Yaux.SetSize(P->Height());
|
||||
Ytmp.SetSize(P->Width());
|
||||
|
||||
Xaux.Distribute(&x);
|
||||
P->Mult(x, Xaux);
|
||||
if (ext)
|
||||
{
|
||||
ext->Mult(Xaux, Yaux);
|
||||
@@ -366,8 +364,8 @@ const
|
||||
" implemented");
|
||||
mat->Mult(Xaux, Yaux);
|
||||
}
|
||||
pfes->GetProlongationMatrix()->MultTranspose(Yaux, Ytmp);
|
||||
y.Add(a,Ytmp);
|
||||
P->MultTranspose(Yaux, Ytmp);
|
||||
y.Add(a, Ytmp);
|
||||
}
|
||||
|
||||
void ParBilinearForm::FormLinearSystem(
|
||||
|
||||
@@ -31,9 +31,8 @@ class ParBilinearForm : public BilinearForm
|
||||
protected:
|
||||
ParFiniteElementSpace *pfes; ///< Points to the same object as #fes
|
||||
|
||||
/// Auxiliary objects used in TrueAddMult().
|
||||
mutable ParGridFunction Xaux, Yaux;
|
||||
mutable Vector Ytmp;
|
||||
/// Auxiliary vectors used in TrueAddMult(): L-, L-, and T-vector, resp.
|
||||
mutable Vector Xaux, Yaux, Ytmp;
|
||||
|
||||
OperatorHandle p_mat, p_mat_e;
|
||||
|
||||
|
||||
+5
-2
@@ -3025,6 +3025,8 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
|
||||
Array<char> mark(diag->Height());
|
||||
mark = 0;
|
||||
|
||||
bool is_dg = FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS;
|
||||
|
||||
for (int k = 0; k < dtrans.embeddings.Size(); k++)
|
||||
{
|
||||
const Embedding &emb = dtrans.embeddings[k];
|
||||
@@ -3053,7 +3055,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
|
||||
int r = DofToVDof(dofs[i], vd);
|
||||
int m = (r >= 0) ? r : (-1 - r);
|
||||
|
||||
if (!mark[m])
|
||||
if (is_dg || !mark[m])
|
||||
{
|
||||
lR.GetRow(i, row);
|
||||
diag->SetRow(r, old_vdofs, row);
|
||||
@@ -3105,7 +3107,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
|
||||
int r = DofToVDof(dofs[i], vd);
|
||||
int m = (r >= 0) ? r : (-1 - r);
|
||||
|
||||
if (!mark[m])
|
||||
if (is_dg || !mark[m])
|
||||
{
|
||||
lR.GetRow(i, row);
|
||||
MFEM_ASSERT(ldof[geom] == row.Size(), "");
|
||||
@@ -3122,6 +3124,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
messages.clear();
|
||||
offd->Finalize(0);
|
||||
offd->SetWidth(col_map.size());
|
||||
|
||||
+132
-19
@@ -48,8 +48,7 @@ void TMOP_Combo_QualityMetric::EvalP(const DenseMatrix &Jpt,
|
||||
for (int i = 0; i < tmop_q_arr.Size(); i++)
|
||||
{
|
||||
tmop_q_arr[i]->EvalP(Jpt, Pt);
|
||||
Pt *= wt_arr[i];
|
||||
P += Pt;
|
||||
P.Add(wt_arr[i], Pt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,12 +61,109 @@ void TMOP_Combo_QualityMetric::AssembleH(const DenseMatrix &Jpt,
|
||||
for (int i = 0; i < tmop_q_arr.Size(); i++)
|
||||
{
|
||||
At = 0.0;
|
||||
tmop_q_arr[i]->AssembleH(Jpt, DS, weight, At);
|
||||
At *= wt_arr[i];
|
||||
tmop_q_arr[i]->AssembleH(Jpt, DS, weight * wt_arr[i], At);
|
||||
A += At;
|
||||
}
|
||||
}
|
||||
|
||||
void TMOP_Combo_QualityMetric::
|
||||
ComputeBalancedWeights(const GridFunction &nodes,
|
||||
const TargetConstructor &tc, Vector &weights) const
|
||||
{
|
||||
const int m_cnt = tmop_q_arr.Size();
|
||||
Vector averages;
|
||||
ComputeAvgMetrics(nodes, tc, averages);
|
||||
weights.SetSize(m_cnt);
|
||||
|
||||
// For [ combo_A_B_C = a m_A + b m_B + c m_C ] we would have:
|
||||
// a = BC / (AB + AC + BC), b = AC / (AB + AC + BC), c = AB / (AB + AC + BC),
|
||||
// where A = avg_m_A, B = avg_m_B, C = avg_m_C.
|
||||
// Nested loop to avoid division, as some avg may be 0.
|
||||
Vector products_no_m(m_cnt); products_no_m = 1.0;
|
||||
for (int m_p = 0; m_p < m_cnt; m_p++)
|
||||
{
|
||||
for (int m_a = 0; m_a < m_cnt; m_a++)
|
||||
{
|
||||
if (m_p != m_a) { products_no_m(m_p) *= averages(m_a); }
|
||||
}
|
||||
}
|
||||
const double pnm_sum = products_no_m.Sum();
|
||||
|
||||
if (pnm_sum == 0.0) { weights = 1.0 / m_cnt; return; }
|
||||
for (int m = 0; m < m_cnt; m++) { weights(m) = products_no_m(m) / pnm_sum; }
|
||||
|
||||
MFEM_ASSERT(fabs(weights.Sum() - 1.0) < 1e-14,
|
||||
"Error: sum should be 1 always: " << weights.Sum());
|
||||
}
|
||||
|
||||
void TMOP_Combo_QualityMetric::ComputeAvgMetrics(const GridFunction &nodes,
|
||||
const TargetConstructor &tc,
|
||||
Vector &averages) const
|
||||
{
|
||||
const int m_cnt = tmop_q_arr.Size(),
|
||||
NE = nodes.FESpace()->GetNE(),
|
||||
dim = nodes.FESpace()->GetMesh()->Dimension();
|
||||
|
||||
averages.SetSize(m_cnt);
|
||||
|
||||
// Integrals of all metrics.
|
||||
Array<int> pos_dofs;
|
||||
averages = 0.0;
|
||||
double volume = 0.0;
|
||||
for (int e = 0; e < NE; e++)
|
||||
{
|
||||
const FiniteElement &fe_pos = *nodes.FESpace()->GetFE(e);
|
||||
const IntegrationRule &ir = IntRules.Get(fe_pos.GetGeomType(),
|
||||
2 * fe_pos.GetOrder());
|
||||
const int nsp = ir.GetNPoints(), dof = fe_pos.GetDof();
|
||||
|
||||
DenseMatrix dshape(dof, dim);
|
||||
DenseMatrix pos(dof, dim);
|
||||
pos.SetSize(dof, dim);
|
||||
Vector posV(pos.Data(), dof * dim);
|
||||
|
||||
nodes.FESpace()->GetElementVDofs(e, pos_dofs);
|
||||
nodes.GetSubVector(pos_dofs, posV);
|
||||
|
||||
DenseTensor W(dim, dim, nsp);
|
||||
DenseMatrix Winv(dim), T(dim), A(dim);
|
||||
tc.ComputeElementTargets(e, fe_pos, ir, posV, W);
|
||||
|
||||
for (int q = 0; q < nsp; q++)
|
||||
{
|
||||
const DenseMatrix &Wj = W(q);
|
||||
CalcInverse(Wj, Winv);
|
||||
|
||||
const IntegrationPoint &ip = ir.IntPoint(q);
|
||||
fe_pos.CalcDShape(ip, dshape);
|
||||
MultAtB(pos, dshape, A);
|
||||
Mult(A, Winv, T);
|
||||
|
||||
const double w_detA = ip.weight * A.Det();
|
||||
for (int m = 0; m < m_cnt; m++)
|
||||
{
|
||||
tmop_q_arr[m]->SetTargetJacobian(Wj);
|
||||
averages(m) += tmop_q_arr[m]->EvalW(T) * w_detA;
|
||||
}
|
||||
volume += w_detA;
|
||||
}
|
||||
}
|
||||
|
||||
// Parallel case.
|
||||
#ifdef MFEM_USE_MPI
|
||||
auto par_nodes = dynamic_cast<const ParGridFunction *>(&nodes);
|
||||
if (par_nodes)
|
||||
{
|
||||
MPI_Allreduce(MPI_IN_PLACE, averages.GetData(), m_cnt,
|
||||
MPI_DOUBLE, MPI_SUM, par_nodes->ParFESpace()->GetComm());
|
||||
MPI_Allreduce(MPI_IN_PLACE, &volume, 1, MPI_DOUBLE, MPI_SUM,
|
||||
par_nodes->ParFESpace()->GetComm());
|
||||
}
|
||||
#endif
|
||||
|
||||
averages /= volume;
|
||||
}
|
||||
|
||||
double TMOP_WorstCaseUntangleOptimizer_Metric::EvalW(const DenseMatrix &Jpt)
|
||||
const
|
||||
{
|
||||
@@ -728,30 +824,30 @@ void TMOP_Metric_301::AssembleH(const DenseMatrix &Jpt,
|
||||
// dW = (1/6)*[z2*dI1b + z1*dI2b], z1 = sqrt(I1b/I2b), z2 = sqrt(I2b/I1b)
|
||||
// ddW = (1/6)*[dI1b x dz2 + z2*ddI1b + dI2b x dz1 + z1*ddI2b]
|
||||
//
|
||||
// dz1 = (1/2)*sqrt(I2b/I1b) [ (1/I2b)*dI1b + (I1b/(I2b*I2b))*dI2b ]
|
||||
// = (1/2)/sqrt(I1b*I2b) [ dI1b + (I1b/I2b)*dI2b ]
|
||||
// dz2 = (1/2)/sqrt(I1b*I2b) [ (I2b/I1b)*dI1b + dI2b ]
|
||||
// dz1 = (1/2)*sqrt(I2b/I1b) [ (1/I2b)*dI1b - (I1b/(I2b*I2b))*dI2b ]
|
||||
// = (1/2)/sqrt(I1b*I2b) [ dI1b - (I1b/I2b)*dI2b ]
|
||||
// dz2 = (1/2)/sqrt(I1b*I2b) [ dI2b - (I2b/I1b)*dI1b ]
|
||||
//
|
||||
// dI1b x dz2 + dI2b x dz1 =
|
||||
// (1/2)/sqrt(I1b*I2b) dI1b x [ (I2b/I1b)*dI1b + dI2b ] +
|
||||
// (1/2)/sqrt(I1b*I2b) dI2b x [ dI1b + (I1b/I2b)*dI2b ] =
|
||||
// (1/2)/sqrt(I1b*I2b) [sqrt(I2b/I1b)*dI1b + sqrt(I1b/I2b)*dI2b] x
|
||||
// [sqrt(I2b/I1b)*dI1b + sqrt(I1b/I2b)*dI2b] =
|
||||
// (1/2)/sqrt(I1b*I2b) [ 6*dW x 6*dW ] =
|
||||
// (1/2)*(I1b*I2b)^{-3/2} (I2b*dI1b + I1b*dI2b) x (I2b*dI1b + I1b*dI2b)
|
||||
// (1/2)/sqrt(I1b*I2b) dI1b x [ dI2b - (I2b/I1b)*dI1b ] +
|
||||
// (1/2)/sqrt(I1b*I2b) dI2b x [ dI1b - (I1b/I2b)*dI2b ] =
|
||||
// (1/2)/sqrt(I1b*I2b) [sqrt(I1b/I2b)*dI2b - sqrt(I2b/I1b)*dI1b] x
|
||||
// [sqrt(I2b/I1b)*dI1b - sqrt(I1b/I2b)*dI2b] =
|
||||
// (1/2)*(I1b*I2b)^{-3/2} (I1b*dI2b - I2b*dI1b) x (I2b*dI1b - I1b*dI2b)
|
||||
// and the last two parentheses are the same up to a sign.
|
||||
//
|
||||
// z1 = I1b/sqrt(I1b*I2b), z2 = I2b/sqrt(I1b*I2b)
|
||||
|
||||
ie.SetJacobian(Jpt.GetData());
|
||||
ie.SetDerivativeMatrix(DS.Height(), DS.GetData());
|
||||
double d_I1b_I2b_data[9];
|
||||
DenseMatrix d_I1b_I2b(d_I1b_I2b_data, 3, 3);
|
||||
Add(ie.Get_I2b(), ie.Get_dI1b(), ie.Get_I1b(), ie.Get_dI2b(), d_I1b_I2b);
|
||||
double X_data[9];
|
||||
DenseMatrix X(X_data, 3, 3);
|
||||
Add(- ie.Get_I2b(), ie.Get_dI1b(), ie.Get_I1b(), ie.Get_dI2b(), X);
|
||||
const double I1b_I2b = ie.Get_I1b()*ie.Get_I2b();
|
||||
const double a = weight/(6*std::sqrt(I1b_I2b));
|
||||
ie.Assemble_ddI1b(a*ie.Get_I2b(), A.GetData());
|
||||
ie.Assemble_ddI2b(a*ie.Get_I1b(), A.GetData());
|
||||
ie.Assemble_TProd(a/(2*I1b_I2b), d_I1b_I2b_data, A.GetData());
|
||||
ie.Assemble_TProd(-a/(2*I1b_I2b), X_data, A.GetData());
|
||||
}
|
||||
|
||||
double TMOP_Metric_302::EvalWMatrixForm(const DenseMatrix &Jpt) const
|
||||
@@ -2798,8 +2894,6 @@ void TMOP_Integrator::GetSurfaceFittingErrors(double &err_avg, double &err_max)
|
||||
loc_sum += std::abs((*surf_fit_gf)(i));
|
||||
}
|
||||
}
|
||||
err_avg = loc_sum / loc_cnt;
|
||||
err_max = loc_max;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
if (targetC->Parallel() == false) { return; }
|
||||
@@ -2809,6 +2903,9 @@ void TMOP_Integrator::GetSurfaceFittingErrors(double &err_avg, double &err_max)
|
||||
MPI_Allreduce(&loc_cnt, &glob_cnt, 1, MPI_INT, MPI_SUM, comm);
|
||||
MPI_Allreduce(&loc_sum, &err_avg, 1, MPI_DOUBLE, MPI_SUM, comm);
|
||||
err_avg = err_avg / glob_cnt;
|
||||
#else
|
||||
err_avg = loc_sum / loc_cnt;
|
||||
err_max = loc_max;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3997,6 +4094,14 @@ void TMOP_Integrator::EnableFiniteDifferences(const GridFunction &x)
|
||||
ComputeFDh(x,*fes);
|
||||
if (discr_tc)
|
||||
{
|
||||
#ifdef MFEM_USE_GSLIB
|
||||
const AdaptivityEvaluator *ae = discr_tc->GetAdaptivityEvaluator();
|
||||
if (dynamic_cast<const InterpolatorFP *>(ae))
|
||||
{
|
||||
MFEM_ABORT("Using GSLIB-based interpolation with finite differences"
|
||||
"requires careful consideration. Contact TMOP team.");
|
||||
}
|
||||
#endif
|
||||
discr_tc->UpdateTargetSpecification(x, false, fes->GetOrdering());
|
||||
discr_tc->UpdateGradientTargetSpecification(x, dx, false, fes->GetOrdering());
|
||||
discr_tc->UpdateHessianTargetSpecification(x, dx, false, fes->GetOrdering());
|
||||
@@ -4011,6 +4116,14 @@ void TMOP_Integrator::EnableFiniteDifferences(const ParGridFunction &x)
|
||||
ComputeFDh(x,*pfes);
|
||||
if (discr_tc)
|
||||
{
|
||||
#ifdef MFEM_USE_GSLIB
|
||||
const AdaptivityEvaluator *ae = discr_tc->GetAdaptivityEvaluator();
|
||||
if (dynamic_cast<const InterpolatorFP *>(ae))
|
||||
{
|
||||
MFEM_ABORT("Using GSLIB-based interpolation with finite differences"
|
||||
"requires careful consideration. Contact TMOP team.");
|
||||
}
|
||||
#endif
|
||||
discr_tc->UpdateTargetSpecification(x, false, pfes->GetOrdering());
|
||||
discr_tc->UpdateGradientTargetSpecification(x, dx, false, pfes->GetOrdering());
|
||||
discr_tc->UpdateHessianTargetSpecification(x, dx, false, pfes->GetOrdering());
|
||||
|
||||
+76
-56
@@ -78,11 +78,14 @@ public:
|
||||
virtual int Id() const { return 0; }
|
||||
};
|
||||
|
||||
/// Abstract class used to define combination of metrics with constant coefficients.
|
||||
class TargetConstructor;
|
||||
|
||||
/// Abstract class used to define explicit combination of metrics with constant
|
||||
/// coefficients.
|
||||
class TMOP_Combo_QualityMetric : public TMOP_QualityMetric
|
||||
{
|
||||
protected:
|
||||
Array<TMOP_QualityMetric *> tmop_q_arr; //not owned
|
||||
Array<TMOP_QualityMetric *> tmop_q_arr; //the metrics are not owned
|
||||
Array<double> wt_arr;
|
||||
|
||||
public:
|
||||
@@ -108,6 +111,25 @@ public:
|
||||
|
||||
virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS,
|
||||
const double weight, DenseMatrix &A) const;
|
||||
|
||||
/// Computes the averages of all metrics (integral of metric / volume).
|
||||
/// Works in parallel when called with a ParGridFunction.
|
||||
void ComputeAvgMetrics(const GridFunction &nodes,
|
||||
const TargetConstructor &tc,
|
||||
Vector &averages) const;
|
||||
|
||||
/// Computes weights so that the averages of all metrics are equal, and the
|
||||
/// weights sum to one. Works in parallel when called with a ParGridFunction.
|
||||
void ComputeBalancedWeights(const GridFunction &nodes,
|
||||
const TargetConstructor &tc,
|
||||
Vector &weights) const;
|
||||
|
||||
/// Changes the weights of the metrics in the combination.
|
||||
void SetWeights(const Vector &weights)
|
||||
{
|
||||
MFEM_VERIFY(tmop_q_arr.Size() == weights.Size(), "Incorrect #weights");
|
||||
for (int i = 0; i < tmop_q_arr.Size(); i++) { wt_arr[i] = weights(i); }
|
||||
}
|
||||
};
|
||||
|
||||
/// Simultaneous Untangler + Worst Case Improvement Metric
|
||||
@@ -272,6 +294,7 @@ public:
|
||||
};
|
||||
|
||||
/// 2D barrier shape (S) metric (polyconvex).
|
||||
/// Grade - A.
|
||||
class TMOP_Metric_002 : public TMOP_QualityMetric
|
||||
{
|
||||
protected:
|
||||
@@ -293,6 +316,7 @@ public:
|
||||
};
|
||||
|
||||
/// 2D non-barrier shape (S) metric.
|
||||
/// Grade - F.
|
||||
class TMOP_Metric_004 : public TMOP_QualityMetric
|
||||
{
|
||||
protected:
|
||||
@@ -378,7 +402,8 @@ public:
|
||||
const double weight, DenseMatrix &A) const;
|
||||
};
|
||||
|
||||
/// 2D barrier (not a shape) metric (polyconvex).
|
||||
/// 2D barrier shape metric (polyconvex).
|
||||
/// Grade - A.
|
||||
class TMOP_Metric_050 : public TMOP_QualityMetric
|
||||
{
|
||||
protected:
|
||||
@@ -395,6 +420,7 @@ public:
|
||||
};
|
||||
|
||||
/// 2D non-barrier size (V) metric (not polyconvex).
|
||||
/// Grade - F.
|
||||
class TMOP_Metric_055 : public TMOP_QualityMetric
|
||||
{
|
||||
protected:
|
||||
@@ -412,6 +438,7 @@ public:
|
||||
};
|
||||
|
||||
/// 2D barrier size (V) metric (polyconvex).
|
||||
/// Grade - C.
|
||||
class TMOP_Metric_056 : public TMOP_QualityMetric
|
||||
{
|
||||
protected:
|
||||
@@ -449,29 +476,29 @@ public:
|
||||
};
|
||||
|
||||
/// 2D non-barrier Shape+Size (VS) metric.
|
||||
/// Grade - F.
|
||||
class TMOP_Metric_066 : public TMOP_Combo_QualityMetric
|
||||
{
|
||||
protected:
|
||||
mutable InvariantsEvaluator2D<double> ie;
|
||||
double gamma;
|
||||
TMOP_QualityMetric *sh_metric, *sz_metric;
|
||||
|
||||
public:
|
||||
TMOP_Metric_066(double gamma_) : gamma(gamma_),
|
||||
sh_metric(new TMOP_Metric_004),
|
||||
sz_metric(new TMOP_Metric_055)
|
||||
TMOP_Metric_066(double gamma)
|
||||
: sh_metric(new TMOP_Metric_004), sz_metric(new TMOP_Metric_055)
|
||||
{
|
||||
// (1-gamma) mu_4 + gamma mu_55
|
||||
AddQualityMetric(sh_metric, 1.-gamma_);
|
||||
AddQualityMetric(sz_metric, gamma_);
|
||||
AddQualityMetric(sh_metric, 1.-gamma);
|
||||
AddQualityMetric(sz_metric, gamma);
|
||||
}
|
||||
virtual int Id() const { return 66; }
|
||||
double GetGamma() const { return gamma; }
|
||||
double GetGamma() const { return wt_arr[1]; }
|
||||
|
||||
virtual ~TMOP_Metric_066() { delete sh_metric; delete sz_metric; }
|
||||
};
|
||||
|
||||
/// 2D barrier size (V) metric (polyconvex).
|
||||
/// Grade - C.
|
||||
class TMOP_Metric_077 : public TMOP_QualityMetric
|
||||
{
|
||||
protected:
|
||||
@@ -490,24 +517,24 @@ public:
|
||||
};
|
||||
|
||||
/// 2D barrier Shape+Size (VS) metric (polyconvex).
|
||||
/// Grade - A.
|
||||
class TMOP_Metric_080 : public TMOP_Combo_QualityMetric
|
||||
{
|
||||
protected:
|
||||
mutable InvariantsEvaluator2D<double> ie;
|
||||
double gamma;
|
||||
TMOP_QualityMetric *sh_metric, *sz_metric;
|
||||
|
||||
public:
|
||||
TMOP_Metric_080(double gamma_) : gamma(gamma_),
|
||||
sh_metric(new TMOP_Metric_002),
|
||||
sz_metric(new TMOP_Metric_077)
|
||||
TMOP_Metric_080(double gamma)
|
||||
: sh_metric(new TMOP_Metric_002), sz_metric(new TMOP_Metric_077)
|
||||
{
|
||||
// (1-gamma) mu_2 + gamma mu_77
|
||||
AddQualityMetric(sh_metric, 1.-gamma_);
|
||||
AddQualityMetric(sz_metric, gamma_);
|
||||
AddQualityMetric(sh_metric, 1.0 - gamma);
|
||||
AddQualityMetric(sz_metric, gamma);
|
||||
}
|
||||
|
||||
virtual int Id() const { return 80; }
|
||||
double GetGamma() const { return gamma; }
|
||||
double GetGamma() const { return wt_arr[1]; }
|
||||
|
||||
virtual ~TMOP_Metric_080() { delete sh_metric; delete sz_metric; }
|
||||
};
|
||||
@@ -808,17 +835,15 @@ class TMOP_Metric_328 : public TMOP_Combo_QualityMetric
|
||||
{
|
||||
protected:
|
||||
mutable InvariantsEvaluator2D<double> ie;
|
||||
double gamma;
|
||||
TMOP_QualityMetric *sh_metric, *sz_metric;
|
||||
|
||||
public:
|
||||
TMOP_Metric_328(double gamma_) : gamma(gamma_),
|
||||
sh_metric(new TMOP_Metric_301),
|
||||
sz_metric(new TMOP_Metric_316)
|
||||
TMOP_Metric_328(double gamma)
|
||||
: sh_metric(new TMOP_Metric_301), sz_metric(new TMOP_Metric_316)
|
||||
{
|
||||
// (1-gamma) mu_301 + gamma mu_316
|
||||
AddQualityMetric(sh_metric, 1.-gamma_);
|
||||
AddQualityMetric(sz_metric, gamma_);
|
||||
AddQualityMetric(sh_metric, 1.-gamma);
|
||||
AddQualityMetric(sz_metric, gamma);
|
||||
}
|
||||
|
||||
virtual ~TMOP_Metric_328() { delete sh_metric; delete sz_metric; }
|
||||
@@ -828,21 +853,19 @@ public:
|
||||
class TMOP_Metric_332 : public TMOP_Combo_QualityMetric
|
||||
{
|
||||
protected:
|
||||
double gamma;
|
||||
TMOP_QualityMetric *sh_metric, *sz_metric;
|
||||
|
||||
public:
|
||||
TMOP_Metric_332(double gamma_) : gamma(gamma_),
|
||||
sh_metric(new TMOP_Metric_302),
|
||||
sz_metric(new TMOP_Metric_315)
|
||||
TMOP_Metric_332(double gamma)
|
||||
: sh_metric(new TMOP_Metric_302), sz_metric(new TMOP_Metric_315)
|
||||
{
|
||||
// (1-gamma) mu_302 + gamma mu_315
|
||||
AddQualityMetric(sh_metric, 1.-gamma_);
|
||||
AddQualityMetric(sz_metric, gamma_);
|
||||
AddQualityMetric(sh_metric, 1.-gamma);
|
||||
AddQualityMetric(sz_metric, gamma);
|
||||
}
|
||||
|
||||
virtual int Id() const { return 332; }
|
||||
double GetGamma() const { return gamma; }
|
||||
double GetGamma() const { return wt_arr[1]; }
|
||||
|
||||
virtual ~TMOP_Metric_332() { delete sh_metric; delete sz_metric; }
|
||||
};
|
||||
@@ -852,17 +875,15 @@ class TMOP_Metric_333 : public TMOP_Combo_QualityMetric
|
||||
{
|
||||
protected:
|
||||
mutable InvariantsEvaluator2D<double> ie;
|
||||
double gamma;
|
||||
TMOP_QualityMetric *sh_metric, *sz_metric;
|
||||
|
||||
public:
|
||||
TMOP_Metric_333(double gamma_) : gamma(gamma_),
|
||||
sh_metric(new TMOP_Metric_302),
|
||||
sz_metric(new TMOP_Metric_316)
|
||||
TMOP_Metric_333(double gamma)
|
||||
: sh_metric(new TMOP_Metric_302), sz_metric(new TMOP_Metric_316)
|
||||
{
|
||||
// (1-gamma) mu_302 + gamma mu_316
|
||||
AddQualityMetric(sh_metric, 1.-gamma_);
|
||||
AddQualityMetric(sz_metric, gamma_);
|
||||
AddQualityMetric(sh_metric, 1.-gamma);
|
||||
AddQualityMetric(sz_metric, gamma);
|
||||
}
|
||||
|
||||
virtual ~TMOP_Metric_333() { delete sh_metric; delete sz_metric; }
|
||||
@@ -873,21 +894,19 @@ class TMOP_Metric_334 : public TMOP_Combo_QualityMetric
|
||||
{
|
||||
protected:
|
||||
mutable InvariantsEvaluator2D<double> ie;
|
||||
double gamma;
|
||||
TMOP_QualityMetric *sh_metric, *sz_metric;
|
||||
|
||||
public:
|
||||
TMOP_Metric_334(double gamma_) : gamma(gamma_),
|
||||
sh_metric(new TMOP_Metric_303),
|
||||
sz_metric(new TMOP_Metric_316)
|
||||
TMOP_Metric_334(double gamma)
|
||||
: sh_metric(new TMOP_Metric_303), sz_metric(new TMOP_Metric_316)
|
||||
{
|
||||
// (1-gamma) mu_303 + gamma mu_316
|
||||
AddQualityMetric(sh_metric, 1.-gamma_);
|
||||
AddQualityMetric(sz_metric, gamma_);
|
||||
AddQualityMetric(sh_metric, 1.-gamma);
|
||||
AddQualityMetric(sz_metric, gamma);
|
||||
}
|
||||
|
||||
virtual int Id() const { return 334; }
|
||||
double GetGamma() const { return gamma; }
|
||||
double GetGamma() const { return wt_arr[1]; }
|
||||
|
||||
virtual ~TMOP_Metric_334() { delete sh_metric; delete sz_metric; }
|
||||
};
|
||||
@@ -897,21 +916,19 @@ class TMOP_Metric_347 : public TMOP_Combo_QualityMetric
|
||||
{
|
||||
protected:
|
||||
mutable InvariantsEvaluator2D<double> ie;
|
||||
double gamma;
|
||||
TMOP_QualityMetric *sh_metric, *sz_metric;
|
||||
|
||||
public:
|
||||
TMOP_Metric_347(double gamma_) : gamma(gamma_),
|
||||
sh_metric(new TMOP_Metric_304),
|
||||
sz_metric(new TMOP_Metric_316)
|
||||
TMOP_Metric_347(double gamma)
|
||||
: sh_metric(new TMOP_Metric_304), sz_metric(new TMOP_Metric_316)
|
||||
{
|
||||
// (1-gamma) mu_304 + gamma mu_316
|
||||
AddQualityMetric(sh_metric, 1.-gamma_);
|
||||
AddQualityMetric(sz_metric, gamma_);
|
||||
AddQualityMetric(sh_metric, 1.-gamma);
|
||||
AddQualityMetric(sz_metric, gamma);
|
||||
}
|
||||
|
||||
virtual int Id() const { return 347; }
|
||||
double GetGamma() const { return gamma; }
|
||||
double GetGamma() const { return wt_arr[1]; }
|
||||
|
||||
virtual ~TMOP_Metric_347() { delete sh_metric; delete sz_metric; }
|
||||
};
|
||||
@@ -1034,17 +1051,15 @@ class TMOP_AMetric_126 : public TMOP_Combo_QualityMetric
|
||||
{
|
||||
protected:
|
||||
mutable InvariantsEvaluator2D<double> ie;
|
||||
double gamma;
|
||||
TMOP_QualityMetric *sh_metric, *sz_metric;
|
||||
|
||||
public:
|
||||
TMOP_AMetric_126(double gamma_) : gamma(gamma_),
|
||||
sh_metric(new TMOP_AMetric_011),
|
||||
sz_metric(new TMOP_AMetric_014a)
|
||||
TMOP_AMetric_126(double gamma)
|
||||
: sh_metric(new TMOP_AMetric_011), sz_metric(new TMOP_AMetric_014a)
|
||||
{
|
||||
// (1-gamma) nu_11 + gamma nu_14
|
||||
AddQualityMetric(sh_metric, 1.-gamma_);
|
||||
AddQualityMetric(sz_metric, gamma_);
|
||||
AddQualityMetric(sh_metric, 1.-gamma);
|
||||
AddQualityMetric(sz_metric, gamma);
|
||||
}
|
||||
|
||||
virtual ~TMOP_AMetric_126() { delete sh_metric; delete sz_metric; }
|
||||
@@ -1551,6 +1566,11 @@ public:
|
||||
adapt_eval = ae;
|
||||
}
|
||||
|
||||
const AdaptivityEvaluator *GetAdaptivityEvaluator() const
|
||||
{
|
||||
return adapt_eval;
|
||||
}
|
||||
|
||||
const Vector &GetTspecPert1H() { return tspec_pert1h; }
|
||||
const Vector &GetTspecPert2H() { return tspec_pert2h; }
|
||||
const Vector &GetTspecPertMixH() { return tspec_pertmix; }
|
||||
|
||||
@@ -68,6 +68,11 @@ public:
|
||||
Vector &new_field,
|
||||
int new_nodes_ordering = Ordering::byNODES);
|
||||
|
||||
const FindPointsGSLIB *GetFindPointsGSLIB() const
|
||||
{
|
||||
return finder;
|
||||
}
|
||||
|
||||
~InterpolatorFP()
|
||||
{
|
||||
finder->FreeData();
|
||||
|
||||
+27
-7
@@ -291,6 +291,10 @@ L2ProjectionGridTransfer::L2ProjectionL2Space::L2ProjectionL2Space(
|
||||
int nel_ho = mesh_ho->GetNE();
|
||||
int nel_lor = mesh_lor->GetNE();
|
||||
|
||||
// The prolongation operation is only well-defined when the LOR space has at
|
||||
// least as many DOFs as the high-order space.
|
||||
const bool build_P = fes_lor.GetTrueVSize() >= fes_ho.GetTrueVSize();
|
||||
|
||||
// If the local mesh is empty, skip all computations
|
||||
if (nel_ho == 0) { return; }
|
||||
|
||||
@@ -319,8 +323,11 @@ L2ProjectionGridTransfer::L2ProjectionL2Space::L2ProjectionL2Space(
|
||||
// R will contain the restriction (L^2 projection operator) defined on each
|
||||
// coarse HO element (and corresponding patch of LOR elements)
|
||||
R.SetSize(offsets[nel_ho]);
|
||||
// P will contain the corresponding prolongation operator
|
||||
P.SetSize(offsets[nel_ho]);
|
||||
if (build_P)
|
||||
{
|
||||
// P will contain the corresponding prolongation operator
|
||||
P.SetSize(offsets[nel_ho]);
|
||||
}
|
||||
|
||||
IntegrationPointTransformation ip_tr;
|
||||
IsoparametricTransformation &emb_tr = ip_tr.Transf;
|
||||
@@ -341,7 +348,6 @@ L2ProjectionGridTransfer::L2ProjectionL2Space::L2ProjectionL2Space(
|
||||
const DenseTensor &pmats = cf_tr.point_matrices[geom];
|
||||
|
||||
DenseMatrix R_iho(&R[offsets[iho]], ndof_lor*nref, ndof_ho);
|
||||
DenseMatrix P_iho(&P[offsets[iho]], ndof_ho, ndof_lor*nref);
|
||||
|
||||
DenseMatrix Minv_lor(ndof_lor*nref, ndof_lor*nref);
|
||||
DenseMatrix M_mixed(ndof_lor*nref, ndof_ho);
|
||||
@@ -385,10 +391,15 @@ L2ProjectionGridTransfer::L2ProjectionL2Space::L2ProjectionL2Space(
|
||||
}
|
||||
mfem::Mult(Minv_lor, M_mixed, R_iho);
|
||||
|
||||
mfem::MultAtB(R_iho, M_lor, RtMlor);
|
||||
mfem::Mult(RtMlor, R_iho, RtMlorR);
|
||||
RtMlorR_inv.Factor();
|
||||
RtMlorR_inv.Mult(RtMlor, P_iho);
|
||||
if (build_P)
|
||||
{
|
||||
DenseMatrix P_iho(&P[offsets[iho]], ndof_ho, ndof_lor*nref);
|
||||
|
||||
mfem::MultAtB(R_iho, M_lor, RtMlor);
|
||||
mfem::Mult(RtMlor, R_iho, RtMlorR);
|
||||
RtMlorR_inv.Factor();
|
||||
RtMlorR_inv.Mult(RtMlor, P_iho);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,6 +473,8 @@ void L2ProjectionGridTransfer::L2ProjectionL2Space::MultTranspose(
|
||||
void L2ProjectionGridTransfer::L2ProjectionL2Space::Prolongate(
|
||||
const Vector &x, Vector &y) const
|
||||
{
|
||||
if (fes_ho.GetNE() == 0) { return; }
|
||||
MFEM_VERIFY(P.Size() > 0, "Prolongation not supported for these spaces.")
|
||||
int vdim = fes_ho.GetVDim();
|
||||
Array<int> vdofs;
|
||||
DenseMatrix xel_mat,yel_mat;
|
||||
@@ -497,6 +510,8 @@ void L2ProjectionGridTransfer::L2ProjectionL2Space::Prolongate(
|
||||
void L2ProjectionGridTransfer::L2ProjectionL2Space::ProlongateTranspose(
|
||||
const Vector &x, Vector &y) const
|
||||
{
|
||||
if (fes_ho.GetNE() == 0) { return; }
|
||||
MFEM_VERIFY(P.Size() > 0, "Prolongation not supported for these spaces.")
|
||||
int vdim = fes_ho.GetVDim();
|
||||
Array<int> vdofs;
|
||||
DenseMatrix xel_mat,yel_mat;
|
||||
@@ -898,6 +913,11 @@ void L2ProjectionGridTransfer::BuildF()
|
||||
}
|
||||
}
|
||||
|
||||
bool L2ProjectionGridTransfer::SupportsBackwardsOperator() const
|
||||
{
|
||||
return ran_fes.GetTrueVSize() >= dom_fes.GetTrueVSize();
|
||||
}
|
||||
|
||||
|
||||
TransferOperator::TransferOperator(const FiniteElementSpace& lFESpace_,
|
||||
const FiniteElementSpace& hFESpace_)
|
||||
|
||||
@@ -98,6 +98,8 @@ public:
|
||||
{
|
||||
return MakeTrueOperator(ran_fes, dom_fes, BackwardOperator(), bw_t_oper);
|
||||
}
|
||||
|
||||
virtual bool SupportsBackwardsOperator() const { return true; }
|
||||
};
|
||||
|
||||
|
||||
@@ -346,6 +348,8 @@ public:
|
||||
virtual const Operator &ForwardOperator();
|
||||
|
||||
virtual const Operator &BackwardOperator();
|
||||
|
||||
virtual bool SupportsBackwardsOperator() const;
|
||||
private:
|
||||
void BuildF();
|
||||
};
|
||||
|
||||
@@ -92,6 +92,9 @@ public:
|
||||
template <typename CT, int N>
|
||||
explicit inline Array(const CT (&values)[N]);
|
||||
|
||||
/// Move constructor ("steals" data from 'src')
|
||||
inline Array(Array<T> &&src) { Swap(src, *this); }
|
||||
|
||||
/// Destructor
|
||||
inline ~Array() { TypeAssert(); data.Delete(); }
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
// 'double' atomicAdd implementation for previous versions of CUDA
|
||||
#if defined(MFEM_USE_CUDA) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600
|
||||
MFEM_DEVICE double atomicAdd(double *add, double val)
|
||||
MFEM_DEVICE inline double atomicAdd(double *add, double val)
|
||||
{
|
||||
unsigned long long int *ptr = (unsigned long long int *) add;
|
||||
unsigned long long int old = *ptr, reg;
|
||||
|
||||
+12
-12
@@ -786,7 +786,7 @@ void *MemoryManager::New_(void *h_tmp, size_t bytes, MemoryType h_mt,
|
||||
void *h_ptr;
|
||||
if (h_tmp == nullptr) { ctrl->Host(h_mt)->Alloc(&h_ptr, bytes); }
|
||||
else { h_ptr = h_tmp; }
|
||||
flags = Mem::REGISTERED | Mem::OWNS_INTERNAL | Mem::OWNS_HOST |
|
||||
flags = Mem::Registered | Mem::OWNS_INTERNAL | Mem::OWNS_HOST |
|
||||
Mem::OWNS_DEVICE | valid_flags;
|
||||
// The other New_() method relies on this lazy allocation behavior.
|
||||
mm.Insert(h_ptr, bytes, h_mt, d_mt); // lazy dev alloc
|
||||
@@ -820,7 +820,7 @@ void *MemoryManager::Register_(void *ptr, void *h_tmp, size_t bytes,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
flags |= Mem::REGISTERED | Mem::OWNS_INTERNAL;
|
||||
flags |= Mem::Registered | Mem::OWNS_INTERNAL;
|
||||
void *h_ptr;
|
||||
|
||||
if (is_host_mem) // HOST TYPES + MANAGED
|
||||
@@ -859,7 +859,7 @@ void MemoryManager::Register2_(void *h_ptr, void *d_ptr, size_t bytes,
|
||||
return;
|
||||
}
|
||||
|
||||
flags |= Mem::REGISTERED | Mem::OWNS_INTERNAL;
|
||||
flags |= Mem::Registered | Mem::OWNS_INTERNAL;
|
||||
|
||||
MFEM_VERIFY(d_ptr || bytes == 0,
|
||||
"cannot register NULL device pointer with bytes = " << bytes);
|
||||
@@ -911,7 +911,7 @@ void MemoryManager::SetDeviceMemoryType_(void *h_ptr, unsigned flags,
|
||||
void MemoryManager::Delete_(void *h_ptr, MemoryType h_mt, unsigned flags)
|
||||
{
|
||||
const bool alias = flags & Mem::ALIAS;
|
||||
const bool registered = flags & Mem::REGISTERED;
|
||||
const bool registered = flags & Mem::Registered;
|
||||
const bool owns_host = flags & Mem::OWNS_HOST;
|
||||
const bool owns_device = flags & Mem::OWNS_DEVICE;
|
||||
const bool owns_internal = flags & Mem::OWNS_INTERNAL;
|
||||
@@ -1018,7 +1018,7 @@ void *MemoryManager::ReadWrite_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
|
||||
size_t bytes, unsigned &flags)
|
||||
{
|
||||
if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
|
||||
if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,""); }
|
||||
if (bytes > 0) { MFEM_VERIFY(flags & Mem::Registered,""); }
|
||||
MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),"");
|
||||
if (IsHostMemory(GetMemoryType(mc)) && mc < MemoryClass::DEVICE)
|
||||
{
|
||||
@@ -1042,7 +1042,7 @@ const void *MemoryManager::Read_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
|
||||
size_t bytes, unsigned &flags)
|
||||
{
|
||||
if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
|
||||
if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,""); }
|
||||
if (bytes > 0) { MFEM_VERIFY(flags & Mem::Registered,""); }
|
||||
MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),"");
|
||||
if (IsHostMemory(GetMemoryType(mc)) && mc < MemoryClass::DEVICE)
|
||||
{
|
||||
@@ -1066,7 +1066,7 @@ void *MemoryManager::Write_(void *h_ptr, MemoryType h_mt, MemoryClass mc,
|
||||
size_t bytes, unsigned &flags)
|
||||
{
|
||||
if (h_ptr) { CheckHostMemoryType_(h_mt, h_ptr, flags & Mem::ALIAS); }
|
||||
if (bytes > 0) { MFEM_VERIFY(flags & Mem::REGISTERED,""); }
|
||||
if (bytes > 0) { MFEM_VERIFY(flags & Mem::Registered,""); }
|
||||
MFEM_ASSERT(MemoryClassCheck_(mc, h_ptr, h_mt, bytes, flags),"");
|
||||
if (IsHostMemory(GetMemoryType(mc)) && mc < MemoryClass::DEVICE)
|
||||
{
|
||||
@@ -1088,8 +1088,8 @@ void MemoryManager::SyncAlias_(const void *base_h_ptr, void *alias_h_ptr,
|
||||
size_t alias_bytes, unsigned base_flags,
|
||||
unsigned &alias_flags)
|
||||
{
|
||||
// This is called only when (base_flags & Mem::REGISTERED) is true.
|
||||
// Note that (alias_flags & REGISTERED) may not be true.
|
||||
// This is called only when (base_flags & Mem::Registered) is true.
|
||||
// Note that (alias_flags & Registered) may not be true.
|
||||
MFEM_ASSERT(alias_flags & Mem::ALIAS, "not an alias");
|
||||
if ((base_flags & Mem::VALID_HOST) && !(alias_flags & Mem::VALID_HOST))
|
||||
{
|
||||
@@ -1097,10 +1097,10 @@ void MemoryManager::SyncAlias_(const void *base_h_ptr, void *alias_h_ptr,
|
||||
}
|
||||
if ((base_flags & Mem::VALID_DEVICE) && !(alias_flags & Mem::VALID_DEVICE))
|
||||
{
|
||||
if (!(alias_flags & Mem::REGISTERED))
|
||||
if (!(alias_flags & Mem::Registered))
|
||||
{
|
||||
mm.InsertAlias(base_h_ptr, alias_h_ptr, alias_bytes, base_flags & Mem::ALIAS);
|
||||
alias_flags = (alias_flags | Mem::REGISTERED | Mem::OWNS_INTERNAL) &
|
||||
alias_flags = (alias_flags | Mem::Registered | Mem::OWNS_INTERNAL) &
|
||||
~(Mem::OWNS_HOST | Mem::OWNS_DEVICE);
|
||||
}
|
||||
mm.GetAliasDevicePtr(alias_h_ptr, alias_bytes, true);
|
||||
@@ -1671,7 +1671,7 @@ void MemoryPrintFlags(unsigned flags)
|
||||
{
|
||||
typedef Memory<int> Mem;
|
||||
mfem::out
|
||||
<< "\n registered = " << bool(flags & Mem::REGISTERED)
|
||||
<< "\n registered = " << bool(flags & Mem::Registered)
|
||||
<< "\n owns host = " << bool(flags & Mem::OWNS_HOST)
|
||||
<< "\n owns device = " << bool(flags & Mem::OWNS_DEVICE)
|
||||
<< "\n owns internal = " << bool(flags & Mem::OWNS_INTERNAL)
|
||||
|
||||
+25
-15
@@ -165,8 +165,16 @@ protected:
|
||||
|
||||
enum FlagMask: unsigned
|
||||
{
|
||||
// Workaround for use with headers that define REGISTERED as a macro,
|
||||
// e.g. nb30.h (which is included by Windows.h):
|
||||
#ifndef REGISTERED
|
||||
REGISTERED = 1 << 0, /**< The host pointer is registered with the
|
||||
MemoryManager */
|
||||
#endif
|
||||
// Use the following identifier if REGISTERED is defined as a macro,
|
||||
// e.g. nb30.h (which is included by Windows.h):
|
||||
Registered = 1 << 0, /**< The host pointer is registered with the
|
||||
MemoryManager */
|
||||
OWNS_HOST = 1 << 1, ///< The host pointer will be deleted by Delete()
|
||||
OWNS_DEVICE = 1 << 2, /**< The device pointer will be deleted by
|
||||
Delete() */
|
||||
@@ -211,6 +219,8 @@ public:
|
||||
validity flags of @a *this to those of @a other. Resets @a other. */
|
||||
Memory &operator=(Memory &&orig)
|
||||
{
|
||||
// Guard self-assignment:
|
||||
if (this == &orig) { return *this; }
|
||||
*this = orig;
|
||||
orig.Reset();
|
||||
return *this;
|
||||
@@ -972,7 +982,7 @@ inline void Memory<T>::MakeAlias(const Memory &base, int offset, int size)
|
||||
capacity = size;
|
||||
h_mt = base.h_mt;
|
||||
h_ptr = base.h_ptr + offset;
|
||||
if (!(base.flags & REGISTERED))
|
||||
if (!(base.flags & Registered))
|
||||
{
|
||||
if (
|
||||
#if !defined(HYPRE_USING_GPU)
|
||||
@@ -1008,7 +1018,7 @@ template <typename T>
|
||||
inline void Memory<T>::SetDeviceMemoryType(MemoryType d_mt)
|
||||
{
|
||||
if (!IsDeviceMemory(d_mt)) { return; }
|
||||
if (!(flags & REGISTERED))
|
||||
if (!(flags & Registered))
|
||||
{
|
||||
MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
|
||||
flags & OWNS_HOST, flags & ALIAS, flags);
|
||||
@@ -1019,7 +1029,7 @@ inline void Memory<T>::SetDeviceMemoryType(MemoryType d_mt)
|
||||
template <typename T>
|
||||
inline void Memory<T>::Delete()
|
||||
{
|
||||
const bool registered = flags & REGISTERED;
|
||||
const bool registered = flags & Registered;
|
||||
const bool mt_host = h_mt == MemoryType::HOST;
|
||||
const bool std_delete = !registered && mt_host;
|
||||
|
||||
@@ -1038,7 +1048,7 @@ inline void Memory<T>::Delete()
|
||||
template <typename T>
|
||||
inline void Memory<T>::DeleteDevice(bool copy_to_host)
|
||||
{
|
||||
if (flags & REGISTERED)
|
||||
if (flags & Registered)
|
||||
{
|
||||
if (copy_to_host) { Read(MemoryClass::HOST, capacity); }
|
||||
MemoryManager::DeleteDevice_((void*)h_ptr, flags);
|
||||
@@ -1098,7 +1108,7 @@ template <typename T>
|
||||
inline T *Memory<T>::ReadWrite(MemoryClass mc, int size)
|
||||
{
|
||||
const size_t bytes = size * sizeof(T);
|
||||
if (!(flags & REGISTERED))
|
||||
if (!(flags & Registered))
|
||||
{
|
||||
if (mc == MemoryClass::HOST) { return h_ptr; }
|
||||
MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
|
||||
@@ -1111,7 +1121,7 @@ template <typename T>
|
||||
inline const T *Memory<T>::Read(MemoryClass mc, int size) const
|
||||
{
|
||||
const size_t bytes = size * sizeof(T);
|
||||
if (!(flags & REGISTERED))
|
||||
if (!(flags & Registered))
|
||||
{
|
||||
if (mc == MemoryClass::HOST) { return h_ptr; }
|
||||
MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
|
||||
@@ -1124,7 +1134,7 @@ template <typename T>
|
||||
inline T *Memory<T>::Write(MemoryClass mc, int size)
|
||||
{
|
||||
const size_t bytes = size * sizeof(T);
|
||||
if (!(flags & REGISTERED))
|
||||
if (!(flags & Registered))
|
||||
{
|
||||
if (mc == MemoryClass::HOST) { return h_ptr; }
|
||||
MemoryManager::Register_(h_ptr, nullptr, capacity*sizeof(T), h_mt,
|
||||
@@ -1136,12 +1146,12 @@ inline T *Memory<T>::Write(MemoryClass mc, int size)
|
||||
template <typename T>
|
||||
inline void Memory<T>::Sync(const Memory &other) const
|
||||
{
|
||||
if (!(flags & REGISTERED) && (other.flags & REGISTERED))
|
||||
if (!(flags & Registered) && (other.flags & Registered))
|
||||
{
|
||||
MFEM_ASSERT(h_ptr == other.h_ptr &&
|
||||
(flags & ALIAS) == (other.flags & ALIAS),
|
||||
"invalid input");
|
||||
flags = (flags | REGISTERED) & ~(OWNS_DEVICE | OWNS_INTERNAL);
|
||||
flags = (flags | Registered) & ~(OWNS_DEVICE | OWNS_INTERNAL);
|
||||
}
|
||||
flags = (flags & ~(VALID_HOST | VALID_DEVICE)) |
|
||||
(other.flags & (VALID_HOST | VALID_DEVICE));
|
||||
@@ -1151,9 +1161,9 @@ template <typename T>
|
||||
inline void Memory<T>::SyncAlias(const Memory &base, int alias_size) const
|
||||
{
|
||||
// Assuming that if *this is registered then base is also registered.
|
||||
MFEM_ASSERT(!(flags & REGISTERED) || (base.flags & REGISTERED),
|
||||
MFEM_ASSERT(!(flags & Registered) || (base.flags & Registered),
|
||||
"invalid base state");
|
||||
if (!(base.flags & REGISTERED)) { return; }
|
||||
if (!(base.flags & Registered)) { return; }
|
||||
MemoryManager::SyncAlias_(base.h_ptr, h_ptr, alias_size*sizeof(T),
|
||||
base.flags, flags);
|
||||
}
|
||||
@@ -1168,7 +1178,7 @@ inline MemoryType Memory<T>::GetMemoryType() const
|
||||
template <typename T>
|
||||
inline MemoryType Memory<T>::GetDeviceMemoryType() const
|
||||
{
|
||||
if (!(flags & REGISTERED)) { return MemoryType::DEFAULT; }
|
||||
if (!(flags & Registered)) { return MemoryType::DEFAULT; }
|
||||
return MemoryManager::GetDeviceMemoryType_(h_ptr, flags & ALIAS);
|
||||
}
|
||||
|
||||
@@ -1188,7 +1198,7 @@ template <typename T>
|
||||
inline void Memory<T>::CopyFrom(const Memory &src, int size)
|
||||
{
|
||||
MFEM_VERIFY(src.capacity>=size && capacity>=size, "Incorrect size");
|
||||
if (!(flags & REGISTERED) && !(src.flags & REGISTERED))
|
||||
if (!(flags & Registered) && !(src.flags & Registered))
|
||||
{
|
||||
if (h_ptr != src.h_ptr && size != 0)
|
||||
{
|
||||
@@ -1208,7 +1218,7 @@ template <typename T>
|
||||
inline void Memory<T>::CopyFromHost(const T *src, int size)
|
||||
{
|
||||
MFEM_VERIFY(capacity>=size, "Incorrect size");
|
||||
if (!(flags & REGISTERED))
|
||||
if (!(flags & Registered))
|
||||
{
|
||||
if (h_ptr != src && size != 0)
|
||||
{
|
||||
@@ -1235,7 +1245,7 @@ template <typename T>
|
||||
inline void Memory<T>::CopyToHost(T *dest, int size) const
|
||||
{
|
||||
MFEM_VERIFY(capacity>=size, "Incorrect size");
|
||||
if (!(flags & REGISTERED))
|
||||
if (!(flags & Registered))
|
||||
{
|
||||
if (h_ptr != dest && size != 0)
|
||||
{
|
||||
|
||||
@@ -97,6 +97,9 @@ const char *GetConfigStr()
|
||||
#ifdef MFEM_USE_HIOP
|
||||
"MFEM_USE_HIOP\n"
|
||||
#endif
|
||||
#ifdef MFEM_USE_IPOPT
|
||||
"MFEM_USE_IPOPT\n"
|
||||
#endif
|
||||
#ifdef MFEM_USE_HIP
|
||||
"MFEM_USE_HIP\n"
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#ifndef __ZSTR_HPP
|
||||
#define __ZSTR_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
@@ -352,6 +352,7 @@ void EliminationSolver::Mult(const Vector& rhs, Vector& sol) const
|
||||
reducedsol = 0.0;
|
||||
krylov->Mult(reducedrhs, reducedsol);
|
||||
final_iter = krylov->GetNumIterations();
|
||||
initial_norm = krylov->GetInitialNorm();
|
||||
final_norm = krylov->GetFinalNorm();
|
||||
converged = krylov->GetConverged();
|
||||
|
||||
@@ -485,6 +486,7 @@ void PenaltyConstrainedSolver::Mult(const Vector& b, Vector& x) const
|
||||
krylov->SetPrintLevel(print_options);
|
||||
krylov->Mult(penalized_rhs, x);
|
||||
final_iter = krylov->GetNumIterations();
|
||||
initial_norm = krylov->GetInitialNorm();
|
||||
final_norm = krylov->GetFinalNorm();
|
||||
converged = krylov->GetConverged();
|
||||
|
||||
@@ -616,6 +618,7 @@ void SchurConstrainedSolver::LagrangeSystemMult(const Vector& x,
|
||||
gmres->Mult(x, y);
|
||||
final_iter = gmres->GetNumIterations();
|
||||
converged = gmres->GetConverged();
|
||||
initial_norm = gmres->GetInitialNorm();
|
||||
final_norm = gmres->GetFinalNorm();
|
||||
delete gmres;
|
||||
}
|
||||
|
||||
+6
-5
@@ -292,13 +292,14 @@ HypreParVector& HypreParVector::operator=(const HypreParVector &y)
|
||||
|
||||
HypreParVector& HypreParVector::operator=(HypreParVector &&y)
|
||||
{
|
||||
// If the argument vector owns its data, then the calling vector will as well
|
||||
WrapHypreParVector(static_cast<hypre_ParVector*>(y), y.own_ParVector);
|
||||
// Either way the argument vector will no longer own its data
|
||||
Vector::operator=(std::move(y));
|
||||
// Self-assignment-safe way to move for 'own_ParVector' and 'x':
|
||||
const auto own_tmp = y.own_ParVector;
|
||||
y.own_ParVector = 0;
|
||||
own_ParVector = own_tmp;
|
||||
const auto x_tmp = y.x;
|
||||
y.x = nullptr;
|
||||
y.data.Reset();
|
||||
y.size = 0;
|
||||
x = x_tmp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
+10
-7
@@ -583,6 +583,7 @@ void SLISolver::Mult(const Vector &b, Vector &x) const
|
||||
{
|
||||
nom0 = nom = sqrt(Dot(r, r));
|
||||
}
|
||||
initial_norm = nom0;
|
||||
|
||||
if (print_options.iterations | print_options.first_and_last)
|
||||
{
|
||||
@@ -735,6 +736,7 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
|
||||
d = r;
|
||||
}
|
||||
nom0 = nom = Dot(d, r);
|
||||
if (nom0 >= 0.0) { initial_norm = sqrt(nom0); }
|
||||
MFEM_ASSERT(IsFinite(nom), "nom = " << nom);
|
||||
if (print_options.iterations || print_options.first_and_last)
|
||||
{
|
||||
@@ -752,6 +754,7 @@ void CGSolver::Mult(const Vector &b, Vector &x) const
|
||||
}
|
||||
converged = false;
|
||||
final_iter = 0;
|
||||
initial_norm = nom;
|
||||
final_norm = nom;
|
||||
return;
|
||||
}
|
||||
@@ -1015,7 +1018,7 @@ void GMRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
r = b;
|
||||
}
|
||||
}
|
||||
double beta = Norm(r); // beta = ||r||
|
||||
double beta = initial_norm = Norm(r); // beta = ||r||
|
||||
MFEM_ASSERT(IsFinite(beta), "beta = " << beta);
|
||||
|
||||
final_norm = std::max(rel_tol*beta, abs_tol);
|
||||
@@ -1175,7 +1178,7 @@ void FGMRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
x = 0.;
|
||||
r = b;
|
||||
}
|
||||
double beta = Norm(r); // beta = ||r||
|
||||
double beta = initial_norm = Norm(r); // beta = ||r||
|
||||
// We need to preallocate this to report the correct result in the case of
|
||||
// no convergence.
|
||||
double resid;
|
||||
@@ -1391,7 +1394,7 @@ void BiCGSTABSolver::Mult(const Vector &b, Vector &x) const
|
||||
}
|
||||
rtilde = r;
|
||||
|
||||
resid = Norm(r);
|
||||
resid = initial_norm = Norm(r);
|
||||
MFEM_ASSERT(IsFinite(resid), "resid = " << resid);
|
||||
if (print_options.iterations || print_options.first_and_last)
|
||||
{
|
||||
@@ -1638,7 +1641,7 @@ void MINRESSolver::Mult(const Vector &b, Vector &x) const
|
||||
{
|
||||
prec->Mult(v1, u1);
|
||||
}
|
||||
eta = beta = sqrt(Dot(*z, v1));
|
||||
eta = beta = initial_norm = sqrt(Dot(*z, v1));
|
||||
MFEM_ASSERT(IsFinite(eta), "eta = " << eta);
|
||||
gamma0 = gamma1 = 1.;
|
||||
sigma0 = sigma1 = 0.;
|
||||
@@ -1833,7 +1836,7 @@ void NewtonSolver::Mult(const Vector &b, Vector &x) const
|
||||
r -= b;
|
||||
}
|
||||
|
||||
norm0 = norm = Norm(r);
|
||||
norm0 = norm = initial_norm = Norm(r);
|
||||
if (print_options.first_and_last && !print_options.iterations)
|
||||
{
|
||||
mfem::out << "Newton iteration " << setw(2) << 0
|
||||
@@ -2031,7 +2034,7 @@ void LBFGSSolver::Mult(const Vector &b, Vector &x) const
|
||||
|
||||
c = r; // initial descent direction
|
||||
|
||||
norm0 = norm = Norm(r);
|
||||
norm0 = norm = initial_norm = Norm(r);
|
||||
if (print_options.first_and_last && !print_options.iterations)
|
||||
{
|
||||
mfem::out << "LBFGS iteration " << setw(2) << 0
|
||||
@@ -2404,7 +2407,7 @@ void SLBQPOptimizer::Mult(const Vector& xt, Vector& x) const
|
||||
}
|
||||
|
||||
// Solve QP with fixed Lagrange multiplier
|
||||
r = solve(l,xt,x,nclip);
|
||||
r = initial_norm = solve(l,xt,x,nclip);
|
||||
print_iteration(nclip, r, l);
|
||||
|
||||
|
||||
|
||||
+32
-4
@@ -159,11 +159,12 @@ protected:
|
||||
///@}
|
||||
|
||||
/// @name Solver statistics (protected attributes)
|
||||
/// Every IterativeSolver is expected to define these in its Mult() call.
|
||||
///@{
|
||||
|
||||
mutable int final_iter;
|
||||
mutable bool converged;
|
||||
mutable double final_norm;
|
||||
mutable int final_iter = -1;
|
||||
mutable bool converged = false;
|
||||
mutable double initial_norm = -1.0, final_norm = -1.0;
|
||||
|
||||
///@}
|
||||
|
||||
@@ -241,11 +242,38 @@ public:
|
||||
virtual void SetPrintLevel(PrintLevel);
|
||||
///@}
|
||||
|
||||
/// @name Solver statistics
|
||||
/// @name Solver statistics.
|
||||
/// These are valid after the call to Mult().
|
||||
///@{
|
||||
|
||||
/// Returns the number of iterations taken during the last call to Mult()
|
||||
int GetNumIterations() const { return final_iter; }
|
||||
/// Returns true if the last call to Mult() converged successfully.
|
||||
bool GetConverged() const { return converged; }
|
||||
/// @brief Returns the initial residual norm from the last call to Mult().
|
||||
///
|
||||
/// This function returns the norm of the residual (or preconditioned
|
||||
/// residual, depending on the solver), computed before the start of the
|
||||
/// iteration.
|
||||
double GetInitialNorm() const { return initial_norm; }
|
||||
/// @brief Returns the final residual norm after termination of the solver
|
||||
/// during the last call to Mult().
|
||||
///
|
||||
/// This function returns the norm of the residual (or preconditioned
|
||||
/// residual, depending on the solver), corresponding to the returned
|
||||
/// solution.
|
||||
double GetFinalNorm() const { return final_norm; }
|
||||
/// @brief Returns the final residual norm after termination of the solver
|
||||
/// during the last call to Mult(), divided by the initial residual norm.
|
||||
/// Returns -1 if one of these norms is left undefined by the solver.
|
||||
///
|
||||
/// @sa GetFinalNorm(), GetInitialNorm()
|
||||
double GetFinalRelNorm() const
|
||||
{
|
||||
if (final_norm < 0.0 || initial_norm < 0.0) { return -1.0; }
|
||||
return final_norm / initial_norm;
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
/// This should be called before SetOperator
|
||||
|
||||
+6
-5
@@ -149,9 +149,10 @@ Vector &Vector::operator=(const Vector &v)
|
||||
Vector &Vector::operator=(Vector &&v)
|
||||
{
|
||||
data = std::move(v.data);
|
||||
size = v.size;
|
||||
v.data.Reset();
|
||||
// Self-assignment-safe way to move v.size to size:
|
||||
const auto size_tmp = v.size;
|
||||
v.size = 0;
|
||||
size = size_tmp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -593,7 +594,7 @@ void Vector::SetSubVector(const Array<int> &dofs, const double value)
|
||||
|
||||
void Vector::SetSubVector(const Array<int> &dofs, const Vector &elemvect)
|
||||
{
|
||||
MFEM_ASSERT(dofs.Size() == elemvect.Size(),
|
||||
MFEM_ASSERT(dofs.Size() <= elemvect.Size(),
|
||||
"Size mismatch: length of dofs is " << dofs.Size()
|
||||
<< ", length of elemvect is " << elemvect.Size());
|
||||
|
||||
@@ -638,7 +639,7 @@ void Vector::SetSubVector(const Array<int> &dofs, double *elem_data)
|
||||
|
||||
void Vector::AddElementVector(const Array<int> &dofs, const Vector &elemvect)
|
||||
{
|
||||
MFEM_ASSERT(dofs.Size() == elemvect.Size(), "Size mismatch: "
|
||||
MFEM_ASSERT(dofs.Size() <= elemvect.Size(), "Size mismatch: "
|
||||
"length of dofs is " << dofs.Size() <<
|
||||
", length of elemvect is " << elemvect.Size());
|
||||
|
||||
@@ -682,7 +683,7 @@ void Vector::AddElementVector(const Array<int> &dofs, double *elem_data)
|
||||
void Vector::AddElementVector(const Array<int> &dofs, const double a,
|
||||
const Vector &elemvect)
|
||||
{
|
||||
MFEM_ASSERT(dofs.Size() == elemvect.Size(), "Size mismatch: "
|
||||
MFEM_ASSERT(dofs.Size() <= elemvect.Size(), "Size mismatch: "
|
||||
"length of dofs is " << dofs.Size() <<
|
||||
", length of elemvect is " << elemvect.Size());
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ $(if $(word 2,$(SRC)),$(error Spaces in SRC = "$(SRC)" are not supported))
|
||||
MFEM_GIT_STRING = $(shell [ -d $(MFEM_DIR)/.git ] && git -C $(MFEM_DIR) \
|
||||
describe --all --long --abbrev=40 --dirty --always 2> /dev/null)
|
||||
|
||||
EXAMPLE_SUBDIRS = amgx caliper ginkgo hiop petsc pumi sundials superlu moonolith
|
||||
EXAMPLE_SUBDIRS = amgx caliper ginkgo hiop ipopt petsc pumi sundials superlu moonolith
|
||||
EXAMPLE_DIRS := examples $(addprefix examples/,$(EXAMPLE_SUBDIRS))
|
||||
EXAMPLE_TEST_DIRS := examples
|
||||
|
||||
@@ -275,7 +275,7 @@ endif
|
||||
|
||||
# List of MFEM dependencies, that require the *_LIB variable to be non-empty
|
||||
MFEM_REQ_LIB_DEPS = ENZYME SUPERLU MUMPS METIS FMS CONDUIT SIDRE LAPACK SUNDIALS\
|
||||
SUITESPARSE STRUMPACK GINKGO GNUTLS NETCDF PETSC SLEPC MPFR PUMI HIOP\
|
||||
SUITESPARSE STRUMPACK GINKGO GNUTLS NETCDF PETSC SLEPC MPFR PUMI HIOP IPOPT\
|
||||
GSLIB OCCA CEED RAJA UMPIRE MKL_CPARDISO AMGX CALIPER PARELAG BENCHMARK\
|
||||
MOONOLITH ALGOIM
|
||||
|
||||
@@ -341,7 +341,7 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\
|
||||
MFEM_USE_SUITESPARSE MFEM_USE_GINKGO MFEM_USE_SUPERLU MFEM_USE_SUPERLU5\
|
||||
MFEM_USE_STRUMPACK MFEM_USE_GNUTLS MFEM_USE_NETCDF MFEM_USE_PETSC\
|
||||
MFEM_USE_SLEPC MFEM_USE_MPFR MFEM_USE_SIDRE MFEM_USE_FMS MFEM_USE_CONDUIT\
|
||||
MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\
|
||||
MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_IPOPT MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\
|
||||
MFEM_USE_OCCA MFEM_USE_MOONOLITH MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE\
|
||||
MFEM_USE_SIMD MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO MFEM_USE_AMGX\
|
||||
MFEM_USE_MUMPS MFEM_USE_ADFORWARD MFEM_USE_CODIPACK MFEM_USE_CALIPER\
|
||||
@@ -690,6 +690,7 @@ status info:
|
||||
$(info MFEM_USE_CONDUIT = $(MFEM_USE_CONDUIT))
|
||||
$(info MFEM_USE_PUMI = $(MFEM_USE_PUMI))
|
||||
$(info MFEM_USE_HIOP = $(MFEM_USE_HIOP))
|
||||
$(info MFEM_USE_IPOPT = $(MFEM_USE_IPOPT))
|
||||
$(info MFEM_USE_GSLIB = $(MFEM_USE_GSLIB))
|
||||
$(info MFEM_USE_CUDA = $(MFEM_USE_CUDA))
|
||||
$(info MFEM_USE_HIP = $(MFEM_USE_HIP))
|
||||
|
||||
+39
-3
@@ -1467,6 +1467,7 @@ void Mesh::InitTables()
|
||||
{
|
||||
el_to_edge =
|
||||
el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
|
||||
face_to_elem = NULL;
|
||||
}
|
||||
|
||||
void Mesh::SetEmpty()
|
||||
@@ -1489,6 +1490,9 @@ void Mesh::DestroyTables()
|
||||
|
||||
delete face_edge;
|
||||
delete edge_vertex;
|
||||
|
||||
delete face_to_elem;
|
||||
face_to_elem = NULL;
|
||||
}
|
||||
|
||||
void Mesh::DestroyPointers()
|
||||
@@ -1550,6 +1554,7 @@ void Mesh::ResetLazyData()
|
||||
{
|
||||
delete el_to_el; el_to_el = NULL;
|
||||
delete face_edge; face_edge = NULL;
|
||||
delete face_to_elem; face_to_elem = NULL;
|
||||
delete edge_vertex; edge_vertex = NULL;
|
||||
DeleteGeometricFactors();
|
||||
nbInteriorFaces = -1;
|
||||
@@ -3632,6 +3637,7 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
|
||||
|
||||
// Do NOT copy the face-to-edge Table, face_edge
|
||||
face_edge = NULL;
|
||||
face_to_elem = NULL;
|
||||
|
||||
// Copy the edge-to-vertex Table, edge_vertex
|
||||
edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
|
||||
@@ -6175,6 +6181,34 @@ void Mesh::GetElementFaces(int i, Array<int> &el_faces, Array<int> &ori) const
|
||||
}
|
||||
}
|
||||
|
||||
Array<int> Mesh::FindFaceNeighbors(const int elem) const
|
||||
{
|
||||
if (face_to_elem == NULL)
|
||||
{
|
||||
face_to_elem = GetFaceToElementTable();
|
||||
}
|
||||
|
||||
Array<int> elem_faces;
|
||||
Array<int> ori;
|
||||
GetElementFaces(elem, elem_faces, ori);
|
||||
|
||||
Array<int> nghb;
|
||||
for (auto f : elem_faces)
|
||||
{
|
||||
Array<int> row;
|
||||
face_to_elem->GetRow(f, row);
|
||||
for (auto r : row)
|
||||
{
|
||||
nghb.Append(r);
|
||||
}
|
||||
}
|
||||
|
||||
nghb.Sort();
|
||||
nghb.Unique();
|
||||
|
||||
return nghb;
|
||||
}
|
||||
|
||||
void Mesh::GetBdrElementFace(int i, int *f, int *o) const
|
||||
{
|
||||
const int *bv, *fv;
|
||||
@@ -9152,8 +9186,9 @@ void Mesh::NonconformingRefinement(const Array<Refinement> &refinements,
|
||||
double Mesh::AggregateError(const Array<double> &elem_error,
|
||||
const int *fine, int nfine, int op)
|
||||
{
|
||||
double error = 0.0;
|
||||
for (int i = 0; i < nfine; i++)
|
||||
double error = elem_error[fine[0]];
|
||||
|
||||
for (int i = 1; i < nfine; i++)
|
||||
{
|
||||
MFEM_VERIFY(fine[i] < elem_error.Size(), "");
|
||||
|
||||
@@ -9317,6 +9352,7 @@ void Mesh::Swap(Mesh& other, bool non_geometry)
|
||||
mfem::Swap(bel_to_edge, other.bel_to_edge);
|
||||
mfem::Swap(be_to_face, other.be_to_face);
|
||||
mfem::Swap(face_edge, other.face_edge);
|
||||
mfem::Swap(face_to_elem, other.face_to_elem);
|
||||
mfem::Swap(edge_vertex, other.edge_vertex);
|
||||
|
||||
mfem::Swap(attributes, other.attributes);
|
||||
@@ -10480,7 +10516,7 @@ void Mesh::PrintVTU(std::string fname,
|
||||
bool bdr)
|
||||
{
|
||||
int ref = (high_order_output && Nodes)
|
||||
? Nodes->FESpace()->GetElementOrder(0) : 1;
|
||||
? Nodes->FESpace()->GetMaxElementOrder() : 1;
|
||||
|
||||
fname = fname + ".vtu";
|
||||
std::fstream os(fname.c_str(),std::ios::out);
|
||||
|
||||
+60
-22
@@ -223,8 +223,13 @@ protected:
|
||||
Array<int> be_to_edge; // for 2D
|
||||
Table *bel_to_edge; // for 3D
|
||||
Array<int> be_to_face;
|
||||
mutable Table *face_edge;
|
||||
mutable Table *edge_vertex;
|
||||
|
||||
// Note that the following tables are owned by this class and should not be
|
||||
// deleted by the caller. Of these three tables, only face_edge and
|
||||
// edge_vertex are returned by access functions.
|
||||
mutable Table *face_to_elem; // Used by FindFaceNeighbors, not returned.
|
||||
mutable Table *face_edge; // Returned by GetFaceEdgeTable().
|
||||
mutable Table *edge_vertex; // Returned by GetEdgeVertexTable().
|
||||
|
||||
IsoparametricTransformation Transformation, Transformation2;
|
||||
IsoparametricTransformation BdrTransformation;
|
||||
@@ -1182,6 +1187,10 @@ public:
|
||||
/// Return the indices and the orientations of all faces of element i.
|
||||
void GetElementFaces(int i, Array<int> &faces, Array<int> &ori) const;
|
||||
|
||||
/** @brief Returns the sorted, unique indices of elements sharing a face with
|
||||
element @a elem, including @a elem. */
|
||||
Array<int> FindFaceNeighbors(const int elem) const;
|
||||
|
||||
/// Return the index and the orientation of the face of bdr element i. (3D)
|
||||
void GetBdrElementFace(int i, int *f, int *o) const;
|
||||
|
||||
@@ -1226,24 +1235,32 @@ public:
|
||||
|
||||
static FiniteElement *GetTransformationFEforElementType(Element::Type);
|
||||
|
||||
/** Builds the transformation defining the i-th element in the user-defined
|
||||
variable. */
|
||||
/// Builds the transformation defining the i-th element in @a ElTr.
|
||||
/// @a ElTr must be allocated in advance and will be owned by the caller.
|
||||
void GetElementTransformation(int i, IsoparametricTransformation *ElTr);
|
||||
|
||||
/// Returns the transformation defining the i-th element
|
||||
/// Returns a pointer to the transformation defining the i-th element.
|
||||
/// Note that the pointer is owned by the class and is shared, i.e., calling
|
||||
/// this function resets pointers obtained from previous calls.
|
||||
ElementTransformation *GetElementTransformation(int i);
|
||||
|
||||
/** Return the transformation defining the i-th element assuming
|
||||
the position of the vertices/nodes are given by 'nodes'. */
|
||||
/// Builds the transformation defining the i-th element in @a ElTr
|
||||
/// assuming position of the vertices/nodes are given by @a nodes.
|
||||
/// @a ElTr must be allocated in advance and will be owned by the caller.
|
||||
void GetElementTransformation(int i, const Vector &nodes,
|
||||
IsoparametricTransformation *ElTr);
|
||||
|
||||
/// Returns the transformation defining the i-th boundary element
|
||||
ElementTransformation * GetBdrElementTransformation(int i);
|
||||
/// Returns a pointer to the transformation defining the i-th boundary
|
||||
/// element. Note that the pointer is owned by the class and is shared, i.e.,
|
||||
/// calling this function resets pointers obtained from previous calls.
|
||||
ElementTransformation *GetBdrElementTransformation(int i);
|
||||
|
||||
/// Builds the transformation defining the i-th boundary element in @a ElTr.
|
||||
/// @a ElTr must be allocated in advance and will be owned by the caller.
|
||||
void GetBdrElementTransformation(int i, IsoparametricTransformation *ElTr);
|
||||
|
||||
/** @brief Returns the transformation defining the given face element in a
|
||||
user-defined variable. */
|
||||
/// Builds the transformation defining the i-th face element in @a FTr.
|
||||
/// @a FTr must be allocated in advance and will be owned by the caller.
|
||||
void GetFaceTransformation(int i, IsoparametricTransformation *FTr);
|
||||
|
||||
/** @brief A helper method that constructs a transformation from the
|
||||
@@ -1255,14 +1272,18 @@ public:
|
||||
IsoparametricTransformation &Transf,
|
||||
int info);
|
||||
|
||||
/// Returns the transformation defining the given face element
|
||||
/// Returns a pointer to the transformation defining the given face element.
|
||||
/// Note that the pointer is owned by the class and is shared, i.e., calling
|
||||
/// this function resets pointers obtained from previous calls.
|
||||
ElementTransformation *GetFaceTransformation(int FaceNo);
|
||||
|
||||
/** Returns the transformation defining the given edge element.
|
||||
The transformation is stored in a user-defined variable. */
|
||||
/// Builds the transformation defining the i-th edge element in @a EdTr.
|
||||
/// @a EdTr must be allocated in advance and will be owned by the caller.
|
||||
void GetEdgeTransformation(int i, IsoparametricTransformation *EdTr);
|
||||
|
||||
/// Returns the transformation defining the given face element
|
||||
/// Returns a pointer to the transformation defining the given edge element.
|
||||
/// Note that the pointer is owned by the class and is shared, i.e., calling
|
||||
/// this function resets pointers obtained from previous calls.
|
||||
ElementTransformation *GetEdgeTransformation(int EdgeNo);
|
||||
|
||||
/// Returns (a pointer to an object containing) the following data:
|
||||
@@ -1295,16 +1316,22 @@ public:
|
||||
/// mask & 4 - Loc1, mask & 8 - Loc2, mask & 16 - Face.
|
||||
/// These mask values are defined in the ConfigMasks enum type as part of the
|
||||
/// FaceElementTransformations class in fem/eltrans.hpp.
|
||||
///
|
||||
/// Note that the pointer is owned by the class and is shared, i.e., calling
|
||||
/// this function resets pointers obtained from previous calls.
|
||||
virtual FaceElementTransformations *GetFaceElementTransformations(
|
||||
int FaceNo,
|
||||
int mask = 31);
|
||||
|
||||
/// See GetFaceElementTransformations().
|
||||
FaceElementTransformations *GetInteriorFaceTransformations (int FaceNo)
|
||||
{
|
||||
if (faces_info[FaceNo].Elem2No < 0) { return NULL; }
|
||||
return GetFaceElementTransformations (FaceNo);
|
||||
}
|
||||
|
||||
/// Builds the transformation defining the given boundary face.
|
||||
/// The returned pointer is owned by the caller.
|
||||
FaceElementTransformations *GetBdrFaceTransformations (int BdrElemNo);
|
||||
|
||||
/// Return the local face index for the given boundary face.
|
||||
@@ -1576,6 +1603,10 @@ public:
|
||||
void SetNodes(const Vector &node_coord);
|
||||
|
||||
/// Return a pointer to the internal node GridFunction (may be NULL).
|
||||
/** If the mesh is straight-sided (low-order), it may not have a GridFunction
|
||||
for the nodes, in which case this function returns NULL. To ensure that
|
||||
the nodal GridFunction exists, call EnsureNodes().
|
||||
@sa SetCurvature(). */
|
||||
GridFunction *GetNodes() { return Nodes; }
|
||||
const GridFunction *GetNodes() const { return Nodes; }
|
||||
/// Return the mesh nodes ownership flag.
|
||||
@@ -1603,15 +1634,22 @@ public:
|
||||
/** Return the FiniteElementSpace on which the current mesh nodes are
|
||||
defined or NULL if the mesh does not have nodes. */
|
||||
const FiniteElementSpace *GetNodalFESpace() const;
|
||||
/** Make sure that the mesh has valid nodes, i.e. its geometry is described
|
||||
by a vector finite element grid function (even if it is a low-order mesh
|
||||
with straight edges). */
|
||||
/** @brief Make sure that the mesh has valid nodes, i.e. its geometry is
|
||||
described by a vector finite element grid function (even if it is a
|
||||
low-order mesh with straight edges).
|
||||
|
||||
@sa GetNodes(). */
|
||||
void EnsureNodes();
|
||||
|
||||
/** Set the curvature of the mesh nodes using the given polynomial degree,
|
||||
'order', and optionally: discontinuous or continuous FE space, 'discont',
|
||||
new space dimension, 'space_dim' (if != -1), and 'ordering' (byVDim by
|
||||
default). */
|
||||
/// Set the curvature of the mesh nodes using the given polynomial degree.
|
||||
/** Creates a nodal GridFunction if one doesn't already exist.
|
||||
|
||||
@param[in] order Polynomial degree of the nodal FE space.
|
||||
@param[in] discont Whether to use a discontinuous or continuous
|
||||
finite element space (continuous is default).
|
||||
@param[in] space_dim The space dimension (optional).
|
||||
@param[in] ordering The Ordering of the finite element space
|
||||
(Ordering::byVDIM is the default). */
|
||||
virtual void SetCurvature(int order, bool discont = false, int space_dim = -1,
|
||||
int ordering = 1);
|
||||
|
||||
|
||||
+12
-18
@@ -2107,8 +2107,6 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
// MFEM does not support pyramids yet
|
||||
case 7: el_order--; // 5-node pyramid
|
||||
case 14: el_order--; // 14-node pyramid (2nd order)
|
||||
case 118: el_order--; // 30-node pyramid (3rd order)
|
||||
@@ -2121,7 +2119,7 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
{
|
||||
el_order--; // Gmsh does not define an order 10 pyr
|
||||
elements_3D.push_back(
|
||||
new Pyramid(&vert_indices[0], phys_domain));
|
||||
new Pyramid(&vert_indices[0], phys_domain));
|
||||
if (el_order > 1)
|
||||
{
|
||||
Array<int> * hov = new Array<int>;
|
||||
@@ -2131,7 +2129,6 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
}
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case 15: // 1-node point
|
||||
{
|
||||
elements_0D.push_back(
|
||||
@@ -2336,8 +2333,6 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
// MFEM does not support pyramids yet
|
||||
case 7: el_order--; // 5-node pyramid
|
||||
case 14: el_order--; // 14-node pyramid (2nd order)
|
||||
case 118: el_order--; // 30-node pyramid (3rd order)
|
||||
@@ -2350,7 +2345,7 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
{
|
||||
el_order--;
|
||||
elements_3D.push_back(
|
||||
new Pyramid(&vert_indices[0], phys_domain));
|
||||
new Pyramid(&vert_indices[0], phys_domain));
|
||||
if (el_order > 1)
|
||||
{
|
||||
Array<int> * hov = new Array<int>;
|
||||
@@ -2360,7 +2355,6 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
}
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case 15: // 1-node point
|
||||
{
|
||||
elements_0D.push_back(
|
||||
@@ -2563,16 +2557,16 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
}
|
||||
vm = ho_wdg[el_order];
|
||||
break;
|
||||
// case Element::PYRAMID:
|
||||
// ho_verts = ho_verts_3D[el];
|
||||
// el_order = ho_el_order_3D[el];
|
||||
// if (ho_pyr[el_order])
|
||||
// {
|
||||
// ho_pyr[el_order] = new int[ho_verts->Size()];
|
||||
// GmshHOPyramidMapping(el_order, ho_pyr[el_order]);
|
||||
// }
|
||||
// vm = ho_pyr[el_order];
|
||||
// break;
|
||||
case Element::PYRAMID:
|
||||
ho_verts = ho_verts_3D[el];
|
||||
el_order = ho_el_order_3D[el];
|
||||
if (!ho_pyr[el_order])
|
||||
{
|
||||
ho_pyr[el_order] = new int[ho_verts->Size()];
|
||||
GmshHOPyramidMapping(el_order, ho_pyr[el_order]);
|
||||
}
|
||||
vm = ho_pyr[el_order];
|
||||
break;
|
||||
default: // Any other element type
|
||||
MFEM_WARNING("Unsupported Gmsh element type.");
|
||||
break;
|
||||
|
||||
+33
-12
@@ -3706,20 +3706,28 @@ void NCMesh::FindSetNeighbors(const Array<char> &elem_set,
|
||||
|
||||
static bool sorted_lists_intersect(const int* a, const int* b, int na, int nb)
|
||||
{
|
||||
if (!na || !nb) { return false; }
|
||||
int a_last = a[na-1], b_last = b[nb-1];
|
||||
if (*b < *a) { goto l2; } // woo-hoo! I always wanted to use a goto! :)
|
||||
l1:
|
||||
if (a_last < *b) { return false; }
|
||||
while (*a < *b) { a++; }
|
||||
if (*a == *b) { return true; }
|
||||
l2:
|
||||
if (b_last < *a) { return false; }
|
||||
while (*b < *a) { b++; }
|
||||
if (*a == *b) { return true; }
|
||||
goto l1;
|
||||
// pointers to "end" sentinel, not last entry. Not for dereferencing.
|
||||
const int * const a_end = a + na;
|
||||
const int * const b_end = b + nb;
|
||||
while (a != a_end && b != b_end)
|
||||
{
|
||||
if (*a < *b)
|
||||
{
|
||||
++a;
|
||||
}
|
||||
else if (*b < *a)
|
||||
{
|
||||
++b;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true; // neither *a < *b nor *b < *a thus a == b
|
||||
}
|
||||
}
|
||||
return false; // no common element found
|
||||
}
|
||||
|
||||
|
||||
void NCMesh::FindNeighbors(int elem, Array<int> &neighbors,
|
||||
const Array<int> *search_set)
|
||||
{
|
||||
@@ -4480,6 +4488,19 @@ void NCMesh::GetPointMatrix(Geometry::Type geom, const char* ref_path,
|
||||
pm = PointMatrix(mid12, mid20, mid01);
|
||||
}
|
||||
}
|
||||
else if (geom == Geometry::SEGMENT)
|
||||
{
|
||||
Point mid01(pm(0), pm(1));
|
||||
|
||||
if (child == 0)
|
||||
{
|
||||
pm = PointMatrix(pm(0), mid01);
|
||||
}
|
||||
else if (child == 1)
|
||||
{
|
||||
pm = PointMatrix(mid01, pm(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write the points to the matrix
|
||||
|
||||
@@ -2689,6 +2689,20 @@ STable3D *ParMesh::GetSharedFacesTable()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::PYRAMID:
|
||||
{
|
||||
for (int j = 0; j < 1; j++)
|
||||
{
|
||||
const int *fv = pyr_t::FaceVert[j];
|
||||
sfaces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
|
||||
}
|
||||
for (int j = 1; j < 5; j++)
|
||||
{
|
||||
const int *fv = pyr_t::FaceVert[j];
|
||||
sfaces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::HEXAHEDRON:
|
||||
{
|
||||
// find the face by the vertices with the smallest 3 numbers
|
||||
@@ -2796,6 +2810,61 @@ STable3D *ParMesh::GetFaceNbrElementToFaceTable(int ret_ftbl)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::PYRAMID:
|
||||
{
|
||||
for (int j = 0; j < 1; j++)
|
||||
{
|
||||
const int *fv = pyr_t::FaceVert[j];
|
||||
int k = 0;
|
||||
int max = v[fv[0]];
|
||||
|
||||
if (max < v[fv[1]]) { max = v[fv[1]], k = 1; }
|
||||
if (max < v[fv[2]]) { max = v[fv[2]], k = 2; }
|
||||
if (max < v[fv[3]]) { k = 3; }
|
||||
|
||||
int v0 = -1, v1 = -1, v2 = -1;
|
||||
switch (k)
|
||||
{
|
||||
case 0:
|
||||
v0 = v[fv[1]]; v1 = v[fv[2]]; v2 = v[fv[3]];
|
||||
break;
|
||||
case 1:
|
||||
v0 = v[fv[0]]; v1 = v[fv[2]]; v2 = v[fv[3]];
|
||||
break;
|
||||
case 2:
|
||||
v0 = v[fv[0]]; v1 = v[fv[1]]; v2 = v[fv[3]];
|
||||
break;
|
||||
case 3:
|
||||
v0 = v[fv[0]]; v1 = v[fv[1]]; v2 = v[fv[2]];
|
||||
break;
|
||||
}
|
||||
int lf = faces_tbl->Index(v0, v1, v2);
|
||||
if (lf < 0)
|
||||
{
|
||||
lf = sfaces_tbl->Index(v0, v1, v2);
|
||||
if (lf >= 0)
|
||||
{
|
||||
lf += NumOfFaces;
|
||||
}
|
||||
}
|
||||
face_nbr_el_to_face->Push(i, lf);
|
||||
}
|
||||
for (int j = 1; j < 5; j++)
|
||||
{
|
||||
const int *fv = pyr_t::FaceVert[j];
|
||||
int lf = faces_tbl->Index(v[fv[0]], v[fv[1]], v[fv[2]]);
|
||||
if (lf < 0)
|
||||
{
|
||||
lf = sfaces_tbl->Index(v[fv[0]], v[fv[1]], v[fv[2]]);
|
||||
if (lf >= 0)
|
||||
{
|
||||
lf += NumOfFaces;
|
||||
}
|
||||
}
|
||||
face_nbr_el_to_face->Push(i, lf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::HEXAHEDRON:
|
||||
{
|
||||
// find the face by the vertices with the smallest 3 numbers
|
||||
|
||||
+13
-4
@@ -501,6 +501,9 @@ public:
|
||||
/// mask & 4 - Loc1, mask & 8 - Loc2, mask & 16 - Face.
|
||||
/// These mask values are defined in the ConfigMasks enum type as part of the
|
||||
/// FaceElementTransformations class in fem/eltrans.hpp.
|
||||
///
|
||||
/// Note that the pointer is owned by the class and is shared, i.e., calling
|
||||
/// this function resets pointers obtained from previous calls.
|
||||
FaceElementTransformations *GetFaceElementTransformations(
|
||||
int FaceNo,
|
||||
int mask = 31) override;
|
||||
@@ -509,7 +512,9 @@ public:
|
||||
using the shared face index @a sf. @a fill2 specify if the information
|
||||
for elem2 of the face should be computed or not.
|
||||
In the returned object, 1 and 2 refer to the local and the neighbor
|
||||
elements, respectively. */
|
||||
elements, respectively.
|
||||
Note that the pointer is owned by the class and is shared, i.e., calling
|
||||
this function resets pointers obtained from previous calls. */
|
||||
FaceElementTransformations *
|
||||
GetSharedFaceTransformations(int sf, bool fill2 = true);
|
||||
|
||||
@@ -517,12 +522,16 @@ public:
|
||||
using the face index @a FaceNo. @a fill2 specify if the information
|
||||
for elem2 of the face should be computed or not.
|
||||
In the returned object, 1 and 2 refer to the local and the neighbor
|
||||
elements, respectively. */
|
||||
elements, respectively.
|
||||
Note that the pointer is owned by the class and is shared, i.e., calling
|
||||
this function resets pointers obtained from previous calls. */
|
||||
FaceElementTransformations *
|
||||
GetSharedFaceTransformationsByLocalIndex(int FaceNo, bool fill2 = true);
|
||||
|
||||
ElementTransformation *
|
||||
GetFaceNbrElementTransformation(int i)
|
||||
/// Returns a pointer to the transformation defining the i-th face neighbor.
|
||||
/// Note that the pointer is owned by the class and is shared, i.e., calling
|
||||
/// this function resets pointers obtained from previous calls.
|
||||
ElementTransformation *GetFaceNbrElementTransformation(int i)
|
||||
{
|
||||
GetFaceNbrElementTransformation(i, &FaceNbrTransformation);
|
||||
|
||||
|
||||
@@ -33,17 +33,17 @@ ParTransferMap::ParTransferMap(const ParGridFunction &src,
|
||||
|
||||
// There is no immediate relation and both src and dst come from a
|
||||
// SubMesh, check if they have an equivalent root parent.
|
||||
if (SubMeshUtils::GetRootParent<ParSubMesh, ParMesh>(*src_sm) !=
|
||||
SubMeshUtils::GetRootParent<ParSubMesh, ParMesh>(*dst_sm))
|
||||
if (SubMeshUtils::GetRootParent(*src_sm) !=
|
||||
SubMeshUtils::GetRootParent(*dst_sm))
|
||||
{
|
||||
MFEM_ABORT("Can't find a relation between the two GridFunctions");
|
||||
}
|
||||
|
||||
category_ = TransferCategory::SubMeshToSubMesh;
|
||||
|
||||
root_fes_ = new ParFiniteElementSpace(*src.ParFESpace(),
|
||||
*const_cast<ParMesh *>(SubMeshUtils::GetRootParent<ParSubMesh, ParMesh>
|
||||
(*src_sm)));
|
||||
root_fes_.reset(new ParFiniteElementSpace(
|
||||
*src.ParFESpace(),
|
||||
*const_cast<ParMesh *>(SubMeshUtils::GetRootParent(*src_sm))));
|
||||
subfes1 = src.ParFESpace();
|
||||
subfes2 = dst.ParFESpace();
|
||||
|
||||
@@ -214,9 +214,4 @@ void ParTransferMap::CommunicateSharedVdofs(Vector &f) const
|
||||
root_gc_->Bcast<double>(f.HostReadWrite());
|
||||
}
|
||||
|
||||
ParTransferMap::~ParTransferMap()
|
||||
{
|
||||
delete root_fes_;
|
||||
}
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "../../fem/pgridfunc.hpp"
|
||||
#include "transfer_category.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -52,8 +53,6 @@ public:
|
||||
*/
|
||||
void Transfer(const ParGridFunction &src, ParGridFunction &dst) const;
|
||||
|
||||
~ParTransferMap();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Communicate from each local processor which index in map is set.
|
||||
@@ -97,7 +96,7 @@ private:
|
||||
/// Pointer to the supplemental ParFiniteElementSpace on the common root
|
||||
/// parent ParMesh. This is only used if this ParTransferMap represents a
|
||||
/// ParSubMesh to ParSubMesh transfer.
|
||||
const ParFiniteElementSpace *root_fes_ = nullptr;
|
||||
std::unique_ptr<const ParFiniteElementSpace> root_fes_;
|
||||
|
||||
const GroupCommunicator *root_gc_ = nullptr;
|
||||
|
||||
|
||||
@@ -111,21 +111,15 @@ void BuildVdofToVdofMap(const FiniteElementSpace& subfes,
|
||||
* @tparam T The type of the input object which has to fulfill the
|
||||
* SubMesh::GetParent() interface.
|
||||
*/
|
||||
template <class T, class RT>
|
||||
const RT* GetRootParent(const T &m)
|
||||
template <class T, class RT = decltype(std::declval<T>().GetParent())>
|
||||
RT GetRootParent(const T &m)
|
||||
{
|
||||
const RT* parent = m.GetParent();
|
||||
RT parent = m.GetParent();
|
||||
while (true)
|
||||
{
|
||||
const T* next = dynamic_cast<const T*>(parent);
|
||||
if (next == nullptr)
|
||||
{
|
||||
return static_cast<const RT *>(parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent = next->GetParent();
|
||||
}
|
||||
if (next == nullptr) { return parent; }
|
||||
else { parent = next->GetParent(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,17 +29,17 @@ TransferMap::TransferMap(const GridFunction &src,
|
||||
|
||||
// There is no immediate relation and both src and dst come from a
|
||||
// SubMesh, check if they have an equivalent root parent.
|
||||
if (SubMeshUtils::GetRootParent<SubMesh, Mesh>(*src_sm) !=
|
||||
SubMeshUtils::GetRootParent<SubMesh, Mesh>(*dst_sm))
|
||||
if (SubMeshUtils::GetRootParent(*src_sm) !=
|
||||
SubMeshUtils::GetRootParent(*dst_sm))
|
||||
{
|
||||
MFEM_ABORT("Can't find a relation between the two GridFunctions");
|
||||
}
|
||||
|
||||
category_ = TransferCategory::SubMeshToSubMesh;
|
||||
|
||||
root_fes_ = new FiniteElementSpace(*src.FESpace(),
|
||||
const_cast<Mesh *>(SubMeshUtils::GetRootParent<SubMesh, Mesh>
|
||||
(*src_sm)));
|
||||
root_fes_.reset(new FiniteElementSpace(
|
||||
*src.FESpace(),
|
||||
const_cast<Mesh *>(SubMeshUtils::GetRootParent(*src_sm))));
|
||||
subfes1 = src.FESpace();
|
||||
subfes2 = dst.FESpace();
|
||||
|
||||
@@ -138,8 +138,3 @@ void TransferMap::Transfer(const GridFunction &src,
|
||||
MFEM_ABORT("unknown TransferCategory: " << category_);
|
||||
}
|
||||
}
|
||||
|
||||
TransferMap::~TransferMap()
|
||||
{
|
||||
delete root_fes_;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "../../fem/gridfunc.hpp"
|
||||
#include "transfer_category.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -50,8 +51,6 @@ public:
|
||||
*/
|
||||
void Transfer(const GridFunction &src, GridFunction &dst) const;
|
||||
|
||||
~TransferMap();
|
||||
|
||||
private:
|
||||
TransferCategory category_;
|
||||
|
||||
@@ -67,7 +66,7 @@ private:
|
||||
/// Pointer to the supplemental FiniteElementSpace on the common root parent
|
||||
/// Mesh. This is only used if this TransferMap represents a SubMesh to
|
||||
/// SubMesh transfer.
|
||||
const FiniteElementSpace *root_fes_ = nullptr;
|
||||
std::unique_ptr<const FiniteElementSpace> root_fes_;
|
||||
|
||||
/// Temporary vector
|
||||
mutable Vector z_;
|
||||
@@ -75,4 +74,4 @@ private:
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_TRANSFERMAP
|
||||
#endif // MFEM_TRANSFERMAP
|
||||
|
||||
@@ -62,6 +62,10 @@ add_mfem_miniapp(minimal-surface
|
||||
MAIN minimal-surface.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(reflector
|
||||
MAIN reflector.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
add_mfem_miniapp(toroid
|
||||
MAIN toroid.cpp
|
||||
LIBRARIES mfem)
|
||||
|
||||
@@ -26,7 +26,7 @@ MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
SEQ_MINIAPPS = mobius-strip klein-bottle toroid trimmer twist mesh-explorer\
|
||||
shaper extruder mesh-optimizer minimal-surface polar-nc
|
||||
shaper extruder mesh-optimizer minimal-surface polar-nc reflector
|
||||
PAR_MINIAPPS = pmesh-optimizer pminimal-surface
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
MINIAPPS = $(SEQ_MINIAPPS)
|
||||
@@ -91,6 +91,8 @@ minimal-surface-test-seq: minimal-surface
|
||||
@$(call mfem-test,$<,, Meshing miniapp)
|
||||
pminimal-surface-test-par: pminimal-surface
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Parallel meshing miniapp)
|
||||
reflector-test-seq: reflector
|
||||
@$(call mfem-test-file,$<,, Meshing miniapp,reflected.mesh)
|
||||
|
||||
# Testing: Specific execution options
|
||||
mesh-explorer-test-seq:
|
||||
@@ -108,13 +110,14 @@ clean: clean-build clean-exec
|
||||
|
||||
clean-build:
|
||||
rm -f *.o *~ mobius-strip klein-bottle toroid twist
|
||||
rm -f mesh-explorer shaper extruder trimmer
|
||||
rm -f mesh-explorer shaper extruder trimmer reflector
|
||||
rm -f mesh-optimizer pmesh-optimizer polar-nc
|
||||
rm -f minimal-surface pminimal-surface
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
clean-exec:
|
||||
@rm -f mobius-strip.mesh klein-bottle.mesh mesh-explorer.mesh
|
||||
@rm -f toroid-*.mesh twist-*.mesh trimmer.mesh
|
||||
@rm -f toroid-*.mesh twist-*.mesh trimmer.mesh reflected.mesh
|
||||
@rm -f partitioning.txt shaper.mesh extruder.mesh
|
||||
@rm -f optimized* perturbed* polar-nc.mesh
|
||||
@rm -rf mesh-explorer-{visit,paraview}*
|
||||
|
||||
@@ -384,6 +384,7 @@ int main (int argc, char *argv[])
|
||||
"o) Reorder elements\n"
|
||||
"S) Save in MFEM format\n"
|
||||
"V) Save in VTK format (only linear and quadratic meshes)\n"
|
||||
"D) Save as a DataCollection\n"
|
||||
"q) Quit\n"
|
||||
#ifdef MFEM_USE_ZLIB
|
||||
"Z) Save in MFEM format with compression\n"
|
||||
@@ -958,7 +959,9 @@ int main (int argc, char *argv[])
|
||||
cin >> nxyz[2]; np *= nxyz[2];
|
||||
}
|
||||
}
|
||||
partitioning = Array<int>(mesh->CartesianPartitioning(nxyz), mesh->GetNE());
|
||||
int *part = mesh->CartesianPartitioning(nxyz);
|
||||
partitioning = Array<int>(part, mesh->GetNE());
|
||||
delete [] part;
|
||||
recover_bdr_partitioning(mesh, partitioning, bdr_partitioning);
|
||||
}
|
||||
else if (pk == 's')
|
||||
@@ -982,8 +985,9 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
cout << "Enter number of processors: " << flush;
|
||||
cin >> np;
|
||||
partitioning = Array<int>(mesh->GeneratePartitioning(np, part_method),
|
||||
mesh->GetNE());
|
||||
int *part = mesh->GeneratePartitioning(np, part_method);
|
||||
partitioning = Array<int>(part, mesh->GetNE());
|
||||
delete [] part;
|
||||
recover_bdr_partitioning(mesh, partitioning, bdr_partitioning);
|
||||
}
|
||||
if (partitioning)
|
||||
@@ -1190,6 +1194,46 @@ int main (int argc, char *argv[])
|
||||
cout << "New VTK mesh file: " << omesh_file << endl;
|
||||
}
|
||||
|
||||
if (mk == 'D')
|
||||
{
|
||||
cout << "What type of DataCollection?\n"
|
||||
"p) ParaView Data Collection\n"
|
||||
"v) VisIt Data Collection\n"
|
||||
"--> " << flush;
|
||||
char dk;
|
||||
cin >> dk;
|
||||
if (dk == 'p' || dk == 'P')
|
||||
{
|
||||
const char omesh_file[] = "mesh-explorer-paraview";
|
||||
ParaViewDataCollection dc(omesh_file, mesh);
|
||||
if (mesh->GetNodes())
|
||||
{
|
||||
int order = mesh->GetNodes()->FESpace()->GetMaxElementOrder();
|
||||
if (order > 1)
|
||||
{
|
||||
dc.SetHighOrderOutput(true);
|
||||
dc.SetLevelsOfDetail(order);
|
||||
}
|
||||
}
|
||||
dc.Save();
|
||||
cout << "New ParaView mesh file: " << omesh_file << endl;
|
||||
}
|
||||
else if (dk == 'v' || dk == 'V')
|
||||
{
|
||||
const char omesh_file[] = "mesh-explorer-visit";
|
||||
VisItDataCollection dc(omesh_file, mesh);
|
||||
dc.SetPrecision(14);
|
||||
dc.Save();
|
||||
cout << "New VisIt mesh file: " << omesh_file << "_000000.mfem_root"
|
||||
<< endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Unrecognized DataCollection type: \"" << dk << "\""
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_ZLIB
|
||||
if (mk == 'Z')
|
||||
{
|
||||
|
||||
@@ -57,10 +57,8 @@
|
||||
// Adapted discrete size+aspect_ratio:
|
||||
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100
|
||||
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -qo 6 -ex -st 1 -nor
|
||||
// Adapted discrete size+orientation (requires GSLIB):
|
||||
// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -fd -ae 1 -nor
|
||||
// Adapted discrete aspect-ratio+orientation (requires GSLIB):
|
||||
// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 8 -ni 10 -bnd -qt 1 -qo 8 -fd -ae 1
|
||||
// Adapted discrete size+orientation:
|
||||
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -fd -nor
|
||||
// Adapted discrete aspect ratio (3D):
|
||||
// mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -bnd -qt 1 -qo 8
|
||||
//
|
||||
@@ -86,7 +84,7 @@
|
||||
// Blade limited shape:
|
||||
// mesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -bnd -qt 1 -qo 8 -lc 5000
|
||||
// ICF shape and equal size:
|
||||
// mesh-optimizer -o 3 -mid 9 -tid 2 -ni 25 -ls 3 -art 2 -qo 5
|
||||
// mesh-optimizer -o 3 -mid 80 -bec -tid 2 -ni 25 -ls 3 -art 2 -qo 5
|
||||
// ICF shape and initial size:
|
||||
// mesh-optimizer -o 3 -mid 9 -tid 3 -ni 30 -ls 3 -bnd -qt 1 -qo 8
|
||||
// ICF shape:
|
||||
@@ -140,6 +138,7 @@ int main(int argc, char *argv[])
|
||||
int max_lin_iter = 100;
|
||||
bool move_bnd = true;
|
||||
int combomet = 0;
|
||||
bool bal_expl_combo = false;
|
||||
bool hradaptivity = false;
|
||||
int h_metric_id = -1;
|
||||
bool normalization = false;
|
||||
@@ -258,6 +257,9 @@ int main(int argc, char *argv[])
|
||||
"0: Use single metric\n\t"
|
||||
"1: Shape + space-dependent size given analytically\n\t"
|
||||
"2: Shape + adapted size given discretely; shared target");
|
||||
args.AddOption(&bal_expl_combo, "-bec", "--balance-explicit-combo",
|
||||
"-no-bec", "--balance-explicit-combo",
|
||||
"Automatic balancing of explicit combo metrics.");
|
||||
args.AddOption(&hradaptivity, "-hr", "--hr-adaptivity", "-no-hr",
|
||||
"--no-hr-adaptivity",
|
||||
"Enable hr-adaptivity.");
|
||||
@@ -740,20 +742,9 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
}
|
||||
|
||||
if (metric_id == 14 || metric_id == 36)
|
||||
{
|
||||
ConstantCoefficient size_coeff(0.1*0.1);
|
||||
size.ProjectCoefficient(size_coeff);
|
||||
tc->SetSerialDiscreteTargetSize(size);
|
||||
}
|
||||
|
||||
if (metric_id == 85)
|
||||
{
|
||||
FunctionCoefficient aspr_coeff(discrete_aspr_2d);
|
||||
aspr.ProjectCoefficient(aspr_coeff);
|
||||
DiffuseField(aspr,2);
|
||||
tc->SetSerialDiscreteTargetAspectRatio(aspr);
|
||||
}
|
||||
ConstantCoefficient size_coeff(0.1*0.1);
|
||||
size.ProjectCoefficient(size_coeff);
|
||||
tc->SetSerialDiscreteTargetSize(size);
|
||||
|
||||
FunctionCoefficient ori_coeff(discrete_ori_2d);
|
||||
ori.ProjectCoefficient(ori_coeff);
|
||||
@@ -780,6 +771,16 @@ int main(int argc, char *argv[])
|
||||
target_c = new TargetConstructor(target_t);
|
||||
}
|
||||
target_c->SetNodes(x0);
|
||||
|
||||
// Automatically balanced gamma in composite metrics.
|
||||
auto metric_combo = dynamic_cast<TMOP_Combo_QualityMetric *>(metric);
|
||||
if (metric_combo && bal_expl_combo)
|
||||
{
|
||||
Vector bal_weights;
|
||||
metric_combo->ComputeBalancedWeights(x, *target_c, bal_weights);
|
||||
metric_combo->SetWeights(bal_weights);
|
||||
}
|
||||
|
||||
TMOP_QualityMetric *metric_to_use = barrier_type > 0 || worst_case_type > 0
|
||||
? untangler_metric
|
||||
: metric;
|
||||
@@ -790,7 +791,6 @@ int main(int argc, char *argv[])
|
||||
tmop_integ->ComputeUntangleMetricQuantiles(x, *fespace);
|
||||
}
|
||||
|
||||
|
||||
// Finite differences for computations of derivatives.
|
||||
if (fdscheme)
|
||||
{
|
||||
@@ -1208,6 +1208,7 @@ int main(int argc, char *argv[])
|
||||
mesh->Print(mesh_ofs);
|
||||
}
|
||||
|
||||
// Report the final energy of the functional.
|
||||
const double fin_energy = a.GetGridFunctionEnergy(x) /
|
||||
(hradaptivity ? mesh->GetNE() : 1);
|
||||
double fin_metric_energy = fin_energy;
|
||||
@@ -1232,7 +1233,7 @@ int main(int argc, char *argv[])
|
||||
cout << "The strain energy decreased by: "
|
||||
<< (init_energy - fin_energy) * 100.0 / init_energy << " %." << endl;
|
||||
|
||||
// 16. Visualize the final mesh and metric values.
|
||||
// Visualize the final mesh and metric values.
|
||||
if (visualization)
|
||||
{
|
||||
char title[] = "Final metric values";
|
||||
@@ -1246,6 +1247,7 @@ int main(int argc, char *argv[])
|
||||
600, 600, 300, 300);
|
||||
}
|
||||
|
||||
// Visualize fitting surfaces and report fitting errors.
|
||||
if (surface_fit_const > 0.0)
|
||||
{
|
||||
if (visualization)
|
||||
@@ -1262,7 +1264,7 @@ int main(int argc, char *argv[])
|
||||
<< "Max fitting error: " << err_max << std::endl;
|
||||
}
|
||||
|
||||
// 17. Visualize the mesh displacement.
|
||||
// Visualize the mesh displacement.
|
||||
if (visualization)
|
||||
{
|
||||
osockstream sock(19916, "localhost");
|
||||
|
||||
@@ -84,24 +84,6 @@ double discrete_ori_2d(const Vector &x)
|
||||
return M_PI * x(1) * (1.0 - x(1)) * cos(2 * M_PI * x(0));
|
||||
}
|
||||
|
||||
double discrete_aspr_2d(const Vector &x)
|
||||
{
|
||||
double xc = x(0)-0.5, yc = x(1)-0.5;
|
||||
double th = 22.5*M_PI/180.;
|
||||
double xn = cos(th)*xc + sin(th)*yc;
|
||||
double yn = -sin(th)*xc + cos(th)*yc;
|
||||
xc = xn; yc = yn;
|
||||
|
||||
double tfac = 20;
|
||||
double s1 = 3;
|
||||
double s2 = 2;
|
||||
double wgt = std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) + 1)
|
||||
- std::tanh((tfac*(yc) + s2*std::sin(s1*M_PI*xc)) - 1);
|
||||
if (wgt > 1) { wgt = 1; }
|
||||
if (wgt < 0) { wgt = 0; }
|
||||
return 0.1 + 1*(1-wgt)*(1-wgt);
|
||||
}
|
||||
|
||||
void discrete_aspr_3d(const Vector &x, Vector &v)
|
||||
{
|
||||
int dim = x.Size();
|
||||
|
||||
@@ -77,7 +77,6 @@ constexpr Element::Type QUAD = Element::QUADRILATERAL;
|
||||
constexpr double NL_DMAX = std::numeric_limits<double>::max();
|
||||
|
||||
// Static variables for GLVis
|
||||
static socketstream glvis;
|
||||
constexpr int GLVIZ_W = 1024;
|
||||
constexpr int GLVIZ_H = 1024;
|
||||
constexpr int visport = 19916;
|
||||
@@ -118,8 +117,10 @@ protected:
|
||||
Opt &opt;
|
||||
Mesh *mesh;
|
||||
Array<int> bc;
|
||||
socketstream glvis;
|
||||
H1_FECollection *fec;
|
||||
FiniteElementSpace *fes;
|
||||
|
||||
public:
|
||||
// Reading from mesh file
|
||||
Surface(Opt &opt, const char *file): Mesh(file, true), opt(opt) { }
|
||||
@@ -157,7 +158,7 @@ public:
|
||||
// Initialize GLVis server if 'visualization' is set
|
||||
if (opt.vis) { opt.vis = glvis.open(vishost, visport) == 0; }
|
||||
// Send to GLVis the first mesh
|
||||
if (opt.vis) { Visualize(opt, mesh, GLVIZ_W, GLVIZ_H); }
|
||||
if (opt.vis) { Visualize(glvis, opt, mesh, GLVIZ_W, GLVIZ_H); }
|
||||
// Create and launch the surface solver
|
||||
if (opt.by_vdim)
|
||||
{
|
||||
@@ -170,7 +171,7 @@ public:
|
||||
if (opt.vis && opt.snapshot)
|
||||
{
|
||||
opt.keys = "Sq";
|
||||
Visualize(opt, mesh, mesh->GetNodes());
|
||||
Visualize(glvis, opt, mesh, mesh->GetNodes());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -243,7 +244,8 @@ public:
|
||||
}
|
||||
|
||||
// Initialize visualization of some given mesh
|
||||
static void Visualize(Opt &opt, const Mesh *mesh,
|
||||
static void Visualize(socketstream &glvis,
|
||||
Opt &opt, const Mesh *mesh,
|
||||
const int w, const int h,
|
||||
const GridFunction *sol = nullptr)
|
||||
{
|
||||
@@ -259,7 +261,8 @@ public:
|
||||
}
|
||||
|
||||
// Visualize some solution on the given mesh
|
||||
static void Visualize(const Opt &opt, const Mesh *mesh,
|
||||
static void Visualize(socketstream &glvis,
|
||||
const Opt &opt, const Mesh *mesh,
|
||||
const GridFunction *sol = nullptr)
|
||||
{
|
||||
const GridFunction &solution = sol ? *sol : *mesh->GetNodes();
|
||||
@@ -324,7 +327,7 @@ public:
|
||||
for (int i=0; i < opt.niters; ++i)
|
||||
{
|
||||
if (opt.amr) { Amr(); }
|
||||
if (opt.vis) { Surface::Visualize(opt, S.mesh); }
|
||||
if (opt.vis) { Surface::Visualize(S.glvis, opt, S.mesh); }
|
||||
if (!opt.id) { mfem::out << "Iteration " << i << ": "; }
|
||||
S.mesh->NodesUpdated();
|
||||
a.Update();
|
||||
@@ -1237,8 +1240,9 @@ static int Problem1(Opt &opt)
|
||||
GridFunction uold(&fes), u(&fes), b(&fes);
|
||||
FunctionCoefficient u0_fc(u0);
|
||||
u.ProjectCoefficient(u0_fc);
|
||||
socketstream glvis;
|
||||
if (opt.vis) { opt.vis = glvis.open(vishost, visport) == 0; }
|
||||
if (opt.vis) { Surface::Visualize(opt, &mesh, GLVIZ_W, GLVIZ_H, &u); }
|
||||
if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, GLVIZ_W, GLVIZ_H, &u); }
|
||||
CGSolver cg;
|
||||
cg.SetRelTol(EPS);
|
||||
cg.SetAbsTol(EPS*EPS);
|
||||
@@ -1270,7 +1274,7 @@ static int Problem1(Opt &opt)
|
||||
mfem::out << "Iteration " << i << ", norm: " << norm
|
||||
<< ", area: " << area << std::endl;
|
||||
}
|
||||
if (opt.vis) { Surface::Visualize(opt, &mesh, &u); }
|
||||
if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, &u); }
|
||||
if (opt.print) { Surface::Print(opt, &mesh, &u); }
|
||||
if (norm < NRM) { break; }
|
||||
}
|
||||
|
||||
@@ -57,10 +57,8 @@
|
||||
// Adapted discrete size+aspect_ratio:
|
||||
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100
|
||||
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -qo 6 -ex -st 1 -nor
|
||||
// Adapted discrete size+orientation (requires GSLIB):
|
||||
// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -fd -ae 1 -nor
|
||||
// Adapted discrete aspect-ratio+orientation (requires GSLIB):
|
||||
// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 8 -ni 10 -bnd -qt 1 -qo 8 -fd -ae 1
|
||||
// Adapted discrete size+orientation:
|
||||
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -fd -nor
|
||||
// Adapted discrete aspect ratio (3D):
|
||||
// mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -bnd -qt 1 -qo 8
|
||||
//
|
||||
@@ -86,7 +84,7 @@
|
||||
// Blade limited shape:
|
||||
// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -bnd -qt 1 -qo 8 -lc 5000
|
||||
// ICF shape and equal size:
|
||||
// mpirun -np 4 pmesh-optimizer -o 3 -mid 9 -tid 2 -ni 25 -ls 3 -art 2 -qo 5
|
||||
// mpirun -np 4 pmesh-optimizer -o 3 -mid 80 -bec -tid 2 -ni 25 -ls 3 -art 2 -qo 5
|
||||
// ICF shape and initial size:
|
||||
// mpirun -np 4 pmesh-optimizer -o 3 -mid 9 -tid 3 -ni 30 -ls 3 -bnd -qt 1 -qo 8
|
||||
// ICF shape:
|
||||
@@ -150,6 +148,7 @@ int main (int argc, char *argv[])
|
||||
int max_lin_iter = 100;
|
||||
bool move_bnd = true;
|
||||
int combomet = 0;
|
||||
bool bal_expl_combo = false;
|
||||
bool hradaptivity = false;
|
||||
int h_metric_id = -1;
|
||||
bool normalization = false;
|
||||
@@ -270,6 +269,9 @@ int main (int argc, char *argv[])
|
||||
"0: Use single metric\n\t"
|
||||
"1: Shape + space-dependent size given analytically\n\t"
|
||||
"2: Shape + adapted size given discretely; shared target");
|
||||
args.AddOption(&bal_expl_combo, "-bec", "--balance-explicit-combo",
|
||||
"-no-bec", "--balance-explicit-combo",
|
||||
"Automatic balancing of explicit combo metrics.");
|
||||
args.AddOption(&hradaptivity, "-hr", "--hr-adaptivity", "-no-hr",
|
||||
"--no-hr-adaptivity",
|
||||
"Enable hr-adaptivity.");
|
||||
@@ -372,9 +374,6 @@ int main (int argc, char *argv[])
|
||||
// transformation of the reference element.
|
||||
pmesh->SetNodalFESpace(pfespace);
|
||||
|
||||
// 6. Set up an empty right-hand side vector b, which is equivalent to b=0.
|
||||
Vector b(0);
|
||||
|
||||
// 7. Get the mesh nodes (vertices and other degrees of freedom in the finite
|
||||
// element space) as a finite element grid function in fespace. Note that
|
||||
// changing x automatically changes the shapes of the mesh elements.
|
||||
@@ -774,20 +773,9 @@ int main (int argc, char *argv[])
|
||||
#endif
|
||||
}
|
||||
|
||||
if (metric_id == 14 || metric_id == 36)
|
||||
{
|
||||
ConstantCoefficient size_coeff(0.1*0.1);
|
||||
size.ProjectCoefficient(size_coeff);
|
||||
tc->SetParDiscreteTargetSize(size);
|
||||
}
|
||||
|
||||
if (metric_id == 85)
|
||||
{
|
||||
FunctionCoefficient aspr_coeff(discrete_aspr_2d);
|
||||
aspr.ProjectCoefficient(aspr_coeff);
|
||||
DiffuseField(aspr,2);
|
||||
tc->SetParDiscreteTargetAspectRatio(aspr);
|
||||
}
|
||||
ConstantCoefficient size_coeff(0.1*0.1);
|
||||
size.ProjectCoefficient(size_coeff);
|
||||
tc->SetParDiscreteTargetSize(size);
|
||||
|
||||
FunctionCoefficient ori_coeff(discrete_ori_2d);
|
||||
ori.ProjectCoefficient(ori_coeff);
|
||||
@@ -811,12 +799,21 @@ int main (int argc, char *argv[])
|
||||
if (myid == 0) { cout << "Unknown target_id: " << target_id << endl; }
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (target_c == NULL)
|
||||
{
|
||||
target_c = new TargetConstructor(target_t, MPI_COMM_WORLD);
|
||||
}
|
||||
target_c->SetNodes(x0);
|
||||
|
||||
// Automatically balanced gamma in composite metrics.
|
||||
auto metric_combo = dynamic_cast<TMOP_Combo_QualityMetric *>(metric);
|
||||
if (metric_combo && bal_expl_combo)
|
||||
{
|
||||
Vector bal_weights;
|
||||
metric_combo->ComputeBalancedWeights(x, *target_c, bal_weights);
|
||||
metric_combo->SetWeights(bal_weights);
|
||||
}
|
||||
|
||||
TMOP_QualityMetric *metric_to_use = barrier_type > 0 || worst_case_type > 0
|
||||
? untangler_metric
|
||||
: metric;
|
||||
@@ -827,7 +824,6 @@ int main (int argc, char *argv[])
|
||||
tmop_integ->ComputeUntangleMetricQuantiles(x, *pfespace);
|
||||
}
|
||||
|
||||
|
||||
// Finite differences for computations of derivatives.
|
||||
if (fdscheme)
|
||||
{
|
||||
@@ -1256,7 +1252,7 @@ int main (int argc, char *argv[])
|
||||
pmesh->PrintAsOne(mesh_ofs);
|
||||
}
|
||||
|
||||
// Compute the final energy of the functional.
|
||||
// Report the final energy of the functional.
|
||||
const double fin_energy = a.GetParGridFunctionEnergy(x) /
|
||||
(hradaptivity ? pmesh->GetGlobalNE() : 1);
|
||||
double fin_metric_energy = fin_energy;
|
||||
@@ -1284,7 +1280,7 @@ int main (int argc, char *argv[])
|
||||
<< (init_energy - fin_energy) * 100.0 / init_energy << " %." << endl;
|
||||
}
|
||||
|
||||
// 18. Visualize the final mesh and metric values.
|
||||
// Visualize the final mesh and metric values.
|
||||
if (visualization)
|
||||
{
|
||||
char title[] = "Final metric values";
|
||||
@@ -1298,6 +1294,7 @@ int main (int argc, char *argv[])
|
||||
600, 600, 300, 300);
|
||||
}
|
||||
|
||||
// Visualize fitting surfaces and report fitting errors.
|
||||
if (surface_fit_const > 0.0)
|
||||
{
|
||||
if (visualization)
|
||||
@@ -1317,7 +1314,7 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 19. Visualize the mesh displacement.
|
||||
// Visualize the mesh displacement.
|
||||
if (visualization)
|
||||
{
|
||||
x0 -= x;
|
||||
@@ -1338,7 +1335,6 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 20. Free the used memory.
|
||||
delete S;
|
||||
delete S_prec;
|
||||
delete target_c2;
|
||||
|
||||
@@ -77,7 +77,6 @@ constexpr Element::Type QUAD = Element::QUADRILATERAL;
|
||||
constexpr double NL_DMAX = std::numeric_limits<double>::max();
|
||||
|
||||
// Static variables for GLVis
|
||||
static socketstream glvis;
|
||||
constexpr int GLVIZ_W = 1024;
|
||||
constexpr int GLVIZ_H = 1024;
|
||||
constexpr int visport = 19916;
|
||||
@@ -118,6 +117,7 @@ protected:
|
||||
Opt &opt;
|
||||
ParMesh *mesh;
|
||||
Array<int> bc;
|
||||
socketstream glvis;
|
||||
H1_FECollection *fec;
|
||||
ParFiniteElementSpace *fes;
|
||||
public:
|
||||
@@ -157,7 +157,7 @@ public:
|
||||
// Initialize GLVis server if 'visualization' is set
|
||||
if (opt.vis) { opt.vis = glvis.open(vishost, visport) == 0; }
|
||||
// Send to GLVis the first mesh
|
||||
if (opt.vis) { Visualize(opt, mesh, GLVIZ_W, GLVIZ_H); }
|
||||
if (opt.vis) { Visualize(glvis, opt, mesh, GLVIZ_W, GLVIZ_H); }
|
||||
// Create and launch the surface solver
|
||||
if (opt.by_vdim)
|
||||
{
|
||||
@@ -170,7 +170,7 @@ public:
|
||||
if (opt.vis && opt.snapshot)
|
||||
{
|
||||
opt.keys = "Sq";
|
||||
Visualize(opt, mesh, mesh->GetNodes());
|
||||
Visualize(glvis, opt, mesh, mesh->GetNodes());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -243,7 +243,8 @@ public:
|
||||
}
|
||||
|
||||
// Initialize visualization of some given mesh
|
||||
static void Visualize(Opt &opt, const Mesh *mesh,
|
||||
static void Visualize(socketstream &glvis,
|
||||
Opt &opt, const Mesh *mesh,
|
||||
const int w, const int h,
|
||||
const GridFunction *sol = nullptr)
|
||||
{
|
||||
@@ -259,7 +260,8 @@ public:
|
||||
}
|
||||
|
||||
// Visualize some solution on the given mesh
|
||||
static void Visualize(const Opt &opt, const Mesh *mesh,
|
||||
static void Visualize(socketstream &glvis,
|
||||
const Opt &opt, const Mesh *mesh,
|
||||
const GridFunction *sol = nullptr)
|
||||
{
|
||||
glvis << "parallel " << opt.sz << " " << opt.id << "\n";
|
||||
@@ -328,7 +330,7 @@ public:
|
||||
for (int i=0; i < opt.niters; ++i)
|
||||
{
|
||||
if (opt.amr) { Amr(); }
|
||||
if (opt.vis) { Surface::Visualize(opt, S.mesh); }
|
||||
if (opt.vis) { Surface::Visualize(S.glvis, opt, S.mesh); }
|
||||
if (!opt.id) { mfem::out << "Iteration " << i << ": "; }
|
||||
S.mesh->NodesUpdated();
|
||||
a.Update();
|
||||
@@ -1246,8 +1248,9 @@ static int Problem1(Opt &opt)
|
||||
ParGridFunction uold(&fes), u(&fes), b(&fes);
|
||||
FunctionCoefficient u0_fc(u0);
|
||||
u.ProjectCoefficient(u0_fc);
|
||||
socketstream glvis;
|
||||
if (opt.vis) { opt.vis = glvis.open(vishost, visport) == 0; }
|
||||
if (opt.vis) { Surface::Visualize(opt, &mesh, GLVIZ_W, GLVIZ_H, &u); }
|
||||
if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, GLVIZ_W, GLVIZ_H, &u); }
|
||||
Vector B, X;
|
||||
OperatorPtr A;
|
||||
CGSolver cg(MPI_COMM_WORLD);
|
||||
@@ -1279,7 +1282,7 @@ static int Problem1(Opt &opt)
|
||||
mfem::out << "Iteration " << i << ", norm: " << norm
|
||||
<< ", area: " << area << std::endl;
|
||||
}
|
||||
if (opt.vis) { Surface::Visualize(opt, &mesh, &u); }
|
||||
if (opt.vis) { Surface::Visualize(glvis, opt, &mesh, &u); }
|
||||
if (opt.print) { Surface::Print(opt, &mesh, &u); }
|
||||
if (norm < NRM) { break; }
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
#include "integ_algoim.hpp"
|
||||
|
||||
|
||||
#if defined(MFEM_USE_ALGOIM) && defined(MFEM_USE_BLITZ)
|
||||
#ifdef MFEM_USE_ALGOIM
|
||||
|
||||
|
||||
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