Compare commits

..
111 changed files with 2277 additions and 11568 deletions
-13
View File
@@ -57,8 +57,6 @@ examples/ex2[0-9]
examples/ex2[0-9]p
examples/ex3[0-9]
examples/ex3[0-9]p
examples/ex4[0-9]
examples/ex4[0-9]p
examples/refined.mesh
examples/displaced.mesh
@@ -272,27 +270,16 @@ miniapps/navier/*_output
miniapps/nurbs/nurbs_ex1
miniapps/nurbs/nurbs_ex1p
miniapps/nurbs/nurbs_ex3
miniapps/nurbs/nurbs_ex5
miniapps/nurbs/nurbs_ex11p
miniapps/nurbs/nurbs_ex24
miniapps/nurbs/nurbs_solenoidal
miniapps/nurbs/nurbs_printfunc
miniapps/nurbs/nurbs_patch_ex1
miniapps/nurbs/nurbs_curveint
miniapps/nurbs/refined.mesh
miniapps/nurbs/mesh.*
miniapps/nurbs/sol_?.gf
miniapps/nurbs/sol.*
miniapps/nurbs/mode_*
miniapps/nurbs/Example1*
miniapps/nurbs/Example3*
miniapps/nurbs/Example5*
miniapps/nurbs/Solenoidal*
miniapps/nurbs/ParaView
miniapps/nurbs/sin-fit.mesh
miniapps/nurbs/ex5.mesh
miniapps/nurbs/exsol.mesh
miniapps/nurbs/CurveInt
miniapps/nurbs/nurbs_naca_cmesh
miniapps/nurbs/naca-cmesh.mesh
-3
View File
@@ -13,9 +13,6 @@
# at Lawrence Livermore National Laboratory (LLNL). This entire pipeline is
# LLNL-specific!
include:
- project: 'lc-templates/id_tokens'
file: 'id_tokens.yml'
# The pipeline is divided into stages. Usually, jobs in a given stage wait for
# the preceding stages to complete before to start. However, we sometimes use
-4
View File
@@ -9,10 +9,6 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
include:
- project: 'lc-templates/id_tokens'
file: 'id_tokens.yml'
# We define the following GitLab pipeline variables:
variables:
+4 -3
View File
@@ -35,8 +35,9 @@ variables:
- when: on_success
# Lassen uses a different job scheduler (spectrum lsf) that does not allow
# pre-allocation the same way slurm does. We use the pci queue on lassen
# to speed-up the allocation.
# pre-allocation the same way slurm does. We use pdebug queue on lassen
# to speed-up the allocation. However this would not be scalable to
# multiple builds.
.build_and_test_on_lassen:
extends: [.on_lassen]
stage: build_and_test
@@ -44,5 +45,5 @@ variables:
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
# Next script uses 'THREADS': leaving it empty --> it uses 'make all -j'
- lalloc 1 -W 45 -q pci --atsdisable tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
- lalloc 1 -W 45 -q pdebug --atsdisable tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
needs: [setup]
+1 -1
View File
@@ -52,4 +52,4 @@ variables:
- echo ${JOBID}
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) --reservation=ci -t 45 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) -t 45 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
+4 -4
View File
@@ -14,14 +14,14 @@ stages:
- build_and_test
- report
opt_mpi_cuda_gcc:
opt_mpi_cuda_xl_16_1_1_12:
variables:
SPEC: "%gcc@8.3.1 +mpi +cuda cuda_arch=70"
SPEC: "%xl@16.1.1.12 +mpi +cuda cuda_arch=70"
extends: .build_and_test_on_lassen
opt_mpi_cuda_hypre_cuda_gcc:
opt_mpi_cuda_hypre_cuda_xl:
variables:
SPEC: "%gcc@8.3.1 +mpi +cuda cuda_arch=70 ^hypre+cuda~shared cuda_arch=70"
SPEC: "%xl@16.1.1.12 +mpi +cuda cuda_arch=70 ^hypre+cuda~shared cuda_arch=70"
extends: .build_and_test_on_lassen
# Jobs report
+2 -2
View File
@@ -32,11 +32,11 @@ mkdir _${BASELINE_TEST} && cd _${BASELINE_TEST}
# run
if [[ "${MACHINE_NAME}" == "quartz" || "${MACHINE_NAME}" == "ruby" ]]; then
salloc --nodes=1 --reservation=ci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
salloc --nodes=1 -p pdebug ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
elif [[ ${MACHINE_NAME} == "corona" ]]; then
salloc --nodes=1 -t 60 -p pbatch ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
elif [[ ${MACHINE_NAME} == "lassen" ]]; then
lalloc 1 -q pci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
lalloc 1 -q pdebug ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
else
echo "Unknown machine: MACHINE_NAME=$MACHINE_NAME"
exit 1
-10
View File
@@ -11,16 +11,6 @@
Version 4.7.1 (development)
===========================
- Added NURBS-based H(div) and H(curl) elements in 2D and 3D. Only on single
patch meshes. Only implemented for serial computations.
- Added miniapps to demonstrate the H(div) and H(curl) NURBS elements.
- Added an MFEM example for the eikonal equation. This new solver is based on
the proximal Galerkin method introduced by Keith and Surowiec.
- API change: in class GridFunction, 'fec' was renamed to 'fec_owned'.
Version 4.7, released on May 7, 2024
====================================
+13 -83
View File
@@ -32,7 +32,7 @@ groups_serial=(
'"examples"
"Examples:"
"examples"
"ex{,[1-9]}[0-9].cpp"'
"ex{,1,2,3}[0-9].cpp"'
# "ex1.cpp"'
'"sundials"
"SUNDIALS examples:"
@@ -58,10 +58,6 @@ groups_serial=(
"HiOp examples:"
"examples/hiop"
"ex9.cpp"'
'"moonolith"
"Moonolith examples:"
"examples/moonolith"
"ex1.cpp"'
'"pumi"
"PUMI examples:"
"examples/pumi"
@@ -70,38 +66,25 @@ groups_serial=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp mesh-quality.cpp
polar-nc.cpp reflector.cpp shaper.cpp trimmer.cpp twist.cpp
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
mesh-optimizer.cpp minimal-surface.cpp"'
'"adjoint"
"Adjoint miniapps:"
"miniapps/adjoint"
"cvsRoberts_ASAi_dns.cpp"'
'"autodiff"
"Autodiff miniapps:"
"miniapps/autodiff"
"seq_example.cpp seq_test.cpp"' # 'seq_test.cpp' has no sample runs
'"dpg"
"DPG miniapps:"
"miniapps/dpg"
"{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
'"gslib"
"GSLIB miniapps:"
"miniapps/gslib"
"field-diff.cpp field-interp.cpp findpts.cpp schwarz_ex1.cpp "'
# todo: miniapps/mtop
'"nurbs"
"NURBS miniapps:"
"miniapps/nurbs"
"nurbs_ex1.cpp"'
# todo: add other nurbs miniapps
# todo: miniapps/solvers (serial)
'"tools"
"Tools miniapps:"
"miniapps/tools"
"convert-dc.cpp display-basis.cpp get-values.cpp load-dc.cpp
lor-transfer.cpp"'
# todo: add other tools miniapps
'"toys"
"Toys miniapps:"
"miniapps/toys"
@@ -117,7 +100,7 @@ groups_parallel=(
'"examples"
"Examples:"
"examples"
"ex{,[1-9]}[0-9]p.cpp"'
"ex{,1,2,3}[0-9]p.cpp"'
# "ex1p.cpp"'
'"sundials"
"SUNDIALS examples:"
@@ -143,10 +126,6 @@ groups_parallel=(
"HiOp examples:"
"examples/hiop"
"ex9p.cpp"'
'"moonolith"
"Moonolith examples:"
"examples/moonolith"
"ex{1,2}p.cpp"'
'"pumi"
"PUMI examples:"
"examples/pumi"
@@ -159,41 +138,24 @@ groups_parallel=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"pmesh-optimizer.cpp pmesh-fitting.cpp pminimal-surface.cpp
fit-node-position.cpp"'
"pmesh-optimizer.cpp pmesh-fitting.cpp pminimal-surface.cpp"'
'"electromagnetics"
"Electromagnetics miniapps:"
"miniapps/electromagnetics"
"joule.cpp"'
# "{joule,maxwell,tesla,volta}.cpp"' # todo: multiline sample runs
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
'"adjoint"
"Adjoint miniapps:"
"miniapps/adjoint"
"adjoint_advection_diffusion.cpp"'
'"autodiff"
"Autodiff miniapps:"
"miniapps/autodiff"
"par_example.cpp"'
'"dpg"
"DPG miniapps:"
"miniapps/dpg"
"p{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
'"gslib"
"GSLIB miniapps:"
"miniapps/gslib"
"pfindpts.cpp schwarz_ex1p.cpp"'
'"hdiv-linear-solver"
"H(div) linear solver miniapps:"
"miniapps/hdiv-linear-solver"
"grad_div.cpp darcy.cpp"'
# 'miniapps/hooke/hooke.cpp' has no sample runs
# todo: miniapps/mtop
# todo: miniapps/multidomain
'"navier"
"Navier miniapps:"
"miniapps/navier"
"navier_cht.cpp"'
# todo: add other navier miniapps
'"nurbs"
"NURBS miniapps:"
"miniapps/nurbs"
@@ -202,18 +164,14 @@ groups_parallel=(
"Shifted miniapps:"
"miniapps/shifted"
"distance.cpp"'
# todo: add other shifted miniapps
'"solvers"
"Solvers miniapps:"
"miniapps/solvers"
"block-solvers.cpp"'
# todo: add other solvers miniapps
# todo: miniapps/spde
'"tools"
"Tools miniapps:"
"miniapps/tools"
"convert-dc.cpp get-values.cpp load-dc.cpp"'
# todo: add other tools miniapps
"convert-cd.cpp get-values.cpp load-dc.cpp"'
'"convergence"
"Convergence tests:"
"tests/convergence"
@@ -228,7 +186,7 @@ groups_all=(
'"examples"
"Examples:"
"examples"
"ex\"{,[1-9]}[0-9]\"{,p}.cpp"'
"ex\"{,1,2,3}[0-9]\"{,p}.cpp"'
'"sundials"
"SUNDIALS examples:"
"examples/sundials"
@@ -257,14 +215,10 @@ groups_all=(
"HiOp examples:"
"examples/hiop"
"ex9.cpp ex9p.cpp"'
'"moonolith"
"Moonolith examples:"
"examples/moonolith"
"ex1.cpp ex{1,2}p.cpp"'
'"pumi"
"PUMI examples:"
"examples/pumi"
"ex1.cpp ex2.cpp ex1p.cpp ex6p.cpp"'
"ex1.cpp ex1p.cpp ex2.cpp ex6p.cpp"'
'"superlu"
"Superlu examples:"
"examples/superlu"
@@ -272,67 +226,43 @@ groups_all=(
'"meshing"
"Meshing miniapps:"
"miniapps/meshing"
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp mesh-quality.cpp
polar-nc.cpp reflector.cpp shaper.cpp trimmer.cpp twist.cpp
{,p}mesh-optimizer.cpp pmesh-fitting.cpp {,p}minimal-surface.cpp
fit-node-position.cpp"'
"mobius-strip.cpp klein-bottle.cpp extruder.cpp toroid.cpp
{,p}mesh-optimizer.cpp pmesh-fitting.cpp {,p}minimal-surface.cpp"'
'"electromagnetics"
"Electromagnetics miniapps:"
"miniapps/electromagnetics"
"joule.cpp"'
# "{joule,maxwell,tesla,volta}.cpp"' # todo: multiline sample runs
# "{volta,tesla,joule}.cpp"' # todo: multiline sample runs
'"adjoint"
"Adjoint miniapps:"
"miniapps/adjoint"
"cvsRoberts_ASAi_dns.cpp adjoint_advection_diffusion.cpp"'
'"autodiff"
"Autodiff miniapps:"
"miniapps/autodiff"
"seq_example.cpp seq_test.cpp par_example.cpp"'
# 'seq_test.cpp' has no sample runs
'"dpg"
"DPG miniapps:"
"miniapps/dpg"
"{,p}{acoustics,convection-diffusion,diffusion,maxwell}.cpp"'
"adjoint_advection_diffusion.cpp cvsRoberts_ASAi_dns.cpp"'
'"gslib"
"GSLIB miniapps:"
"miniapps/gslib"
"field-diff.cpp field-interp.cpp findpts.cpp schwarz_ex1.cpp pfindpts.cpp
schwarz_ex1p.cpp"'
'"hdiv-linear-solver"
"H(div) linear solver miniapps:"
"miniapps/hdiv-linear-solver"
"grad_div.cpp darcy.cpp"'
# 'miniapps/hooke/hooke.cpp' has no sample runs
# todo: miniapps/mtop
# todo: miniapps/multidomain
'"navier"
"Navier miniapps:"
"miniapps/navier"
"navier_cht.cpp"'
# todo: add other navier miniapps
'"nurbs"
"NURBS miniapps:"
"miniapps/nurbs"
"nurbs_ex1.cpp nurbs_ex1p.cpp nurbs_ex11p.cpp"'
# todo: add other nurbs miniapps
'"shifted"
"Shifted miniapps:"
"miniapps/shifted"
"distance.cpp"'
# todo: add other shifted miniapps
'"solvers"
"Solvers miniapps:"
"miniapps/solvers"
"block-solvers.cpp"'
# todo: add other solvers miniapps
# todo: miniapps/spde
'"tools"
"Tools miniapps:"
"miniapps/tools"
"convert-dc.cpp display-basis.cpp get-values.cpp load-dc.cpp
lor-transfer.cpp"'
# todo: add other tools miniapps
'"toys"
"Toys miniapps:"
"miniapps/toys"
@@ -456,7 +386,7 @@ function help_message()
mfem_config [${mfem_config}]
Set MFEM configuration options
make [${make}], mpiexec [${mpiexec}], mpiexec_np [${mpiexec_np}]
Their values can also be set using the respective uppercase environment
Their values can also set using the respective uppercase environment
variable
mfem_build_dir [${mfem_build_dir}]
Same as '-d': set this variable to something different from <mfem_dir>
+3 -3
View File
@@ -18,9 +18,9 @@ elements
boundary
4
1 1 0 1
2 1 2 3
3 1 3 0
4 1 1 2
1 1 2 3
1 1 3 0
1 1 1 2
edges
4
+1 -3
View File
@@ -980,7 +980,6 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/miniapps/mtop \
@MFEM_SOURCE_DIR@/miniapps/multidomain \
@MFEM_SOURCE_DIR@/miniapps/navier \
@MFEM_SOURCE_DIR@/miniapps/stabilized \
@MFEM_SOURCE_DIR@/miniapps/nurbs \
@MFEM_SOURCE_DIR@/miniapps/parelag \
@MFEM_SOURCE_DIR@/miniapps/performance \
@@ -1050,8 +1049,7 @@ RECURSIVE = NO
EXCLUDE = @MFEM_SOURCE_DIR@/config/_config.hpp \
@MFEM_SOURCE_DIR@/config/get_hypre_version.cpp \
@MFEM_SOURCE_DIR@/general/tinyxml2.h \
@MFEM_SOURCE_DIR@/general/tinyxml2.cpp \
@MFEM_SOURCE_DIR@/linalg/lapack.hpp
@MFEM_SOURCE_DIR@/general/tinyxml2.cpp
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
+1 -18
View File
@@ -114,9 +114,7 @@ namespace mfem {
* - <a class="el" href="ex37p_8cpp_source.html">Example 37p</a>: parallel topology optimization
* - <a class="el" href="ex38_8cpp_source.html">Example 38</a>: cut-surface and cut-volume integration
* - <a class="el" href="ex39_8cpp_source.html">Example 39</a>: named mesh attributes
* - <a class="el" href="ex39p_8cpp_source.html">Example 39p</a>: parallel named mesh attributes
* - <a class="el" href="ex40_8cpp_source.html">Example 40</a>: eikonal equation
* - <a class="el" href="ex40p_8cpp_source.html">Example 40p</a>: parallel eikonal equation
* - <a class="el" href="ex39p_8cpp_source.html">Example 39</a>: parallel named mesh attributes
*
* <H4>AmgX Examples</H4>
* - Variants of Examples
@@ -182,21 +180,6 @@ namespace mfem {
* <a class="el" href="examples_2superlu_2ex1p_8cpp_source.html">1p</a>,
* demonstrating the use of MFEM's \link superlu.hpp SuperLU integration\endlink.
*
* <H4>NURBS Examples</H4>
* - Variants of Examples
* <a class="el" href="nurbs__ex1_8cpp_source.html">1</a>,
* <a class="el" href="nurbs__ex1p_8cpp_source.html">1p</a>,
* <a class="el" href="nurbs__ex3_8cpp_source.html">3</a>,
* <a class="el" href="nurbs__ex5_8cpp_source.html">5</a>,
* <a class="el" href="nurbs__ex11p_8cpp_source.html">11p</a>, and
* <a class="el" href="nurbs__ex24_8cpp_source.html">24</a>,
* demonstrating howto perform NURBS-based Isogeometric Analysis.
* - Variant of Example <a class="el" href="nurbs__patch__ex1_8cpp_source.html">1</a>: demonstrates the use of patch integration
* - <a class="el" href="nurbs__solenoidal_8cpp_source.html">NURBS Divergence-free</a>: solve a solenoidal vector projection with NURBS-based H(div) elements
* - <a class="el" href="nurbs__curveint_8cpp_source.html">NURBS Interpolation</a>: NURBS interpolation of given geometry
* - <a class="el" href="nurbs__naca__cmesh_8cpp_source.html">NURBS NACA Mesher</a>: generate NURBS based mesh around a NACA foil
* - <a class="el" href="nurbs__printfunc_8cpp_source.html">NURBS Printer</a>: print the NURBS-basis
*
* <H3>Miniapps</H3>
* - <a class="el" href="volta_8cpp_source.html">Volta</a>: simple electrostatics simulation code
* - <a class="el" href="tesla_8cpp_source.html">Tesla</a>: simple magnetostatics simulation code
+3 -10
View File
@@ -45,7 +45,6 @@ list(APPEND ALL_EXE_SRCS
ex37.cpp
ex38.cpp
ex39.cpp
ex40.cpp
)
if (MFEM_USE_MPI)
@@ -88,7 +87,6 @@ if (MFEM_USE_MPI)
ex36p.cpp
ex37p.cpp
ex39p.cpp
ex40p.cpp
)
endif()
@@ -148,10 +146,10 @@ if (MFEM_ENABLE_TESTING)
# Add CUDA/HIP tests.
set(DEVICE_EXAMPLES
# serial examples with device support:
ex1 ex3 ex4 ex5 ex6 ex9 ex14 ex22 ex24 ex25 ex26 ex34
ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
# parallel examples with device support:
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex14p ex22p ex24p ex25p
ex26p ex34p ex35p)
ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p ex24p ex25p ex26p
ex34p ex35p)
set(MFEM_TEST_DEVICE)
if (MFEM_USE_CUDA)
set(MFEM_TEST_DEVICE "cuda")
@@ -161,11 +159,6 @@ if (MFEM_ENABLE_TESTING)
if (MFEM_TEST_DEVICE)
foreach(TEST_NAME ${DEVICE_EXAMPLES})
set(THIS_TEST_OPTIONS "-no-vis" "-d" "${MFEM_TEST_DEVICE}")
if (${TEST_NAME} MATCHES "ex14p")
list(APPEND THIS_TEST_OPTIONS "-rs" "2" "-rp" "0" "-pa")
elseif (${TEST_NAME} MATCHES "ex14")
list(APPEND THIS_TEST_OPTIONS "-r" "2" "-pa")
endif()
if (NOT (${TEST_NAME} MATCHES ".*p$"))
add_test(NAME ${TEST_NAME}_${MFEM_TEST_DEVICE}_ser
COMMAND ${TEST_NAME} ${THIS_TEST_OPTIONS})
+20 -16
View File
@@ -44,7 +44,7 @@ protected:
BilinearForm *M;
BilinearForm *K;
SparseMatrix Mmat, Kmat;
SparseMatrix Mmat, Kmat, Kmat0;
SparseMatrix *T; // T = M + dt K
real_t current_dt;
@@ -83,24 +83,25 @@ WaveOperator::WaveOperator(FiniteElementSpace &f,
: SecondOrderTimeDependentOperator(f.GetTrueVSize(), (real_t) 0.0),
fespace(f), M(NULL), K(NULL), T(NULL), current_dt(0.0), z(height)
{
// Assemble Laplace matrix
const real_t rel_tol = 1e-8;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
c2 = new ConstantCoefficient(speed*speed);
K = new BilinearForm(&fespace);
K->AddDomainIntegrator(new DiffusionIntegrator(*c2));
K->Assemble();
// Assemble Mass matrix
Array<int> dummy;
K->FormSystemMatrix(dummy, Kmat0);
K->FormSystemMatrix(ess_tdof_list, Kmat);
M = new BilinearForm(&fespace);
M->AddDomainIntegrator(new MassIntegrator());
M->Assemble();
// Apply Bcs
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
K->FormSystemMatrix(ess_tdof_list, Kmat);
M->FormSystemMatrix(ess_tdof_list, Mmat);
// Configure preconditioner
const real_t rel_tol = 1e-8;
M_solver.iterative_mode = false;
M_solver.SetRelTol(rel_tol);
M_solver.SetAbsTol(0.0);
@@ -109,13 +110,14 @@ WaveOperator::WaveOperator(FiniteElementSpace &f,
M_solver.SetPreconditioner(M_prec);
M_solver.SetOperator(Mmat);
// Configure solver
T_solver.iterative_mode = false;
T_solver.SetRelTol(rel_tol);
T_solver.SetAbsTol(0.0);
T_solver.SetMaxIter(100);
T_solver.SetPrintLevel(0);
T_solver.SetPreconditioner(T_prec);
T = NULL;
}
void WaveOperator::Mult(const Vector &u, const Vector &du_dt,
@@ -124,11 +126,9 @@ void WaveOperator::Mult(const Vector &u, const Vector &du_dt,
// Compute:
// d2udt2 = M^{-1}*-K(u)
// for d2udt2
K->FullMult(u, z);
Kmat.Mult(u, z);
z.Neg(); // z = -z
z.SetSubVector(ess_tdof_list, 0.0);
M_solver.Mult(z, d2udt2);
d2udt2.SetSubVector(ess_tdof_list, 0.0);
}
void WaveOperator::ImplicitSolve(const real_t fac0, const real_t fac1,
@@ -142,11 +142,14 @@ void WaveOperator::ImplicitSolve(const real_t fac0, const real_t fac1,
T = Add(1.0, Mmat, fac0, Kmat);
T_solver.SetOperator(*T);
}
K->FullMult(u, z);
Kmat0.Mult(u, z);
z.Neg();
z.SetSubVector(ess_tdof_list, 0.0);
for (int i = 0; i < ess_tdof_list.Size(); i++)
{
z[ess_tdof_list[i]] = 0.0;
}
T_solver.Mult(z, d2udt2);
d2udt2.SetSubVector(ess_tdof_list, 0.0);
}
void WaveOperator::SetParameters(const Vector &u)
@@ -311,6 +314,7 @@ int main(int argc, char *argv[])
ess_bdr = 0;
}
}
WaveOperator oper(fespace, ess_bdr, speed);
u_gf.SetFromTrueDofs(u);
-374
View File
@@ -1,374 +0,0 @@
// MFEM Example 40
//
// Compile with: make ex40
//
// Sample runs: ex40 -step 10 -gr 2.0
// ex40 -step 10 -gr 2.0 -o 3 -r 1
// ex40 -step 10 -gr 2.0 -r 4 -m ../data/l-shape.mesh
// ex40 -step 10 -gr 2.0 -r 2 -m ../data/fichera.mesh
//
// Description: This example code demonstrates how to use MFEM to solve the
// eikonal equation,
//
// |∇𝑢| = 1 in Ω, 𝑢 = g on ∂Ω.
//
// The solution of this problem coincides with the unique optimum of
// the nonlinear program
//
// maximize ∫_Ω 𝑢 d𝑥 subject to |∇𝑢| ≤ 1, 𝑢 = g on Ω, (⋆)
//
// which is the foundation for method implemented below.
//
// Following the proximal Galerkin methodology [1] (see also Example
// 36), we construct a Legendre function for the unit ball
// 𝐵₁ := {𝑥 ∈ Rⁿ | |𝑥| < 1}. Our choice is the Hellinger entropy,
//
// h(𝑥) = ( 1 |𝑥|² )^{1/2},
//
// although other choices are possible, each leading to a slightly
// different algorithm. We then adaptively regularize the optimization
// problem (⋆) with the Bregman divergence of the Hellinger entropy,
//
// maximize ∫_Ω 𝑢 d𝑥 - αₖ⁻¹ Dₕ(∇𝑢,∇𝑢ₖ₋₁) subject to 𝑢 = g on Ω.
//
// This results in a sequence of functions ( 𝜓ₖ , 𝑢ₖ ),
//
// 𝑢ₖ → 𝑢, 𝜓ₖ/|𝜓ₖ| → ∇𝑢 as k → \infty,
//
// defined by the nonlinear saddle-point problems
//
// Find 𝜓ₖ ∈ H(div,Ω) and 𝑢ₖ ∈ L²(Ω) such that
// ( Zₖ(𝜓ₖ) , τ ) + ( 𝑢ₖ , ∇⋅τ ) = ⟨ g , τ⋅n ⟩ ∀ τ ∈ H(div,Ω)
// ( ∇⋅𝜓ₖ , v ) = ( ∇⋅𝜓ₖ₋₁ - 1 , v ) ∀ v ∈ L²(Ω)
//
// where Zₖ(𝜓) := ∇h⁻¹(αₖ 𝜓) = 𝜓 / ( αₖ⁻² + |𝜓|² )^{1/2} and step size
// αₖ > 0. These saddle-point problems are solved using a damped Newton's
// method. This example assumes that g = 0 and allows the step size to
// grow geometrically, αₖ = α₀rᵏ, where r ≥ 1 is the growth rate.
//
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
class ZCoefficient : public VectorCoefficient
{
protected:
GridFunction *psi;
real_t alpha;
public:
ZCoefficient(int vdim, GridFunction &psi_, real_t alpha_ = 1.0)
: VectorCoefficient(vdim), psi(&psi_), alpha(alpha_) { }
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
class DZCoefficient : public MatrixCoefficient
{
protected:
GridFunction *psi;
real_t alpha;
public:
DZCoefficient(int height, GridFunction &psi_, real_t alpha_ = 1.0)
: MatrixCoefficient(height), psi(&psi_), alpha(alpha_) { }
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
int max_it = 5;
int ref_levels = 3;
real_t alpha = 1.0;
real_t growth_rate = 1.0;
real_t newton_scaling = 0.9;
real_t tichonov = 1e-1;
real_t tol = 1e-4;
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&ref_levels, "-r", "--refs",
"Number of h-refinements.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of iterations");
args.AddOption(&tol, "-tol", "--tol",
"Stopping criteria based on the difference between"
"successive solution updates");
args.AddOption(&alpha, "-step", "--step",
"Initial size alpha");
args.AddOption(&growth_rate, "-gr", "--growth-rate",
"Growth rate of the step size alpha");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the mesh from the mesh file.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
int sdim = mesh.SpaceDimension();
MFEM_ASSERT(mesh.bdr_attributes.Size(),
"This example does not currently support meshes"
" without boundary attributes."
)
// 3. Postprocess the mesh.
// 3A. Refine the mesh to increase the resolution.
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
// 3B. Interpolate the geometry after refinement to control geometry error.
// NOTE: Minimum second-order interpolation is used to improve the accuracy.
int curvature_order = max(order,2);
mesh.SetCurvature(curvature_order);
// 4. Define the necessary finite element spaces on the mesh.
RT_FECollection RTfec(order, dim);
FiniteElementSpace RTfes(&mesh, &RTfec);
L2_FECollection L2fec(order, dim);
FiniteElementSpace L2fes(&mesh, &L2fec);
cout << "Number of H(div) dofs: "
<< RTfes.GetTrueVSize() << endl;
cout << "Number of L² dofs: "
<< L2fes.GetTrueVSize() << endl;
// 5. Define the offsets for the block matrices
Array<int> offsets(3);
offsets[0] = 0;
offsets[1] = RTfes.GetVSize();
offsets[2] = L2fes.GetVSize();
offsets.PartialSum();
BlockVector x(offsets), rhs(offsets);
x = 0.0; rhs = 0.0;
// 6. Define the solution vectors as a finite element grid functions
// corresponding to the fespaces.
GridFunction u_gf, delta_psi_gf;
delta_psi_gf.MakeRef(&RTfes,x,offsets[0]);
u_gf.MakeRef(&L2fes,x,offsets[1]);
GridFunction psi_old_gf(&RTfes);
GridFunction psi_gf(&RTfes);
GridFunction u_old_gf(&L2fes);
// 7. Define initial guesses for the solution variables.
delta_psi_gf = 0.0;
psi_gf = 0.0;
u_gf = 0.0;
psi_old_gf = psi_gf;
u_old_gf = u_gf;
// 8. Prepare for glvis output.
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock;
if (visualization)
{
sol_sock.open(vishost,visport);
sol_sock.precision(8);
}
// 9. Coefficients to be used later.
ConstantCoefficient neg_one(-1.0);
ConstantCoefficient zero(0.0);
ConstantCoefficient tichonov_cf(tichonov);
ConstantCoefficient neg_tichonov_cf(-1.0*tichonov);
ZCoefficient Z(sdim, psi_gf, alpha);
DZCoefficient DZ(sdim, psi_gf, alpha);
ScalarVectorProductCoefficient neg_Z(-1.0, Z);
DivergenceGridFunctionCoefficient div_psi_cf(&psi_gf);
DivergenceGridFunctionCoefficient div_psi_old_cf(&psi_old_gf);
SumCoefficient psi_old_minus_psi(div_psi_old_cf, div_psi_cf, 1.0, -1.0);
// 10. Assemble constant matrices/vectors to avoid reassembly in the loop.
LinearForm b0, b1;
b0.MakeRef(&RTfes,rhs.GetBlock(0),0);
b1.MakeRef(&L2fes,rhs.GetBlock(1),0);
b0.AddDomainIntegrator(new VectorFEDomainLFIntegrator(neg_Z));
b1.AddDomainIntegrator(new DomainLFIntegrator(neg_one));
b1.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
BilinearForm a00(&RTfes);
a00.AddDomainIntegrator(new VectorFEMassIntegrator(DZ));
a00.AddDomainIntegrator(new VectorFEMassIntegrator(tichonov_cf));
MixedBilinearForm a10(&RTfes,&L2fes);
a10.AddDomainIntegrator(new VectorFEDivergenceIntegrator());
a10.Assemble();
a10.Finalize();
SparseMatrix &A10 = a10.SpMat();
SparseMatrix *A01 = Transpose(A10);
BilinearForm a11(&L2fes);
a11.AddDomainIntegrator(new MassIntegrator(neg_tichonov_cf));
a11.Assemble();
a11.Finalize();
SparseMatrix &A11 = a11.SpMat();
// 11. Iterate.
int k;
int total_iterations = 0;
real_t increment_u = 0.1;
GridFunction u_tmp(&L2fes);
for (k = 0; k < max_it; k++)
{
u_tmp = u_old_gf;
Z.SetAlpha(alpha);
DZ.SetAlpha(alpha);
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
int j;
for ( j = 0; j < 5; j++)
{
total_iterations++;
b0.Assemble();
b1.Assemble();
a00.Assemble(false);
a00.Finalize(false);
SparseMatrix &A00 = a00.SpMat();
// Construct Schur-complement preconditioner
Vector A00_diag(a00.Height());
A00.GetDiag(A00_diag);
A00_diag.Reciprocal();
SparseMatrix *S = Mult_AtDA(*A01, A00_diag);
BlockDiagonalPreconditioner prec(offsets);
prec.SetDiagonalBlock(0,new DSmoother(A00));
#ifndef MFEM_USE_SUITESPARSE
prec.SetDiagonalBlock(1,new GSSmoother(*S));
#else
prec.SetDiagonalBlock(1,new UMFPackSolver(*S));
#endif
prec.owns_blocks = 1;
BlockOperator A(offsets);
A.SetBlock(0,0,&A00);
A.SetBlock(1,0,&A10);
A.SetBlock(0,1,A01);
A.SetBlock(1,1,&A11);
GMRES(A,prec,rhs,x,0,2000,500,1e-12,0.0);
delete S;
u_tmp -= u_gf;
real_t Newton_update_size = u_tmp.ComputeL2Error(zero);
u_tmp = u_gf;
// Damped Newton update
psi_gf.Add(newton_scaling, delta_psi_gf);
a00.Update();
if (visualization)
{
sol_sock << "solution\n" << mesh << u_gf << "window_title 'Discrete solution'"
<< flush;
}
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
if (Newton_update_size < increment_u)
{
break;
}
}
u_tmp = u_gf;
u_tmp -= u_old_gf;
increment_u = u_tmp.ComputeL2Error(zero);
mfem::out << "Number of Newton iterations = " << j+1 << endl;
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
u_old_gf = u_gf;
psi_old_gf = psi_gf;
if (increment_u < tol || k == max_it-1)
{
break;
}
alpha *= max(growth_rate, 1_r);
}
mfem::out << "\n Outer iterations: " << k+1
<< "\n Total iterations: " << total_iterations
<< "\n Total dofs: " << RTfes.GetTrueVSize() + L2fes.GetTrueVSize()
<< endl;
delete A01;
return 0;
}
void ZCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(psi != NULL, "grid function is not set");
MFEM_ASSERT(alpha > 0, "alpha is not positive");
Vector psi_vals(vdim);
psi->GetVectorValue(T, ip, psi_vals);
real_t norm = psi_vals.Norml2();
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
V = psi_vals;
V *= phi;
}
void DZCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(psi != NULL, "grid function is not set");
MFEM_ASSERT(alpha > 0, "alpha is not positive");
Vector psi_vals(height);
psi->GetVectorValue(T, ip, psi_vals);
real_t norm = psi_vals.Norml2();
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
K = 0.0;
for (int i = 0; i < height; i++)
{
K(i,i) = phi;
for (int j = 0; j < height; j++)
{
K(i,j) -= psi_vals(i) * psi_vals(j) * pow(phi, 3);
}
}
}
-436
View File
@@ -1,436 +0,0 @@
// MFEM Example 40 - Parallel Version
//
// Compile with: make ex40p
//
// Sample runs: mpirun -np 4 ex40p -step 10 -gr 2.0
// mpirun -np 4 ex40p -step 10 -gr 2.0 -o 3 -r 1
// mpirun -np 4 ex40p -step 10 -gr 2.0 -r 4 -m ../data/l-shape.mesh
// mpirun -np 4 ex40p -step 10 -gr 2.0 -r 2 -m ../data/fichera.mesh
//
// Description: This example code demonstrates how to use MFEM to solve the
// eikonal equation,
//
// |∇𝑢| = 1 in Ω, 𝑢 = g on ∂Ω.
//
// The solution of this problem coincides with the unique optimum of
// the nonlinear program
//
// maximize ∫_Ω 𝑢 d𝑥 subject to |∇𝑢| ≤ 1, 𝑢 = g on Ω, (⋆)
//
// which is the foundation for method implemented below.
//
// Following the proximal Galerkin methodology [1] (see also Example
// 36), we construct a Legendre function for the unit ball
// 𝐵₁ := {𝑥 ∈ Rⁿ | |𝑥| < 1}. Our choice is the Hellinger entropy,
//
// h(𝑥) = ( 1 |𝑥|² )^{1/2},
//
// although other choices are possible, each leading to a slightly
// different algorithm. We then adaptively regularize the optimization
// problem (⋆) with the Bregman divergence of the Hellinger entropy,
//
// maximize ∫_Ω 𝑢 d𝑥 - αₖ⁻¹ Dₕ(∇𝑢,∇𝑢ₖ₋₁) subject to 𝑢 = g on Ω.
//
// This results in a sequence of functions ( 𝜓ₖ , 𝑢ₖ ),
//
// 𝑢ₖ → 𝑢, 𝜓ₖ/|𝜓ₖ| → ∇𝑢 as k → \infty,
//
// defined by the nonlinear saddle-point problems
//
// Find 𝜓ₖ ∈ H(div,Ω) and 𝑢ₖ ∈ L²(Ω) such that
// ( Zₖ(𝜓ₖ) , τ ) + ( 𝑢ₖ , ∇⋅τ ) = ⟨ g , τ⋅n ⟩ ∀ τ ∈ H(div,Ω)
// ( ∇⋅𝜓ₖ , v ) = ( ∇⋅𝜓ₖ₋₁ - 1 , v ) ∀ v ∈ L²(Ω)
//
// where Zₖ(𝜓) := ∇h⁻¹(αₖ 𝜓) = 𝜓 / ( αₖ⁻² + |𝜓|² )^{1/2} and step size
// αₖ > 0. These saddle-point problems are solved using a damped Newton's
// method. This example assumes that g = 0 and allows the step size to
// grow geometrically, αₖ = α₀rᵏ, where r ≥ 1 is the growth rate.
//
// [1] Keith, B. and Surowiec, T. (2023) Proximal Galerkin: A structure-
// preserving finite element method for pointwise bound constraints.
// arXiv:2307.12444 [math.NA]
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
class ZCoefficient : public VectorCoefficient
{
protected:
ParGridFunction *psi;
real_t alpha;
public:
ZCoefficient(int vdim, ParGridFunction &psi_, real_t alpha_ = 1.0)
: VectorCoefficient(vdim), psi(&psi_), alpha(alpha_) { }
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
class DZCoefficient : public MatrixCoefficient
{
protected:
ParGridFunction *psi;
real_t alpha;
public:
DZCoefficient(int height, ParGridFunction &psi_, real_t alpha_ = 1.0)
: MatrixCoefficient(height), psi(&psi_), alpha(alpha_) { }
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
void SetAlpha(real_t alpha_) { alpha = alpha_; }
};
int main(int argc, char *argv[])
{
// 0. Initialize MPI and HYPRE.
Mpi::Init();
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
int max_it = 5;
int ref_levels = 3;
real_t alpha = 1.0;
real_t growth_rate = 1.0;
real_t newton_scaling = 0.9;
real_t tichonov = 1e-1;
real_t tol = 1e-4;
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&ref_levels, "-r", "--refs",
"Number of h-refinements.");
args.AddOption(&max_it, "-mi", "--max-it",
"Maximum number of iterations");
args.AddOption(&tol, "-tol", "--tol",
"Stopping criteria based on the difference between"
"successive solution updates");
args.AddOption(&alpha, "-step", "--step",
"Initial size alpha");
args.AddOption(&growth_rate, "-gr", "--growth-rate",
"Growth rate of the step size alpha");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 2. Read the mesh from the mesh file.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
int sdim = mesh.SpaceDimension();
MFEM_ASSERT(mesh.bdr_attributes.Size(),
"This example does not currently support meshes"
" without boundary attributes."
)
// 3. Postprocess the mesh.
// 3A. Refine the mesh to increase the resolution.
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
// 3B. Interpolate the geometry after refinement to control geometry error.
// NOTE: Minimum second-order interpolation is used to improve the accuracy.
int curvature_order = max(order,2);
mesh.SetCurvature(curvature_order);
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
// 4. Define the necessary finite element spaces on the mesh.
RT_FECollection RTfec(order, dim);
ParFiniteElementSpace RTfes(&pmesh, &RTfec);
L2_FECollection L2fec(order, dim);
ParFiniteElementSpace L2fes(&pmesh, &L2fec);
int num_dofs_RT = RTfes.GlobalTrueVSize();
int num_dofs_L2 = L2fes.GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of H(div) dofs: "
<< num_dofs_RT << endl;
cout << "Number of L² dofs: "
<< num_dofs_L2 << endl;
}
// 5. Define the offsets for the block matrices
Array<int> offsets(3);
offsets[0] = 0;
offsets[1] = RTfes.GetVSize();
offsets[2] = L2fes.GetVSize();
offsets.PartialSum();
Array<int> toffsets(3);
toffsets[0] = 0;
toffsets[1] = RTfes.GetTrueVSize();
toffsets[2] = L2fes.GetTrueVSize();
toffsets.PartialSum();
BlockVector x(offsets), rhs(offsets);
x = 0.0; rhs = 0.0;
BlockVector tx(toffsets), trhs(toffsets);
tx = 0.0; trhs = 0.0;
// 6. Define the solution vectors as a finite element grid functions
// corresponding to the fespaces.
ParGridFunction u_gf, delta_psi_gf;
delta_psi_gf.MakeRef(&RTfes,x,offsets[0]);
u_gf.MakeRef(&L2fes,x,offsets[1]);
ParGridFunction psi_old_gf(&RTfes);
ParGridFunction psi_gf(&RTfes);
ParGridFunction u_old_gf(&L2fes);
// 7. Define initial guesses for the solution variables.
delta_psi_gf = 0.0;
psi_gf = 0.0;
u_gf = 0.0;
psi_old_gf = psi_gf;
u_old_gf = u_gf;
// 8. Prepare for glvis output.
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock;
if (visualization)
{
sol_sock.open(vishost,visport);
sol_sock.precision(8);
}
// 9. Coefficients to be used later.
ConstantCoefficient neg_one(-1.0);
ConstantCoefficient zero(0.0);
ConstantCoefficient tichonov_cf(tichonov);
ConstantCoefficient neg_tichonov_cf(-1.0*tichonov);
ZCoefficient Z(sdim, psi_gf, alpha);
DZCoefficient DZ(sdim, psi_gf, alpha);
ScalarVectorProductCoefficient neg_Z(-1.0, Z);
DivergenceGridFunctionCoefficient div_psi_cf(&psi_gf);
DivergenceGridFunctionCoefficient div_psi_old_cf(&psi_old_gf);
SumCoefficient psi_old_minus_psi(div_psi_old_cf, div_psi_cf, 1.0, -1.0);
// 10. Assemble constant matrices/vectors to avoid reassembly in the loop.
ParLinearForm b0, b1;
b0.MakeRef(&RTfes,rhs.GetBlock(0),0);
b1.MakeRef(&L2fes,rhs.GetBlock(1),0);
b0.AddDomainIntegrator(new VectorFEDomainLFIntegrator(neg_Z));
b1.AddDomainIntegrator(new DomainLFIntegrator(neg_one));
b1.AddDomainIntegrator(new DomainLFIntegrator(psi_old_minus_psi));
ParBilinearForm a00(&RTfes);
a00.AddDomainIntegrator(new VectorFEMassIntegrator(DZ));
a00.AddDomainIntegrator(new VectorFEMassIntegrator(tichonov_cf));
ParMixedBilinearForm a10(&RTfes,&L2fes);
a10.AddDomainIntegrator(new VectorFEDivergenceIntegrator());
a10.Assemble();
a10.Finalize();
HypreParMatrix *A10 = a10.ParallelAssemble();
HypreParMatrix *A01 = A10->Transpose();
ParBilinearForm a11(&L2fes);
a11.AddDomainIntegrator(new MassIntegrator(neg_tichonov_cf));
a11.Assemble();
a11.Finalize();
HypreParMatrix *A11 = a11.ParallelAssemble();
// 11. Iterate.
int k;
int total_iterations = 0;
real_t increment_u = 0.1;
ParGridFunction u_tmp(&L2fes);
for (k = 0; k < max_it; k++)
{
u_tmp = u_old_gf;
Z.SetAlpha(alpha);
DZ.SetAlpha(alpha);
if (myid == 0)
{
mfem::out << "\nOUTER ITERATION " << k+1 << endl;
}
int j;
for ( j = 0; j < 5; j++)
{
total_iterations++;
b0.Assemble();
b0.ParallelAssemble(trhs.GetBlock(0));
b1.Assemble();
b1.ParallelAssemble(trhs.GetBlock(1));
a00.Assemble(false);
a00.Finalize(false);
HypreParMatrix *A00 = a00.ParallelAssemble();
// Construct Schur-complement preconditioner
HypreParVector A00_diag(MPI_COMM_WORLD, A00->GetGlobalNumRows(),
A00->GetRowStarts());
A00->GetDiag(A00_diag);
HypreParMatrix S_tmp(*A01);
S_tmp.InvScaleRows(A00_diag);
HypreParMatrix *S = ParMult(A10, &S_tmp, true);
BlockDiagonalPreconditioner prec(toffsets);
HypreBoomerAMG P00(*A00);
P00.SetPrintLevel(0);
HypreBoomerAMG P11(*S);
P11.SetPrintLevel(0);
prec.SetDiagonalBlock(0,&P00);
prec.SetDiagonalBlock(1,&P11);
BlockOperator A(toffsets);
A.SetBlock(0,0,A00);
A.SetBlock(1,0,A10);
A.SetBlock(0,1,A01);
A.SetBlock(1,1,A11);
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetPrintLevel(-1);
gmres.SetRelTol(1e-8);
gmres.SetMaxIter(2000);
gmres.SetKDim(500);
gmres.SetOperator(A);
gmres.SetPreconditioner(prec);
gmres.Mult(trhs,tx);
delete S;
delete A00;
delta_psi_gf.SetFromTrueDofs(tx.GetBlock(0));
u_gf.SetFromTrueDofs(tx.GetBlock(1));
u_tmp -= u_gf;
real_t Newton_update_size = u_tmp.ComputeL2Error(zero);
u_tmp = u_gf;
// Damped Newton update
psi_gf.Add(newton_scaling, delta_psi_gf);
a00.Update();
if (visualization)
{
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock << "solution\n" << pmesh << u_gf << "window_title 'Discrete solution'"
<< flush;
}
if (myid == 0)
{
mfem::out << "Newton_update_size = " << Newton_update_size << endl;
}
if (Newton_update_size < increment_u)
{
break;
}
}
u_tmp = u_gf;
u_tmp -= u_old_gf;
increment_u = u_tmp.ComputeL2Error(zero);
if (myid == 0)
{
mfem::out << "Number of Newton iterations = " << j+1 << endl;
mfem::out << "Increment (|| uₕ - uₕ_prvs||) = " << increment_u << endl;
}
u_old_gf = u_gf;
psi_old_gf = psi_gf;
if (increment_u < tol || k == max_it-1)
{
break;
}
alpha *= max(growth_rate, 1_r);
}
// 12. Print stats.
if (myid == 0)
{
mfem::out << "\n Outer iterations: " << k+1
<< "\n Total iterations: " << total_iterations
<< "\n Total dofs: " << RTfes.GetTrueVSize() + L2fes.GetTrueVSize()
<< endl;
}
// 13. Free the used memory.
delete A01;
delete A10;
delete A11;
return 0;
}
void ZCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(psi != NULL, "grid function is not set");
MFEM_ASSERT(alpha > 0, "alpha is not positive");
Vector psi_vals(vdim);
psi->GetVectorValue(T, ip, psi_vals);
real_t norm = psi_vals.Norml2();
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
V = psi_vals;
V *= phi;
}
void DZCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(psi != NULL, "grid function is not set");
MFEM_ASSERT(alpha > 0, "alpha is not positive");
Vector psi_vals(height);
psi->GetVectorValue(T, ip, psi_vals);
real_t norm = psi_vals.Norml2();
real_t phi = 1.0 / sqrt(1.0/(alpha*alpha) + norm*norm);
K = 0.0;
for (int i = 0; i < height; i++)
{
K(i,i) = phi;
for (int j = 0; j < height; j++)
{
K(i,j) -= psi_vals(i) * psi_vals(j) * pow(phi, 3);
}
}
}
+5 -13
View File
@@ -23,14 +23,14 @@ MFEM_LIB_FILE = mfem_is_not_built
SEQ_EXAMPLES = ex0 ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 \
ex17 ex18 ex19 ex20 ex21 ex22 ex23 ex24 ex25 ex26 ex27 ex28 ex29 ex30 \
ex31 ex33 ex34 ex36 ex37 ex38 ex39 ex40
ex31 ex33 ex34 ex36 ex37 ex38 ex39
PAR_EXAMPLES = ex0p ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p \
ex12p ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p \
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p ex34p ex35p ex36p \
ex37p ex39p ex40p
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex14 ex22 ex24 ex25 ex26 ex34
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex14p \
ex22p ex24p ex25p ex26p ex34p ex35p
ex37p ex39p
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex22 ex24 ex25 ex26 ex34
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex22p \
ex24p ex25p ex26p ex34p ex35p
ifeq ($(MFEM_USE_LAPACK),YES)
SEQ_EXAMPLES += ex38
@@ -138,14 +138,6 @@ ex10-test-seq: ex10
@$(call mfem-test,$<,, Serial example,-tf 5)
ex10p-test-par: ex10p
@$(call mfem-test,$<, $(RUN_MPI), Parallel example,-tf 5)
ex14-test-seq-cuda: ex14
@$(call mfem-test,$<,, Serial CUDA example,-r 2 -pa -d cuda)
ex14p-test-par-cuda: ex14p
@$(call mfem-test,$<, $(RUN_MPI), Parallel CUDA example,-rs 2 -rp 0 -pa -d cuda)
ex14-test-seq-hip: ex14
@$(call mfem-test,$<,, Serial HIP example,-r 2 -pa -d hip)
ex14p-test-par-hip: ex14p
@$(call mfem-test,$<, $(RUN_MPI), Parallel HIP example,-rs 2 -rp 0 -pa -d hip)
ex15-test-seq: ex15
@$(call mfem-test,$<,, Serial example,-e 1)
ex15p-test-par: ex15p
+510
View File
@@ -0,0 +1,510 @@
// MFEM Maxwell example (with imaginary mass coeff)
//
// ∇×(1/μ ∇×E) - (ω^2 ϵ + i ω σ) E = J , in Ω (by default ϵ=0)
// E×n = E_0, on ∂Ω
//
// Compile with: pmaxwell
//
// Sample runs:
// mpirun -np 8 ./pmaxwell -o 1 -sref 0 -m ../data/inline-hex.mesh -rnum 3.0 -pref 4 -sigma 1.0 -no-herm -vis
/*
Ref | Dofs | ω | H(curl) Error | Rate | Solv it |
-----------------------------------------------------------------
0 | 300 | 6.0 π | 2.697e+01 | 0.00 | 28 (20)|
1 | 1944 | 6.0 π | 2.183e+01 | -0.34 | 28 (19)|
2 | 13872 | 6.0 π | 1.227e+01 | -0.88 | 30 (19)|
3 | 104544 | 6.0 π | 6.341e+00 | -0.98 | 36 (19)|
4 | 811200 | 6.0 π | 3.197e+00 | -1.00 | 46 (19)|
*/
// mpirun -np 8 ./pmaxwell -o 2 -sref 0 -m ../data/inline-hex.mesh -rnum 3.0 -pref 3 -sigma 1.0 -vis
/*
Ref | Dofs | ω | H(curl) Error | Rate | Solv it |
-----------------------------------------------------------------
0 | 1944 | 6.0 π | 2.121e+01 | 0.00 | 28 (24)|
1 | 13872 | 6.0 π | 7.291e+00 | -1.63 | 34 (19)|
2 | 104544 | 6.0 π | 1.926e+00 | -1.98 | 48 (19)|
3 | 811200 | 6.0 π | 4.862e-01 | -2.02 | 60 (19)|
*/
// mpirun -np 8 ./pmaxwell -o 3 -sref 0 -m ../data/inline-hex.mesh -rnum 3.0 -pref 2 -sigma 1.0 -vis
/*
Ref | Dofs | ω | H(curl) Error | Rate | Solv it |
-----------------------------------------------------------------
0 | 6084 | 6.0 π | 9.797e+00 | 0.00 | 36 (22)|
1 | 45000 | 6.0 π | 1.475e+00 | -2.84 | 56 (19)|
2 | 345744 | 6.0 π | 1.918e-01 | -3.00 | 78 (19)|
*/
// Note: (*) indicates a priconditioner with exact inverse of the diagonal blocks
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
void E_exact_r(const Vector &x, Vector & E_r);
void E_exact_i(const Vector &x, Vector & E_i);
void rhs_func_r(const Vector &x, Vector & J_r);
void rhs_func_i(const Vector &x, Vector & J_i);
void curlE_exact_r(const Vector &x, Vector &curlE_r);
void curlE_exact_i(const Vector &x, Vector &curlE_i);
void maxwell_solution(const Vector & X,
std::vector<complex<real_t>> &E);
void maxwell_solution_curl(const Vector & X,
std::vector<complex<real_t>> &curlE);
void maxwell_solution_curlcurl(const Vector & X,
std::vector<complex<real_t>> &curlcurlE);
int dim;
int dimc;
real_t omega;
real_t mu = 1.0;
real_t epsilon = 0.0;
real_t sigma = 0.1;
complex<real_t> zi = complex<real_t>(0., 1.);
int main(int argc, char *argv[])
{
Mpi::Init();
int myid = Mpi::WorldRank();
int num_procs = Mpi::WorldSize();
Hypre::Init();
const char *mesh_file = "../data/inline-hex.mesh";
int order = 1;
bool visualization = false;
real_t rnum=1.0;
int sr = 0;
int pr = 0;
bool paraview = false;
bool mumps_solver = false;
bool herm_conv = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree)");
args.AddOption(&rnum, "-rnum", "--number_of_wavelenths",
"Number of wavelengths");
args.AddOption(&mu, "-mu", "--permeability",
"Permeability of free space (or 1/(spring constant)).");
args.AddOption(&epsilon, "-eps", "--permittivity",
"Permittivity of free space (or mass constant).");
args.AddOption(&sigma, "-sigma", "--conductivity",
"Conductivity");
args.AddOption(&sr, "-sref", "--serial_ref",
"Number of serial refinements.");
args.AddOption(&pr, "-pref", "--parallel_ref",
"Number of parallel refinements.");
args.AddOption(&herm_conv, "-herm", "--hermitian", "-no-herm",
"--no-hermitian", "Use convention for Hermitian operators.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&paraview, "-paraview", "--paraview", "-no-paraview",
"--no-paraview",
"Enable or disable ParaView visualization.");
args.AddOption(&mumps_solver, "-mumps-solver", "--mumps-solver",
"-no-mumps-solver",
"--no-mumps-solver",
"Enable or disable mumps solver");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
ComplexOperator::Convention conv =
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
socketstream E_out_r;
socketstream E_out_i;
omega = real_t(2.0 * M_PI)*rnum;
Mesh mesh(mesh_file, 1, 1);
dim = mesh.Dimension();
dimc = (dim == 3) ? 3 : 1;
for (int i = 0; i<sr; i++)
{
mesh.UniformRefinement();
}
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
ND_FECollection fec(order, dim);
ParFiniteElementSpace E_fes(&pmesh, &fec);
// Bilinear form coefficients
ConstantCoefficient one(1.0);
ConstantCoefficient muinv(1./mu);
ConstantCoefficient omeg(omega);
ConstantCoefficient eps(epsilon);
ConstantCoefficient negomeg2eps(-omega*omega*epsilon);
ConstantCoefficient omegsigma(omega*sigma);
VectorFunctionCoefficient Jr(dim,rhs_func_r);
VectorFunctionCoefficient Ji(dim,rhs_func_i);
VectorFunctionCoefficient Er(dim,E_exact_r);
VectorFunctionCoefficient Ei(dim,E_exact_i);
VectorFunctionCoefficient CurlEr(dim,curlE_exact_r);
VectorFunctionCoefficient CurlEi(dim,curlE_exact_i);
ParComplexLinearForm b(&E_fes, conv);
b.Vector::operator=(0.0);
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(Jr),
new VectorFEDomainLFIntegrator(Ji));
ParSesquilinearForm a(&E_fes, conv);
a.AddDomainIntegrator(new CurlCurlIntegrator(muinv),nullptr);
a.AddDomainIntegrator(new VectorFEMassIntegrator(negomeg2eps),
new VectorFEMassIntegrator(omegsigma));
ParBilinearForm prec(&E_fes);
prec.AddDomainIntegrator(new CurlCurlIntegrator(muinv));
prec.AddDomainIntegrator(new VectorFEMassIntegrator(omegsigma));
ParComplexGridFunction E_gf(&E_fes);
E_gf.real() = 0.0;
E_gf.imag() = 0.0;
ParaViewDataCollection * paraview_dc = nullptr;
if (paraview)
{
paraview_dc = new ParaViewDataCollection(mesh_file, &pmesh);
paraview_dc->SetPrefixPath("ParaView");
paraview_dc->SetLevelsOfDetail(order);
paraview_dc->SetCycle(0);
paraview_dc->SetDataFormat(VTKFormat::BINARY);
paraview_dc->SetHighOrderOutput(true);
paraview_dc->SetTime(0.0); // set the time
paraview_dc->RegisterField("E_r",&E_gf.real());
paraview_dc->RegisterField("E_i",&E_gf.imag());
}
if (Mpi::Root())
{
std::cout << "\n Ref |"
<< " Dofs |"
<< " ω |"
<< " H(curl) Error |"
<< " Rate |"
<< " Solv it |" << endl;
std::cout << std::string(65,'-')
<< endl;
}
real_t err0 = 0.;
int dof0;
for (int it = 0; it<=pr; it++)
{
b.Assemble();
a.Assemble();
prec.Assemble();
Array<int> ess_tdof_list;
Array<int> ess_bdr;
if (pmesh.bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh.bdr_attributes.Max());
ess_bdr = 1;
E_fes.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
E_gf.real() = 0.0;
E_gf.imag() = 0.0;
E_gf.ProjectBdrCoefficientTangent(Er,Ei, ess_bdr);
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, E_gf, b, A, X, B);
HypreParMatrix M;
prec.FormSystemMatrix(ess_tdof_list, M);
Array<int> offsets(3);
offsets[0] = 0;
offsets[1] = E_fes.TrueVSize();
offsets[2] = E_fes.TrueVSize();
offsets.PartialSum();
BlockDiagonalPreconditioner BlockPrec(offsets);
std::unique_ptr<Operator> pc_r;
std::unique_ptr<Operator> pc_i;
int s = (conv == ComplexOperator::HERMITIAN) ? -1 : 1;
#ifdef MFEM_USE_MUMPS
if (mumps_solver)
{
pc_r.reset(new MUMPSSolver(M));
pc_i.reset(new ScaledOperator(pc_r.get(), s));
}
#else
mumps_solver = false;
#endif
if (!mumps_solver)
{
pc_r.reset(new HypreAMS(M,&E_fes));
pc_i.reset(new ScaledOperator(pc_r.get(), s));
}
BlockPrec.SetDiagonalBlock(0,pc_r.get());
BlockPrec.SetDiagonalBlock(1,pc_i.get());
std::unique_ptr<IterativeSolver> solver;
if (conv == ComplexOperator::HERMITIAN)
{
solver.reset(new FGMRESSolver(MPI_COMM_WORLD));
}
else
{
solver.reset(new MINRESSolver(MPI_COMM_WORLD));
}
solver.get()->SetRelTol(1e-12);
solver.get()->SetMaxIter(2000);
solver.get()->SetPrintLevel(0);
solver.get()->SetPreconditioner(BlockPrec);
solver.get()->SetOperator(*A);
solver.get()->Mult(B, X);
int num_iter = solver.get()->GetNumIterations();
a.RecoverFEMSolution(X, b, E_gf);
real_t err_r = E_gf.real().ComputeHCurlError(&Er,&CurlEr);
real_t err_i = E_gf.imag().ComputeHCurlError(&Ei,&CurlEi);
real_t totalerr = std::sqrt(err_r*err_r + err_i*err_i);
int dofs = E_fes.GlobalTrueVSize();
real_t rate_err = (it) ? dim*log(err0/totalerr)/log((real_t)dof0/dofs) : 0.0;
err0 = totalerr;
dof0 = dofs;
if (Mpi::Root())
{
std::ios oldState(nullptr);
oldState.copyfmt(std::cout);
std::cout << std::right << std::setw(5) << it << " | "
<< std::setw(10) << dof0 << " | "
<< std::setprecision(1) << std::fixed
<< std::setw(4) << 2.0*rnum << " π | "
<< std::setprecision(3);
std::cout << std::setw(13) << std::scientific << err0 << " | "
<< std::setprecision(2)
<< std::setw(6) << std::fixed << rate_err << " | "
<< std::setw(7) << std::fixed << num_iter << " | "
<< std::endl;
std::cout.copyfmt(oldState);
}
if (visualization)
{
// Define visualization keys for GLVis (see GLVis documentation)
string keys;
keys = (dim == 3) ? "keys macF\n" : keys = "keys amrRljcUUuu\n";
char vishost[] = "localhost";
int visport = 19916;
{
socketstream sol_sock_re(vishost, visport);
sol_sock_re.precision(8);
sol_sock_re << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << pmesh << E_gf.real() << keys
<< "window_title 'Solution real part'" << flush;
}
{
socketstream sol_sock_im(vishost, visport);
sol_sock_im.precision(8);
sol_sock_im << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << pmesh << E_gf.imag() << keys
<< "window_title 'Solution imag part'" << flush;
}
}
if (paraview)
{
paraview_dc->SetCycle(it);
paraview_dc->SetTime((real_t)it);
paraview_dc->Save();
}
pmesh.UniformRefinement();
E_fes.Update();
E_gf.Update();
a.Update();
b.Update();
prec.Update();
}
if (paraview)
{
delete paraview_dc;
}
return 0;
}
void maxwell_solution(const Vector & X, std::vector<complex<real_t>> &E)
{
E.resize(dim);
for (int i = 0; i < dim; ++i)
{
E[i] = 0.0;
}
E[0] = exp(zi * omega * (X.Sum()));
}
void maxwell_solution_curl(const Vector & X,
std::vector<complex<real_t>> &curlE)
{
curlE.resize(dimc);
for (int i = 0; i < dimc; ++i)
{
curlE[i] = 0.0;
}
std::complex<real_t> pw = exp(zi * omega * (X.Sum()));
if (dim == 3)
{
curlE[0] = 0.0;
curlE[1] = zi * omega * pw;
curlE[2] = -zi * omega * pw;
}
else
{
curlE[0] = -zi * omega * pw;
}
}
void maxwell_solution_curlcurl(const Vector & X,
std::vector<complex<real_t>> &curlcurlE)
{
curlcurlE.resize(dim);
for (int i = 0; i < dim; ++i)
{
curlcurlE[i] = 0.0;;
}
std::complex<real_t> pw = exp(zi * omega * (X.Sum()));
if (dim == 3)
{
curlcurlE[0] = 2_r * omega * omega * pw;
curlcurlE[1] = - omega * omega * pw;
curlcurlE[2] = - omega * omega * pw;
}
else
{
curlcurlE[0] = omega * omega * pw;
curlcurlE[1] = -omega * omega * pw;
}
}
void E_exact_r(const Vector &x, Vector & E_r)
{
std::vector<std::complex<real_t>> E;
maxwell_solution(x,E);
E_r.SetSize(E.size());
for (unsigned i = 0; i < E.size(); i++)
{
E_r[i]= E[i].real();
}
}
void E_exact_i(const Vector &x, Vector & E_i)
{
std::vector<std::complex<real_t>> E;
maxwell_solution(x, E);
E_i.SetSize(E.size());
for (unsigned i = 0; i < E.size(); i++)
{
E_i[i]= E[i].imag();
}
}
void curlE_exact_r(const Vector &x, Vector &curlE_r)
{
std::vector<std::complex<real_t>> curlE;
maxwell_solution_curl(x, curlE);
curlE_r.SetSize(curlE.size());
for (unsigned i = 0; i < curlE.size(); i++)
{
curlE_r[i]= curlE[i].real();
}
}
void curlE_exact_i(const Vector &x, Vector &curlE_i)
{
std::vector<std::complex<real_t>> curlE;
maxwell_solution_curl(x, curlE);
curlE_i.SetSize(curlE.size());
for (unsigned i = 0; i < curlE.size(); i++)
{
curlE_i[i]= curlE[i].imag();
}
}
void rhs_func_r(const Vector &x, Vector & J_r)
{
std::vector<std::complex<real_t>> curlcurlE;
std::vector<std::complex<real_t>> E;
maxwell_solution(x,E);
maxwell_solution_curlcurl(x, curlcurlE);
J_r.SetSize(dim);
for (int i = 0; i<dim; i++)
{
const complex<real_t> tmp = 1_r/mu*curlcurlE[i]
+ zi * omega *(sigma+zi*omega*epsilon) *E[i];
J_r(i) = tmp.real();
}
}
void rhs_func_i(const Vector &x, Vector & J_i)
{
std::vector<std::complex<real_t>> curlcurlE;
std::vector<std::complex<real_t>> E;
maxwell_solution(x,E);
maxwell_solution_curlcurl(x, curlcurlE);
J_i.SetSize(dim);
for (int i = 0; i<dim; i++)
{
const complex<real_t> tmp = 1_r/mu*curlcurlE[i]
+ zi * omega *(sigma+zi*omega*epsilon) *E[i];
J_i(i) = tmp.imag();
}
}
+1
View File
@@ -66,6 +66,7 @@ int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI) and HYPRE.
Mpi::Init(argc, argv);
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
+2
View File
@@ -80,6 +80,8 @@ int main(int argc, char *argv[])
{
// 1. Initialize MPI (required by PUMI) and HYPRE.
Mpi::Init(argc, argv);
int num_proc = Mpi::WorldSize();
int myId = Mpi::WorldRank();
Hypre::Init();
// 2. Parse command-line options.
-345
View File
@@ -1539,351 +1539,6 @@ const IntegrationRule &ConvectionIntegrator::GetRule(
return GetRule(el,el,Trans);
}
void LaplaceIntegrator::AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat )
{
int nd = el.GetDof();
real_t w;
elmat.SetSize(nd);
shape.SetSize(nd);
laplace.SetSize(nd);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
el.CalcPhysShape(Trans, shape);
el.CalcPhysLaplacian(Trans, laplace);
w = Trans.Weight() * ip.weight * alpha;
if (Q)
{
w *= Q -> Eval(Trans, ip);
}
shape *= w;
AddMultVWt(shape, laplace, elmat);
}
}
void LaplaceIntegrator::AssembleElementMatrix2(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat)
{
int tr_nd = trial_fe.GetDof();
int te_nd = test_fe.GetDof();
elmat.SetSize(te_nd, tr_nd);
laplace.SetSize(tr_nd);
shape.SetSize(te_nd);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
Trans);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
test_fe.CalcPhysShape(Trans, shape);
trial_fe.CalcPhysLaplacian(Trans, laplace);
real_t w = Trans.Weight() * ip.weight * alpha;
if (Q)
{
w *= Q -> Eval(Trans, ip);
}
AddMult_a_VWt(w, shape, laplace, elmat);
}
}
const IntegrationRule &LaplaceIntegrator::GetRule(
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans)
{
int order = trial_fe.GetOrder() + test_fe.GetOrder();
return IntRules.Get(trial_fe.GetGeomType(), order);
}
void LaplaceGradIntegrator::AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat )
{
int nd = el.GetDof();
dim = el.GetDim();
elmat.SetSize(nd);
dshape.SetSize(nd,dim);
adjJ.SetSize(dim);
laplace.SetSize(nd);
vec2.SetSize(dim);
BdFidxT.SetSize(nd);
Vector vec1;
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
Q->Eval(Q_ir, Trans, *ir);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
el.CalcDShape(ip, dshape);
el.CalcPhysLaplacian(Trans, laplace);
Trans.SetIntPoint(&ip);
CalcAdjugate(Trans.Jacobian(), adjJ);
Q_ir.GetColumnReference(i, vec1);
vec1 *= alpha * ip.weight;
adjJ.Mult(vec1, vec2);
dshape.Mult(vec2, BdFidxT);
AddMultVWt(BdFidxT, laplace, elmat);
}
}
void LaplaceGradIntegrator::AssembleElementMatrix2(const FiniteElement
&trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat)
{
dim = trial_fe.GetDim();
int tr_nd = trial_fe.GetDof();
int te_nd = test_fe.GetDof();
elmat.SetSize(te_nd, tr_nd);
laplace.SetSize(tr_nd);
dshape.SetSize(te_nd,dim);
adjJ.SetSize(dim);
vec2.SetSize(dim);
BdFidxT.SetSize(te_nd);
Vector vec1;
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
Trans);
Q->Eval(Q_ir, Trans, *ir);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
test_fe.CalcDShape(ip, dshape);
trial_fe.CalcPhysLaplacian(Trans, laplace);
Trans.SetIntPoint(&ip);
CalcAdjugate(Trans.Jacobian(), adjJ);
Q_ir.GetColumnReference(i, vec1);
vec1 *= alpha * ip.weight;
adjJ.Mult(vec1, vec2);
dshape.Mult(vec2, BdFidxT);
AddMultVWt(BdFidxT, laplace,elmat);
}
}
const IntegrationRule &LaplaceGradIntegrator::GetRule(
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans)
{
int order = trial_fe.GetOrder() + test_fe.GetOrder();
return IntRules.Get(trial_fe.GetGeomType(), order);
}
void LaplaceLaplaceIntegrator::AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat )
{
int nd = el.GetDof();
real_t w;
elmat.SetSize(nd);
laplace.SetSize(nd);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
el.CalcPhysLaplacian(Trans, laplace);
w = Trans.Weight() * ip.weight * alpha;
if (Q)
{
w *= Q -> Eval(Trans, ip);
}
AddMult_a_VVt(w, laplace, elmat);
}
}
void LaplaceLaplaceIntegrator::AssembleElementMatrix2(const FiniteElement
&trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat)
{
int
dim = trial_fe.GetDim();
int tr_nd = trial_fe.GetDof();
int te_nd = test_fe.GetDof();
real_t w;
elmat.SetSize(te_nd, tr_nd);
laplace.SetSize(tr_nd);
te_laplace.SetSize(te_nd);
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
Trans);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
trial_fe.CalcPhysLaplacian(Trans, laplace);
test_fe.CalcPhysLaplacian(Trans, te_laplace);
w = Trans.Weight() * ip.weight * alpha;
if (Q)
{
w *= Q -> Eval(Trans, ip);
}
AddMult_a_VWt(w, te_laplace, laplace, elmat);
}
}
const IntegrationRule &LaplaceLaplaceIntegrator::GetRule(
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans)
{
int order = trial_fe.GetOrder() + test_fe.GetOrder();
return IntRules.Get(trial_fe.GetGeomType(), order);
}
void InverseEstimateIntegrator::AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat )
{
elmat = 0.0;
int nd = el.GetDof();
int dim = el.GetDim();
shape.SetSize(nd);
dshape.SetSize(nd,dim);
laplace.SetSize(nd);
lapmat.SetSize(nd,nd);
bimat.SetSize(nd,nd);
ovec.SetSize(nd);
real_t w,q;
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
int order = Trans.OrderGrad(&el) + Trans.Order() + el.GetOrder();
ir = &IntRules.Get(el.GetGeomType(), order);
}
bimat = 0.0;
lapmat = 0.0;
ovec = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint(&ip);
w = Trans.Weight()*ip.weight;
if (Q)
{
q = Q->Eval(Trans, ip);
}
el.CalcPhysDShape(Trans, dshape);
AddMult_a_AAt(w*q, dshape, lapmat);
el.CalcPhysLaplacian(Trans, laplace);
AddMult_a_VVt(w*q*q, laplace, bimat);
el.CalcPhysShape(Trans, shape);
ovec.Add(w, shape);
}
// Power method
Vector x(nd);
x.Randomize(696383532);
// Correct nullspace + inverse
AddMult_a_VVt(1.0, ovec, lapmat);
DenseMatrixInverse L_inv(lapmat);
// DenseMatrix M_i, Q_i;
real_t alpha= 0.0, eval_i = 0.0, eval_prev = 0.0;
// Inverse power method
Vector x_tmp(nd);
int iter = 0;
const real_t rel_tol = 1e-4;
alpha = ovec*ovec;
ovec *= 1.0/sqrt(alpha);
do
{
// Othogonalize
alpha = x*ovec;
x.Add(-alpha, ovec);
// MatVec (2x)
bimat.Mult(x, x_tmp);
L_inv.Mult(x_tmp, x);
eval_prev = eval_i;
eval_i = x.Norml2();
x *= 1.0/eval_i;
++iter;
}
while ((iter < 10000) && (fabs(eval_i - eval_prev)/fabs(eval_i) > rel_tol));
MFEM_VERIFY(fabs(eval_i - eval_prev)/fabs(eval_i) <= rel_tol,
"Inverse power method did not converge."
<< "\n\t iter = " << iter
<< "\n\t eval_i = " << eval_i
<< "\n\t eval_prev = " << eval_prev
<< "\n\t fabs(eval_i - eval_prev)/fabs(eval_i) = "
<< fabs(eval_i - eval_prev)/fabs(eval_i));
cout<<"evev = "<<eval_i<<" "<<iter<<endl;
}
const IntegrationRule &InverseEstimateIntegrator::GetRule(
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans)
{
// int order = Trans.OrderGrad(&trial_fe) + Trans.Order() + test_fe.GetOrder() - 2;
int order = trial_fe.GetOrder() + test_fe.GetOrder();
return IntRules.Get(trial_fe.GetGeomType(), order);
}
void VectorMassIntegrator::AssembleElementMatrix
( const FiniteElement &el, ElementTransformation &Trans,
DenseMatrix &elmat )
+3 -132
View File
@@ -1741,7 +1741,7 @@ public:
{ vector_fe.CalcPhysDShape(Trans, shape); }
};
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \cdot \nabla u, \nabla \cdot v)$ in 2D
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \cdot \nabla \cdot u, \nabla \cdot v)$ in 2D
or 3D and where $\hat{V}$ is a vector coefficient, $u$ is in $H^1$ and $v$ is in $H(div)$. */
class MixedGradDivIntegrator : public MixedScalarVectorIntegrator
{
@@ -1780,7 +1780,7 @@ public:
{ scalar_fe.CalcPhysDivShape(Trans, shape); }
};
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \nabla \cdot u, \nabla v)$ in 2D
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} \nabla \cdot u, \nabla \cdot v)$ in 2D
or 3D and where $\hat{V}$ is a vector coefficient, $u$ is in $H(div)$ and $v$ is in $H^1$. */
class MixedDivGradIntegrator : public MixedScalarVectorIntegrator
{
@@ -1820,7 +1820,7 @@ public:
{ scalar_fe.CalcPhysDivShape(Trans, shape); }
};
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} u, \nabla v)$ in 2D or 3D
/** Class for integrating the bilinear form $a(u,v) := (-\hat{V} u, \nabla \cdot v)$ in 2D or 3D
and where $\hat{V}$ is a vector coefficient, $u$ is in $H^1$ or $L_2$ and $v$ is in $H^1$. */
class MixedScalarWeakDivergenceIntegrator : public MixedScalarVectorIntegrator
{
@@ -2450,135 +2450,6 @@ public:
DenseMatrix &);
};
/// $\alpha (Q \Delta u, v)$
class LaplaceIntegrator : public BilinearFormIntegrator
{
protected:
Coefficient *Q;
real_t alpha;
private:
Vector laplace, shape;
public:
LaplaceIntegrator(Coefficient &q, real_t a = 1.0)
: Q(&q) { alpha = a; }
virtual void AssembleElementMatrix(const FiniteElement &,
ElementTransformation &,
DenseMatrix &);
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans);
};
/// $\alpha (u, Q \Delta v)$
class TransposeLaplaceIntegrator : public TransposeIntegrator
{
public:
TransposeLaplaceIntegrator (Coefficient &q, real_t a = 1.0)
: TransposeIntegrator(new LaplaceIntegrator(q, a)) { }
};
/// $\alpha (\Delta u, Q \cdot \nabla v)$
class LaplaceGradIntegrator : public BilinearFormIntegrator
{
protected:
VectorCoefficient *Q;
real_t alpha;
int dim;
private:
Vector laplace, vec2, BdFidxT;
DenseMatrix dshape, adjJ, Q_ir;
public:
LaplaceGradIntegrator(VectorCoefficient &q, real_t a = 1.0)
: Q(&q) { alpha = a; }
virtual void AssembleElementMatrix(const FiniteElement &,
ElementTransformation &,
DenseMatrix &);
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans);
};
/// $\alpha (Q \cdot \nabla u, \Delta v)$
class GradLaplaceIntegrator : public TransposeIntegrator
{
public:
GradLaplaceIntegrator(VectorCoefficient &q, real_t a = 1.0)
: TransposeIntegrator(new LaplaceGradIntegrator(q, a)) { }
};
/// $\alpha (Q \Delta u, \Delta v)$
class LaplaceLaplaceIntegrator : public BilinearFormIntegrator
{
protected:
Coefficient *Q;
real_t alpha;
private:
Vector laplace, te_laplace;
public:
LaplaceLaplaceIntegrator(Coefficient &q, real_t a = 1.0)
: Q(&q) { alpha = a; }
virtual void AssembleElementMatrix(const FiniteElement &,
ElementTransformation &,
DenseMatrix &);
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans,
DenseMatrix &elmat);
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans);
};
// Alias for @LaplaceLaplaceIntegrator.
using BiHarmonicIntegrator = LaplaceLaplaceIntegrator;
/// Get the inverse estimate
class InverseEstimateIntegrator : public BilinearFormIntegrator
{
protected:
Coefficient *Q;
private:
Vector laplace, shape, ovec;//, vec2, BdFidxT;
DenseMatrix dshape, lapmat, bimat;//, adjJ, Q_ir;
public:
InverseEstimateIntegrator(Coefficient &q)
: Q(&q) { }
virtual void AssembleElementMatrix(const FiniteElement &,
ElementTransformation &,
DenseMatrix &);
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans);
};
/** Class for integrating the bilinear form $a(u,v) := (Q u, v)$,
where $u=(u_1,\dots,u_n)$ and $v=(v_1,\dots,v_n)$, $u_i$ and $v_i$ are defined
by scalar FE through standard transformation. */
+4 -407
View File
@@ -807,7 +807,6 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
QuadratureSpaceBase &qspace = *qf.GetSpace();
const int ne = qspace.GetNE();
qf.HostWrite();
DenseMatrix values;
DenseSymmetricMatrix matrix;
for (int iel = 0; iel < ne; ++iel)
@@ -819,7 +818,7 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
{
const IntegrationPoint &ip = ir[iq];
T.SetIntPoint(&ip);
matrix.UseExternalData(&values(0, iq), height);
matrix.UseExternalData(&values(0, iq), vdim);
Eval(matrix, T, ip);
}
}
@@ -829,12 +828,13 @@ void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
void SymmetricMatrixCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip)
{
Eval(mat_aux, T, ip);
mat.SetSize(height);
Eval(mat, T, ip);
for (int j = 0; j < width; ++j)
{
for (int i = 0; i < height; ++ i)
{
K(i, j) = mat_aux(i, j);
K(i, j) = mat(i, j);
}
}
}
@@ -924,75 +924,6 @@ void MatrixArrayCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
}
}
MatrixArrayVectorCoefficient::MatrixArrayVectorCoefficient (int dim)
: MatrixCoefficient (dim)
{
Coeff.SetSize(height);
ownCoeff.SetSize(height);
for (int i = 0; i < height; i++)
{
Coeff[i] = NULL;
ownCoeff[i] = true;
}
}
void MatrixArrayVectorCoefficient::SetTime(real_t t)
{
for (int i=0; i < height; i++)
{
if (Coeff[i]) { Coeff[i]->SetTime(t); }
}
this->MatrixCoefficient::SetTime(t);
}
void MatrixArrayVectorCoefficient::Set(int i, VectorCoefficient * c, bool own)
{
MFEM_ASSERT(i < height && i >= 0, "Row "
<< i << " does not exist. " <<
"Matrix height = " << height << ".");
if (ownCoeff[i]) { delete Coeff[i]; }
Coeff[i] = c;
ownCoeff[i] = own;
}
MatrixArrayVectorCoefficient::~MatrixArrayVectorCoefficient ()
{
for (int i=0; i < height; i++)
{
if (ownCoeff[i]) { delete Coeff[i]; }
}
}
void MatrixArrayVectorCoefficient::Eval(int i, Vector &V,
ElementTransformation &T,
const IntegrationPoint &ip)
{
MFEM_ASSERT(i < height && i >= 0, "Row "
<< i << " does not exist. " <<
"Matrix height = " << height << ".");
if (Coeff[i])
{
Coeff[i] -> Eval(V, T, ip);
}
else
{
V = 0.0;
}
}
void MatrixArrayVectorCoefficient::Eval(DenseMatrix &K,
ElementTransformation &T,
const IntegrationPoint &ip)
{
K.SetSize(height, width);
Vector V(width);
for (int i = 0; i < height; i++)
{
this->Eval(i, V, T, ip);
K.SetRow(i, V);
}
}
void MatrixRestrictedCoefficient::SetTime(real_t t)
{
if (c) { c->SetTime(t); }
@@ -1110,27 +1041,6 @@ real_t DeterminantCoefficient::Eval(ElementTransformation &T,
return ma.Det();
}
TraceCoefficient::TraceCoefficient(MatrixCoefficient &A)
: a(&A), ma(A.GetHeight(), A.GetWidth())
{
MFEM_ASSERT(A.GetHeight() == A.GetWidth(),
"TraceCoefficient: "
"Argument must be a square matrix.");
}
void TraceCoefficient::SetTime(real_t t)
{
if (a) { a->SetTime(t); }
this->Coefficient::SetTime(t);
}
real_t TraceCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
a->Eval(ma, T, ip);
return ma.Trace();
}
VectorSumCoefficient::VectorSumCoefficient(int dim)
: VectorCoefficient(dim),
ACoef(NULL), BCoef(NULL),
@@ -1416,30 +1326,6 @@ void InverseMatrixCoefficient::Eval(DenseMatrix &M,
M.Invert();
}
ExponentialMatrixCoefficient::ExponentialMatrixCoefficient(MatrixCoefficient &A)
: MatrixCoefficient(A.GetHeight(), A.GetWidth()), a(&A)
{
MFEM_ASSERT(A.GetHeight() == A.GetWidth() && A.GetHeight() == 2,
"ExponentialMatrixCoefficient: "
<< "Argument must be a square 2x2 matrix."
<< " Height = " << A.GetHeight()
<< ", Width = " << A.GetWidth());
}
void ExponentialMatrixCoefficient::SetTime(real_t t)
{
if (a) { a->SetTime(t); }
this->MatrixCoefficient::SetTime(t);
}
void ExponentialMatrixCoefficient::Eval(DenseMatrix &M,
ElementTransformation &T,
const IntegrationPoint &ip)
{
a->Eval(M, T, ip);
M.Exponential();
}
OuterProductCoefficient::OuterProductCoefficient(VectorCoefficient &A,
VectorCoefficient &B)
: MatrixCoefficient(A.GetVDim(), B.GetVDim()), a(&A), b(&B),
@@ -1504,295 +1390,6 @@ void CrossCrossCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
M *= ((a == NULL ) ? aConst : a->Eval(T, ip) );
}
InverseEstimateCoefficient::InverseEstimateCoefficient(FiniteElementSpace *f)
: fes(f), Q(NULL), ir(NULL)
{
ComputeInverseEstimates();
}
InverseEstimateCoefficient::InverseEstimateCoefficient(FiniteElementSpace *f,
Coefficient &q)
: fes(f), Q(&q), ir(NULL)
{
ComputeInverseEstimates();
}
GridFunction *InverseEstimateCoefficient::GetGridFunction()
{
FiniteElementCollection* fec_ec = new L2_FECollection(0,
fes ->GetMesh()->Dimension());
FiniteElementSpace *fes_ec = new FiniteElementSpace(fes ->GetMesh(), fec_ec);
GridFunction *gf = new GridFunction(fes_ec, elemInvEst.GetData());
gf->MakeOwner(fec_ec);
return gf;
}
void InverseEstimateCoefficient::ComputeInverseEstimates()
{
elemInvEst.SetSize(fes -> GetNE());
SetIntRule(*fes->GetFE(0));
for (int i = 0; i < fes -> GetNE(); i++)
{
elemInvEst[i] = ElementInverseEstimate(*fes->GetFE(i),
*fes->GetElementTransformation(i));
}
}
void InverseEstimateCoefficient::SetIntRule(const FiniteElement &el)
{
ir = &IntRules.Get(el.GetGeomType(), 2*el.GetOrder());
}
real_t InverseEstimateCoefficient::ElementInverseEstimate(
const FiniteElement &el,
ElementTransformation &Trans)
{
if (el.GetOrder() < 2)
{
return std::numeric_limits<real_t>::min();
}
int nd = el.GetDof();
int dim = el.GetDim();
shape.SetSize(nd);
dshape.SetSize(nd,dim);
laplace.SetSize(nd);
lapmat.SetSize(nd,nd);
bimat.SetSize(nd,nd);
ovec.SetSize(nd);
real_t w,q = 1.0;
bimat = 0.0;
lapmat = 0.0;
ovec = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint(&ip);
w = Trans.Weight()*ip.weight;
if (Q)
{
q = Q->Eval(Trans, ip);
}
el.CalcPhysDShape(Trans, dshape);
AddMult_a_AAt(w*q, dshape, lapmat);
el.CalcPhysLaplacian(Trans, laplace);
AddMult_a_VVt(w*q*q, laplace, bimat);
el.CalcPhysShape(Trans, shape);
ovec.Add(w, shape);
}
ovec *= 1.0/ovec.Norml2();
// Correct nullspace
AddMultVVt(ovec, lapmat);
// Return largest eigenvalue
return bimat.Eigenvalue(lapmat);
}
ElasticInverseEstimateCoefficient
::ElasticInverseEstimateCoefficient(FiniteElementSpace *f)
: fes(f), Q(NULL), ir(NULL)
{
ComputeInverseEstimates();
}
ElasticInverseEstimateCoefficient
::ElasticInverseEstimateCoefficient(FiniteElementSpace *f,
Coefficient &q)
: fes(f), Q(&q), ir(NULL)
{
ComputeInverseEstimates();
}
GridFunction *ElasticInverseEstimateCoefficient::GetGridFunction()
{
FiniteElementCollection* fec_ec = new L2_FECollection(0,
fes ->GetMesh()->Dimension());
FiniteElementSpace *fes_ec = new FiniteElementSpace(fes ->GetMesh(), fec_ec);
GridFunction *gf = new GridFunction(fes_ec, elemInvEst.GetData());
gf->MakeOwner(fec_ec);
return gf;
}
void ElasticInverseEstimateCoefficient::ComputeInverseEstimates()
{
elemInvEst.SetSize(fes -> GetNE());
SetIntRule(*fes->GetFE(0));
int dim = fes->GetFE(0)->GetDim();
emat.SetSize(dim,dim);
divmat.SetSize(dim,dim);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
emat(i,j)= new DenseMatrix();
divmat(i,j)= new DenseMatrix();
}
}
hmap.SetSize(dim,dim);
if (dim == 2)
{
hmap(0,0) = 0;
hmap(0,1) = hmap(1,0) = 1;
hmap(1,1) = 2;
}
else if (dim == 2)
{
hmap(0,0) = 0;
hmap(0,1) = hmap(1,0) = 1;
hmap(0,2) = hmap(2,0) = 2;
hmap(1,1) = 3;
hmap(1,2) = hmap(2,1) = 4;
hmap(2,2) = 5;
}
else
{
mfem_error("Only implemented for 2D and 3D");
}
for (int i = 0; i < fes -> GetNE(); i++)
{
elemInvEst[i] = ElementInverseEstimate(*fes->GetFE(i),
*fes->GetElementTransformation(i));
}
}
void ElasticInverseEstimateCoefficient::SetIntRule(const FiniteElement &el)
{
ir = &IntRules.Get(el.GetGeomType(), 2*el.GetOrder());
}
real_t ElasticInverseEstimateCoefficient::ElementInverseEstimate(
const FiniteElement &el,
ElementTransformation &Trans)
{
// if (el.GetDerivType() != (int) FiniteElement::HESS)
// {
// return std::numeric_limits<real_t>::min();
// }
int nd = el.GetDof();
int dim = el.GetDim();
shape.SetSize(nd);
dshape.SetSize(nd,dim);
hshape.SetSize(nd,dim*(dim+1)/2);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
emat(i,j)->SetSize(nd,nd);
*emat(i,j) = 0.0;
divmat(i,j)->SetSize(nd,nd);
*divmat(i,j) = 0.0;
}
}
real_t w,q = 1.0;
for (int ii = 0; ii < ir->GetNPoints(); ii++)
{
const IntegrationPoint &ip = ir->IntPoint(ii);
Trans.SetIntPoint(&ip);
w = Trans.Weight()*ip.weight;
if (Q)
{
q = Q->Eval(Trans, ip);
}
el.CalcPhysDShape(Trans, dshape);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
AddMult_a_VVt(w*q, Vector(dshape.GetColumn(i),nd), *emat(j,j));
AddMult_a_VWt(w*q, Vector(dshape.GetColumn(i),nd),
Vector(dshape.GetColumn(j),nd), *emat(j,i));
AddMult_a_VWt(w*q, Vector(dshape.GetColumn(j),nd),
Vector(dshape.GetColumn(i),nd), *emat(i,j));
AddMult_a_VVt(w*q, Vector(dshape.GetColumn(j),nd), *emat(i,i));
}
}
el.CalcPhysHessian(Trans, hshape);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
for (int k = 0; k < dim; k++)
{
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,i)),nd),
Vector(hshape.GetColumn(hmap(k,k)),nd), *divmat(j,j));
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,i)),nd),
Vector(hshape.GetColumn(hmap(k,j)),nd), *divmat(j,k));
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,j)),nd),
Vector(hshape.GetColumn(hmap(k,k)),nd), *divmat(i,j));
AddMult_a_VWt(w*q*q, Vector(hshape.GetColumn(hmap(i,j)),nd),
Vector(hshape.GetColumn(hmap(k,j)),nd), *divmat(i,k));
}
}
}
}
// Collect matrices
emat_tot.SetSize(nd*dim,nd*dim);
divmat_tot.SetSize(nd*dim,nd*dim);
for (int i = 0; i < dim; i++)
{
for (int j = 0; j < dim; j++)
{
emat_tot .SetSubMatrix(i*nd, j*nd, *emat(i,j));
divmat_tot.SetSubMatrix(i*nd, j*nd, *divmat(i,j));
}
}
// Correct nullspace
DenseMatrix ns;
emat_tot.NullSpace(ns, 1e-10);
for (int i = 0; i < ns.Width(); i++)
{
AddMultVVt(Vector(ns.GetColumn(i),nd*dim), emat_tot);
}
// Return largest eigenvalue
return divmat_tot.Eigenvalue(emat_tot);
}
ElasticInverseEstimateCoefficient::~ElasticInverseEstimateCoefficient()
{
for (int i = 0; i < emat.NumRows(); i++)
{
for (int j = 0; j < emat.NumCols(); j++)
{
delete emat(i,j);
}
}
for (int i = 0; i < divmat.NumRows(); i++)
{
for (int j = 0; j < divmat.NumCols(); j++)
{
delete divmat(i,j);
}
}
}
real_t LpNormLoop(real_t p, Coefficient &coeff, Mesh &mesh,
const IntegrationRule *irs[])
{
+6 -221
View File
@@ -1334,46 +1334,6 @@ public:
virtual ~MatrixArrayCoefficient();
};
/** @brief Matrix coefficient defined row-wise by an array of vector
coefficients. Rows that are not set will evaluate to zero. The
matrix coefficient is stored as an array indexing the rows of
the matrix. */
class MatrixArrayVectorCoefficient : public MatrixCoefficient
{
private:
Array<VectorCoefficient *> Coeff;
Array<bool> ownCoeff;
public:
/** @brief Construct a coefficient matrix of dimensions @a dim * @a dim. The
actual coefficients still need to be added with Set(). */
explicit MatrixArrayVectorCoefficient (int dim);
/// Set the time for internally stored coefficients
void SetTime(real_t t) override;
/// Get the vector coefficient located at the i-th row of the matrix
VectorCoefficient* GetCoeff (int i) { return Coeff[i]; }
/** @brief Set the coefficient located at the i-th row of the matrix.
By this will take ownership of the Coefficient passed in, but this
can be overridden with the @a own parameter. */
void Set(int i, VectorCoefficient * c, bool own=true);
using MatrixCoefficient::Eval;
/// Evaluate coefficient located at the i-th row of the matrix using integration
/// point @a ip.
void Eval(int i, Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
/// Evaluate the matrix coefficient @a ip.
void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip) override;
virtual ~MatrixArrayVectorCoefficient();
};
/** @brief Derived matrix coefficient that has the value of the parent matrix
coefficient where it is active and is zero otherwise. */
@@ -1466,13 +1426,12 @@ public:
class SymmetricMatrixCoefficient : public MatrixCoefficient
{
protected:
/// Internal matrix used when evaluating this coefficient as a DenseMatrix.
mutable DenseSymmetricMatrix mat_aux;
DenseSymmetricMatrix mat;
public:
/// Construct a dim x dim matrix coefficient.
explicit SymmetricMatrixCoefficient(int dimension)
: MatrixCoefficient(dimension, true), mat_aux(height) { }
: MatrixCoefficient(dimension, true) { }
/// Get the size of the matrix.
int GetSize() const { return height; }
@@ -1505,9 +1464,8 @@ public:
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
const IntegrationPoint &ip);
/// @deprecated Return a reference to the internal matrix used when evaluating this coefficient as a DenseMatrix.
MFEM_DEPRECATED const DenseSymmetricMatrix& GetMatrix() { return mat_aux; }
/// Return a reference to the constant matrix.
const DenseSymmetricMatrix& GetMatrix() { return mat; }
virtual ~SymmetricMatrixCoefficient() { }
};
@@ -1527,10 +1485,6 @@ public:
/// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseSymmetricMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip) { M = mat; }
/// Return a reference to the constant matrix.
const DenseSymmetricMatrix& GetMatrix() { return mat; }
};
@@ -1807,31 +1761,6 @@ public:
const IntegrationPoint &ip);
};
/// Scalar coefficient defined as the trace of a matrix coefficient
class TraceCoefficient : public Coefficient
{
private:
MatrixCoefficient * a;
mutable DenseMatrix ma;
public:
/// Construct with the matrix.
TraceCoefficient(MatrixCoefficient &A);
/// Set the time for internally stored coefficients
void SetTime(real_t t);
/// Reset the matrix coefficient
void SetACoef(MatrixCoefficient &A) { a = &A; }
/// Return the matrix coefficient
MatrixCoefficient * GetACoef() const { return a; }
/// Evaluate the trace coefficient at @a ip.
virtual real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip);
};
/// Vector coefficient defined as the linear combination of two vectors
class VectorSumCoefficient : public VectorCoefficient
{
@@ -2183,7 +2112,7 @@ public:
const IntegrationPoint &ip);
};
/// Matrix coefficient defined as the transpose of a matrix coefficient
/// Matrix coefficient defined as the transpose a matrix coefficient
class TransposeMatrixCoefficient : public MatrixCoefficient
{
private:
@@ -2206,7 +2135,7 @@ public:
const IntegrationPoint &ip);
};
/// Matrix coefficient defined as the inverse of a matrix coefficient.
/// Matrix coefficient defined as the inverse a matrix coefficient.
class InverseMatrixCoefficient : public MatrixCoefficient
{
private:
@@ -2229,29 +2158,6 @@ public:
const IntegrationPoint &ip);
};
/// Matrix coefficient defined as the exponential of a matrix coefficient.
class ExponentialMatrixCoefficient : public MatrixCoefficient
{
private:
MatrixCoefficient * a;
public:
/// Construct the matrix coefficient. Result is $ \exp(A) $.
ExponentialMatrixCoefficient(MatrixCoefficient &A);
/// Set the time for internally stored coefficients
void SetTime(real_t t);
/// Reset the matrix coefficient
void SetACoef(MatrixCoefficient &A) { a = &A; }
/// Return the matrix coefficient
MatrixCoefficient * GetACoef() const { return a; }
/// Evaluate the matrix coefficient at @a ip.
virtual void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationPoint &ip);
};
/// Matrix coefficient defined as the outer product of two vector coefficients.
class OuterProductCoefficient : public MatrixCoefficient
{
@@ -2328,127 +2234,6 @@ public:
};
///@}
/** @brief
*/
class InverseEstimateCoefficient : public Coefficient
{
private:
///
Vector elemInvEst;
/// FE space on which the grid function lives. Owned if #fec is not NULL.
FiniteElementSpace *fes;
///
const IntegrationRule *ir;
///
Coefficient *Q;
Vector laplace, shape, ovec, evec;
DenseMatrix dshape, lapmat, bimat;
///
void SetIntRule(const FiniteElement &el);
///
void ComputeInverseEstimates();
real_t ElementInverseEstimate(const FiniteElement &el,
ElementTransformation &Trans);
public:
///
InverseEstimateCoefficient(FiniteElementSpace *f);
InverseEstimateCoefficient(FiniteElementSpace *f, Coefficient &q);
/// Caller gets owner ship of GridFunction and
GridFunction *GetGridFunction();
/// Reset the scalar factor
void SetDiffusion(Coefficient &q)
{
if (Q != &q)
{
Q = &q;
ComputeInverseEstimates();
}
}
/// Return the scalar factor
Coefficient * GetDiffusion() const { return Q; }
/// Evaluate the coefficient at @a ip.
virtual real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{ return elemInvEst[T.ElementNo]; }
};
class ElasticInverseEstimateCoefficient : public Coefficient
{
private:
///
Vector elemInvEst;
/// FE space on which the grid function lives. Owned if #fec is not NULL.
FiniteElementSpace *fes;
///
const IntegrationRule *ir;
///
Coefficient *Q;
Vector shape, ovec, evec;
DenseMatrix dshape, hshape, emat_tot, divmat_tot;
Array2D<DenseMatrix*> emat,divmat;
Array2D<int> hmap;
///
void SetIntRule(const FiniteElement &el);
///
void ComputeInverseEstimates();
///
real_t ElementInverseEstimate(const FiniteElement &el,
ElementTransformation &Trans);
public:
///
ElasticInverseEstimateCoefficient(FiniteElementSpace *f);
ElasticInverseEstimateCoefficient(FiniteElementSpace *f, Coefficient &q);
/// Caller gets owner ship of GridFunction and
GridFunction *GetGridFunction();
/// Reset the scalar factor
void SetDiffusion(Coefficient &q)
{
if (Q != &q)
{
Q = &q;
ComputeInverseEstimates();
}
}
void SetShearModulus(Coefficient &q) { SetDiffusion(q);}
/// Return the scalar factor
Coefficient * GetDiffusion() const { return Q; }
Coefficient * GetModulus() const { return GetDiffusion(); }
/// Evaluate the coefficient at @a ip.
virtual real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{ return elemInvEst[T.ElementNo]; }
// Destructor
~ElasticInverseEstimateCoefficient();
};
///@}
/** @brief Vector quadrature function coefficient which requires that the
quadrature rules used for this vector coefficient be the same as those that
live within the supplied QuadratureFunction. */
+2 -17
View File
@@ -52,15 +52,6 @@ protected:
const DenseMatrix &EvalTransAdjugateJ();
const DenseMatrix &EvalInverseJ();
/// @name Tolerance used for point comparisons
///@{
#ifdef MFEM_USE_DOUBLE
static constexpr real_t tol_0 = 1e-15;
#elif defined(MFEM_USE_SINGLE)
static constexpr real_t tol_0 = 1e-7;
#endif
///@}
public:
/** This enumeration declares the values stored in
@@ -185,7 +176,7 @@ public:
returned. This method is not 100 percent reliable for non-linear
transformations. */
virtual int TransformBack(const Vector &pt, IntegrationPoint &ip,
const real_t phys_tol = tol_0) = 0;
const real_t phys_tol = 1e-15) = 0;
virtual ~ElementTransformation() { }
};
@@ -290,15 +281,9 @@ public:
rel_qpts_order(-1),
solver_type(NewtonElementProject),
max_iter(16),
#ifdef MFEM_USE_DOUBLE
ref_tol(1e-15),
phys_rtol(1e-15),
ip_tol(1e-8),
#elif defined(MFEM_USE_SINGLE)
ref_tol(1e-7),
phys_rtol(1e-7),
ip_tol(1e-4),
#endif
print_level(-1)
{ }
@@ -464,7 +449,7 @@ public:
returned. This method is not 100 percent reliable for non-linear
transformations. */
virtual int TransformBack(const Vector & v, IntegrationPoint & ip,
const real_t phys_rel_tol = tol_0)
const real_t phys_rel_tol = 1e-15)
{
InverseElementTransformation inv_tr(this);
inv_tr.SetPhysicalRelTol(phys_rel_tol);
+8 -8
View File
@@ -221,7 +221,7 @@ void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans,
{
for (int nd = 0; nd < dof; nd++)
{
Laplacian[nd] = hess(nd,0) + hess(nd,3) + hess(nd,5);
Laplacian[nd] = hess(nd,0) + hess(nd,4) + hess(nd,5);
}
}
else if (dim == 2)
@@ -259,10 +259,10 @@ void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans,
scale[1] = 2*Gij(0,1);
scale[2] = 2*Gij(0,2);
scale[3] = Gij(1,1);
scale[4] = 2*Gij(1,2);
scale[3] = 2*Gij(1,2);
scale[4] = Gij(2,2);
scale[5] = Gij(2,2);
scale[5] = Gij(1,1);
}
else if (dim == 2)
{
@@ -299,12 +299,12 @@ void FiniteElement::CalcPhysHessian(ElementTransformation &Trans,
map[2] = 2;
map[3] = 1;
map[4] = 3;
map[5] = 4;
map[4] = 5;
map[5] = 3;
map[6] = 2;
map[7] = 4;
map[8] = 5;
map[7] = 3;
map[8] = 4;
}
else if (dim == 2)
{
+27 -29
View File
@@ -299,8 +299,7 @@ public:
NONE, ///< No derivatives implemented
GRAD, ///< Implements CalcDShape methods
DIV, ///< Implements CalcDivShape methods
CURL, ///< Implements CalcCurlShape methods
HESS ///< Implements CalcHessian & CalcDShape methods
CURL ///< Implements CalcCurlShape methods
};
/** @brief Construct FiniteElement with given
@@ -357,7 +356,7 @@ public:
/** @brief Returns the FiniteElement::DerivType of the element describing the
spatial derivative method implemented, one of {NONE, GRAD,
DIV, CURL, HESS}. */
DIV, CURL}. */
int GetDerivType() const { return deriv_type; }
/** @brief Returns the FiniteElement::DerivType of the element describing how
@@ -395,32 +394,7 @@ public:
/// Get a const reference to the nodes of the element
const IntegrationRule & GetNodes() const { return Nodes; }
/** @brief Evaluate the Hessians of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
part of the Hessian of one shape function.
The order in 2D is {u_xx, u_xy, u_yy}.
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
element in physical space at the given point @a ip. */
/** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
void CalcPhysHessian(ElementTransformation &Trans,
DenseMatrix& Hessian) const;
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
element in physical space at the given point @a ip. */
/** The size (#dof) of @a Laplacian must be set in advance. */
void CalcPhysLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
element in physical space at the given point @a ip. */
/** The size (#dof) of @a Laplacian must be set in advance. */
void CalcPhysLinLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
// virtual functions for finite elements on vector spaces
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in reference space at the given point @a ip. */
@@ -480,6 +454,30 @@ public:
*/
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
/** @brief Evaluate the Hessians of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
part of the Hessian of one shape function.
The order in 2D is {u_xx, u_xy, u_yy}.
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
virtual void CalcHessian(const IntegrationPoint &ip,
DenseMatrix &Hessian) const;
/** @brief Evaluate the Hessian of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** The size (#dof, #dim*(#dim+1)/2) of @a Hessian must be set in advance. */
virtual void CalcPhysHessian(ElementTransformation &Trans,
DenseMatrix& Hessian) const;
/** @brief Evaluate the Laplacian of all shape functions of a scalar finite
element in reference space at the given point @a ip. */
/** The size (#dof) of @a Laplacian must be set in advance. */
virtual void CalcPhysLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
virtual void CalcPhysLinLaplacian(ElementTransformation &Trans,
Vector& Laplacian) const;
/** @brief Return the local interpolation matrix @a I (Dof x Dof) where the
fine element is the image of the base geometry under the given
transformation. */
+11 -624
View File
@@ -349,10 +349,10 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip,
d2sum[1] += ( hessian(o,1) = dsx*dsy*sz*weights(o) );
d2sum[2] += ( hessian(o,2) = dsx*sy*dsz*weights(o) );
d2sum[3] += ( hessian(o,3) = sx*d2sy*sz*weights(o) );
d2sum[4] += ( hessian(o,4) = sx*dsy*dsz*weights(o) );
d2sum[3] += ( hessian(o,3) = sx*dsy*dsz*weights(o) );
d2sum[5] += ( hessian(o,5) = sx*sy*d2sz*weights(o) );
d2sum[4] += ( hessian(o,4) = sx*sy*d2sz*weights(o) );
d2sum[5] += ( hessian(o,5) = sx*d2sy*sz*weights(o) );
}
}
}
@@ -387,632 +387,19 @@ void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip,
+ u[o]*sum*(2*dsum[0]*dsum[2] - d2sum[2]);
hessian(o,3) = hessian(o,3)*sum
- 2*du(o,1)*sum*dsum[1]
+ u[o]*sum*(2*dsum[1]*dsum[1] - d2sum[3]);
hessian(o,4) = hessian(o,4)*sum
- du(o,1)*sum*dsum[2]
- du(o,2)*sum*dsum[1]
+ u[o]*sum*(2*dsum[1]*dsum[2] - d2sum[4]);
+ u[o]*sum*(2*dsum[1]*dsum[2] - d2sum[3]);
hessian(o,4) = hessian(o,4)*sum
- 2*du(o,2)*sum*dsum[2]
+ u[o]*sum*(2*dsum[2]*dsum[2] - d2sum[4]);
hessian(o,5) = hessian(o,5)*sum
- 2*du(o,2)*sum*dsum[2]
+ u[o]*sum*(2*dsum[2]*dsum[2] - d2sum[5]);
- 2*du(o,1)*sum*dsum[1]
+ u[o]*sum*(2*dsum[1]*dsum[1] - d2sum[5]);
}
}
void NURBS_HDiv2DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
order = max(orders[0]+1, orders[1]+1);
dof = (orders[0] + 2)*(orders[1] + 1)
+ (orders[1] + 1)*(orders[1] + 2);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HDiv2DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,0) = shape1_x(i)*sy;
shape(o,1) = 0.0;
}
}
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1 = shape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,0) = 0.0;
shape(o,1) = shape_x(i)*sy1;
}
}
}
void NURBS_HDiv2DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & J = Trans.Jacobian();
MFEM_ASSERT(J.Width() == 2 && J.Height() == 2,
"NURBS_HDiv2DFiniteElement cannot be embedded in "
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
shape(i, 0) = sx * J(0, 0) + sy * J(0, 1);
shape(i, 1) = sx * J(1, 0) + sy * J(1, 1);
}
shape *= (1.0 / Trans.Weight());
}
void NURBS_HDiv2DFiniteElement::CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
divshape(o) = dshape1_x(i)*sy;
}
}
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t dsy1 = dshape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
divshape(o) = shape_x(i)*dsy1;
}
}
}
NURBS_HDiv2DFiniteElement::~NURBS_HDiv2DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
}
void NURBS_HDiv3DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
orders[2] = kv[2]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
kv1[2] = kv[2]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
shape_z.SetSize(orders[2]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
dshape_z.SetSize(orders[2]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
d2shape_z.SetSize(orders[2]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
shape1_z.SetSize(orders[2]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
dshape1_z.SetSize(orders[2]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
d2shape1_z.SetSize(orders[2]+2);
order = max(orders[0]+1, max( orders[1]+1, orders[2]+1));
dof = (orders[0] + 2)*(orders[1] + 1)*(orders[2] + 1) +
(orders[0] + 1)*(orders[1] + 2)*(orders[2] + 1) +
(orders[0] + 1)*(orders[1] + 1)*(orders[2] + 2);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HDiv3DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv[2]->CalcShape(shape_z, ijk[2], ip.z);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
shape = 0.0;
int o = 0;
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz = shape_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,0) = shape1_x(i)*sy_sz;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz = shape1_y(j)*sz;
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,1) = shape_x(i)*sy1_sz;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz1 = shape_y(j)*sz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,2) = shape_x(i)*sy_sz1;
}
}
}
}
void NURBS_HDiv3DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & J = Trans.Jacobian();
MFEM_ASSERT(J.Width() == 3 && J.Height() == 3,
"RT_R2D_FiniteElement cannot be embedded in "
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
real_t sz = shape(i, 2);
shape(i, 0) = sx * J(0, 0) + sy * J(0, 1) + sz * J(0, 2);
shape(i, 1) = sx * J(1, 0) + sy * J(1, 1) + sz * J(1, 2);
shape(i, 2) = sx * J(2, 0) + sy * J(2, 1) + sz * J(2, 2);
}
shape *= (1.0 / Trans.Weight());
}
void NURBS_HDiv3DFiniteElement::CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv[2]->CalcShape ( shape_z, ijk[2], ip.z);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
kv1[2]->CalcDShape(dshape1_z, ijk[2], ip.z);
int o = 0;
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz = shape_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
divshape(o) = dshape1_x(i)*sy_sz;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t dy1_sz = dshape1_y(j)*sz;
for (int i = 0; i <= orders[0]; i++, o++)
{
divshape(o) = shape_x(i)*dy1_sz;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t dz1 = dshape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_dz1 = shape_y(j)*dz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
divshape(o) = shape_x(i)*sy_dz1;
}
}
}
}
NURBS_HDiv3DFiniteElement::~NURBS_HDiv3DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
}
void NURBS_HCurl2DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
order = max(orders[0]+1, orders[1]+1);
dof = (orders[0] + 1)*(orders[1] + 2)
+ (orders[1] + 2)*(orders[1] + 1);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HCurl2DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1 = shape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,0) = shape_x(i)*sy1;
shape(o,1) = 0.0;
}
}
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,0) = 0.0;
shape(o,1) = shape1_x(i)*sy;
}
}
}
void NURBS_HCurl2DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & JI = Trans.InverseJacobian();
MFEM_ASSERT(JI.Width() == 2 && JI.Height() == 2,
"NURBS_HCurl2DFiniteElement cannot be embedded in "
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
shape(i, 0) = sx * JI(0, 0) + sy * JI(1, 0);
shape(i, 1) = sx * JI(0, 1) + sy * JI(1, 1);
}
}
void NURBS_HCurl2DFiniteElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
int o = 0;
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t dsy1 = dshape1_y(j);
for (int i = 0; i <= orders[0]; i++, o++)
{
curl_shape(o,0) = -shape_x(i)*dsy1;
}
}
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy = shape_y(j);
for (int i = 0; i <= orders[0]+1; i++, o++)
{
curl_shape(o,0) = dshape1_x(i)*sy;
}
}
}
NURBS_HCurl2DFiniteElement::~NURBS_HCurl2DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
}
void NURBS_HCurl3DFiniteElement::SetOrder() const
{
orders[0] = kv[0]->GetOrder();
orders[1] = kv[1]->GetOrder();
orders[2] = kv[2]->GetOrder();
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
kv1[0] = kv[0]->DegreeElevate(1);
kv1[1] = kv[1]->DegreeElevate(1);
kv1[2] = kv[2]->DegreeElevate(1);
shape_x.SetSize(orders[0]+1);
shape_y.SetSize(orders[1]+1);
shape_z.SetSize(orders[2]+1);
dshape_x.SetSize(orders[0]+1);
dshape_y.SetSize(orders[1]+1);
dshape_z.SetSize(orders[2]+1);
d2shape_x.SetSize(orders[0]+1);
d2shape_y.SetSize(orders[1]+1);
d2shape_z.SetSize(orders[2]+1);
shape1_x.SetSize(orders[0]+2);
shape1_y.SetSize(orders[1]+2);
shape1_z.SetSize(orders[2]+2);
dshape1_x.SetSize(orders[0]+2);
dshape1_y.SetSize(orders[1]+2);
dshape1_z.SetSize(orders[2]+2);
d2shape1_x.SetSize(orders[0]+2);
d2shape1_y.SetSize(orders[1]+2);
d2shape1_z.SetSize(orders[2]+2);
order = max(orders[0]+1, max( orders[1]+1, orders[2]+1));
dof = (orders[0] + 1)*(orders[1] + 2)*(orders[2] + 2) +
(orders[0] + 2)*(orders[1] + 1)*(orders[2] + 2) +
(orders[0] + 2)*(orders[1] + 2)*(orders[2] + 1);
u.SetSize(dof);
du.SetSize(dof);
weights.SetSize(dof);
}
void NURBS_HCurl3DFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
kv[0]->CalcShape(shape_x, ijk[0], ip.x);
kv[1]->CalcShape(shape_y, ijk[1], ip.y);
kv[2]->CalcShape(shape_z, ijk[2], ip.z);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
shape = 0.0;
int o = 0;
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz1 = shape1_y(j)*sz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
shape(o,0) = shape_x(i)*sy1_sz1;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_sz1 = shape_y(j)*sz1;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,1) = shape1_x(i)*sy_sz1;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz = shape1_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
shape(o,2) = shape1_x(i)*sy1_sz;
}
}
}
}
void NURBS_HCurl3DFiniteElement::CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const
{
CalcVShape(Trans.GetIntPoint(), shape);
const DenseMatrix & JI = Trans.InverseJacobian();
MFEM_ASSERT(JI.Width() == 3 && JI.Height() == 3,
"NURBS_HCurl3DFiniteElement must be in a"
"3 dimensional spaces");
for (int i=0; i<dof; i++)
{
real_t sx = shape(i, 0);
real_t sy = shape(i, 1);
real_t sz = shape(i, 2);
shape(i, 0) = sx * JI(0, 0) + sy * JI(1, 0) + sz * JI(2, 0);
shape(i, 1) = sx * JI(0, 1) + sy * JI(1, 1) + sz * JI(2, 1);
shape(i, 2) = sx * JI(0, 2) + sy * JI(1, 2) + sz * JI(2, 2);
}
}
void NURBS_HCurl3DFiniteElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const
{
kv[0]->CalcShape ( shape_x, ijk[0], ip.x);
kv[1]->CalcShape ( shape_y, ijk[1], ip.y);
kv[2]->CalcShape ( shape_z, ijk[2], ip.z);
kv1[0]->CalcShape(shape1_x, ijk[0], ip.x);
kv1[1]->CalcShape(shape1_y, ijk[1], ip.y);
kv1[2]->CalcShape(shape1_z, ijk[2], ip.z);
kv1[0]->CalcDShape(dshape1_x, ijk[0], ip.x);
kv1[1]->CalcDShape(dshape1_y, ijk[1], ip.y);
kv1[2]->CalcDShape(dshape1_z, ijk[2], ip.z);
int o = 0;
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k), dsz1 = dshape1_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_dsz1 = shape1_y(j)*dsz1,
dsy1_sz1 = dshape1_y(j)*sz1;
for (int i = 0; i <= orders[0]; i++, o++)
{
curl_shape(o,0) = 0.0;
curl_shape(o,1) = shape_x(i)*sy1_dsz1;
curl_shape(o,2) = -shape_x(i)*dsy1_sz1;
}
}
}
for (int k = 0; k <= orders[2]+1; k++)
{
const real_t sz1 = shape1_z(k), dsz1 = dshape1_z(k);
for (int j = 0; j <= orders[1]; j++)
{
const real_t sy_dsz1 = shape_y(j)*dsz1,
sy_sz1 = shape_y(j)*sz1;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
curl_shape(o,0) = -shape1_x(i)*sy_dsz1;
curl_shape(o,1) = 0.0;
curl_shape(o,2) = dshape1_x(i)*sy_sz1;
}
}
}
for (int k = 0; k <= orders[2]; k++)
{
const real_t sz = shape_z(k);
for (int j = 0; j <= orders[1]+1; j++)
{
const real_t sy1_sz = shape1_y(j)*sz,
dsy1_sz = dshape1_y(j)*sz;
for (int i = 0; i <= orders[0]+1; i++, o++)
{
curl_shape(o,0) = shape1_x(i)*dsy1_sz;
curl_shape(o,1) = -dshape1_x(i)*sy1_sz;
curl_shape(o,2) = 0.0;
}
}
}
}
NURBS_HCurl3DFiniteElement::~NURBS_HCurl3DFiniteElement()
{
if (kv1[0]) { delete kv1[0]; }
if (kv1[1]) { delete kv1[1]; }
if (kv1[2]) { delete kv1[2]; }
}
}
+23 -380
View File
@@ -20,7 +20,7 @@ namespace mfem
class KnotVector;
/// An arbitrary order and dimension NURBS element
class NURBSFiniteElement
class NURBSFiniteElement : public ScalarFiniteElement
{
protected:
mutable Array <const KnotVector*> kv;
@@ -30,34 +30,31 @@ protected:
public:
/** @brief Construct NURBSFiniteElement with given
@param dim Reference space dimension
@param D Reference space dimension
@param G Geometry type (of type Geometry::Type)
@param Do Number of degrees of freedom in the FiniteElement
@param O Order/degree of the FiniteElement
@param F FunctionSpace type of the FiniteElement
*/
NURBSFiniteElement(int dim)
NURBSFiniteElement(int D, Geometry::Type G, int Do, int O, int F)
: ScalarFiniteElement(D, G, Do, O, F)
{
ijk = NULL;
patch = elem = -1;
kv.SetSize(dim);
weights.SetSize(dof);
weights = 1.0;
}
/// Resets the patch and element data stored in the element
void Reset () const { patch = elem = -1; }
/// Set which IJK in patch should be evaluated
void SetIJK (const int *IJK) const { ijk = IJK; }
/// Get which patch is currently considered
int GetPatch () const { return patch; }
/// Set which patch should be evaluated
void SetPatch (int p) const { patch = p; }
/// Set which elemenet should be evaluated
int GetElement () const { return elem; }
/// Get which element is currently considered
void SetElement (int e) const { elem = e; }
/// Get the KnotVectors
Array <const KnotVector*> &KnotVectors() const { return kv; }
/// Get the Weights
Vector &Weights () const { return weights; }
/// Update the polynomial order according to the currently set knotvectors
/// Resizes all internal data members to have the correct size
/// related to the polynomial order
/// Update the NURBSFiniteElement according to the currently set knot vectors
virtual void SetOrder () const { }
/// Returns the indices (i,j) in 2D or (i,j,k) in 3D of this element in the
@@ -67,8 +64,7 @@ public:
/// An arbitrary order 1D NURBS element on a segment
class NURBS1DFiniteElement : public ScalarFiniteElement,
public NURBSFiniteElement
class NURBS1DFiniteElement : public NURBSFiniteElement
{
protected:
mutable Vector shape_x;
@@ -76,8 +72,7 @@ protected:
public:
/// Construct the NURBS1DFiniteElement of order @a p
NURBS1DFiniteElement(int p)
: ScalarFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk),
NURBSFiniteElement(1),
: NURBSFiniteElement(1, Geometry::SEGMENT, p + 1, p, FunctionSpace::Qk),
shape_x(p + 1) { }
virtual void SetOrder() const;
@@ -89,8 +84,7 @@ public:
};
/// An arbitrary order 2D NURBS element on a square
class NURBS2DFiniteElement : public ScalarFiniteElement,
public NURBSFiniteElement
class NURBS2DFiniteElement : public NURBSFiniteElement
{
protected:
mutable Vector u, shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
@@ -99,18 +93,16 @@ protected:
public:
/// Construct the NURBS2DFiniteElement of order @a p
NURBS2DFiniteElement(int p)
: ScalarFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p,
FunctionSpace::Qk),
NURBSFiniteElement(2),
: NURBSFiniteElement(2, Geometry::SQUARE, (p + 1)*(p + 1), p,
FunctionSpace::Qk),
u(dof), shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1), du(dof,2)
{ orders[0] = orders[1] = p; }
/// Construct the NURBS2DFiniteElement with x-order @a px and y-order @a py
NURBS2DFiniteElement(int px, int py)
: ScalarFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1),
std::max(px, py), FunctionSpace::Qk),
NURBSFiniteElement(2),
: NURBSFiniteElement(2, Geometry::SQUARE, (px + 1)*(py + 1),
std::max(px, py), FunctionSpace::Qk),
u(dof), shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1), du(dof,2)
{ orders[0] = px; orders[1] = py; }
@@ -124,8 +116,7 @@ public:
};
/// An arbitrary order 3D NURBS element on a cube
class NURBS3DFiniteElement : public ScalarFiniteElement,
public NURBSFiniteElement
class NURBS3DFiniteElement : public NURBSFiniteElement
{
protected:
mutable Vector u, shape_x, shape_y, shape_z;
@@ -136,9 +127,8 @@ protected:
public:
/// Construct the NURBS3DFiniteElement of order @a p
NURBS3DFiniteElement(int p)
: ScalarFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p,
FunctionSpace::Qk),
NURBSFiniteElement(3),
: NURBSFiniteElement(3, Geometry::CUBE, (p + 1)*(p + 1)*(p + 1), p,
FunctionSpace::Qk),
u(dof), shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1), du(dof,3)
@@ -147,9 +137,8 @@ public:
/// Construct the NURBS3DFiniteElement with x-order @a px and y-order @a py
/// and z-order @a pz
NURBS3DFiniteElement(int px, int py, int pz)
: ScalarFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1),
std::max(std::max(px,py),pz), FunctionSpace::Qk),
NURBSFiniteElement(2),
: NURBSFiniteElement(3, Geometry::CUBE, (px + 1)*(py + 1)*(pz + 1),
std::max(std::max(px,py),pz), FunctionSpace::Qk),
u(dof), shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1), du(dof,3)
@@ -163,352 +152,6 @@ public:
DenseMatrix &hessian) const;
};
/** An arbitrary order H(div)-conforming 2D NURBS element on a square.
More details in the following papers:
[1] Annalisa Buffa, Carlo De Falco, Giancarlo Sangalli
"Isogeometric analysis: stable elements for the 2D Stokes equation."
International Journal for Numerical Methods in Fluids 65 (1112) 1407-1422
[2] John A Evans, Thomas JR Hughes
"Isogeometric divergence-conforming B-splines for the unsteady NavierStokes equations."
Journal of Computational Physics (241) 141-167
*/
class NURBS_HDiv2DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
mutable Vector shape1_x, shape1_y, dshape1_x, dshape1_y, d2shape1_x, d2shape1_y;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HDiv2DFiniteElement of order @a p
NURBS_HDiv2DFiniteElement(int p)
: VectorFiniteElement(2, Geometry::SQUARE, 2*(p + 1)*(p + 2), p,
H_DIV,FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1),
shape1_x(p + 2), shape1_y(p + 2), dshape1_x(p + 2),
dshape1_y(p + 2), d2shape1_x(p + 2), d2shape1_y(p + 2),
u(dof), du(dof,2)
{
orders[0] = orders[1] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
/// Construct the NURBS_HDiv2DFiniteElement with x-order @a px and y-order @a py
NURBS_HDiv2DFiniteElement(int px, int py)
: VectorFiniteElement(2, Geometry::SQUARE,
(px + 2)*(py + 1)+(px + 1)*(py + 2),
std::max(px, py), H_DIV, FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1),
shape1_x(px + 2), shape1_y(py + 2), dshape1_x(px + 2),
dshape1_y(py + 2), d2shape1_x(px + 2), d2shape1_y(py + 2),
u(dof), du(dof,2)
{
orders[0] = px; orders[1] = py;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the divergence of all shape functions of a *vector*
finite element in reference space at the given point @a ip. */
/** The size (#dof) of the result Vector @a divshape must be set in advance.
*/
virtual void CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const;
~NURBS_HDiv2DFiniteElement();
};
/** An arbitrary order H(div)-conforming 3D NURBS element on a cube
More details in the following papers:
[1] Annalisa Buffa, Carlo De Falco, Giancarlo Sangalli
"Isogeometric analysis: stable elements for the 2D Stokes equation."
International Journal for Numerical Methods in Fluids 65 (1112) 1407-1422
[2] John A Evans, Thomas JR Hughes
"Isogeometric divergence-conforming B-splines for the unsteady
NavierStokes equations."
Journal of Computational Physics (241) 141-167 */
class NURBS_HDiv3DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, shape_z;
mutable Vector dshape_x, dshape_y, dshape_z;
mutable Vector d2shape_x, d2shape_y, d2shape_z;
mutable Vector shape1_x, shape1_y, shape1_z;
mutable Vector dshape1_x, dshape1_y, dshape1_z;
mutable Vector d2shape1_x, d2shape1_y, d2shape1_z;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HDiv3DFiniteElement of order @a p
NURBS_HDiv3DFiniteElement(int p)
: VectorFiniteElement(3, Geometry::CUBE, 3*(p + 1)*(p + 1)*(p + 2),
p, H_DIV,FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1),
shape1_x(p + 2), shape1_y(p + 2), shape1_z(p + 2),
dshape1_x(p + 2), dshape1_y(p + 2),dshape1_z(p + 2),
d2shape1_x(p + 2), d2shape1_y(p + 2), d2shape1_z(p + 2),
u(dof), du(dof,3)
{
orders[0] = orders[1] = orders[2] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
/// Construct the NURBS_HDiv3DFiniteElement with x-order @a px, y-order @a py and z-order @a pz
NURBS_HDiv3DFiniteElement(int px, int py, int pz)
: VectorFiniteElement(3, Geometry::CUBE,
(px + 2)*(py + 1)*(pz + 1) +
(px + 1)*(py + 2)*(pz + 1) +
(px + 1)*(py + 1)*(pz + 2),
std::max(px, py), H_DIV, FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1),
shape1_x(px + 2), shape1_y(py + 2), shape1_z(pz + 2),
dshape1_x(px + 2), dshape1_y(py + 2),dshape1_z(pz + 2),
d2shape1_x(px + 2), d2shape1_y(py + 2), d2shape1_z(pz + 2),
u(dof), du(dof,3)
{
orders[0] = px; orders[1] = py; orders[2] = pz;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the divergence of all shape functions of a *vector*
finite element in reference space at the given point @a ip. */
/** The size (#dof) of the result Vector @a divshape must be set in advance.
*/
virtual void CalcDivShape(const IntegrationPoint &ip,
Vector &divshape) const;
~NURBS_HDiv3DFiniteElement();
};
/** An arbitrary order H(curl)-conforming 2D NURBS element on a square
More details in the following paper:
[1] Annalisa Buffa, Giancarlo Sangalli, Rafael Vázquez
"Isogeometric analysis in electromagnetics: B-splines approximation."
Computer Methods in Applied Mechanics and Engineering (199) 1143-1152 */
class NURBS_HCurl2DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
mutable Vector shape1_x, shape1_y, dshape1_x, dshape1_y, d2shape1_x, d2shape1_y;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HCurl2DFiniteElement of order @a p
NURBS_HCurl2DFiniteElement(int p)
: VectorFiniteElement(2, Geometry::SQUARE, 2*(p + 1)*(p + 2), p,
H_CURL,FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1),
shape1_x(p + 2), shape1_y(p + 2), dshape1_x(p + 2),
dshape1_y(p + 2), d2shape1_x(p + 2), d2shape1_y(p + 2),
u(dof), du(dof,2)
{
orders[0] = orders[1] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
/// Construct the NURBS_HCurl2DFiniteElement with x-order @a px and y-order @a py
NURBS_HCurl2DFiniteElement(int px, int py)
: VectorFiniteElement(2, Geometry::SQUARE,
(px + 1)*(py + 2)+(px + 2)*(py + 1),
std::max(px, py), H_CURL, FunctionSpace::Qk),
NURBSFiniteElement(2),
shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1),
shape1_x(px + 2), shape1_y(py + 2), dshape1_x(px + 2),
dshape1_y(py + 2), d2shape1_x(px + 2), d2shape1_y(py + 2),
u(dof), du(dof,2)
{
orders[0] = px; orders[1] = py;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the curl of all shape functions of a *vector* finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a curl_shape contains the components
of the curl of one vector shape function. The size (#dof x CDim) of
@a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
CDim = 1 for #dim = 2. */
virtual void CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const;
~NURBS_HCurl2DFiniteElement();
};
/** An arbitrary order H(curl)-conforming 3D NURBS element on a cube
More details in the following paper:
[1] Annalisa Buffa, Giancarlo Sangalli, Rafael Vázquez
"Isogeometric analysis in electromagnetics: B-splines approximation."
Computer Methods in Applied Mechanics and Engineering (199) 1143-1152 */
class NURBS_HCurl3DFiniteElement : public VectorFiniteElement,
public NURBSFiniteElement
{
protected:
mutable Vector shape_x, shape_y, shape_z;
mutable Vector dshape_x, dshape_y, dshape_z;
mutable Vector d2shape_x, d2shape_y, d2shape_z;
mutable Vector shape1_x, shape1_y, shape1_z;
mutable Vector dshape1_x, dshape1_y, dshape1_z;
mutable Vector d2shape1_x, d2shape1_y, d2shape1_z;
mutable Vector u;
mutable DenseMatrix du;
mutable Array <const KnotVector*> kv1;
public:
/// Construct the NURBS_HCurl3DFiniteElement of order @a p
NURBS_HCurl3DFiniteElement(int p)
: VectorFiniteElement(3, Geometry::CUBE, 3*(p + 1)*(p + 2)*(p + 2), p,
H_CURL,FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1),
shape1_x(p + 2), shape1_y(p + 2), shape1_z(p + 2),
dshape1_x(p + 2), dshape1_y(p + 2),dshape1_z(p + 2),
d2shape1_x(p + 2), d2shape1_y(p + 2), d2shape1_z(p + 2),
u(dof), du(dof,3)
{
orders[0] = orders[1] = orders[2] = p;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
/// Construct the NURBS_HCurl3DFiniteElement with x-order @a px, y-order @a py and z-order @a pz
NURBS_HCurl3DFiniteElement(int px, int py, int pz)
: VectorFiniteElement(3, Geometry::CUBE,
(px + 1)*(py + 2)*(pz + 2) +
(px + 2)*(py + 1)*(pz + 2) +
(px + 2)*(py + 2)*(pz + 1),
std::max(std::max(px, py), pz), H_CURL, FunctionSpace::Qk),
NURBSFiniteElement(3),
shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1),
shape1_x(px + 2), shape1_y(py + 2), shape1_z(pz + 2),
dshape1_x(px + 2), dshape1_y(py + 2),dshape1_z(pz + 2),
d2shape1_x(px + 2), d2shape1_y(py + 2), d2shape1_z(pz + 2),
u(dof), du(dof,3)
{
orders[0] = px; orders[1] = py; orders[2] = pz;
kv1.SetSize(dim);
kv1[0] = nullptr;
kv1[1] = nullptr;
kv1[2] = nullptr;
}
virtual void SetOrder() const;
virtual void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
/** @brief Evaluate the values of all shape functions of a *vector* finite
element in physical space at the point described by @a Trans. */
/** Each row of the result DenseMatrix @a shape contains the components of
one vector shape function. The size (#dof x SDim) of @a shape must be set
in advance, where SDim >= #dim is the physical space dimension as
described by @a Trans. */
virtual void CalcVShape(ElementTransformation &Trans,
DenseMatrix &shape) const;
/** @brief Evaluate the curl of all shape functions of a *vector* finite
element in reference space at the given point @a ip. */
/** Each row of the result DenseMatrix @a curl_shape contains the components
of the curl of one vector shape function. The size (#dof x CDim) of
@a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
CDim = 1 for #dim = 2. */
virtual void CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const;
~NURBS_HCurl3DFiniteElement();
};
} // namespace mfem
#endif
-214
View File
@@ -344,32 +344,6 @@ FiniteElementCollection *FiniteElementCollection::New(const char *name)
{
fec = new Local_FECollection(name + 6);
}
else if (!strncmp(name, "NURBS_HDiv", 10))
{
if (name[10] != '\0')
{
// "NURBS" + "number" --> fixed order nurbs collection
fec = new NURBS_HDivFECollection(atoi(name + 10));
}
else
{
// "NURBS" --> variable order nurbs collection
fec = new NURBS_HDivFECollection();
}
}
else if (!strncmp(name, "NURBS_HCurl", 11))
{
if (name[11] != '\0')
{
// "NURBS" + "number" --> fixed order nurbs collection
fec = new NURBS_HCurlFECollection(atoi(name + 11));
}
else
{
// "NURBS" --> variable order nurbs collection
fec = new NURBS_HCurlFECollection();
}
}
else if (!strncmp(name, "NURBS", 5))
{
if (name[5] != '\0')
@@ -3559,192 +3533,4 @@ FiniteElementCollection *NURBSFECollection::GetTraceCollection() const
return NULL;
}
NURBS_HDivFECollection::NURBS_HDivFECollection(int Order, const int dim)
: NURBSFECollection((Order == VariableOrder) ? 1 : Order)
{
const int order = (Order == VariableOrder) ? 1 : Order;
SegmentFE = new NURBS1DFiniteElement(order);
QuadrilateralFE = new NURBS2DFiniteElement(order);
QuadrilateralVFE = new NURBS_HDiv2DFiniteElement(order);
ParallelepipedVFE = new NURBS_HDiv3DFiniteElement(order);
if (dim != -1) { SetDim(dim); }
SetOrder(Order);
}
void NURBS_HDivFECollection::SetDim(int dim)
{
if (dim == 2)
{
sFE = SegmentFE;
qFE = QuadrilateralVFE;
hFE = nullptr;
}
else if (dim == 3)
{
sFE = nullptr;
qFE = QuadrilateralFE;
hFE = ParallelepipedVFE;
}
else
{
mfem::err<<"Dimension = "<<dim<<endl;
mfem_error ("NURBS_HDivFECollection: wrong dimension!");
}
}
NURBS_HDivFECollection::~NURBS_HDivFECollection()
{
delete SegmentFE;
delete QuadrilateralFE;
delete QuadrilateralVFE;
delete ParallelepipedVFE;
}
const FiniteElement *
NURBS_HDivFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
switch (GeomType)
{
case Geometry::SEGMENT: return sFE;
case Geometry::SQUARE: return qFE;
case Geometry::CUBE: return hFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("NURBS_HDivFECollection: unknown geometry type.");
}
return QuadrilateralFE; // Make some compilers happy
}
void NURBS_HDivFECollection::SetOrder(int Order) const
{
mOrder = Order;
if (Order != VariableOrder)
{
snprintf(name, 16, "NURBS_HDiv%i", Order);
}
else
{
snprintf(name, 16, "NURBS_HDiv");
}
}
int NURBS_HDivFECollection::DofForGeometry(Geometry::Type GeomType) const
{
mfem_error("NURBS_HDivFECollection::DofForGeometry");
return 0; // Make some compilers happy
}
const int *NURBS_HDivFECollection::DofOrderForOrientation(
Geometry::Type GeomType,
int Or) const
{
mfem_error("NURBS_HDivFECollection::DofOrderForOrientation");
return NULL;
}
FiniteElementCollection *NURBS_HDivFECollection::GetTraceCollection() const
{
MFEM_ABORT("NURBS finite elements can not be statically condensed!");
return NULL;
}
NURBS_HCurlFECollection::NURBS_HCurlFECollection(int Order, const int dim)
: NURBSFECollection((Order == VariableOrder) ? 1 : Order)
{
const int order = (Order == VariableOrder) ? 1 : Order;
SegmentFE = new NURBS1DFiniteElement(order+1);
QuadrilateralFE = new NURBS2DFiniteElement(order+1);
QuadrilateralVFE = new NURBS_HCurl2DFiniteElement(order);
ParallelepipedVFE = new NURBS_HCurl3DFiniteElement(order);
if (dim != -1) { SetDim(dim); }
SetOrder(Order);
}
void NURBS_HCurlFECollection::SetDim(int dim)
{
if (dim == 2)
{
sFE = SegmentFE;
qFE = QuadrilateralVFE;
hFE = nullptr;
}
else if (dim == 3)
{
sFE = nullptr;
qFE = QuadrilateralFE;
hFE = ParallelepipedVFE;
}
else
{
mfem::err<<"Dimension = "<<dim<<endl;
mfem_error ("NURBS_HCurlFECollection: wrong dimension!");
}
}
NURBS_HCurlFECollection::~NURBS_HCurlFECollection()
{
delete SegmentFE;
delete QuadrilateralFE;
delete QuadrilateralVFE;
delete ParallelepipedVFE;
}
const FiniteElement *
NURBS_HCurlFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
switch (GeomType)
{
case Geometry::SEGMENT: return sFE;
case Geometry::SQUARE: return qFE;
case Geometry::CUBE: return hFE;
default:
if (error_mode == RETURN_NULL) { return nullptr; }
mfem_error ("NURBS_HCurlFECollection: unknown geometry type.");
}
return QuadrilateralFE; // Make some compilers happy
}
void NURBS_HCurlFECollection::SetOrder(int Order) const
{
mOrder = Order;
if (Order != VariableOrder)
{
snprintf(name, 16, "NURBS_HCurl%i", Order);
}
else
{
snprintf(name, 16, "NURBS_HCurl");
}
}
int NURBS_HCurlFECollection::DofForGeometry(Geometry::Type GeomType) const
{
mfem_error("NURBS_HCurlFECollection::DofForGeometry");
return 0; // Make some compilers happy
}
const int *NURBS_HCurlFECollection::DofOrderForOrientation(
Geometry::Type GeomType,
int Or) const
{
mfem_error("NURBS_HCurlFECollection::DofOrderForOrientation");
return NULL;
}
FiniteElementCollection *NURBS_HCurlFECollection::GetTraceCollection() const
{
MFEM_ABORT("NURBS finite elements can not be statically condensed!");
return NULL;
}
}
+4 -109
View File
@@ -680,8 +680,8 @@ public:
/// Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
class NURBSFECollection : public FiniteElementCollection
{
protected:
PointFiniteElement *PointFE;
private:
PointFiniteElement *PointFE;
NURBS1DFiniteElement *SegmentFE;
NURBS2DFiniteElement *QuadrilateralFE;
NURBS3DFiniteElement *ParallelepipedFE;
@@ -701,15 +701,13 @@ public:
order, or VariableOrder (default). */
explicit NURBSFECollection(int Order = VariableOrder);
virtual void Reset() const
void Reset() const
{
SegmentFE->Reset();
QuadrilateralFE->Reset();
ParallelepipedFE->Reset();
}
virtual void SetDim(const int dim) {};
/** @brief Get the order of the NURBS collection: either a positive number,
when using fixed order, or VariableOrder. */
/** @note Not to be confused with FiniteElementCollection::GetOrder(). */
@@ -717,7 +715,7 @@ public:
/** @brief Set the order and the name, based on the given @a Order: either a
positive number for fixed order, or VariableOrder. */
virtual void SetOrder(int Order) const;
void SetOrder(int Order) const;
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
@@ -736,109 +734,6 @@ public:
virtual ~NURBSFECollection();
};
/// Arbitrary order H(div) NURBS finite elements.
class NURBS_HDivFECollection : public NURBSFECollection
{
private:
NURBS1DFiniteElement *SegmentFE;
NURBS2DFiniteElement *QuadrilateralFE;
NURBS_HDiv2DFiniteElement *QuadrilateralVFE;
NURBS_HDiv3DFiniteElement *ParallelepipedVFE;
FiniteElement *sFE;
FiniteElement *qFE;
FiniteElement *hFE;
public:
/** @brief The parameter @a Order must be either a positive number, for fixed
order, or VariableOrder (default). */
explicit NURBS_HDivFECollection(int Order = VariableOrder, const int vdim = -1);
virtual void Reset() const override
{
SegmentFE->Reset();
QuadrilateralFE->Reset();
QuadrilateralVFE->Reset();
ParallelepipedVFE->Reset();
}
virtual void SetDim(const int dim) override;
/** @brief Set the order and the name, based on the given @a Order: either a
positive number for fixed order, or VariableOrder. */
virtual void SetOrder(int Order) const override;
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
int DofForGeometry(Geometry::Type GeomType) const override;
const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const override;
const char *Name() const override { return name; }
int GetContType() const override { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const override;
virtual ~NURBS_HDivFECollection();
};
/// Arbitrary order H(curl) NURBS finite elements.
class NURBS_HCurlFECollection : public NURBSFECollection
{
private:
NURBS1DFiniteElement *SegmentFE;
NURBS2DFiniteElement *QuadrilateralFE;
NURBS_HCurl2DFiniteElement *QuadrilateralVFE;
NURBS_HCurl3DFiniteElement *ParallelepipedVFE;
FiniteElement *sFE;
FiniteElement *qFE;
FiniteElement *hFE;
public:
/** @brief The parameter @a Order must be either a positive number, for fixed
order, or VariableOrder (default). */
explicit NURBS_HCurlFECollection(int Order = VariableOrder,
const int vdim = -1);
virtual void Reset() const override
{
SegmentFE->Reset();
QuadrilateralFE->Reset();
QuadrilateralVFE->Reset();
ParallelepipedVFE->Reset();
}
virtual void SetDim(const int dim) override;
/** @brief Set the order and the name, based on the given @a Order: either a
positive number for fixed order, or VariableOrder. */
virtual void SetOrder(int Order) const override;
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
int DofForGeometry(Geometry::Type GeomType) const override;
const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const override;
const char *Name() const override { return name; }
int GetContType() const override { return CONTINUOUS; }
FiniteElementCollection *GetTraceCollection() const override;
virtual ~NURBS_HCurlFECollection();
};
/// Piecewise-(bi/tri)linear continuous finite elements.
class LinearFECollection : public FiniteElementCollection
{
+37 -262
View File
@@ -1525,67 +1525,6 @@ SparseMatrix *FiniteElementSpace::RefinementMatrix_main(
return P;
}
SparseMatrix *FiniteElementSpace::VariableOrderRefinementMatrix(
const int coarse_ndofs, const Table &coarse_elem_dof) const
{
MFEM_VERIFY(mesh->GetLastOperation() == Mesh::REFINE, "");
Array<int> dofs, coarse_dofs, coarse_vdofs;
Vector row;
Mesh::GeometryList elem_geoms(*mesh);
SparseMatrix *P = new SparseMatrix(GetVSize(), coarse_ndofs*vdim);
Array<int> mark(P->Height());
mark = 0;
const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
DenseMatrix lP;
IsoparametricTransformation isotr;
for (int k = 0; k < mesh->GetNE(); k++)
{
const Embedding &emb = rtrans.embeddings[k];
const Geometry::Type geom = mesh->GetElementBaseGeometry(k);
const FiniteElement *fe = GetFE(k);
isotr.SetIdentityTransformation(geom);
const int ldof = fe->GetDof();
lP.SetSize(ldof, ldof);
const DenseTensor &pmats = rtrans.point_matrices[geom];
isotr.SetPointMat(pmats(emb.matrix));
fe->GetLocalInterpolation(isotr, lP);
const int fine_ldof = lP.Height();
elem_dof->GetRow(k, dofs);
coarse_elem_dof.GetRow(emb.parent, coarse_dofs);
for (int vd = 0; vd < vdim; vd++)
{
coarse_dofs.Copy(coarse_vdofs);
DofsToVDofs(vd, coarse_vdofs, coarse_ndofs);
for (int i = 0; i < fine_ldof; i++)
{
const int r = DofToVDof(dofs[i], vd);
int m = (r >= 0) ? r : (-1 - r);
if (!mark[m])
{
lP.GetRow(i, row);
P->SetRow(r, coarse_vdofs, row);
mark[m] = 1;
}
}
}
}
MFEM_VERIFY(mark.Sum() == P->Height(), "Not all rows of P set.");
P->Finalize();
return P;
}
void FiniteElementSpace::GetLocalRefinementMatrices(
Geometry::Type geom, DenseTensor &localP) const
{
@@ -1617,20 +1556,15 @@ SparseMatrix* FiniteElementSpace::RefinementMatrix(int old_ndofs,
"Previous mesh is not coarser.");
Mesh::GeometryList elem_geoms(*mesh);
if (!IsVariableOrder())
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
{
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
{
GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
localP);
}
else
{
return VariableOrderRefinementMatrix(old_ndofs, *old_elem_dof);
GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
localP);
}
FiniteElementSpace::RefinementOperator::RefinementOperator(
@@ -1648,12 +1582,9 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
if (!fespace->IsVariableOrder())
for (int i = 0; i < elem_geoms.Size(); i++)
{
for (int i = 0; i < elem_geoms.Size(); i++)
{
fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
}
ConstructDoFTransArray();
@@ -1666,13 +1597,10 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
{
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
if (!fespace->IsVariableOrder())
for (int i = 0; i < elem_geoms.Size(); i++)
{
for (int i = 0; i < elem_geoms.Size(); i++)
{
fespace->GetLocalRefinementMatrices(*coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
}
fespace->GetLocalRefinementMatrices(*coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
}
// Make a copy of the coarse elem_dof Table.
@@ -1748,25 +1676,11 @@ void FiniteElementSpace::RefinementOperator::Mult(const Vector &x,
Vector subY, subX;
DenseMatrix eP;
IsoparametricTransformation isotr;
for (int k = 0; k < mesh_ref->GetNE(); k++)
{
const Embedding &emb = trans_ref.embeddings[k];
const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
if (fespace->IsVariableOrder())
{
const FiniteElement *fe = fespace->GetFE(k);
isotr.SetIdentityTransformation(geom);
const int ldof = fe->GetDof();
eP.SetSize(ldof, ldof);
const DenseTensor &pmats = trans_ref.point_matrices[geom];
isotr.SetPointMat(pmats(emb.matrix));
fe->GetLocalInterpolation(isotr, eP);
}
const DenseMatrix &lP = (fespace->IsVariableOrder()) ? eP : localP[geom](
emb.matrix);
const DenseMatrix &lP = localP[geom](emb.matrix);
subY.SetSize(lP.Height());
@@ -1831,28 +1745,11 @@ void FiniteElementSpace::RefinementOperator::MultTranspose(const Vector &x,
Vector subY, subX, subYt;
DenseMatrix eP;
IsoparametricTransformation isotr;
const FiniteElement *fe = nullptr;
for (int k = 0; k < mesh_ref->GetNE(); k++)
{
const Embedding &emb = trans_ref.embeddings[k];
const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
if (fespace->IsVariableOrder())
{
fe = fespace->GetFE(k);
isotr.SetIdentityTransformation(geom);
const int ldof = fe->GetDof();
eP.SetSize(ldof);
const DenseTensor &pmats = trans_ref.point_matrices[geom];
isotr.SetPointMat(pmats(emb.matrix));
fe->GetLocalInterpolation(isotr, eP);
}
const DenseMatrix &lP = (fespace->IsVariableOrder()) ? eP : localP[geom](
emb.matrix);
const DenseMatrix &lP = localP[geom](emb.matrix);
DofTransformation *doftrans = fespace->GetElementDofs(k, f_dofs);
old_elem_dof->GetRow(emb.parent, c_dofs);
@@ -2211,12 +2108,9 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
Mesh::GeometryList elem_geoms(*mesh);
DenseTensor localR[Geometry::NumGeom];
if (!IsVariableOrder())
for (int i = 0; i < elem_geoms.Size(); i++)
{
for (int i = 0; i < elem_geoms.Size(); i++)
{
GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
}
GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
}
SparseMatrix *R = new SparseMatrix(ndofs*vdim, old_ndofs*vdim);
@@ -2231,34 +2125,14 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
bool is_dg = FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS;
int num_marked = 0;
const FiniteElement *fe = nullptr;
DenseMatrix localRVO; //for variable order only
for (int k = 0; k < dtrans.embeddings.Size(); k++)
{
const Embedding &emb = dtrans.embeddings[k];
Geometry::Type geom = mesh->GetElementBaseGeometry(emb.parent);
if (IsVariableOrder())
{
fe = GetFE(emb.parent);
const DenseTensor &pmats = dtrans.point_matrices[geom];
const int ldof = fe->GetDof();
IsoparametricTransformation isotr;
isotr.SetIdentityTransformation(geom);
localRVO.SetSize(ldof, ldof);
isotr.SetPointMat(pmats(emb.matrix));
// Local restriction is size ldofxldof assuming that the parent and
// child are of same polynomial order.
fe->GetLocalRestriction(isotr, localRVO);
}
DenseMatrix &lR = IsVariableOrder() ? localRVO : localR[geom](emb.matrix);
DenseMatrix &lR = localR[geom](emb.matrix);
elem_dof->GetRow(emb.parent, dofs);
old_elem_dof->GetRow(k, old_dofs);
MFEM_VERIFY(old_dofs.Size() == dofs.Size(),
"Parent and child must have same #dofs.");
for (int vd = 0; vd < vdim; vd++)
{
@@ -2284,7 +2158,7 @@ SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
}
}
if (!is_dg && !IsVariableOrder())
if (!is_dg)
{
MFEM_VERIFY(num_marked == R->Height(),
"internal error: not all rows of R were set.");
@@ -2342,7 +2216,6 @@ void FiniteElementSpace::Constructor(Mesh *mesh_, NURBSExtension *NURBSext_,
const NURBSFECollection *nurbs_fec =
dynamic_cast<const NURBSFECollection *>(fec_);
if (nurbs_fec)
{
MFEM_VERIFY(mesh_->NURBSext, "NURBS FE space requires a NURBS mesh.");
@@ -2439,63 +2312,12 @@ void FiniteElementSpace::UpdateNURBS()
face_dof = NULL;
face_to_be.DeleteAll();
// Depending on the element type create the appropriate extensions
// for the individual components.
dynamic_cast<const NURBSFECollection *>(fec)->Reset();
if (dynamic_cast<const NURBS_HDivFECollection *>(fec))
{
VNURBSext.SetSize(mesh->Dimension());
for (int d = 0; d < mesh->Dimension(); d++)
{
VNURBSext[d] = NURBSext->GetDivExtension(d);
}
}
ndofs = NURBSext->GetNDof();
elem_dof = NURBSext->GetElementDofTable();
bdr_elem_dof = NURBSext->GetBdrElementDofTable();
if (dynamic_cast<const NURBS_HCurlFECollection *>(fec))
{
VNURBSext.SetSize(mesh->Dimension());
for (int d = 0; d < mesh->Dimension(); d++)
{
VNURBSext[d] = NURBSext->GetCurlExtension(d);
}
}
// If required: concatenate the dof tables of the individual components into
// one dof table for the vector fespace.
if (VNURBSext.Size() == 2)
{
int offset1 = VNURBSext[0]->GetNDof();
ndofs = VNURBSext[0]->GetNDof() + VNURBSext[1]->GetNDof();
// Merge Tables
elem_dof = new Table(*VNURBSext[0]->GetElementDofTable(),
*VNURBSext[1]->GetElementDofTable(),offset1 );
bdr_elem_dof = new Table(*VNURBSext[0]->GetBdrElementDofTable(),
*VNURBSext[1]->GetBdrElementDofTable(),offset1);
}
else if (VNURBSext.Size() == 3)
{
int offset1 = VNURBSext[0]->GetNDof();
int offset2 = offset1 + VNURBSext[1]->GetNDof();
ndofs = offset2 + VNURBSext[2]->GetNDof();
// Merge Tables
elem_dof = new Table(*VNURBSext[0]->GetElementDofTable(),
*VNURBSext[1]->GetElementDofTable(),offset1,
*VNURBSext[2]->GetElementDofTable(),offset2);
bdr_elem_dof = new Table(*VNURBSext[0]->GetBdrElementDofTable(),
*VNURBSext[1]->GetBdrElementDofTable(),offset1,
*VNURBSext[2]->GetBdrElementDofTable(),offset2);
}
else
{
ndofs = NURBSext->GetNDof();
elem_dof = NURBSext->GetElementDofTable();
bdr_elem_dof = NURBSext->GetBdrElementDofTable();
}
mesh_sequence = mesh->GetSequence();
sequence++;
}
@@ -3497,21 +3319,11 @@ void FiniteElementSpace::Destroy()
dof_elem_array.DeleteAll();
dof_ldof_array.DeleteAll();
for (int i = 0; i < VNURBSext.Size(); i++)
{
delete VNURBSext[i];
}
if (NURBSext)
{
if (own_ext) { delete NURBSext; }
delete face_dof;
face_to_be.DeleteAll();
if (VNURBSext.Size() > 0 )
{
delete elem_dof;
delete bdr_elem_dof;
}
}
else
{
@@ -3523,8 +3335,6 @@ void FiniteElementSpace::Destroy()
delete [] bdofs;
}
ceed::RemoveBasisAndRestriction(this);
}
void FiniteElementSpace::DestroyDoFTransArray()
@@ -3543,27 +3353,19 @@ void FiniteElementSpace::GetTransferOperator(
if (T.Type() == Operator::MFEM_SPARSEMAT)
{
if (!IsVariableOrder())
{
Mesh::GeometryList elem_geoms(*mesh);
Mesh::GeometryList elem_geoms(*mesh);
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
{
GetLocalRefinementMatrices(coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
}
T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
coarse_fes.GetElementToDofTable(),
coarse_fes.
GetElementToFaceOrientationTable(),
localP));
}
else
DenseTensor localP[Geometry::NumGeom];
for (int i = 0; i < elem_geoms.Size(); i++)
{
T.Reset(VariableOrderRefinementMatrix(coarse_fes.GetNDofs(),
coarse_fes.GetElementToDofTable()));
GetLocalRefinementMatrices(coarse_fes, elem_geoms[i],
localP[elem_geoms[i]]);
}
T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
coarse_fes.GetElementToDofTable(),
coarse_fes.
GetElementToFaceOrientationTable(),
localP));
}
else
{
@@ -3614,33 +3416,19 @@ void FiniteElementSpace::GetTrueTransferOperator(
void FiniteElementSpace::UpdateElementOrders()
{
const CoarseFineTransformations &cf_tr = mesh->GetRefinementTransforms();
Array<char> new_order(mesh->GetNE());
switch (mesh->GetLastOperation())
{
case Mesh::REFINE:
{
const CoarseFineTransformations &cf_tr = mesh->GetRefinementTransforms();
for (int i = 0; i < mesh->GetNE(); i++)
{
new_order[i] = elem_order[cf_tr.embeddings[i].parent];
}
break;
}
case Mesh::DEREFINE:
{
const CoarseFineTransformations &cf_tr =
mesh->ncmesh->GetDerefinementTransforms();
Table coarse_to_fine;
cf_tr.MakeCoarseToFineTable(coarse_to_fine);
Array<int> tabrow;
for (int i = 0; i < coarse_to_fine.Size(); i++)
{
coarse_to_fine.GetRow(i, tabrow);
//For now we require that all children are of same polynomial order.
new_order[i] = elem_order[tabrow[0]];
}
break;
}
default:
MFEM_ABORT("not implemented yet");
}
@@ -3735,23 +3523,11 @@ void FiniteElementSpace::Update(bool want_transform)
{
BuildConformingInterpolation();
Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
if (IsVariableOrder())
if (cP && cR)
{
if (cP && cR_hp)
{
Th.SetOperatorOwner(false);
Th.Reset(new TripleProductOperator(cP.get(), cR_hp.get(), Th.Ptr(),
false, false, true));
}
}
else
{
if (cP && cR)
{
Th.SetOperatorOwner(false);
Th.Reset(new TripleProductOperator(cP.get(), cR.get(), Th.Ptr(),
false, false, true));
}
Th.SetOperatorOwner(false);
Th.Reset(new TripleProductOperator(cP.get(), cR.get(), Th.Ptr(),
false, false, true));
}
break;
}
@@ -3864,7 +3640,6 @@ FiniteElementCollection *FiniteElementSpace::Load(Mesh *m, std::istream &input)
input >> ord;
NURBSFECollection *nurbs_fec = dynamic_cast<NURBSFECollection*>(r_fec);
if (nurbs_fec) { nurbs_fec->SetDim(m->Dimension()); }
NURBSExtension *nurbs_ext = NULL;
if (fes_format == 90) // original format, v0.9
{
-11
View File
@@ -268,10 +268,6 @@ protected:
Array<int> dof_elem_array, dof_ldof_array;
NURBSExtension *NURBSext;
/** array of NURBS extension for H(div) and H(curl) vector elements.
For each direction an extension is created from the base NURBSext,
with an increase in order in the appropriate direction. */
Array<NURBSExtension*> VNURBSext;
int own_ext;
mutable Array<int> face_to_be; // NURBS FE space only
@@ -473,11 +469,6 @@ protected:
const Table *coarse_elem_fos,
const DenseTensor localP[]) const;
/* This method returns the Refinement matrix (i.e., the embedding)
from a coarse variable-order fes to a fine fes (after a geometric refinement) */
SparseMatrix *VariableOrderRefinementMatrix(const int coarse_ndofs,
const Table &coarse_elem_dof) const;
void GetLocalRefinementMatrices(Geometry::Type geom,
DenseTensor &localP) const;
void GetLocalDerefinementMatrices(Geometry::Type geom,
@@ -526,8 +517,6 @@ protected:
const Array<int> *perm);
public:
/** @brief Default constructor: the object is invalid until initialized using
the method Load(). */
FiniteElementSpace();
+75 -210
View File
@@ -12,8 +12,6 @@
// Implementation of GridFunction
#include "gridfunc.hpp"
#include "linearform.hpp"
#include "bilinearform.hpp"
#include "quadinterpolator.hpp"
#include "../mesh/nurbs.hpp"
#include "../general/text.hpp"
@@ -41,7 +39,7 @@ GridFunction::GridFunction(Mesh *m, std::istream &input)
UseDevice(true);
fes = new FiniteElementSpace;
fec_owned = fes->Load(m, input);
fec = fes->Load(m, input);
skip_comment_lines(input, '#');
istream::int_type next_char = input.peek();
@@ -83,10 +81,10 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
int vdim, ordering;
fes = gf_array[0]->FESpace();
fec_owned = FiniteElementCollection::New(fes->FEColl()->Name());
fec = FiniteElementCollection::New(fes->FEColl()->Name());
vdim = fes->GetVDim();
ordering = fes->GetOrdering();
fes = new FiniteElementSpace(m, fec_owned, vdim, ordering);
fes = new FiniteElementSpace(m, fec, vdim, ordering);
SetSize(fes->GetVSize());
if (m->NURBSext)
@@ -155,11 +153,11 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
void GridFunction::Destroy()
{
if (fec_owned)
if (fec)
{
delete fes;
delete fec_owned;
fec_owned = NULL;
delete fec;
fec = NULL;
}
}
@@ -327,9 +325,10 @@ int GridFunction::VectorDim() const
const FiniteElement *fe;
if (!fes->GetNE())
{
const FiniteElementCollection *fe_coll = fes->FEColl();
static const Geometry::Type geoms[3] =
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
fe = fes->FEColl()->
fe = fe_coll->
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
}
else
@@ -351,8 +350,8 @@ int GridFunction::CurlDim() const
{
static const Geometry::Type geoms[3] =
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
fe = fes->FEColl()->
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
fe = fes->FEColl()->FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()
-1]);
}
else
{
@@ -1323,9 +1322,9 @@ void GridFunction::ProjectVectorFieldOn(GridFunction &vec_field, int comp)
}
}
void GridFunction::AccumulateAndCountDerivativeValues(
int comp, int der_comp, GridFunction &der,
Array<int> &zones_per_dof) const
void GridFunction::AccumulateAndCountDerivativeValues(int comp, int der_comp,
GridFunction &der,
Array<int> &zones_per_dof)
{
FiniteElementSpace * der_fes = der.FESpace();
ElementTransformation * transf;
@@ -1376,8 +1375,7 @@ void GridFunction::AccumulateAndCountDerivativeValues(
}
}
void GridFunction::GetDerivative(int comp, int der_comp,
GridFunction &der) const
void GridFunction::GetDerivative(int comp, int der_comp, GridFunction &der)
{
Array<int> overlap;
AccumulateAndCountDerivativeValues(comp, der_comp, der, overlap);
@@ -2064,37 +2062,41 @@ void GridFunction::AccumulateAndCountBdrValues(
Coefficient *coeff[], VectorCoefficient *vcoeff, const Array<int> &attr,
Array<int> &values_counter)
{
int i, j, fdof, d, ind, vdim;
real_t val;
const FiniteElement *fe;
ElementTransformation *transf;
Array<int> vdofs;
Vector vc;
values_counter.SetSize(Size());
values_counter = 0;
const int vdim = fes->GetVDim();
vdim = fes->GetVDim();
HostReadWrite();
for (int i = 0; i < fes->GetNBE(); i++)
for (i = 0; i < fes->GetNBE(); i++)
{
if (attr[fes->GetBdrAttribute(i) - 1] == 0) { continue; }
const FiniteElement *fe = fes->GetBE(i);
const int fdof = fe->GetDof();
ElementTransformation *transf = fes->GetBdrElementTransformation(i);
fe = fes->GetBE(i);
fdof = fe->GetDof();
transf = fes->GetBdrElementTransformation(i);
const IntegrationRule &ir = fe->GetNodes();
fes->GetBdrElementVDofs(i, vdofs);
for (int j = 0; j < fdof; j++)
for (j = 0; j < fdof; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
transf->SetIntPoint(&ip);
if (vcoeff) { vcoeff->Eval(vc, *transf, ip); }
for (int d = 0; d < vdim; d++)
for (d = 0; d < vdim; d++)
{
if (!vcoeff && !coeff[d]) { continue; }
real_t val = vcoeff ? vc(d) : coeff[d]->Eval(*transf, ip);
int ind = vdofs[fdof*d+j];
if ( ind < 0 )
val = vcoeff ? vc(d) : coeff[d]->Eval(*transf, ip);
if ( (ind = vdofs[fdof*d+j]) < 0 )
{
val = -val, ind = -1-ind;
}
@@ -2116,11 +2118,10 @@ void GridFunction::AccumulateAndCountBdrValues(
// iff A_ij != 0. It is sufficient to resolve just the first level of
// dependency, since A is a projection matrix: A^n = A due to cR.cP = I.
// Cases like these arise in 3D when boundary edges are constrained by
// (depend on) internal faces/elements, or for internal boundaries in 2 or
// 3D. We use the virtual method GetBoundaryClosure from NCMesh to resolve
// the dependencies.
if (fes->Nonconforming() && (fes->GetMesh()->Dimension() == 2 ||
fes->GetMesh()->Dimension() == 3))
// (depend on) internal faces/elements. We use the virtual method
// GetBoundaryClosure from NCMesh to resolve the dependencies.
if (fes->Nonconforming() && fes->GetMesh()->Dimension() == 3)
{
Vector vals;
Mesh *mesh = fes->GetMesh();
@@ -2128,19 +2129,26 @@ void GridFunction::AccumulateAndCountBdrValues(
Array<int> bdr_edges, bdr_vertices, bdr_faces;
ncmesh->GetBoundaryClosure(attr, bdr_vertices, bdr_edges, bdr_faces);
auto mark_dofs = [&](ElementTransformation &transf, const FiniteElement &fe)
for (i = 0; i < bdr_edges.Size(); i++)
{
int edge = bdr_edges[i];
fes->GetEdgeVDofs(edge, vdofs);
if (vdofs.Size() == 0) { continue; }
transf = mesh->GetEdgeTransformation(edge);
transf->Attribute = -1; // TODO: set the boundary attribute
fe = fes->GetEdgeElement(edge);
if (!vcoeff)
{
vals.SetSize(fe.GetDof());
for (int d = 0; d < vdim; d++)
vals.SetSize(fe->GetDof());
for (d = 0; d < vdim; d++)
{
if (!coeff[d]) { continue; }
fe.Project(*coeff[d], transf, vals);
fe->Project(*coeff[d], *transf, vals);
for (int k = 0; k < vals.Size(); k++)
{
const int ind = vdofs[d*vals.Size()+k];
ind = vdofs[d*vals.Size()+k];
if (++values_counter[ind] == 1)
{
(*this)(ind) = vals(k);
@@ -2154,11 +2162,11 @@ void GridFunction::AccumulateAndCountBdrValues(
}
else // vcoeff != NULL
{
vals.SetSize(vdim*fe.GetDof());
fe.Project(*vcoeff, transf, vals);
vals.SetSize(vdim*fe->GetDof());
fe->Project(*vcoeff, *transf, vals);
for (int k = 0; k < vals.Size(); k++)
{
const int ind = vdofs[k];
ind = vdofs[k];
if (++values_counter[ind] == 1)
{
(*this)(ind) = vals(k);
@@ -2169,26 +2177,6 @@ void GridFunction::AccumulateAndCountBdrValues(
}
}
}
};
for (auto edge : bdr_edges)
{
fes->GetEdgeVDofs(edge, vdofs);
if (vdofs.Size() == 0) { continue; }
ElementTransformation *transf = mesh->GetEdgeTransformation(edge);
const FiniteElement *fe = fes->GetEdgeElement(edge);
mark_dofs(*transf, *fe);
}
for (auto face : bdr_faces)
{
fes->GetFaceVDofs(face, vdofs);
if (vdofs.Size() == 0) { continue; }
ElementTransformation *transf = mesh->GetFaceTransformation(face);
const FiniteElement *fe = fes->GetFaceElement(face);
mark_dofs(*transf, *fe);
}
}
}
@@ -2241,37 +2229,26 @@ void GridFunction::AccumulateAndCountBdrTangentValues(
accumulate_dofs(dofs, lvec, *this, values_counter);
}
if (fes->Nonconforming() && (fes->GetMesh()->Dimension() == 2 ||
fes->GetMesh()->Dimension() == 3))
if (fes->Nonconforming() && fes->GetMesh()->Dimension() == 3)
{
Mesh *mesh = fes->GetMesh();
NCMesh *ncmesh = mesh->ncmesh;
Array<int> bdr_edges, bdr_vertices, bdr_faces;
ncmesh->GetBoundaryClosure(bdr_attr, bdr_vertices, bdr_edges, bdr_faces);
for (auto edge : bdr_edges)
for (int i = 0; i < bdr_edges.Size(); i++)
{
int edge = bdr_edges[i];
fes->GetEdgeDofs(edge, dofs);
if (dofs.Size() == 0) { continue; }
T = mesh->GetEdgeTransformation(edge);
T->Attribute = -1; // TODO: set the boundary attribute
fe = fes->GetEdgeElement(edge);
lvec.SetSize(fe->GetDof());
fe->Project(vcoeff, *T, lvec);
accumulate_dofs(dofs, lvec, *this, values_counter);
}
for (auto face : bdr_faces)
{
fes->GetFaceDofs(face, dofs);
if (dofs.Size() == 0) { continue; }
T = mesh->GetFaceTransformation(face);
fe = fes->GetFaceElement(face);
lvec.SetSize(fe->GetDof());
fe->Project(vcoeff, *T, lvec);
accumulate_dofs(dofs, lvec, *this, values_counter);
}
}
}
@@ -2374,48 +2351,19 @@ void GridFunction::ProjectCoefficient(Coefficient &coeff)
if (delta_c == NULL)
{
if (fes->GetNURBSext() == NULL)
{
Array<int> vdofs;
Vector vals;
Array<int> vdofs;
Vector vals;
for (int i = 0; i < fes->GetNE(); i++)
for (int i = 0; i < fes->GetNE(); i++)
{
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
{
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
{
doftrans->TransformPrimal(vals);
}
SetSubVector(vdofs, vals);
doftrans->TransformPrimal(vals);
}
}
else
{
// Define and assemble linear form
LinearForm b(fes);
b.AddDomainIntegrator(new DomainLFIntegrator(coeff));
b.Assemble();
// Define and assemble bilinear form
BilinearForm a(fes);
a.AddDomainIntegrator(new MassIntegrator());
a.Assemble();
// Set solver and preconditioner
SparseMatrix A(a.SpMat());
GSSmoother prec(A);
CGSolver cg;
cg.SetOperator(A);
cg.SetPreconditioner(prec);
cg.SetRelTol(1e-12);
cg.SetMaxIter(1000);
cg.SetPrintLevel(0);
// Solve and get solution
*this = 0.0;
cg.Mult(b,*this);
SetSubVector(vdofs, vals);
}
}
else
@@ -2456,54 +2404,22 @@ void GridFunction::ProjectCoefficient(
void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff)
{
if (fes->GetNURBSext() == NULL)
int i;
Array<int> vdofs;
Vector vals;
DofTransformation * doftrans = NULL;
for (i = 0; i < fes->GetNE(); i++)
{
int i;
Array<int> vdofs;
Vector vals;
DofTransformation * doftrans = NULL;
for (i = 0; i < fes->GetNE(); i++)
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
{
doftrans = fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
if (doftrans)
{
doftrans->TransformPrimal(vals);
}
SetSubVector(vdofs, vals);
doftrans->TransformPrimal(vals);
}
}
else
{
// Define and assemble linear form
LinearForm b(fes);
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(vcoeff));
b.Assemble();
// Define and assemble bilinear form
BilinearForm a(fes);
a.AddDomainIntegrator(new VectorFEMassIntegrator());
a.Assemble();
// Set solver and preconditioner
SparseMatrix A(a.SpMat());
GSSmoother prec(A);
CGSolver cg;
cg.SetOperator(A);
cg.SetPreconditioner(prec);
cg.SetRelTol(1e-12);
cg.SetMaxIter(1000);
cg.SetPrintLevel(0);
// Solve and get solution
*this = 0.0;
cg.Mult(b,*this);
SetSubVector(vdofs, vals);
}
}
@@ -3051,57 +2967,6 @@ real_t GridFunction::ComputeDivError(
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
}
real_t GridFunction::ComputeLaplaceError(
Coefficient *exlap, const IntegrationRule *irs[]) const
{
real_t error = 0.0, a;
const FiniteElement *fe;
ElementTransformation *Tr;
Array<int> dofs;
int intorder, fdof;
Vector laplace;
for (int i = 0; i < fes->GetNE(); i++)
{
laplace.SetSize(fdof);
fe = fes->GetFE(i);
Tr = fes->GetElementTransformation(i);
intorder = 2*fe->GetOrder() + 3;
const IntegrationRule *ir;
if (irs)
{
ir = irs[fe->GetGeomType()];
}
else
{
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
fes->GetElementDofs(i, dofs);
fdof = fe->GetDof();
laplace.SetSize(fdof);
for (int j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
Tr->SetIntPoint(&ip);
fe->CalcPhysLaplacian(*Tr, laplace);
a = 0;
for (int k = 0; k < fdof; k++)
if (dofs[k] >= 0)
{
a += (*this)(dofs[k]) * laplace(k);
}
else
{
a -= (*this)(-1-dofs[k]) * laplace(k);
}
a -= exlap->Eval(*Tr, ip);
error += ip.weight * Tr->Weight() * a * a;
}
}
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
}
real_t GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
Coefficient *ell_coeff,
class JumpScaling jump_scaling,
@@ -4040,7 +3905,7 @@ void GridFunction::LegacyNCReorder()
mesh->GetEdgeVertices(i, ev);
if (old_vertex[ev[0]] > old_vertex[ev[1]])
{
const int *ind = fes->FEColl()->DofOrderForOrientation(Geometry::SEGMENT, -1);
const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, -1);
fes->GetEdgeInteriorDofs(i, dofs);
for (int k = 0; k < dofs.Size(); k++)
+15 -21
View File
@@ -30,14 +30,14 @@ namespace mfem
class GridFunction : public Vector
{
protected:
/// FE space on which the grid function lives. Owned if #fec_owned is not NULL.
/// FE space on which the grid function lives. Owned if #fec is not NULL.
FiniteElementSpace *fes;
/** @brief Used when the grid function is read from a file. It can also be
set explicitly, see MakeOwner().
If not NULL, this pointer is owned by the GridFunction. */
FiniteElementCollection *fec_owned;
FiniteElementCollection *fec;
long fes_sequence; // see FiniteElementSpace::sequence, Mesh::sequence
@@ -72,16 +72,16 @@ protected:
public:
GridFunction() { fes = NULL; fec_owned = NULL; fes_sequence = 0; UseDevice(true); }
GridFunction() { fes = NULL; fec = NULL; fes_sequence = 0; UseDevice(true); }
/// Copy constructor. The internal true-dof vector #t_vec is not copied.
GridFunction(const GridFunction &orig)
: Vector(orig), fes(orig.fes), fec_owned(NULL), fes_sequence(orig.fes_sequence)
: Vector(orig), fes(orig.fes), fec(NULL), fes_sequence(orig.fes_sequence)
{ UseDevice(true); }
/// Construct a GridFunction associated with the FiniteElementSpace @a *f.
GridFunction(FiniteElementSpace *f) : Vector(f->GetVSize())
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/// Construct a GridFunction using previously allocated array @a data.
/** The GridFunction does not assume ownership of @a data which is assumed to
@@ -91,13 +91,13 @@ public:
*/
GridFunction(FiniteElementSpace *f, real_t *data)
: Vector(data, f->GetVSize())
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/** @brief Construct a GridFunction using previously allocated Vector @a base
starting at the given offset, @a base_offset. */
GridFunction(FiniteElementSpace *f, Vector &base, int base_offset = 0)
: Vector(base, base_offset, f->GetVSize())
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
/// Construct a GridFunction on the given Mesh, using the data from @a input.
/** The content of @a input should be in the format created by the method
@@ -116,12 +116,12 @@ public:
GridFunction &operator=(const GridFunction &rhs)
{ return operator=((const Vector &)rhs); }
/// Make the GridFunction the owner of #fec_owned and #fes.
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec_owned
/// Make the GridFunction the owner of #fec and #fes.
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec
and #fes is taken away. */
void MakeOwner(FiniteElementCollection *fec_) { fec_owned = fec_; }
void MakeOwner(FiniteElementCollection *fec_) { fec = fec_; }
FiniteElementCollection *OwnFEC() { return fec_owned; }
FiniteElementCollection *OwnFEC() { return fec; }
int VectorDim() const;
int CurlDim() const;
@@ -321,7 +321,7 @@ public:
@param[out] der The resulting derivative (scalar function). The
FiniteElementSpace of this function must be set
before the call. */
void GetDerivative(int comp, int der_comp, GridFunction &der) const;
void GetDerivative(int comp, int der_comp, GridFunction &der);
real_t GetDivergence(ElementTransformation &tr) const;
@@ -387,8 +387,7 @@ public:
/** @brief Project @a coeff Coefficient to @a this GridFunction. The
projection computation depends on the choice of the FiniteElementSpace
#fes. Note that this is usually interpolation at the degrees of freedom
in each element (not L2 projection). For NURBS spaces these degrees of
freedom are not available and L2 projection is resorted to as fallback. */
in each element (not L2 projection). */
virtual void ProjectCoefficient(Coefficient &coeff);
/** @brief Project @a coeff Coefficient to @a this GridFunction, using one
@@ -399,8 +398,7 @@ public:
/** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction. The
projection computation depends on the choice of the FiniteElementSpace
#fes. Note that this is usually interpolation at the degrees of freedom
in each element (not L2 projection). For NURBS spaces these degrees of
freedom are not available and L2 projection is resorted to as fallback. */
in each element (not L2 projection).*/
void ProjectCoefficient(VectorCoefficient &vcoeff);
/** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction, using
@@ -445,7 +443,7 @@ protected:
GetDerivative() method; see its documentation. */
void AccumulateAndCountDerivativeValues(int comp, int der_comp,
GridFunction &der,
Array<int> &zones_per_dof) const;
Array<int> &zones_per_dof);
void AccumulateAndCountBdrValues(Coefficient *coeff[],
VectorCoefficient *vcoeff,
@@ -533,10 +531,6 @@ public:
virtual real_t ComputeDivError(Coefficient *exdiv,
const IntegrationRule *irs[] = NULL) const;
/// Returns ||lap u_ex - lap u_h||_L2 for H1 elements
virtual real_t ComputeLaplaceError(Coefficient *exlap,
const IntegrationRule *irs[] = NULL) const;
/// Returns the Face Jumps error for L2 elements. The error can be weighted
/// by a constant nu, by nu/h, or nu*p^2/h, depending on the value of
/// @a jump_scaling.
-2
View File
@@ -1393,10 +1393,8 @@ GSOPGSLIB::~GSOPGSLIB()
void GSOPGSLIB::UpdateIdentifiers(const Array<long long> &ids)
{
long long minval = ids.Min();
#ifdef MFEM_USE_MPI
MPI_Allreduce(MPI_IN_PLACE, &minval, 1, MPI_LONG_LONG_INT,
MPI_MIN, gsl_comm->c);
#endif
MFEM_VERIFY(minval >= 0, "Unique identifier cannot be negative.");
if (gsl_data != NULL) { gslib_gs_free(gsl_data); }
num_ids = ids.Size();
+44 -44
View File
@@ -220,8 +220,8 @@ void MomentFittingIntRules::ComputeSurfaceWeights1D(ElementTransformation& Tr)
{
IntegrationPoint ip2;
ip2.x = .5;
while (LvlSet->Eval(Tr, ip2) > tol_1
|| LvlSet->Eval(Tr, ip2) < -tol_1)
while (LvlSet->Eval(Tr, ip2) > 1e-12
|| LvlSet->Eval(Tr, ip2) < -1e-12)
{
if (LvlSet->Eval(Tr, ip0) * LvlSet->Eval(Tr, ip2) < 0.)
{
@@ -237,12 +237,12 @@ void MomentFittingIntRules::ComputeSurfaceWeights1D(ElementTransformation& Tr)
intp.x = ip2.x;
intp.weight = 1. / Tr.Weight();
}
else if (LvlSet->Eval(Tr, ip0) > 0. && LvlSet->Eval(Tr, ip1) <= tol_1)
else if (LvlSet->Eval(Tr, ip0) > 0. && LvlSet->Eval(Tr, ip1) <= 1e-12)
{
intp.x = 1.;
intp.weight = 1. / Tr.Weight();
}
else if (LvlSet->Eval(Tr, ip1) > 0. && LvlSet->Eval(Tr, ip0) <= tol_1)
else if (LvlSet->Eval(Tr, ip1) > 0. && LvlSet->Eval(Tr, ip0) <= 1e-12)
{
intp.x = 0.;
intp.weight = 1. / Tr.Weight();
@@ -290,8 +290,8 @@ void MomentFittingIntRules::ComputeVolumeWeights1D(ElementTransformation& Tr,
}
}
}
else if (LvlSet->Eval(Tr, ip0) <= -tol_1
|| LvlSet->Eval(Tr, ip1) <= -tol_1)
else if (LvlSet->Eval(Tr, ip0) <= -1e-12
|| LvlSet->Eval(Tr, ip1) <= -1e-12)
{
for (int ip = 0; ip < ir.GetNPoints(); ip++)
{
@@ -356,24 +356,24 @@ void MomentFittingIntRules::ComputeSurfaceWeights2D(ElementTransformation& Tr)
IntegrationPoint ipB;
Trafo.TransformBack(pointB, ipB);
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1)
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -tol_1
&& LvlSet->Eval(Trafo, ipB) > -tol_1)
if (LvlSet->Eval(Trafo, ipA) > -1e-12
&& LvlSet->Eval(Trafo, ipB) > -1e-12)
{
layout = Layout::inside;
}
else if (LvlSet->Eval(Trafo, ipA) > tol_2
else if (LvlSet->Eval(Trafo, ipA) > 1e-15
&& LvlSet->Eval(Trafo, ipB) <= 0.)
{
layout = Layout::intersected;
}
else if (LvlSet->Eval(Trafo, ipA) <= 0.
&& LvlSet->Eval(Trafo, ipB) > tol_2)
&& LvlSet->Eval(Trafo, ipB) > 1e-15)
{
layout = Layout::intersected;
Vector temp(pointA.Size());
@@ -399,10 +399,10 @@ void MomentFittingIntRules::ComputeSurfaceWeights2D(ElementTransformation& Tr)
IntegrationPoint ip;
Trafo.TransformBack(mid, ip);
while (LvlSet->Eval(Trafo, ip) > tol_1
|| LvlSet->Eval(Trafo, ip) < -tol_1)
while (LvlSet->Eval(Trafo, ip) > 1e-12
|| LvlSet->Eval(Trafo, ip) < -1e-12)
{
if (LvlSet->Eval(Trafo, ip) > tol_1)
if (LvlSet->Eval(Trafo, ip) > 1e-12)
{
pointC = mid;
}
@@ -539,7 +539,7 @@ void MomentFittingIntRules::ComputeSurfaceWeights2D(ElementTransformation& Tr)
temp2 = 0.;
for (int i = 0; i < nBasis; i++)
{
if (SVD.Singularvalue(i) > tol_1)
if (SVD.Singularvalue(i) > 1e-12)
{
temp2(i) = temp(i) / SVD.Singularvalue(i);
}
@@ -606,24 +606,24 @@ void MomentFittingIntRules::ComputeVolumeWeights2D(ElementTransformation& Tr,
IntegrationPoint ipB;
Trafo.TransformBack(pointB, ipB);
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1)
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -tol_1
&& LvlSet->Eval(Trafo, ipB) > -tol_1)
if (LvlSet->Eval(Trafo, ipA) > -1e-12
&& LvlSet->Eval(Trafo, ipB) > -1e-12)
{
layout = Layout::inside;
}
else if (LvlSet->Eval(Trafo, ipA) > tol_2
else if (LvlSet->Eval(Trafo, ipA) > 1e-15
&& LvlSet->Eval(Trafo, ipB) <= 0.)
{
layout = Layout::intersected;
}
else if (LvlSet->Eval(Trafo, ipA) <= 0.
&& LvlSet->Eval(Trafo, ipB) > tol_2)
&& LvlSet->Eval(Trafo, ipB) > 1e-15)
{
layout = Layout::intersected;
Vector temp(pointA.Size());
@@ -648,10 +648,10 @@ void MomentFittingIntRules::ComputeVolumeWeights2D(ElementTransformation& Tr,
IntegrationPoint ip;
Trafo.TransformBack(mid, ip);
while (LvlSet->Eval(Trafo, ip) > tol_1
|| LvlSet->Eval(Trafo, ip) < -tol_1)
while (LvlSet->Eval(Trafo, ip) > 1e-12
|| LvlSet->Eval(Trafo, ip) < -1e-12)
{
if (LvlSet->Eval(Trafo, ip) > tol_1)
if (LvlSet->Eval(Trafo, ip) > 1e-12)
{
pointC = mid;
}
@@ -786,7 +786,7 @@ void MomentFittingIntRules::ComputeVolumeWeights2D(ElementTransformation& Tr,
VolumeSVD->LeftSingularvectors().MultTranspose(RHS, temp);
for (int i = 0; i < nBasisVolume; i++)
{
if (VolumeSVD->Singularvalue(i) > tol_1)
if (VolumeSVD->Singularvalue(i) > 1e-12)
{
temp2(i) = temp(i) / VolumeSVD->Singularvalue(i);
}
@@ -865,18 +865,18 @@ void MomentFittingIntRules::ComputeSurfaceWeights3D(ElementTransformation& Tr)
IntegrationPoint ipD;
Trafo.TransformBack(pointD, ipD);
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1
|| LvlSet->Eval(Trafo, ipC) < -tol_1
|| LvlSet->Eval(Trafo, ipD) < -tol_1)
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12
|| LvlSet->Eval(Trafo, ipC) < -1e-12
|| LvlSet->Eval(Trafo, ipD) < -1e-12)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -tol_1
|| LvlSet->Eval(Trafo, ipB) > -tol_1
|| LvlSet->Eval(Trafo, ipC) > -tol_1
|| LvlSet->Eval(Trafo, ipD) > -tol_1)
if (LvlSet->Eval(Trafo, ipA) > -1e-12
|| LvlSet->Eval(Trafo, ipB) > -1e-12
|| LvlSet->Eval(Trafo, ipC) > -1e-12
|| LvlSet->Eval(Trafo, ipD) > -1e-12)
{
element_int = true;
}
@@ -978,7 +978,7 @@ void MomentFittingIntRules::ComputeSurfaceWeights3D(ElementTransformation& Tr)
temp2 = 0.;
for (int i = 0; i < nBasis; i++)
{
if (SVD.Singularvalue(i) > tol_1)
if (SVD.Singularvalue(i) > 1e-12)
{
temp2(i) = temp(i) / SVD.Singularvalue(i);
}
@@ -1047,18 +1047,18 @@ void MomentFittingIntRules::ComputeVolumeWeights3D(ElementTransformation& Tr,
IntegrationPoint ipD;
Trafo.TransformBack(pointD, ipD);
if (LvlSet->Eval(Trafo, ipA) < -tol_1
|| LvlSet->Eval(Trafo, ipB) < -tol_1
|| LvlSet->Eval(Trafo, ipC) < -tol_1
|| LvlSet->Eval(Trafo, ipD) < -tol_1)
if (LvlSet->Eval(Trafo, ipA) < -1e-12
|| LvlSet->Eval(Trafo, ipB) < -1e-12
|| LvlSet->Eval(Trafo, ipC) < -1e-12
|| LvlSet->Eval(Trafo, ipD) < -1e-12)
{
interior = false;
}
if (LvlSet->Eval(Trafo, ipA) > -tol_1
|| LvlSet->Eval(Trafo, ipB) > -tol_1
|| LvlSet->Eval(Trafo, ipC) > -tol_1
|| LvlSet->Eval(Trafo, ipD) > -tol_1)
if (LvlSet->Eval(Trafo, ipA) > -1e-12
|| LvlSet->Eval(Trafo, ipB) > -1e-12
|| LvlSet->Eval(Trafo, ipC) > -1e-12
|| LvlSet->Eval(Trafo, ipD) > -1e-12)
{
element_int = true;
}
@@ -1159,7 +1159,7 @@ void MomentFittingIntRules::ComputeVolumeWeights3D(ElementTransformation& Tr,
VolumeSVD->LeftSingularvectors().MultTranspose(RHS, temp);
temp2 = 0.;
for (int i = 0; i < nBasisVolume; i++)
if (VolumeSVD->Singularvalue(i) > tol_1)
if (VolumeSVD->Singularvalue(i) > 1e-12)
{
temp2(i) = temp(i) / VolumeSVD->Singularvalue(i);
}
-11
View File
@@ -36,17 +36,6 @@ protected:
/// Space order for the LS projection.
int lsOrder;
/// @name Tolerances used for point comparisons
///@{
#ifdef MFEM_USE_DOUBLE
static constexpr real_t tol_1 = 1e-12;
static constexpr real_t tol_2 = 1e-15;
#elif defined(MFEM_USE_SINGLE)
static constexpr real_t tol_1 = 1e-5;
static constexpr real_t tol_2 = 1e-7;
#endif
///@}
/** @brief Constructor to set up the generated cut IntegrationRules.
@param [in] order Order of the constructed IntegrationRule.
-29
View File
@@ -123,35 +123,6 @@ void DomainLFGradIntegrator::AssembleDeltaElementVect(
dshape.Mult(Qvec, elvect);
}
void DomainLFLaplaceIntegrator::AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect)
{
int dof = el.GetDof();
laplace.SetSize(dof); // vector of size dof
elvect.SetSize(dof);
elvect = 0.0;
const IntegrationRule *ir = NULL;//IntRule;
if (ir == NULL)
{
ir = &IntRules.Get(el.GetGeomType(), oa * el.GetOrder() + ob + 4);
}
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Tr.SetIntPoint (&ip);
real_t val = Tr.Weight() * Q.Eval(Tr, ip) * alpha;
el.CalcPhysLaplacian(Tr, laplace);
add(elvect, ip.weight * val, laplace, elvect);
}
}
void BoundaryLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
-23
View File
@@ -174,29 +174,6 @@ public:
using LinearFormIntegrator::AssembleRHSElementVect;
};
/// Class for domain integrator $ L(v) := (f, \Delta v) $
class DomainLFLaplaceIntegrator : public LinearFormIntegrator
{
private:
Vector laplace;
Coefficient &Q;
real_t alpha;
int oa, ob;
public:
/// Constructs the domain integrator $ (Q, \nabla v) $
DomainLFLaplaceIntegrator(Coefficient &QF, real_t alp = 1.0, int a = 2,
int b = 0)
: Q(QF), oa(a), ob(b) { alpha = alp; }
/** Given a particular Finite Element and a transformation (Tr)
computes the element right hand side element vector, elvect. */
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect);
using LinearFormIntegrator::AssembleRHSElementVect;
};
/// Class for boundary integration $ L(v) := (g, v) $
class BoundaryLFIntegrator : public LinearFormIntegrator
+4 -5
View File
@@ -39,10 +39,9 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, const GridFunction *gf,
{
const FiniteElementSpace *glob_fes = gf->FESpace();
// duplicate the FiniteElementCollection from 'gf'
fec_owned = FiniteElementCollection::New(glob_fes->FEColl()->Name());
fec = FiniteElementCollection::New(glob_fes->FEColl()->Name());
// create a local ParFiniteElementSpace from the global one:
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning,
fec_owned);
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning, fec);
SetSize(pfes->GetVSize());
if (partitioning)
@@ -82,7 +81,7 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, std::istream &input)
: GridFunction(pmesh, input)
{
// Convert the FiniteElementSpace, fes, to a ParFiniteElementSpace:
pfes = new ParFiniteElementSpace(pmesh, fec_owned, fes->GetVDim(),
pfes = new ParFiniteElementSpace(pmesh, fec, fes->GetVDim(),
fes->GetOrdering());
delete fes;
fes = pfes;
@@ -521,7 +520,7 @@ void ParGridFunction::CountElementsPerVDof(Array<int> &elem_per_vdof) const
}
void ParGridFunction::GetDerivative(int comp, int der_comp,
ParGridFunction &der) const
ParGridFunction &der)
{
Array<int> overlap;
AccumulateAndCountDerivativeValues(comp, der_comp, der, overlap);
+1 -1
View File
@@ -231,7 +231,7 @@ public:
void CountElementsPerVDof(Array<int> &elem_per_vdof) const override;
/// Parallel version of GridFunction::GetDerivative(); see its documentation.
void GetDerivative(int comp, int der_comp, ParGridFunction &der) const;
void GetDerivative(int comp, int der_comp, ParGridFunction &der);
/** Sets the output vector @a dof_vals to the values of the degrees of
freedom of element @a el. If @a el is greater than or equal to the number
+124 -238
View File
@@ -2949,15 +2949,6 @@ void TMOP_Integrator::EnableSurfaceFitting(const GridFunction &s0,
MFEM_VERIFY(surf_fit_pos == NULL,
"Using both fitting approaches is not supported.");
const int dim = s0.FESpace()->GetMesh()->Dimension();
Mesh *mesh = s0.FESpace()->GetMesh();
MFEM_VERIFY(mesh->GetNodes()->Size() == dim*s0.Size(),
"Mesh and level-set polynomial order must be the same.");
const H1_FECollection *fec = dynamic_cast<const H1_FECollection *>
(s0.FESpace()->FEColl());
MFEM_VERIFY(fec, "Only H1_FECollection is supported for the surface fitting "
"grid function.");
delete surf_fit_gf;
surf_fit_gf = new GridFunction(s0);
surf_fit_gf->CountElementsPerVDof(surf_fit_dof_count);
@@ -2996,24 +2987,12 @@ void TMOP_Integrator::EnableSurfaceFitting(const GridFunction &pos,
void TMOP_Integrator::EnableSurfaceFitting(const ParGridFunction &s0,
const Array<bool> &smarker,
Coefficient &coeff,
AdaptivityEvaluator &ae,
AdaptivityEvaluator *aegrad,
AdaptivityEvaluator *aehess)
AdaptivityEvaluator &ae)
{
// To have both we must duplicate the markers.
MFEM_VERIFY(surf_fit_pos == NULL,
"Using both fitting approaches is not supported.");
const int dim = s0.FESpace()->GetMesh()->Dimension();
ParMesh *pmesh = s0.ParFESpace()->GetParMesh();
MFEM_VERIFY(pmesh->GetNodes()->Size() == dim*s0.Size(),
"Mesh and level-set polynomial order must be the same.");
const H1_FECollection *fec = dynamic_cast<const H1_FECollection *>
(s0.FESpace()->FEColl());
MFEM_VERIFY(fec, "Only H1_FECollection is supported for the surface fitting "
"grid function.");
delete surf_fit_gf;
surf_fit_gf = new GridFunction(s0);
s0.CountElementsPerVDof(surf_fit_dof_count);
@@ -3021,80 +3000,11 @@ void TMOP_Integrator::EnableSurfaceFitting(const ParGridFunction &s0,
surf_fit_coeff = &coeff;
surf_fit_eval = &ae;
surf_fit_eval->SetParMetaInfo(*pmesh, *s0.ParFESpace());
surf_fit_eval->SetParMetaInfo(*s0.ParFESpace()->GetParMesh(),
*s0.ParFESpace());
surf_fit_eval->SetInitialField
(*surf_fit_gf->FESpace()->GetMesh()->GetNodes(), *surf_fit_gf);
if (!aegrad) { return; }
MFEM_VERIFY(aehess, "AdaptivityEvaluator for Hessians must be provided too.");
ParFiniteElementSpace *fes = s0.ParFESpace();
// FE space for gradients.
delete surf_fit_grad;
H1_FECollection *fec_grad = new H1_FECollection(fec->GetOrder(), dim,
fec->GetBasisType());
ParFiniteElementSpace *fes_grad = new ParFiniteElementSpace(pmesh, fec_grad,
dim);
// Initial gradients.
surf_fit_grad = new GridFunction(fes_grad);
surf_fit_grad->MakeOwner(fec_grad);
for (int d = 0; d < dim; d++)
{
ParGridFunction surf_fit_grad_comp(fes, surf_fit_grad->GetData()+d*s0.Size());
s0.GetDerivative(1, d, surf_fit_grad_comp);
}
surf_fit_eval_grad = aegrad;
surf_fit_eval_grad->SetParMetaInfo(*pmesh, *fes_grad);
surf_fit_eval_grad->SetInitialField(*pmesh->GetNodes(), *surf_fit_grad);
// FE space for Hessians.
delete surf_fit_hess;
H1_FECollection *fec_hess = new H1_FECollection(fec->GetOrder(), dim,
fec->GetBasisType());
ParFiniteElementSpace *fes_hess = new ParFiniteElementSpace(pmesh, fec_hess,
dim*dim);
// Initial Hessians.
surf_fit_hess = new GridFunction(fes_hess);
surf_fit_hess->MakeOwner(fec_hess);
int id = 0;
for (int d = 0; d < dim; d++)
{
for (int idir = 0; idir < dim; idir++)
{
ParGridFunction surf_fit_grad_comp(fes,
surf_fit_grad->GetData()+d*s0.Size());
ParGridFunction surf_fit_hess_comp(fes,
surf_fit_hess->GetData()+id*s0.Size());
surf_fit_grad_comp.GetDerivative(1, idir, surf_fit_hess_comp);
id++;
}
}
surf_fit_eval_hess = aehess;
surf_fit_eval_hess->SetParMetaInfo(*pmesh, *fes_hess);
surf_fit_eval_hess->SetInitialField(*pmesh->GetNodes(), *surf_fit_hess);
// Store DOF indices that are marked for fitting. Used to reduce work for
// transferring information between source/background and current mesh.
surf_fit_marker_dof_index.SetSize(0);
#ifdef MFEM_USE_GSLIB
if (dynamic_cast<InterpolatorFP *>(surf_fit_eval) &&
dynamic_cast<InterpolatorFP *>(surf_fit_eval_grad) &&
dynamic_cast<InterpolatorFP *>(surf_fit_eval_hess))
{
for (int i = 0; i < surf_fit_marker->Size(); i++)
{
if ((*surf_fit_marker)[i] == true)
{
surf_fit_marker_dof_index.Append(i);
}
}
}
#endif
*surf_fit_grad = 0.0;
*surf_fit_hess = 0.0;
surf_fit_gf_bg = false;
}
void TMOP_Integrator::EnableSurfaceFittingFromSource(
@@ -3112,17 +3022,16 @@ void TMOP_Integrator::EnableSurfaceFittingFromSource(
// Setup for level set function
delete surf_fit_gf;
surf_fit_gf = new GridFunction(s0);
*surf_fit_gf = 0.0;
surf_fit_marker = &smarker;
surf_fit_coeff = &coeff;
surf_fit_eval = &ae;
surf_fit_gf_bg = true;
surf_fit_eval->SetParMetaInfo(*s_bg.ParFESpace()->GetParMesh(),
*s_bg.ParFESpace());
surf_fit_eval->SetInitialField
(*s_bg.FESpace()->GetMesh()->GetNodes(), s_bg);
GridFunction *nodes = s0.FESpace()->GetMesh()->GetNodes();
surf_fit_eval->ComputeAtNewPosition(*nodes, *surf_fit_gf,
nodes->FESpace()->GetOrdering());
// Setup for gradient on background mesh
MFEM_VERIFY(s_bg_grad.ParFESpace()->GetOrdering() ==
@@ -3132,11 +3041,11 @@ void TMOP_Integrator::EnableSurfaceFittingFromSource(
delete surf_fit_grad;
surf_fit_grad = new GridFunction(s0_grad);
*surf_fit_grad = 0.0;
surf_fit_eval_grad = &age;
surf_fit_eval_hess = &ahe;
surf_fit_eval_grad->SetParMetaInfo(*s_bg_grad.ParFESpace()->GetParMesh(),
*s_bg_grad.ParFESpace());
surf_fit_eval_grad->SetInitialField
surf_fit_eval_bg_grad = &age;
surf_fit_eval_bg_hess = &ahe;
surf_fit_eval_bg_grad->SetParMetaInfo(*s_bg_grad.ParFESpace()->GetParMesh(),
*s_bg_grad.ParFESpace());
surf_fit_eval_bg_grad->SetInitialField
(*s_bg_grad.FESpace()->GetMesh()->GetNodes(), s_bg_grad);
// Setup for Hessian on background mesh
@@ -3147,9 +3056,9 @@ void TMOP_Integrator::EnableSurfaceFittingFromSource(
delete surf_fit_hess;
surf_fit_hess = new GridFunction(s0_hess);
*surf_fit_hess = 0.0;
surf_fit_eval_hess->SetParMetaInfo(*s_bg_hess.ParFESpace()->GetParMesh(),
*s_bg_hess.ParFESpace());
surf_fit_eval_hess->SetInitialField
surf_fit_eval_bg_hess->SetParMetaInfo(*s_bg_hess.ParFESpace()->GetParMesh(),
*s_bg_hess.ParFESpace());
surf_fit_eval_bg_hess->SetInitialField
(*s_bg_hess.FESpace()->GetMesh()->GetNodes(), s_bg_hess);
// Count number of zones that share each of the DOFs
@@ -3954,7 +3863,7 @@ void TMOP_Integrator::AssembleElemVecSurfFit(const FiniteElement &el_x,
Vector sigma_e(dof_s);
DenseMatrix surf_fit_grad_e(dof_s, dim);
if (surf_fit_gf)
if (surf_fit_gf || surf_fit_gf_bg)
{
surf_fit_gf->GetSubVector(vdofs, sigma_e);
@@ -3962,7 +3871,7 @@ void TMOP_Integrator::AssembleElemVecSurfFit(const FiniteElement &el_x,
// The FE coefficients of the gradient go in surf_fit_grad_e.
Vector grad_ptr(surf_fit_grad_e.GetData(), dof_s * dim);
DenseMatrix grad_phys; // This will be (dof x dim, dof).
if (surf_fit_grad)
if (surf_fit_gf_bg)
{
surf_fit_grad->FESpace()->GetElementVDofs(el_id, dofs);
surf_fit_grad->GetSubVector(dofs, grad_ptr);
@@ -4036,7 +3945,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
Vector sigma_e(dof_s);
DenseMatrix surf_fit_grad_e(dof_s, dim);
DenseMatrix surf_fit_hess_e(dof_s, dim*dim);
if (surf_fit_gf)
if (surf_fit_gf || surf_fit_gf_bg)
{
surf_fit_gf->GetSubVector(vdofs, sigma_e);
@@ -4044,7 +3953,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
// The FE coefficients of the gradient go in surf_fit_grad_e.
Vector grad_ptr(surf_fit_grad_e.GetData(), dof_s * dim);
DenseMatrix grad_phys; // This will be (dof x dim, dof).
if (surf_fit_grad)
if (surf_fit_gf_bg)
{
surf_fit_grad->FESpace()->GetElementVDofs(el_id, dofs);
surf_fit_grad->GetSubVector(dofs, grad_ptr);
@@ -4058,7 +3967,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
// Project the Hessian of sigma in the same space.
// The FE coefficients of the Hessian go in surf_fit_hess_e.
Vector hess_ptr(surf_fit_hess_e.GetData(), dof_s*dim*dim);
if (surf_fit_hess)
if (surf_fit_gf_bg)
{
surf_fit_hess->FESpace()->GetElementVDofs(el_id, dofs);
surf_fit_hess->GetSubVector(dofs, hess_ptr);
@@ -4085,7 +3994,7 @@ void TMOP_Integrator::AssembleElemGradSurfFit(const FiniteElement &el_x,
Tpr.SetIntPoint(&ip);
real_t w = surf_fit_normal * surf_fit_coeff->Eval(Tpr, ip);
if (surf_fit_gf)
if (surf_fit_gf || surf_fit_gf_bg)
{
Vector gg_ptr(surf_fit_hess_s.GetData(), dim * dim);
surf_fit_hess_e.GetRow(s, gg_ptr);
@@ -4467,130 +4376,6 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x,
dx = detv_avg_min / dxscale;
}
void TMOP_Integrator::RemapSurfaceFittingLevelSetAtNodes(const Vector &new_x,
int new_x_ordering)
{
if (!surf_fit_gf) { return; }
if (surf_fit_marker_dof_index.Size())
{
// Interpolate information only at DOFs marked for fitting.
const int dim = surf_fit_gf->FESpace()->GetMesh()->Dimension();
const int cnt = surf_fit_marker_dof_index.Size();
const int total_cnt = new_x.Size()/dim;
Vector new_x_sorted(cnt*dim);
if (new_x_ordering == 0)
{
for (int d = 0; d < dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
new_x_sorted(i + d*cnt) = new_x(dof_index + d*total_cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < dim; d++)
{
new_x_sorted(d + i*dim) = new_x(d + dof_index*dim);
}
}
}
// Interpolate values of the LS.
Vector surf_fit_gf_int, surf_fit_grad_int, surf_fit_hess_int;
surf_fit_eval->ComputeAtNewPosition(new_x_sorted, surf_fit_gf_int,
new_x_ordering);
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_gf)[dof_index] = surf_fit_gf_int(i);
}
// Interpolate gradients of the LS.
surf_fit_eval_grad->ComputeAtNewPosition(new_x_sorted, surf_fit_grad_int,
new_x_ordering);
// Assumes surf_fit_grad and surf_fit_gf share the same space
const int grad_dim = surf_fit_grad->VectorDim();
const int grad_cnt = surf_fit_grad->Size()/grad_dim;
if (surf_fit_grad->FESpace()->GetOrdering() == Ordering::byNODES)
{
for (int d = 0; d < grad_dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_grad)[dof_index + d*grad_cnt] =
surf_fit_grad_int(i + d*cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < grad_dim; d++)
{
(*surf_fit_grad)[dof_index*grad_dim + d] =
surf_fit_grad_int(i*grad_dim + d);
}
}
}
// Interpolate Hessians of the LS.
surf_fit_eval_hess->ComputeAtNewPosition(new_x_sorted, surf_fit_hess_int,
new_x_ordering);
// Assumes surf_fit_hess and surf_fit_gf share the same space
const int hess_dim = surf_fit_hess->VectorDim();
const int hess_cnt = surf_fit_hess->Size()/hess_dim;
if (surf_fit_hess->FESpace()->GetOrdering() == Ordering::byNODES)
{
for (int d = 0; d < hess_dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_hess)[dof_index + d*hess_cnt] =
surf_fit_hess_int(i + d*cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < hess_dim; d++)
{
(*surf_fit_hess)[dof_index*hess_dim + d] =
surf_fit_hess_int(i*hess_dim + d);
}
}
}
}
else
{
surf_fit_eval->ComputeAtNewPosition(new_x, *surf_fit_gf, new_x_ordering);
if (surf_fit_eval_grad)
{
surf_fit_eval_grad->ComputeAtNewPosition(new_x, *surf_fit_grad,
new_x_ordering);
}
if (surf_fit_eval_hess)
{
surf_fit_eval_hess->ComputeAtNewPosition(new_x, *surf_fit_hess,
new_x_ordering);
}
}
}
void TMOP_Integrator::
UpdateAfterMeshPositionChange(const Vector &x_new,
const FiniteElementSpace &x_fes)
@@ -4621,11 +4406,112 @@ UpdateAfterMeshPositionChange(const Vector &x_new,
adapt_lim_eval->ComputeAtNewPosition(x_new, *adapt_lim_gf, ordering);
}
// Update surf_fit_gf (and optionally its gradients) if surface
// fitting is enabled.
// Update surf_fit_gf if surface fitting is enabled.
if (surf_fit_gf)
{
RemapSurfaceFittingLevelSetAtNodes(x_new, ordering);
if (surf_fit_gf_bg)
{
// Interpolate information for only DOFs marked for fitting.
const int dim = surf_fit_gf->FESpace()->GetMesh()->Dimension();
const int cnt = surf_fit_marker_dof_index.Size();
const int total_cnt = x_new.Size()/dim;
Vector new_x_sorted(cnt*dim);
if (ordering == 0)
{
for (int d = 0; d < dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
new_x_sorted(i + d*cnt) = x_new(dof_index + d*total_cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < dim; d++)
{
new_x_sorted(d + i*dim) = x_new(d + dof_index*dim);
}
}
}
Vector surf_fit_gf_int, surf_fit_grad_int, surf_fit_hess_int;
surf_fit_eval->ComputeAtNewPosition(
new_x_sorted, surf_fit_gf_int, ordering);
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_gf)[dof_index] = surf_fit_gf_int(i);
}
surf_fit_eval_bg_grad->ComputeAtNewPosition(
new_x_sorted, surf_fit_grad_int, ordering);
// Assumes surf_fit_grad and surf_fit_gf share the same space
const int grad_dim = surf_fit_grad->VectorDim();
const int grad_cnt = surf_fit_grad->Size()/grad_dim;
if (surf_fit_grad->FESpace()->GetOrdering() == Ordering::byNODES)
{
for (int d = 0; d < grad_dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_grad)[dof_index + d*grad_cnt] =
surf_fit_grad_int(i + d*cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < grad_dim; d++)
{
(*surf_fit_grad)[dof_index*dim + d] =
surf_fit_grad_int(i*dim + d);
}
}
}
surf_fit_eval_bg_hess->ComputeAtNewPosition(
new_x_sorted, surf_fit_hess_int, ordering);
// Assumes surf_fit_hess and surf_fit_gf share the same space
const int hess_dim = surf_fit_hess->VectorDim();
const int hess_cnt = surf_fit_hess->Size()/hess_dim;
if (surf_fit_hess->FESpace()->GetOrdering() == Ordering::byNODES)
{
for (int d = 0; d < hess_dim; d++)
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
(*surf_fit_hess)[dof_index + d*hess_cnt] =
surf_fit_hess_int(i + d*cnt);
}
}
}
else
{
for (int i = 0; i < cnt; i++)
{
int dof_index = surf_fit_marker_dof_index[i];
for (int d = 0; d < hess_dim; d++)
{
(*surf_fit_hess)[dof_index*dim + d] =
surf_fit_hess_int(i*dim + d);
}
}
}
}
else
{
surf_fit_eval->ComputeAtNewPosition(x_new, *surf_fit_gf, ordering);
}
}
}
+10 -18
View File
@@ -1784,11 +1784,12 @@ protected:
// Fitting to given physical positions.
TMOP_QuadraticLimiter *surf_fit_limiter; // Owned. Created internally.
const GridFunction *surf_fit_pos; // Not owned. Positions to fit.
real_t surf_fit_normal; // Normalization factor.
GridFunction *surf_fit_grad, *surf_fit_hess; // Owned. Created internally.
AdaptivityEvaluator *surf_fit_eval_grad, *surf_fit_eval_hess; // Not owned.
Array<int> surf_fit_dof_count; // Number of dofs per node.
Array<int> surf_fit_marker_dof_index; // Indices of nodes to fit.
real_t surf_fit_normal;
bool surf_fit_gf_bg;
GridFunction *surf_fit_grad, *surf_fit_hess;
AdaptivityEvaluator *surf_fit_eval_bg_grad, *surf_fit_eval_bg_hess;
Array<int> surf_fit_dof_count;
Array<int> surf_fit_marker_dof_index;
DiscreteAdaptTC *discr_tc;
@@ -1984,10 +1985,6 @@ protected:
real_t ComputeUntanglerMaxMuBarrier(const Vector &x,
const FiniteElementSpace &fes);
// Remaps the internal surface fitting gridfunction object at provided
// locations.
void RemapSurfaceFittingLevelSetAtNodes(const Vector &new_x,
int new_x_ordering);
public:
/** @param[in] m TMOP_QualityMetric for r-adaptivity (not owned).
@param[in] tc Target-matrix construction algorithm to use (not owned).
@@ -2003,8 +2000,9 @@ public:
surf_fit_marker(NULL), surf_fit_coeff(NULL),
surf_fit_gf(NULL), surf_fit_eval(NULL),
surf_fit_limiter(NULL), surf_fit_pos(NULL),
surf_fit_normal(1.0), surf_fit_grad(NULL), surf_fit_hess(NULL),
surf_fit_eval_grad(NULL), surf_fit_eval_hess(NULL),
surf_fit_normal(1.0),
surf_fit_gf_bg(false), surf_fit_grad(NULL), surf_fit_hess(NULL),
surf_fit_eval_bg_grad(NULL), surf_fit_eval_bg_hess(NULL),
discr_tc(dynamic_cast<DiscreteAdaptTC *>(tc)),
fdflag(false), dxscale(1.0e3), fd_call_flag(false), exact_action(false)
{ PA.enabled = false; }
@@ -2105,15 +2103,9 @@ public:
#ifdef MFEM_USE_MPI
/// Parallel support for surface fitting to the zero level set of a function.
/// Here, we add two optional inputs: @a aegrad and @a aehess. When provided,
/// the first and second derivative of the input level set are computed on
/// the initial mesh, and @a aegrad and @a aehess are used to remap grad_s(x)
/// from grad_s0(x0) and hess_s(x) from hess_s0(x0), respectively.
void EnableSurfaceFitting(const ParGridFunction &s0,
const Array<bool> &smarker, Coefficient &coeff,
AdaptivityEvaluator &ae,
AdaptivityEvaluator *aegrad = NULL,
AdaptivityEvaluator *aehess = NULL);
AdaptivityEvaluator &ae);
/** @brief Fitting of certain DOFs in the current mesh to the zero level set
of a function defined on another (finer) source mesh.
+36 -88
View File
@@ -429,13 +429,11 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
#endif
real_t scale = 1.0;
bool fitting = IsSurfaceFittingEnabled();
real_t init_fit_avg_err, init_fit_max_err = 0.0;
if (fitting && surf_fit_converge_error)
real_t avg_surf_fit_err, max_surf_fit_err = 0.0;
if (surf_fit_max_threshold > 0.0)
{
GetSurfaceFittingError(x_out_loc, init_fit_avg_err, init_fit_max_err);
// Check for convergence
if (init_fit_max_err < surf_fit_max_err_limit)
GetSurfaceFittingError(x_out_loc, avg_surf_fit_err, max_surf_fit_err);
if (max_surf_fit_err < surf_fit_max_threshold)
{
if (print_options.iterations)
{
@@ -446,12 +444,11 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
return scale;
}
}
if (surf_fit_adapt_count >= surf_fit_adapt_count_limit)
if (adapt_inc_count >= max_adapt_inc_count)
{
if (print_options.iterations)
{
mfem::out << "TMOPNewtonSolver terminated "
mfem::out << "TMOPNewtonSolver converged "
"based on max number of times surface fitting weight can"
"be increased. \n";
}
@@ -470,7 +467,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
// reference to detect deteriorations.
MFEM_VERIFY(min_det_ptr != NULL, " Initial mesh was valid, but"
" intermediate mesh is invalid. Contact TMOP Developers.");
MFEM_VERIFY(min_detJ_limit == 0.0,
MFEM_VERIFY(min_detJ_threshold == 0.0,
"This setup is not supported. Contact TMOP Developers.");
*min_det_ptr = untangle_factor * min_detT_in;
}
@@ -481,7 +478,6 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
bool x_out_ok = false;
real_t energy_out = 0.0, min_detT_out;
const real_t norm_in = Norm(r);
real_t avg_fit_err, max_fit_err = 0.0;
const real_t detJ_factor = (solver_type == 1) ? 0.25 : 0.5;
compute_metric_quantile_flag = false;
@@ -492,9 +488,6 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
// Perform the line search.
for (int i = 0; i < 12; i++)
{
avg_fit_err = 0.0;
max_fit_err = 0.0;
// Update the mesh and get the L-vector in x_out_loc.
add(x, -scale, c, x_out);
if (serial)
@@ -509,7 +502,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
// Check the changes in detJ.
min_detT_out = ComputeMinDet(x_out_loc, *fes);
if (untangling == false && min_detT_out <= min_detJ_limit)
if (untangling == false && min_detT_out <= min_detJ_threshold)
{
// No untangling, and detJ got negative (or small) -- no good.
if (print_options.iterations)
@@ -536,19 +529,18 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
// Check the changes in total energy.
ProcessNewState(x_out);
// Ensure sufficient decrease in fitting error if we are trying to
// converge based on error.
if (fitting && surf_fit_converge_error)
real_t avg_fit_err, max_fit_err = 0.0;
if (surf_fit_max_threshold > 0.0)
{
GetSurfaceFittingError(x_out_loc, avg_fit_err, max_fit_err);
if (max_fit_err >= 1.2*init_fit_max_err)
}
if (surf_fit_max_threshold > 0.0 && max_fit_err >= 1.2*max_surf_fit_err)
{
if (print_options.iterations)
{
if (print_options.iterations)
{
mfem::out << "Scale = " << scale << " Surf fit err increased.\n";
}
scale *= 0.5; continue;
mfem::out << "Scale = " << scale << " Surf fit err increased.\n";
}
scale *= 0.5; continue;
}
if (serial)
@@ -622,7 +614,7 @@ real_t TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
if (x_out_ok == false) { scale = 0.0; }
if (surf_fit_scale_factor > 0.0) { surf_fit_coeff_update = true; }
if (surf_fit_scale_factor > 0.0) { update_surf_fit_coeff = true; }
compute_metric_quantile_flag = true;
return scale;
@@ -665,7 +657,7 @@ void TMOPNewtonSolver::GetSurfaceFittingWeight(Array<real_t> &weights) const
for (int i = 0; i < integs.Size(); i++)
{
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
if (ti && ti->IsSurfaceFittingEnabled())
if (ti)
{
weight = ti->GetSurfaceFittingWeight();
weights.Append(weight);
@@ -676,11 +668,8 @@ void TMOPNewtonSolver::GetSurfaceFittingWeight(Array<real_t> &weights) const
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
for (int j = 0; j < ati.Size(); j++)
{
if (ati[j]->IsSurfaceFittingEnabled())
{
weight = ati[j]->GetSurfaceFittingWeight();
weights.Append(weight);
}
weight = ati[j]->GetSurfaceFittingWeight();
weights.Append(weight);
}
}
}
@@ -727,39 +716,6 @@ void TMOPNewtonSolver::GetSurfaceFittingError(const Vector &x_loc,
}
}
bool TMOPNewtonSolver::IsSurfaceFittingEnabled() const
{
const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
const Array<NonlinearFormIntegrator*> &integs = *nlf->GetDNFI();
TMOP_Integrator *ti = NULL;
TMOPComboIntegrator *co = NULL;
for (int i = 0; i < integs.Size(); i++)
{
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
if (ti)
{
if (ti->IsSurfaceFittingEnabled())
{
return true;
}
}
co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
if (co)
{
Array<TMOP_Integrator *> ati = co->GetTMOPIntegrators();
for (int j = 0; j < ati.Size(); j++)
{
if (ati[j]->IsSurfaceFittingEnabled())
{
return true;
}
}
}
}
return false;
}
void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
{
const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
@@ -845,46 +801,38 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
// adaptive surface fitting is enabled. The idea is to increase the
// coefficient if the surface fitting error does not sufficiently
// decrease between subsequent TMOPNewtonSolver iterations.
if (surf_fit_coeff_update)
if (update_surf_fit_coeff)
{
// Get surface fitting errors.
GetSurfaceFittingError(x_loc, surf_fit_avg_err, surf_fit_max_err);
GetSurfaceFittingError(x_loc, surf_fit_err_avg, surf_fit_err_max);
// Get array with surface fitting weights.
Array<real_t> fitweights;
GetSurfaceFittingWeight(fitweights);
Array<real_t> weights;
GetSurfaceFittingWeight(weights);
if (print_options.iterations)
{
mfem::out << "Avg/Max surface fitting error: " <<
surf_fit_avg_err << " " <<
surf_fit_max_err << "\n";
surf_fit_err_avg << " " <<
surf_fit_err_max << "\n";
mfem::out << "Min/Max surface fitting weight: " <<
fitweights.Min() << " " << fitweights.Max() << "\n";
weights.Min() << " " << weights.Max() << "\n";
}
real_t change_surf_fit_err = surf_fit_avg_err_prvs-surf_fit_avg_err;
real_t rel_change_surf_fit_err = change_surf_fit_err/surf_fit_avg_err_prvs;
real_t change_surf_fit_err = surf_fit_err_avg_prvs-surf_fit_err_avg;
real_t rel_change_surf_fit_err = change_surf_fit_err/surf_fit_err_avg_prvs;
// Increase the surface fitting coefficient if the surface fitting error
// does not decrease sufficiently. If we are converging based on residual,
// also make sure we have not reached the maximum fitting weight and
// error threshold.
if (rel_change_surf_fit_err < surf_fit_err_rel_change_limit &&
(surf_fit_converge_error ||
(fitweights.Max() < surf_fit_weight_limit &&
surf_fit_max_err > surf_fit_max_err_limit)))
// does not decrease sufficiently.
if (rel_change_surf_fit_err < surf_fit_rel_change_threshold)
{
real_t scale_factor = std::min(surf_fit_scale_factor,
surf_fit_weight_limit/fitweights.Max());
UpdateSurfaceFittingWeight(scale_factor);
surf_fit_adapt_count += 1;
UpdateSurfaceFittingWeight(surf_fit_scale_factor);
adapt_inc_count += 1;
}
else
{
surf_fit_adapt_count = 0;
adapt_inc_count = 0;
}
surf_fit_avg_err_prvs = surf_fit_avg_err;
surf_fit_coeff_update = false;
surf_fit_err_avg_prvs = surf_fit_err_avg;
update_surf_fit_coeff = false;
}
}
+26 -87
View File
@@ -134,20 +134,18 @@ protected:
int solver_type;
bool parallel;
// Line search step is rejected if min(detJ) <= min_detJ_limit.
real_t min_detJ_limit = 0.0;
// Line search step is rejected if min(detJ) <= min_detJ_threshold.
real_t min_detJ_threshold = 0.0;
// Surface fitting variables.
mutable real_t surf_fit_avg_err_prvs = 10000.0;
mutable real_t surf_fit_avg_err, surf_fit_max_err;
mutable bool surf_fit_coeff_update = false;
real_t surf_fit_max_err_limit = -1.0;
real_t surf_fit_err_rel_change_limit = 0.001;
mutable real_t surf_fit_err_avg_prvs = 10000.0;
mutable real_t surf_fit_err_avg, surf_fit_err_max;
mutable bool update_surf_fit_coeff = false;
real_t surf_fit_max_threshold = -1.0;
real_t surf_fit_rel_change_threshold = 0.001;
real_t surf_fit_scale_factor = 0.0;
mutable int surf_fit_adapt_count = 0;
mutable int surf_fit_adapt_count_limit = 10;
mutable real_t surf_fit_weight_limit = 1e10;
bool surf_fit_converge_error = false;
mutable int adapt_inc_count = 0;
mutable int max_adapt_inc_count = 10;
// Minimum determinant over the whole mesh. Used for mesh untangling.
real_t *min_det_ptr = nullptr;
@@ -193,9 +191,6 @@ protected:
void GetSurfaceFittingWeight(Array<real_t> &weights) const;
///@}
/// Check if surface fitting is enabled.
bool IsSurfaceFittingEnabled() const;
public:
#ifdef MFEM_USE_MPI
TMOPNewtonSolver(MPI_Comm comm, const IntegrationRule &irule, int type = 0)
@@ -229,94 +224,38 @@ public:
/// (ii) surface fitting weight.
virtual void ProcessNewState(const Vector &x) const;
/** @name Methods for adaptive surface fitting.
\brief These methods control the behavior of the weight and the
termination of the solver. (Experimental)
Adaptive fitting weight: The weight is modified after each
TMOPNewtonSolver iteration as:
w_{k+1} = w_{k} * \ref surf_fit_scale_factor if the relative
change in average fitting error < \ref surf_fit_err_rel_change_limit.
When converging based on the residual, we enforce the fitting weight
to be at-most \ref surf_fit_weight_limit, and increase it only if the
fitting error is below user prescribed threshold
(\ref surf_fit_max_err_limit).
See \ref SetAdaptiveSurfaceFittingScalingFactor and
\ref SetAdaptiveSurfaceFittingRelativeChangeThreshold.
Note that the solver stops if the maximum surface fitting error
does not sufficiently decrease for \ref surf_fit_adapt_count_limit (default 10)
consecutive increments of the fitting weight during weight adaptation.
This typically occurs when the mesh cannot align with the level-set
without degrading element quality.
See \ref SetMaxNumberofIncrementsForAdaptiveFitting.
Convergence criterion: There are two modes, residual- and error-based,
which can be toggled using \ref SetSurfaceFittingConvergenceBasedOnError.
(i) Residual based (default): Stop when the norm of the gradient of the
TMOP objective reaches the prescribed tolerance. This method is best used
with a reasonable value for \ref surf_fit_weight_limit when the
adaptive surface fitting scheme is used. See method
\ref SetSurfaceFittingWeightLimit.
(ii) Error based: Stop when the maximum fitting error
reaches the user-prescribed threshold, \ref surf_fit_max_err_limit.
In this case, \ref surf_fit_weight_limit is ignored during weight
adaptation.
*/
///@{
/** @name Methods for adaptive surface fitting weight. (Experimental) */
/// Enable/Disable adaptive surface fitting weight.
/// The weight is modified after each TMOPNewtonSolver iteration as:
/// w_{k+1} = w_{k} * @a surf_fit_scale_factor if relative change in
/// max surface fitting error < @a surf_fit_rel_change_threshold.
/// The solver terminates if the maximum surface fitting error does
/// not sufficiently decrease for @a max_adapt_inc_count consecutive
/// solver iterations or if the max error falls below @a surf_fit_max_threshold.
void EnableAdaptiveSurfaceFitting()
{
surf_fit_scale_factor = 10.0;
surf_fit_rel_change_threshold = 0.001;
}
void SetAdaptiveSurfaceFittingScalingFactor(real_t factor)
{
MFEM_VERIFY(factor > 1.0, "Scaling factor must be greater than 1.");
surf_fit_scale_factor = factor;
}
void SetAdaptiveSurfaceFittingRelativeChangeThreshold(real_t threshold)
{
surf_fit_err_rel_change_limit = threshold;
surf_fit_rel_change_threshold = threshold;
}
/// Used for stopping based on the number of consecutive failed weight
/// adaptation iterations.
// TODO: Rename to SetMaxNumberofIncrementsForAdaptiveSurfaceFitting
// in future.
void SetMaxNumberofIncrementsForAdaptiveFitting(int count)
{
surf_fit_adapt_count_limit = count;
max_adapt_inc_count = count;
}
/// Used for error-based surface fitting termination.
void SetTerminationWithMaxSurfaceFittingError(real_t max_error)
{
surf_fit_max_err_limit = max_error;
surf_fit_converge_error = true;
surf_fit_max_threshold = max_error;
}
/// Could be used with both error-based or residual-based convergence.
void SetSurfaceFittingMaxErrorLimit(real_t max_error)
{
surf_fit_max_err_limit = max_error;
}
/// Used for residual-based surface fitting termination.
void SetSurfaceFittingWeightLimit(real_t weight)
{
surf_fit_weight_limit = weight;
}
/// Toggle convergence based on residual or error.
void SetSurfaceFittingConvergenceBasedOnError(bool mode)
{
surf_fit_converge_error = mode;
if (surf_fit_converge_error)
{
MFEM_VERIFY(surf_fit_max_err_limit >= 0,
"Fitting error based convergence requires the user to "
"first set the error threshold."
"See SetTerminationWithMaxSurfaceFittingError");
}
}
///@}
/// Set minimum determinant enforced during line-search.
void SetMinimumDeterminantThreshold(real_t threshold)
{
min_detJ_limit = threshold;
min_detJ_threshold = threshold;
}
virtual void Mult(const Vector &b, Vector &x) const
-2
View File
@@ -1233,8 +1233,6 @@ void PRefinementTransferOperator::Mult(const Vector& x, Vector& y) const
int vdim = lFESpace.GetVDim();
y = 0.0;
for (int i = 0; i < mesh->GetNE(); i++)
{
DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
+2 -2
View File
@@ -63,9 +63,9 @@
#define MFEM_FOREACH_THREAD(i,k,N) for(int i=0; i<N; i++)
#endif
// 'double' and 'float' atomicAdd implementation for previous versions of CUDA
// 'double' atomicAdd implementation for previous versions of CUDA
#if defined(MFEM_USE_CUDA) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600
MFEM_DEVICE inline mfem::real_t atomicAdd(mfem::real_t *add, mfem::real_t val)
MFEM_DEVICE inline real_t atomicAdd(real_t *add, real_t val)
{
unsigned long long int *ptr = (unsigned long long int *) add;
unsigned long long int old = *ptr, reg;
+1 -1
View File
@@ -51,7 +51,7 @@ int isockstream::establish()
{
// char myname[129];
char myname[] = "localhost";
int sfd = -1;
int sfd;
struct addrinfo hints, *res, *rp;
memset(&hints, 0, sizeof(hints));
+2 -2
View File
@@ -134,7 +134,7 @@ int socketbuf::open(const char hostname[], int port)
{
closesocket(socket_descriptor);
socket_descriptor = -2;
continue;
return -1;
}
#endif
@@ -148,7 +148,7 @@ int socketbuf::open(const char hostname[], int port)
}
freeaddrinfo(res);
return (socket_descriptor < 0) ? -1 : 0;
return 0;
}
int socketbuf::close()
-72
View File
@@ -37,78 +37,6 @@ Table::Table(const Table &table)
}
}
Table::Table(const Table &table1,
const Table &table2, int offset)
{
MFEM_ASSERT(table1.size == table2.size,
"Tables have different sizes can not merge.");
size = table1.size;
const int nnz = table1.I[size] + table2.I[size];
I.New(size+1, table1.I.GetMemoryType());
J.New(nnz, table1.J.GetMemoryType());
I[0] = 0;
Array<int> row;
for (int i = 0; i < size; i++)
{
I[i+1] = I[i];
table1.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = row[r];
}
table2.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset : row[r] + offset;
}
}
}
Table::Table(const Table &table1,
const Table &table2, int offset2,
const Table &table3, int offset3)
{
MFEM_ASSERT(table1.size == table2.size,
"Tables have different sizes can not merge.");
MFEM_ASSERT(table1.size == table3.size,
"Tables have different sizes can not merge.");
size = table1.size;
const int nnz = table1.I[size] + table2.I[size] + table3.I[size];
I.New(size+1, table1.I.GetMemoryType());
J.New(nnz, table1.J.GetMemoryType());
I[0] = 0;
Array<int> row;
for (int i = 0; i < size; i++)
{
I[i+1] = I[i];
table1.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = row[r];
}
table2.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset2 : row[r] + offset2;
}
table3.GetRow(i, row);
for (int r = 0; r < row.Size(); r++, I[i+1] ++)
{
J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset3 : row[r] + offset3;
}
}
}
Table& Table::operator=(const Table &rhs)
{
Clear();
-8
View File
@@ -58,14 +58,6 @@ public:
/// Copy constructor
Table(const Table &);
/** Merge constructors
This is used to combine two or three tables into one table.*/
Table(const Table &table1,
const Table &table2, int offset2);
Table(const Table &table1,
const Table &table2, int offset2,
const Table &table3, int offset3);
/// Assignment operator: deep copy
Table& operator=(const Table &rhs);
-1
View File
@@ -44,7 +44,6 @@ list(APPEND HDRS
handle.hpp
invariants.hpp
kernels.hpp
lapack.hpp
linalg.hpp
matrix.hpp
ode.hpp
+138 -20
View File
@@ -10,9 +10,60 @@
// CONTRIBUTING.md for details.
#include "complex_densemat.hpp"
#include "lapack.hpp"
#include <complex>
#ifdef MFEM_USE_LAPACK
#ifdef MFEM_USE_SINGLE
extern "C" void
cgetrf_(int *, int *, std::complex<float> *, int *, int *, int *);
extern "C" void
cgetrs_(char *, int *, int *, std::complex<float> *, int *, int *,
std::complex<float> *, int *, int *);
extern "C" void
cgetri_(int *, std::complex<float> *, int *, int *,
std::complex<float> *, int *, int *);
extern "C" void
ctrsm_(char *, char *, char *, char *, int *, int *, std::complex<float> *,
std::complex<float> *, int *, std::complex<float> *, int *);
extern "C" void
cpotrf_(char *, int *, std::complex<float> *, int *, int *);
extern "C" void
ctrtrs_(char *, char*, char *, int *, int *, std::complex<float> *, int *,
std::complex<float> *, int *, int *);
extern "C" void
cpotri_(char *, int *, std::complex<float> *, int*, int *);
extern "C" void
cpotrs_(char *, int *, int *, std::complex<float> *, int *,
std::complex<float> *, int *, int *);
#elif defined MFEM_USE_DOUBLE
extern "C" void
zgetrf_(int *, int *, std::complex<double> *, int *, int *, int *);
extern "C" void
zgetrs_(char *, int *, int *, std::complex<double> *, int *, int *,
std::complex<double> *, int *, int *);
extern "C" void
zgetri_(int *, std::complex<double> *, int *, int *,
std::complex<double> *, int *, int *);
extern "C" void
ztrsm_(char *, char *, char *, char *, int *, int *, std::complex<double> *,
std::complex<double> *, int *, std::complex<double> *, int *);
extern "C" void
zpotrf_(char *, int *, std::complex<double> *, int *, int *);
extern "C" void
ztrtrs_(char *, char*, char *, int *, int *, std::complex<double> *, int *,
std::complex<double> *, int *, int *);
extern "C" void
zpotri_(char *, int *, std::complex<double> *, int*, int *);
extern "C" void
zpotrs_(char *, int *, int *, std::complex<double> *, int *,
std::complex<double> *, int *, int *);
#endif
#endif
namespace mfem
{
@@ -124,17 +175,35 @@ ComplexDenseMatrix * ComplexDenseMatrix::ComputeInverse()
std::complex<real_t> qwork, *work;
int info;
MFEM_LAPACK_COMPLEX(getrf_)(&w, &w, data, &w, ipiv, &info);
#ifdef MFEM_USE_SINGLE
cgetrf_(&w, &w, data, &w, ipiv, &info);
#elif defined MFEM_USE_DOUBLE
zgetrf_(&w, &w, data, &w, ipiv, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (info)
{
mfem_error("DenseMatrix::Invert() : Error in ZGETRF");
}
MFEM_LAPACK_COMPLEX(getri_)(&w, data, &w, ipiv, &qwork, &lwork, &info);
#ifdef MFEM_USE_SINGLE
cgetri_(&w, data, &w, ipiv, &qwork, &lwork, &info);
#elif defined MFEM_USE_DOUBLE
zgetri_(&w, data, &w, ipiv, &qwork, &lwork, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
lwork = (int) qwork.real();
work = new std::complex<real_t>[lwork];
MFEM_LAPACK_COMPLEX(getri_)(&w, data, &w, ipiv, work, &lwork, &info);
#ifdef MFEM_USE_SINGLE
cgetri_(&w, data, &w, ipiv, work, &lwork, &info);
#elif defined MFEM_USE_DOUBLE
zgetri_(&w, data, &w, ipiv, work, &lwork, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
if (info)
{
mfem_error("DenseMatrix::Invert() : Error in ZGETRI");
@@ -424,7 +493,11 @@ bool ComplexLUFactors::Factor(int m, real_t TOL)
#ifdef MFEM_USE_LAPACK
int info = 0;
MFEM_VERIFY(data, "Matrix data not set");
if (m) { MFEM_LAPACK_COMPLEX(getrf_)(&m, &m, data, &m, ipiv, &info); }
#ifdef MFEM_USE_SINGLE
if (m) { cgetrf_(&m, &m, data, &m, ipiv, &info); }
#elif defined MFEM_USE_DOUBLE
if (m) { zgetrf_(&m, &m, data, &m, ipiv, &info); }
#endif
return info == 0;
#else
// compiling without LAPACK
@@ -586,10 +659,13 @@ void ComplexLUFactors::Solve(int m, int n, real_t *X_r, real_t * X_i) const
std::complex<real_t> * x = ComplexFactors::RealToComplex(m*n,X_r,X_i);
char trans = 'N';
int info = 0;
if (m > 0 && n > 0)
{
MFEM_LAPACK_COMPLEX(getrs_)(&trans, &m, &n, data, &m, ipiv, x, &m, &info);
}
#ifdef MFEM_USE_SINGLE
if (m > 0 && n > 0) { cgetrs_(&trans, &m, &n, data, &m, ipiv, x, &m, &info); }
#elif defined MFEM_USE_DOUBLE
if (m > 0 && n > 0) { zgetrs_(&trans, &m, &n, data, &m, ipiv, x, &m, &info); }
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "LAPACK: error in ZGETRS");
ComplexFactors::ComplexToReal(m*n,x,X_r,X_i);
delete [] x;
@@ -609,8 +685,15 @@ void ComplexLUFactors::RightSolve(int m, int n, real_t *X_r, real_t * X_i) const
if (m > 0 && n > 0)
{
std::complex<real_t> alpha(1.0,0.0);
MFEM_LAPACK_COMPLEX(trsm_)(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
MFEM_LAPACK_COMPLEX(trsm_)(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#ifdef MFEM_USE_SINGLE
ctrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
ctrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#elif defined MFEM_USE_DOUBLE
ztrsm_(&side,&u_ch,&n_ch,&n_ch,&n,&m,&alpha,data,&m,X,&n);
ztrsm_(&side,&l_ch,&n_ch,&u_ch,&n,&m,&alpha,data,&m,X,&n);
#else
MFEM_ABORT("Floating point type undefined");
#endif
}
#else
// compiling without LAPACK
@@ -732,7 +815,13 @@ bool ComplexCholeskyFactors::Factor(int m, real_t TOL)
int info = 0;
char uplo = 'L';
MFEM_VERIFY(data, "Matrix data not set");
if (m) { MFEM_LAPACK_COMPLEX(potrf_)(&uplo, &m, data, &m, &info); }
#ifdef MFEM_USE_SINGLE
if (m) {cpotrf_(&uplo, &m, data, &m, &info);}
#elif defined MFEM_USE_DOUBLE
if (m) {zpotrf_(&uplo, &m, data, &m, &info);}
#else
MFEM_ABORT("Floating point type undefined");
#endif
return info == 0;
#else
// CholeskyCrout algorithm
@@ -832,8 +921,13 @@ void ComplexCholeskyFactors::LSolve(int m, int n, real_t * X_r,
char diag = 'N';
int info = 0;
MFEM_LAPACK_COMPLEX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, x, &m,
&info);
#ifdef MFEM_USE_SINGLE
ctrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#elif defined MFEM_USE_DOUBLE
ztrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "ComplexCholeskyFactors:LSolve:: info");
#else
for (int k = 0; k < n; k++)
@@ -866,8 +960,13 @@ void ComplexCholeskyFactors::USolve(int m, int n, real_t * X_r,
char diag = 'N';
int info = 0;
MFEM_LAPACK_COMPLEX(trtrs_)(&uplo, &trans, &diag, &m, &n, data, &m, x, &m,
&info);
#ifdef MFEM_USE_SINGLE
ctrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#elif defined MFEM_USE_DOUBLE
ztrtrs_(&uplo, &trans, &diag, &m, &n, data, &m, x, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "ComplexCholeskyFactors:USolve:: info");
#else
// X <- L^{-t} X
@@ -895,7 +994,13 @@ void ComplexCholeskyFactors::Solve(int m, int n, real_t * X_r,
char uplo = 'L';
int info = 0;
std::complex<real_t> *x = ComplexFactors::RealToComplex(m*n,X_r,X_i);
MFEM_LAPACK_COMPLEX(potrs_)(&uplo, &m, &n, data, &m, x, &m, &info);
#ifdef MFEM_USE_SINGLE
cpotrs_(&uplo, &m, &n, data, &m, x, &m, &info);
#elif defined MFEM_USE_DOUBLE
zpotrs_(&uplo, &m, &n, data, &m, x, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "ComplexCholeskyFactors:Solve:: info");
ComplexFactors::ComplexToReal(m*n,x,X_r,X_i);
delete x;
@@ -921,8 +1026,15 @@ void ComplexCholeskyFactors::RightSolve(int m, int n, real_t * X_r,
std::complex<real_t> alpha(1.0,0.0);
if (m > 0 && n > 0)
{
MFEM_LAPACK_COMPLEX(trsm_)(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
MFEM_LAPACK_COMPLEX(trsm_)(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
#ifdef MFEM_USE_SINGLE
ctrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
ctrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
#elif defined MFEM_USE_DOUBLE
ztrsm_(&side,&uplo,&transt,&diag,&n,&m,&alpha,data,&m,x,&n);
ztrsm_(&side,&uplo,&trans,&diag,&n,&m,&alpha,data,&m,x,&n);
#else
MFEM_ABORT("Floating point type undefined");
#endif
}
#else
// X <- X L^{-H}
@@ -973,7 +1085,13 @@ void ComplexCholeskyFactors::GetInverseMatrix(int m, real_t * X_r,
}
char uplo = 'L';
int info = 0;
MFEM_LAPACK_COMPLEX(potri_)(&uplo, &m, X, &m, &info);
#ifdef MFEM_USE_SINGLE
cpotri_(&uplo, &m, X, &m, &info);
#elif defined MFEM_USE_DOUBLE
zpotri_(&uplo, &m, X, &m, &info);
#else
MFEM_ABORT("Floating point type undefined");
#endif
MFEM_VERIFY(!info, "ComplexCholeskyFactors:GetInverseMatrix:: info");
// fill in the upper triangular part
for (int i = 0; i<m; i++)
+522 -538
View File
File diff suppressed because it is too large Load Diff
+8 -28
View File
@@ -207,10 +207,6 @@ public:
/// Replaces the current matrix with its square root inverse
void SquareRootInverse();
/// Replaces the current matrix with its exponential
/// (currently only supports 2x2 matrices)
void Exponential();
/// Calculates the determinant of the matrix
/// (optimized for 2x2, 3x3, and 4x4 matrices)
real_t Det() const;
@@ -272,51 +268,35 @@ public:
/// Compute the square of the Frobenius norm of the matrix
real_t FNorm2() const { real_t s, n2; FNorm(s, n2); return s*s*n2; }
/** Compute eigenvalues of A x = ev x where A = *this
A is assumed to be symmetric. */
/// Compute eigenvalues of A x = ev x where A = *this
void Eigenvalues(Vector &ev)
{ Eigensystem(ev); }
/** Compute ith eigenvalue of A x = ev x where A = *this
A is assumed to be symmetric. */
real_t Eigenvalue(int i = -1);
/** Compute eigenvalues and eigenvectors of A x = ev x where A = *this
A is assumed to be symmetric. */
/// Compute eigenvalues and eigenvectors of A x = ev x where A = *this
void Eigenvalues(Vector &ev, DenseMatrix &evect)
{ Eigensystem(ev, &evect); }
/** Compute eigenvalues and eigenvectors of A x = ev x where A = *this
A is assumed to be symmetric. */
/// Compute eigenvalues and eigenvectors of A x = ev x where A = *this
void Eigensystem(Vector &ev, DenseMatrix &evect)
{ Eigensystem(ev, &evect); }
/** Compute generalized eigenvalues of A x = ev B x, where A = *this
A and B are assumed to be symmetric. */
/** Compute generalized eigenvalues and eigenvectors of A x = ev B x,
where A = *this */
void Eigenvalues(DenseMatrix &b, Vector &ev)
{ Eigensystem(b, ev); }
/** Compute ith eigenvalue of A x = ev B x where A = *this
A and B are assumed to be symmetric. */
real_t Eigenvalue(DenseMatrix &b, int i = -1);
/** Compute generalized eigenvalues and eigenvectors of A x = ev B x,
where A = *this. A and B are assumed to be symmetric.*/
/// Compute generalized eigenvalues of A x = ev B x, where A = *this
void Eigenvalues(DenseMatrix &b, Vector &ev, DenseMatrix &evect)
{ Eigensystem(b, ev, &evect); }
/** Compute generalized eigenvalues and eigenvectors of A x = ev B x,
where A = *this. A and B are assumed to be symmetric.*/
where A = *this */
void Eigensystem(DenseMatrix &b, Vector &ev, DenseMatrix &evect)
{ Eigensystem(b, ev, &evect); }
void SingularValues(Vector &sv) const;
int Rank(real_t tol) const;
/** Compute the Null Space of the matrix, such that A x = 0,
where A = *this* and x is a column of ns */
void NullSpace(DenseMatrix &ns, real_t tol);
/// Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
real_t CalcSingularvalue(const int i) const;
@@ -338,6 +318,7 @@ public:
void SetCol(int c, const real_t* col);
void SetCol(int c, const Vector &col);
/// Set all entries of a row to the specified value.
void SetRow(int row, real_t value);
/// Set all entries of a column to the specified value.
@@ -361,7 +342,6 @@ public:
void Transpose(const DenseMatrix &A);
/// (*this) = 1/2 ((*this) + (*this)^t)
void Symmetrize();
bool IsSymmetric(real_t tol = 1e-10);
void Lump();
+66 -70
View File
@@ -410,19 +410,19 @@ HYPRE_Int HypreParVector::Randomize(HYPRE_Int seed)
return hypre_ParVectorSetRandomValues(x,seed);
}
void HypreParVector::Print(const std::string &fname) const
void HypreParVector::Print(const char *fname) const
{
hypre_ParVectorPrint(x, fname.c_str());
hypre_ParVectorPrint(x,fname);
}
void HypreParVector::Read(MPI_Comm comm, const std::string &fname)
void HypreParVector::Read(MPI_Comm comm, const char *fname)
{
if (own_ParVector)
{
hypre_ParVectorDestroy(x);
}
data.Delete();
x = hypre_ParVectorRead(comm, fname.c_str());
x = hypre_ParVectorRead(comm, fname);
own_ParVector = true;
_SetDataAndSize_();
}
@@ -792,44 +792,6 @@ static void SyncBackBoolCSR(Table *bool_csr, MemoryIJData &mem_csr)
}
}
/// @brief Return the size of the partitioning arrays, see @ref
/// hypre_partitioning_descr.
static int GetPartitioningArraySize(MPI_Comm comm)
{
if (HYPRE_AssumedPartitionCheck())
{
return 2;
}
else
{
int comm_size;
MPI_Comm_size(comm, &comm_size);
return comm_size + 1;
}
}
/// @brief Returns true if the row and col arrays are equal (across all MPI
/// ranks).
///
/// Both @a row and @a col are partitioning arrays, whose length is returned by
/// GetPartitioningArraySize(), see @ref hypre_partitioning_descr.
static bool RowAndColStartsAreEqual(MPI_Comm comm, HYPRE_BigInt *rows,
HYPRE_BigInt *cols)
{
const int part_size = GetPartitioningArraySize(comm);
bool are_equal = true;
for (int i = 0; i < part_size; ++i)
{
if (rows[i] != cols[i])
{
are_equal = false;
break;
}
}
MPI_Allreduce(MPI_IN_PLACE, &are_equal, 1, MPI_C_BOOL, MPI_LAND, comm);
return are_equal;
}
// static method
signed char HypreParMatrix::HypreCsrToMem(hypre_CSRMatrix *h_mat,
MemoryType h_mat_mt,
@@ -962,7 +924,7 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
hypre_ParCSRMatrixSetNumNonzeros(A);
/* Make sure that the first entry in each row is the diagonal one. */
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
if (row_starts == col_starts)
{
HypreReadWrite();
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
@@ -1012,12 +974,11 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
hypre_ParCSRMatrixSetNumNonzeros(A);
/* Make sure that the first entry in each row is the diagonal one. */
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
if (row_starts == col_starts)
{
HypreReadWrite();
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
// update diag, if needed
if (!own_diag_offd) { SyncBackCSR(diag, mem_diag); }
SyncBackCSR(diag, mem_diag); // update diag, if needed
}
hypre_MatvecCommPkgCreate(A);
@@ -1070,7 +1031,7 @@ HypreParMatrix::HypreParMatrix(
hypre_ParCSRMatrixSetNumNonzeros(A);
/* Make sure that the first entry in each row is the diagonal one. */
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
if (row_starts == col_starts)
{
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
}
@@ -1132,7 +1093,7 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
hypre_CSRMatrixDestroy(csr_a);
/* Make sure that the first entry in each row is the diagonal one. */
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
if (row_starts == col_starts)
{
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(new_A));
}
@@ -1171,7 +1132,7 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
hypre_ParCSRMatrixSetNumNonzeros(A);
/* Make sure that the first entry in each row is the diagonal one. */
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
if (row_starts == col_starts)
{
HypreReadWrite();
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
@@ -1286,10 +1247,11 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
Init();
// Determine partitioning size, and my column start and end
const int part_size = GetPartitioningArraySize(comm);
int part_size;
HYPRE_BigInt my_col_start, my_col_end; // my range: [my_col_start, my_col_end)
if (HYPRE_AssumedPartitionCheck())
{
part_size = 2;
my_col_start = cols[0];
my_col_end = cols[1];
}
@@ -1297,14 +1259,15 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
{
int myid;
MPI_Comm_rank(comm, &myid);
MPI_Comm_size(comm, &part_size);
part_size++;
my_col_start = cols[myid];
my_col_end = cols[myid+1];
}
// Copy in the row and column partitionings
const bool rows_eq_cols = RowAndColStartsAreEqual(comm, rows, cols);
HYPRE_BigInt *row_starts, *col_starts;
if (rows_eq_cols)
if (rows == cols)
{
row_starts = col_starts = mfem_hypre_TAlloc_host(HYPRE_BigInt, part_size);
for (int i = 0; i < part_size; i++)
@@ -1397,14 +1360,14 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
}
hypre_ParCSRMatrixSetNumNonzeros(A);
// Make sure that the first entry in each row is the diagonal one.
if (rows_eq_cols)
/* Make sure that the first entry in each row is the diagonal one. */
if (row_starts == col_starts)
{
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
}
#if MFEM_HYPRE_VERSION > 22200
mfem_hypre_TFree_host(row_starts);
if (!rows_eq_cols)
if (rows != cols)
{
mfem_hypre_TFree_host(col_starts);
}
@@ -1517,7 +1480,16 @@ void HypreParMatrix::CopyRowStarts()
return;
}
const int row_starts_size = GetPartitioningArraySize(hypre_ParCSRMatrixComm(A));
int row_starts_size;
if (HYPRE_AssumedPartitionCheck())
{
row_starts_size = 2;
}
else
{
MPI_Comm_size(hypre_ParCSRMatrixComm(A), &row_starts_size);
row_starts_size++; // num_proc + 1
}
HYPRE_BigInt *old_row_starts = hypre_ParCSRMatrixRowStarts(A);
HYPRE_BigInt *new_row_starts = mfem_hypre_CTAlloc_host(HYPRE_BigInt,
@@ -1548,7 +1520,16 @@ void HypreParMatrix::CopyColStarts()
return;
}
const int col_starts_size = GetPartitioningArraySize(hypre_ParCSRMatrixComm(A));
int col_starts_size;
if (HYPRE_AssumedPartitionCheck())
{
col_starts_size = 2;
}
else
{
MPI_Comm_size(hypre_ParCSRMatrixComm(A), &col_starts_size);
col_starts_size++; // num_proc + 1
}
HYPRE_BigInt *old_col_starts = hypre_ParCSRMatrixColStarts(A);
HYPRE_BigInt *new_col_starts = mfem_hypre_CTAlloc_host(HYPRE_BigInt,
@@ -2310,8 +2291,13 @@ void HypreParMatrix::Threshold(real_t threshold)
A = parcsr_A_ptr;
hypre_ParCSRMatrixSetNumNonzeros(A);
// Make sure that the first entry in each row is the diagonal one.
if (RowAndColStartsAreEqual(comm, row_starts, col_starts))
/* Make sure that the first entry in each row is the diagonal one. */
#if MFEM_HYPRE_VERSION <= 22200
if (row_starts == col_starts)
#else
if ((row_starts[0] == col_starts[0]) &&
(row_starts[1] == col_starts[1]))
#endif
{
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
}
@@ -2637,38 +2623,48 @@ void HypreParMatrix::EliminateBC(const Array<int> &ess_dofs,
mfem_hypre_TFree(eliminate_col);
}
void HypreParMatrix::Print(const std::string &fname, HYPRE_Int offi,
void HypreParMatrix::Print(const char *fname, HYPRE_Int offi,
HYPRE_Int offj) const
{
HostRead();
hypre_ParCSRMatrixPrintIJ(A, offi, offj, fname.c_str());
hypre_ParCSRMatrixPrintIJ(A,offi,offj,fname);
HypreRead();
}
void HypreParMatrix::Read(MPI_Comm comm, const std::string &fname)
void HypreParMatrix::Read(MPI_Comm comm, const char *fname)
{
HYPRE_ParCSRMatrix A_parcsr;
Destroy();
Init();
HYPRE_Int base_i, base_j;
hypre_ParCSRMatrixReadIJ(comm, fname.c_str(), &base_i, &base_j, &A_parcsr);
WrapHypreParCSRMatrix(A_parcsr, true);
hypre_ParCSRMatrixReadIJ(comm, fname, &base_i, &base_j, &A);
hypre_ParCSRMatrixSetNumNonzeros(A);
if (!hypre_ParCSRMatrixCommPkg(A)) { hypre_MatvecCommPkgCreate(A); }
height = GetNumRows();
width = GetNumCols();
}
void HypreParMatrix::Read_IJMatrix(MPI_Comm comm, const std::string &fname)
void HypreParMatrix::Read_IJMatrix(MPI_Comm comm, const char *fname)
{
Destroy();
Init();
HYPRE_IJMatrix A_ij;
HYPRE_IJMatrixRead(fname.c_str(), comm, 5555, &A_ij); // HYPRE_PARCSR = 5555
HYPRE_IJMatrixRead(fname, comm, 5555, &A_ij); // HYPRE_PARCSR = 5555
HYPRE_ParCSRMatrix A_parcsr;
HYPRE_IJMatrixGetObject(A_ij, (void**) &A_parcsr);
WrapHypreParCSRMatrix(A_parcsr, true);
A = (hypre_ParCSRMatrix*)A_parcsr;
hypre_ParCSRMatrixSetNumNonzeros(A);
if (!hypre_ParCSRMatrixCommPkg(A)) { hypre_MatvecCommPkgCreate(A); }
height = GetNumRows();
width = GetNumCols();
}
void HypreParMatrix::PrintCommPkg(std::ostream &os) const
+6 -8
View File
@@ -364,10 +364,10 @@ public:
HYPRE_Int Randomize(HYPRE_Int seed);
/// Prints the locally owned rows in parallel
void Print(const std::string &fname) const;
void Print(const char *fname) const;
/// Reads a HypreParVector from files saved with HypreParVector::Print
void Read(MPI_Comm comm, const std::string &fname);
void Read(MPI_Comm comm, const char *fname);
/// Calls hypre's destroy function
~HypreParVector();
@@ -919,14 +919,12 @@ public:
const Memory<HYPRE_Int> &GetDiagMemoryJ() const { return mem_diag.J; }
const Memory<real_t> &GetDiagMemoryData() const { return mem_diag.data; }
/// @brief Prints the locally owned rows in parallel. The resulting files can
/// be read with Read_IJMatrix().
void Print(const std::string &fname, HYPRE_Int offi = 0,
HYPRE_Int offj = 0) const;
/// Prints the locally owned rows in parallel
void Print(const char *fname, HYPRE_Int offi = 0, HYPRE_Int offj = 0) const;
/// Reads the matrix from a file
void Read(MPI_Comm comm, const std::string &fname);
void Read(MPI_Comm comm, const char *fname);
/// Read a matrix saved as a HYPRE_IJMatrix
void Read_IJMatrix(MPI_Comm comm, const std::string &fname);
void Read_IJMatrix(MPI_Comm comm, const char *fname);
/// Print information about the hypre_ParCSRCommPkg of the HypreParMatrix.
void PrintCommPkg(std::ostream &out = mfem::out) const;
-141
View File
@@ -1,141 +0,0 @@
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_LAPACK_HPP
#define MFEM_LAPACK_HPP
#include "../config/config.hpp"
#ifdef MFEM_USE_LAPACK
#ifdef MFEM_USE_SINGLE
#define MFEM_LAPACK_PREFIX(stub) s##stub
#define MFEM_LAPACK_COMPLEX(stub) c##stub
#elif defined(MFEM_USE_DOUBLE)
#define MFEM_LAPACK_PREFIX(stub) d##stub
#define MFEM_LAPACK_COMPLEX(stub) z##stub
#endif
namespace mfem
{
extern "C" void
MFEM_LAPACK_PREFIX(gemm_)(char *, char *, int *, int *, int *, real_t *,
real_t *, int *, real_t *, int *, real_t *, real_t *,
int *);
extern "C" void
MFEM_LAPACK_PREFIX(getrf_)(int *, int *, real_t *, int *, int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(getrs_)(char *, int *, int *, real_t *, int *, int *,
real_t *, int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(getri_)(int *N, real_t *A, int *LDA, int *IPIV, real_t *WORK,
int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(syevr_)(char *JOBZ, char *RANGE, char *UPLO, int *N,
real_t *A, int *LDA, real_t *VL, real_t *VU, int *IL,
int *IU, real_t *ABSTOL, int *M, real_t *W,
real_t *Z, int *LDZ, int *ISUPPZ, real_t *WORK,
int *LWORK, int *IWORK, int *LIWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(syev_)(char *JOBZ, char *UPLO, int *N, real_t *A, int *LDA,
real_t *W, real_t *WORK, int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(sygv_) (int *ITYPE, char *JOBZ, char *UPLO, int * N,
real_t *A, int *LDA, real_t *B, int *LDB, real_t *W,
real_t *WORK, int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(sygvx_)(int *ITYPE, char *JOBZ, char *RANGE, char *UPLO,
int *N, double *A, int *LDA, double *B, int *LDB,
double *VL, double *VU, int *IL, int *IU,
double *ABSTOL, int *M, double *W, double *Z,
int *LDZ, double *WORK, int *LWORK,int *IWORK,
int *IFAIL, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(gesvd_)(char *JOBU, char *JOBVT, int *M, int *N, real_t *A,
int *LDA, real_t *S, real_t *U, int *LDU, real_t *VT,
int *LDVT, real_t *WORK, int *LWORK, int *INFO);
extern "C" void
MFEM_LAPACK_PREFIX(trsm_)(char *side, char *uplo, char *transa, char *diag,
int *m, int *n, real_t *alpha, real_t *a, int *lda,
real_t *b, int *ldb);
extern "C" void
MFEM_LAPACK_PREFIX(ggev_)(char *jobvl, char *jobvr, int *n, real_t *a, int *lda,
real_t *B, int *ldb, real_t *alphar, real_t *alphai,
real_t *beta, real_t *vl, int * ldvl, real_t * vr,
int * ldvr, real_t * work, int * lwork, int* info);
// Cholesky factorizations/solves
extern "C" void
MFEM_LAPACK_PREFIX(potrf_)(char *, int *, real_t *, int *, int *);
// Solve
extern "C" void
MFEM_LAPACK_PREFIX(potrs_)(char *, int *, int *, real_t *, int *, real_t *,
int *, int *);
// Triangular Solves
extern "C" void
MFEM_LAPACK_PREFIX(trtrs_)(char *, char*, char *, int *, int *, real_t *, int *,
real_t *, int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(potri_)(char *, int *, real_t *, int*, int *);
// LAPACK routines for NNLSSolver
extern "C" void
MFEM_LAPACK_PREFIX(ormqr_)(char *, char *, int *, int *, int *, real_t *, int*,
real_t *, real_t *, int *, real_t *, int*, int*);
extern "C" void
MFEM_LAPACK_PREFIX(geqrf_)(int *, int *, real_t *, int *, real_t *, real_t *,
int *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(gemv_)(char *, int *, int *, real_t *, real_t *, int *,
real_t *, int *, real_t *, real_t *, int *);
extern "C" void
MFEM_LAPACK_PREFIX(trsm_)(char *side, char *uplo, char *transa, char *diag,
int *m, int *n, real_t *alpha, real_t *a, int *lda,
real_t *b, int *ldb);
// Complex
extern "C" void
MFEM_LAPACK_COMPLEX(getrf_)(int *, int *, std::complex<real_t> *, int *, int *,
int *);
extern "C" void
MFEM_LAPACK_COMPLEX(getrs_)(char *, int *, int *, std::complex<real_t> *, int *,
int *, std::complex<real_t> *, int *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(getri_)(int *, std::complex<real_t> *, int *, int *,
std::complex<real_t> *, int *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(trsm_)(char *, char *, char *, char *, int *, int *,
std::complex<real_t> *, std::complex<real_t> *,
int *, std::complex<real_t> *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(potrf_)(char *, int *, std::complex<real_t> *, int *,
int *);
extern "C" void
MFEM_LAPACK_COMPLEX(trtrs_)(char *, char*, char *, int *, int *,
std::complex<real_t> *, int *,
std::complex<real_t> *, int *, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(potri_)(char *, int *, std::complex<real_t> *, int*, int *);
extern "C" void
MFEM_LAPACK_COMPLEX(potrs_)(char *, int *, int *, std::complex<real_t> *, int *,
std::complex<real_t> *, int *, int *);
}
#endif
#endif
+52 -130
View File
@@ -309,51 +309,18 @@ public:
/// Base abstract class for first order time dependent operators.
/** Operator of the form: (u,t) -> k(u,t), where k generally solves the
algebraic equation F(u,k,t) = G(u,t). The functions F and G represent the
_implicit_ and _explicit_ parts of the operator, respectively.
A common use for this class is representing a differential algebraic
equation of the form $ F(y,\frac{dy}{dt},t) = G(y,t) $.
For example, consider an ordinary differential equation of the form
$ M \frac{dy}{dt} = g(y,t) $. There are various ways of expressing this ODE
as a TimeDependentOperator depending on the choices for F and G. Here are
some common choices:
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t),
2. F(u,k,t) = M k and G(u,t) = g(u,t),
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0.
Note that depending on the ODE solver, some of the above choices may be
preferable to the others.
*/
/** Operator of the form: (x,t) -> f(x,t), where k = f(x,t) generally solves the
algebraic equation F(x,k,t) = G(x,t). The functions F and G represent the
_implicit_ and _explicit_ parts of the operator, respectively. For explicit
operators, F(x,k,t) = k, so f(x,t) = G(x,t). */
class TimeDependentOperator : public Operator
{
public:
/// Enum used to describe the form of the time-dependent operator.
/** The type should be set by classes derived from TimeDependentOperator to
describe the form, in terms of the functions F and G, used by the
specific derived class. This information can be queried by classes or
functions (like time stepping algorithms) to make choices about the
algorithm to use, or to ensure that the TimeDependentOperator uses the
form expected by the class/function.
For example, assume that a derived class is implementing the ODE
$M \frac{dy}{dt} = g(y,t)$ and chooses to define $F(u,k,t) = M k$ and
$G(u,t) = g(u,t)$. Then it cannot use type EXPLICIT, unless $M = I$, or
type HOMOGENEOUS, unless $g(u,t) = 0$. If, on the other hand, the derived
class chooses to define $F(u,k,t) = k$ and $G(u,t) = M^{-1} g(y,t)$, then
the natural choice is to set the type to EXPLICIT, even though setting it
to IMPLICIT is also not wrong -- doing so will simply fail to inform
methods that query this information that it uses a more specific
implementation, EXPLICIT, that may allow the use of algorithms that
support only the EXPLICIT type. */
enum Type
{
EXPLICIT, ///< This type assumes F(u,k,t) = k.
EXPLICIT, ///< This type assumes F(x,k,t) = k, i.e. k = f(x,t) = G(x,t).
IMPLICIT, ///< This is the most general type, no assumptions on F and G.
HOMOGENEOUS ///< This type assumes that G(u,t) = 0.
HOMOGENEOUS ///< This type assumes that G(x,t) = 0.
};
/// Evaluation mode. See SetEvalMode() for details.
@@ -361,30 +328,29 @@ public:
{
/** Normal evaluation. */
NORMAL,
/** Assuming additive split, k(u,t) = k1(u,t) + k2(u,t), evaluate the
first term, k1. */
/** Assuming additive split, f(x,t) = f1(x,t) + f2(x,t), evaluate the
first term, f1. */
ADDITIVE_TERM_1,
/** Assuming additive split, k(u,t) = k1(u,t) + k2(u,t), evaluate the
second term, k2. */
/** Assuming additive split, f(x,t) = f1(x,t) + f2(x,t), evaluate the
second term, f2. */
ADDITIVE_TERM_2
};
protected:
real_t t; ///< Current time.
Type type; /**< @brief Describes the form of the TimeDependentOperator, see
the documentation of #Type. */
Type type; ///< Describes the form of the TimeDependentOperator.
EvalMode eval_mode; ///< Current evaluation mode.
public:
/** @brief Construct a "square" TimeDependentOperator (u,t) -> k(u,t), where
u and k have the same dimension @a n. */
/** @brief Construct a "square" TimeDependentOperator y = f(x,t), where x and
y have the same dimension @a n. */
explicit TimeDependentOperator(int n = 0, real_t t_ = 0.0,
Type type_ = EXPLICIT)
: Operator(n) { t = t_; type = type_; eval_mode = NORMAL; }
/** @brief Construct a TimeDependentOperator (u,t) -> k(u,t), where u and k
have dimensions @a w and @a h, respectively. */
TimeDependentOperator(int h, int w, double t_ = 0.0, Type type_ = EXPLICIT)
/** @brief Construct a TimeDependentOperator y = f(x,t), where x and y have
dimensions @a w and @a h, respectively. */
TimeDependentOperator(int h, int w, real_t t_ = 0.0, Type type_ = EXPLICIT)
: Operator(h, w) { t = t_; type = type_; eval_mode = NORMAL; }
/// Read the currently set time.
@@ -407,7 +373,7 @@ public:
/** The evaluation mode is a switch that allows time-stepping methods to
request evaluation of separate components/terms of the time-dependent
operator. For example, IMEX methods typically assume additive split of
the operator: k(u,t) = k1(u,t) + k2(u,t) and they rely on the ability to
the operator: f(x,t) = f1(x,t) + f2(x,t) and they rely on the ability to
evaluate the two terms separately.
Generally, setting the evaluation mode should affect the behavior of all
@@ -418,104 +384,62 @@ public:
{ eval_mode = new_eval_mode; }
/** @brief Perform the action of the explicit part of the operator, G:
@a v = G(@a u, t) where t is the current time.
@a y = G(@a x, t) where t is the current time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual. */
virtual void ExplicitMult(const Vector &u, Vector &v) const;
virtual void ExplicitMult(const Vector &x, Vector &y) const;
/** @brief Perform the action of the implicit part of the operator, F:
@a v = F(@a u, @a k, t) where t is the current time.
@a y = F(@a x, @a k, t) where t is the current time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual.*/
virtual void ImplicitMult(const Vector &u, const Vector &k, Vector &v) const;
virtual void ImplicitMult(const Vector &x, const Vector &k, Vector &y) const;
/** @brief Perform the action of the operator (u,t) -> k(u,t) where t is the
current time set by SetTime() and @a k satisfies
F(@a u, @a k, t) = G(@a u, t).
/** @brief Perform the action of the operator: @a y = k = f(@a x, t), where
k solves the algebraic equation F(@a x, k, t) = G(@a x, t) and t is the
current time. */
virtual void Mult(const Vector &x, Vector &y) const;
For solving an ordinary differential equation of the form
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined in
various ways, e.g.:
/** @brief Solve the equation: @a k = f(@a x + @a dt @a k, t), for the
unknown @a k at the current time t.
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
2. F(u,k,t) = M k and G(u,t) = g(u,t)
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0.
For general F and G, the equation for @a k becomes:
F(@a x + @a dt @a k, @a k, t) = G(@a x + @a dt @a k, t).
Regardless of the choice of F and G, this function should always compute
@a k = inv(M) g(@a u, t). */
virtual void Mult(const Vector &u, Vector &v) const override;
The input vector @a x corresponds to time index (or cycle) n, while the
currently set time, #t, and the result vector @a k correspond to time
index n+1. The time step @a dt corresponds to the time interval between
cycles n and n+1.
/** @brief Solve for the unknown @a k, at the current time t, the following
equation:
F(@a u + @a gamma @a k, @a k, t) = G(@a u + @a gamma @a k, t).
For solving an ordinary differential equation of the form
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined in
various ways, e.g.:
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
2. F(u,k,t) = M k and G(u,t) = g(u,t)
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
Regardless of the choice of F and G, this function should solve for @a k
in M @a k = g(@a u + @a gamma @a k, t).
To see how @a k can be useful, consider the backward Euler method defined
by $ y(t + \Delta t) = y(t) + \Delta t k_0 $ where
$ M k_0 = g \big( y(t) + \Delta t k_0, t + \Delta t \big) $. A backward
Euler integrator can use @a k from this function for $k_0$, with the call
using @a u set to $ y(t) $, @a gamma set to $ \Delta t$, and time set to
$t + \Delta t$. See class BackwardEulerSolver.
Generalizing further, consider a diagonally implicit Runge-Kutta (DIRK)
method defined by
$ y(t + \Delta t) = y(t) + \Delta t \sum_{i=1}^s b_i k_i $ where
$ M k_i = g \big( y(t) + \Delta t \sum_{j=1}^i a_{ij} k_j,
t + c_i \Delta t \big) $.
A DIRK integrator can use @a k from this function, with @a u set to
$ y(t) + \Delta t \sum_{j=1}^{i-1} a_{ij} k_j $ and @a gamma set to
$ a_{ii} \Delta t $, for $ k_i $. For example, see class SDIRK33Solver.
This method allows for the abstract implementation of some time
integration methods, including diagonal implicit Runge-Kutta (DIRK)
methods and the backward Euler method in particular.
If not re-implemented, this method simply generates an error. */
virtual void ImplicitSolve(const real_t gamma, const Vector &u, Vector &k);
virtual void ImplicitSolve(const real_t dt, const Vector &x, Vector &k);
/** @brief Return an Operator representing (dF/dk @a shift + dF/du) at the
given @a u, @a k, and the currently set time.
/** @brief Return an Operator representing (dF/dk @a shift + dF/dx) at the
given @a x, @a k, and the currently set time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual. */
virtual Operator& GetImplicitGradient(const Vector &u, const Vector &k,
virtual Operator& GetImplicitGradient(const Vector &x, const Vector &k,
real_t shift) const;
/** @brief Return an Operator representing dG/du at the given point @a u and
/** @brief Return an Operator representing dG/dx at the given point @a x and
the currently set time.
Presently, this method is used by some PETSc ODE solvers, for more
details, see the PETSc Manual. */
virtual Operator& GetExplicitGradient(const Vector &u) const;
virtual Operator& GetExplicitGradient(const Vector &x) const;
/** @brief Setup a linear system as needed by some SUNDIALS ODE solvers.
/** @brief Setup the ODE linear system $ A(x,t) = (I - gamma J) $ or
$ A = (M - gamma J) $, where $ J(x,t) = \frac{df}{dt(x,t)} $.
For solving an ordinary differential equation of the form
$ M \frac{dy}{dt} = g(y,t) $, recall that F and G can be defined as one
of the following:
1. F(u,k,t) = k and G(u,t) = inv(M) g(u,t)
2. F(u,k,t) = M k and G(u,t) = g(u,t)
3. F(u,k,t) = M k - g(u,t) and G(u,t) = 0
This function performs setup to solve $ A x = b $ where A is either
1. A(@a y,t) = I - @a gamma inv(M) J(@a y,t)
2. A(@a y,t) = M - @a gamma J(@a y,t)
3. A(@a y,t) = M - @a gamma J(@a y,t)
with J = dg/dy (or a reasonable approximation thereof).
@param[in] y The state at which A(@a y,t) should be evaluated.
@param[in] v The value of inv(M) g(y,t) for 1 or g(y,t) for 2 & 3.
@param[in] x The state at which $A(x,t)$ should be evaluated.
@param[in] fx The current value of the ODE rhs function, $f(x,t)$.
@param[in] jok Flag indicating if the Jacobian should be updated.
@param[out] jcur Flag to signal if the Jacobian was updated.
@param[in] gamma The scaled time step value.
@@ -524,10 +448,10 @@ public:
Presently, this method is used by SUNDIALS ODE solvers, for more
details, see the SUNDIALS User Guides. */
virtual int SUNImplicitSetup(const Vector &y, const Vector &v,
virtual int SUNImplicitSetup(const Vector &x, const Vector &fx,
int jok, int *jcur, real_t gamma);
/** @brief Solve the ODE linear system A @a x = @a b, where A is defined by
/** @brief Solve the ODE linear system $ A x = b $ as setup by
the method SUNImplicitSetup().
@param[in] b The linear system right-hand side.
@@ -540,8 +464,7 @@ public:
details, see the SUNDIALS User Guides. */
virtual int SUNImplicitSolve(const Vector &b, Vector &x, real_t tol);
/** @brief Setup the mass matrix in the ODE system
$ M \frac{dy}{dt} = g(y,t) $ .
/** @brief Setup the mass matrix in the ODE system $ M y' = f(y,t) $ .
If not re-implemented, this method simply generates an error.
@@ -549,8 +472,8 @@ public:
details, see the ARKode User Guide. */
virtual int SUNMassSetup();
/** @brief Solve the mass matrix linear system M @a x = @a b, where M is
defined by the method SUNMassSetup().
/** @brief Solve the mass matrix linear system $ M x = b $
as setup by the method SUNMassSetup().
@param[in] b The linear system right-hand side.
@param[in,out] x On input, the initial guess. On output, the solution.
@@ -562,8 +485,7 @@ public:
details, see the ARKode User Guide. */
virtual int SUNMassSolve(const Vector &b, Vector &x, real_t tol);
/** @brief Compute the mass matrix-vector product @a v = M @a x, where M is
defined by the method SUNMassSetup().
/** @brief Compute the mass matrix-vector product $ v = M x $ .
@param[in] x The vector to multiply.
@param[out] v The result of the matrix-vector product.
+138 -53
View File
@@ -10,7 +10,6 @@
// CONTRIBUTING.md for details.
#include "linalg.hpp"
#include "lapack.hpp"
#include "../general/annotation.hpp"
#include "../general/forall.hpp"
#include "../general/globals.hpp"
@@ -3544,6 +3543,38 @@ void AuxSpaceSmoother::Mult(const Vector &x, Vector &y, bool transpose) const
#endif // MFEM_USE_MPI
#ifdef MFEM_USE_LAPACK
// LAPACK routines for NNLSSolver
#ifdef MFEM_USE_SINGLE
extern "C" void
sormqr_(char *, char *, int *, int *, int *, float *, int*, float *,
float *, int *, float *, int*, int*);
extern "C" void
sgeqrf_(int *, int *, float *, int *, float *, float *, int *, int *);
extern "C" void
sgemv_(char *, int *, int *, float *, float *, int *, float *, int *,
float *, float *, int *);
extern "C" void
strsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n,
float *alpha, float *a, int *lda, float *b, int *ldb);
#elif defined MFEM_USE_DOUBLE
extern "C" void
dormqr_(char *, char *, int *, int *, int *, double *, int*, double *,
double *, int *, double *, int*, int*);
extern "C" void
dgeqrf_(int *, int *, double *, int *, double *, double *, int *, int *);
extern "C" void
dgemv_(char *, int *, int *, double *, double *, int *, double *, int *,
double *, double *, int *);
extern "C" void
dtrsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n,
double *alpha, double *a, int *lda, double *b, int *ldb);
#endif
NNLSSolver::NNLSSolver()
: Solver(0), mat(nullptr), const_tol_(1.0e-14), min_nnz_(0),
@@ -3907,19 +3938,25 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
lwork = -1;
work.resize(10);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &n_update,
&i_qr_start, mat_qr_data.GetData(), &m,
tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m),
&m, work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T A update work calculation failed
lwork = static_cast<int>(work[0]);
work.resize(lwork);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &n_update,
&i_qr_start, mat_qr_data.GetData(), &m,
tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m),
&m, work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &n_update, &i_qr_start,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
mat_qr_data.GetData() + (i_qr_start * m), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T A update failed
// Compute QR factorization of the submatrix
lwork = -1;
@@ -3940,16 +3977,24 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
sub_tau[j] = tau[i_qr_start + j];
}
MFEM_LAPACK_PREFIX(geqrf_)(&m_update, &n_update, submat_data.GetData(),
&m_update, sub_tau.GetData(), work.data(),
&lwork, &info);
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m_update, &n_update,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m_update, &n_update,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR update factorization work calc
lwork = static_cast<int>(work[0]);
if (lwork == 0) { lwork = 1; }
work.resize(lwork);
MFEM_LAPACK_PREFIX(geqrf_)(&m_update, &n_update, submat_data.GetData(),
&m_update, sub_tau.GetData(), work.data(),
&lwork, &info);
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m_update, &n_update,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m_update, &n_update,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR update factorization failed
// Copy result back
@@ -3978,13 +4023,23 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
// perform qr)
lwork = -1;
work.resize(10);
MFEM_LAPACK_PREFIX(geqrf_)(&m, &n_glob, mat_qr_data.GetData(), &m,
tau.GetData(), work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m, &n_glob,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR factorization work calculation
lwork = static_cast<int>(work[0]);
work.resize(lwork);
MFEM_LAPACK_PREFIX(geqrf_)(&m, &n_glob, mat_qr_data.GetData(), &m,
tau.GetData(), work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sgeqrf_(&m, &n_glob,
#elif defined MFEM_USE_DOUBLE
dgeqrf_(&m, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // QR factorization failed
}
@@ -4012,17 +4067,25 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
sub_tau[0] = tau[i_qr_start];
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m_update, &ione, &ione,
submat_data.GetData(), &m_update,
sub_tau.GetData(), sub_qt.GetData(),
&m_update, work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m_update, &ione, &ione,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m_update, &ione, &ione,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
sub_qt.GetData(), &m_update,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // H_last y work calculation failed
lwork = static_cast<int>(work[0]);
work.resize(lwork);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m_update, &ione, &ione,
submat_data.GetData(), &m_update,
sub_tau.GetData(), sub_qt.GetData(),
&m_update, work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m_update, &ione, &ione,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m_update, &ione, &ione,
#endif
submat_data.GetData(), &m_update, sub_tau.GetData(),
sub_qt.GetData(), &m_update,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // H_last y failed
// Copy result back
for (int i=0; i<m_update; ++i)
@@ -4036,17 +4099,25 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
qt_rhs_glob = rhs_avg_glob;
lwork = -1;
work.resize(10);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &ione, &n_glob,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &ione, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T b work calculation failed
lwork = static_cast<int>(work[0]);
work.resize(lwork);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &trans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &trans, &m, &ione, &n_glob,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &trans, &m, &ione, &n_glob,
#endif
mat_qr_data.GetData(), &m, tau.GetData(),
qt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q^T b failed
}
@@ -4059,10 +4130,14 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
char upper = 'U';
char nounit = 'N';
vec1 = qt_rhs_glob;
MFEM_LAPACK_PREFIX(trsm_)(&lside, &upper, &notrans, &nounit,
&n_glob, &ione, &fone,
mat_qr_data.GetData(), &m,
vec1.GetData(), &n_glob);
#ifdef MFEM_USE_SINGLE
strsm_(&lside, &upper, &notrans, &nounit,
#elif defined MFEM_USE_DOUBLE
dtrsm_(&lside, &upper, &notrans, &nounit,
#endif
&n_glob, &ione, &fone,
mat_qr_data.GetData(), &m,
vec1.GetData(), &n_glob);
if (verbosity_ > 2)
{
@@ -4285,10 +4360,14 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
{
res_glob = rhs_avg_glob;
real_t fmone = -1.0;
MFEM_LAPACK_PREFIX(gemv_)(&notrans, &m, &n_glob, &fmone,
mat_0_data.GetData(), &m,
soln_nz_glob.GetData(), &ione, &fone,
res_glob.GetData(), &ione);
#ifdef MFEM_USE_SINGLE
sgemv_(&notrans, &m, &n_glob, &fmone,
#elif defined MFEM_USE_DOUBLE
dgemv_(&notrans, &m, &n_glob, &fmone,
#endif
mat_0_data.GetData(), &m,
soln_nz_glob.GetData(), &ione, &fone,
res_glob.GetData(), &ione);
}
else
{
@@ -4302,18 +4381,24 @@ void NNLSSolver::Solve(const Vector& rhs_lb, const Vector& rhs_ub,
qqt_rhs_glob(i) = qt_rhs_glob(i);
}
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &notrans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m,
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#endif
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q Q^T b work calculation failed.
lwork = static_cast<int>(work[0]);
work.resize(lwork);
MFEM_LAPACK_PREFIX(ormqr_)(&lside, &notrans, &m, &ione, &n_glob,
mat_qr_data.GetData(), &m,
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
#ifdef MFEM_USE_SINGLE
sormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#elif defined MFEM_USE_DOUBLE
dormqr_(&lside, &notrans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
#endif
tau.GetData(), qqt_rhs_glob.GetData(), &m,
work.data(), &lwork, &info);
MFEM_VERIFY(info == 0, ""); // Q Q^T b calculation failed.
res_glob = rhs_avg_glob;
res_glob -= qqt_rhs_glob;
+5 -14
View File
@@ -58,20 +58,6 @@ DenseSymmetricMatrix &DenseSymmetricMatrix::operator=(real_t c)
return *this;
}
DenseSymmetricMatrix &DenseSymmetricMatrix::operator=(const DenseSymmetricMatrix
&m)
{
SetSize(m.height);
const int hw = m.GetStoredSize();
for (int i = 0; i < hw; i++)
{
data[i] = m.data[i];
}
return *this;
}
real_t &DenseSymmetricMatrix::Elem(int i, int j)
{
return (*this)(i,j);
@@ -103,6 +89,11 @@ MatrixInverse *DenseSymmetricMatrix::Inverse() const
return nullptr;
}
void DenseSymmetricMatrix::Print (std::ostream & os, int width_) const
{
mfem_error("DenseSymmetricMatrix::Print() not implemented!");
}
DenseSymmetricMatrix::~DenseSymmetricMatrix()
{
data.Delete();
+3 -3
View File
@@ -102,9 +102,6 @@ public:
DenseSymmetricMatrix &operator*=(real_t c);
/// Sets the matrix size and elements equal to those of m
DenseSymmetricMatrix &operator=(const DenseSymmetricMatrix &m);
std::size_t MemoryUsage() const { return data.Capacity() * sizeof(real_t); }
/// Shortcut for mfem::Read( GetMemory(), TotalSize(), on_dev).
@@ -137,6 +134,9 @@ public:
/// Returns a pointer to (an approximation) of the matrix inverse.
virtual MatrixInverse *Inverse() const;
/// Prints matrix to stream out.
virtual void Print (std::ostream & out = mfem::out, int width_ = 4) const;
/// Destroys the symmetric matrix.
virtual ~DenseSymmetricMatrix();
};
+11 -43
View File
@@ -466,8 +466,7 @@ void Mesh::GetBdrElementTransformation(int i,
{
for (int j = 0; j < n; j++)
{
int idx = vdofs[n*k+j];
pm(k,j) = nodes((idx<0)? -1-idx:idx);
pm(k,j) = nodes(vdofs[n*k+j]);
}
}
ElTr->SetFE(bdr_el);
@@ -7132,15 +7131,17 @@ Table *Mesh::GetEdgeVertexTable() const
Table *Mesh::GetVertexToElementTable()
{
int i, j, nv, *v;
Table *vert_elem = new Table;
vert_elem->MakeI(NumOfVertices);
for (int i = 0; i < NumOfElements; i++)
for (i = 0; i < NumOfElements; i++)
{
const int nv = elements[i]->GetNVertices();
const int *v = elements[i]->GetVertices();
for (int j = 0; j < nv; j++)
nv = elements[i]->GetNVertices();
v = elements[i]->GetVertices();
for (j = 0; j < nv; j++)
{
vert_elem->AddAColumnInRow(v[j]);
}
@@ -7148,11 +7149,11 @@ Table *Mesh::GetVertexToElementTable()
vert_elem->MakeJ();
for (int i = 0; i < NumOfElements; i++)
for (i = 0; i < NumOfElements; i++)
{
const int nv = elements[i]->GetNVertices();
const int *v = elements[i]->GetVertices();
for (int j = 0; j < nv; j++)
nv = elements[i]->GetNVertices();
v = elements[i]->GetVertices();
for (j = 0; j < nv; j++)
{
vert_elem->AddConnection(v[j], i);
}
@@ -7163,39 +7164,6 @@ Table *Mesh::GetVertexToElementTable()
return vert_elem;
}
Table *Mesh::GetVertexToBdrElementTable()
{
Table *vert_bdr_elem = new Table;
vert_bdr_elem->MakeI(NumOfVertices);
for (int i = 0; i < NumOfBdrElements; i++)
{
const int nv = boundary[i]->GetNVertices();
const int *v = boundary[i]->GetVertices();
for (int j = 0; j < nv; j++)
{
vert_bdr_elem->AddAColumnInRow(v[j]);
}
}
vert_bdr_elem->MakeJ();
for (int i = 0; i < NumOfBdrElements; i++)
{
const int nv = boundary[i]->GetNVertices();
const int *v = boundary[i]->GetVertices();
for (int j = 0; j < nv; j++)
{
vert_bdr_elem->AddConnection(v[j], i);
}
}
vert_bdr_elem->ShiftUpI();
return vert_bdr_elem;
}
Table *Mesh::GetFaceToElementTable() const
{
Table *face_elem = new Table;
+1 -6
View File
@@ -857,9 +857,7 @@ public:
vectors using Mesh::CreatePeriodicVertexMapping.
@note MFEM requires that each edge of the resulting mesh be uniquely
identifiable by a pair of distinct vertices. As a consequence, periodic
boundaries must be separated by at least two interior vertices.
@note The resulting mesh uses a discontinuous nodal function, see
SetCurvature() for further details. */
boundaries must be connected by at least three edges. */
static Mesh MakePeriodic(const Mesh &orig_mesh, const std::vector<int> &v2v);
///@}
@@ -1537,9 +1535,6 @@ public:
/// @note The returned Table should be deleted by the caller
Table *GetVertexToElementTable();
/// @note The returned Table should be deleted by the caller
Table *GetVertexToBdrElementTable();
/// Return the "face"-element Table. Here "face" refers to face (3D),
/// edge (2D), or vertex (1D).
///
+4 -16
View File
@@ -1151,24 +1151,15 @@ void Mesh::ReadXML_VTKMesh(std::istream &input, int &curved, int &read_gf,
}
if (cells_xml == NULL) { MFEM_ABORT(erstr); }
// Read the element attributes, which are stored as CellData named either
// "material" or "attribute". We prioritize "material" over "attribute" for
// backwards compatibility.
// Read the element attributes, which are stored as CellData named "material"
Array<int> cell_attributes;
bool found_attributes = false;
for (const XMLElement *cell_data_xml = piece->FirstChildElement();
cell_data_xml != NULL;
cell_data_xml = cell_data_xml->NextSiblingElement())
{
const bool is_cell_data =
StringCompare(cell_data_xml->Name(), "CellData");
const bool is_material =
StringCompare(cell_data_xml->Attribute("Scalars"), "material");
const bool is_attribute =
StringCompare(cell_data_xml->Attribute("Scalars"), "attribute");
if (is_cell_data && (is_material || (is_attribute && !found_attributes)))
if (StringCompare(cell_data_xml->Name(), "CellData")
&& StringCompare(cell_data_xml->Attribute("Scalars"), "material"))
{
found_attributes = true;
const XMLElement *data_xml = cell_data_xml->FirstChildElement();
if (data_xml != NULL && StringCompare(data_xml->Name(), "DataArray"))
{
@@ -1283,7 +1274,6 @@ void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf,
// Read the cell materials
// bool found_material = false;
Array<int> cell_attributes;
bool found_attributes = false;
while ((input.good()))
{
getline(input, buff);
@@ -1291,10 +1281,8 @@ void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf,
{
break; // We have entered the POINT_DATA block. Quit.
}
else if (buff.rfind("SCALARS material") == 0 ||
(buff.rfind("SCALARS attribute") == 0 && !found_attributes))
else if (buff.rfind("SCALARS material") == 0)
{
found_attributes = true;
getline(input, buff); // LOOKUP_TABLE default
if (buff.rfind("LOOKUP_TABLE default") != 0)
{
+18 -103
View File
@@ -1857,7 +1857,7 @@ NURBSPatch *Revolve3D(NURBSPatch &patch, real_t n[], real_t ang, int times)
{
if (patch.Dim != 4)
{
mfem_error("Revolve3D(NURBSPatch &, real_t [], real_t)");
mfem_error("Revolve3D(NURBSPatch &, double [], double)");
}
int size = 1, ns;
@@ -2008,23 +2008,23 @@ NURBSExtension::NURBSExtension(std::istream &input, bool spacing)
input >> numSpacing;
for (int j = 0; j < numSpacing; j++)
{
int ki, spacingType, numIntParam, numRealParam;
input >> ki >> spacingType >> numIntParam >> numRealParam;
int ki, spacingType, numIntParam, numDoubleParam;
input >> ki >> spacingType >> numIntParam >> numDoubleParam;
MFEM_VERIFY(0 <= ki && ki < NumOfKnotVectors,
"Invalid knotvector index");
MFEM_VERIFY(numIntParam >= 0 && numRealParam >= 0,
MFEM_VERIFY(numIntParam >= 0 && numDoubleParam >= 0,
"Invalid number of parameters in KnotVector");
Array<int> ipar(numIntParam);
Vector dpar(numRealParam);
Vector dpar(numDoubleParam);
for (int i=0; i<numIntParam; ++i)
{
input >> ipar[i];
}
for (int i=0; i<numRealParam; ++i)
for (int i=0; i<numDoubleParam; ++i)
{
input >> dpar[i];
}
@@ -2064,7 +2064,7 @@ NURBSExtension::NURBSExtension(std::istream &input, bool spacing)
new KnotVector(*patches[p]->GetKV(0));
}
}
else if (Dimension() == 2)
if (Dimension() == 2)
{
patchTopo->GetElementEdges(p, edges, oedge);
if (knotVectors[KnotInd(edges[0])] == NULL)
@@ -2230,8 +2230,7 @@ NURBSExtension::NURBSExtension(NURBSExtension *parent, int newOrder)
}
NURBSExtension::NURBSExtension(NURBSExtension *parent,
const Array<int> &newOrders, Mode mode)
: mode(mode)
const Array<int> &newOrders)
{
newOrders.Copy(mOrders);
SetOrderFromOrders();
@@ -3892,16 +3891,7 @@ void NURBSExtension::GenerateBdrElementDofTable()
int ndof = bel_dof->Size_of_connections();
for (int i = 0; i < ndof; i++)
{
int idx = dof[i];
if (idx < 0)
{
dof[i] = -1 - (activeDof[-1-idx] - 1);
dof[i] = -activeDof[-1-idx];
}
else
{
dof[i] = activeDof[idx] - 1;
}
dof[i] = activeDof[dof[i]] - 1;
}
}
@@ -3953,22 +3943,6 @@ void NURBSExtension::Generate2DBdrElementDofTable()
// Load dofs
const int nks0 = kv[0]->GetNKS();
const int ord0 = kv[0]->GetOrder();
bool add_dofs = true;
int s = 1;
if (mode == Mode::H_DIV)
{
int fn = patchTopo->GetBdrElementFaceIndex(b);
if (ord0 == mOrders.Max()) { add_dofs = false; }
if (fn == 0) { s = -1; }
if (fn == 2) { s = -1; }
}
else if (mode == Mode::H_CURL)
{
if (ord0 == mOrders.Max()) { add_dofs = false; }
}
for (int i = 0; i < nks0; i++)
{
if (kv[0]->isElement(i))
@@ -3976,14 +3950,10 @@ void NURBSExtension::Generate2DBdrElementDofTable()
if (activeBdrElem[gbe])
{
Connection conn(lbe,0);
if (add_dofs)
for (int ii = 0; ii <= ord0; ii++)
{
for (int ii = 0; ii <= ord0; ii++)
{
conn.to = DofMap(p2g[(okv[0] >= 0) ? (i+ii) : (nx-i-ii)]);
if (s == -1) { conn.to = -1 -conn.to; }
bel_dof_list.Append(conn);
}
conn.to = DofMap(p2g[(okv[0] >= 0) ? (i+ii) : (nx-i-ii)]);
bel_dof_list.Append(conn);
}
bel_to_patch[lbe] = b;
bel_to_IJK(lbe,0) = (okv[0] >= 0) ? i : (-1-i);
@@ -4020,25 +3990,6 @@ void NURBSExtension::Generate3DBdrElementDofTable()
const int ord0 = kv[0]->GetOrder();
const int nks1 = kv[1]->GetNKS();
const int ord1 = kv[1]->GetOrder();
// Check if dofs are actually defined on boundary
bool add_dofs = true;
int s = 1;
if (mode == Mode::H_DIV)
{
int fn = patchTopo->GetBdrElementFaceIndex(b);
if (ord0 != ord1) { add_dofs = false; }
if (fn == 4) { s = -1; }
if (fn == 1) { s = -1; }
if (fn == 0) { s = -1; }
}
else if (mode == Mode::H_CURL)
{
if (ord0 == ord1) { add_dofs = false; }
}
for (int j = 0; j < nks1; j++)
{
if (kv[1]->isElement(j))
@@ -4050,18 +4001,14 @@ void NURBSExtension::Generate3DBdrElementDofTable()
if (activeBdrElem[gbe])
{
Connection conn(lbe,0);
if (add_dofs)
for (int jj = 0; jj <= ord1; jj++)
{
for (int jj = 0; jj <= ord1; jj++)
const int jj_ = (okv[1] >= 0) ? (j+jj) : (ny-j-jj);
for (int ii = 0; ii <= ord0; ii++)
{
const int jj_ = (okv[1] >= 0) ? (j+jj) : (ny-j-jj);
for (int ii = 0; ii <= ord0; ii++)
{
const int ii_ = (okv[0] >= 0) ? (i+ii) : (nx-i-ii);
conn.to = DofMap(p2g(ii_, jj_));
if (s == -1) { conn.to = -1 -conn.to; }
bel_dof_list.Append(conn);
}
const int ii_ = (okv[0] >= 0) ? (i+ii) : (nx-i-ii);
conn.to = DofMap(p2g(ii_, jj_));
bel_dof_list.Append(conn);
}
}
bel_to_patch[lbe] = b;
@@ -4294,38 +4241,6 @@ void NURBSExtension::DegreeElevate(int rel_degree, int degree)
}
}
NURBSExtension* NURBSExtension::GetDivExtension(int component)
{
// Smarter routine
if (GetNP() > 1)
{
mfem_error("NURBSExtension::GetDivExtension currently "
"only works for single patch NURBS meshes ");
}
Array<int> newOrders = GetOrders();
newOrders[component] += 1;
return new NURBSExtension(this, newOrders, Mode::H_DIV);
}
NURBSExtension* NURBSExtension::GetCurlExtension(int component)
{
// Smarter routine
if (GetNP() > 1)
{
mfem_error("NURBSExtension::GetCurlExtension currently "
"only works for single patch NURBS meshes ");
}
Array<int> newOrders = GetOrders();
for (int c = 0; c < newOrders.Size(); c++) { newOrders[c]++; }
newOrders[component] -= 1;
return new NURBSExtension(this, newOrders, Mode::H_CURL);
}
void NURBSExtension::UniformRefinement(Array<int> const& rf)
{
for (int p = 0; p < patches.Size(); p++)
+1 -24
View File
@@ -426,16 +426,6 @@ class NURBSExtension
friend class NURBSPatchMap;
protected:
/// Flag for indicating what type of NURBS fespace this extension is used for.
enum class Mode
{
H_1, ///> Extension for a standard scalar-valued space
H_DIV, ///> Extension for a divergence conforming vector-valued space
H_CURL, ///> Extension for a curl conforming vector-valued space
};
Mode mode = Mode::H_1;
/// Order of KnotVectors, see GetOrder() for description.
int mOrder;
@@ -665,10 +655,8 @@ public:
/** @a note If a KnotVector in @a parent already has order greater than or
equal to the corresponding entry in @a newOrder, it will be used
unmodified. */
NURBSExtension(NURBSExtension *parent, const Array<int> &newOrders,
Mode mode = Mode::H_1);
NURBSExtension(NURBSExtension *parent, const Array<int> &newOrders);
/// Construct a NURBSExtension by merging a partitioned NURBS mesh.
NURBSExtension(Mesh *mesh_array[], int num_pieces);
/// Copy assignment not supported.
@@ -853,16 +841,6 @@ public:
void KnotInsert(Array<KnotVector *> &kv);
void KnotInsert(Array<Vector *> &kv);
/** Returns the NURBSExtension to be used for @a component of
an H(div) conforming NURBS space. Caller gets ownership of
the returned object, and is responsible for deletion.*/
NURBSExtension* GetDivExtension(int component);
/** Returns the NURBSExtension to be used for @a component of
an H(curl) conforming NURBS space. Caller gets ownership of
the returned object, and is responsible for deletion.*/
NURBSExtension* GetCurlExtension(int component);
void KnotRemove(Array<Vector *> &kv, real_t tol = 1.0e-12);
/** Calls GetCoarseningFactors for each patch and finds the minimum factor
@@ -870,7 +848,6 @@ public:
non-nested spacing functions. */
void GetCoarseningFactors(Array<int> & f) const;
/// Returns the index of the patch containing element @a elem.
int GetElementPatch(int elem) const { return el_to_patch[elem]; }
+3 -3
View File
@@ -819,7 +819,7 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh,
apf::Downward verts;
apf_mesh->getDownward(ent,0,verts);
int *v = nullptr, nv = 0;
int *v, nv = 0;
apf::Mesh::Type ftype = apf_mesh->getType(ent);
if (ftype == apf::Mesh::TRIANGLE)
{
@@ -890,9 +890,9 @@ GridFunctionPumi::GridFunctionPumi(Mesh* m, apf::Mesh2* PumiM,
{
int spDim = m->SpaceDimension();
// Note: default BasisType for 'fec' is GaussLobatto.
fec_owned = new H1_FECollection(mesh_order, m->Dimension());
fec = new H1_FECollection(mesh_order, m->Dimension());
int ordering = Ordering::byVDIM; // x1y1z1/x2y2z2/...
fes = new FiniteElementSpace(m, fec_owned, spDim, ordering);
fes = new FiniteElementSpace(m, fec, spDim, ordering);
int data_size = fes->GetVSize();
// Read PUMI mesh data
-1
View File
@@ -37,4 +37,3 @@ add_subdirectory(tribol)
add_subdirectory(hooke)
add_subdirectory(dpg)
add_subdirectory(hdiv-linear-solver)
add_subdirectory(stabilized)
+5 -5
View File
@@ -15,11 +15,11 @@
//
// Sample runs
//
// acoustics -ref 4 -o 1 -rnum 1.0
// acoustics -m ../../data/inline-tri.mesh -ref 4 -o 2 -sc -rnum 3.0
// acoustics -m ../../data/amr-quad.mesh -ref 3 -o 3 -sc -rnum 4.5 -prob 1
// acoustics -m ../../data/inline-quad.mesh -ref 2 -o 4 -sc -rnum 11.5 -prob 1
// acoustics -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
// acoustics -ref 4 -o 1 -rnum 1.0
// acoustics -m ../../data/inline-tri.mesh -ref 4 -o 2 -sc -rnum 3.0
// acoustics -m ../../data/amr-quad.mesh -ref 3 -o 3 -sc -rnum 4.5 -prob 1
// acoustics -m ../../data/inline-quad.mesh -ref 2 -o 4 -sc -rnum 11.5 -prob 1
// acoustics -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
// Description:
// This example code demonstrates the use of MFEM to define and solve
+6 -6
View File
@@ -14,14 +14,14 @@
// Compile with: make convection-diffusion
//
// sample runs
// convection-diffusion -m ../../data/star.mesh -o 2 -ref 2 -theta 0.0 -eps 1e-1 -beta '2 3'
// convection-diffusion -m ../../data/beam-hex.mesh -o 2 -ref 2 -theta 0.0 -eps 1e0 -beta '1 0 2'
// convection-diffusion -m ../../data/inline-tri.mesh -o 3 -ref 2 -theta 0.0 -eps 1e-2 -beta '4 2' -sc
// convection-diffusion -m ../../data/star.mesh -o 2 -ref 2 -theta 0.0 -eps 1e-1 -beta '2 3'
// convection-diffusion -m ../../data/beam-hex.mesh -o 2 -ref 2 -theta 0.0 -eps 1e0 -beta '1 0 2'
// convection-diffusion -m ../../data/inline-tri.mesh -o 3 -ref 2 -theta 0.0 -eps 1e-2 -beta '4 2' -sc
// AMR runs
// convection-diffusion -o 3 -ref 5 -prob 1 -eps 1e-1 -theta 0.75
// convection-diffusion -o 2 -ref 9 -prob 1 -eps 1e-2 -theta 0.75
// convection-diffusion -o 3 -ref 9 -prob 1 -eps 1e-3 -theta 0.75 -sc
// convection-diffusion -o 3 -ref 5 -prob 1 -eps 1e-1 -theta 0.75
// convection-diffusion -o 2 -ref 9 -prob 1 -eps 1e-2 -theta 0.75
// convection-diffusion -o 3 -ref 9 -prob 1 -eps 1e-3 -theta 0.75 -sc
// Description:
// This example code demonstrates the use of MFEM to define and solve
+4 -4
View File
@@ -14,10 +14,10 @@
// Compile with: make maxwell
//
// Sample runs
// maxwell -m ../../data/inline-tri.mesh -ref 4 -o 1 -rnum 1.0
// maxwell -m ../../data/amr-quad.mesh -ref 3 -o 2 -rnum 1.6 -sc
// maxwell -m ../../data/inline-quad.mesh -ref 2 -o 3 -rnum 4.2 -sc
// maxwell -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
// maxwell -m ../../data/inline-tri.mesh -ref 4 -o 1 -rnum 1.0
// maxwell -m ../../data/amr-quad.mesh -ref 3 -o 2 -rnum 1.6 -sc
// maxwell -m ../../data/inline-quad.mesh -ref 2 -o 3 -rnum 4.2 -sc
// maxwell -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
// Description:
// This example code demonstrates the use of MFEM to define and solve
+11 -11
View File
@@ -15,19 +15,19 @@
//
// sample runs
// mpirun -np 4 pacoustics -o 3 -m ../../data/star.mesh -sref 1 -pref 2 -rnum 1.9 -sc -prob 0
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 1 -pref 2 -rnum 5.2 -sc -prob 1
// mpirun -np 4 pacoustics -o 4 -m ../../data/inline-tri.mesh -sref 1 -pref 2 -rnum 7.1 -sc -prob 1
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 1.9 -sc -prob 0
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 2 -pref 1 -rnum 7.1 -sc -prob 2
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 4.1 -sc -prob 2
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 7.1 -sc -prob 3
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 10.1 -sc -prob 4
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 12.1 -sc -prob 5
// mpirun -np 4 pacoustics -o 3 -m ../../data/star.mesh -sref 1 -pref 2 -rnum 1.9 -sc -prob 0
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 1 -pref 2 -rnum 5.2 -sc -prob 1
// mpirun -np 4 pacoustics -o 4 -m ../../data/inline-tri.mesh -sref 1 -pref 2 -rnum 7.1 -sc -prob 1
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 1.9 -sc -prob 0
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 2 -pref 1 -rnum 7.1 -sc -prob 2
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 4.1 -sc -prob 2
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 7.1 -sc -prob 3
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 10.1 -sc -prob 4
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 12.1 -sc -prob 5
// AMR runs
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 7 -theta 0.75 -rnum 10.1 -sc -prob 3
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 12 -theta 0.75 -rnum 20.1 -sc -prob 3
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 7 -theta 0.75 -rnum 10.1 -sc -prob 3
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 12 -theta 0.75 -rnum 20.1 -sc -prob 3
// Description:
// This example code demonstrates the use of MFEM to define and solve
+7 -7
View File
@@ -11,17 +11,17 @@
//
// MFEM Ultraweak DPG parallel example for convection-diffusion
//
// Compile with: make pconvection-diffusion
// Compile with: make pconvection-diffusion
//
// sample runs
// mpirun -np 4 pconvection-diffusion -o 2 -ref 3 -prob 0 -eps 1e-1 -beta '4 2' -theta 0.0
// mpirun -np 4 pconvection-diffusion -o 3 -ref 3 -prob 0 -eps 1e-2 -beta '2 3' -theta 0.0
// mpirun -np 4 pconvection-diffusion -m ../../data/inline-hex.mesh -o 2 -ref 1 -prob 0 -sc -eps 1e-1 -theta 0.0
// mpirun -np 4 pconvection-diffusion -o 2 -ref 3 -prob 0 -eps 1e-1 -beta '4 2' -theta 0.0
// mpirun -np 4 pconvection-diffusion -o 3 -ref 3 -prob 0 -eps 1e-2 -beta '2 3' -theta 0.0
// mpirun -np 4 pconvection-diffusion -m ../../data/inline-hex.mesh -o 2 -ref 1 -prob 0 -sc -eps 1e-1 -theta 0.0
// AMR runs
// mpirun -np 4 pconvection-diffusion -o 3 -ref 10 -prob 1 -eps 1e-3 -beta '1 0' -theta 0.7 -sc
// mpirun -np 4 pconvection-diffusion -o 3 -ref 15 -prob 2 -eps 5e-3 -theta 0.7 -sc
// mpirun -np 4 pconvection-diffusion -o 2 -ref 12 -prob 3 -eps 1e-2 -beta '1 2' -theta 0.7 -sc
// mpirun -np 4 pconvection-diffusion -o 3 -ref 10 -prob 1 -eps 1e-3 -beta '1 0' -theta 0.7 -sc
// mpirun -np 4 pconvection-diffusion -o 3 -ref 15 -prob 2 -eps 5e-3 -theta 0.7 -sc
// mpirun -np 4 pconvection-diffusion -o 2 -ref 12 -prob 3 -eps 1e-2 -beta '1 2' -theta 0.7 -sc
// Description:
// This example code demonstrates the use of MFEM to define and solve a parallel
+7 -7
View File
@@ -14,18 +14,18 @@
// Compile with: make pdiffusion
//
// Sample runs
// mpirun -np 4 pdiffusion -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 2 -theta 0.0 -prob 0
// mpirun -np 4 pdiffusion -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -theta 0.0 -prob 0 -sc
// mpirun -np 4 pdiffusion -m ../../data/beam-tet.mesh -o 3 -sref 0 -pref 2 -theta 0.0 -prob 0 -sc
// mpirun -np 4 pdiffusion -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 2 -theta 0.0 -prob 0
// mpirun -np 4 pdiffusion -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -theta 0.0 -prob 0 -sc
// mpirun -np 4 pdiffusion -m ../../data/beam-tet.mesh -o 3 -sref 0 -pref 2 -theta 0.0 -prob 0 -sc
// L-shape runs
// Note: uniform ref are expected to give sub-optimal rate for the L-shape problem (rate = 2/3)
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 5 -theta 0.0 -prob 1
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 5 -theta 0.0 -prob 1
// L-shape AMR runs
// mpirun -np 4 pdiffusion -o 1 -sref 1 -pref 10 -theta 0.8 -prob 1
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 8 -theta 0.75 -prob 1 -sc
// mpirun -np 4 pdiffusion -o 3 -sref 1 -pref 6 -theta 0.75 -prob 1 -sc -do 2
// mpirun -np 4 pdiffusion -o 1 -sref 1 -pref 10 -theta 0.8 -prob 1
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 8 -theta 0.75 -prob 1 -sc
// mpirun -np 4 pdiffusion -o 3 -sref 1 -pref 6 -theta 0.75 -prob 1 -sc -do 2
// Description:
// This example code demonstrates the use of MFEM to define and solve
+7 -7
View File
@@ -14,16 +14,16 @@
// Compile with: make pmaxwell
//
// sample run
// mpirun -np 4 pmaxwell -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4
// mpirun -np 4 pmaxwell -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4
// AMR run. Note that this is a computationally intensive sample run.
// We recommend trying it on a large machine with more mpi ranks
// mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc
// mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc
// Description:
// This example code demonstrates the use of MFEM to define and solve
+1 -1
View File
@@ -206,7 +206,7 @@ int main (int argc, char *argv[])
solver.SetMaxIter(200);
solver.SetRelTol(1e-10);
solver.SetAbsTol(0.0);
solver.SetAdaptiveSurfaceFittingScalingFactor(10);
solver.EnableAdaptiveSurfaceFitting();
solver.SetTerminationWithMaxSurfaceFittingError(1e-3);
// Solve.
-16
View File
@@ -34,22 +34,6 @@ real_t circle_level_set(const Vector &x)
}
}
real_t squircle_level_set(const Vector &x)
{
const int dim = x.Size();
if (dim == 2)
{
const real_t xc = x(0) - 0.5, yc = x(1) - 0.5;
return std::pow(xc, 4.0) + std::pow(yc, 4.0) - std::pow(0.24, 4.0);
}
else
{
const real_t xc = x(0) - 0.5, yc = x(1) - 0.5, zc = x(2) - 0.5;
return std::pow(xc, 4.0) + std::pow(yc, 4.0) +
std::pow(zc, 4.0) - std::pow(0.24, 4.0);
}
}
real_t in_circle(const Vector &x, const Vector &x_center, real_t radius)
{
Vector x_current = x;
+89 -102
View File
@@ -33,15 +33,13 @@
// Compile with: make pmesh-fitting
//
// Sample runs:
// Surface fitting:
// mpirun -np 4 pmesh-fitting -o 3 -mid 58 -tid 1 -vl 1 -sfc 5e4 -rtol 1e-5
// mpirun -np 4 pmesh-fitting -m square01-tri.mesh -o 3 -rs 0 -mid 58 -tid 1 -vl 1 -sfc 1e4 -rtol 1e-5
// Interface fitting:
// mpirun -np 4 pmesh-fitting -o 3 -mid 58 -tid 1 -ni 200 -vl 1 -sfc 5e4 -rtol 1e-5
// mpirun -np 4 pmesh-fitting -m square01-tri.mesh -o 3 -rs 0 -mid 58 -tid 1 -ni 200 -vl 1 -sfc 1e4 -rtol 1e-5
// Surface fitting with weight adaptation and termination based on fitting error:
// mpirun -np 4 pmesh-fitting -o 2 -mid 2 -tid 1 -vl 2 -sfc 10 -rtol 1e-20 -sfa 10.0 -sft 1e-5 -no-resid
// Surface fitting with weight adaptation, limit on max weight, and convergence based on residual.
// * mpirun -np 4 pmesh-fitting -m ../../data/inline-tri.mesh -o 2 -mid 2 -tid 4 -vl 2 -sfc 10 -rtol 1e-10 -sfa 10.0 -sft 1e-5 -bgamriter 3 -sbgmesh -ae 1 -marking -slstype 3 -resid -sfcmax 10000 -mod-bndr-attr
// Surface fitting to Fischer-Tropsch reactor like domain (requires GSLIB):
// * mpirun -np 6 pmesh-fitting -m ../../data/inline-tri.mesh -o 2 -rs 4 -mid 2 -tid 1 -vl 2 -sfc 100 -rtol 1e-12 -li 20 -ae 1 -bnd -sbgmesh -slstype 2 -smtype 0 -sfa 10.0 -sft 1e-4 -no-resid -bgamriter 5 -dist -mod-bndr-attr
// mpirun -np 4 pmesh-fitting -o 2 -mid 2 -tid 1 -ni 100 -vl 2 -sfc 10 -rtol 1e-20 -st 0 -sfa 10.0 -sft 1e-5
// Fitting to Fischer-Tropsch reactor like domain (requires GSLIB):
// * mpirun -np 6 pmesh-fitting -m ../../data/inline-tri.mesh -o 2 -rs 4 -mid 2 -tid 1 -vl 2 -sfc 100 -rtol 1e-12 -ni 100 -li 40 -ae 1 -bnd -sbgmesh -slstype 2 -smtype 0 -sfa 10.0 -sft 1e-4 -amriter 5 -dist -mod-bndr-attr
#include "mesh-fitting.hpp"
@@ -50,16 +48,12 @@ using namespace std;
int main (int argc, char *argv[])
{
#ifdef HYPRE_USING_GPU
cout << "\nThis miniapp is NOT supported with the GPU version of hypre.\n\n";
return MFEM_SKIP_RETURN_VALUE;
#endif
// 0. Initialize MPI and HYPRE.
Mpi::Init(argc, argv);
int myid = Mpi::WorldRank();
Hypre::Init();
// Set the method's default parameters.
// 1. Set the method's default parameters.
const char *mesh_file = "square01.mesh";
int mesh_poly_deg = 1;
int rs_levels = 1;
@@ -67,6 +61,7 @@ int main (int argc, char *argv[])
int metric_id = 2;
int target_id = 1;
real_t surface_fit_const = 100.0;
int quad_type = 1;
int quad_order = 8;
int solver_type = 0;
int solver_iter = 20;
@@ -75,28 +70,27 @@ int main (int argc, char *argv[])
#else
real_t solver_rtol = 1e-10;
#endif
int solver_art_type = 0;
int lin_solver = 2;
int max_lin_iter = 100;
bool move_bnd = true;
bool visualization = false;
bool visualization = true;
int verbosity_level = 0;
int adapt_eval = 0;
const char *devopt = "cpu";
real_t surface_fit_adapt = 0.0;
real_t surface_fit_threshold = -10;
real_t surf_fit_const_max = 1e20;
bool adapt_marking = false;
bool surf_bg_mesh = false;
bool comp_dist = false;
int surf_ls_type = 1;
int marking_type = 0;
bool mod_bndr_attr = false;
bool material = false;
bool surf_bg_mesh = false;
bool comp_dist = false;
int surf_ls_type = 1;
int marking_type = 0;
bool mod_bndr_attr = false;
bool material = false;
int mesh_node_ordering = 0;
int bg_amr_iters = 0;
bool conv_residual = true;
int amr_iters = 0;
// Parse command-line options.
// 2. Parse command-line options.
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
@@ -117,6 +111,11 @@ int main (int argc, char *argv[])
"5: Ideal shape, given size (in physical space)");
args.AddOption(&surface_fit_const, "-sfc", "--surface-fit-const",
"Surface preservation constant.");
args.AddOption(&quad_type, "-qt", "--quad-type",
"Quadrature rule type:\n\t"
"1: Gauss-Lobatto\n\t"
"2: Gauss-Legendre\n\t"
"3: Closed uniform points");
args.AddOption(&quad_order, "-qo", "--quad_order",
"Order of the quadrature rule.");
args.AddOption(&solver_type, "-st", "--solver-type",
@@ -125,6 +124,11 @@ int main (int argc, char *argv[])
"Maximum number of Newton iterations.");
args.AddOption(&solver_rtol, "-rtol", "--newton-rel-tolerance",
"Relative tolerance for the Newton solver.");
args.AddOption(&solver_art_type, "-art", "--adaptive-rel-tol",
"Type of adaptive relative linear solver tolerance:\n\t"
"0: None (default)\n\t"
"1: Eisenstat-Walker type 1\n\t"
"2: Eisenstat-Walker type 2");
args.AddOption(&lin_solver, "-ls", "--lin-solver",
"Linear solver:\n\t"
"0: l1-Jacobi\n\t"
@@ -147,12 +151,10 @@ int main (int argc, char *argv[])
args.AddOption(&devopt, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&surface_fit_adapt, "-sfa", "--adaptive-surface-fit",
"Scaling factor for surface fitting weight.");
"Enable or disable adaptive surface fitting.");
args.AddOption(&surface_fit_threshold, "-sft", "--surf-fit-threshold",
"Set threshold for surface fitting. TMOP solver will"
"terminate when max surface fitting error is below this limit");
args.AddOption(&surf_fit_const_max, "-sfcmax", "--surf-fit-const-max",
"Max surface fitting weight allowed");
args.AddOption(&adapt_marking, "-marking", "--adaptive-marking", "-no-amarking",
"--no-adaptive-marking",
"Enable or disable adaptive marking surface fitting.");
@@ -163,9 +165,9 @@ int main (int argc, char *argv[])
"-no-dist","--no-comp-dist",
"Compute distance from 0 level set or not.");
args.AddOption(&surf_ls_type, "-slstype", "--surf-ls-type",
"1 - Circle (DEFAULT), 2 - reactor level-set, 3 - squircle.");
"1 - Circle (DEFAULT), 2 - Squircle, 3 - Butterfly.");
args.AddOption(&marking_type, "-smtype", "--surf-marking-type",
"0 - Interface (DEFAULT), otherwise Boundary attribute.");
"1 - Interface (DEFAULT), 2 - Boundary attribute.");
args.AddOption(&mod_bndr_attr, "-mod-bndr-attr", "--modify-boundary-attribute",
"-fix-bndr-attr", "--fix-boundary-attribute",
"Change boundary attribute based on alignment with Cartesian axes.");
@@ -174,11 +176,8 @@ int main (int argc, char *argv[])
args.AddOption(&mesh_node_ordering, "-mno", "--mesh_node_ordering",
"Ordering of mesh nodes."
"0 (default): byNodes, 1: byVDIM");
args.AddOption(&bg_amr_iters, "-bgamriter", "--amr-iter",
args.AddOption(&amr_iters, "-amriter", "--amr-iter",
"Number of amr iterations on background mesh");
args.AddOption(&conv_residual, "-resid", "--resid", "-no-resid",
"--no-resid",
"Enable residual based convergence.");
args.Parse();
if (!args.Good())
{
@@ -190,11 +189,7 @@ int main (int argc, char *argv[])
Device device(devopt);
if (myid == 0) { device.Print();}
MFEM_VERIFY(surface_fit_const > 0.0,
"This miniapp is for surface fitting only. See (p)mesh-optimizer"
"miniapps for general high-order mesh optimization.");
// Initialize and refine the starting mesh.
// 3. Initialize and refine the starting mesh.
Mesh *mesh = new Mesh(mesh_file, 1, 1, false);
for (int lev = 0; lev < rs_levels; lev++)
{
@@ -212,10 +207,6 @@ int main (int argc, char *argv[])
{
ls_coeff = new FunctionCoefficient(reactor);
}
else if (surf_ls_type == 3) //squircle
{
ls_coeff = new FunctionCoefficient(squircle_level_set);
}
else if (surf_ls_type == 6) // 3D shape
{
ls_coeff = new FunctionCoefficient(csg_cubecylsph);
@@ -229,7 +220,7 @@ int main (int argc, char *argv[])
delete mesh;
for (int lev = 0; lev < rp_levels; lev++) { pmesh->UniformRefinement(); }
// Setup background mesh for surface fitting
// 4. Setup background mesh for surface fitting
ParMesh *pmesh_surf_fit_bg = NULL;
if (surf_bg_mesh)
{
@@ -249,10 +240,10 @@ int main (int argc, char *argv[])
delete mesh_surf_fit_bg;
}
// Define a finite element space on the mesh. Here we use vector finite
// elements which are tensor products of quadratic finite elements. The
// number of components in the vector finite element space is specified by
// the last parameter of the FiniteElementSpace constructor.
// 5. Define a finite element space on the mesh. Here we use vector finite
// elements which are tensor products of quadratic finite elements. The
// number of components in the vector finite element space is specified by
// the last parameter of the FiniteElementSpace constructor.
FiniteElementCollection *fec;
if (mesh_poly_deg <= 0)
{
@@ -263,21 +254,21 @@ int main (int argc, char *argv[])
ParFiniteElementSpace *pfespace =
new ParFiniteElementSpace(pmesh, fec, dim, mesh_node_ordering);
// Make the mesh curved based on the above finite element space. This
// means that we define the mesh elements through a fespace-based
// transformation of the reference element.
// 6. Make the mesh curved based on the above finite element space. This
// means that we define the mesh elements through a fespace-based
// transformation of the reference element.
pmesh->SetNodalFESpace(pfespace);
// 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.
// 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.
ParGridFunction x(pfespace);
pmesh->SetNodalGridFunction(&x);
x.SetTrueVector();
// Save the starting (prior to the optimization) mesh to a file. This
// output can be viewed later using GLVis: "glvis -m perturbed -np
// num_mpi_tasks".
// 10. Save the starting (prior to the optimization) mesh to a file. This
// output can be viewed later using GLVis: "glvis -m perturbed -np
// num_mpi_tasks".
{
ostringstream mesh_name;
mesh_name << "perturbed.mesh";
@@ -335,7 +326,16 @@ int main (int argc, char *argv[])
TMOP_Integrator *tmop_integ = new TMOP_Integrator(metric, target_c);
// Setup the quadrature rules for the TMOP integrator.
IntegrationRules *irules = &IntRulesLo;
IntegrationRules *irules = NULL;
switch (quad_type)
{
case 1: irules = &IntRulesLo; break;
case 2: irules = &IntRules; break;
case 3: irules = &IntRulesCU; break;
default:
if (myid == 0) { cout << "Unknown quad_type: " << quad_type << endl; }
return 3;
}
tmop_integ->SetIntegrationRules(*irules, quad_order);
if (myid == 0 && dim == 2)
{
@@ -423,7 +423,7 @@ int main (int argc, char *argv[])
if (surf_bg_mesh)
{
OptimizeMeshWithAMRAroundZeroLevelSet(*pmesh_surf_fit_bg, *ls_coeff,
bg_amr_iters, *surf_fit_bg_gf0);
amr_iters, *surf_fit_bg_gf0);
pmesh_surf_fit_bg->Rebalance();
surf_fit_bg_fes->Update();
surf_fit_bg_gf0->Update();
@@ -505,7 +505,6 @@ int main (int argc, char *argv[])
ModifyAttributeForMarkingDOFS(pmesh, mat, 0);
ModifyAttributeForMarkingDOFS(pmesh, mat, 1);
}
pmesh->SetAttributes();
GridFunctionCoefficient coeff_mat(&mat);
surf_fit_mat_gf.ProjectDiscCoefficient(coeff_mat,
@@ -580,22 +579,6 @@ int main (int argc, char *argv[])
}
}
// Unify marker across processor boundary
surf_fit_mat_gf.ExchangeFaceNbrData();
{
GroupCommunicator &gcomm = surf_fit_mat_gf.ParFESpace()->GroupComm();
Array<real_t> gf_array(surf_fit_mat_gf.GetData(),
surf_fit_mat_gf.Size());
gcomm.Reduce<real_t>(gf_array, GroupCommunicator::Max);
gcomm.Bcast(gf_array);
}
surf_fit_mat_gf.ExchangeFaceNbrData();
for (int i = 0; i < surf_fit_mat_gf.Size(); i++)
{
surf_fit_marker[i] = surf_fit_mat_gf(i) == 1.0;
}
// Set AdaptivityEvaluators for transferring information from initial
// mesh to current mesh as it moves during adaptivity.
if (adapt_eval == 0)
@@ -607,8 +590,11 @@ int main (int argc, char *argv[])
{
#ifdef MFEM_USE_GSLIB
adapt_surface = new InterpolatorFP;
adapt_grad_surface = new InterpolatorFP;
adapt_hess_surface = new InterpolatorFP;
if (surf_bg_mesh)
{
adapt_grad_surface = new InterpolatorFP;
adapt_hess_surface = new InterpolatorFP;
}
#else
MFEM_ABORT("MFEM is not built with GSLIB support!");
#endif
@@ -618,9 +604,7 @@ int main (int argc, char *argv[])
if (!surf_bg_mesh)
{
tmop_integ->EnableSurfaceFitting(surf_fit_gf0, surf_fit_marker,
surf_fit_coeff, *adapt_surface,
adapt_grad_surface,
adapt_hess_surface);
surf_fit_coeff, *adapt_surface);
}
else
{
@@ -648,9 +632,16 @@ int main (int argc, char *argv[])
}
}
}
pmesh->SetAttributes();
// Setup the final NonlinearForm.
// 13. Setup the final NonlinearForm (which defines the integral of interest,
// its first and second derivatives). Here we can use a combination of
// metrics, i.e., optimize the sum of two integrals, where both are
// scaled by used-defined space-dependent weights. Note that there are
// no command-line options for the weights and the type of the second
// metric; one should update those in the code.
ParNonlinearForm a(pfespace);
ConstantCoefficient *metric_coeff1 = NULL;
a.AddDomainIntegrator(tmop_integ);
// Compute the minimum det(J) of the starting mesh.
@@ -683,10 +674,10 @@ int main (int argc, char *argv[])
surf_fit_coeff.constant = surface_fit_const;
}
// Fix all boundary nodes, or fix only a given component depending on the
// boundary attributes of the given mesh. Attributes 1/2/3 correspond to
// fixed x/y/z components of the node. Attribute dim+1 corresponds to
// an entirely fixed node.
// 14. Fix all boundary nodes, or fix only a given component depending on the
// boundary attributes of the given mesh. Attributes 1/2/3 correspond to
// fixed x/y/z components of the node. Attribute dim+1 corresponds to
// an entirely fixed node.
if (move_bnd == false)
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
@@ -742,7 +733,8 @@ int main (int argc, char *argv[])
a.SetEssentialVDofs(ess_vdofs);
}
// Setup the linear solver for the system's Jacobian.
// 15. As we use the Newton method to solve the resulting nonlinear system,
// here we setup the linear solver for the system's Jacobian.
Solver *S = NULL, *S_prec = NULL;
#ifdef MFEM_USE_SINGLE
const real_t linsol_rtol = 1e-5;
@@ -792,14 +784,8 @@ int main (int argc, char *argv[])
}
if (surface_fit_threshold > 0)
{
solver.SetSurfaceFittingMaxErrorLimit(surface_fit_threshold);
solver.SetTerminationWithMaxSurfaceFittingError(surface_fit_threshold);
}
solver.SetSurfaceFittingConvergenceBasedOnError(!conv_residual);
if (conv_residual)
{
solver.SetSurfaceFittingWeightLimit(surf_fit_const_max);
}
// Provide all integration rules in case of a mixed mesh.
solver.SetIntegrationRules(*irules, quad_order);
if (solver_type == 0)
@@ -811,14 +797,18 @@ int main (int argc, char *argv[])
solver.SetRelTol(solver_rtol);
solver.SetAbsTol(0.0);
solver.SetMinimumDeterminantThreshold(0.001*min_detJ);
if (solver_art_type > 0)
{
solver.SetAdaptiveLinRtol(solver_art_type, 0.5, 0.9);
}
solver.SetPrintLevel(verbosity_level >= 1 ? 1 : -1);
solver.SetOperator(a);
Vector b(0);
solver.Mult(b, x.GetTrueVector());
x.SetFromTrueVector();
// Save the optimized mesh to a file. This output can be viewed later
// using GLVis: "glvis -m optimized -np num_mpi_tasks".
// 16. Save the optimized mesh to a file. This output can be viewed later
// using GLVis: "glvis -m optimized -np num_mpi_tasks".
{
ostringstream mesh_name;
mesh_name << "optimized.mesh";
@@ -852,13 +842,9 @@ int main (int argc, char *argv[])
if (surface_fit_const > 0.0)
{
adapt_surface->ComputeAtNewPosition(x, surf_fit_gf0,
x.FESpace()->GetOrdering());
if (visualization)
{
socketstream vis1, vis2, vis3;
common::VisualizeField(vis1, "localhost", 19916, surf_fit_gf0,
"Level Set", 000, 400, 300, 300);
socketstream vis2, vis3;
common::VisualizeField(vis2, "localhost", 19916, mat,
"Materials", 300, 400, 300, 300);
common::VisualizeField(vis3, "localhost", 19916, surf_fit_mat_gf,
@@ -873,7 +859,7 @@ int main (int argc, char *argv[])
}
}
// Visualize the mesh displacement.
// 18. Visualize the mesh displacement.
if (visualization)
{
x0 -= x;
@@ -884,6 +870,7 @@ int main (int argc, char *argv[])
delete S;
delete S_prec;
delete metric_coeff1;
delete adapt_surface;
delete adapt_grad_surface;
delete adapt_hess_surface;
-3
View File
@@ -55,9 +55,6 @@ MESH_FILES = $(notdir $(wildcard $(SRC)*.mesh))
$(MESH_FILES): %: $(SRC)%
ln -sf $(<) .
multidomain: | $(MESH_FILES)
# The target 'copy-data' is used by the makefile in ../../tests/unit
.PHONY: copy-data
copy-data: | $(MESH_FILES)
endif
MFEM_TESTS = MINIAPPS
+7 -84
View File
@@ -13,18 +13,6 @@ add_mfem_miniapp(nurbs_ex1
MAIN nurbs_ex1.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_ex3
MAIN nurbs_ex3.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_ex5
MAIN nurbs_ex5.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_ex24
MAIN nurbs_ex24.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_curveint
MAIN nurbs_curveint.cpp
LIBRARIES mfem)
@@ -41,14 +29,6 @@ add_mfem_miniapp(nurbs_patch_ex1
MAIN nurbs_patch_ex1.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_solenoidal
MAIN nurbs_solenoidal.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_biharm
MAIN nurbs_biharm.cpp
LIBRARIES mfem)
if (MFEM_ENABLE_TESTING)
add_test(NAME nurbs_ex1_1d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
@@ -84,10 +64,6 @@ if (MFEM_ENABLE_TESTING)
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 --weak-bc -r 2)
add_test(NAME nurbs_ex1_neu_r2_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -r 2 --neu "3")
add_test(NAME nurbs_ex1_weak_mp_ser
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/ball-nurbs.mesh -o 2 --weak-bc -r 0)
@@ -149,64 +125,9 @@ if (MFEM_ENABLE_TESTING)
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/two-cubes-nurbs-autoedge.mesh -o 1 -r 3 -rf ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/two-cubes.ref)
add_test(NAME nurbs_ex1_periodic_2d
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -o 2 -r 2 --master "3" --slave "4")
add_test(NAME nurbs_ex1_periodic_3d
COMMAND $<TARGET_FILE:nurbs_ex1> -no-vis
-m ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube-nurbs.mesh
-rf ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube.ref
--master "1" --slave "2")
add_test(NAME nurbs_ex3_2d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_ex3> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
add_test(NAME nurbs_ex3_3d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_ex3> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2)
add_test(NAME nurbs_ex5_2d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_ex5> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
add_test(NAME nurbs_ex5_3d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_ex5> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2)
add_test(NAME nurbs_ex24_2d_r1_o2_p0_ser
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 0)
add_test(NAME nurbs_ex24_2d_r1_o2_p2_ser
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 2)
add_test(NAME nurbs_ex24_3d_r1_o2_p0_ser
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2 -p 0)
add_test(NAME nurbs_ex24_3d_r1_o2_p1_ser
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2 -p 1)
add_test(NAME nurbs_ex24_3d_r1_o2_p2_ser
COMMAND $<TARGET_FILE:nurbs_ex24> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2 -p 2)
add_test(NAME nurbs_solenoidal_2d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_solenoidal> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/pipe-nurbs-2d.mesh -r 1 -o 2)
add_test(NAME nurbs_solenoidal_3d_r1_o2_ser
COMMAND $<TARGET_FILE:nurbs_solenoidal> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/cube-nurbs.mesh -r 1 -o 2)
add_test(NAME nurbs_biharm_ser
COMMAND $<TARGET_FILE:nurbs_biharm> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
-m ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube-nurbs.mesh -pm "1" -ps "2" -rf ${PROJECT_SOURCE_DIR}/miniapps/nurbs/meshes/cube.ref)
endif()
if (MFEM_USE_MPI)
@@ -214,10 +135,6 @@ if (MFEM_USE_MPI)
MAIN nurbs_ex1p.cpp
LIBRARIES mfem)
add_mfem_miniapp(nurbs_ex11p
MAIN nurbs_ex11p.cpp
LIBRARIES mfem)
if (MFEM_ENABLE_TESTING)
add_test(NAME nurbs_ex1p_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
@@ -252,7 +169,13 @@ if (MFEM_USE_MPI)
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex1p> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-disc-nurbs-patch.mesh -o 2 --weak-bc -r 1)
endif()
add_mfem_miniapp(nurbs_ex11p
MAIN nurbs_ex11p.cpp
LIBRARIES mfem)
if (MFEM_ENABLE_TESTING)
add_test(NAME nurbs_ex11p_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:nurbs_ex11p> -no-vis
+4 -33
View File
@@ -21,7 +21,8 @@ CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_MINIAPPS = nurbs_ex1 nurbs_patch_ex1 nurbs_ex3 nurbs_ex5 nurbs_ex24 nurbs_curveint nurbs_printfunc nurbs_solenoidal nurbs_naca_cmesh
SEQ_MINIAPPS = nurbs_ex1 nurbs_patch_ex1 nurbs_curveint nurbs_printfunc nurbs_naca_cmesh
PAR_MINIAPPS = nurbs_ex1p nurbs_ex11p
ifeq ($(MFEM_USE_MPI),NO)
MINIAPPS = $(SEQ_MINIAPPS)
@@ -102,36 +103,6 @@ endif
@$(call mfem-test,$<,, NURBS miniapp,$(EX1PATCH_ARGS_2))
@$(call mfem-test,$<,, NURBS miniapp,$(EX1PATCH_ARGS_3))
EX3_ARGS_1 := -m $(MFEM_DIR)/data/square-nurbs.mesh -r 1 -o 2
EX3_ARGS_2 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2
nurbs_ex3-test-seq: nurbs_ex3
@$(call mfem-test,$<,, NURBS miniapp,$(EX3_ARGS_1))
@$(call mfem-test,$<,, NURBS miniapp,$(EX3_ARGS_2))
EX5_ARGS_1 := -m $(MFEM_DIR)/data/square-nurbs.mesh -r 1 -o 2
EX5_ARGS_2 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2
nurbs_ex5-test-seq: nurbs_ex5
@$(call mfem-test,$<,, NURBS miniapp,$(EX5_ARGS_1))
@$(call mfem-test,$<,, NURBS miniapp,$(EX5_ARGS_2))
EX24_ARGS_1 := -m $(MFEM_DIR)/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 0
EX24_ARGS_2 := -m $(MFEM_DIR)/data/pipe-nurbs-2d.mesh -r 1 -o 2 -p 2
EX24_ARGS_3 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2 -p 0
EX24_ARGS_4 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2 -p 1
EX24_ARGS_5 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2 -p 2
nurbs_ex24-test-seq: nurbs_ex24
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_1))
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_2))
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_3))
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_4))
@$(call mfem-test,$<,, NURBS miniapp,$(EX24_ARGS_5))
SOL_ARGS_1 := -m $(MFEM_DIR)/data/pipe-nurbs-2d.mesh -r 1 -o 2
SOL_ARGS_1 := -m $(MFEM_DIR)/data/cube-nurbs.mesh -r 1 -o 2
nurbs_sol-test-seq: nurbs_solenoidal
@$(call mfem-test,$<,, NURBS miniapp,$(SOL_ARGS_1))
@$(call mfem-test,$<,, NURBS miniapp,$(SOl_ARGS_2))
CI_ARGS_1 := -uw -n 9 -no-visit
CI_ARGS_2 := -nw -n 9 -no-visit
@@ -180,6 +151,6 @@ clean-build:
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -f refined.mesh sin-fit.mesh ex5.mesh exsol.mesh mesh.* sol.* mode_* naca-cmesh.mesh sol_?.gf
@rm -rf Example1* Example3* Example5* Solenoidal_* ParaView
@rm -f refined.mesh sin-fit.mesh mesh.* sol.* mode_* naca-cmesh.mesh
@rm -rf Example1*
@rm -rf CurveInt Naca_cmesh glvis_naca-cmesh.mesh
-408
View File
@@ -1,408 +0,0 @@
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
//
// Stabilized Convection-Diffusion
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <list>
using namespace std;
using namespace mfem;
real_t kappa_param = 1.0;
real_t dif_fun(const Vector & x)
{
return kappa_param;
}
real_t force_fun(const Vector & x)
{
int d = x.Size();
real_t kappa = dif_fun(x);
real_t pi = (real_t)(M_PI);
real_t sx = sin(pi*x[0]);
real_t sy = 1.0;
real_t sz = 1.0;
if (d >= 2)
{
sy = sin(pi*x[1]);
}
if (d >= 3)
{
sz = sin(pi*x[2]);
}
return d*d*kappa*pi*pi*pi*pi*sx*sy*sz;
}
real_t sol_fun(const Vector & x)
{
real_t pi = (real_t)(M_PI);
real_t sx = sin(pi*x[0]);
real_t sy = 1.0;
real_t sz = 1.0;
int d = x.Size();
if (d >= 2)
{
sy = sin(pi*x[1]);
}
if (d >= 3)
{
sz = sin(pi*x[2]);
}
return sx*sy*sz;
}
void grad_fun(const Vector & x, Vector & a)
{
real_t pi = (real_t)(M_PI);
real_t sx = sin(pi*x[0]);
real_t cx = cos(pi*x[0]);
real_t sy = 1.0;
real_t cy = 1.0;
real_t sz = 1.0;
real_t cz = 1.0;
int d = x.Size();
if (d >= 2)
{
sy = sin(pi*x[1]);
cy = cos(pi*x[1]);
}
if (d >= 3)
{
sz = sin(pi*x[2]);
cz = cos(pi*x[2]);
}
a[0] = pi*cx*sy;
a[1] = pi*sx*cy;
}
//----------------------------------------------------------
real_t lap_fun(const Vector & x)
{
real_t pi = (real_t)(M_PI);
real_t sx = sin(pi*x[0]);
real_t cx = cos(pi*x[0]);
real_t sy = 1.0;
real_t cy = 1.0;
real_t sz = 1.0;
real_t cz = 1.0;
int d = x.Size();
if (d >= 2)
{
sy = sin(pi*x[1]);
cy = cos(pi*x[1]);
}
if (d >= 3)
{
sz = sin(pi*x[2]);
cz = cos(pi*x[2]);
}
return -d*pi*pi*sx*sy*sz;
}
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/square-nurbs.mesh";
const char *per_file = "none";
const char *ref_file = "";
int ref_levels = 0;
Array<int> master(0);
Array<int> slave(0);
bool static_cond = false;
bool visualization = false;
real_t penalty = -1;
Array<int> order(1);
order[0] = 2;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&per_file, "-p", "--per",
"Periodic BCS file.");
args.AddOption(&ref_file, "-rf", "--ref-file",
"File with refinement data");
args.AddOption(&master, "-pm", "--master",
"Master boundaries for periodic BCs");
args.AddOption(&slave, "-ps", "--slave",
"Slave boundaries for periodic BCs");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&kappa_param, "-k", "--kappa",
"Sets the diffusion parameters, should be positive."
" Negative values are replaced with function defined in source.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(mfem::out);
return 1;
}
args.PrintOptions(mfem::out);
if (order.Min()< 2)
{
mfem_error("Wrong order.");
}
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement and knot insertion of knots defined
// in a refinement file. We choose 'ref_levels' to be the largest number
// that gives a final mesh with no more than 50,000 elements.
{
// Mesh refinement as defined in refinement file
if (mesh->NURBSext && (strlen(ref_file) != 0))
{
mesh->RefineNURBSFromFile(ref_file);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
mesh->PrintInfo();
}
// 4. Define a finite element space on the mesh. Here we use continuous
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
NURBSExtension *NURBSext = NULL;
int own_fec = 0;
if (mesh->NURBSext)
{
fec = new NURBSFECollection(order[0]);
own_fec = 1;
int nkv = mesh->NURBSext->GetNKV();
if (order.Size() == 1)
{
int tmp = order[0];
order.SetSize(nkv);
order = tmp;
}
if (order.Size() != nkv ) { mfem_error("Wrong number of orders set."); }
NURBSext = new NURBSExtension(mesh->NURBSext, order);
// Read periodic BCs from file
std::ifstream in;
in.open(per_file, std::ifstream::in);
if (in.is_open())
{
int psize;
in >> psize;
master.SetSize(psize);
slave.SetSize(psize);
master.Load(in, psize);
slave.Load(in, psize);
in.close();
}
master.Print();
slave.Print();
NURBSext->ConnectBoundaries(master,slave);
}
else if (order[0] == -1) // Isoparametric
{
if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
own_fec = 0;
mfem::out << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
mfem::out <<"Mesh does not have FEs --> Assume order 1.\n";
fec = new H1_FECollection(1, dim);
own_fec = 1;
}
}
else
{
if (order.Size() > 1) { cout <<"Wrong number of orders set, needs one.\n"; }
fec = new H1_FECollection(abs(order[0]), dim);
own_fec = 1;
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, NURBSext, fec);
mfem::out << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
// Remove periodic BCs
for (int i = 0; i < master.Size(); i++)
{
ess_bdr[master[i]-1] = 0;
ess_bdr[slave[i]-1] = 0;
}
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
ConstantCoefficient u_dir(0.0);
Coefficient *kappa_tmp;
if (kappa_param < 0.0)
{
kappa_tmp = new FunctionCoefficient(dif_fun);
}
else
{
kappa_tmp = new ConstantCoefficient(kappa_param);
}
Coefficient& kappa = *kappa_tmp;
FunctionCoefficient force(force_fun);
LinearForm *b = new LinearForm(fespace);
b->AddDomainIntegrator(new DomainLFIntegrator(force));
b->Assemble();
// 7. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
GridFunction x(fespace);
x = 0.0;
// 8. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new LaplaceLaplaceIntegrator(kappa));
// 9. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
mfem::out << "Size of linear system: " << A.Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 10. Define a simple Jacobi preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
GMRES(A, M, B, X, 1, 2000, 2000, 1e-16, 0.0);
#else
// 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
#endif
// 11. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 12. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
{
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
sol_ofs.close();
}
// 13. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 14. Error computation
Vector norm(3);
int order_quad = 3*order.Max() + 4;
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
FunctionCoefficient sol_cf(sol_fun);
VectorFunctionCoefficient grad_cf(mesh->Dimension(), grad_fun);
FunctionCoefficient lap_cf(lap_fun);
norm[0]= x.ComputeL2Error(sol_cf,irs);
norm[1]= x.ComputeGradError(&grad_cf, irs);
norm[2] = x.ComputeLaplaceError(&lap_cf, irs);
mfem::out << "|| x_h - x_ex || = " << norm[0] << "\n";
mfem::out << "|| grad x_h - grad x_ex || = " << norm[1] << "\n";
mfem::out << "|| lap x_h - lap x_ex || = " << norm[2] << "\n";
// 15. Save data in the VisIt format
VisItDataCollection visit_dc("Biharm", mesh);
visit_dc.RegisterField("solution", &x);
visit_dc.Save();
// 16. Free the used memory.
delete fespace;
if (own_fec) { delete fec; }
delete mesh;
return 0;
}
+103 -71
View File
@@ -6,7 +6,6 @@
// nurbs_ex1 -m ../../data/square-nurbs.mesh -o 2 --weak-bc
// nurbs_ex1 -m ../../data/cube-nurbs.mesh -o 2 -no-ibp
// nurbs_ex1 -m ../../data/pipe-nurbs-2d.mesh -o 2 -no-ibp
// nurbs_ex1 -m ../../data/pipe-nurbs-2d.mesh -o 2 -r 2 --neu "3"
// nurbs_ex1 -m ../../data/square-disc-nurbs.mesh -o -1
// nurbs_ex1 -m ../../data/disc-nurbs.mesh -o -1
// nurbs_ex1 -m ../../data/pipe-nurbs.mesh -o -1
@@ -53,17 +52,101 @@ public:
inline bool operator==(const Data& d1,const Data& d2) { return (d1.x == d2.x); }
inline bool operator <(const Data& d1,const Data& d2) { return (d1.x < d2.x); }
/** Class for integrating the bilinear form a(u,v) := (Q Laplace u, v) where Q
can be a scalar coefficient. */
class Diffusion2Integrator: public BilinearFormIntegrator
{
private:
#ifndef MFEM_THREAD_SAFE
Vector shape,laplace;
#endif
Coefficient *Q;
public:
/// Construct a diffusion integrator with coefficient Q = 1
Diffusion2Integrator() { Q = NULL; }
/// Construct a diffusion integrator with a scalar coefficient q
Diffusion2Integrator (Coefficient &q) : Q(&q) { }
/** Given a particular Finite Element
computes the element stiffness matrix elmat. */
virtual void AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat)
{
int nd = el.GetDof();
int dim = el.GetDim();
real_t w;
#ifdef MFEM_THREAD_SAFE
Vector shape(nd);
Vector laplace(nd);
#else
shape.SetSize(nd);
laplace.SetSize(nd);
#endif
elmat.SetSize(nd);
const IntegrationRule *ir = IntRule;
if (ir == NULL)
{
int order;
if (el.Space() == FunctionSpace::Pk)
{
order = 2*el.GetOrder() - 2;
}
else
{
order = 2*el.GetOrder() + dim - 1;
}
if (el.Space() == FunctionSpace::rQk)
{
ir = &RefinedIntRules.Get(el.GetGeomType(),order);
}
else
{
ir = &IntRules.Get(el.GetGeomType(),order);
}
}
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint(&ip);
w = -ip.weight * Trans.Weight();
el.CalcShape(ip, shape);
el.CalcPhysLaplacian(Trans, laplace);
if (Q)
{
w *= Q->Eval(Trans, ip);
}
for (int jj = 0; jj < nd; jj++)
{
for (int ii = 0; ii < nd; ii++)
{
elmat(ii, jj) += w*shape(ii)*laplace(jj);
}
}
}
}
};
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/square-nurbs.mesh";
const char *mesh_file = "../../data/star.mesh";
const char *per_file = "none";
const char *ref_file = "";
int ref_levels = -1;
Array<int> master(0);
Array<int> slave(0);
Array<int> neu(0);
bool static_cond = false;
bool visualization = 1;
int lod = 0;
@@ -86,8 +169,6 @@ int main(int argc, char *argv[])
"Master boundaries for periodic BCs");
args.AddOption(&slave, "-ps", "--slave",
"Slave boundaries for periodic BCs");
args.AddOption(&neu, "-n", "--neu",
"Boundaries with Neumann BCs");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
@@ -185,6 +266,8 @@ int main(int argc, char *argv[])
slave.Load(in, psize);
in.close();
}
master.Print();
slave.Print();
NURBSext->ConnectBoundaries(master,slave);
}
else if (order[0] == -1) // Isoparametric
@@ -240,84 +323,39 @@ int main(int argc, char *argv[])
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_bdr(0);
Array<int> neu_bdr(0);
Array<int> per_bdr(0);
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
ess_bdr.SetSize(mesh->bdr_attributes.Max());
neu_bdr.SetSize(mesh->bdr_attributes.Max());
per_bdr.SetSize(mesh->bdr_attributes.Max());
ess_bdr = 1;
neu_bdr = 0;
per_bdr = 0;
// Apply Neumann BCs
for (int i = 0; i < neu.Size(); i++)
Array<int> ess_bdr(mesh->bdr_attributes.Max());
if (strongBC)
{
if ( neu[i]-1 >= 0 &&
neu[i]-1 < mesh->bdr_attributes.Max())
{
ess_bdr[neu[i]-1] = 0;
neu_bdr[neu[i]-1] = 1;
}
else
{
cout <<"Neumann boundary "<<neu[i]<<" out of range -- discarded"<< endl;
}
ess_bdr = 1;
}
else
{
ess_bdr = 0;
}
// Correct for periodic BCs
// Remove periodic BCs
for (int i = 0; i < master.Size(); i++)
{
if ( master[i]-1 >= 0 &&
master[i]-1 < mesh->bdr_attributes.Max())
{
ess_bdr[master[i]-1] = 0;
neu_bdr[master[i]-1] = 0;
per_bdr[master[i]-1] = 1;
}
else
{
cout <<"Master boundary "<<master[i]<<" out of range -- discarded"<< endl;
}
}
for (int i = 0; i < slave.Size(); i++)
{
if ( slave[i]-1 >= 0 &&
slave[i]-1 < mesh->bdr_attributes.Max())
{
ess_bdr[slave[i]-1] = 0;
neu_bdr[slave[i]-1] = 0;
per_bdr[slave[i]-1] = 1;
}
else
{
cout <<"Slave boundary "<<slave[i]<<" out of range -- discarded"<< endl;
}
ess_bdr[master[i]-1] = 0;
ess_bdr[slave[i]-1] = 0;
}
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
cout <<"Boundary conditions:"<< endl;
cout <<" - Periodic : "; per_bdr.Print();
cout <<" - Essential : "; ess_bdr.Print();
cout <<" - Neumann : "; neu_bdr.Print();
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
ConstantCoefficient one(1.0);
ConstantCoefficient mone(-1.0);
ConstantCoefficient zero(0.0);
LinearForm *b = new LinearForm(fespace);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->AddBoundaryIntegrator( new BoundaryLFIntegrator(one),neu_bdr);
if (!strongBC)
b->AddBdrFaceIntegrator(
new DGDirichletLFIntegrator(zero, one, -1.0, kappa), ess_bdr);
new DGDirichletLFIntegrator(zero, one, -1.0, kappa));
b->Assemble();
// 7. Define the solution vector x as a finite element grid function
@@ -336,13 +374,12 @@ int main(int argc, char *argv[])
}
else
{
a->AddDomainIntegrator(new LaplaceIntegrator(one, -1.0));
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(mone, 0.0, 0.0), neu_bdr);
a->AddDomainIntegrator(new Diffusion2Integrator(one));
}
if (!strongBC)
{
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, -1.0, kappa), ess_bdr);
a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, -1.0, kappa));
}
// 9. Assemble the bilinear form and the corresponding linear system,
@@ -354,11 +391,6 @@ int main(int argc, char *argv[])
SparseMatrix A;
Vector B, X;
Array<int> ess_tdof_list(0);
if (strongBC)
{
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A.Height() << endl;
-459
View File
@@ -1,459 +0,0 @@
// MFEM Example 24 -- modified for NURBS FE
//
// Compile with: make nurbs_ex24
//
// Sample runs: nurbs_ex24 -m ../../data/pipe-nurbs-2d.mesh -o 2
// nurbs_ex24 -m ../../data/pipe-nurbs-2d.mesh -p 2
// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2
// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2 -p 1
// nurbs_ex24 -m ../../data/cube-nurbs.mesh -o 2 -p 2
// nurbs_ex24 -m ../../data/escher.mesh
// nurbs_ex24 -m ../../data/escher.mesh -o 2
// nurbs_ex24 -m ../../data/fichera.mesh
// nurbs_ex24 -m ../../data/fichera-q2.vtk
// nurbs_ex24 -m ../../data/fichera-q3.mesh
// nurbs_ex24 -m ../../data/amr-quad.mesh -o 2
// nurbs_ex24 -m ../../data/amr-hex.mesh
//
// Device sample runs -- do not work for NURBS:
// nurbs_ex24 -m ../../data/escher.mesh -pa -d cuda
// nurbs_ex24 -m ../../data/escher.mesh -pa -d raja-cuda
// nurbs_ex24 -m ../../data/escher.mesh -pa -d raja-omp
//
// Description: This example code illustrates usage of mixed finite element
// spaces, with three variants:
//
// 0) (grad p, u) for p in H^1 tested against u in H(curl)
// 1) (curl v, u) for v in H(curl) tested against u in H(div), 3D
// 2) (div v, q) for v in H(div) tested against q in L_2
//
// Using different approaches, we project the gradient, curl, or
// divergence to the appropriate space.
//
// NURBS-based H(curl) and H(div) spaces only implemented
// for meshes consisting of a single patch.
//
// We recommend viewing examples 1, 3, and 5 before viewing this
// example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
real_t p_exact(const Vector &x);
void gradp_exact(const Vector &, Vector &);
real_t div_gradp_exact(const Vector &x);
void v_exact(const Vector &x, Vector &v);
void curlv_exact(const Vector &x, Vector &cv);
int dim;
real_t freq = 1.0, kappa;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/cube-nurbs.mesh";
int ref_levels = -1;
int order = 1;
bool NURBS = true;
int prob = 0;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&NURBS, "-n", "--nurbs", "-nn","--no-nurbs",
"NURBS.");
args.AddOption(&prob, "-p", "--problem-type",
"Choose between 0: grad, 1: curl, 2: div");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
kappa = freq * M_PI;
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
if ((prob == 1) &&(dim != 3))
{
MFEM_ABORT("The curl problem is only defined in 3D.");
}
int sdim = mesh->SpaceDimension();
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 50,000
// elements.
{
if (ref_levels < 0)
{
ref_levels = (int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a finite element space on the mesh. Here we use Nedelec or
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *trial_fec = nullptr;
FiniteElementCollection *test_fec = nullptr;
NURBSExtension *NURBSext = nullptr;
if (mesh->NURBSext && NURBS)
{
NURBSext = new NURBSExtension(mesh->NURBSext, order);
if (prob == 0)
{
trial_fec = new NURBSFECollection(order);
test_fec = new NURBS_HCurlFECollection(order, dim);
}
else if (prob == 1)
{
trial_fec = new NURBS_HCurlFECollection(order, dim);
test_fec = new NURBS_HDivFECollection(order, dim);
}
else
{
trial_fec = new NURBS_HDivFECollection(order, dim);
test_fec = new NURBSFECollection(order);
}
mfem::out<<"Create NURBS fec and ext"<<std::endl;
}
else
{
if (prob == 0)
{
trial_fec = new H1_FECollection(order, dim);
test_fec = new ND_FECollection(order, dim);
}
else if (prob == 1)
{
trial_fec = new ND_FECollection(order, dim);
test_fec = new RT_FECollection(order-1, dim);
}
else
{
trial_fec = new RT_FECollection(order-1, dim);
test_fec = new L2_FECollection(order-1, dim);
}
}
FiniteElementSpace trial_fes(mesh, NURBSext, trial_fec);
FiniteElementSpace test_fes(mesh,trial_fes.StealNURBSext(), test_fec);
int trial_size = trial_fes.GetTrueVSize();
int test_size = test_fes.GetTrueVSize();
if (prob == 0)
{
cout << "Number of Nedelec finite element unknowns: " << test_size << endl;
cout << "Number of H1 finite element unknowns: " << trial_size << endl;
}
else if (prob == 1)
{
cout << "Number of Nedelec finite element unknowns: " << trial_size << endl;
cout << "Number of Raviart-Thomas finite element unknowns: " << test_size <<
endl;
}
else
{
cout << "Number of Raviart-Thomas finite element unknowns: "
<< trial_size << endl;
cout << "Number of L2 finite element unknowns: " << test_size << endl;
}
// 6. Define the solution vector as a finite element grid function
// corresponding to the trial fespace.
GridFunction gftest(&test_fes);
GridFunction gftrial(&trial_fes);
GridFunction x(&test_fes);
FunctionCoefficient p_coef(p_exact);
VectorFunctionCoefficient gradp_coef(sdim, gradp_exact);
VectorFunctionCoefficient v_coef(sdim, v_exact);
VectorFunctionCoefficient curlv_coef(sdim, curlv_exact);
FunctionCoefficient divgradp_coef(div_gradp_exact);
if (prob == 0)
{
gftrial.ProjectCoefficient(p_coef);
}
else if (prob == 1)
{
gftrial.ProjectCoefficient(v_coef);
}
else
{
gftrial.ProjectCoefficient(gradp_coef);
}
gftrial.SetTrueVector();
gftrial.SetFromTrueVector();
// 7. Set up the bilinear forms for L2 projection.
ConstantCoefficient one(1.0);
BilinearForm a(&test_fes);
MixedBilinearForm a_mixed(&trial_fes, &test_fes);
if (pa)
{
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
a_mixed.SetAssemblyLevel(AssemblyLevel::PARTIAL);
}
if (prob == 0)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorGradientIntegrator(one));
}
else if (prob == 1)
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(one));
a_mixed.AddDomainIntegrator(new MixedVectorCurlIntegrator(one));
}
else
{
a.AddDomainIntegrator(new MassIntegrator(one));
a_mixed.AddDomainIntegrator(new VectorFEDivergenceIntegrator(one));
}
// 8. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a.EnableStaticCondensation(); }
a.Assemble();
if (!pa) { a.Finalize(); }
a_mixed.Assemble();
if (!pa) { a_mixed.Finalize(); }
if (pa)
{
a_mixed.Mult(gftrial, x);
}
else
{
SparseMatrix& mixed = a_mixed.SpMat();
mixed.Mult(gftrial, x);
}
// 9. Define and apply a PCG solver for Ax = b with Jacobi preconditioner.
{
GridFunction rhs(&test_fes);
rhs = x;
x = 0.0;
CGSolver cg;
cg.SetRelTol(1e-12);
cg.SetMaxIter(1000);
cg.SetPrintLevel(1);
if (pa)
{
Array<int> ess_tdof_list; // empty
OperatorJacobiSmoother Jacobi(a, ess_tdof_list);
cg.SetOperator(a);
cg.SetPreconditioner(Jacobi);
cg.Mult(rhs, x);
}
else
{
SparseMatrix& Amat = a.SpMat();
DSmoother Jacobi(Amat);
cg.SetOperator(Amat);
cg.SetPreconditioner(Jacobi);
cg.Mult(rhs, x);
}
}
// 10. Compute the projection of the exact field.
GridFunction exact_proj(&test_fes);
if (prob == 0)
{
exact_proj.ProjectCoefficient(gradp_coef);
}
else if (prob == 1)
{
exact_proj.ProjectCoefficient(curlv_coef);
}
else
{
exact_proj.ProjectCoefficient(divgradp_coef);
}
exact_proj.SetTrueVector();
exact_proj.SetFromTrueVector();
// 11. Compute and print the L_2 norm of the error.
if (prob == 0)
{
real_t errSol = x.ComputeL2Error(gradp_coef);
real_t errProj = exact_proj.ComputeL2Error(gradp_coef);
cout << "\n Solution of (E_h,v) = (grad p_h,v) for E_h and v in H(curl): "
"|| E_h - grad p ||_{L_2} = " << errSol << '\n' << endl;
cout << " Projection E_h of exact grad p in H(curl): || E_h - grad p "
"||_{L_2} = " << errProj << '\n' << endl;
}
else if (prob == 1)
{
real_t errSol = x.ComputeL2Error(curlv_coef);
real_t errProj = exact_proj.ComputeL2Error(curlv_coef);
cout << "\n Solution of (E_h,w) = (curl v_h,w) for E_h and w in H(div): "
"|| E_h - curl v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Projection E_h of exact curl v in H(div): || E_h - curl v "
"||_{L_2} = " << errProj << '\n' << endl;
}
else
{
int order_quad = max(3, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t errSol = x.ComputeL2Error(divgradp_coef, irs);
real_t errProj = exact_proj.ComputeL2Error(divgradp_coef, irs);
cout << "\n Solution of (f_h,q) = (div v_h,q) for f_h and q in L_2: "
"|| f_h - div v ||_{L_2} = " << errSol << '\n' << endl;
cout << " Projection f_h of exact div v in L_2: || f_h - div v "
"||_{L_2} = " << errProj << '\n' << endl;
}
// 12. Save the refined mesh and the solution. This output can be viewed
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
// 13. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 14. Free the used memory.
delete trial_fec;
delete test_fec;
delete mesh;
return 0;
}
real_t p_exact(const Vector &x)
{
if (dim == 3)
{
return sin(x(0)) * sin(x(1)) * sin(x(2));
}
else if (dim == 2)
{
return sin(x(0)) * sin(x(1));
}
return 0.0;
}
void gradp_exact(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = cos(x(0)) * sin(x(1)) * sin(x(2));
f(1) = sin(x(0)) * cos(x(1)) * sin(x(2));
f(2) = sin(x(0)) * sin(x(1)) * cos(x(2));
}
else
{
f(0) = cos(x(0)) * sin(x(1));
f(1) = sin(x(0)) * cos(x(1));
if (x.Size() == 3) { f(2) = 0.0; }
}
}
real_t div_gradp_exact(const Vector &x)
{
if (dim == 3)
{
return -3.0 * sin(x(0)) * sin(x(1)) * sin(x(2));
}
else if (dim == 2)
{
return -2.0 * sin(x(0)) * sin(x(1));
}
return 0.0;
}
void v_exact(const Vector &x, Vector &v)
{
if (dim == 3)
{
v(0) = sin(kappa * x(1));
v(1) = sin(kappa * x(2));
v(2) = sin(kappa * x(0));
}
else
{
v(0) = sin(kappa * x(1));
v(1) = sin(kappa * x(0));
if (x.Size() == 3) { v(2) = 0.0; }
}
}
void curlv_exact(const Vector &x, Vector &cv)
{
if (dim == 3)
{
cv(0) = -kappa * cos(kappa * x(2));
cv(1) = -kappa * cos(kappa * x(0));
cv(2) = -kappa * cos(kappa * x(1));
}
else
{
cv = 0.0;
}
}
-284
View File
@@ -1,284 +0,0 @@
// MFEM Example 3 -- modified for NURBS FE
//
// Compile with: make nurbs_ex3
//
// Sample runs: nurbs_ex3 -m ../../data/square-nurbs.mesh
// nurbs_ex3 -m ../../data/square-nurbs.mesh -o 2
// nurbs_ex3 -m ../../data/cube-nurbs.mesh
//
// Description: This example code solves a simple electromagnetic diffusion
// problem corresponding to the second order definite Maxwell
// equation curl curl E + E = f with boundary condition
// E x n = <given tangential field>. Here, we use a given exact
// solution E and compute the corresponding r.h.s. f.
// We discretize with Nedelec finite elements in 2D or 3D.
//
// The example demonstrates the use of H(curl) finite element
// spaces with the curl-curl and the (vector finite element) mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Static condensation is
// also illustrated.
//
// NURBS-based H(curl) spaces only implemented for meshes
// consisting of a single patch.
//
// We recommend viewing examples 1-2 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Exact solution, E, and r.h.s., f. See below for implementation.
void E_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
real_t freq = 1.0, kappa;
int dim;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/square-nurbs.mesh";
int ref_levels = -1;
bool NURBS = true;
int order = 1;
bool static_cond = false;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&NURBS, "-n", "--nurbs", "-nn","--no-nurbs",
"NURBS.");
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
" solution.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
kappa = freq * M_PI;
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 50,000
// elements.
{
if (ref_levels < 0)
{
ref_levels =
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a finite element space on the mesh. Here we use the
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *fec = nullptr;
NURBSExtension *NURBSext = nullptr;
if (mesh->NURBSext && NURBS)
{
fec = new NURBS_HCurlFECollection(order,dim);
NURBSext = new NURBSExtension(mesh->NURBSext, order);
mfem::out<<"Create NURBS fec and ext"<<std::endl;
}
else
{
NURBS = false;
fec = new ND_FECollection(order, dim);
mfem::out<<"Create Normal fec"<<std::endl;
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, NURBSext, fec);
cout << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 6. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
cout << "Number of knowns in essential BCs: "
<< ess_tdof_list.Size() << endl;
// 7. Set up the linear form b(.) which corresponds to the right-hand side
// of the FEM linear system, which in this case is (f,phi_i) where f is
// given by the function f_exact and phi_i are the basis functions in the
// finite element fespace.
VectorFunctionCoefficient f(sdim, f_exact);
LinearForm *b = new LinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 8. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
GridFunction x(fespace);
VectorFunctionCoefficient E(sdim, E_exact);
x.ProjectCoefficient(E);
// 9. Set up the bilinear form corresponding to the EM diffusion operator
// curl muinv curl + sigma I, by adding the curl-curl and the mass domain
// integrators.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
BilinearForm *a = new BilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
// 10. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
OperatorPtr A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A->Height() << endl;
// 11. Solve the linear system A X = B.
if (pa) // Jacobi preconditioning in partial assembly mode
{
OperatorJacobiSmoother M(*a, ess_tdof_list);
PCG(*A, M, B, X, 1, 1000, 1e-12, 0.0);
}
else
{
#ifndef MFEM_USE_SUITESPARSE
// 11. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system Ax=b with PCG.
GSSmoother M((SparseMatrix&)(*A));
PCG(*A, M, B, X, 1, 500, 1e-12, 0.0);
#else
// 11. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the
// system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(*A);
umf_solver.Mult(B, X);
#endif
}
// 12. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 13. Compute and print the L^2 norm of the error.
cout << "\n|| E_h - E ||_{L^2} = " << x.ComputeL2Error(E) << '\n' << endl;
// 14. Save the refined mesh and the solution. This output can be viewed
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
{
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 15. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 16. Create output in visit format
VisItDataCollection visit_dc("Example3", mesh);
visit_dc.RegisterField("x", &x);
visit_dc.Save();
// 17. Free the used memory.
delete a;
delete sigma;
delete muinv;
delete b;
delete fespace;
delete fec;
delete mesh;
return 0;
}
void E_exact(const Vector &x, Vector &E)
{
if (dim == 3)
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(2));
E(2) = sin(kappa * x(0));
}
else
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(0));
if (x.Size() == 3) { E(2) = 0.0; }
}
}
void f_exact(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
}
else
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
if (x.Size() == 3) { f(2) = 0.0; }
}
}
-498
View File
@@ -1,498 +0,0 @@
// MFEM Example 5 -- modified for NURBS FE
//
// Compile with: make nurbs_ex5
//
// Sample runs: nurbs_ex5 -m ../../data/square-nurbs.mesh -o 3
// nurbs_ex5 -m ../../data/cube-nurbs.mesh -r 3
// nurbs_ex5 -m ../../data/pipe-nurbs-2d.mesh
// nurbs_ex5 -m ../../data/beam-tet.mesh
// nurbs_ex5 -m ../../data/beam-hex.mesh
// nurbs_ex5 -m ../../data/escher.mesh
// nurbs_ex5 -m ../../data/fichera.mesh
//
// Device sample runs -- do not work for NURBS:
// nurbs_ex5 -m ../../data/escher.mesh -pa -d cuda
// nurbs_ex5 -m ../../data/escher.mesh -pa -d raja-cuda
// nurbs_ex5 -m ../../data/escher.mesh -pa -d raja-omp
//
// Description: This example code solves a simple 2D/3D mixed Darcy problem
// corresponding to the saddle point system
//
// k*u + grad p = f
// - div u = g
//
// with natural boundary condition -p = <given pressure>.
// Here, we use a given exact solution (u,p) and compute the
// corresponding r.h.s. (f,g). We discretize with Raviart-Thomas
// finite elements (velocity u) and piecewise discontinuous
// polynomials (pressure p).
//
// NURBS-based H(div) spaces only implemented for meshes
// consisting of a single patch.
//
// The example demonstrates the use of the BlockOperator class, as
// well as the collective saving of several grid functions in
// VisIt (visit.llnl.gov) and ParaView (paraview.org) formats.
//
// We recommend viewing examples 1-4 before viewing this example.
// Sample runs: nurbs_ex3 -m ../../data/square-nurbs.mesh
// nurbs_ex3 -m ../../data/square-nurbs.mesh -o 2
// nurbs_ex3 -m ../../data/cube-nurbs.mesh
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace mfem;
// Define the analytical solution and forcing terms / boundary conditions
void uFun_ex(const Vector & x, Vector & u);
real_t pFun_ex(const Vector & x);
void fFun(const Vector & x, Vector & f);
real_t gFun(const Vector & x);
real_t f_natural(const Vector & x);
int main(int argc, char *argv[])
{
StopWatch chrono;
// 1. Parse command-line options.
const char *mesh_file = "../../data/square-nurbs.mesh";
int ref_levels = -1;
int order = 1;
bool pa = false;
const char *device_config = "cpu";
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 10,000
// elements.
{
if (ref_levels < 0)
{
ref_levels =
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a finite element space on the mesh. Here we use the
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *hdiv_coll = nullptr;
FiniteElementCollection *l2_coll = nullptr;
NURBSExtension *NURBSext = nullptr;
if (mesh->NURBSext && !pa)
{
hdiv_coll = new NURBS_HDivFECollection(order,dim);
l2_coll = new NURBSFECollection(order);
NURBSext = new NURBSExtension(mesh->NURBSext, order);
mfem::out<<"Create NURBS fec and ext"<<std::endl;
}
else
{
hdiv_coll = new RT_FECollection(order, dim);
l2_coll = new L2_FECollection(order, dim);
mfem::out<<"Create Normal fec"<<std::endl;
}
pa = false;
FiniteElementSpace *W_space = new FiniteElementSpace(mesh, NURBSext, l2_coll);
FiniteElementSpace *R_space = new FiniteElementSpace(mesh,
W_space->StealNURBSext(),
hdiv_coll);
// 6. Define the BlockStructure of the problem, i.e. define the array of
// offsets for each variable. The last component of the Array is the sum
// of the dimensions of each block.
Array<int> block_offsets(3); // number of variables + 1
block_offsets[0] = 0;
block_offsets[1] = R_space->GetVSize();
block_offsets[2] = W_space->GetVSize();
block_offsets.PartialSum();
std::cout << "***********************************************************\n";
std::cout << "dim(R) = " << block_offsets[1] - block_offsets[0] << "\n";
std::cout << "dim(W) = " << block_offsets[2] - block_offsets[1] << "\n";
std::cout << "dim(R+W) = " << block_offsets.Last() << "\n";
std::cout << "***********************************************************\n";
{
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
R_space->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
cout << "Number boundary dofs in H(div): "
<< ess_tdof_list.Size() << endl;
}
{
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
W_space->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
cout << "Number boundary dofs in H1: "
<< ess_tdof_list.Size() << endl;
}
// 7. Define the coefficients, analytical solution, and rhs of the PDE.
ConstantCoefficient k(1.0);
VectorFunctionCoefficient fcoeff(dim, fFun);
FunctionCoefficient fnatcoeff(f_natural);
FunctionCoefficient gcoeff(gFun);
VectorFunctionCoefficient ucoeff(dim, uFun_ex);
FunctionCoefficient pcoeff(pFun_ex);
// 8. Allocate memory (x, rhs) for the analytical solution and the right hand
// side. Define the GridFunction u,p for the finite element solution and
// linear forms fform and gform for the right hand side. The data
// allocated by x and rhs are passed as a reference to the grid functions
// (u,p) and the linear forms (fform, gform).
MemoryType mt = device.GetMemoryType();
BlockVector x(block_offsets, mt), rhs(block_offsets, mt);
LinearForm *fform(new LinearForm);
fform->Update(R_space, rhs.GetBlock(0), 0);
fform->AddDomainIntegrator(new VectorFEDomainLFIntegrator(fcoeff));
fform->AddBoundaryIntegrator(new VectorFEBoundaryFluxLFIntegrator(fnatcoeff));
fform->Assemble();
fform->SyncAliasMemory(rhs);
LinearForm *gform(new LinearForm);
gform->Update(W_space, rhs.GetBlock(1), 0);
gform->AddDomainIntegrator(new DomainLFIntegrator(gcoeff));
gform->Assemble();
gform->SyncAliasMemory(rhs);
// 9. Assemble the finite element matrices for the Darcy operator
//
// D = [ M B^T ]
// [ B 0 ]
// where:
//
// M = \int_\Omega k u_h \cdot v_h d\Omega u_h, v_h \in R_h
// B = -\int_\Omega \div u_h q_h d\Omega u_h \in R_h, q_h \in W_h
BilinearForm *mVarf(new BilinearForm(R_space));
MixedBilinearForm *bVarf(new MixedBilinearForm(R_space, W_space));
if (pa) { mVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(k));
mVarf->Assemble();
if (!pa) { mVarf->Finalize(); }
if (pa) { bVarf->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
bVarf->Assemble();
if (!pa) { bVarf->Finalize(); }
BlockOperator darcyOp(block_offsets);
TransposeOperator *Bt = NULL;
if (pa)
{
Bt = new TransposeOperator(bVarf);
darcyOp.SetBlock(0,0, mVarf);
darcyOp.SetBlock(0,1, Bt, -1.0);
darcyOp.SetBlock(1,0, bVarf, -1.0);
}
else
{
SparseMatrix &M(mVarf->SpMat());
SparseMatrix &B(bVarf->SpMat());
B *= -1.;
Bt = new TransposeOperator(&B);
darcyOp.SetBlock(0,0, &M);
darcyOp.SetBlock(0,1, Bt);
darcyOp.SetBlock(1,0, &B);
}
// 10. Construct the operators for preconditioner
//
// P = [ diag(M) 0 ]
// [ 0 B diag(M)^-1 B^T ]
//
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
// pressure Schur Complement
SparseMatrix *MinvBt = NULL;
Vector Md(mVarf->Height());
BlockDiagonalPreconditioner darcyPrec(block_offsets);
Solver *invM, *invS;
SparseMatrix *S = NULL;
if (pa)
{
mVarf->AssembleDiagonal(Md);
auto Md_host = Md.HostRead();
Vector invMd(mVarf->Height());
for (int i=0; i<mVarf->Height(); ++i)
{
invMd(i) = 1.0 / Md_host[i];
}
Vector BMBt_diag(bVarf->Height());
bVarf->AssembleDiagonal_ADAt(invMd, BMBt_diag);
Array<int> ess_tdof_list; // empty
invM = new OperatorJacobiSmoother(Md, ess_tdof_list);
invS = new OperatorJacobiSmoother(BMBt_diag, ess_tdof_list);
}
else
{
SparseMatrix &M(mVarf->SpMat());
M.GetDiag(Md);
Md.HostReadWrite();
SparseMatrix &B(bVarf->SpMat());
MinvBt = Transpose(B);
for (int i = 0; i < Md.Size(); i++)
{
MinvBt->ScaleRow(i, 1./Md(i));
}
S = Mult(B, *MinvBt);
invM = new DSmoother(M);
#ifndef MFEM_USE_SUITESPARSE
invS = new GSSmoother(*S);
#else
invS = new UMFPackSolver(*S);
#endif
}
invM->iterative_mode = false;
invS->iterative_mode = false;
darcyPrec.SetDiagonalBlock(0, invM);
darcyPrec.SetDiagonalBlock(1, invS);
// 11. Solve the linear system with MINRES.
// Check the norm of the unpreconditioned residual.
int maxIter(10000);
real_t rtol(1.e-10);
real_t atol(1.e-10);
chrono.Clear();
chrono.Start();
MINRESSolver solver;
solver.SetAbsTol(atol);
solver.SetRelTol(rtol);
solver.SetMaxIter(maxIter);
solver.SetOperator(darcyOp);
solver.SetPreconditioner(darcyPrec);
solver.SetPrintLevel(1);
x = 0.0;
solver.Mult(rhs, x);
if (device.IsEnabled()) { x.HostRead(); }
chrono.Stop();
if (solver.GetConverged())
{
std::cout << "MINRES converged in " << solver.GetNumIterations()
<< " iterations with a residual norm of "
<< solver.GetFinalNorm() << ".\n";
}
else
{
std::cout << "MINRES did not converge in " << solver.GetNumIterations()
<< " iterations. Residual norm is " << solver.GetFinalNorm()
<< ".\n";
}
std::cout << "MINRES solver took " << chrono.RealTime() << "s.\n";
// 12. Create the grid functions u and p. Compute the L2 error norms.
GridFunction u, p;
u.MakeRef(R_space, x.GetBlock(0), 0);
p.MakeRef(W_space, x.GetBlock(1), 0);
int order_quad = max(2, 2*order+1);
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t err_u = u.ComputeL2Error(ucoeff, irs);
real_t norm_u = ComputeLpNorm(2., ucoeff, *mesh, irs);
real_t err_p = p.ComputeL2Error(pcoeff, irs);
real_t norm_p = ComputeLpNorm(2., pcoeff, *mesh, irs);
std::cout << "|| u_h - u_ex || / || u_ex || = " << err_u / norm_u << "\n";
std::cout << "|| p_h - p_ex || / || p_ex || = " << err_p / norm_p << "\n";
// 13. Save the mesh and the solution. This output can be viewed later using
// GLVis: "glvis -m ex5.mesh -g sol_u.gf" or "glvis -m ex5.mesh -g
// sol_p.gf".
{
ofstream mesh_ofs("ex5.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream u_ofs("sol_u.gf");
u_ofs.precision(8);
u.Save(u_ofs);
ofstream p_ofs("sol_p.gf");
p_ofs.precision(8);
p.Save(p_ofs);
}
// 14. Save data in the VisIt format
VisItDataCollection visit_dc("Example5", mesh);
visit_dc.RegisterField("velocity", &u);
visit_dc.RegisterField("pressure", &p);
visit_dc.Save();
// 15. Save data in the ParaView format
ParaViewDataCollection paraview_dc("Example5", mesh);
paraview_dc.SetPrefixPath("ParaView");
paraview_dc.SetLevelsOfDetail(order);
paraview_dc.SetCycle(0);
paraview_dc.SetDataFormat(VTKFormat::BINARY);
paraview_dc.SetHighOrderOutput(true);
paraview_dc.SetTime(0.0); // set the time
paraview_dc.RegisterField("velocity",&u);
paraview_dc.RegisterField("pressure",&p);
paraview_dc.Save();
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream u_sock(vishost, visport);
u_sock.precision(8);
u_sock << "solution\n" << *mesh << u << "window_title 'Velocity'" << endl;
socketstream p_sock(vishost, visport);
p_sock.precision(8);
p_sock << "solution\n" << *mesh << p << "window_title 'Pressure'" << endl;
}
// 17. Free the used memory.
delete fform;
delete gform;
delete invM;
delete invS;
delete S;
delete Bt;
delete MinvBt;
delete mVarf;
delete bVarf;
delete W_space;
delete R_space;
delete l2_coll;
delete hdiv_coll;
delete mesh;
return 0;
}
void uFun_ex(const Vector & x, Vector & u)
{
real_t xi(x(0));
real_t yi(x(1));
real_t zi(0.0);
if (x.Size() == 3)
{
zi = x(2);
}
u(0) = - exp(xi)*sin(yi)*cos(zi);
u(1) = - exp(xi)*cos(yi)*cos(zi);
if (x.Size() == 3)
{
u(2) = exp(xi)*sin(yi)*sin(zi);
}
}
// Change if needed
real_t pFun_ex(const Vector & x)
{
real_t xi(x(0));
real_t yi(x(1));
real_t zi(0.0);
if (x.Size() == 3)
{
zi = x(2);
}
return exp(xi)*sin(yi)*cos(zi);
}
void fFun(const Vector & x, Vector & f)
{
f = 0.0;
}
real_t gFun(const Vector & x)
{
if (x.Size() == 3)
{
return -pFun_ex(x);
}
else
{
return 0;
}
}
real_t f_natural(const Vector & x)
{
return (-pFun_ex(x));
}
+1 -2
View File
@@ -153,8 +153,7 @@ int main(int argc, char *argv[])
if (patchAssembly && reducedIntegration && !pa)
{
#ifdef MFEM_USE_SINGLE
cout << "Reduced integration is not supported in single precision.\n";
return MFEM_SKIP_RETURN_VALUE;
MFEM_ABORT("Reduced integration is not supported in single precision.");
#endif
di->SetIntegrationMode(NonlinearFormIntegrator::Mode::PATCHWISE_REDUCED);
-401
View File
@@ -1,401 +0,0 @@
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
//
// ------------------------------------------------------------
// NURBS Solenoidal Miniapp: Project solenoidal velocity
// ------------------------------------------------------------
//
//
// Compile with: make nurbs_solenoidal
//
// Sample runs: nurbs_solenoidal -m ../../data/square-nurbs.mesh -o 2
// nurbs_solenoidal -m ../../data/cube-nurbs.mesh -o 2
//
// Description: This code projects a velocity field, and forces this field
// to be solenoidal, viz. the divergence is zero. If the correct
// discrete spaces are chosen the divergence is pointwise zero.
//
// This is achieved by solving a simple 2D/3D mixed Darcy problem
// corresponding to the saddle point system (similar to ex5)
//
// u + grad p = u_ex
// - div u = 0
//
// NURBS-based H(div) spaces only implemented for meshes
// consisting of a single patch.
//
// Here, u_ex is the specified velocity field. If u_ex is
// divergence free, we expect the pressure to converge to zero.
// We discretize with H(div) and L2/H1 conforming elements.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace mfem;
void u_2d(const Vector & x, Vector & u)
{
real_t xi(x(0));
real_t yi(x(1));
int p = 4;
u(0) = pow(xi,p + 1)*pow(yi,p );
u(1) = -pow(xi,p )*pow(yi,p + 1);
}
void u_3d(const Vector & x, Vector & u)
{
real_t xi(x(0));
real_t yi(x(1));
real_t zi(x(2));
int p = 4;
real_t cx = 3.0/4.0;
real_t cy = 2.0/3.0;
real_t cz = -cx - cy;
u(0) = cx*pow(xi,p + 1)*pow(yi,p )*pow(zi,p );
u(1) = cy*pow(xi,p )*pow(yi,p + 1)*pow(zi,p );
u(2) = cz*pow(xi,p )*pow(yi,p )*pow(zi,p + 1);
}
// Define the analytical solution and forcing terms / boundary conditions
void u_ex(const Vector & x, Vector & u)
{
if (x.Size() == 2)
{
u_2d(x, u);
}
else if (x.Size() == 3)
{
u_3d(x, u);
}
}
int main(int argc, char *argv[])
{
StopWatch chrono;
// 1. Parse command-line options.
const char *mesh_file = "../../data/square-nurbs.mesh";
int ref_levels = -1;
int order = 1;
const char *device_config = "cpu";
bool visualization = 1;
bool NURBS = true;
bool div_free = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly, -1 for auto.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&div_free, "-df", "--div-free", "-p","--proj",
"Div-free or standard projection.");
args.AddOption(&NURBS, "-n", "--nurbs", "-nn","--no-nurbs",
"NURBS.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(mfem::out);
return 1;
}
args.PrintOptions(mfem::out);
// 2. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
device.Print();
// 3. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 10,000
// elements.
{
if (ref_levels < 0)
{
ref_levels =
(int)floor(log(5000./mesh->GetNE())/log(2.)/dim);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 5. Define a finite element space on the mesh. Here we use the
// Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *hdiv_coll = nullptr;
FiniteElementCollection *l2_coll = nullptr;
NURBSExtension *NURBSext = nullptr;
if (mesh->NURBSext&& NURBS)
{
hdiv_coll = new NURBS_HDivFECollection(order, dim);
l2_coll = new NURBSFECollection(order);
NURBSext = new NURBSExtension(mesh->NURBSext, order);
mfem::out<<"Create NURBS fec and ext"<<std::endl;
}
else
{
NURBS = false;
hdiv_coll = new RT_FECollection(order, dim);
l2_coll = new L2_FECollection(order, dim);
mfem::out<<"Create Normal fec"<<std::endl;
}
FiniteElementSpace *W_space = new FiniteElementSpace(mesh, NURBSext, l2_coll);
FiniteElementSpace *R_space = new FiniteElementSpace(mesh,
W_space->StealNURBSext(),
hdiv_coll);
// 6. Define the BlockStructure of the problem, i.e. define the array of
// offsets for each variable. The last component of the Array is the sum
// of the dimensions of each block.
Array<int> block_offsets(3); // number of variables + 1
block_offsets[0] = 0;
block_offsets[1] = R_space->GetVSize();
block_offsets[2] = W_space->GetVSize();
block_offsets.PartialSum();
mfem::out << "***********************************************************\n";
mfem::out << "dim(R) = " << block_offsets[1] - block_offsets[0] << "\n";
mfem::out << "dim(W) = " << block_offsets[2] - block_offsets[1] << "\n";
mfem::out << "dim(R+W) = " << block_offsets.Last() << "\n";
mfem::out << "***********************************************************\n";
// 7. Define the coefficients, analytical solution, and rhs of the PDE.
ConstantCoefficient one(1.0);
ConstantCoefficient zero(0.0);
VectorFunctionCoefficient ucoeff(dim, u_ex);
// 8. Allocate memory (x, rhs) for the analytical solution and the right hand
// side. Define the GridFunction u,p for the finite element solution and
// linear forms fform and gform for the right hand side. The data
// allocated by x and rhs are passed as a reference to the grid functions
// (u,p) and the linear forms (fform, gform).
MemoryType mt = device.GetMemoryType();
BlockVector x(block_offsets, mt), rhs(block_offsets, mt);
rhs = 0.0;
LinearForm *fform(new LinearForm);
fform->Update(R_space, rhs.GetBlock(0), 0);
fform->AddDomainIntegrator(new VectorFEDomainLFIntegrator(ucoeff));
fform->Assemble();
fform->SyncAliasMemory(rhs);
// 9. Assemble the finite element matrices for the Darcy operator
//
// D = [ M B^T ]
// [ B 0 ]
// where:
//
// M = \int_\Omega k u_h \cdot v_h d\Omega u_h, v_h \in R_h
// B = -\int_\Omega \div u_h q_h d\Omega u_h \in R_h, q_h \in W_h
BilinearForm *mVarf(new BilinearForm(R_space));
MixedBilinearForm *bVarf(new MixedBilinearForm(R_space, W_space));
mVarf->AddDomainIntegrator(new VectorFEMassIntegrator(one));
mVarf->Assemble();
mVarf->Finalize();
bVarf->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
bVarf->Assemble();
bVarf->Finalize();
SparseMatrix &M(mVarf->SpMat());
SparseMatrix &B(bVarf->SpMat());
B *= -1.;
TransposeOperator *Bt = new TransposeOperator(&B);
BlockOperator darcyOp(block_offsets);
darcyOp.SetBlock(0,0, &M);
if (div_free) { darcyOp.SetBlock(0,1, Bt); }
if (div_free) { darcyOp.SetBlock(1,0, &B); }
// 10. Construct the operators for preconditioner
//
// P = [ diag(M) 0 ]
// [ 0 B diag(M)^-1 B^T ]
//
// Here we use Symmetric Gauss-Seidel to approximate the inverse of the
// pressure Schur Complement
Vector Md(mVarf->Height());
M.GetDiag(Md);
Md.HostReadWrite();
SparseMatrix *MinvBt = Transpose(B);
for (int i = 0; i < Md.Size(); i++)
{
MinvBt->ScaleRow(i, 1./Md(i));
}
SparseMatrix *S = Mult(B, *MinvBt);
Solver *invS;
#ifndef MFEM_USE_SUITESPARSE
invS = new GSSmoother(*S);
#else
invS = new UMFPackSolver(*S);
#endif
invS->iterative_mode = false;
Solver *invM = new GSSmoother(M);
invM->iterative_mode = false;
BlockDiagonalPreconditioner darcyPrec(block_offsets);
darcyPrec.SetDiagonalBlock(0, invM);
darcyPrec.SetDiagonalBlock(1, invS);
// 11. Solve the linear system with MINRES.
// Check the norm of the unpreconditioned residual.
int maxIter(10000);
real_t rtol(10*std::numeric_limits<real_t>::epsilon());
real_t atol(10*std::numeric_limits<real_t>::epsilon());
chrono.Clear();
chrono.Start();
MINRESSolver solver;
solver.SetAbsTol(atol);
solver.SetRelTol(rtol);
solver.SetMaxIter(maxIter);
solver.SetOperator(darcyOp);
solver.SetPreconditioner(darcyPrec);
solver.SetPrintLevel(2);
x = 0.0;
solver.Mult(rhs, x);
if (device.IsEnabled()) { x.HostRead(); }
chrono.Stop();
if (solver.GetConverged())
{
mfem::out << "MINRES converged in " << solver.GetNumIterations()
<< " iterations with a residual norm of "
<< solver.GetFinalNorm() << ".\n";
}
else
{
mfem::out << "MINRES did not converge in " << solver.GetNumIterations()
<< " iterations. Residual norm is " << solver.GetFinalNorm()
<< ".\n";
}
mfem::out << "MINRES solver took " << chrono.RealTime() << "s.\n";
// 12. Create the grid functions u and p
GridFunction u, p, uu, vv, ww;
u.MakeRef(R_space, x.GetBlock(0), 0);
p.MakeRef(W_space, x.GetBlock(1), 0);
// 13. Save the mesh and the solution. This output can be viewed later using
// GLVis: "glvis -m exsol.mesh -g sol_u.gf" or "glvis -m exsol.mesh -g
// sol_p.gf".
{
ofstream mesh_ofs("exsol.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream u_ofs("sol_u.gf");
u_ofs.precision(8);
u.Save(u_ofs);
ofstream p_ofs("sol_p.gf");
p_ofs.precision(8);
p.Save(p_ofs);
}
// 14. Save data in the VisIt format
VisItDataCollection visit_dc("Solenoidal", mesh);
visit_dc.RegisterField("velocity", &u);
visit_dc.RegisterField("pressure", &p);
visit_dc.Save();
// 15. Save data in the ParaView format
ParaViewDataCollection paraview_dc("Solenoidal", mesh);
paraview_dc.SetPrefixPath("ParaView");
paraview_dc.SetLevelsOfDetail(order);
paraview_dc.SetCycle(0);
paraview_dc.SetDataFormat(VTKFormat::BINARY);
paraview_dc.SetHighOrderOutput(true);
paraview_dc.SetTime(0.0); // set the time
paraview_dc.RegisterField("velocity",&u);
paraview_dc.RegisterField("pressure",&p);
paraview_dc.Save();
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream u_sock(vishost, visport);
u_sock.precision(8);
u_sock << "solution\n" << *mesh << u << "window_title 'Velocity'" << endl;
socketstream p_sock(vishost, visport);
p_sock.precision(8);
p_sock << "solution\n" << *mesh << p << "window_title 'Pressure'" << endl;
}
// 17. Compute errors
int order_quad = 2*order+2;
const IntegrationRule *irs[Geometry::NumGeom];
for (int i=0; i < Geometry::NumGeom; ++i)
{
irs[i] = &(IntRules.Get(i, order_quad));
}
real_t err_u = u.ComputeL2Error(ucoeff, irs);
real_t err_p = p.ComputeL2Error(zero, irs);
real_t err_div = u.ComputeDivError(&zero, irs);
mfem::out << "|| u_h - u_ex || = " << err_u << "\n";
mfem::out << "|| div u_h - div u_ex || = " << err_div << "\n";
mfem::out << "|| p_h - p_ex || = " << err_p << "\n";
// 18. Free the used memory.
delete fform;
delete invM;
delete invS;
delete S;
delete Bt;
delete MinvBt;
delete mVarf;
delete bVarf;
delete W_space;
delete R_space;
delete l2_coll;
delete hdiv_coll;
delete mesh;
if (err_div > 1e4*std::numeric_limits<real_t>::epsilon() )
{
mfem::out << "std::numeric_limits<real_t>::epsilon() = "
<< std::numeric_limits<real_t>::epsilon() << "\n";
mfem_error("Divergence error larger than expected");
}
return 0;
}
-51
View File
@@ -1,51 +0,0 @@
# Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
# LICENSE and NOTICE for details. LLNL-CODE-806117.
#
# This file is part of the MFEM library. For more information and source code
# availability visit https://mfem.org.
#
# MFEM is free software; you can redistribute it and/or modify it under the
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
list(APPEND STAB_COMMON_SOURCES
stab_tau.cpp stab_condif.cpp stab_navsto.cpp)
list(APPEND STAB_COMMON_HEADERS
stab_tau.hpp stab_condif.hpp stab_navsto.hpp manu.hpp skew.hpp)
set(STAB_COMMON_FILES
EXTRA_SOURCES ${STAB_COMMON_SOURCES}
EXTRA_HEADERS ${STAB_COMMON_HEADERS})
add_mfem_miniapp(condif
MAIN condif.cpp
${STAB_COMMON_FILES}
LIBRARIES mfem)
add_mfem_miniapp(navsto
MAIN navsto.cpp
${STAB_COMMON_FILES}
LIBRARIES mfem)
if (MFEM_ENABLE_TESTING)
add_test(NAME ex_condif
COMMAND $<TARGET_FILE:condif> -no-vis
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
endif()
if (MFEM_USE_MPI)
add_mfem_miniapp(navsto_p
MAIN navsto_p.cpp
${STAB_COMMON_FILES}
LIBRARIES mfem)
if (MFEM_ENABLE_TESTING)
add_test(NAME navsto_np=4
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS} $<TARGET_FILE:navsto> -no-vis
${MPIEXEC_POSTFLAGS}
-m ${PROJECT_SOURCE_DIR}/data/square-nurbs.mesh -r 1 -o 2)
endif()
endif()
-405
View File
@@ -1,405 +0,0 @@
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
//
// Stabilized Convection-Diffusion
#include "stab_condif.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <list>
using namespace std;
using namespace mfem;
real_t att_param = 1.0;
real_t kappa_param = 1.0;
real_t pi = (real_t)(M_PI);
using VectorFun = std::function<void(const Vector & x, Vector & a)>;
using ScalarFun = std::function<real_t(const Vector & x)>;
#include "skew.hpp"
#include "manu.hpp"
void evaluate1D(Vector &x, Vector &f, GridFunction *gf, int lod)
{
// Get Mesh and Nodes gridfunction
Mesh *mesh = gf->FESpace()->GetMesh();
GridFunction *nodes = mesh->GetNodes();
if (!nodes)
{
nodes = new GridFunction(gf->FESpace());
mesh->GetNodes(*nodes);
}
// Evaluate
std::list<pair<real_t,real_t>> sol;
Vector vals,coords;
for (int i = 0; i < mesh->GetNE(); i++)
{
int geom = mesh->GetElementBaseGeometry(i);
RefinedGeometry *refined_geo = GlobGeometryRefiner.Refine(( Geometry::Type)geom, 1, lod);
gf->GetValues(i, refined_geo->RefPts, vals);
nodes->GetValues(i, refined_geo->RefPts, coords);
for (int j = 0; j < vals.Size(); j++)
{
sol.push_back(std::make_pair(coords[j],vals[j]));
}
}
// Sort and make unique
sol.sort();
sol.unique();
// Convert to Vectors
x.SetSize(sol.size());
f.SetSize(sol.size());
int i = 0;
for (std::list<pair<real_t,real_t>>::iterator d = sol.begin() ; d != sol.end(); ++d, i++)
{
x[i] = d->first;
f[i] = d->second;
}
}
StabType GetStabilisationType(int stype)
{
switch (stype)
{
case GALERKIN:
mfem::out<<"Galerkin formulation"<<std::endl;
break;
case SUPG:
mfem::out<<"SUPG formulation"<<std::endl;
break;
case GLS:
mfem::out<<"GLS formulation"<<std::endl;
break;
case VMS:
mfem::out<<"VMS formulation"<<std::endl;
break;
default:
mfem::out<<"GAL"<<"\t"<<"SUPG"<<"\t"<<"GLS"<<"\t"<<"VMS"<<std::endl;
mfem::out<<GALERKIN<<"\t"<<SUPG<<"\t"<<GLS<<"\t"<<VMS<<std::endl;
mfem_error("Wrong formulation");
}
return (StabType) stype;
}
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/inline-quad.mesh";
const char *ref_file = "";
int problem = 0;
int sstype = -2;
bool static_cond = false;
bool visualization = false;
int lod = 0;
real_t penalty = -1;
Array<int> order(1);
order[0] = 2;
int ref_levels = 0;
bool mono = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_file, "-rf", "--ref-file",
"File with refinement data");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh.");
args.AddOption(&kappa_param , "-k", "--kappa",
"Sets the diffusion parameters, should be positive.");
args.AddOption(&att_param , "-a", "--att",
"Sets the velocity direction");
args.AddOption(&problem, "-p", "--problem",
"Select the problem to solve:\n\t"
" 0 = convection skew-to-the mesh\n\t"
" 1 = manufactured solution\n");
args.AddOption(&sstype, "-s", "--stab", " Stabilization type:\n\t"
" -2 = Galerkin\n\t"
" -1 = GLS\n\t"
" 0 = SUPG\n\t"
" 1 = VMS\n");
args.AddOption(&mono, "-mo", "--mono", "-co",
"--comp",
"Use a monolithic integrator or a composed one.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&lod, "-lod", "--level-of-detail",
"Refinement level for 1D solution output (0 means no output).");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
}
args.PrintOptions(mfem::out);
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement and knot insertion of knots defined
// in a refinement file. We choose 'ref_levels' to be the largest number
// that gives a final mesh with no more than 50,000 elements.
{
// Mesh refinement as defined in refinement file
if (mesh->NURBSext && (strlen(ref_file) != 0))
{
mesh->RefineNURBSFromFile(ref_file);
}
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
mesh->PrintInfo();
}
// 4. Define a finite element space on the mesh. Here we use continuous
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
NURBSExtension *NURBSext = nullptr;
int own_fec = 1;
if (mesh->NURBSext)
{
fec = new NURBSFECollection(order[0]);
int nkv = mesh->NURBSext->GetNKV();
if (order.Size() == 1)
{
int tmp = order[0];
order.SetSize(nkv);
order = tmp;
}
if (order.Size() != nkv ) { mfem_error("Wrong number of orders set."); }
NURBSext = new NURBSExtension(mesh->NURBSext, order);
}
else if (order[0] == -1) // Isoparametric
{
if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
own_fec = 0;
mfem::out << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
mfem::out <<"Mesh does not have FEs --> Assume order 1.\n";
fec = new H1_FECollection(1, dim);
}
}
else
{
if (order.Size() > 1) { cout <<"Wrong number of orders set, needs one.\n"; }
fec = new H1_FECollection(abs(order[0]), dim);
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, NURBSext, fec);
mfem::out << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
VectorFunctionCoefficient *adv, *grad;
FunctionCoefficient *kappa,*force, *sol, *lap;
if (problem == 0)
{
if (mesh->Dimension() != 2) mfem_error("Advection skew to the mesh needs a 2D mesh!");
adv = new VectorFunctionCoefficient(mesh->Dimension(), skew::adv);
kappa= new FunctionCoefficient(skew::kappa);
force = new FunctionCoefficient(skew::force);
sol = new FunctionCoefficient(skew::sol);
grad = new VectorFunctionCoefficient(mesh->Dimension(), skew::grad);
lap = new FunctionCoefficient(skew::laplace);
}
else if (problem == 1)
{
adv = new VectorFunctionCoefficient(mesh->Dimension(), manufactured::adv);
kappa= new FunctionCoefficient(manufactured::kappa);
force = new FunctionCoefficient(manufactured::force);
sol = new FunctionCoefficient(manufactured::sol);
grad = new VectorFunctionCoefficient(mesh->Dimension(), manufactured::grad);
lap = new FunctionCoefficient(manufactured::laplace);
}
else
{
mfem_error("Incorrect problem!");
}
// 7. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
GridFunction x(fespace);
x.ProjectCoefficient(*sol);
if (problem == 1)
{
Vector norm(3);
norm[0] = x.ComputeL2Error(*sol);
norm[1] = x.ComputeGradError(grad);
norm[2] = x.ComputeLaplaceError(lap);
mfem::out << "|| x_h - x_ex || = " << norm[0] << "\n";
mfem::out << "|| grad x_h - grad x_ex || = " << norm[1] << "\n";
mfem::out << "|| lap x_h - lap x_ex || = " << norm[2] << "\n";
}
// 9. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
StabType stype = GetStabilisationType(sstype);
FFH92Tau tau (adv, kappa, fespace);
StabConDifComposition stab_condif_comp(adv, kappa, force, &tau);
BilinearForm a(fespace);
LinearForm b(fespace);
if (mono)
{
a.AddDomainIntegrator(new StabConDifIntegrator(adv, kappa, force, &tau, stype));
b.AddDomainIntegrator(new StabConDifIntegrator(adv, kappa, force, &tau, stype));
}
else
{
stab_condif_comp.SetBilinearIntegrators(&a, stype);
stab_condif_comp.SetLinearIntegrators(&b, stype);
}
a.Assemble();
b.Assemble();
if (static_cond) { a.EnableStaticCondensation(); }
SparseMatrix A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
mfem::out << "Size of linear system: " << A.Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 10. Define a simple Jacobi preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
GMRES(A, M, B, X, 1, 2000, 2000, 1e-16, 0.0);
#else
// 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
#endif
// 11. Recover the solution as a finite element grid function.
a.RecoverFEMSolution(X, b, x);
// 12. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
{
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
sol_ofs.close();
}
// 13. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
if (mesh->Dimension() == 1 && lod > 0)
{
Vector coord, val;
evaluate1D(coord, val, &x, lod);
ofstream sol_ofs("solution.dat");
for (int i = 0; i < x.Size();i++)
{
sol_ofs<<coord[i] <<"\t"<<val[i]<<endl;
}
sol_ofs.close();
}
// 14. Error computation
if (problem == 1)
{
Vector norm(3);
norm[0] = x.ComputeL2Error(*sol);
norm[1] = x.ComputeGradError(grad);
norm[2] = x.ComputeLaplaceError(lap);
mfem::out << "|| x_h - x_ex || = " << norm[0] << "\n";
mfem::out << "|| grad x_h - grad x_ex || = " << norm[1] << "\n";
mfem::out << "|| lap x_h - lap x_ex || = " << norm[2] << "\n";
}
// 15. Save data in the VisIt format
VisItDataCollection visit_dc("condif", mesh);
visit_dc.RegisterField("solution", &x);
visit_dc.Save();
// 16. Free the used memory.
delete fespace;
if (own_fec) { delete fec; }
delete mesh;
delete adv, grad;
delete kappa, force, sol, lap;
return 0;
}
-114
View File
@@ -1,114 +0,0 @@
namespace manufactured
{
//----------------------------------------------------------
void adv(const Vector & x, Vector & a)
{
a[1] = 1.0/(1.0 + att_param*att_param);
a[0] = sqrt(1.0 - a[1]*a[1]);
}
//----------------------------------------------------------
real_t kappa(const Vector & x)
{
return kappa_param;
}
//----------------------------------------------------------
real_t force(const Vector & x)
{
int d = x.Size();
Vector a(d);
adv(x, a);
real_t ax = a[0];
real_t ay = 0.0;
real_t az = 0.0;
real_t k = kappa(x);
real_t sx = sin(pi*x[0]);
real_t cx = cos(pi*x[0]);
real_t sy = 1.0;
real_t cy = 1.0;
real_t sz = 1.0;
real_t cz = 1.0;
if (d >= 2)
{
sy = sin(pi*x[1]);
cy = cos(pi*x[1]);
ay = a[1];
}
if (d >= 3)
{
sz = sin(pi*x[2]);
cz = cos(pi*x[2]);
az = a[2];
}
return ax*pi*cx*sy*sz
+ ay*pi*sx*cy*sz
+ az*pi*sx*sy*cz + d*k*pi*pi*sx*sy*sz;
}
//----------------------------------------------------------
real_t sol(const Vector & x)
{
real_t sx = sin(pi*x[0]);
real_t sy = 1.0;
real_t sz = 1.0;
int d = x.Size();
if (d >= 2)
{
sy = sin(pi*x[1]);
}
if (d >= 3)
{
sz = sin(pi*x[2]);
}
return sx*sy*sz;
}
//----------------------------------------------------------
void grad(const Vector & x, Vector &grad)
{
real_t sx = sin(pi*x[0]);
real_t sy = 1.0;
real_t sz = 1.0;
real_t gx = pi*cos(pi*x[0]);
real_t gy = 0.0;
real_t gz = 0.0;
grad[0] = gx;
int d = x.Size();
if (d >= 2)
{
sy = sin(pi*x[1]);
gy = pi*cos(pi*x[1]);
grad[0] = gx*sy;
grad[1] = sx*gy;
}
if (d >= 3)
{
sz = sin(pi*x[2]);
gz = pi*cos(pi*x[2]);
grad[0] = gx*sy*sz;
grad[1] = sx*gy*sz;
grad[2] = sx*sy*gz;
}
}
//----------------------------------------------------------
real_t laplace(const Vector & x)
{
return -x.Size()*pi*pi*sol(x);
}
}
-282
View File
@@ -1,282 +0,0 @@
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
//
// Stabilized Navier-Stokes
#include "stab_navsto.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <list>
using namespace std;
using namespace mfem;
real_t kappa_param = 1.0;
real_t pi = (real_t)(M_PI);
using VectorFun = std::function<void(const Vector & x, Vector & a)>;
using ScalarFun = std::function<real_t(const Vector & x)>;
void sol_fun(const Vector & x, Vector &sol)
{
sol = 0.0;
if ((x[1] - 0.99 > 0.0) &&
(fabs(x[0] - 0.5) < 0.49) )
{
sol[0] = 1.0;
}
}
real_t kappa_fun(const Vector & x)
{
return kappa_param;
}
void force_fun(const Vector & x, Vector &f)
{
f = 0.0;
// f[0] = x[1]*(1.0-x[1])*x[0]*(1.0-x[0]);
}
StabType GetStabilisationType(int stype)
{
switch (stype)
{
case GALERKIN:
mfem::out<<"Galerkin formulation"<<std::endl;
break;
case SUPG:
mfem::out<<"SUPG formulation"<<std::endl;
break;
case GLS:
mfem::out<<"GLS formulation"<<std::endl;
break;
case VMS:
mfem::out<<"VMS formulation"<<std::endl;
break;
default:
mfem::out<<"GAL"<<"\t"<<"SUPG"<<"\t"<<"GLS"<<"\t"<<"VMS"<<std::endl;
mfem::out<<GALERKIN<<"\t"<<SUPG<<"\t"<<GLS<<"\t"<<VMS<<std::endl;
mfem_error("Wrong formulation");
}
return (StabType) stype;
}
int main(int argc, char *argv[])
{
// Parse command-line options.
const char *mesh_file = "../../data/inline-quad.mesh";
const char *ref_file = "";
int problem = 0;
int sstype = -2;
bool static_cond = false;
bool visualization = false;
real_t penalty = -1;
int order = 1;
int ref_levels = 0;
bool mono = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_file, "-rf", "--ref-file",
"File with refinement data");
args.AddOption(&order, "-o", "--order",
"Finite element order isoparametric space.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh.");
args.AddOption(&kappa_param , "-k", "--kappa",
"Sets the diffusion parameters, should be positive.");
args.AddOption(&problem, "-p", "--problem",
"Select the problem to solve:\n\t"
" 0 = convection skew-to-the mesh\n\t"
" 1 = manufactured solution\n");
args.AddOption(&sstype, "-s", "--stab", " Stabilization type:\n\t"
" -2 = Galerkin\n\t"
" -1 = GLS\n\t"
" 0 = SUPG\n\t"
" 1 = VMS\n");
args.AddOption(&mono, "-mo", "--mono", "-co",
"--comp",
"Use a monolithic integrator or a composed one.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
}
args.PrintOptions(mfem::out);
// Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
// Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement and knot insertion of knots defined
// in a refinement file. We choose 'ref_levels' to be the largest number
// that gives a final mesh with no more than 50,000 elements.
{
// Mesh refinement as defined in refinement file
if (mesh.NURBSext && (strlen(ref_file) != 0))
{
mesh.RefineNURBSFromFile(ref_file);
}
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
mesh.PrintInfo();
}
// Define a finite element space on the mesh. Here we use continuous
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
Array<FiniteElementCollection *> fecs(2);
fecs[0] = new H1_FECollection(order, dim);
fecs[1] = new H1_FECollection(order, dim);
Array<FiniteElementSpace *> spaces(2);
spaces[0] = new FiniteElementSpace(&mesh, fecs[0], dim);
spaces[1] = new FiniteElementSpace(&mesh, fecs[1]);
mfem::out << "Number of finite element unknowns:\n"
<< "\tVelocity = "<<spaces[0]->GetTrueVSize() << endl
<< "\tPressure = "<<spaces[1]->GetTrueVSize() << endl;
// Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<Array<int> *> ess_bdr(2);
Array<int> ess_tdof_list;
Array<int> ess_bdr_u(spaces[0]->GetMesh()->bdr_attributes.Max());
Array<int> ess_bdr_p(spaces[1]->GetMesh()->bdr_attributes.Max());
ess_bdr_p = 0;
ess_bdr_u = 1;
ess_bdr[0] = &ess_bdr_u;
ess_bdr[1] = &ess_bdr_p;
// Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
// Define the solution vector xp as a finite element grid function
Array<int> bOffsets(3);
bOffsets[0] = 0;
bOffsets[1] = spaces[0]->GetTrueVSize();
bOffsets[2] = spaces[1]->GetTrueVSize();
bOffsets.PartialSum();
BlockVector xp(bOffsets);
GridFunction x_u(spaces[0]);
GridFunction x_p(spaces[1]);
x_u.MakeTRef(spaces[0], xp.GetBlock(0), 0);
x_p.MakeTRef(spaces[1], xp.GetBlock(1), 0);
VectorFunctionCoefficient sol(dim, sol_fun);
x_u.ProjectCoefficient(sol);
x_p = 0.0;
x_u.SetTrueVector();
x_p.SetTrueVector();
// Define the output
VisItDataCollection visit_dc("navsto", &mesh);
visit_dc.RegisterField("u", &x_u);
visit_dc.RegisterField("p", &x_p);
visit_dc.SetCycle(0);
visit_dc.Save();
// Define the problem parameters
FunctionCoefficient kappa(kappa_fun);
VectorFunctionCoefficient force(dim, force_fun);
// Define the stabilisation parameters
VectorGridFunctionCoefficient adv(&x_u);
ElasticInverseEstimateCoefficient invEst(spaces[0]);
FFH92Tau tau(&adv, &kappa, &invEst, 4.0);
FF91Delta delta(&adv, &kappa, &invEst);
tau.print = delta.print = true;
// Define the block nonlinear form
BlockNonlinearForm Hform(spaces);
Hform.AddDomainIntegrator(new StabInNavStoIntegrator(kappa, force, tau, delta));
Array<Vector *> rhs(2);
rhs = nullptr; // Set all entries in the array
Hform.SetEssentialBC(ess_bdr, rhs);
// Set up the preconditioner
JacobianPreconditioner jac_prec(bOffsets,
Array<Solver *>({new GSSmoother(0,5),
new GSSmoother(0,5)}));
// Set up the Jacobian solver
GeneralResidualMonitor j_monitor("\t\t\t\tFGMRES", 25);
FGMRESSolver j_gmres;
j_gmres.iterative_mode = false;
j_gmres.SetRelTol(1e-2);
j_gmres.SetAbsTol(1e-12);
j_gmres.SetMaxIter(300);
j_gmres.SetPrintLevel(-1);
j_gmres.SetMonitor(j_monitor);
j_gmres.SetPreconditioner(jac_prec);
// Set up the newton solver
SystemResidualMonitor newton_monitor("Newton", 1, bOffsets, &visit_dc);
NewtonSolver newton_solver;
newton_solver.iterative_mode = true;
newton_solver.SetPrintLevel(-1);
newton_solver.SetMonitor(newton_monitor);
newton_solver.SetRelTol(1e-4);
newton_solver.SetAbsTol(1e-8);
newton_solver.SetMaxIter(25);
newton_solver.SetSolver(j_gmres);
newton_solver.SetOperator(Hform);
// Solve the Newton system
Vector zero;
newton_solver.Mult(zero, xp);
// Save data in the VisIt format
visit_dc.SetCycle(999999);
visit_dc.Save();
// Free the used memory.
for (int i = 0; i < fecs.Size(); ++i)
{
delete fecs[i];
}
for (int i = 0; i < spaces.Size(); ++i)
{
delete spaces[i];
}
return 0;
}
-297
View File
@@ -1,297 +0,0 @@
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
//
// Stabilized Navier-Stokes
#include "stab_navsto.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <list>
using namespace std;
using namespace mfem;
real_t kappa_param = 1.0;
real_t pi = (real_t)(M_PI);
using VectorFun = std::function<void(const Vector & x, Vector & a)>;
using ScalarFun = std::function<real_t(const Vector & x)>;
void sol_fun(const Vector & x, Vector &sol)
{
sol = 0.0;
if ((x[1] - 0.99 > 0.0) &&
(fabs(x[0] - 0.5) < 0.49) )
{
sol[0] = 1.0;
}
}
real_t kappa_fun(const Vector & x)
{
return kappa_param;
}
void force_fun(const Vector & x, Vector &f)
{
f = 0.0;
// f[0] = x[1]*(1.0-x[1])*x[0]*(1.0-x[0]);
}
StabType GetStabilisationType(int stype)
{
switch (stype)
{
case GALERKIN:
mfem::out<<"Galerkin formulation"<<std::endl;
break;
case SUPG:
mfem::out<<"SUPG formulation"<<std::endl;
break;
case GLS:
mfem::out<<"GLS formulation"<<std::endl;
break;
case VMS:
mfem::out<<"VMS formulation"<<std::endl;
break;
default:
mfem::out<<"GAL"<<"\t"<<"SUPG"<<"\t"<<"GLS"<<"\t"<<"VMS"<<std::endl;
mfem::out<<GALERKIN<<"\t"<<SUPG<<"\t"<<GLS<<"\t"<<VMS<<std::endl;
mfem_error("Wrong formulation");
}
return (StabType) stype;
}
int main(int argc, char *argv[])
{
// Initialize MPI and HYPRE.
Mpi::Init(argc, argv);
int num_procs = Mpi::WorldSize();
int myid = Mpi::WorldRank();
Hypre::Init();
// Parse command-line options.
const char *mesh_file = "../../data/inline-quad.mesh";
const char *ref_file = "";
int problem = 0;
int sstype = -2;
bool static_cond = false;
bool visualization = false;
real_t penalty = -1;
int order = 1;
int ref_levels = 0;
bool mono = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ref_file, "-rf", "--ref-file",
"File with refinement data");
args.AddOption(&order, "-o", "--order",
"Finite element order isoparametric space.");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh.");
args.AddOption(&kappa_param , "-k", "--kappa",
"Sets the diffusion parameters, should be positive.");
args.AddOption(&problem, "-p", "--problem",
"Select the problem to solve:\n\t"
" 0 = convection skew-to-the mesh\n\t"
" 1 = manufactured solution\n");
args.AddOption(&sstype, "-s", "--stab", " Stabilization type:\n\t"
" -2 = Galerkin\n\t"
" -1 = GLS\n\t"
" 0 = SUPG\n\t"
" 1 = VMS\n");
args.AddOption(&mono, "-mo", "--mono", "-co",
"--comp",
"Use a monolithic integrator or a composed one.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0) args.PrintUsage(cout);
return 1;
}
if (myid == 0) args.PrintOptions(cout);
// Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
// Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement and knot insertion of knots defined
// in a refinement file. We choose 'ref_levels' to be the largest number
// that gives a final mesh with no more than 50,000 elements.
{
// Mesh refinement as defined in refinement file
if (mesh.NURBSext && (strlen(ref_file) != 0))
{
mesh.RefineNURBSFromFile(ref_file);
}
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
if (myid == 0) mesh.PrintInfo();
}
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
// Define a finite element space on the mesh. Here we use continuous
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
Array<FiniteElementCollection *> fecs(2);
fecs[0] = new H1_FECollection(order, dim);
fecs[1] = new H1_FECollection(order, dim);
Array<ParFiniteElementSpace *> spaces(2);
spaces[0] = new ParFiniteElementSpace(&pmesh, fecs[0], dim);//, Ordering::byVDIM);
spaces[1] = new ParFiniteElementSpace(&pmesh, fecs[1]);
Array<int> tdof(num_procs),udof(num_procs),pdof(num_procs);
tdof = 0;
tdof[myid] = spaces[0]->TrueVSize();
MPI_Reduce(tdof.GetData(), udof.GetData(), num_procs, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
tdof = 0;
tdof[myid] = spaces[1]->TrueVSize();
MPI_Reduce(tdof.GetData(), pdof.GetData(), num_procs, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
if (myid == 0)
{
mfem::out << "Number of finite element unknowns:\n";
mfem::out << "\tVelocity = "<<spaces[0]->GlobalTrueVSize() << endl;
mfem::out << "\tPressure = "<<spaces[1]->GlobalTrueVSize() << endl;
mfem::out << "Number of finite element unknowns per partition:\n";
mfem::out << "\tVelocity = ";udof.Print(mfem::out, num_procs);
mfem::out << "\tPressure = ";pdof.Print(mfem::out, num_procs);
}
// Mark all velocity boundary dofs as essential
Array<Array<int> *> ess_bdr(2);
// Array<int> ess_tdof_list;
Array<int> ess_bdr_u(spaces[0]->GetMesh()->bdr_attributes.Max());
Array<int> ess_bdr_p(spaces[1]->GetMesh()->bdr_attributes.Max());
ess_bdr_p = 0;
ess_bdr_u = 1;
ess_bdr[0] = &ess_bdr_u;
ess_bdr[1] = &ess_bdr_p;
// Define the solution vector xp as a finite element grid function
Array<int> bOffsets(3);
bOffsets[0] = 0;
bOffsets[1] = spaces[0]->TrueVSize();
bOffsets[2] = spaces[1]->TrueVSize();
bOffsets.PartialSum();
BlockVector xp(bOffsets);
ParGridFunction x_u(spaces[0]);
ParGridFunction x_p(spaces[1]);
VectorFunctionCoefficient sol(dim, sol_fun);
x_u.ProjectCoefficient(sol);
x_p = 0.0;
x_u.GetTrueDofs(xp.GetBlock(0));
x_p.GetTrueDofs(xp.GetBlock(1));
VisItDataCollection visit_dc("navsto", &pmesh);
visit_dc.RegisterField("u", &x_u);
visit_dc.RegisterField("p", &x_p);
visit_dc.SetCycle(0);
visit_dc.Save();
// Define the problem parameters
FunctionCoefficient kappa(kappa_fun);
VectorFunctionCoefficient force(dim, force_fun);
// Define the stabilisation parameters
VectorGridFunctionCoefficient adv(&x_u);
ElasticInverseEstimateCoefficient invEst(spaces[0]);
FFH92Tau tau(&adv, &kappa, &invEst, 4.0);
FF91Delta delta(&adv, &kappa, &invEst);
tau.print = delta.print = (myid == 0);
// Define the block nonlinear form
ParBlockNonlinearForm Hform(spaces);
Hform.AddDomainIntegrator(new StabInNavStoIntegrator(kappa, force, tau, delta));
Array<Vector *> rhs(2);
rhs = nullptr; // Set all entries in the array
Hform.SetEssentialBC(ess_bdr, rhs);
// Set up the preconditioner
JacobianPreconditioner jac_prec(bOffsets,
Array<Solver *>({new HypreSmoother(),
new HypreSmoother()}));
// Set up the Jacobian solver
GeneralResidualMonitor j_monitor(MPI_COMM_WORLD,"\t\t\t\tFGMRES", 25);
FGMRESSolver j_gmres(MPI_COMM_WORLD);
j_gmres.iterative_mode = false;
j_gmres.SetRelTol(1e-2);
j_gmres.SetAbsTol(1e-12);
j_gmres.SetMaxIter(300);
j_gmres.SetPrintLevel(-1);
j_gmres.SetMonitor(j_monitor);
j_gmres.SetPreconditioner(jac_prec);
// Set up the newton solver
SystemResidualMonitor newton_monitor(MPI_COMM_WORLD,"Newton", 1, bOffsets, &visit_dc, &xp,
Array<ParGridFunction *>({&x_u, &x_p}));
NewtonSolver newton_solver(MPI_COMM_WORLD);
newton_solver.iterative_mode = true;
newton_solver.SetPrintLevel(-1);
newton_solver.SetMonitor(newton_monitor);
newton_solver.SetRelTol(1e-4);
newton_solver.SetAbsTol(1e-8);
newton_solver.SetMaxIter(25);
newton_solver.SetSolver(j_gmres);
newton_solver.SetOperator(Hform);
// Solve the Newton system
Vector zero;
newton_solver.Mult(zero, xp);
// Save data in the VisIt format
// Define the output
// Save data in the VisIt format
visit_dc.SetCycle(999999);
visit_dc.Save();
// Free the used memory.
for (int i = 0; i < fecs.Size(); ++i)
{
delete fecs[i];
}
for (int i = 0; i < spaces.Size(); ++i)
{
delete spaces[i];
}
return 0;
}
-46
View File
@@ -1,46 +0,0 @@
namespace skew
{
//----------------------------------------------------------
void adv(const Vector & x, Vector & a)
{
a[1] = 1.0/(1.0 + att_param*att_param);
a[0] = sqrt(1.0 - a[1]*a[1]);
}
//----------------------------------------------------------
real_t kappa(const Vector & x)
{
return kappa_param;
}
//----------------------------------------------------------
real_t force(const Vector & x)
{
return 0.0;
}
//----------------------------------------------------------
real_t sol(const Vector & x)
{
if ((x[1] - x[0] - 0.2 < 0.0)
&(x[0] + x[1] -0.99 < 0.0))
{
return 1.0;
}
return 0.0;
}
//----------------------------------------------------------
void grad(const Vector & x, Vector &grad)
{
grad = 0.0;
}
//----------------------------------------------------------
real_t laplace(const Vector & x)
{
return 0.0;
}
}
-234
View File
@@ -1,234 +0,0 @@
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "stab_condif.hpp"
using namespace mfem;
StabConDifIntegrator::StabConDifIntegrator(VectorCoefficient *a,
Coefficient *k,
Coefficient *f,
Tau *t, StabType s)
: adv(a), kappa(k), force(f), tau(t), stab(s), own_tau(false)
{
if (tau == nullptr)
{
tau = new FFH92Tau(adv, kappa, 12.0);
own_tau = true;
}
else
{
tau->SetConvection(adv);
tau->SetDiffusion(kappa);
}
}
StabConDifIntegrator::~StabConDifIntegrator()
{
if (own_tau) { delete tau; }
}
const IntegrationRule &StabConDifIntegrator::GetRule(
const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans)
{
int order = trial_fe.GetOrder() + test_fe.GetOrder();
return IntRules.Get(trial_fe.GetGeomType(), order);
}
void StabConDifIntegrator::AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
DenseMatrix &elmat )
{
int nd = el.GetDof();
int dim = el.GetDim();
real_t w,k,t = 0;
Vector a(dim);
elmat.SetSize(nd);
shape.SetSize(nd);
dshape.SetSize(nd,dim);
adshape.SetSize(nd);
laplace.SetSize(nd);
trail.SetSize(nd);
test.SetSize(nd);
const IntegrationRule *ir = NonlinearFormIntegrator::IntRule ? NonlinearFormIntegrator::IntRule : &GetRule(el, el, Trans);
elmat = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
w = Trans.Weight() * ip.weight;
// Calculate shapes
el.CalcPhysShape(Trans, shape);
el.CalcPhysDShape(Trans, dshape);
// Evaluate coefficients
k = kappa->Eval(Trans, ip);
adv->Eval(a, Trans, ip);
// Galerkin convection term
dshape.Mult(a, adshape);
AddMult_a_VWt(w, shape, adshape, elmat);
// Galerkin diffusion term
AddMult_a_AAt(w*k, dshape, elmat);
if (stab != GALERKIN)
{
// Calculate shapes
el.CalcPhysLaplacian(Trans, laplace);
// Evaluate coefficients
t = tau->Eval(Trans, ip);
// Stablization term
// - GLS: stab = -1
// - SUPG: stab = 0
// - VMS: stab = +1
add(adshape, stab*k, laplace, test);
add(adshape, -k, laplace, trail);
AddMult_a_VWt(w*t, test, trail, elmat);
}
}
}
void StabConDifIntegrator::AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Trans,
Vector &elvect)
{
int nd = el.GetDof();
int dim = el.GetDim();
real_t w,k,t,f;
Vector a(dim);
elvect.SetSize(nd);
shape.SetSize(nd);
dshape.SetSize(nd,dim);
adshape.SetSize(nd);
laplace.SetSize(nd);
test.SetSize(nd);
const IntegrationRule *ir = LinearFormIntegrator::IntRule ? LinearFormIntegrator::IntRule : &GetRule(el, el, Trans);
elvect = 0.0;
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Trans.SetIntPoint (&ip);
w = Trans.Weight() * ip.weight;
// Calculate shapes
el.CalcPhysShape(Trans, shape);
// Evaluate coefficients
f = force->Eval(Trans, ip);
// Galerkin term
elvect.Add(w*f, shape);
if (stab != GALERKIN)
{
// Calculate shapes
el.CalcPhysDShape(Trans, dshape);
el.CalcPhysLaplacian(Trans, laplace);
// Evaluate coefficients
k = kappa->Eval(Trans, ip);
adv->Eval(a, Trans, ip);
t = tau->Eval(Trans, ip);
// Advective derivative
dshape.Mult(a, adshape);
// Stablization term
// - GLS: stab = -1
// - SUPG: stab = 0
// - VMS: stab = +1
add(adshape, stab*k, laplace, test);
elvect.Add(w*f*t, test);
}
}
}
StabConDifComposition::StabConDifComposition(VectorCoefficient *a,
Coefficient *k,
Coefficient *f,
Tau *t)
: adv(a), kappa(k), force(f), tau(t), own_tau(false)
{
if (tau == nullptr)
{
tau = new FFH92Tau(adv, kappa, 12.0);
own_tau = true;
}
else
{
tau->SetConvection(adv);
tau->SetDiffusion(kappa);
}
// SUPG coefficients
adv_tau = new ScalarVectorProductCoefficient(*tau, *adv);
adv_tau_force = new ScalarVectorProductCoefficient(*force, *adv_tau);
adv_tau_kappa = new ScalarVectorProductCoefficient(*kappa, *adv_tau);
adv_tau_adv = new OuterProductCoefficient(*adv_tau, *adv);
// GLS/VMS coefficients
kappa_tau = new ProductCoefficient(*kappa, *tau);
kappa_tau_kappa = new ProductCoefficient(*kappa_tau, *kappa);
kappa_tau_force = new ProductCoefficient(*kappa_tau, *force);
}
StabConDifComposition::~StabConDifComposition()
{
if (own_tau) { delete tau; }
delete adv_tau, adv_tau_kappa, adv_tau_adv, adv_tau_force,
kappa_tau, kappa_tau_kappa,kappa_tau_force;
}
void StabConDifComposition::SetBilinearIntegrators(BilinearForm *a, StabType stype)
{
a->AddDomainIntegrator(new ConservativeConvectionIntegrator(*adv));
a->AddDomainIntegrator(new DiffusionIntegrator(*kappa));
if (stype == GALERKIN) return;
// Add SUPG terms
a->AddDomainIntegrator(new DiffusionIntegrator(*adv_tau_adv));
a->AddDomainIntegrator(new GradLaplaceIntegrator(*adv_tau_kappa, 1.0));
if (stype == SUPG) return;
// Add VMS/GLS terms
real_t s = (stype == GLS)? -1.0: 1.0;
a->AddDomainIntegrator(new LaplaceGradIntegrator(*adv_tau_kappa,-s));
a->AddDomainIntegrator(new LaplaceLaplaceIntegrator(*kappa_tau_kappa,-s));
}
void StabConDifComposition::SetLinearIntegrators(LinearForm *b, StabType stype)
{
b->AddDomainIntegrator(new DomainLFIntegrator(*force));
if (stype == GALERKIN) return;
// Add SUPG terms
b->AddDomainIntegrator(new DomainLFGradIntegrator(*adv_tau_force));
if (stype == SUPG) return;
// Add VMS/GLS terms
real_t s = (stype == GLS)? -1.0: 1.0;
b->AddDomainIntegrator(new DomainLFLaplaceIntegrator(*kappa_tau_force,-s));
}
-130
View File
@@ -1,130 +0,0 @@
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_STAB_CONDIF_HPP
#define MFEM_STAB_CONDIF_HPP
#include "mfem.hpp"
#include "stab_tau.hpp"
namespace mfem
{
/** This Class defines a monolithic integrator for stabilized multi-dimensional
convection-diffusion.
$(a \cdot \nabla u, v) + (\kappa \nabla u, \nabla v)
+ \sum (a \cdot \nabla u - \kappa \Delta u, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
$(f, \nabla v)
+ \sum (f, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
*/
class StabConDifIntegrator : public BilinearFormIntegrator,
public LinearFormIntegrator
{
protected:
/// The advection field
VectorCoefficient *adv;
/// The diffusion parameter and force fields
Coefficient *kappa, *force;
/// The stabilization parameter
Tau *tau;
bool own_tau;
StabType stab;
private:
Vector laplace, shape, adshape, trail, test;
DenseMatrix dshape;
public:
StabConDifIntegrator(VectorCoefficient *a,
Coefficient *k,
Coefficient *f,
Tau *t = nullptr, StabType s = GALERKIN);
~StabConDifIntegrator();
virtual void AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Tr,
DenseMatrix &elmat);
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
ElementTransformation &Trans);
virtual void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect);
using LinearFormIntegrator::AssembleRHSElementVect;
};
/** This Class composes standard integrators to obtain a stabilized formulation for
multi-dimensional convection-diffusion.
$(a \cdot \nabla u, v) + (\kappa \nabla u, \nabla v)
+ \sum (a \cdot \nabla u - \kappa \Delta u, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
$(f, \nabla v)
+ \sum (f, \tau (a \cdot \nabla v + s \kappa \Delta v))_e$
*/
class StabConDifComposition
{
private:
/// The advection field
VectorCoefficient *adv;
/// The diffusion parameter and force fields
Coefficient *kappa, *force;
/// The stabilization parameter
Tau *tau;
bool own_tau;
//// Helper coefficients for defining the weak forms
VectorCoefficient *adv_tau;
Coefficient *kappa_tau;
/// SUPG coefficients
VectorCoefficient *adv_tau_force;
VectorCoefficient *adv_tau_kappa;
MatrixCoefficient *adv_tau_adv;
/// GLS/VMS coefficients
Coefficient *kappa_tau_kappa;
Coefficient *kappa_tau_force;
public:
/** Constructor
@a a: is the advection velocity field.
@a k: is the diffusion param field.
@a f: is the force field. */
StabConDifComposition(VectorCoefficient *a,
Coefficient *k,
Coefficient *f,
Tau *t = nullptr);
/// Destructor
~StabConDifComposition();
/// This method sets the integrators for the bilinearform
void SetBilinearIntegrators(BilinearForm *a, StabType s);
/// This method sets the integrators for the linearform
void SetLinearIntegrators(LinearForm *b, StabType s);
};
} // namespace mfem
#endif
-394
View File
@@ -1,394 +0,0 @@
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "stab_navsto.hpp"
using namespace mfem;
StabInNavStoIntegrator::StabInNavStoIntegrator(Coefficient &mu_,
VectorCoefficient &force_,
Tau &t, Tau &d, StabType s)
: c_mu(&mu_), c_force(&force_), tau(&t), delta(&d), stab(s)
{ }
void StabInNavStoIntegrator::SetDim(int dim_)
{
if (dim_ != dim)
{
dim = dim_;
u.SetSize(dim);
f.SetSize(dim);
res.SetSize(dim);
up.SetSize(dim);
grad_u.SetSize(dim);
hess_u.SetSize(dim, (dim*(dim+1))/2);
grad_p.SetSize(dim);
hmap.SetSize(dim,dim);
if (dim == 2)
{
hmap(0,0) = 0;
hmap(0,1) = hmap(1,0) = 1;
hmap(1,1) = 2;
}
else if (dim == 2)
{
hmap(0,0) = 0;
hmap(0,1) = hmap(1,0) = 1;
hmap(0,2) = hmap(2,0) = 2;
hmap(1,1) = 3;
hmap(1,2) = hmap(2,1) = 4;
hmap(2,2) = 5;
}
else
{
mfem_error("Only implemented for 2D and 3D");
}
}
}
real_t StabInNavStoIntegrator::GetElementEnergy(
const Array<const FiniteElement *>&el,
ElementTransformation &Tr,
const Array<const Vector *>&elfun)
{
if (el.Size() != 2)
{
mfem_error("StabInNavStoIntegrator::GetElementEnergy"
" has incorrect block finite element space size!");
}
SetDim(el[0]->GetDim());
int dof_u = el[0]->GetDof();
sh_u.SetSize(dof_u);
elf_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
int intorder = 2*el[0]->GetOrder();
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
real_t energy = 0.0;
for (int i = 0; i < ir.GetNPoints(); ++i)
{
const IntegrationPoint &ip = ir.IntPoint(i);
Tr.SetIntPoint(&ip);
real_t w = ip.weight * Tr.Weight();
el[0]->CalcPhysShape(Tr, sh_u);
elf_u.MultTranspose(sh_u, u);
energy += w*(u*u)/2;
}
return energy;
}
void StabInNavStoIntegrator::AssembleElementVector(
const Array<const FiniteElement *> &el,
ElementTransformation &Tr,
const Array<const Vector *> &elfun,
const Array<Vector *> &elvec)
{
if (el.Size() != 2)
{
mfem_error("StabInNavStoIntegrator::AssembleElementVector"
" has finite element space of incorrect block number");
}
int dof_u = el[0]->GetDof();
int dof_p = el[1]->GetDof();
SetDim(el[0]->GetDim());
int spaceDim = Tr.GetSpaceDim();
bool hess = (el[0]->GetDerivType() == (int) FiniteElement::HESS);
if (dim != spaceDim)
{
mfem_error("StabInNavStoIntegrator::AssembleElementVector"
" is not defined on manifold meshes");
}
elvec[0]->SetSize(dof_u*dim);
elvec[1]->SetSize(dof_p);
*elvec[0] = 0.0;
*elvec[1] = 0.0;
elf_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
elv_u.UseExternalData(elvec[0]->GetData(), dof_u, dim);
sh_u.SetSize(dof_u);
shg_u.SetSize(dof_u, dim);
ushg_u.SetSize(dof_u);
shh_u.SetSize(dof_u, (dim*(dim+1))/2);
sh_p.SetSize(dof_p);
shg_p.SetSize(dof_p, dim);
int intorder = 2*el[0]->GetOrder();
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
for (int i = 0; i < ir.GetNPoints(); ++i)
{
const IntegrationPoint &ip = ir.IntPoint(i);
Tr.SetIntPoint(&ip);
real_t w = ip.weight * Tr.Weight();
real_t mu = c_mu->Eval(Tr, ip);
c_force->Eval(f, Tr, ip);
// Compute shape and interpolate
el[0]->CalcPhysShape(Tr, sh_u);
elf_u.MultTranspose(sh_u, u);
el[0]->CalcPhysDShape(Tr, shg_u);
shg_u.Mult(u, ushg_u);
MultAtB(elf_u, shg_u, grad_u);
if (hess)
{
el[0]->CalcPhysHessian(Tr,shh_u);
MultAtB(elf_u, shh_u, hess_u);
}
else
{
shh_u = 0.0;
hess_u = 0.0;
}
el[1]->CalcPhysShape(Tr, sh_p);
real_t p = sh_p*(*elfun[1]);
el[1]->CalcPhysDShape(Tr, shg_p);
shg_p.MultTranspose(*elfun[1], grad_p);
// Compute strong residual
grad_u.Mult(u,res); // Add convection
res += grad_p; // Add pressure
res -= f; // Subtract force
for (int i = 0; i < dim; ++i)
{
for (int j = 0; j < dim; ++j)
{
res[j] -= mu*(hess_u(j,hmap(i,i)) +
hess_u(i,hmap(j,i))); // Add diffusion
}
}
// Compute stability params
real_t t = tau->Eval(Tr, ip);
real_t d = delta->Eval(Tr, ip);
// Compute momentum weak residual
flux.Diag(-p + d*grad_u.Trace(),dim); // Add pressure & LSIC to flux
grad_u.Symmetrize(); // Grad to strain
flux.Add(2*mu,grad_u); // Add stress to flux
AddMult_a_VVt(-1.0, u, flux); // Add convection to flux
AddMult_a_VWt(t, res, u, flux); // Add SUPG to flux --> check order u and res
AddMult_a_ABt(w, shg_u, flux, elv_u); // Add flux term to rhs
AddMult_a_VWt(-w, sh_u, f, elv_u); // Add force term to rhs
// Compute momentum weak residual
elvec[1]->Add(w*grad_u.Trace(), sh_p); // Add Galerkin term
shg_p.Mult(res, sh_p); // PSPG help term
elvec[1]->Add(w*t, sh_p); // Add PSPG term - sign looks worng?
}
}
void StabInNavStoIntegrator::AssembleElementGrad(
const Array<const FiniteElement*> &el,
ElementTransformation &Tr,
const Array<const Vector *> &elfun,
const Array2D<DenseMatrix *> &elmats)
{
int dof_u = el[0]->GetDof();
int dof_p = el[1]->GetDof();
SetDim(el[0]->GetDim());
bool hess = (el[0]->GetDerivType() == (int) FiniteElement::HESS);
elf_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
elmats(0,0)->SetSize(dof_u*dim, dof_u*dim);
elmats(0,1)->SetSize(dof_u*dim, dof_p);
elmats(1,0)->SetSize(dof_p, dof_u*dim);
elmats(1,1)->SetSize(dof_p, dof_p);
*elmats(0,0) = 0.0;
*elmats(0,1) = 0.0;
*elmats(1,0) = 0.0;
*elmats(1,1) = 0.0;
sh_u.SetSize(dof_u);
shg_u.SetSize(dof_u, dim);
ushg_u.SetSize(dof_u);
sh_p.SetSize(dof_p);
shg_p.SetSize(dof_p, dim);
int intorder = 2*el[0]->GetOrder();
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
for (int i = 0; i < ir.GetNPoints(); ++i)
{
const IntegrationPoint &ip = ir.IntPoint(i);
Tr.SetIntPoint(&ip);
real_t w = ip.weight * Tr.Weight();
real_t mu = c_mu->Eval(Tr, ip);
real_t t = tau->Eval(Tr, ip);
real_t d = delta->Eval(Tr, ip);
el[0]->CalcPhysShape(Tr, sh_u);
elf_u.MultTranspose(sh_u, u);
el[0]->CalcPhysDShape(Tr, shg_u);
MultAtB(elf_u, shg_u, grad_u);
shg_u.Mult(u, ushg_u);
el[1]->CalcPhysShape(Tr, sh_p);
real_t p = sh_p*(*elfun[1]);
el[1]->CalcPhysDShape(Tr, shg_p);
shg_p.MultTranspose(*elfun[1], grad_p);
// u,u block
for (int i_u = 0; i_u < dof_u; ++i_u)
{
for (int j_u = 0; j_u < dof_u; ++j_u)
{
// Diffusion
real_t mat = 0.0;
for (int dim_u = 0; dim_u < dim; ++dim_u)
{
mat += shg_u(i_u,dim_u)*shg_u(j_u,dim_u);
}
mat *= mu;
// Convection
mat -= ushg_u(i_u)*sh_u(j_u); // Galerkin
mat += t*ushg_u(i_u)*ushg_u(j_u); // SUPG
mat *= w;
for (int dim_u = 0; dim_u < dim; ++dim_u)
{
(*elmats(0,0))(i_u + dim_u*dof_u, j_u + dim_u*dof_u) += mat;
}
for (int i_dim = 0; i_dim < dim; ++i_dim)
{
for (int j_dim = 0; j_dim < dim; ++j_dim)
{
(*elmats(0,0))(i_u + i_dim*dof_u, j_u + j_dim*dof_u) +=
(mu + d)*shg_u(i_u,j_dim)*shg_u(j_u,i_dim)*w;
}
}
}
}
// u,p and p,u blocks
for (int i_p = 0; i_p < dof_p; ++i_p)
{
for (int j_u = 0; j_u < dof_u; ++j_u)
{
for (int dim_u = 0; dim_u < dim; ++dim_u)
{
(*elmats(0,1))(j_u + dof_u * dim_u, i_p) += (shg_p(i_p, dim_u)*t*ushg_u(j_u)
-shg_u(j_u,dim_u)*sh_p(i_p))*w;
(*elmats(1,0))(i_p, j_u + dof_u * dim_u) += shg_u(j_u,dim_u)*sh_p(i_p)*w;
}
}
}
// p,p block
AddMult_a_AAt(w*t, shg_p, *elmats(1,1));
}
}
void GeneralResidualMonitor::MonitorResidual(int it, real_t norm,
const Vector &r, bool final)
{
if (it == 0)
{
norm0 = norm;
}
if ((print_level > 0 && it%print_level == 0) || final)
{
mfem::out << prefix << " iteration " << std::setw(2) << it
<< " : ||r|| = " << norm
<< ", ||r||/||r_0|| = " << 100*norm/norm0<<" % \n";
}
}
void SystemResidualMonitor::MonitorResidual(int it, real_t norm,
const Vector &r, bool final)
{
if (dc && (it > 0))
{
if (rank > 1)
{
for (int i = 0; i < nvar; ++i)
{
pgf[i]->Distribute(xp->GetBlock(i));
}
}
dc->SetCycle(it);
dc->Save();
}
Vector vnorm(nvar);
for (int i = 0; i < nvar; ++i)
{
Vector r_i(r.GetData() + bOffsets[i], bOffsets[i+1] - bOffsets[i]);
if ( rank == 1 )
{
vnorm[i] = r_i.Norml2();
}
else
{
vnorm[i] = sqrt(InnerProduct(MPI_COMM_WORLD, r_i, r_i));
}
if (it == 0) norm0[i] = vnorm[i];
}
bool print = (print_level > 0 && it%print_level == 0) || final;
if (print)
{
mfem::out << prefix << " iteration " << std::setw(3) << it <<"\n"
<< " ||r|| \t"<< "||r||/||r_0|| \n";
for (int i = 0; i < nvar; ++i)
{
mfem::out <<vnorm[i]<<"\t"<< 100*vnorm[i]/norm0[i]<<" % \n";
}
}
}
void JacobianPreconditioner::SetOperator(const Operator &op)
{
BlockOperator *jacobian = (BlockOperator *) &op;
for (int i = 0; i < prec.Size(); ++i)
{
prec[i]->SetOperator(jacobian->GetBlock(i,i));
SetDiagonalBlock(i, prec[i]);
}
SetBlock(1,0, const_cast<Operator*>(&jacobian->GetBlock(1,0)));
}
JacobianPreconditioner::~JacobianPreconditioner()
{
for (int i = 0; i < prec.Size(); ++i)
{
delete prec[i];
}
}
-242
View File
@@ -1,242 +0,0 @@
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_STAB_NAVSTO_HPP
#define MFEM_STAB_NAVSTO_HPP
#include "mfem.hpp"
#include "stab_tau.hpp"
namespace mfem
{
/** Stabilized incompressible Navier-Stokes integrator
Start with Galerkin for stokes - done
Add convection - done
Modify diffusion - done
Add difussion to residual - done
CHECK NUMBERING HESSIAN -> NURBS = WRONG?? 2D = ok --> 3D??? --> DONE NEEDS CHECKING???
Inverse estimate check order -> done
Add force -> done
Parallel --> done
Add supg - rhs done, jac conv + press --> ignore diffusion for now
Add pspg - rhs done, jac conv + press --> ignore diffusion for now
Add lsic - rhs done, jac conv + press --> ignore diffusion for now
Add correct inverse estimate -> done?? number does not coincide with H&C
Add VMS/GLS
Add selection option of different stab modes
Add Hessian check to inverse estimate
Check
- Hessian numbering in 3D
- Power method --> Laplack / null-space
- Elastic Inverse estimate
Leopoldo P. Franca, Sérgio L. Frey
Stabilized finite element methods:
II. The incompressible Navier-Stokes equations.
Computer Methods in Applied Mechanics and Engineering, 99(2-3), 209-233.
https://doi.org/10.1016/0045-7825(92)90041-H
https://www.sciencedirect.com/science/article/pii/004578259290041H
*/
class StabInNavStoIntegrator : public BlockNonlinearFormIntegrator
{
private:
Coefficient *c_mu;
VectorCoefficient *c_force;
Vector u, f, grad_p;
DenseMatrix flux;
DenseMatrix elf_u, elv_u;
// Vector elf_u, elv_u;//
DenseMatrix elf_p, elv_p;
Vector sh_u, ushg_u, sh_p;
DenseMatrix shg_u, shh_u, shg_p, grad_u, hess_u;
Array2D<int> hmap;
/// The stabilization parameters
StabType stab;
Tau *tau = nullptr;
Tau *delta = nullptr;
Vector res, up;
/// The advection field
VectorCoefficient *adv = nullptr; // tbd???
int dim = -1;
void SetDim(int dim);
public:
StabInNavStoIntegrator(Coefficient &mu_,
VectorCoefficient &force_,
Tau &t, Tau &d,
StabType s = GALERKIN);
virtual real_t GetElementEnergy(const Array<const FiniteElement *>&el,
ElementTransformation &Tr,
const Array<const Vector *> &elfun);
/// Perform the local action of the NonlinearFormIntegrator
virtual void AssembleElementVector(const Array<const FiniteElement *> &el,
ElementTransformation &Tr,
const Array<const Vector *> &elfun,
const Array<Vector *> &elvec);
/// Assemble the local gradient matrix
virtual void AssembleElementGrad(const Array<const FiniteElement*> &el,
ElementTransformation &Tr,
const Array<const Vector *> &elfun,
const Array2D<DenseMatrix *> &elmats);
};
class GeneralResidualMonitor : public IterativeSolverMonitor
{
public:
GeneralResidualMonitor(const std::string& prefix_, int print_lvl)
: prefix(prefix_)
{
print_level = print_lvl;
rank = 1;
}
GeneralResidualMonitor(MPI_Comm comm,
const std::string& prefix_, int print_lvl)
: prefix(prefix_)
{
#ifndef MFEM_USE_MPI
print_level = print_lvl;
#else
MPI_Comm_rank(comm, &rank);
if (rank == 0)
{
print_level = print_lvl;
}
else
{
print_level = -1;
}
#endif
}
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final);
private:
const std::string prefix;
int rank, print_level;
mutable real_t norm0;
};
class SystemResidualMonitor : public IterativeSolverMonitor
{
public:
SystemResidualMonitor(const std::string& prefix_,
int print_lvl,
Array<int> &offsets,
DataCollection *dc_ = nullptr)
: prefix(prefix_), bOffsets(offsets), dc(dc_)
{
print_level = print_lvl;
nvar = bOffsets.Size()-1;
norm0.SetSize(nvar);
rank = 1;
}
SystemResidualMonitor(MPI_Comm comm,
const std::string& prefix_,
int print_lvl,
Array<int> &offsets)
: prefix(prefix_), bOffsets(offsets), dc(nullptr), xp(nullptr)
{
#ifndef MFEM_USE_MPI
print_level = print_lvl;
rank = 1;
#else
MPI_Comm_rank(comm, &rank);
if (rank == 0)
{
print_level = print_lvl;
}
else
{
print_level = -1;
}
#endif
nvar = bOffsets.Size()-1;
norm0.SetSize(nvar);
}
SystemResidualMonitor(MPI_Comm comm,
const std::string& prefix_,
int print_lvl,
Array<int> &offsets,
DataCollection *dc_,
BlockVector *x,
Array<ParGridFunction *> pgf_)
: prefix(prefix_), bOffsets(offsets), dc(dc_), xp(x), pgf(pgf_)
{
#ifndef MFEM_USE_MPI
print_level = print_lvl;
rank = 1;
#else
MPI_Comm_rank(comm, &rank);
if (rank == 0)
{
print_level = print_lvl;
}
else
{
print_level = -1;
}
#endif
nvar = bOffsets.Size()-1;
norm0.SetSize(nvar);
}
virtual void MonitorResidual(int it, real_t norm, const Vector &r, bool final);
private:
const std::string prefix;
int print_level, nvar, rank;
mutable Vector norm0;
// Offsets for extracting block vector segments
Array<int> &bOffsets;
DataCollection *dc;
BlockVector *xp;
Array<ParGridFunction *> pgf;
};
// Custom block preconditioner for the Jacobian
class JacobianPreconditioner : public BlockLowerTriangularPreconditioner //BlockDiagonalPreconditioner
{
protected:
Array<Solver *> prec;
public:
JacobianPreconditioner(Array<int> &offsets, Array<Solver *> p)
: BlockLowerTriangularPreconditioner (offsets), prec(p)
{ MFEM_VERIFY(offsets.Size()-1 == p.Size(), ""); };
virtual void SetOperator(const Operator &op);
virtual ~JacobianPreconditioner();
};
} // namespace mfem
#endif

Some files were not shown because too many files have changed in this diff Show More