Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f10bc713a4 | ||
|
|
96c110dab4 | ||
|
|
a417272578 | ||
|
|
7423f8c998 | ||
|
|
db8d1f6cd4 |
-11
@@ -272,27 +272,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
|
||||
|
||||
@@ -11,16 +11,9 @@
|
||||
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
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -182,21 +182,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
|
||||
|
||||
+20
-16
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -1504,295 +1504,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[])
|
||||
{
|
||||
|
||||
@@ -2328,127 +2328,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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 (11‐12) 1407-1422
|
||||
|
||||
[2] John A Evans, Thomas JR Hughes
|
||||
"Isogeometric divergence-conforming B-splines for the unsteady Navier–Stokes equations."
|
||||
Journal of Computational Physics (241) 141-167
|
||||
*/
|
||||
class NURBS_HDiv2DFiniteElement : public VectorFiniteElement,
|
||||
public NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
|
||||
mutable Vector shape1_x, shape1_y, dshape1_x, dshape1_y, d2shape1_x, d2shape1_y;
|
||||
mutable Vector u;
|
||||
mutable DenseMatrix du;
|
||||
mutable Array <const KnotVector*> kv1;
|
||||
|
||||
public:
|
||||
/// Construct the NURBS_HDiv2DFiniteElement of order @a p
|
||||
NURBS_HDiv2DFiniteElement(int p)
|
||||
: VectorFiniteElement(2, Geometry::SQUARE, 2*(p + 1)*(p + 2), p,
|
||||
H_DIV,FunctionSpace::Qk),
|
||||
NURBSFiniteElement(2),
|
||||
shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
|
||||
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1),
|
||||
shape1_x(p + 2), shape1_y(p + 2), dshape1_x(p + 2),
|
||||
dshape1_y(p + 2), d2shape1_x(p + 2), d2shape1_y(p + 2),
|
||||
u(dof), du(dof,2)
|
||||
{
|
||||
orders[0] = orders[1] = p;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
}
|
||||
|
||||
/// Construct the NURBS_HDiv2DFiniteElement with x-order @a px and y-order @a py
|
||||
NURBS_HDiv2DFiniteElement(int px, int py)
|
||||
: VectorFiniteElement(2, Geometry::SQUARE,
|
||||
(px + 2)*(py + 1)+(px + 1)*(py + 2),
|
||||
std::max(px, py), H_DIV, FunctionSpace::Qk),
|
||||
NURBSFiniteElement(2),
|
||||
shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
|
||||
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1),
|
||||
shape1_x(px + 2), shape1_y(py + 2), dshape1_x(px + 2),
|
||||
dshape1_y(py + 2), d2shape1_x(px + 2), d2shape1_y(py + 2),
|
||||
u(dof), du(dof,2)
|
||||
{
|
||||
orders[0] = px; orders[1] = py;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
}
|
||||
|
||||
virtual void SetOrder() const;
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the values of all shape functions of a *vector* finite
|
||||
element in physical space at the point described by @a Trans. */
|
||||
/** Each row of the result DenseMatrix @a shape contains the components of
|
||||
one vector shape function. The size (#dof x SDim) of @a shape must be set
|
||||
in advance, where SDim >= #dim is the physical space dimension as
|
||||
described by @a Trans. */
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the divergence of all shape functions of a *vector*
|
||||
finite element in reference space at the given point @a ip. */
|
||||
/** The size (#dof) of the result Vector @a divshape must be set in advance.
|
||||
*/
|
||||
virtual void CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const;
|
||||
|
||||
~NURBS_HDiv2DFiniteElement();
|
||||
};
|
||||
|
||||
|
||||
/** An arbitrary order H(div)-conforming 3D NURBS element on a cube
|
||||
More details in the following papers:
|
||||
|
||||
[1] Annalisa Buffa, Carlo De Falco, Giancarlo Sangalli
|
||||
"Isogeometric analysis: stable elements for the 2D Stokes equation."
|
||||
International Journal for Numerical Methods in Fluids 65 (11‐12) 1407-1422
|
||||
|
||||
[2] John A Evans, Thomas JR Hughes
|
||||
"Isogeometric divergence-conforming B-splines for the unsteady
|
||||
Navier–Stokes equations."
|
||||
Journal of Computational Physics (241) 141-167 */
|
||||
class NURBS_HDiv3DFiniteElement : public VectorFiniteElement,
|
||||
public NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Vector shape_x, shape_y, shape_z;
|
||||
mutable Vector dshape_x, dshape_y, dshape_z;
|
||||
mutable Vector d2shape_x, d2shape_y, d2shape_z;
|
||||
mutable Vector shape1_x, shape1_y, shape1_z;
|
||||
mutable Vector dshape1_x, dshape1_y, dshape1_z;
|
||||
mutable Vector d2shape1_x, d2shape1_y, d2shape1_z;
|
||||
mutable Vector u;
|
||||
mutable DenseMatrix du;
|
||||
mutable Array <const KnotVector*> kv1;
|
||||
|
||||
public:
|
||||
/// Construct the NURBS_HDiv3DFiniteElement of order @a p
|
||||
NURBS_HDiv3DFiniteElement(int p)
|
||||
: VectorFiniteElement(3, Geometry::CUBE, 3*(p + 1)*(p + 1)*(p + 2),
|
||||
p, H_DIV,FunctionSpace::Qk),
|
||||
NURBSFiniteElement(3),
|
||||
shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
|
||||
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
|
||||
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1),
|
||||
shape1_x(p + 2), shape1_y(p + 2), shape1_z(p + 2),
|
||||
dshape1_x(p + 2), dshape1_y(p + 2),dshape1_z(p + 2),
|
||||
d2shape1_x(p + 2), d2shape1_y(p + 2), d2shape1_z(p + 2),
|
||||
u(dof), du(dof,3)
|
||||
{
|
||||
orders[0] = orders[1] = orders[2] = p;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
kv1[2] = nullptr;
|
||||
}
|
||||
|
||||
/// Construct the NURBS_HDiv3DFiniteElement with x-order @a px, y-order @a py and z-order @a pz
|
||||
NURBS_HDiv3DFiniteElement(int px, int py, int pz)
|
||||
: VectorFiniteElement(3, Geometry::CUBE,
|
||||
(px + 2)*(py + 1)*(pz + 1) +
|
||||
(px + 1)*(py + 2)*(pz + 1) +
|
||||
(px + 1)*(py + 1)*(pz + 2),
|
||||
std::max(px, py), H_DIV, FunctionSpace::Qk),
|
||||
NURBSFiniteElement(3),
|
||||
shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
|
||||
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
|
||||
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1),
|
||||
shape1_x(px + 2), shape1_y(py + 2), shape1_z(pz + 2),
|
||||
dshape1_x(px + 2), dshape1_y(py + 2),dshape1_z(pz + 2),
|
||||
d2shape1_x(px + 2), d2shape1_y(py + 2), d2shape1_z(pz + 2),
|
||||
u(dof), du(dof,3)
|
||||
{
|
||||
orders[0] = px; orders[1] = py; orders[2] = pz;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
kv1[2] = nullptr;
|
||||
}
|
||||
|
||||
virtual void SetOrder() const;
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the values of all shape functions of a *vector* finite
|
||||
element in physical space at the point described by @a Trans. */
|
||||
/** Each row of the result DenseMatrix @a shape contains the components of
|
||||
one vector shape function. The size (#dof x SDim) of @a shape must be set
|
||||
in advance, where SDim >= #dim is the physical space dimension as
|
||||
described by @a Trans. */
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the divergence of all shape functions of a *vector*
|
||||
finite element in reference space at the given point @a ip. */
|
||||
/** The size (#dof) of the result Vector @a divshape must be set in advance.
|
||||
*/
|
||||
virtual void CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const;
|
||||
|
||||
~NURBS_HDiv3DFiniteElement();
|
||||
};
|
||||
|
||||
|
||||
/** An arbitrary order H(curl)-conforming 2D NURBS element on a square
|
||||
More details in the following paper:
|
||||
|
||||
[1] Annalisa Buffa, Giancarlo Sangalli, Rafael Vázquez
|
||||
"Isogeometric analysis in electromagnetics: B-splines approximation."
|
||||
Computer Methods in Applied Mechanics and Engineering (199) 1143-1152 */
|
||||
class NURBS_HCurl2DFiniteElement : public VectorFiniteElement,
|
||||
public NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
|
||||
mutable Vector shape1_x, shape1_y, dshape1_x, dshape1_y, d2shape1_x, d2shape1_y;
|
||||
mutable Vector u;
|
||||
mutable DenseMatrix du;
|
||||
mutable Array <const KnotVector*> kv1;
|
||||
|
||||
public:
|
||||
/// Construct the NURBS_HCurl2DFiniteElement of order @a p
|
||||
NURBS_HCurl2DFiniteElement(int p)
|
||||
: VectorFiniteElement(2, Geometry::SQUARE, 2*(p + 1)*(p + 2), p,
|
||||
H_CURL,FunctionSpace::Qk),
|
||||
NURBSFiniteElement(2),
|
||||
shape_x(p + 1), shape_y(p + 1), dshape_x(p + 1),
|
||||
dshape_y(p + 1), d2shape_x(p + 1), d2shape_y(p + 1),
|
||||
shape1_x(p + 2), shape1_y(p + 2), dshape1_x(p + 2),
|
||||
dshape1_y(p + 2), d2shape1_x(p + 2), d2shape1_y(p + 2),
|
||||
u(dof), du(dof,2)
|
||||
{
|
||||
orders[0] = orders[1] = p;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
}
|
||||
|
||||
/// Construct the NURBS_HCurl2DFiniteElement with x-order @a px and y-order @a py
|
||||
NURBS_HCurl2DFiniteElement(int px, int py)
|
||||
: VectorFiniteElement(2, Geometry::SQUARE,
|
||||
(px + 1)*(py + 2)+(px + 2)*(py + 1),
|
||||
std::max(px, py), H_CURL, FunctionSpace::Qk),
|
||||
NURBSFiniteElement(2),
|
||||
shape_x(px + 1), shape_y(py + 1), dshape_x(px + 1),
|
||||
dshape_y(py + 1), d2shape_x(px + 1), d2shape_y(py + 1),
|
||||
shape1_x(px + 2), shape1_y(py + 2), dshape1_x(px + 2),
|
||||
dshape1_y(py + 2), d2shape1_x(px + 2), d2shape1_y(py + 2),
|
||||
u(dof), du(dof,2)
|
||||
{
|
||||
orders[0] = px; orders[1] = py;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
}
|
||||
|
||||
virtual void SetOrder() const;
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the values of all shape functions of a *vector* finite
|
||||
element in physical space at the point described by @a Trans. */
|
||||
/** Each row of the result DenseMatrix @a shape contains the components of
|
||||
one vector shape function. The size (#dof x SDim) of @a shape must be set
|
||||
in advance, where SDim >= #dim is the physical space dimension as
|
||||
described by @a Trans. */
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the curl of all shape functions of a *vector* finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** Each row of the result DenseMatrix @a curl_shape contains the components
|
||||
of the curl of one vector shape function. The size (#dof x CDim) of
|
||||
@a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
|
||||
CDim = 1 for #dim = 2. */
|
||||
virtual void CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
|
||||
~NURBS_HCurl2DFiniteElement();
|
||||
};
|
||||
|
||||
|
||||
/** An arbitrary order H(curl)-conforming 3D NURBS element on a cube
|
||||
More details in the following paper:
|
||||
|
||||
[1] Annalisa Buffa, Giancarlo Sangalli, Rafael Vázquez
|
||||
"Isogeometric analysis in electromagnetics: B-splines approximation."
|
||||
Computer Methods in Applied Mechanics and Engineering (199) 1143-1152 */
|
||||
class NURBS_HCurl3DFiniteElement : public VectorFiniteElement,
|
||||
public NURBSFiniteElement
|
||||
{
|
||||
protected:
|
||||
mutable Vector shape_x, shape_y, shape_z;
|
||||
mutable Vector dshape_x, dshape_y, dshape_z;
|
||||
mutable Vector d2shape_x, d2shape_y, d2shape_z;
|
||||
mutable Vector shape1_x, shape1_y, shape1_z;
|
||||
mutable Vector dshape1_x, dshape1_y, dshape1_z;
|
||||
mutable Vector d2shape1_x, d2shape1_y, d2shape1_z;
|
||||
mutable Vector u;
|
||||
mutable DenseMatrix du;
|
||||
mutable Array <const KnotVector*> kv1;
|
||||
|
||||
public:
|
||||
/// Construct the NURBS_HCurl3DFiniteElement of order @a p
|
||||
NURBS_HCurl3DFiniteElement(int p)
|
||||
: VectorFiniteElement(3, Geometry::CUBE, 3*(p + 1)*(p + 2)*(p + 2), p,
|
||||
H_CURL,FunctionSpace::Qk),
|
||||
NURBSFiniteElement(3),
|
||||
shape_x(p + 1), shape_y(p + 1), shape_z(p + 1),
|
||||
dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1),
|
||||
d2shape_x(p + 1), d2shape_y(p + 1), d2shape_z(p + 1),
|
||||
shape1_x(p + 2), shape1_y(p + 2), shape1_z(p + 2),
|
||||
dshape1_x(p + 2), dshape1_y(p + 2),dshape1_z(p + 2),
|
||||
d2shape1_x(p + 2), d2shape1_y(p + 2), d2shape1_z(p + 2),
|
||||
u(dof), du(dof,3)
|
||||
{
|
||||
orders[0] = orders[1] = orders[2] = p;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
kv1[2] = nullptr;
|
||||
}
|
||||
|
||||
/// Construct the NURBS_HCurl3DFiniteElement with x-order @a px, y-order @a py and z-order @a pz
|
||||
NURBS_HCurl3DFiniteElement(int px, int py, int pz)
|
||||
: VectorFiniteElement(3, Geometry::CUBE,
|
||||
(px + 1)*(py + 2)*(pz + 2) +
|
||||
(px + 2)*(py + 1)*(pz + 2) +
|
||||
(px + 2)*(py + 2)*(pz + 1),
|
||||
std::max(std::max(px, py), pz), H_CURL, FunctionSpace::Qk),
|
||||
NURBSFiniteElement(3),
|
||||
shape_x(px + 1), shape_y(py + 1), shape_z(pz + 1),
|
||||
dshape_x(px + 1), dshape_y(py + 1), dshape_z(pz + 1),
|
||||
d2shape_x(px + 1), d2shape_y(py + 1), d2shape_z(pz + 1),
|
||||
shape1_x(px + 2), shape1_y(py + 2), shape1_z(pz + 2),
|
||||
dshape1_x(px + 2), dshape1_y(py + 2),dshape1_z(pz + 2),
|
||||
d2shape1_x(px + 2), d2shape1_y(py + 2), d2shape1_z(pz + 2),
|
||||
u(dof), du(dof,3)
|
||||
{
|
||||
orders[0] = px; orders[1] = py; orders[2] = pz;
|
||||
kv1.SetSize(dim);
|
||||
kv1[0] = nullptr;
|
||||
kv1[1] = nullptr;
|
||||
kv1[2] = nullptr;
|
||||
}
|
||||
|
||||
virtual void SetOrder() const;
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the values of all shape functions of a *vector* finite
|
||||
element in physical space at the point described by @a Trans. */
|
||||
/** Each row of the result DenseMatrix @a shape contains the components of
|
||||
one vector shape function. The size (#dof x SDim) of @a shape must be set
|
||||
in advance, where SDim >= #dim is the physical space dimension as
|
||||
described by @a Trans. */
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
/** @brief Evaluate the curl of all shape functions of a *vector* finite
|
||||
element in reference space at the given point @a ip. */
|
||||
/** Each row of the result DenseMatrix @a curl_shape contains the components
|
||||
of the curl of one vector shape function. The size (#dof x CDim) of
|
||||
@a curl_shape must be set in advance, where CDim = 3 for #dim = 3 and
|
||||
CDim = 1 for #dim = 2. */
|
||||
virtual void CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
|
||||
~NURBS_HCurl3DFiniteElement();
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
-214
@@ -344,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
@@ -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
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
+33
-147
@@ -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,7 @@ 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 = fec->FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2374,48 +2372,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 +2425,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 +2988,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 +3926,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++)
|
||||
|
||||
+13
-19
@@ -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;
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
+44
-44
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
+3
-4
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ list(APPEND HDRS
|
||||
handle.hpp
|
||||
invariants.hpp
|
||||
kernels.hpp
|
||||
lapack.hpp
|
||||
linalg.hpp
|
||||
matrix.hpp
|
||||
ode.hpp
|
||||
|
||||
+138
-20
@@ -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
|
||||
// Cholesky–Crout 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
-475
File diff suppressed because it is too large
Load Diff
+8
-24
@@ -272,51 +272,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 +322,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 +346,6 @@ public:
|
||||
void Transpose(const DenseMatrix &A);
|
||||
/// (*this) = 1/2 ((*this) + (*this)^t)
|
||||
void Symmetrize();
|
||||
bool IsSymmetric(real_t tol = 1e-10);
|
||||
|
||||
void Lump();
|
||||
|
||||
|
||||
@@ -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
|
||||
+138
-53
@@ -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, ¬rans, &nounit,
|
||||
&n_glob, &ione, &fone,
|
||||
mat_qr_data.GetData(), &m,
|
||||
vec1.GetData(), &n_glob);
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
strsm_(&lside, &upper, ¬rans, &nounit,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dtrsm_(&lside, &upper, ¬rans, &nounit,
|
||||
#endif
|
||||
&n_glob, &ione, &fone,
|
||||
mat_qr_data.GetData(), &m,
|
||||
vec1.GetData(), &n_glob);
|
||||
|
||||
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_)(¬rans, &m, &n_glob, &fmone,
|
||||
mat_0_data.GetData(), &m,
|
||||
soln_nz_glob.GetData(), &ione, &fone,
|
||||
res_glob.GetData(), &ione);
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sgemv_(¬rans, &m, &n_glob, &fmone,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dgemv_(¬rans, &m, &n_glob, &fmone,
|
||||
#endif
|
||||
mat_0_data.GetData(), &m,
|
||||
soln_nz_glob.GetData(), &ione, &fone,
|
||||
res_glob.GetData(), &ione);
|
||||
}
|
||||
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, ¬rans, &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, ¬rans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dormqr_(&lside, ¬rans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
|
||||
#endif
|
||||
tau.GetData(), qqt_rhs_glob.GetData(), &m,
|
||||
work.data(), &lwork, &info);
|
||||
|
||||
MFEM_VERIFY(info == 0, ""); // Q Q^T b work calculation failed.
|
||||
lwork = static_cast<int>(work[0]);
|
||||
work.resize(lwork);
|
||||
MFEM_LAPACK_PREFIX(ormqr_)(&lside, ¬rans, &m, &ione, &n_glob,
|
||||
mat_qr_data.GetData(), &m,
|
||||
tau.GetData(), qqt_rhs_glob.GetData(), &m,
|
||||
work.data(), &lwork, &info);
|
||||
#ifdef MFEM_USE_SINGLE
|
||||
sormqr_(&lside, ¬rans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
|
||||
#elif defined MFEM_USE_DOUBLE
|
||||
dormqr_(&lside, ¬rans, &m, &ione, &n_glob, mat_qr_data.GetData(), &m,
|
||||
#endif
|
||||
tau.GetData(), qqt_rhs_glob.GetData(), &m,
|
||||
work.data(), &lwork, &info);
|
||||
MFEM_VERIFY(info == 0, ""); // Q Q^T b calculation failed.
|
||||
res_glob = rhs_avg_glob;
|
||||
res_glob -= qqt_rhs_glob;
|
||||
|
||||
+11
-43
@@ -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;
|
||||
|
||||
@@ -1537,9 +1537,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).
|
||||
///
|
||||
|
||||
+18
-103
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -37,4 +37,3 @@ add_subdirectory(tribol)
|
||||
add_subdirectory(hooke)
|
||||
add_subdirectory(dpg)
|
||||
add_subdirectory(hdiv-linear-solver)
|
||||
add_subdirectory(stabilized)
|
||||
|
||||
@@ -0,0 +1,637 @@
|
||||
// Parallel contact example
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 1 -testno 4
|
||||
// CG iteration numbers = 105 114 116 115 113 109 113 108 107 114 206 236 268 435 987
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 5
|
||||
// CG iteration numbers = 106 116 116 116 115 113 107 107 128 131 531 1437 1318
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 6
|
||||
// CG iteration numbers = 18 18 18 18 18 17 17 21 22 46 52 53
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "ipsolver/ParIPsolver.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
double GetBdrElementVolume(int i, Mesh & mesh)
|
||||
{
|
||||
ElementTransformation *et = mesh.GetBdrElementTransformation(i);
|
||||
const IntegrationRule &ir = IntRules.Get(mesh.GetBdrElementGeometry(i),
|
||||
et->OrderJ());
|
||||
double volume = 0.0;
|
||||
for (int j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(j);
|
||||
et->SetIntPoint(&ip);
|
||||
volume += ip.weight * et->Weight();
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
|
||||
double GetBdrArea(int bdrattr, Mesh&mesh)
|
||||
{
|
||||
double area = 0.0;
|
||||
for (int i = 0; i<mesh.GetNBE(); i++)
|
||||
{
|
||||
if (mesh.GetBdrAttribute(i) == bdrattr)
|
||||
{
|
||||
area += GetBdrElementVolume(i,mesh);
|
||||
}
|
||||
}
|
||||
|
||||
MPI_Allreduce(MPI_IN_PLACE,&area,1, MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
|
||||
return area;
|
||||
}
|
||||
|
||||
void OutputData(ostringstream & file_name, double E0, double Ef, int dofs, int constr, int optit, const Array<int> & iters)
|
||||
{
|
||||
file_name << ".csv";
|
||||
std::ofstream outputfile(file_name.str().c_str());
|
||||
//if (!outputfile.is_open())
|
||||
//{
|
||||
// MFEM_ABORT("Failed to open file for writing.\n");
|
||||
//}
|
||||
outputfile << "Initial Energy objective = " << E0 << endl;
|
||||
outputfile << "Final Energy objective = " << Ef << endl;
|
||||
outputfile << "Global number of dofs = " << dofs << endl;
|
||||
outputfile << "Global number of constraints = " << constr << endl;
|
||||
outputfile << "Optimizer number of iterations = " << optit << endl;
|
||||
outputfile << "CG iteration numbers = "; iters.Print(outputfile, iters.Size());
|
||||
outputfile << "OptimizerIteration,CGIterations" << endl;
|
||||
for (int i = 0; i< iters.Size(); i++)
|
||||
{
|
||||
outputfile << i+1 <<","<< iters[i] << endl;
|
||||
}
|
||||
outputfile.close();
|
||||
std::cout << " Data has been written to " << file_name.str().c_str() << endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Mpi::Init();
|
||||
int myid = Mpi::WorldRank();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
Hypre::Init();
|
||||
|
||||
int order = 1;
|
||||
int sref = 1;
|
||||
int pref = 0;
|
||||
Array<int> attr;
|
||||
Array<int> m_attr;
|
||||
bool visualization = true;
|
||||
bool paraview = false;
|
||||
int paraview_plot_every = 1;
|
||||
int SQPrepeat = 1;
|
||||
double linsolverrtol = 1e-10;
|
||||
double linsolveratol = 1e-12;
|
||||
int relax_type = 8;
|
||||
double optimizer_tol = 1e-6;
|
||||
int optimizer_maxit = 20;
|
||||
int linsolver = 2; // PCG - AMG
|
||||
bool elast = false;
|
||||
bool nocontact = false;
|
||||
int testNo = -1; // 0-6
|
||||
int nsteps = 1;
|
||||
bool outputfiles = false;
|
||||
bool doublepass = false;
|
||||
// 1. Parse command-line options.
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&testNo, "-testno", "--test-number",
|
||||
"Choice of test problem:"
|
||||
"-1: default (original 2 block problem)"
|
||||
"0: not implemented yet"
|
||||
"1: not implemented yet"
|
||||
"2: not implemented yet"
|
||||
"3: not implemented yet"
|
||||
"4: two block problem - diablo"
|
||||
"41: two block problem - twisted"
|
||||
"5: ironing problem"
|
||||
"51: ironing problem extended"
|
||||
"6: nested spheres problem");
|
||||
args.AddOption(&attr, "-at", "--attributes-surf",
|
||||
"Attributes of boundary faces on contact surface for mesh 2.");
|
||||
args.AddOption(&sref, "-sr", "--serial-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&nsteps, "-nsteps", "--nsteps",
|
||||
"Number of steps.");
|
||||
args.AddOption(&pref, "-pr", "--parallel-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&linsolverrtol, "-srtol", "--solver-rel-tol",
|
||||
"Linear Solver Relative Tolerance.");
|
||||
args.AddOption(&linsolveratol, "-satol", "--solver-abs-tol",
|
||||
"Linear Solver Abs Tolerance.");
|
||||
args.AddOption(&elast, "-elast", "--elast", "-no-elast",
|
||||
"--no-elast",
|
||||
"Enable or disable AMG Elasticity options.");
|
||||
args.AddOption(&nocontact, "-nocontact", "--nocontact", "-no-nocontact",
|
||||
"--no-nocontact",
|
||||
"Enable or disable AMG solve with no contact for testing.");
|
||||
args.AddOption(&doublepass, "-doublepass", "--double-pass", "-singlepass",
|
||||
"--single-pass",
|
||||
"Enable or disable double pass for contact constraints.");
|
||||
args.AddOption(&optimizer_tol, "-otol", "--optimizer-tol",
|
||||
"Interior Point Solver Tolerance.");
|
||||
args.AddOption(&optimizer_maxit, "-omaxit", "--optimizer-maxit",
|
||||
"Interior Point Solver maximum number of iterations.");
|
||||
args.AddOption(&relax_type, "-rt", "--relax-type",
|
||||
"Selection of Smoother for AMG");
|
||||
args.AddOption(&linsolver, "-ls", "--linear-solver",
|
||||
"Selection of inner linear solver:"
|
||||
"0: mumps,"
|
||||
"1: mumps-reduced,"
|
||||
"2: PCG-AMG-reduced,"
|
||||
"3: PCG- with block-diag(AMG,direct solver)"
|
||||
"4: with static cond of contact dofs");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(¶view, "-paraview", "--paraview", "-no-paraview",
|
||||
"--no-paraview",
|
||||
"Enable or disable ParaView visualization.");
|
||||
args.AddOption(¶view_plot_every, "-plot_every", "--plot-every",
|
||||
"Output every plot_every pseudotimesteps as a paraview file");
|
||||
args.AddOption(&SQPrepeat, "-nSQPrepeat", "--nSQP-repeats", "Number of times to relinearize and resolve the SQP before incremenetally updating forcing and boundary terms");
|
||||
args.AddOption(&outputfiles, "-out", "--output", "-no-out",
|
||||
"--no-ouput",
|
||||
"Enable or disable ouput to files.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
if (Mpi::Root())
|
||||
{
|
||||
mfem::out << "Solving test problem number: " << testNo << endl;
|
||||
}
|
||||
|
||||
const char *mesh_file = nullptr;
|
||||
|
||||
switch (testNo)
|
||||
{
|
||||
case -1:
|
||||
mesh_file = "meshes/two-block.mesh";
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
MFEM_ABORT("Problem not implemented yet");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
mesh_file = "meshes/Test4.mesh";
|
||||
break;
|
||||
case 40:
|
||||
mesh_file = "meshes/Test40.mesh";
|
||||
break;
|
||||
case 41:
|
||||
mesh_file = "meshes/Test41.mesh";
|
||||
break;
|
||||
case 42:
|
||||
mesh_file = "meshes/Test42.mesh";
|
||||
break;
|
||||
case 5:
|
||||
mesh_file = "meshes/Test5.mesh";
|
||||
break;
|
||||
case 51:
|
||||
mesh_file = "meshes/Test51.mesh";
|
||||
break;
|
||||
case 6:
|
||||
mesh_file = "meshes/Test6.mesh";
|
||||
break;
|
||||
case 61:
|
||||
// Something wrong with this mesh
|
||||
mesh_file = "meshes/Test61.mesh";
|
||||
break;
|
||||
case 62:
|
||||
mesh_file = "meshes/Test62.mesh";
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Should be unreachable");
|
||||
break;
|
||||
}
|
||||
|
||||
Mesh * mesh = new Mesh(mesh_file,1);
|
||||
for (int i = 0; i<sref; i++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
ParMesh * pmesh = new ParMesh(MPI_COMM_WORLD,*mesh);
|
||||
|
||||
for (int i = 0; i<pref; i++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
Array<int> ess_bdr_attr;
|
||||
Array<int> ess_bdr_attr_comp;
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(1);
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(2);
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 62)
|
||||
{
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 40)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(10); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(6); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
ParElasticityProblem * prob = new ParElasticityProblem(pmesh,
|
||||
ess_bdr_attr,ess_bdr_attr_comp,
|
||||
order);
|
||||
Vector lambda(prob->GetMesh()->attributes.Max());
|
||||
Vector mu(prob->GetMesh()->attributes.Max());
|
||||
|
||||
if (testNo == -1 )
|
||||
{
|
||||
lambda = 57.6923076923;
|
||||
mu = 38.4615384615;
|
||||
}
|
||||
else if (testNo == 6 || testNo == 61 || testNo == 62)
|
||||
{
|
||||
lambda = (1000*0.3)/(1.3*0.4);
|
||||
mu = 500/(1.3);
|
||||
}
|
||||
else
|
||||
{
|
||||
//lambda = 57.6923076923;
|
||||
//mu = 38.4615384615;
|
||||
//lambda = 0.499 / (1.499 * 0.002);
|
||||
//mu = 1. / (2. * 1.499);
|
||||
lambda[0] = 0.499/(1.499*0.002);
|
||||
lambda[1] = 0.0;
|
||||
mu[0] = 1. / (2. * 1.499);
|
||||
mu[1] = 500.;
|
||||
}
|
||||
|
||||
prob->SetLambda(lambda); prob->SetMu(mu);
|
||||
|
||||
int dim = pmesh->Dimension();
|
||||
Vector ess_values(dim);
|
||||
int essbdr_attr;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
|
||||
ess_values = 0.0;
|
||||
|
||||
|
||||
double area = GetBdrArea(3,*mesh);
|
||||
|
||||
// ConstantCoefficient one(-area);
|
||||
ConstantCoefficient one(-1.0);
|
||||
|
||||
std::set<int> mortar_attr;
|
||||
std::set<int> nonmortar_attr;
|
||||
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[0] = 1;
|
||||
ess_bdr[1] = 1;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else if(testNo == 62)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
prob->SetNeumanData(0,3,-2.0);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (testNo == -1 || testNo == 41)
|
||||
{
|
||||
ess_values[0] = 0.1/nsteps;
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_values[2] = 1.0 / 1.4 / nsteps;
|
||||
//ess_values[2] = 0.25 / nsteps;//1.0/1.4/nsteps;
|
||||
// ess_values[0] = -2.0/nsteps;
|
||||
}
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = (testNo == 40) ? 10 : 6;
|
||||
ess_values = 0.0; ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
if (testNo == 40)
|
||||
{
|
||||
mortar_attr.insert(4);
|
||||
nonmortar_attr.insert(7);
|
||||
}
|
||||
else
|
||||
{
|
||||
mortar_attr.insert(3);
|
||||
nonmortar_attr.insert(4);
|
||||
}
|
||||
}
|
||||
|
||||
ParFiniteElementSpace * fes = prob->GetFESpace();
|
||||
ParGridFunction x_gf(fes); x_gf = 0.0;
|
||||
ParGridFunction xnew(fes); xnew = 0.0;
|
||||
ParaViewDataCollection * paraview_dc = nullptr;
|
||||
ParMesh pmesh_copy(*pmesh);
|
||||
ParFiniteElementSpace fes_copy(*fes,pmesh_copy);
|
||||
ParGridFunction xcopy_gf(&fes_copy); xcopy_gf = 0.0;
|
||||
|
||||
if (paraview)
|
||||
{
|
||||
std::ostringstream paraview_file_name;
|
||||
paraview_file_name << "QPContact-Test_" << testNo
|
||||
<< "_par_ref_" << pref
|
||||
<< "_ser_ref_" << sref;
|
||||
paraview_dc = new ParaViewDataCollection(paraview_file_name.str(), &pmesh_copy);
|
||||
paraview_dc->SetPrefixPath("ParaView");
|
||||
paraview_dc->SetLevelsOfDetail(1);
|
||||
paraview_dc->SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc->SetHighOrderOutput(true);
|
||||
// paraview_dc->RegisterField("u", &x_gf);
|
||||
paraview_dc->RegisterField("u", &xcopy_gf);
|
||||
paraview_dc->SetCycle(0);
|
||||
paraview_dc->SetTime(double(0));
|
||||
paraview_dc->Save();
|
||||
}
|
||||
socketstream sol_sock;
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
sol_sock.open(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
}
|
||||
// ParGridFunction coords(prob->GetFESpace());
|
||||
ParGridFunction ref_coords(prob->GetFESpace());
|
||||
ParGridFunction new_coords(prob->GetFESpace());
|
||||
pmesh->GetNodes(new_coords);
|
||||
pmesh->GetNodes(ref_coords);
|
||||
|
||||
Vector xref(x_gf.GetTrueVector().Size());
|
||||
|
||||
HypreParMatrix *dgdu;
|
||||
double p = 1;
|
||||
ConstantCoefficient f(p);
|
||||
|
||||
// SQPrepeat solves on same problem (forcing/boundary conditions)
|
||||
int Nsteps = nsteps * SQPrepeat;
|
||||
|
||||
double pseudotime = 0.0;
|
||||
double pseudotimestep = 1.0 / ((double) nsteps);
|
||||
double paraview_time = 0.0;
|
||||
double paraview_subtimestep = pseudotimestep / ((double) SQPrepeat);
|
||||
int paraview_cycle = 1;
|
||||
|
||||
bool QPConverged;
|
||||
|
||||
std::ofstream numConstraintsStream;
|
||||
std::ostringstream numConstraints_file_name;
|
||||
numConstraints_file_name << "data/numConstraints_ref" << sref << ".dat";
|
||||
if (Mpi::Root)
|
||||
{
|
||||
numConstraintsStream.open(numConstraints_file_name.str(), ios::out | ios::trunc);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nsteps; i++)
|
||||
{
|
||||
pseudotime = ((double) (i + 1)) / ((double) nsteps);
|
||||
for (int j = 0; j < SQPrepeat; j++)
|
||||
{
|
||||
paraview_time = pseudotime + j * paraview_subtimestep;
|
||||
if (testNo == 6)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
f.constant = -p * pseudotime;
|
||||
prob->SetNeumanPressureData(f,ess_bdr);
|
||||
// prob->SetNeumanData(0,3,-p*(i+1)/nsteps);
|
||||
}
|
||||
else if (testNo == 4 || testNo == 40 || testNo == 5 || testNo == 51)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
ess_values = 0.0;
|
||||
//ess_values[2] = 4.0 / 7.0 * pseudotime;
|
||||
//ess_values[2] = 0.25 * pseudotime; //1.0/1.4 * pseudotime;
|
||||
ess_values[2] = 1.0 / 1.4 * pseudotime;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
else if (testNo == 41)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_values[0] = 0.5 * pseudotime; //0.5/nsteps*(i+1);
|
||||
// ess_values[0] = 0.0;
|
||||
essbdr_attr = 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = 6;
|
||||
ess_values = 0.0;
|
||||
// ess_values[0] = -0.5/nsteps*(i+1);
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "ess_values[0] = " << ess_values[0] << endl;
|
||||
}
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
|
||||
//xref.Set(1.0, x_gf.GetTrueVector());
|
||||
xref = 0.0;
|
||||
ParContactProblem contact(prob, mortar_attr, nonmortar_attr, &new_coords, doublepass);
|
||||
QPOptParContactProblem qpopt(&contact, xref);
|
||||
int numconstr = contact.GetGlobalNumConstraints();
|
||||
ParInteriorPointSolver optimizer(&qpopt);
|
||||
optimizer.SetTol(optimizer_tol);
|
||||
optimizer.SetMaxIter(optimizer_maxit);
|
||||
optimizer.SetLinearSolver(linsolver);
|
||||
optimizer.SetLinearSolveRelTol(linsolverrtol);
|
||||
optimizer.SetLinearSolveAbsTol(linsolveratol);
|
||||
optimizer.SetLinearSolveRelaxType(relax_type);
|
||||
if (nocontact)
|
||||
{
|
||||
optimizer.EnableNoContactSolve();
|
||||
}
|
||||
if (elast)
|
||||
{
|
||||
optimizer.SetElasticityOptions(prob->GetFESpace());
|
||||
}
|
||||
// ParGridFunction x = prob->GetDisplacementGridFunction();
|
||||
// x.SetTrueVector();
|
||||
// Vector x0 = x.GetTrueVector();
|
||||
|
||||
x_gf.SetTrueVector();
|
||||
|
||||
|
||||
Vector x0 = x_gf.GetTrueVector();
|
||||
int ndofs = x0.Size();
|
||||
Vector xf(ndofs); xf = 0.0;
|
||||
optimizer.Mult(x0, xf);
|
||||
QPConverged = optimizer.GetConverged();
|
||||
|
||||
/* exit if not converged */
|
||||
MFEM_VERIFY(QPConverged, "IPM not converged on QP contact problem");
|
||||
|
||||
|
||||
double Einitial = contact.E(x0);
|
||||
double Efinal = contact.E(xf);
|
||||
Array<int> & CGiterations = optimizer.GetCGIterNumbers();
|
||||
int gndofs = prob->GetGlobalNumDofs();
|
||||
int gnconstraints = contact.GetGlobalNumConstraints();
|
||||
|
||||
//std::ofstream xfStream;
|
||||
//std::ostringstream xf_file_name;
|
||||
//xf_file_name << "data/xf_" << i << ".dat";
|
||||
//if (Mpi::Root())
|
||||
//{
|
||||
// xfStream.open(xf_file_name.str(), ios::out | ios::trunc);
|
||||
// for (int ii = 0; ii < xf.Size(); ii++)
|
||||
// {
|
||||
// xfStream << xf(ii) << "\n";
|
||||
// }
|
||||
// xfStream.close();
|
||||
//}
|
||||
//if (Mpi::Root)
|
||||
//{
|
||||
// numConstraintsStream.open(numConstraints_file_name.str(), ios::out | ios::trunc);
|
||||
//}
|
||||
|
||||
|
||||
if (Mpi::Root())
|
||||
{
|
||||
|
||||
mfem::out << endl;
|
||||
mfem::out << " Initial Energy objective = " << Einitial << endl;
|
||||
mfem::out << " Final Energy objective = " << Efinal << endl;
|
||||
mfem::out << " Global number of dofs = " << gndofs << endl;
|
||||
mfem::out << " Global number of constraints = " << numconstr << endl;
|
||||
mfem::out << " Optimizer number of iterations = " <<
|
||||
optimizer.GetNumIterations() << endl;
|
||||
if (linsolver == 2 || linsolver == 3 || linsolver == 4)
|
||||
{
|
||||
mfem::out << " CG iteration numbers = " ;
|
||||
CGiterations.Print(mfem::out, CGiterations.Size());
|
||||
}
|
||||
if (nocontact)
|
||||
{
|
||||
Array<int> & CGNoContactIterations = optimizer.GetCGNoContactIterNumbers();
|
||||
mfem::out << " CG no Contact iteration numbers = " ;
|
||||
CGNoContactIterations.Print(mfem::out, CGNoContactIterations.Size());
|
||||
}
|
||||
if (outputfiles)
|
||||
{
|
||||
ostringstream file_name;
|
||||
file_name << "output/Testno-"<<testNo<<"-ref-"<<sref+pref << "-step-" << i;
|
||||
OutputData(file_name, Einitial, Efinal, gndofs,numconstr, optimizer.GetNumIterations(), CGiterations);
|
||||
}
|
||||
numConstraintsStream << gnconstraints << endl;
|
||||
}
|
||||
|
||||
// Vector X_new(xf.GetData(),fes->GetTrueVSize());
|
||||
// xnew.SetFromTrueDofs(X_new);
|
||||
// x_gf = xnew;
|
||||
x_gf.SetFromTrueDofs(xf);
|
||||
// mfem::out << "x_gf norm = " << x_gf.Norml2() << endl;
|
||||
// cin.get();
|
||||
// pmesh->MoveNodes(xnew);
|
||||
// pmesh_copy.MoveNodes(xnew);
|
||||
// pmesh_copy.MoveNodes(xnew);
|
||||
add(ref_coords,x_gf,new_coords);
|
||||
// mfem::out << " ref_coords norm " << ref_coords.Norml2() << endl;
|
||||
// mfem::out << " x_gf norm " << x_gf.Norml2() << endl;
|
||||
// mfem::out << " new_coords norm " << new_coords.Norml2() << endl;
|
||||
// pmesh_copy.SetNodes(new_coords);
|
||||
pmesh_copy.SetNodes(new_coords);
|
||||
xcopy_gf = x_gf;
|
||||
// pmesh_copy.MoveNodes(x_gf);
|
||||
// pmesh_copy.SetNodes(x_gf);
|
||||
if (paraview && ((i+1) % paraview_plot_every == 0 ))
|
||||
{
|
||||
paraview_cycle += 1;
|
||||
paraview_dc->SetCycle(paraview_cycle) ;
|
||||
paraview_dc->SetTime(paraview_time);
|
||||
paraview_dc->Save();
|
||||
}
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n"
|
||||
<< "solution\n" << pmesh_copy << x_gf << flush;
|
||||
|
||||
if (i == nsteps - 1 && j == SQPrepeat - 1)
|
||||
{
|
||||
pmesh->MoveNodes(x_gf);
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock1(vishost, visport);
|
||||
sol_sock1 << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock1.precision(8);
|
||||
sol_sock1 << "solution\n" << *pmesh << x_gf << flush;
|
||||
}
|
||||
}
|
||||
if (i == nsteps - 1 && j == SQPrepeat) break;
|
||||
|
||||
prob->UpdateStep();
|
||||
if (testNo == 6 )
|
||||
{
|
||||
double area_new = GetBdrArea(3,*pmesh);
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "New area = " << area_new << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Mpi::Root)
|
||||
{
|
||||
numConstraintsStream.close();
|
||||
}
|
||||
delete prob;
|
||||
delete pmesh;
|
||||
delete mesh;
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,114 @@
|
||||
#include "mfem.hpp"
|
||||
#include "../problems/parproblems.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
|
||||
#ifndef PARIPSOLVER
|
||||
#define PARIPSOLVER
|
||||
|
||||
class ParInteriorPointSolver
|
||||
{
|
||||
protected:
|
||||
QPOptParContactProblem* problem = nullptr;
|
||||
double OptTol;
|
||||
int max_iter;
|
||||
int iter=0;
|
||||
double mu_k; // \mu_k
|
||||
Vector lk, zlk;
|
||||
|
||||
double sMax, kSig, tauMin, eta, thetaMin, delta, sTheta, sPhi, kMu, thetaMu;
|
||||
double thetaMax, kSoc, gTheta, gPhi, kEps;
|
||||
|
||||
// filter
|
||||
Array<double> F1, F2;
|
||||
|
||||
// quantities computed in lineSearch
|
||||
double alpha, alphaz;
|
||||
double thx0, thxtrial;
|
||||
double phx0, phxtrial;
|
||||
bool descentDirection, switchCondition, sufficientDecrease, lineSearchSuccess, inFilterRegion;
|
||||
double Dxphi0_xhat;
|
||||
|
||||
int dimU, dimM, dimC;
|
||||
int gdimU, gdimM, gdimC;
|
||||
Array<int> block_offsetsumlz, block_offsetsuml, block_offsetsx;
|
||||
Vector ml;
|
||||
|
||||
Vector ckSoc;
|
||||
HypreParMatrix * Huu = nullptr;
|
||||
HypreParMatrix * Hum = nullptr;
|
||||
HypreParMatrix * Hmu = nullptr;
|
||||
HypreParMatrix * Hmm = nullptr;
|
||||
HypreParMatrix * Wmm = nullptr;
|
||||
HypreParMatrix * Ju = nullptr;
|
||||
HypreParMatrix * Jm = nullptr;
|
||||
HypreParMatrix * JuT = nullptr;
|
||||
HypreParMatrix * JmT = nullptr;
|
||||
|
||||
Array<int> cgnum_iterations;
|
||||
Array<int> cgnum_iterations_nocontact;
|
||||
ParFiniteElementSpace *pfes = nullptr;
|
||||
|
||||
int jOpt;
|
||||
bool converged;
|
||||
|
||||
int MyRank;
|
||||
bool iAmRoot;
|
||||
|
||||
bool saveLogBarrierIterates = false;
|
||||
|
||||
int linSolver=0;
|
||||
double linSolveAbsTol = 1e-12;
|
||||
double linSolveRelTol = 1e-6;
|
||||
int relax_type = 8;
|
||||
bool nocontact = false;
|
||||
public:
|
||||
ParInteriorPointSolver(QPOptParContactProblem*);
|
||||
double MaxStepSize(Vector& , Vector& , Vector& , double);
|
||||
double MaxStepSize(Vector& , Vector& , double);
|
||||
void Mult(const BlockVector& , BlockVector&);
|
||||
void Mult(const Vector&, Vector &);
|
||||
void FormIPNewtonMat(BlockVector& , Vector& , Vector& , BlockOperator &);
|
||||
void IPNewtonSolve(BlockVector& , Vector& , Vector& , Vector&, BlockVector& , double, bool);
|
||||
void lineSearch(BlockVector& , BlockVector& , double);
|
||||
void projectZ(const Vector & , Vector &, double);
|
||||
void filterCheck(double, double);
|
||||
double E(const BlockVector &, const Vector &, const Vector &, double, bool);
|
||||
double E(const BlockVector &, const Vector &, const Vector &, bool);
|
||||
bool GetConverged() const;
|
||||
Array<int> & GetCGIterNumbers() {return cgnum_iterations;}
|
||||
Array<int> & GetCGNoContactIterNumbers() {return cgnum_iterations_nocontact;}
|
||||
int GetNumIterations() {return iter;}
|
||||
// TO DO: include Hessian of Lagrangian
|
||||
double theta(const BlockVector &);
|
||||
double phi(const BlockVector &, double);
|
||||
void Dxphi(const BlockVector &, double, BlockVector &);
|
||||
double L(const BlockVector &, const Vector &, const Vector &);
|
||||
void DxL(const BlockVector &, const Vector &, const Vector &, BlockVector &);
|
||||
void SetTol(double);
|
||||
void SetMaxIter(int);
|
||||
void SetBarrierParameter(double);
|
||||
void SaveLogBarrierHessianIterates(bool);
|
||||
void SaveLambda(int);
|
||||
void SaveZl(int);
|
||||
void SetLinearSolver(int);
|
||||
void SetLinearSolveAbsTol(double);
|
||||
void SetLinearSolveRelTol(double);
|
||||
void SetLinearSolveRelaxType(int);
|
||||
|
||||
void SetElasticityOptions(ParFiniteElementSpace * pfes_)
|
||||
{
|
||||
pfes = pfes_;
|
||||
}
|
||||
void EnableNoContactSolve()
|
||||
{
|
||||
nocontact = true;
|
||||
}
|
||||
virtual ~ParInteriorPointSolver();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
# Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
|
||||
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
# LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
#
|
||||
# This file is part of the MFEM library. For more information and source code
|
||||
# availability visit https://mfem.org.
|
||||
#
|
||||
# MFEM is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/contact/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
|
||||
# Include defaults.mk to get XLINKER
|
||||
#DEFAULTS_MK = $(MFEM_DIR)/config/defaults.mk
|
||||
#include $(DEFAULTS_MK)
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
FRAMEWORK_SRC = ipsolver/ParIPsolver.cpp problems/parproblems.cpp problems/parproblems_util.cpp
|
||||
CONTACT_SRC = contact.cpp $(FRAMEWORK_SRC)
|
||||
CONTACT_OBJ = $(CONTACT_SRC:.cpp=.o)
|
||||
|
||||
CONTACT_FDCHECK_SRC = contactFDcheck.cpp $(FRAMEWORK_SRC)
|
||||
CONTACT_FDCHECK_OBJ = $(CONTACT_FDCHECK_SRC:.cpp=.o)
|
||||
|
||||
SCRATCH_SRC = scratch.cpp $(FRAMEWORK_SRC)
|
||||
SCRATCH_OBJ = $(SCRATCH_SRC:.cpp=.o)
|
||||
|
||||
|
||||
SEQ_MINIAPPS =
|
||||
PAR_MINIAPPS = scratch contact contactFDcheck
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
MINIAPPS = $(SEQ_MINIAPPS)
|
||||
else
|
||||
MINIAPPS = $(PAR_MINIAPPS) $(SEQ_MINIAPPS)
|
||||
endif
|
||||
|
||||
COMMON_LIB = -L$(MFEM_BUILD_DIR)/miniapps/common -lmfem-common
|
||||
|
||||
# If MFEM_SHARED is set, add the ../common rpath
|
||||
COMMON_LIB += $(if $(MFEM_SHARED:YES=),,\
|
||||
$(if $(MFEM_USE_CUDA:YES=),$(CXX_XLINKER),$(CUDA_XLINKER))-rpath,$(abspath\
|
||||
$(MFEM_BUILD_DIR)/miniapps/common))
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .cpp .mk
|
||||
.PHONY: all lib-common clean clean-build clean-exec
|
||||
|
||||
# Remove built-in rule
|
||||
%: %.cpp
|
||||
%.o: %.cpp
|
||||
|
||||
%.o: $(SRC)%.cpp $(wildcard $(SRC)%.hpp) $(MFEM_LIB_FILE)\
|
||||
$(CONFIG_MK) | lib-common
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@
|
||||
|
||||
problems/%.o: $(SRC)problems/%.cpp $(wildcard $(SRC)problems/%.hpp) $(MFEM_LIB_FILE)\
|
||||
$(CONFIG_MK) | lib-common
|
||||
mkdir -p $(@D)
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@
|
||||
|
||||
|
||||
all: $(MINIAPPS)
|
||||
|
||||
contact: $(CONTACT_OBJ)
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(CONTACT_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
|
||||
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
|
||||
|
||||
contactFDcheck: $(CONTACT_FDCHECK_OBJ)
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(CONTACT_FDCHECK_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
|
||||
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
|
||||
|
||||
scratch: $(SCRATCH_OBJ)
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(SCRATCH_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
|
||||
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
|
||||
|
||||
|
||||
# Rule for building lib-common
|
||||
lib-common:
|
||||
$(MAKE) -C $(MFEM_BUILD_DIR)/miniapps/common
|
||||
|
||||
MFEM_TESTS = MINIAPPS
|
||||
include $(MFEM_TEST_MK)
|
||||
|
||||
# Testing: Specific execution options
|
||||
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
|
||||
contact-test-par: contact
|
||||
@$(call mfem-test,$<, $(RUN_MPI), pcontact miniapp,)
|
||||
|
||||
# Generate an error message if the MFEM library is not built and exit
|
||||
$(MFEM_LIB_FILE):
|
||||
$(error The MFEM library is not built)
|
||||
|
||||
clean: clean-build clean-exec
|
||||
|
||||
clean-build:
|
||||
rm -f *.o *~ $(PAR_MINIAPPS) $(SEQ_MINIAPPS)
|
||||
rm -f $(CONTACT_OBJ)
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
clean-exec:
|
||||
@rm -rf ParaView
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,453 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
# PYRAMID = 7
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
89
|
||||
1 5 0 1 5 4 40 41 45 44
|
||||
1 5 40 41 45 44 80 81 85 84
|
||||
1 5 44 45 49 48 84 85 89 88
|
||||
1 5 4 5 9 8 44 45 49 48
|
||||
1 5 5 6 10 9 45 46 50 49
|
||||
1 5 45 46 50 49 85 86 90 89
|
||||
1 5 41 42 46 45 81 82 86 85
|
||||
1 5 1 2 6 5 41 42 46 45
|
||||
1 5 2 3 7 6 42 43 47 46
|
||||
1 5 42 43 47 46 82 83 87 86
|
||||
1 5 6 7 11 10 46 47 51 50
|
||||
1 5 46 47 51 50 86 87 91 90
|
||||
1 5 86 87 91 90 126 127 131 130
|
||||
1 5 82 83 87 86 122 123 127 126
|
||||
1 5 81 82 86 85 121 122 126 125
|
||||
1 5 80 81 85 84 120 121 125 124
|
||||
1 5 84 85 89 88 124 125 129 128
|
||||
1 5 85 86 90 89 125 126 130 129
|
||||
1 5 89 90 94 93 129 130 134 133
|
||||
1 5 88 89 93 92 128 129 133 132
|
||||
1 5 92 93 97 96 132 133 137 136
|
||||
1 5 93 94 98 97 133 134 138 137
|
||||
1 5 94 95 99 98 134 135 139 138
|
||||
1 5 54 55 59 58 94 95 99 98
|
||||
1 5 90 91 95 94 130 131 135 134
|
||||
1 5 50 51 55 54 90 91 95 94
|
||||
1 5 10 11 15 14 50 51 55 54
|
||||
1 5 14 15 19 18 54 55 59 58
|
||||
1 5 13 14 18 17 53 54 58 57
|
||||
1 5 53 54 58 57 93 94 98 97
|
||||
1 5 49 50 54 53 89 90 94 93
|
||||
1 5 9 10 14 13 49 50 54 53
|
||||
1 5 8 9 13 12 48 49 53 52
|
||||
1 5 48 49 53 52 88 89 93 92
|
||||
1 5 52 53 57 56 92 93 97 96
|
||||
1 5 12 13 17 16 52 53 57 56
|
||||
1 5 16 17 21 20 56 57 61 60
|
||||
1 5 56 57 61 60 96 97 101 100
|
||||
1 5 57 58 62 61 97 98 102 101
|
||||
1 5 17 18 22 21 57 58 62 61
|
||||
1 5 18 19 23 22 58 59 63 62
|
||||
1 5 58 59 63 62 98 99 103 102
|
||||
1 5 98 99 103 102 138 139 143 142
|
||||
1 5 97 98 102 101 137 138 142 141
|
||||
1 5 96 97 101 100 136 137 141 140
|
||||
1 5 100 101 105 104 140 141 145 144
|
||||
1 5 101 102 106 105 141 142 146 145
|
||||
1 5 102 103 107 106 142 143 147 146
|
||||
1 5 62 63 67 66 102 103 107 106
|
||||
1 5 22 23 27 26 62 63 67 66
|
||||
1 5 21 22 26 25 61 62 66 65
|
||||
1 5 61 62 66 65 101 102 106 105
|
||||
1 5 60 61 65 64 100 101 105 104
|
||||
1 5 20 21 25 24 60 61 65 64
|
||||
1 5 24 25 29 28 64 65 69 68
|
||||
1 5 64 65 69 68 104 105 109 108
|
||||
1 5 68 69 73 72 108 109 113 112
|
||||
1 5 28 29 33 32 68 69 73 72
|
||||
1 5 29 30 34 33 69 70 74 73
|
||||
1 5 69 70 74 73 109 110 114 113
|
||||
1 5 65 66 70 69 105 106 110 109
|
||||
1 5 25 26 30 29 65 66 70 69
|
||||
1 5 26 27 31 30 66 67 71 70
|
||||
1 5 66 67 71 70 106 107 111 110
|
||||
1 5 30 31 35 34 70 71 75 74
|
||||
1 5 70 71 75 74 110 111 115 114
|
||||
1 5 110 111 115 114 150 151 155 154
|
||||
1 5 106 107 111 110 146 147 151 150
|
||||
1 5 105 106 110 109 145 146 150 149
|
||||
1 5 109 110 114 113 149 150 154 153
|
||||
1 5 104 105 109 108 144 145 149 148
|
||||
1 5 108 109 113 112 148 149 153 152
|
||||
1 5 112 113 117 116 152 153 157 156
|
||||
1 5 113 114 118 117 153 154 158 157
|
||||
1 5 114 115 119 118 154 155 159 158
|
||||
1 5 74 75 79 78 114 115 119 118
|
||||
1 5 34 35 39 38 74 75 79 78
|
||||
1 5 33 34 38 37 73 74 78 77
|
||||
1 5 73 74 78 77 113 114 118 117
|
||||
1 5 72 73 77 76 112 113 117 116
|
||||
1 5 32 33 37 36 72 73 77 76
|
||||
2 5 160 161 164 163 169 170 173 172
|
||||
2 5 163 164 167 166 172 173 176 175
|
||||
2 5 172 173 176 175 181 182 185 184
|
||||
2 5 169 170 173 172 178 179 182 181
|
||||
2 5 170 171 174 173 179 180 183 182
|
||||
2 5 173 174 177 176 182 183 186 185
|
||||
2 5 164 165 168 167 173 174 177 176
|
||||
2 5 161 162 165 164 170 171 174 173
|
||||
|
||||
boundary
|
||||
150
|
||||
1 3 0 4 5 1
|
||||
1 3 1 5 6 2
|
||||
1 3 2 6 7 3
|
||||
1 3 4 8 9 5
|
||||
1 3 5 9 10 6
|
||||
1 3 6 10 11 7
|
||||
1 3 8 12 13 9
|
||||
1 3 9 13 14 10
|
||||
1 3 10 14 15 11
|
||||
1 3 12 16 17 13
|
||||
1 3 13 17 18 14
|
||||
1 3 14 18 19 15
|
||||
1 3 16 20 21 17
|
||||
1 3 17 21 22 18
|
||||
1 3 18 22 23 19
|
||||
1 3 20 24 25 21
|
||||
1 3 21 25 26 22
|
||||
1 3 22 26 27 23
|
||||
1 3 24 28 29 25
|
||||
1 3 25 29 30 26
|
||||
1 3 26 30 31 27
|
||||
1 3 28 32 33 29
|
||||
1 3 29 33 34 30
|
||||
1 3 30 34 35 31
|
||||
1 3 32 36 37 33
|
||||
1 3 33 37 38 34
|
||||
1 3 34 38 39 35
|
||||
1 3 120 121 125 124
|
||||
1 3 121 122 126 125
|
||||
1 3 122 123 127 126
|
||||
1 3 124 125 129 128
|
||||
1 3 125 126 130 129
|
||||
1 3 126 127 131 130
|
||||
1 3 128 129 133 132
|
||||
1 3 129 130 134 133
|
||||
1 3 130 131 135 134
|
||||
1 3 132 133 137 136
|
||||
1 3 133 134 138 137
|
||||
1 3 134 135 139 138
|
||||
1 3 136 137 141 140
|
||||
1 3 137 138 142 141
|
||||
1 3 138 139 143 142
|
||||
1 3 140 141 145 144
|
||||
1 3 141 142 146 145
|
||||
1 3 142 143 147 146
|
||||
1 3 144 145 149 148
|
||||
1 3 145 146 150 149
|
||||
1 3 146 147 151 150
|
||||
1 3 148 149 153 152
|
||||
1 3 149 150 154 153
|
||||
1 3 150 151 155 154
|
||||
1 3 152 153 157 156
|
||||
1 3 153 154 158 157
|
||||
1 3 154 155 159 158
|
||||
2 3 0 40 44 4
|
||||
2 3 4 44 48 8
|
||||
2 3 8 48 52 12
|
||||
2 3 12 52 56 16
|
||||
2 3 16 56 60 20
|
||||
2 3 20 60 64 24
|
||||
2 3 24 64 68 28
|
||||
2 3 28 68 72 32
|
||||
2 3 32 72 76 36
|
||||
2 3 40 80 84 44
|
||||
2 3 44 84 88 48
|
||||
2 3 48 88 92 52
|
||||
2 3 52 92 96 56
|
||||
2 3 56 96 100 60
|
||||
2 3 60 100 104 64
|
||||
2 3 64 104 108 68
|
||||
2 3 68 108 112 72
|
||||
2 3 72 112 116 76
|
||||
2 3 80 120 124 84
|
||||
2 3 84 124 128 88
|
||||
2 3 88 128 132 92
|
||||
2 3 92 132 136 96
|
||||
2 3 96 136 140 100
|
||||
2 3 100 140 144 104
|
||||
2 3 104 144 148 108
|
||||
2 3 108 148 152 112
|
||||
2 3 112 152 156 116
|
||||
3 3 3 7 47 43
|
||||
3 3 7 11 51 47
|
||||
3 3 11 15 55 51
|
||||
3 3 15 19 59 55
|
||||
3 3 19 23 63 59
|
||||
3 3 23 27 67 63
|
||||
3 3 27 31 71 67
|
||||
3 3 31 35 75 71
|
||||
3 3 35 39 79 75
|
||||
3 3 43 47 87 83
|
||||
3 3 47 51 91 87
|
||||
3 3 51 55 95 91
|
||||
3 3 55 59 99 95
|
||||
3 3 59 63 103 99
|
||||
3 3 63 67 107 103
|
||||
3 3 67 71 111 107
|
||||
3 3 71 75 115 111
|
||||
3 3 75 79 119 115
|
||||
3 3 83 87 127 123
|
||||
3 3 87 91 131 127
|
||||
3 3 91 95 135 131
|
||||
3 3 95 99 139 135
|
||||
3 3 99 103 143 139
|
||||
3 3 103 107 147 143
|
||||
3 3 107 111 151 147
|
||||
3 3 111 115 155 151
|
||||
3 3 115 119 159 155
|
||||
1 3 0 1 41 40
|
||||
1 3 40 41 81 80
|
||||
1 3 80 81 121 120
|
||||
1 3 1 2 42 41
|
||||
1 3 41 42 82 81
|
||||
1 3 81 82 122 121
|
||||
1 3 2 3 43 42
|
||||
1 3 42 43 83 82
|
||||
1 3 82 83 123 122
|
||||
1 3 36 76 77 37
|
||||
1 3 76 116 117 77
|
||||
1 3 116 156 157 117
|
||||
1 3 37 77 78 38
|
||||
1 3 77 117 118 78
|
||||
1 3 117 157 158 118
|
||||
1 3 38 78 79 39
|
||||
1 3 78 118 119 79
|
||||
1 3 118 158 159 119
|
||||
5 3 160 163 164 161
|
||||
5 3 161 164 165 162
|
||||
5 3 163 166 167 164
|
||||
5 3 164 167 168 165
|
||||
5 3 178 179 182 181
|
||||
5 3 179 180 183 182
|
||||
5 3 181 182 185 184
|
||||
5 3 182 183 186 185
|
||||
4 3 160 169 172 163
|
||||
4 3 163 172 175 166
|
||||
4 3 169 178 181 172
|
||||
4 3 172 181 184 175
|
||||
6 3 162 165 174 171
|
||||
6 3 165 168 177 174
|
||||
6 3 171 174 183 180
|
||||
6 3 174 177 186 183
|
||||
5 3 160 161 170 169
|
||||
5 3 169 170 179 178
|
||||
5 3 161 162 171 170
|
||||
5 3 170 171 180 179
|
||||
5 3 166 175 176 167
|
||||
5 3 175 184 185 176
|
||||
5 3 167 176 177 168
|
||||
5 3 176 185 186 177
|
||||
|
||||
vertices
|
||||
187
|
||||
3
|
||||
-1 0 0
|
||||
-0.66666667 0 0
|
||||
-0.33333333 0 0
|
||||
0 0 0
|
||||
-1 0.33333333 0
|
||||
-0.66666667 0.33333333 0
|
||||
-0.33333333 0.33333333 0
|
||||
0 0.33333333 0
|
||||
-1 0.66666667 0
|
||||
-0.66666667 0.66666667 0
|
||||
-0.33333333 0.66666667 0
|
||||
0 0.66666667 0
|
||||
-1 1 0
|
||||
-0.66666667 1 0
|
||||
-0.33333333 1 0
|
||||
0 1 0
|
||||
-1 1.3333333 0
|
||||
-0.66666667 1.3333333 0
|
||||
-0.33333333 1.3333333 0
|
||||
0 1.3333333 0
|
||||
-1 1.6666667 0
|
||||
-0.66666667 1.6666667 0
|
||||
-0.33333333 1.6666667 0
|
||||
0 1.6666667 0
|
||||
-1 2 0
|
||||
-0.66666667 2 0
|
||||
-0.33333333 2 0
|
||||
0 2 0
|
||||
-1 2.3333333 0
|
||||
-0.66666667 2.3333333 0
|
||||
-0.33333333 2.3333333 0
|
||||
0 2.3333333 0
|
||||
-1 2.6666667 0
|
||||
-0.66666667 2.6666667 0
|
||||
-0.33333333 2.6666667 0
|
||||
0 2.6666667 0
|
||||
-1 3 0
|
||||
-0.66666667 3 0
|
||||
-0.33333333 3 0
|
||||
0 3 0
|
||||
-1 0 0.33333333
|
||||
-0.66666667 0 0.33333333
|
||||
-0.33333333 0 0.33333333
|
||||
0 0 0.33333333
|
||||
-1 0.33333333 0.33333333
|
||||
-0.66666667 0.33333333 0.33333333
|
||||
-0.33333333 0.33333333 0.33333333
|
||||
0 0.33333333 0.33333333
|
||||
-1 0.66666667 0.33333333
|
||||
-0.66666667 0.66666667 0.33333333
|
||||
-0.33333333 0.66666667 0.33333333
|
||||
0 0.66666667 0.33333333
|
||||
-1 1 0.33333333
|
||||
-0.66666667 1 0.33333333
|
||||
-0.33333333 1 0.33333333
|
||||
0 1 0.33333333
|
||||
-1 1.3333333 0.33333333
|
||||
-0.66666667 1.3333333 0.33333333
|
||||
-0.33333333 1.3333333 0.33333333
|
||||
0 1.3333333 0.33333333
|
||||
-1 1.6666667 0.33333333
|
||||
-0.66666667 1.6666667 0.33333333
|
||||
-0.33333333 1.6666667 0.33333333
|
||||
0 1.6666667 0.33333333
|
||||
-1 2 0.33333333
|
||||
-0.66666667 2 0.33333333
|
||||
-0.33333333 2 0.33333333
|
||||
0 2 0.33333333
|
||||
-1 2.3333333 0.33333333
|
||||
-0.66666667 2.3333333 0.33333333
|
||||
-0.33333333 2.3333333 0.33333333
|
||||
0 2.3333333 0.33333333
|
||||
-1 2.6666667 0.33333333
|
||||
-0.66666667 2.6666667 0.33333333
|
||||
-0.33333333 2.6666667 0.33333333
|
||||
0 2.6666667 0.33333333
|
||||
-1 3 0.33333333
|
||||
-0.66666667 3 0.33333333
|
||||
-0.33333333 3 0.33333333
|
||||
0 3 0.33333333
|
||||
-1 0 0.66666667
|
||||
-0.66666667 0 0.66666667
|
||||
-0.33333333 0 0.66666667
|
||||
0 0 0.66666667
|
||||
-1 0.33333333 0.66666667
|
||||
-0.66666667 0.33333333 0.66666667
|
||||
-0.33333333 0.33333333 0.66666667
|
||||
0 0.33333333 0.66666667
|
||||
-1 0.66666667 0.66666667
|
||||
-0.66666667 0.66666667 0.66666667
|
||||
-0.33333333 0.66666667 0.66666667
|
||||
0 0.66666667 0.66666667
|
||||
-1 1 0.66666667
|
||||
-0.66666667 1 0.66666667
|
||||
-0.33333333 1 0.66666667
|
||||
0 1 0.66666667
|
||||
-1 1.3333333 0.66666667
|
||||
-0.66666667 1.3333333 0.66666667
|
||||
-0.33333333 1.3333333 0.66666667
|
||||
0 1.3333333 0.66666667
|
||||
-1 1.6666667 0.66666667
|
||||
-0.66666667 1.6666667 0.66666667
|
||||
-0.33333333 1.6666667 0.66666667
|
||||
0 1.6666667 0.66666667
|
||||
-1 2 0.66666667
|
||||
-0.66666667 2 0.66666667
|
||||
-0.33333333 2 0.66666667
|
||||
0 2 0.66666667
|
||||
-1 2.3333333 0.66666667
|
||||
-0.66666667 2.3333333 0.66666667
|
||||
-0.33333333 2.3333333 0.66666667
|
||||
0 2.3333333 0.66666667
|
||||
-1 2.6666667 0.66666667
|
||||
-0.66666667 2.6666667 0.66666667
|
||||
-0.33333333 2.6666667 0.66666667
|
||||
0 2.6666667 0.66666667
|
||||
-1 3 0.66666667
|
||||
-0.66666667 3 0.66666667
|
||||
-0.33333333 3 0.66666667
|
||||
0 3 0.66666667
|
||||
-1 0 1
|
||||
-0.66666667 0 1
|
||||
-0.33333333 0 1
|
||||
0 0 1
|
||||
-1 0.33333333 1
|
||||
-0.66666667 0.33333333 1
|
||||
-0.33333333 0.33333333 1
|
||||
0 0.33333333 1
|
||||
-1 0.66666667 1
|
||||
-0.66666667 0.66666667 1
|
||||
-0.33333333 0.66666667 1
|
||||
0 0.66666667 1
|
||||
-1 1 1
|
||||
-0.66666667 1 1
|
||||
-0.33333333 1 1
|
||||
0 1 1
|
||||
-1 1.3333333 1
|
||||
-0.66666667 1.3333333 1
|
||||
-0.33333333 1.3333333 1
|
||||
0 1.3333333 1
|
||||
-1 1.6666667 1
|
||||
-0.66666667 1.6666667 1
|
||||
-0.33333333 1.6666667 1
|
||||
0 1.6666667 1
|
||||
-1 2 1
|
||||
-0.66666667 2 1
|
||||
-0.33333333 2 1
|
||||
0 2 1
|
||||
-1 2.3333333 1
|
||||
-0.66666667 2.3333333 1
|
||||
-0.33333333 2.3333333 1
|
||||
0 2.3333333 1
|
||||
-1 2.6666667 1
|
||||
-0.66666667 2.6666667 1
|
||||
-0.33333333 2.6666667 1
|
||||
0 2.6666667 1
|
||||
-1 3 1
|
||||
-0.66666667 3 1
|
||||
-0.33333333 3 1
|
||||
0 3 1
|
||||
0 1.5 0.25251263
|
||||
0.175 1.5 0.25251263
|
||||
0.35 1.5 0.25251263
|
||||
0 1.6237437 0.37625631
|
||||
0.175 1.6237437 0.37625631
|
||||
0.35 1.6237437 0.37625631
|
||||
0 1.7474874 0.5
|
||||
0.175 1.7474874 0.5
|
||||
0.35 1.7474874 0.5
|
||||
0 1.3762563 0.37625631
|
||||
0.175 1.3762563 0.37625631
|
||||
0.35 1.3762563 0.37625631
|
||||
0 1.5 0.5
|
||||
0.175 1.5 0.5
|
||||
0.35 1.5 0.5
|
||||
0 1.6237437 0.62374369
|
||||
0.175 1.6237437 0.62374369
|
||||
0.35 1.6237437 0.62374369
|
||||
0 1.2525126 0.5
|
||||
0.175 1.2525126 0.5
|
||||
0.35 1.2525126 0.5
|
||||
0 1.3762563 0.62374369
|
||||
0.175 1.3762563 0.62374369
|
||||
0.35 1.3762563 0.62374369
|
||||
0 1.5 0.74748737
|
||||
0.175 1.5 0.74748737
|
||||
0.35 1.5 0.74748737
|
||||
@@ -0,0 +1,453 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
# PYRAMID = 7
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
89
|
||||
1 5 0 1 5 4 40 41 45 44
|
||||
1 5 40 41 45 44 80 81 85 84
|
||||
1 5 44 45 49 48 84 85 89 88
|
||||
1 5 4 5 9 8 44 45 49 48
|
||||
1 5 5 6 10 9 45 46 50 49
|
||||
1 5 45 46 50 49 85 86 90 89
|
||||
1 5 41 42 46 45 81 82 86 85
|
||||
1 5 1 2 6 5 41 42 46 45
|
||||
1 5 2 3 7 6 42 43 47 46
|
||||
1 5 42 43 47 46 82 83 87 86
|
||||
1 5 6 7 11 10 46 47 51 50
|
||||
1 5 46 47 51 50 86 87 91 90
|
||||
1 5 86 87 91 90 126 127 131 130
|
||||
1 5 82 83 87 86 122 123 127 126
|
||||
1 5 81 82 86 85 121 122 126 125
|
||||
1 5 80 81 85 84 120 121 125 124
|
||||
1 5 84 85 89 88 124 125 129 128
|
||||
1 5 85 86 90 89 125 126 130 129
|
||||
1 5 89 90 94 93 129 130 134 133
|
||||
1 5 88 89 93 92 128 129 133 132
|
||||
1 5 92 93 97 96 132 133 137 136
|
||||
1 5 93 94 98 97 133 134 138 137
|
||||
1 5 94 95 99 98 134 135 139 138
|
||||
1 5 54 55 59 58 94 95 99 98
|
||||
1 5 90 91 95 94 130 131 135 134
|
||||
1 5 50 51 55 54 90 91 95 94
|
||||
1 5 10 11 15 14 50 51 55 54
|
||||
1 5 14 15 19 18 54 55 59 58
|
||||
1 5 13 14 18 17 53 54 58 57
|
||||
1 5 53 54 58 57 93 94 98 97
|
||||
1 5 49 50 54 53 89 90 94 93
|
||||
1 5 9 10 14 13 49 50 54 53
|
||||
1 5 8 9 13 12 48 49 53 52
|
||||
1 5 48 49 53 52 88 89 93 92
|
||||
1 5 52 53 57 56 92 93 97 96
|
||||
1 5 12 13 17 16 52 53 57 56
|
||||
1 5 16 17 21 20 56 57 61 60
|
||||
1 5 56 57 61 60 96 97 101 100
|
||||
1 5 57 58 62 61 97 98 102 101
|
||||
1 5 17 18 22 21 57 58 62 61
|
||||
1 5 18 19 23 22 58 59 63 62
|
||||
1 5 58 59 63 62 98 99 103 102
|
||||
1 5 98 99 103 102 138 139 143 142
|
||||
1 5 97 98 102 101 137 138 142 141
|
||||
1 5 96 97 101 100 136 137 141 140
|
||||
1 5 100 101 105 104 140 141 145 144
|
||||
1 5 101 102 106 105 141 142 146 145
|
||||
1 5 102 103 107 106 142 143 147 146
|
||||
1 5 62 63 67 66 102 103 107 106
|
||||
1 5 22 23 27 26 62 63 67 66
|
||||
1 5 21 22 26 25 61 62 66 65
|
||||
1 5 61 62 66 65 101 102 106 105
|
||||
1 5 60 61 65 64 100 101 105 104
|
||||
1 5 20 21 25 24 60 61 65 64
|
||||
1 5 24 25 29 28 64 65 69 68
|
||||
1 5 64 65 69 68 104 105 109 108
|
||||
1 5 68 69 73 72 108 109 113 112
|
||||
1 5 28 29 33 32 68 69 73 72
|
||||
1 5 29 30 34 33 69 70 74 73
|
||||
1 5 69 70 74 73 109 110 114 113
|
||||
1 5 65 66 70 69 105 106 110 109
|
||||
1 5 25 26 30 29 65 66 70 69
|
||||
1 5 26 27 31 30 66 67 71 70
|
||||
1 5 66 67 71 70 106 107 111 110
|
||||
1 5 30 31 35 34 70 71 75 74
|
||||
1 5 70 71 75 74 110 111 115 114
|
||||
1 5 110 111 115 114 150 151 155 154
|
||||
1 5 106 107 111 110 146 147 151 150
|
||||
1 5 105 106 110 109 145 146 150 149
|
||||
1 5 109 110 114 113 149 150 154 153
|
||||
1 5 104 105 109 108 144 145 149 148
|
||||
1 5 108 109 113 112 148 149 153 152
|
||||
1 5 112 113 117 116 152 153 157 156
|
||||
1 5 113 114 118 117 153 154 158 157
|
||||
1 5 114 115 119 118 154 155 159 158
|
||||
1 5 74 75 79 78 114 115 119 118
|
||||
1 5 34 35 39 38 74 75 79 78
|
||||
1 5 33 34 38 37 73 74 78 77
|
||||
1 5 73 74 78 77 113 114 118 117
|
||||
1 5 72 73 77 76 112 113 117 116
|
||||
1 5 32 33 37 36 72 73 77 76
|
||||
2 5 160 161 164 163 169 170 173 172
|
||||
2 5 163 164 167 166 172 173 176 175
|
||||
2 5 172 173 176 175 181 182 185 184
|
||||
2 5 169 170 173 172 178 179 182 181
|
||||
2 5 170 171 174 173 179 180 183 182
|
||||
2 5 173 174 177 176 182 183 186 185
|
||||
2 5 164 165 168 167 173 174 177 176
|
||||
2 5 161 162 165 164 170 171 174 173
|
||||
|
||||
boundary
|
||||
150
|
||||
1 3 0 4 5 1
|
||||
1 3 1 5 6 2
|
||||
1 3 2 6 7 3
|
||||
1 3 4 8 9 5
|
||||
1 3 5 9 10 6
|
||||
1 3 6 10 11 7
|
||||
1 3 8 12 13 9
|
||||
1 3 9 13 14 10
|
||||
1 3 10 14 15 11
|
||||
1 3 12 16 17 13
|
||||
1 3 13 17 18 14
|
||||
1 3 14 18 19 15
|
||||
1 3 16 20 21 17
|
||||
1 3 17 21 22 18
|
||||
1 3 18 22 23 19
|
||||
1 3 20 24 25 21
|
||||
1 3 21 25 26 22
|
||||
1 3 22 26 27 23
|
||||
1 3 24 28 29 25
|
||||
1 3 25 29 30 26
|
||||
1 3 26 30 31 27
|
||||
1 3 28 32 33 29
|
||||
1 3 29 33 34 30
|
||||
1 3 30 34 35 31
|
||||
1 3 32 36 37 33
|
||||
1 3 33 37 38 34
|
||||
1 3 34 38 39 35
|
||||
1 3 120 121 125 124
|
||||
1 3 121 122 126 125
|
||||
1 3 122 123 127 126
|
||||
1 3 124 125 129 128
|
||||
1 3 125 126 130 129
|
||||
1 3 126 127 131 130
|
||||
1 3 128 129 133 132
|
||||
1 3 129 130 134 133
|
||||
1 3 130 131 135 134
|
||||
1 3 132 133 137 136
|
||||
1 3 133 134 138 137
|
||||
1 3 134 135 139 138
|
||||
1 3 136 137 141 140
|
||||
1 3 137 138 142 141
|
||||
1 3 138 139 143 142
|
||||
1 3 140 141 145 144
|
||||
1 3 141 142 146 145
|
||||
1 3 142 143 147 146
|
||||
1 3 144 145 149 148
|
||||
1 3 145 146 150 149
|
||||
1 3 146 147 151 150
|
||||
1 3 148 149 153 152
|
||||
1 3 149 150 154 153
|
||||
1 3 150 151 155 154
|
||||
1 3 152 153 157 156
|
||||
1 3 153 154 158 157
|
||||
1 3 154 155 159 158
|
||||
2 3 0 40 44 4
|
||||
2 3 4 44 48 8
|
||||
2 3 8 48 52 12
|
||||
2 3 12 52 56 16
|
||||
2 3 16 56 60 20
|
||||
2 3 20 60 64 24
|
||||
2 3 24 64 68 28
|
||||
2 3 28 68 72 32
|
||||
2 3 32 72 76 36
|
||||
2 3 40 80 84 44
|
||||
2 3 44 84 88 48
|
||||
2 3 48 88 92 52
|
||||
2 3 52 92 96 56
|
||||
2 3 56 96 100 60
|
||||
2 3 60 100 104 64
|
||||
2 3 64 104 108 68
|
||||
2 3 68 108 112 72
|
||||
2 3 72 112 116 76
|
||||
2 3 80 120 124 84
|
||||
2 3 84 124 128 88
|
||||
2 3 88 128 132 92
|
||||
2 3 92 132 136 96
|
||||
2 3 96 136 140 100
|
||||
2 3 100 140 144 104
|
||||
2 3 104 144 148 108
|
||||
2 3 108 148 152 112
|
||||
2 3 112 152 156 116
|
||||
3 3 3 7 47 43
|
||||
3 3 7 11 51 47
|
||||
3 3 11 15 55 51
|
||||
3 3 15 19 59 55
|
||||
3 3 19 23 63 59
|
||||
3 3 23 27 67 63
|
||||
3 3 27 31 71 67
|
||||
3 3 31 35 75 71
|
||||
3 3 35 39 79 75
|
||||
3 3 43 47 87 83
|
||||
3 3 47 51 91 87
|
||||
3 3 51 55 95 91
|
||||
3 3 55 59 99 95
|
||||
3 3 59 63 103 99
|
||||
3 3 63 67 107 103
|
||||
3 3 67 71 111 107
|
||||
3 3 71 75 115 111
|
||||
3 3 75 79 119 115
|
||||
3 3 83 87 127 123
|
||||
3 3 87 91 131 127
|
||||
3 3 91 95 135 131
|
||||
3 3 95 99 139 135
|
||||
3 3 99 103 143 139
|
||||
3 3 103 107 147 143
|
||||
3 3 107 111 151 147
|
||||
3 3 111 115 155 151
|
||||
3 3 115 119 159 155
|
||||
1 3 0 1 41 40
|
||||
1 3 40 41 81 80
|
||||
1 3 80 81 121 120
|
||||
1 3 1 2 42 41
|
||||
1 3 41 42 82 81
|
||||
1 3 81 82 122 121
|
||||
1 3 2 3 43 42
|
||||
1 3 42 43 83 82
|
||||
1 3 82 83 123 122
|
||||
1 3 36 76 77 37
|
||||
1 3 76 116 117 77
|
||||
1 3 116 156 157 117
|
||||
1 3 37 77 78 38
|
||||
1 3 77 117 118 78
|
||||
1 3 117 157 158 118
|
||||
1 3 38 78 79 39
|
||||
1 3 78 118 119 79
|
||||
1 3 118 158 159 119
|
||||
5 3 160 163 164 161
|
||||
5 3 161 164 165 162
|
||||
5 3 163 166 167 164
|
||||
5 3 164 167 168 165
|
||||
5 3 178 179 182 181
|
||||
5 3 179 180 183 182
|
||||
5 3 181 182 185 184
|
||||
5 3 182 183 186 185
|
||||
4 3 160 169 172 163
|
||||
4 3 163 172 175 166
|
||||
4 3 169 178 181 172
|
||||
4 3 172 181 184 175
|
||||
6 3 162 165 174 171
|
||||
6 3 165 168 177 174
|
||||
6 3 171 174 183 180
|
||||
6 3 174 177 186 183
|
||||
5 3 160 161 170 169
|
||||
5 3 169 170 179 178
|
||||
5 3 161 162 171 170
|
||||
5 3 170 171 180 179
|
||||
5 3 166 175 176 167
|
||||
5 3 175 184 185 176
|
||||
5 3 167 176 177 168
|
||||
5 3 176 185 186 177
|
||||
|
||||
vertices
|
||||
187
|
||||
3
|
||||
-1 0 0
|
||||
-0.66666667 0 0
|
||||
-0.33333333 0 0
|
||||
0 0 0
|
||||
-1 0.33333333 0
|
||||
-0.66666667 0.33333333 0
|
||||
-0.33333333 0.33333333 0
|
||||
0 0.33333333 0
|
||||
-1 0.66666667 0
|
||||
-0.66666667 0.66666667 0
|
||||
-0.33333333 0.66666667 0
|
||||
0 0.66666667 0
|
||||
-1 1 0
|
||||
-0.66666667 1 0
|
||||
-0.33333333 1 0
|
||||
0 1 0
|
||||
-1 1.3333333 0
|
||||
-0.66666667 1.3333333 0
|
||||
-0.33333333 1.3333333 0
|
||||
0 1.3333333 0
|
||||
-1 1.6666667 0
|
||||
-0.66666667 1.6666667 0
|
||||
-0.33333333 1.6666667 0
|
||||
0 1.6666667 0
|
||||
-1 2 0
|
||||
-0.66666667 2 0
|
||||
-0.33333333 2 0
|
||||
0 2 0
|
||||
-1 2.3333333 0
|
||||
-0.66666667 2.3333333 0
|
||||
-0.33333333 2.3333333 0
|
||||
0 2.3333333 0
|
||||
-1 2.6666667 0
|
||||
-0.66666667 2.6666667 0
|
||||
-0.33333333 2.6666667 0
|
||||
0 2.6666667 0
|
||||
-1 3 0
|
||||
-0.66666667 3 0
|
||||
-0.33333333 3 0
|
||||
0 3 0
|
||||
-1 0 0.33333333
|
||||
-0.66666667 0 0.33333333
|
||||
-0.33333333 0 0.33333333
|
||||
0 0 0.33333333
|
||||
-1 0.33333333 0.33333333
|
||||
-0.66666667 0.33333333 0.33333333
|
||||
-0.33333333 0.33333333 0.33333333
|
||||
0 0.33333333 0.33333333
|
||||
-1 0.66666667 0.33333333
|
||||
-0.66666667 0.66666667 0.33333333
|
||||
-0.33333333 0.66666667 0.33333333
|
||||
0 0.66666667 0.33333333
|
||||
-1 1 0.33333333
|
||||
-0.66666667 1 0.33333333
|
||||
-0.33333333 1 0.33333333
|
||||
0 1 0.33333333
|
||||
-1 1.3333333 0.33333333
|
||||
-0.66666667 1.3333333 0.33333333
|
||||
-0.33333333 1.3333333 0.33333333
|
||||
0 1.3333333 0.33333333
|
||||
-1 1.6666667 0.33333333
|
||||
-0.66666667 1.6666667 0.33333333
|
||||
-0.33333333 1.6666667 0.33333333
|
||||
0 1.6666667 0.33333333
|
||||
-1 2 0.33333333
|
||||
-0.66666667 2 0.33333333
|
||||
-0.33333333 2 0.33333333
|
||||
0 2 0.33333333
|
||||
-1 2.3333333 0.33333333
|
||||
-0.66666667 2.3333333 0.33333333
|
||||
-0.33333333 2.3333333 0.33333333
|
||||
0 2.3333333 0.33333333
|
||||
-1 2.6666667 0.33333333
|
||||
-0.66666667 2.6666667 0.33333333
|
||||
-0.33333333 2.6666667 0.33333333
|
||||
0 2.6666667 0.33333333
|
||||
-1 3 0.33333333
|
||||
-0.66666667 3 0.33333333
|
||||
-0.33333333 3 0.33333333
|
||||
0 3 0.33333333
|
||||
-1 0 0.66666667
|
||||
-0.66666667 0 0.66666667
|
||||
-0.33333333 0 0.66666667
|
||||
0 0 0.66666667
|
||||
-1 0.33333333 0.66666667
|
||||
-0.66666667 0.33333333 0.66666667
|
||||
-0.33333333 0.33333333 0.66666667
|
||||
0 0.33333333 0.66666667
|
||||
-1 0.66666667 0.66666667
|
||||
-0.66666667 0.66666667 0.66666667
|
||||
-0.33333333 0.66666667 0.66666667
|
||||
0 0.66666667 0.66666667
|
||||
-1 1 0.66666667
|
||||
-0.66666667 1 0.66666667
|
||||
-0.33333333 1 0.66666667
|
||||
0 1 0.66666667
|
||||
-1 1.3333333 0.66666667
|
||||
-0.66666667 1.3333333 0.66666667
|
||||
-0.33333333 1.3333333 0.66666667
|
||||
0 1.3333333 0.66666667
|
||||
-1 1.6666667 0.66666667
|
||||
-0.66666667 1.6666667 0.66666667
|
||||
-0.33333333 1.6666667 0.66666667
|
||||
0 1.6666667 0.66666667
|
||||
-1 2 0.66666667
|
||||
-0.66666667 2 0.66666667
|
||||
-0.33333333 2 0.66666667
|
||||
0 2 0.66666667
|
||||
-1 2.3333333 0.66666667
|
||||
-0.66666667 2.3333333 0.66666667
|
||||
-0.33333333 2.3333333 0.66666667
|
||||
0 2.3333333 0.66666667
|
||||
-1 2.6666667 0.66666667
|
||||
-0.66666667 2.6666667 0.66666667
|
||||
-0.33333333 2.6666667 0.66666667
|
||||
0 2.6666667 0.66666667
|
||||
-1 3 0.66666667
|
||||
-0.66666667 3 0.66666667
|
||||
-0.33333333 3 0.66666667
|
||||
0 3 0.66666667
|
||||
-1 0 1
|
||||
-0.66666667 0 1
|
||||
-0.33333333 0 1
|
||||
0 0 1
|
||||
-1 0.33333333 1
|
||||
-0.66666667 0.33333333 1
|
||||
-0.33333333 0.33333333 1
|
||||
0 0.33333333 1
|
||||
-1 0.66666667 1
|
||||
-0.66666667 0.66666667 1
|
||||
-0.33333333 0.66666667 1
|
||||
0 0.66666667 1
|
||||
-1 1 1
|
||||
-0.66666667 1 1
|
||||
-0.33333333 1 1
|
||||
0 1 1
|
||||
-1 1.3333333 1
|
||||
-0.66666667 1.3333333 1
|
||||
-0.33333333 1.3333333 1
|
||||
0 1.3333333 1
|
||||
-1 1.6666667 1
|
||||
-0.66666667 1.6666667 1
|
||||
-0.33333333 1.6666667 1
|
||||
0 1.6666667 1
|
||||
-1 2 1
|
||||
-0.66666667 2 1
|
||||
-0.33333333 2 1
|
||||
0 2 1
|
||||
-1 2.3333333 1
|
||||
-0.66666667 2.3333333 1
|
||||
-0.33333333 2.3333333 1
|
||||
0 2.3333333 1
|
||||
-1 2.6666667 1
|
||||
-0.66666667 2.6666667 1
|
||||
-0.33333333 2.6666667 1
|
||||
0 2.6666667 1
|
||||
-1 3 1
|
||||
-0.66666667 3 1
|
||||
-0.33333333 3 1
|
||||
0 3 1
|
||||
0 0.83333333 0.25251263
|
||||
0.175 0.83333333 0.25251263
|
||||
0.35 0.83333333 0.25251263
|
||||
0 0.95707702 0.37625631
|
||||
0.175 0.95707702 0.37625631
|
||||
0.35 0.95707702 0.37625631
|
||||
0 1.0808207 0.5
|
||||
0.175 1.0808207 0.5
|
||||
0.35 1.0808207 0.5
|
||||
0 0.70958965 0.37625631
|
||||
0.175 0.70958965 0.37625631
|
||||
0.35 0.70958965 0.37625631
|
||||
0 0.83333333 0.5
|
||||
0.175 0.83333333 0.5
|
||||
0.35 0.83333333 0.5
|
||||
0 0.95707702 0.62374369
|
||||
0.175 0.95707702 0.62374369
|
||||
0.35 0.95707702 0.62374369
|
||||
0 0.58584596 0.5
|
||||
0.175 0.58584596 0.5
|
||||
0.35 0.58584596 0.5
|
||||
0 0.70958965 0.62374369
|
||||
0.175 0.70958965 0.62374369
|
||||
0.35 0.70958965 0.62374369
|
||||
0 0.83333333 0.74748737
|
||||
0.175 0.83333333 0.74748737
|
||||
0.35 0.83333333 0.74748737
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,231 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
# PYRAMID = 7
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
35
|
||||
1 5 0 1 5 4 16 17 21 20
|
||||
1 5 16 17 21 20 32 33 37 36
|
||||
1 5 17 18 22 21 33 34 38 37
|
||||
1 5 1 2 6 5 17 18 22 21
|
||||
1 5 5 6 10 9 21 22 26 25
|
||||
1 5 21 22 26 25 37 38 42 41
|
||||
1 5 20 21 25 24 36 37 41 40
|
||||
1 5 4 5 9 8 20 21 25 24
|
||||
1 5 8 9 13 12 24 25 29 28
|
||||
1 5 24 25 29 28 40 41 45 44
|
||||
1 5 9 10 14 13 25 26 30 29
|
||||
1 5 25 26 30 29 41 42 46 45
|
||||
1 5 41 42 46 45 57 58 62 61
|
||||
1 5 40 41 45 44 56 57 61 60
|
||||
1 5 36 37 41 40 52 53 57 56
|
||||
1 5 37 38 42 41 53 54 58 57
|
||||
1 5 32 33 37 36 48 49 53 52
|
||||
1 5 33 34 38 37 49 50 54 53
|
||||
1 5 34 35 39 38 50 51 55 54
|
||||
1 5 38 39 43 42 54 55 59 58
|
||||
1 5 42 43 47 46 58 59 63 62
|
||||
1 5 26 27 31 30 42 43 47 46
|
||||
1 5 10 11 15 14 26 27 31 30
|
||||
1 5 6 7 11 10 22 23 27 26
|
||||
1 5 22 23 27 26 38 39 43 42
|
||||
1 5 18 19 23 22 34 35 39 38
|
||||
1 5 2 3 7 6 18 19 23 22
|
||||
1 5 64 65 68 67 73 74 77 76
|
||||
1 5 67 68 71 70 76 77 80 79
|
||||
1 5 76 77 80 79 85 86 89 88
|
||||
1 5 73 74 77 76 82 83 86 85
|
||||
1 5 74 75 78 77 83 84 87 86
|
||||
1 5 77 78 81 80 86 87 90 89
|
||||
1 5 68 69 72 71 77 78 81 80
|
||||
1 5 65 66 69 68 74 75 78 77
|
||||
|
||||
boundary
|
||||
78
|
||||
1 3 0 4 5 1
|
||||
1 3 1 5 6 2
|
||||
1 3 2 6 7 3
|
||||
1 3 4 8 9 5
|
||||
1 3 5 9 10 6
|
||||
1 3 6 10 11 7
|
||||
1 3 8 12 13 9
|
||||
1 3 9 13 14 10
|
||||
1 3 10 14 15 11
|
||||
1 3 48 49 53 52
|
||||
1 3 49 50 54 53
|
||||
1 3 50 51 55 54
|
||||
1 3 52 53 57 56
|
||||
1 3 53 54 58 57
|
||||
1 3 54 55 59 58
|
||||
1 3 56 57 61 60
|
||||
1 3 57 58 62 61
|
||||
1 3 58 59 63 62
|
||||
2 3 0 16 20 4
|
||||
2 3 4 20 24 8
|
||||
2 3 8 24 28 12
|
||||
2 3 16 32 36 20
|
||||
2 3 20 36 40 24
|
||||
2 3 24 40 44 28
|
||||
2 3 32 48 52 36
|
||||
2 3 36 52 56 40
|
||||
2 3 40 56 60 44
|
||||
3 3 3 7 23 19
|
||||
3 3 7 11 27 23
|
||||
3 3 11 15 31 27
|
||||
3 3 19 23 39 35
|
||||
3 3 23 27 43 39
|
||||
3 3 27 31 47 43
|
||||
3 3 35 39 55 51
|
||||
3 3 39 43 59 55
|
||||
3 3 43 47 63 59
|
||||
1 3 0 1 17 16
|
||||
1 3 16 17 33 32
|
||||
1 3 32 33 49 48
|
||||
1 3 1 2 18 17
|
||||
1 3 17 18 34 33
|
||||
1 3 33 34 50 49
|
||||
1 3 2 3 19 18
|
||||
1 3 18 19 35 34
|
||||
1 3 34 35 51 50
|
||||
1 3 12 28 29 13
|
||||
1 3 28 44 45 29
|
||||
1 3 44 60 61 45
|
||||
1 3 13 29 30 14
|
||||
1 3 29 45 46 30
|
||||
1 3 45 61 62 46
|
||||
1 3 14 30 31 15
|
||||
1 3 30 46 47 31
|
||||
1 3 46 62 63 47
|
||||
5 3 64 67 68 65
|
||||
5 3 65 68 69 66
|
||||
5 3 67 70 71 68
|
||||
5 3 68 71 72 69
|
||||
5 3 82 83 86 85
|
||||
5 3 83 84 87 86
|
||||
5 3 85 86 89 88
|
||||
5 3 86 87 90 89
|
||||
4 3 64 73 76 67
|
||||
4 3 67 76 79 70
|
||||
4 3 73 82 85 76
|
||||
4 3 76 85 88 79
|
||||
6 3 66 69 78 75
|
||||
6 3 69 72 81 78
|
||||
6 3 75 78 87 84
|
||||
6 3 78 81 90 87
|
||||
5 3 64 65 74 73
|
||||
5 3 73 74 83 82
|
||||
5 3 65 66 75 74
|
||||
5 3 74 75 84 83
|
||||
5 3 70 79 80 71
|
||||
5 3 79 88 89 80
|
||||
5 3 71 80 81 72
|
||||
5 3 80 89 90 81
|
||||
|
||||
vertices
|
||||
91
|
||||
3
|
||||
-1 0 0
|
||||
-0.66666667 0 0
|
||||
-0.33333333 0 0
|
||||
0 0 0
|
||||
-1 0.33333333 0
|
||||
-0.66666667 0.33333333 0
|
||||
-0.33333333 0.33333333 0
|
||||
0 0.33333333 0
|
||||
-1 0.66666667 0
|
||||
-0.66666667 0.66666667 0
|
||||
-0.33333333 0.66666667 0
|
||||
0 0.66666667 0
|
||||
-1 1 0
|
||||
-0.66666667 1 0
|
||||
-0.33333333 1 0
|
||||
0 1 0
|
||||
-1 0 0.33333333
|
||||
-0.66666667 0 0.33333333
|
||||
-0.33333333 0 0.33333333
|
||||
0 0 0.33333333
|
||||
-1 0.33333333 0.33333333
|
||||
-0.66666667 0.33333333 0.33333333
|
||||
-0.33333333 0.33333333 0.33333333
|
||||
0 0.33333333 0.33333333
|
||||
-1 0.66666667 0.33333333
|
||||
-0.66666667 0.66666667 0.33333333
|
||||
-0.33333333 0.66666667 0.33333333
|
||||
0 0.66666667 0.33333333
|
||||
-1 1 0.33333333
|
||||
-0.66666667 1 0.33333333
|
||||
-0.33333333 1 0.33333333
|
||||
0 1 0.33333333
|
||||
-1 0 0.66666667
|
||||
-0.66666667 0 0.66666667
|
||||
-0.33333333 0 0.66666667
|
||||
0 0 0.66666667
|
||||
-1 0.33333333 0.66666667
|
||||
-0.66666667 0.33333333 0.66666667
|
||||
-0.33333333 0.33333333 0.66666667
|
||||
0 0.33333333 0.66666667
|
||||
-1 0.66666667 0.66666667
|
||||
-0.66666667 0.66666667 0.66666667
|
||||
-0.33333333 0.66666667 0.66666667
|
||||
0 0.66666667 0.66666667
|
||||
-1 1 0.66666667
|
||||
-0.66666667 1 0.66666667
|
||||
-0.33333333 1 0.66666667
|
||||
0 1 0.66666667
|
||||
-1 0 1
|
||||
-0.66666667 0 1
|
||||
-0.33333333 0 1
|
||||
0 0 1
|
||||
-1 0.33333333 1
|
||||
-0.66666667 0.33333333 1
|
||||
-0.33333333 0.33333333 1
|
||||
0 0.33333333 1
|
||||
-1 0.66666667 1
|
||||
-0.66666667 0.66666667 1
|
||||
-0.33333333 0.66666667 1
|
||||
0 0.66666667 1
|
||||
-1 1 1
|
||||
-0.66666667 1 1
|
||||
-0.33333333 1 1
|
||||
0 1 1
|
||||
0 0.5 0.14644661
|
||||
0.25 0.5 0.14644661
|
||||
0.5 0.5 0.14644661
|
||||
0 0.6767767 0.3232233
|
||||
0.25 0.6767767 0.3232233
|
||||
0.5 0.6767767 0.3232233
|
||||
0 0.85355339 0.5
|
||||
0.25 0.85355339 0.5
|
||||
0.5 0.85355339 0.5
|
||||
0 0.3232233 0.3232233
|
||||
0.25 0.3232233 0.3232233
|
||||
0.5 0.3232233 0.3232233
|
||||
0 0.5 0.5
|
||||
0.25 0.5 0.5
|
||||
0.5 0.5 0.5
|
||||
0 0.6767767 0.6767767
|
||||
0.25 0.6767767 0.6767767
|
||||
0.5 0.6767767 0.6767767
|
||||
0 0.14644661 0.5
|
||||
0.25 0.14644661 0.5
|
||||
0.5 0.14644661 0.5
|
||||
0 0.3232233 0.6767767
|
||||
0.25 0.3232233 0.6767767
|
||||
0.5 0.3232233 0.6767767
|
||||
0 0.5 0.85355339
|
||||
0.25 0.5 0.85355339
|
||||
0.5 0.5 0.85355339
|
||||
@@ -0,0 +1,663 @@
|
||||
#include "parproblems.hpp"
|
||||
|
||||
void ParElasticityProblem::Init()
|
||||
{
|
||||
int dim = pmesh->Dimension();
|
||||
fec = new H1_FECollection(order,dim);
|
||||
fes = new ParFiniteElementSpace(pmesh,fec,dim,Ordering::byVDIM);
|
||||
ndofs = fes->GetVSize();
|
||||
ntdofs = fes->GetTrueVSize();
|
||||
gndofs = fes->GlobalTrueVSize();
|
||||
pmesh->SetNodalFESpace(fes);
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(pmesh->bdr_attributes.Max());
|
||||
}
|
||||
ess_bdr = 0;
|
||||
Array<int> ess_tdof_list_temp;
|
||||
for (int i = 0; i < ess_bdr_attr.Size(); i++ )
|
||||
{
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 1;
|
||||
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list_temp,ess_bdr_attr_comp[i]);
|
||||
ess_tdof_list.Append(ess_tdof_list_temp);
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 0;
|
||||
}
|
||||
// Solution GridFunction
|
||||
x.SetSpace(fes); x = 0.0;
|
||||
// RHS
|
||||
b = new ParLinearForm(fes);
|
||||
|
||||
// Elasticity operator
|
||||
lambda.SetSize(pmesh->attributes.Max()); lambda = 57.6923076923;
|
||||
mu.SetSize(pmesh->attributes.Max()); mu = 38.4615384615;
|
||||
|
||||
lambda_cf.UpdateConstants(lambda);
|
||||
mu_cf.UpdateConstants(mu);
|
||||
|
||||
a = new ParBilinearForm(fes);
|
||||
a->AddDomainIntegrator(new ElasticityIntegrator(lambda_cf,mu_cf));
|
||||
}
|
||||
|
||||
void ParElasticityProblem::FormLinearSystem()
|
||||
{
|
||||
if (!formsystem)
|
||||
{
|
||||
formsystem = true;
|
||||
b->Assemble();
|
||||
a->Assemble();
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
}
|
||||
}
|
||||
|
||||
void ParElasticityProblem::UpdateLinearSystem()
|
||||
{
|
||||
UpdateStep();
|
||||
FormLinearSystem();
|
||||
}
|
||||
|
||||
// #ifdef MFEM_USE_TRIBOL
|
||||
|
||||
|
||||
|
||||
ParContactProblem::ParContactProblem(ParElasticityProblem * prob_,
|
||||
const std::set<int> & mortar_attrs_,
|
||||
const std::set<int> & nonmortar_attrs_,
|
||||
ParGridFunction * coords_,
|
||||
bool doublepass_)
|
||||
: prob(prob_), mortar_attrs(mortar_attrs_), nonmortar_attrs(nonmortar_attrs_), doublepass(doublepass_), coords(coords_)
|
||||
{
|
||||
ParMesh* pmesh = prob->GetMesh();
|
||||
comm = pmesh->GetComm();
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
MPI_Comm_size(comm, &numprocs);
|
||||
|
||||
dim = pmesh->Dimension();
|
||||
nodes0.SetSpace(pmesh->GetNodes()->FESpace());
|
||||
nodes0 = *pmesh->GetNodes();
|
||||
nodes1 = pmesh->GetNodes();
|
||||
|
||||
prob->FormLinearSystem();
|
||||
K = new HypreParMatrix(prob->GetOperator());
|
||||
B = new Vector(prob->GetRHS());
|
||||
if (doublepass)
|
||||
{
|
||||
SetupTribolDoublePass();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupTribol();
|
||||
}
|
||||
}
|
||||
|
||||
void ParContactProblem::SetupTribol()
|
||||
{
|
||||
axom::slic::SimpleLogger logger;
|
||||
axom::slic::setIsRoot(mfem::Mpi::Root());
|
||||
|
||||
// Initialize Tribol contact library
|
||||
tribol::initialize(3, MPI_COMM_WORLD);
|
||||
|
||||
int coupling_scheme_id = 0;
|
||||
int mesh1_id = 0;
|
||||
int mesh2_id = 1;
|
||||
vfes = prob->GetFESpace();
|
||||
ParMesh * pmesh = prob->GetMesh();
|
||||
tribol::registerMfemCouplingScheme(
|
||||
coupling_scheme_id, mesh1_id, mesh2_id,
|
||||
*pmesh, *coords, mortar_attrs, nonmortar_attrs,
|
||||
tribol::SURFACE_TO_SURFACE,
|
||||
tribol::NO_SLIDING,
|
||||
tribol::SINGLE_MORTAR,
|
||||
tribol::FRICTIONLESS,
|
||||
tribol::LAGRANGE_MULTIPLIER,
|
||||
tribol::BINNING_GRID
|
||||
);
|
||||
|
||||
// Access Tribol's pressure grid function (on the contact surface)
|
||||
auto& pressure = tribol::getMfemPressure(coupling_scheme_id);
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of pressure unknowns: " <<
|
||||
pressure.ParFESpace()->GlobalTrueVSize() << std::endl;
|
||||
}
|
||||
|
||||
// Set Tribol options for Lagrange multiplier enforcement
|
||||
tribol::setLagrangeMultiplierOptions(
|
||||
coupling_scheme_id,
|
||||
tribol::ImplicitEvalMode::MORTAR_RESIDUAL_JACOBIAN
|
||||
);
|
||||
|
||||
// Update contact mesh decomposition
|
||||
tribol::updateMfemParallelDecomposition();
|
||||
|
||||
// Update contact gaps, forces, and tangent stiffness
|
||||
int cycle = 1; // pseudo cycle
|
||||
double t = 1.0; // pseudo time
|
||||
double dt = 1.0; // pseudo dt
|
||||
tribol::update(cycle, t, dt);
|
||||
|
||||
// Return contact contribution to the tangent stiffness matrix
|
||||
auto A_blk = tribol::getMfemBlockJacobian(coupling_scheme_id);
|
||||
|
||||
HypreParMatrix * Mfull = (HypreParMatrix *)(&A_blk->GetBlock(1,0));
|
||||
Mfull->EliminateCols(prob->GetEssentialDofs());
|
||||
int h = Mfull->Height();
|
||||
SparseMatrix merged;
|
||||
Mfull->MergeDiagAndOffd(merged);
|
||||
Array<int> nonzero_rows;
|
||||
for (int i = 0; i<h; i++)
|
||||
{
|
||||
if (!merged.RowIsEmpty(i))
|
||||
{
|
||||
nonzero_rows.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hnew = nonzero_rows.Size();
|
||||
SparseMatrix P(hnew,h);
|
||||
|
||||
for (int i = 0; i<hnew; i++)
|
||||
{
|
||||
int col = nonzero_rows[i];
|
||||
P.Set(i,col,1.0);
|
||||
}
|
||||
P.Finalize();
|
||||
|
||||
SparseMatrix * reduced_merged = Mult(P,merged);
|
||||
|
||||
int rows[2];
|
||||
int cols[2];
|
||||
cols[0] = Mfull->ColPart()[0];
|
||||
cols[1] = Mfull->ColPart()[1];
|
||||
int nrows = reduced_merged->Height();
|
||||
|
||||
int row_offset;
|
||||
MPI_Scan(&nrows,&row_offset,1,MPI_INT,MPI_SUM,Mfull->GetComm());
|
||||
|
||||
row_offset-=nrows;
|
||||
rows[0] = row_offset;
|
||||
rows[1] = row_offset+nrows;
|
||||
int glob_nrows;
|
||||
MPI_Allreduce(&nrows, &glob_nrows,1,MPI_INT,MPI_SUM,Mfull->GetComm());
|
||||
|
||||
|
||||
int glob_ncols = reduced_merged->Width();
|
||||
M = new HypreParMatrix(Mfull->GetComm(), nrows, glob_nrows,
|
||||
glob_ncols, reduced_merged->GetI(), reduced_merged->GetJ(),
|
||||
reduced_merged->GetData(), rows,cols);
|
||||
|
||||
Vector gap;
|
||||
tribol::getMfemGap(coupling_scheme_id, gap);
|
||||
auto& P_submesh = *pressure.ParFESpace()->GetProlongationMatrix();
|
||||
Vector gap_true;
|
||||
gap_true.SetSize(P_submesh.Width());
|
||||
P_submesh.MultTranspose(gap,gap_true);
|
||||
|
||||
gapv.SetSize(nrows);
|
||||
for (int i = 0; i<nrows; i++)
|
||||
{
|
||||
gapv[i] = gap_true[nonzero_rows[i]];
|
||||
}
|
||||
|
||||
constraints_starts.SetSize(2);
|
||||
constraints_starts[0] = M->RowPart()[0];
|
||||
constraints_starts[1] = M->RowPart()[1];
|
||||
|
||||
// find elast dofs in contact;
|
||||
HypreParMatrix * Jt = (HypreParMatrix *)(&A_blk->GetBlock(0,1));
|
||||
Jt->EliminateRows(prob->GetEssentialDofs());
|
||||
|
||||
int hJt = Jt->Height();
|
||||
SparseMatrix mergedJt;
|
||||
Jt->MergeDiagAndOffd(mergedJt);
|
||||
|
||||
Array<int> nonzerorows;
|
||||
Array<int> zerorows;
|
||||
for (int i = 0; i<hJt; i++)
|
||||
{
|
||||
if (!mergedJt.RowIsEmpty(i))
|
||||
{
|
||||
nonzerorows.Append(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
zerorows.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hb = nonzerorows.Size();
|
||||
SparseMatrix Pbt(hb,K->GetGlobalNumCols());
|
||||
|
||||
for (int i = 0; i<hb; i++)
|
||||
{
|
||||
int col = nonzerorows[i]+prob->GetFESpace()->GetMyTDofOffset();
|
||||
Pbt.Set(i,col,1.0);
|
||||
}
|
||||
Pbt.Finalize();
|
||||
|
||||
int rows_b[2];
|
||||
int cols_b[2];
|
||||
int nrows_b = Pbt.Height();
|
||||
|
||||
int row_offset_b;
|
||||
MPI_Scan(&nrows_b,&row_offset_b,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
row_offset_b-=nrows_b;
|
||||
rows_b[0] = row_offset_b;
|
||||
rows_b[1] = row_offset_b+nrows_b;
|
||||
cols_b[0] = K->ColPart()[0];
|
||||
cols_b[1] = K->ColPart()[1];
|
||||
int glob_nrows_b;
|
||||
int glob_ncols_b = K->GetGlobalNumCols();
|
||||
MPI_Allreduce(&nrows_b, &glob_nrows_b,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
HypreParMatrix * P_bt = new HypreParMatrix(MPI_COMM_WORLD, nrows_b, glob_nrows_b,
|
||||
glob_ncols_b, Pbt.GetI(), Pbt.GetJ(),
|
||||
Pbt.GetData(), rows_b,cols_b);
|
||||
|
||||
Pb = P_bt->Transpose();
|
||||
delete P_bt;
|
||||
|
||||
int hi = zerorows.Size();
|
||||
SparseMatrix Pit(hi,K->GetGlobalNumCols());
|
||||
|
||||
for (int i = 0; i<hi; i++)
|
||||
{
|
||||
int col = zerorows[i]+prob->GetFESpace()->GetMyTDofOffset();
|
||||
Pit.Set(i,col,1.0);
|
||||
}
|
||||
Pit.Finalize();
|
||||
|
||||
int rows_i[2];
|
||||
int cols_i[2];
|
||||
int nrows_i = Pit.Height();
|
||||
|
||||
int row_offset_i;
|
||||
MPI_Scan(&nrows_i,&row_offset_i,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
row_offset_i-=nrows_i;
|
||||
rows_i[0] = row_offset_i;
|
||||
rows_i[1] = row_offset_i+nrows_i;
|
||||
cols_i[0] = K->ColPart()[0];
|
||||
cols_i[1] = K->ColPart()[1];
|
||||
int glob_nrows_i;
|
||||
int glob_ncols_i = K->GetGlobalNumCols();
|
||||
MPI_Allreduce(&nrows_i, &glob_nrows_i,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
HypreParMatrix * P_it = new HypreParMatrix(MPI_COMM_WORLD, nrows_i, glob_nrows_i,
|
||||
glob_ncols_i, Pit.GetI(), Pit.GetJ(),
|
||||
Pit.GetData(), rows_i,cols_i);
|
||||
|
||||
Pi = P_it->Transpose();
|
||||
delete P_it;
|
||||
}
|
||||
|
||||
void ParContactProblem::SetupTribolDoublePass()
|
||||
{
|
||||
axom::slic::SimpleLogger logger1;
|
||||
axom::slic::setIsRoot(mfem::Mpi::Root());
|
||||
|
||||
// Initialize Tribol contact library
|
||||
tribol::initialize(3, MPI_COMM_WORLD);
|
||||
|
||||
int coupling_scheme_id1 = 0;
|
||||
int mesh1_id1 = 0;
|
||||
int mesh2_id1 = 1;
|
||||
vfes = prob->GetFESpace();
|
||||
ParGridFunction * coords1 = new ParGridFunction(vfes);
|
||||
ParMesh * pmesh1 = prob->GetMesh();
|
||||
pmesh1->SetNodalGridFunction(coords1);
|
||||
tribol::registerMfemCouplingScheme(
|
||||
coupling_scheme_id1, mesh1_id1, mesh2_id1,
|
||||
*pmesh1, *coords1, mortar_attrs, nonmortar_attrs,
|
||||
tribol::SURFACE_TO_SURFACE,
|
||||
tribol::NO_SLIDING,
|
||||
tribol::SINGLE_MORTAR,
|
||||
tribol::FRICTIONLESS,
|
||||
tribol::LAGRANGE_MULTIPLIER,
|
||||
tribol::BINNING_GRID
|
||||
);
|
||||
|
||||
// Access Tribol's pressure grid function (on the contact surface)
|
||||
auto& pressure1 = tribol::getMfemPressure(coupling_scheme_id1);
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of pressure unknowns: " <<
|
||||
pressure1.ParFESpace()->GlobalTrueVSize() << std::endl;
|
||||
}
|
||||
|
||||
// Set Tribol options for Lagrange multiplier enforcement
|
||||
tribol::setLagrangeMultiplierOptions(
|
||||
coupling_scheme_id1,
|
||||
tribol::ImplicitEvalMode::MORTAR_RESIDUAL_JACOBIAN
|
||||
);
|
||||
|
||||
// Update contact mesh decomposition
|
||||
tribol::updateMfemParallelDecomposition();
|
||||
|
||||
// Update contact gaps, forces, and tangent stiffness
|
||||
int cycle1 = 1; // pseudo cycle
|
||||
double t1 = 1.0; // pseudo time
|
||||
double dt1 = 1.0; // pseudo dt
|
||||
tribol::update(cycle1, t1, dt1);
|
||||
|
||||
// Return contact contribution to the tangent stiffness matrix
|
||||
auto A_blk1 = tribol::getMfemBlockJacobian(coupling_scheme_id1);
|
||||
|
||||
HypreParMatrix * Mfull1 = (HypreParMatrix *)(&A_blk1->GetBlock(1,0));
|
||||
Mfull1->EliminateCols(prob->GetEssentialDofs());
|
||||
int h1 = Mfull1->Height();
|
||||
SparseMatrix merged1;
|
||||
Mfull1->MergeDiagAndOffd(merged1);
|
||||
Array<int> nonzero_rows1;
|
||||
for (int i = 0; i<h1; i++)
|
||||
{
|
||||
if (!merged1.RowIsEmpty(i))
|
||||
{
|
||||
nonzero_rows1.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hnew1 = nonzero_rows1.Size();
|
||||
SparseMatrix P1(hnew1,h1);
|
||||
|
||||
for (int i = 0; i<hnew1; i++)
|
||||
{
|
||||
int col = nonzero_rows1[i];
|
||||
P1.Set(i,col,1.0);
|
||||
}
|
||||
P1.Finalize();
|
||||
|
||||
SparseMatrix * reduced_merged1 = Mult(P1,merged1);
|
||||
|
||||
int rows1[2];
|
||||
int cols1[2];
|
||||
cols1[0] = Mfull1->ColPart()[0];
|
||||
cols1[1] = Mfull1->ColPart()[1];
|
||||
int nrows1 = reduced_merged1->Height();
|
||||
|
||||
int row_offset1;
|
||||
MPI_Scan(&nrows1,&row_offset1,1,MPI_INT,MPI_SUM,Mfull1->GetComm());
|
||||
|
||||
row_offset1-=nrows1;
|
||||
rows1[0] = row_offset1;
|
||||
rows1[1] = row_offset1+nrows1;
|
||||
int glob_nrows1;
|
||||
MPI_Allreduce(&nrows1, &glob_nrows1,1,MPI_INT,MPI_SUM,Mfull1->GetComm());
|
||||
|
||||
|
||||
int glob_ncols1 = reduced_merged1->Width();
|
||||
HypreParMatrix * M1 = new HypreParMatrix(Mfull1->GetComm(), nrows1, glob_nrows1,
|
||||
glob_ncols1, reduced_merged1->GetI(), reduced_merged1->GetJ(),
|
||||
reduced_merged1->GetData(), rows1,cols1);
|
||||
|
||||
Vector gap1;
|
||||
tribol::getMfemGap(coupling_scheme_id1, gap1);
|
||||
auto& P_submesh1 = *pressure1.ParFESpace()->GetProlongationMatrix();
|
||||
Vector gap_true1;
|
||||
gap_true1.SetSize(P_submesh1.Width());
|
||||
P_submesh1.MultTranspose(gap1,gap_true1);
|
||||
|
||||
tribol::finalize();
|
||||
|
||||
// ------------------------------
|
||||
// second pass
|
||||
// ------------------------------
|
||||
// Initialize Tribol contact library
|
||||
tribol::initialize(3, MPI_COMM_WORLD);
|
||||
|
||||
int coupling_scheme_id2 = 0;
|
||||
int mesh1_id2 = 0;
|
||||
int mesh2_id2 = 1;
|
||||
ParGridFunction * coords2 = new ParGridFunction(vfes);
|
||||
ParMesh * pmesh2 = prob->GetMesh();
|
||||
pmesh2->SetNodalGridFunction(coords2);
|
||||
tribol::registerMfemCouplingScheme(
|
||||
coupling_scheme_id2, mesh1_id2, mesh2_id2,
|
||||
*pmesh2, *coords2, nonmortar_attrs, mortar_attrs,
|
||||
tribol::SURFACE_TO_SURFACE,
|
||||
tribol::NO_SLIDING,
|
||||
tribol::SINGLE_MORTAR,
|
||||
tribol::FRICTIONLESS,
|
||||
tribol::LAGRANGE_MULTIPLIER,
|
||||
tribol::BINNING_GRID
|
||||
);
|
||||
|
||||
// Access Tribol's pressure grid function (on the contact surface)
|
||||
auto& pressure2 = tribol::getMfemPressure(coupling_scheme_id2);
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of pressure unknowns: " <<
|
||||
pressure2.ParFESpace()->GlobalTrueVSize() << std::endl;
|
||||
}
|
||||
|
||||
// Set Tribol options for Lagrange multiplier enforcement
|
||||
tribol::setLagrangeMultiplierOptions(
|
||||
coupling_scheme_id2,
|
||||
tribol::ImplicitEvalMode::MORTAR_RESIDUAL_JACOBIAN
|
||||
);
|
||||
|
||||
// Update contact mesh decomposition
|
||||
tribol::updateMfemParallelDecomposition();
|
||||
|
||||
// Update contact gaps, forces, and tangent stiffness
|
||||
int cycle2 = 1; // pseudo cycle
|
||||
double t2 = 1.0; // pseudo time
|
||||
double dt2 = 1.0; // pseudo dt
|
||||
tribol::update(cycle2, t2, dt2);
|
||||
|
||||
// Return contact contribution to the tangent stiffness matrix
|
||||
auto A_blk2 = tribol::getMfemBlockJacobian(coupling_scheme_id2);
|
||||
|
||||
HypreParMatrix * Mfull2 = (HypreParMatrix *)(&A_blk2->GetBlock(1,0));
|
||||
Mfull2->EliminateCols(prob->GetEssentialDofs());
|
||||
int h2 = Mfull2->Height();
|
||||
SparseMatrix merged2;
|
||||
Mfull2->MergeDiagAndOffd(merged2);
|
||||
Array<int> nonzero_rows2;
|
||||
for (int i = 0; i<h2; i++)
|
||||
{
|
||||
if (!merged2.RowIsEmpty(i))
|
||||
{
|
||||
nonzero_rows2.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hnew2 = nonzero_rows2.Size();
|
||||
SparseMatrix P2(hnew2,h2);
|
||||
|
||||
for (int i = 0; i<hnew2; i++)
|
||||
{
|
||||
int col = nonzero_rows2[i];
|
||||
P2.Set(i,col,1.0);
|
||||
}
|
||||
P2.Finalize();
|
||||
|
||||
SparseMatrix * reduced_merged2 = Mult(P2,merged2);
|
||||
|
||||
int rows2[2];
|
||||
int cols2[2];
|
||||
cols2[0] = Mfull2->ColPart()[0];
|
||||
cols2[1] = Mfull2->ColPart()[1];
|
||||
int nrows2 = reduced_merged2->Height();
|
||||
|
||||
int row_offset2;
|
||||
MPI_Scan(&nrows2,&row_offset2,1,MPI_INT,MPI_SUM,Mfull2->GetComm());
|
||||
|
||||
row_offset2-=nrows2;
|
||||
rows2[0] = row_offset2;
|
||||
rows2[1] = row_offset2+nrows2;
|
||||
int glob_nrows2;
|
||||
MPI_Allreduce(&nrows2, &glob_nrows2,1,MPI_INT,MPI_SUM,Mfull2->GetComm());
|
||||
|
||||
|
||||
int glob_ncols2 = reduced_merged2->Width();
|
||||
HypreParMatrix * M2 = new HypreParMatrix(Mfull2->GetComm(), nrows2, glob_nrows2,
|
||||
glob_ncols2, reduced_merged2->GetI(), reduced_merged2->GetJ(),
|
||||
reduced_merged2->GetData(), rows2,cols2);
|
||||
|
||||
Vector gap2;
|
||||
tribol::getMfemGap(coupling_scheme_id2, gap2);
|
||||
auto& P_submesh2 = *pressure2.ParFESpace()->GetProlongationMatrix();
|
||||
Vector gap_true2;
|
||||
gap_true2.SetSize(P_submesh2.Width());
|
||||
P_submesh2.MultTranspose(gap2,gap_true2);
|
||||
|
||||
tribol::finalize();
|
||||
|
||||
|
||||
gapv.SetSize(nrows1+nrows2);
|
||||
for (int i = 0; i<nrows1; i++)
|
||||
{
|
||||
gapv[i] = gap_true1[nonzero_rows1[i]];
|
||||
}
|
||||
for (int i = 0; i<nrows2; i++)
|
||||
{
|
||||
gapv[nrows1+i] = gap_true2[nonzero_rows2[i]];
|
||||
}
|
||||
|
||||
Array2D<HypreParMatrix *> A_array(2,1);
|
||||
A_array(0,0) = M1;
|
||||
A_array(1,0) = M2;
|
||||
|
||||
M = HypreParMatrixFromBlocks(A_array);
|
||||
|
||||
constraints_starts.SetSize(2);
|
||||
constraints_starts[0] = M->RowPart()[0];
|
||||
constraints_starts[1] = M->RowPart()[1];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
double ParContactProblem::E(const Vector & d)
|
||||
{
|
||||
Vector kd(K->Height());
|
||||
K->Mult(d,kd);
|
||||
return 0.5 * InnerProduct(comm,d, kd) - InnerProduct(comm,d, *B);
|
||||
}
|
||||
|
||||
void ParContactProblem::DdE(const Vector &d, Vector &gradE)
|
||||
{
|
||||
gradE.SetSize(K->Height());
|
||||
K->Mult(d, gradE);
|
||||
gradE.Add(-1.0, *B);
|
||||
}
|
||||
|
||||
HypreParMatrix* ParContactProblem::DddE(const Vector &d)
|
||||
{
|
||||
return K;
|
||||
}
|
||||
|
||||
void ParContactProblem::g(const Vector &d, Vector &gd)
|
||||
{
|
||||
gd = GetGapFunction();
|
||||
}
|
||||
|
||||
HypreParMatrix* ParContactProblem::Ddg(const Vector &d)
|
||||
{
|
||||
return GetJacobian();
|
||||
}
|
||||
|
||||
HypreParMatrix* ParContactProblem::lDddg(const Vector &d, const Vector &l)
|
||||
{
|
||||
return nullptr; // for now
|
||||
}
|
||||
|
||||
|
||||
QPOptParContactProblem::QPOptParContactProblem(ParContactProblem * problem_, Vector &xref_)
|
||||
: problem(problem_)
|
||||
{
|
||||
dimU = problem->GetNumDofs();
|
||||
dimM = problem->GetNumConstraints();
|
||||
dimC = problem->GetNumConstraints();
|
||||
ml.SetSize(dimM); ml = 0.0;
|
||||
Vector negone(dimM); negone = -1.0;
|
||||
SparseMatrix diag(negone);
|
||||
|
||||
xref.SetSize(xref_.Size());
|
||||
xref.Set(1.0, xref_);
|
||||
|
||||
int gsize = problem->GetGlobalNumConstraints();
|
||||
int * rows = problem->GetConstraintsStarts().GetData();
|
||||
|
||||
NegId = new HypreParMatrix(problem->GetComm(),gsize, rows,&diag);
|
||||
HypreStealOwnership(*NegId, diag);
|
||||
}
|
||||
|
||||
int QPOptParContactProblem::GetDimU() { return dimU; }
|
||||
|
||||
int QPOptParContactProblem::GetDimM() { return dimM; }
|
||||
|
||||
int QPOptParContactProblem::GetDimC() { return dimC; }
|
||||
|
||||
Vector & QPOptParContactProblem::Getml() { return ml; }
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Duuf(const BlockVector & x)
|
||||
{
|
||||
return problem->DddE(x.GetBlock(0));
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dumf(const BlockVector & x)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dmuf(const BlockVector & x)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dmmf(const BlockVector & x)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Duc(const BlockVector & x)
|
||||
{
|
||||
return problem->Ddg(x.GetBlock(0));
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dmc(const BlockVector & x)
|
||||
{
|
||||
return NegId;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::lDuuc(const BlockVector & x, const Vector & l)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void QPOptParContactProblem::c(const BlockVector &x, Vector & y)
|
||||
{
|
||||
Vector g0; // g(dref)
|
||||
problem->g(x.GetBlock(0), g0); // gap function
|
||||
|
||||
// temp = d - xref (expansion)
|
||||
Vector temp(x.GetBlock(0).Size()); temp = 0.0;
|
||||
temp.Set(1.0, x.GetBlock(0));
|
||||
temp.Add(-1.0, xref); // displacement at previous time step
|
||||
|
||||
problem->GetJacobian()->Mult(temp, y); // J * (d - xref)
|
||||
y.Add(1.0, g0); // J * (d - xref) + g0
|
||||
y.Add(-1.0, x.GetBlock(1)); // J * (d - xref) + g0 - s
|
||||
}
|
||||
|
||||
double QPOptParContactProblem::CalcObjective(const BlockVector & x)
|
||||
{
|
||||
return problem->E(x.GetBlock(0));
|
||||
}
|
||||
|
||||
void QPOptParContactProblem::CalcObjectiveGrad(const BlockVector & x, BlockVector & y)
|
||||
{
|
||||
problem->DdE(x.GetBlock(0), y.GetBlock(0));
|
||||
y.GetBlock(1) = 0.0;
|
||||
}
|
||||
|
||||
QPOptParContactProblem::~QPOptParContactProblem()
|
||||
{
|
||||
delete NegId;
|
||||
}
|
||||
|
||||
// #endif
|
||||
@@ -0,0 +1,335 @@
|
||||
|
||||
#include "parproblems_util.hpp"
|
||||
|
||||
class ParElasticityProblem
|
||||
{
|
||||
private:
|
||||
MPI_Comm comm;
|
||||
bool formsystem = false;
|
||||
ParMesh * pmesh = nullptr;
|
||||
Array<int> ess_bdr_attr, ess_bdr_attr_comp;
|
||||
int order;
|
||||
int ndofs;
|
||||
int ntdofs;
|
||||
int gndofs;
|
||||
FiniteElementCollection * fec = nullptr;
|
||||
ParFiniteElementSpace * fes = nullptr;
|
||||
Vector lambda, mu;
|
||||
PWConstCoefficient lambda_cf, mu_cf;
|
||||
Array<int> ess_bdr, ess_tdof_list;
|
||||
ParBilinearForm * a = nullptr;
|
||||
ParLinearForm * b = nullptr;
|
||||
ParGridFunction x;
|
||||
HypreParMatrix A;
|
||||
Vector B,X;
|
||||
ConstantCoefficient pressure_cf;
|
||||
VectorArrayCoefficient * bf = nullptr;
|
||||
void Init();
|
||||
bool own_mesh;
|
||||
public:
|
||||
ParElasticityProblem(MPI_Comm comm_, const char *mesh_file , int sref, int pref,
|
||||
Array<int> & ess_bdr_attr_, Array<int> & ess_bdr_attr_comp_,
|
||||
int order_ = 1 )
|
||||
: comm(comm_), ess_bdr_attr(ess_bdr_attr_),ess_bdr_attr_comp(ess_bdr_attr_comp_), order(order_)
|
||||
{
|
||||
own_mesh = true;
|
||||
Mesh * mesh = new Mesh(mesh_file,1,1);
|
||||
for (int i = 0; i<sref; i++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
pmesh = new ParMesh(comm,*mesh);
|
||||
MFEM_VERIFY(pmesh->GetNE(), "ParElasticityProblem::Empty partition");
|
||||
delete mesh;
|
||||
for (int i = 0; i<pref; i++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
Init();
|
||||
}
|
||||
|
||||
ParElasticityProblem(ParMesh * pmesh_, Array<int> & ess_bdr_attr_, Array<int> & ess_bdr_attr_comp_, int order_ = 1)
|
||||
: pmesh(pmesh_), ess_bdr_attr(ess_bdr_attr_), ess_bdr_attr_comp(ess_bdr_attr_comp_), order(order_)
|
||||
{
|
||||
own_mesh = false;
|
||||
comm = pmesh->GetComm();
|
||||
Init();
|
||||
}
|
||||
|
||||
ParMesh * GetMesh() { return pmesh; }
|
||||
ParFiniteElementSpace * GetFESpace() { return fes; }
|
||||
FiniteElementCollection * GetFECol() { return fec; }
|
||||
int GetNumDofs() { return ndofs; }
|
||||
int GetNumTDofs() { return ntdofs; }
|
||||
int GetGlobalNumDofs() { return gndofs; }
|
||||
HypreParMatrix & GetOperator()
|
||||
{
|
||||
MFEM_VERIFY(formsystem, "System not formed yet. Call FormLinearSystem()");
|
||||
return A;
|
||||
}
|
||||
Vector & GetRHS()
|
||||
{
|
||||
MFEM_VERIFY(formsystem, "System not formed yet. Call FormLinearSystem()");
|
||||
return B;
|
||||
}
|
||||
|
||||
void SetLambda(const Vector & lambda_)
|
||||
{
|
||||
lambda = lambda_;
|
||||
lambda_cf.UpdateConstants(lambda);
|
||||
}
|
||||
void SetMu(const Vector & mu_)
|
||||
{
|
||||
mu = mu_;
|
||||
mu_cf.UpdateConstants(mu);
|
||||
}
|
||||
|
||||
void SetNeumanPressureData(ConstantCoefficient &f, Array<int> & bdr_marker)
|
||||
{
|
||||
pressure_cf.constant = f.constant;
|
||||
b->AddBoundaryIntegrator(new VectorBoundaryFluxLFIntegrator(pressure_cf),bdr_marker);
|
||||
}
|
||||
|
||||
void SetNeumanData(int comp, int bdrattr, double value)
|
||||
{
|
||||
int dim = pmesh->Dimension();
|
||||
bf = new VectorArrayCoefficient(dim);
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
if (i == comp)
|
||||
{
|
||||
Vector pull_force(pmesh->bdr_attributes.Max());
|
||||
pull_force = 0.0;
|
||||
pull_force(bdrattr-1) = value;
|
||||
bf->Set(i, new PWConstCoefficient(pull_force));
|
||||
}
|
||||
else
|
||||
{
|
||||
bf->Set(i, new ConstantCoefficient(0.0));
|
||||
}
|
||||
}
|
||||
b->AddBoundaryIntegrator(new VectorBoundaryLFIntegrator(*bf));
|
||||
}
|
||||
|
||||
void UpdateEssentialBC(Array<int> & ess_bdr_attr_, Array<int> & ess_bdr_attr_comp_)
|
||||
{
|
||||
ess_bdr_attr = ess_bdr_attr_;
|
||||
ess_bdr_attr_comp = ess_bdr_attr_comp_;
|
||||
ess_tdof_list.SetSize(0);
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(pmesh->bdr_attributes.Max());
|
||||
}
|
||||
ess_bdr = 0;
|
||||
Array<int> ess_tdof_list_temp;
|
||||
for (int i = 0; i < ess_bdr_attr.Size(); i++ )
|
||||
{
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 1;
|
||||
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list_temp,ess_bdr_attr_comp[i]);
|
||||
ess_tdof_list.Append(ess_tdof_list_temp);
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateStep()
|
||||
{
|
||||
if (formsystem)
|
||||
{
|
||||
delete b;
|
||||
b = new ParLinearForm(fes);
|
||||
delete a;
|
||||
a = new ParBilinearForm(fes);
|
||||
a->AddDomainIntegrator(new ElasticityIntegrator(lambda_cf,mu_cf));
|
||||
|
||||
|
||||
// a->Update();
|
||||
formsystem = false;
|
||||
}
|
||||
}
|
||||
|
||||
void FormLinearSystem();
|
||||
void UpdateLinearSystem();
|
||||
|
||||
void SetDisplacementDirichletData(const Vector & delta)
|
||||
{
|
||||
VectorConstantCoefficient delta_cf(delta);
|
||||
x.ProjectBdrCoefficient(delta_cf,ess_bdr);
|
||||
bool vis = false;
|
||||
if (vis)
|
||||
{
|
||||
int myid, num_procs;
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *pmesh << x << std::flush;
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
};
|
||||
|
||||
void ResetDisplacementDirichletData()
|
||||
{
|
||||
x = 0.0;
|
||||
}
|
||||
|
||||
void SetDisplacementDirichletData(const Vector & delta, Array<int> essbdr)
|
||||
{
|
||||
VectorConstantCoefficient delta_cf(delta);
|
||||
x.ProjectBdrCoefficient(delta_cf,essbdr);
|
||||
bool vis = false;
|
||||
if (vis)
|
||||
{
|
||||
int myid, num_procs;
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *pmesh << x << std::flush;
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
};
|
||||
|
||||
ParGridFunction & GetDisplacementGridFunction() {return x;};
|
||||
Array<int> & GetEssentialDofs() {return ess_tdof_list;};
|
||||
|
||||
~ParElasticityProblem()
|
||||
{
|
||||
delete a;
|
||||
delete b;
|
||||
delete fes;
|
||||
delete fec;
|
||||
if (own_mesh)
|
||||
{
|
||||
delete pmesh;
|
||||
}
|
||||
delete bf;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #ifdef MFEM_USE_TRIBOL
|
||||
|
||||
class ParContactProblem
|
||||
{
|
||||
private:
|
||||
MPI_Comm comm;
|
||||
int numprocs;
|
||||
int myid;
|
||||
ParElasticityProblem * prob = nullptr;
|
||||
ParFiniteElementSpace * vfes = nullptr;
|
||||
int dim;
|
||||
GridFunction nodes0;
|
||||
GridFunction *nodes1 = nullptr;
|
||||
std::set<int> contact_vertices;
|
||||
std::vector<int> dof_offsets;
|
||||
std::vector<int> vertex_offsets;
|
||||
std::vector<int> constraints_offsets;
|
||||
Array<int> tdof_offsets;
|
||||
Array<int> constraints_starts;
|
||||
Array<int> globalvertices;
|
||||
Array<int> vertices;
|
||||
ParGridFunction * coords = nullptr;
|
||||
//ParGridFunction * xref = nullptr;
|
||||
|
||||
protected:
|
||||
int npoints=0;
|
||||
int gnpoints=0;
|
||||
int nv, gnv;
|
||||
HypreParMatrix * K = nullptr;
|
||||
HypreParMatrix * Pi = nullptr;
|
||||
HypreParMatrix * Pb = nullptr;
|
||||
Vector *B = nullptr;
|
||||
Vector gapv;
|
||||
HypreParMatrix * M=nullptr;
|
||||
void SetupTribol();
|
||||
void SetupTribolDoublePass();
|
||||
std::set<int> mortar_attrs;
|
||||
// plane of top block
|
||||
std::set<int> nonmortar_attrs;
|
||||
bool doublepass = false;
|
||||
|
||||
public:
|
||||
ParContactProblem(ParElasticityProblem * prob_,
|
||||
const std::set<int> & mortar_attrs_, const std::set<int> & nonmortar_attrs_,
|
||||
ParGridFunction * coords_,
|
||||
bool doublepass = false);
|
||||
|
||||
ParElasticityProblem * GetElasticityProblem() {return prob;}
|
||||
MPI_Comm GetComm() {return comm;}
|
||||
int GetNumDofs() {return K->Height();}
|
||||
int GetGlobalNumDofs() {return K->GetGlobalNumRows();}
|
||||
int GetNumConstraints() {return M->Height();}
|
||||
int GetGlobalNumConstraints() { return M->GetGlobalNumRows(); }
|
||||
|
||||
std::vector<int> & GetDofOffets() { return dof_offsets; }
|
||||
std::vector<int> & GetVertexOffsets() { return vertex_offsets; }
|
||||
std::vector<int> & GetConstraintsOffsets() { return constraints_offsets; }
|
||||
Array<int> & GetConstraintsStarts() { return constraints_starts; }
|
||||
|
||||
Vector & GetGapFunction() {return gapv;}
|
||||
|
||||
HypreParMatrix * GetJacobian() {return M;}
|
||||
|
||||
double E(const Vector & d);
|
||||
void DdE(const Vector &d, Vector &gradE);
|
||||
HypreParMatrix* DddE(const Vector &d);
|
||||
void g(const Vector &d, Vector &gd);
|
||||
HypreParMatrix* Ddg(const Vector &d);
|
||||
HypreParMatrix* lDddg(const Vector &d, const Vector &l);
|
||||
|
||||
HypreParMatrix * GetRestrictionToInteriorDofs() {return Pi;}
|
||||
HypreParMatrix * GetRestrictionToContactDofs() {return Pb;}
|
||||
|
||||
~ParContactProblem()
|
||||
{
|
||||
delete B;
|
||||
delete K;
|
||||
delete M;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class QPOptParContactProblem
|
||||
{
|
||||
private:
|
||||
ParContactProblem * problem = nullptr;
|
||||
int dimU, dimM, dimC;
|
||||
Vector ml;
|
||||
HypreParMatrix * NegId = nullptr;
|
||||
Vector xref;
|
||||
public:
|
||||
QPOptParContactProblem(ParContactProblem * problem_, Vector & xref_);
|
||||
int GetDimU();
|
||||
int GetDimM();
|
||||
int GetDimC();
|
||||
Vector & Getml();
|
||||
MPI_Comm GetComm() {return problem->GetComm();}
|
||||
int * GetConstraintsStarts() {return problem->GetConstraintsStarts().GetData();}
|
||||
int GetGlobalNumConstraints() {return problem->GetGlobalNumConstraints();}
|
||||
|
||||
ParElasticityProblem * GetElasticityProblem() {return problem->GetElasticityProblem();}
|
||||
|
||||
HypreParMatrix * Duuf(const BlockVector &);
|
||||
HypreParMatrix * Dumf(const BlockVector &);
|
||||
HypreParMatrix * Dmuf(const BlockVector &);
|
||||
HypreParMatrix * Dmmf(const BlockVector &);
|
||||
HypreParMatrix * Duc(const BlockVector &);
|
||||
HypreParMatrix * Dmc(const BlockVector &);
|
||||
HypreParMatrix * lDuuc(const BlockVector &, const Vector &);
|
||||
|
||||
HypreParMatrix * GetRestrictionToInteriorDofs() {return problem->GetRestrictionToInteriorDofs();}
|
||||
HypreParMatrix * GetRestrictionToContactDofs() {return problem->GetRestrictionToContactDofs();}
|
||||
|
||||
void c(const BlockVector &, Vector &);
|
||||
double CalcObjective(const BlockVector &);
|
||||
void CalcObjectiveGrad(const BlockVector &, BlockVector &);
|
||||
~QPOptParContactProblem();
|
||||
};
|
||||
|
||||
// #endif
|
||||
@@ -0,0 +1,115 @@
|
||||
#include "parproblems_util.hpp"
|
||||
|
||||
int get_rank(int tdof, std::vector<int> & tdof_offsets)
|
||||
{
|
||||
int size = tdof_offsets.size();
|
||||
if (size == 1) { return 0; }
|
||||
std::vector<int>::iterator up;
|
||||
up=std::upper_bound(tdof_offsets.begin(), tdof_offsets.end(),tdof); //
|
||||
return std::distance(tdof_offsets.begin(),up)-1;
|
||||
}
|
||||
|
||||
void ComputeTdofOffsets(const ParFiniteElementSpace * pfes,
|
||||
std::vector<int> & tdof_offsets)
|
||||
{
|
||||
MPI_Comm comm = pfes->GetComm();
|
||||
int num_procs;
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
tdof_offsets.resize(num_procs);
|
||||
int mytoffset = pfes->GetMyTDofOffset();
|
||||
MPI_Allgather(&mytoffset,1,MPI_INT,&tdof_offsets[0],1,MPI_INT,comm);
|
||||
}
|
||||
|
||||
void ComputeTdofOffsets(MPI_Comm comm, int mytoffset, std::vector<int> & tdof_offsets)
|
||||
{
|
||||
int num_procs;
|
||||
MPI_Comm_size(comm,&num_procs);
|
||||
tdof_offsets.resize(num_procs);
|
||||
MPI_Allgather(&mytoffset,1,MPI_INT,&tdof_offsets[0],1,MPI_INT,comm);
|
||||
}
|
||||
|
||||
void ComputeTdofs(MPI_Comm comm, int mytoffs, std::vector<int> & tdofs)
|
||||
{
|
||||
int num_procs;
|
||||
MPI_Comm_size(comm,&num_procs);
|
||||
tdofs.resize(num_procs);
|
||||
MPI_Allgather(&mytoffs,1,MPI_INT,&tdofs,1,MPI_INT,comm);
|
||||
}
|
||||
|
||||
|
||||
// Performs Pᵀ * A * P for BlockOperator P (with blocks as HypreParMatrices)
|
||||
// and A a HypreParMatrix, i.e., this handles the special case
|
||||
// where P = [P₁ P₂ ⋅⋅⋅ Pₙ]
|
||||
// C = Pᵀ * A * P
|
||||
void RAP(const HypreParMatrix & A, const BlockOperator & P,
|
||||
BlockOperator & C)
|
||||
{
|
||||
int nblocks = P.NumColBlocks();
|
||||
|
||||
const HypreParMatrix * Pi = nullptr;
|
||||
const HypreParMatrix * Pj = nullptr;
|
||||
HypreParMatrix * PitAPj = nullptr;
|
||||
|
||||
for (int i = 0; i< nblocks; i++)
|
||||
{
|
||||
if (P.IsZeroBlock(0,i)) continue;
|
||||
Pi = dynamic_cast<const HypreParMatrix*>(&P.GetBlock(0,i));
|
||||
for (int j = 0; j<nblocks; j++)
|
||||
{
|
||||
if (P.IsZeroBlock(0,j)) continue;
|
||||
Pj = dynamic_cast<const HypreParMatrix*>(&P.GetBlock(0,j));
|
||||
if (i == j)
|
||||
{
|
||||
PitAPj = RAP(&A, Pj);
|
||||
}
|
||||
else
|
||||
{
|
||||
PitAPj = RAP(Pi, &A, Pj);
|
||||
}
|
||||
C.SetBlock(i,j,PitAPj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParAdd(const BlockOperator & A, const BlockOperator & B, BlockOperator & C)
|
||||
{
|
||||
int n = A.NumRowBlocks();
|
||||
int m = A.NumColBlocks();
|
||||
MFEM_VERIFY(B.NumRowBlocks() == n, "Inconsistent number of row blocks");
|
||||
MFEM_VERIFY(B.NumColBlocks() == m, "Inconsistent number of column blocks");
|
||||
|
||||
const HypreParMatrix * a;
|
||||
const HypreParMatrix * b;
|
||||
for (int i = 0; i<n; i++)
|
||||
{
|
||||
for (int j = 0; j<m; j++)
|
||||
{
|
||||
a = nullptr;
|
||||
b = nullptr;
|
||||
if (!A.IsZeroBlock(i,j))
|
||||
{
|
||||
a = dynamic_cast<const HypreParMatrix*>(&A.GetBlock(i,j));
|
||||
}
|
||||
if (!B.IsZeroBlock(i,j))
|
||||
{
|
||||
b = dynamic_cast<const HypreParMatrix*>(&B.GetBlock(i,j));
|
||||
}
|
||||
if (a && b)
|
||||
{
|
||||
C.SetBlock(i,j,ParAdd(a,b));
|
||||
}
|
||||
else if (a)
|
||||
{
|
||||
C.SetBlock(i,j,new HypreParMatrix(*a));
|
||||
}
|
||||
else if (b)
|
||||
{
|
||||
C.SetBlock(i,j,new HypreParMatrix(*b));
|
||||
}
|
||||
else
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
#include "mfem.hpp"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
#include "axom/slic.hpp"
|
||||
|
||||
#include "tribol/interface/tribol.hpp"
|
||||
#include "tribol/interface/mfem_tribol.hpp"
|
||||
int get_rank(int tdof, std::vector<int> & tdof_offsets);
|
||||
void ComputeTdofOffsets(const ParFiniteElementSpace * pfes,
|
||||
std::vector<int> & tdof_offsets);
|
||||
void ComputeTdofOffsets(MPI_Comm comm, int mytoffset, std::vector<int> & tdof_offsets);
|
||||
void ComputeTdofs(MPI_Comm comm, int mytoffs, std::vector<int> & tdofs);
|
||||
|
||||
|
||||
// Performs Pᵀ * A * P for BlockOperator P (with blocks as HypreParMatrices)
|
||||
// and A a HypreParMatrix, i.e., this handles the special case
|
||||
// where P = [P₁ P₂ ⋅⋅⋅ Pₙ]
|
||||
void RAP(const HypreParMatrix & A, const BlockOperator & P, BlockOperator & C);
|
||||
void ParAdd(const BlockOperator & A, const BlockOperator & B, BlockOperator & C);
|
||||
@@ -0,0 +1,564 @@
|
||||
// Parallel contact example
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 1 -testno 4
|
||||
// CG iteration numbers = 105 114 116 115 113 109 113 108 107 114 206 236 268 435 987
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 5
|
||||
// CG iteration numbers = 106 116 116 116 115 113 107 107 128 131 531 1437 1318
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 6
|
||||
// CG iteration numbers = 18 18 18 18 18 17 17 21 22 46 52 53
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "ipsolver/ParIPsolver.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Mpi::Init();
|
||||
int myid = Mpi::WorldRank();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
Hypre::Init();
|
||||
|
||||
int order = 1;
|
||||
int sref = 1;
|
||||
int pref = 0;
|
||||
Array<int> attr;
|
||||
Array<int> m_attr;
|
||||
bool visualization = true;
|
||||
bool paraview = false;
|
||||
bool elast = false;
|
||||
bool nocontact = false;
|
||||
int testNo = -1; // 0-6
|
||||
// 1. Parse command-line options.
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&testNo, "-testno", "--test-number",
|
||||
"Choice of test problem:"
|
||||
"-1: default (original 2 block problem)"
|
||||
"0: not implemented yet"
|
||||
"1: not implemented yet"
|
||||
"2: not implemented yet"
|
||||
"3: not implemented yet"
|
||||
"4: two block problem - diablo"
|
||||
"41: two block problem - twisted"
|
||||
"5: ironing problem"
|
||||
"51: ironing problem extended"
|
||||
"6: nested spheres problem");
|
||||
args.AddOption(&attr, "-at", "--attributes-surf",
|
||||
"Attributes of boundary faces on contact surface for mesh 2.");
|
||||
args.AddOption(&sref, "-sr", "--serial-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&pref, "-pr", "--parallel-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&elast, "-elast", "--elast", "-no-elast",
|
||||
"--no-elast",
|
||||
"Enable or disable AMG Elasticity options.");
|
||||
args.AddOption(&nocontact, "-nocontact", "--nocontact", "-no-nocontact",
|
||||
"--no-nocontact",
|
||||
"Enable or disable AMG solve with no contact for testing.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(¶view, "-paraview", "--paraview", "-no-paraview",
|
||||
"--no-paraview",
|
||||
"Enable or disable ParaView visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
if (Mpi::Root())
|
||||
{
|
||||
mfem::out << "Solving test problem number: " << testNo << endl;
|
||||
}
|
||||
|
||||
const char *mesh_file = nullptr;
|
||||
|
||||
switch (testNo)
|
||||
{
|
||||
case -1:
|
||||
mesh_file = "meshes/two-block.mesh";
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
MFEM_ABORT("Problem not implemented yet");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
mesh_file = "meshes/Test4.mesh";
|
||||
break;
|
||||
case 40:
|
||||
mesh_file = "meshes/Test40.mesh";
|
||||
break;
|
||||
case 41:
|
||||
mesh_file = "meshes/Test41.mesh";
|
||||
break;
|
||||
case 42:
|
||||
mesh_file = "meshes/Test42.mesh";
|
||||
break;
|
||||
case 5:
|
||||
mesh_file = "meshes/Test5.mesh";
|
||||
break;
|
||||
case 51:
|
||||
mesh_file = "meshes/Test51.mesh";
|
||||
break;
|
||||
case 6:
|
||||
mesh_file = "meshes/Test6.mesh";
|
||||
break;
|
||||
case 61:
|
||||
// Something wrong with this mesh
|
||||
mesh_file = "meshes/Test61.mesh";
|
||||
break;
|
||||
case 62:
|
||||
mesh_file = "meshes/Test62.mesh";
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Should be unreachable");
|
||||
break;
|
||||
}
|
||||
|
||||
Mesh * mesh = new Mesh(mesh_file,1);
|
||||
for (int i = 0; i<sref; i++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
ParMesh * pmesh = new ParMesh(MPI_COMM_WORLD,*mesh);
|
||||
|
||||
for (int i = 0; i<pref; i++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
Array<int> ess_bdr_attr;
|
||||
Array<int> ess_bdr_attr_comp;
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(1);
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(2);
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 62)
|
||||
{
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 40)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(10); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(6); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
ParElasticityProblem * prob = new ParElasticityProblem(pmesh,
|
||||
ess_bdr_attr,ess_bdr_attr_comp,
|
||||
order);
|
||||
Vector lambda(prob->GetMesh()->attributes.Max());
|
||||
Vector mu(prob->GetMesh()->attributes.Max());
|
||||
|
||||
if (testNo == -1 )
|
||||
{
|
||||
lambda = 57.6923076923;
|
||||
mu = 38.4615384615;
|
||||
}
|
||||
else if (testNo == 6 || testNo == 61 || testNo == 62)
|
||||
{
|
||||
lambda = (1000*0.3)/(1.3*0.4);
|
||||
mu = 500/(1.3);
|
||||
}
|
||||
else
|
||||
{
|
||||
lambda[0] = 0.499/(1.499*0.002);
|
||||
lambda[1] = 0.0;
|
||||
mu[0] = 1./(2*1.499);
|
||||
mu[1] = 500;
|
||||
}
|
||||
|
||||
prob->SetLambda(lambda); prob->SetMu(mu);
|
||||
|
||||
int dim = pmesh->Dimension();
|
||||
Vector ess_values(dim);
|
||||
int essbdr_attr;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
|
||||
ess_values = 0.0;
|
||||
|
||||
|
||||
// ConstantCoefficient one(-area);
|
||||
ConstantCoefficient one(-1.0);
|
||||
|
||||
std::set<int> mortar_attr;
|
||||
std::set<int> nonmortar_attr;
|
||||
|
||||
int nsteps = 100;
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[0] = 1;
|
||||
ess_bdr[1] = 1;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else if(testNo == 62)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
prob->SetNeumanData(0,3,-2.0);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (testNo == -1 || testNo == 41)
|
||||
{
|
||||
ess_values[0] = 0.1/nsteps;
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_values[2] = 1.0/1.4/nsteps;
|
||||
// ess_values[0] = -2.0/nsteps;
|
||||
}
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = (testNo == 40) ? 10 : 6;
|
||||
ess_values = 0.0; ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
if (testNo == 40)
|
||||
{
|
||||
mortar_attr.insert(4);
|
||||
nonmortar_attr.insert(7);
|
||||
}
|
||||
else
|
||||
{
|
||||
mortar_attr.insert(3);
|
||||
nonmortar_attr.insert(4);
|
||||
}
|
||||
}
|
||||
|
||||
ParFiniteElementSpace * fes = prob->GetFESpace();
|
||||
ParGridFunction x_gf(fes); x_gf = 0.0;
|
||||
ParGridFunction xnew(fes); xnew = 0.0;
|
||||
ParaViewDataCollection * paraview_dc = nullptr;
|
||||
ParMesh pmesh_copy(*pmesh);
|
||||
ParFiniteElementSpace fes_copy(*fes,pmesh_copy);
|
||||
ParGridFunction xcopy_gf(&fes_copy); xcopy_gf = 0.0;
|
||||
|
||||
if (paraview)
|
||||
{
|
||||
std::ostringstream paraview_file_name;
|
||||
paraview_file_name << "QPContact-Test_" << testNo
|
||||
<< "_par_ref_" << pref
|
||||
<< "_ser_ref_" << sref;
|
||||
paraview_dc = new ParaViewDataCollection(paraview_file_name.str(), &pmesh_copy);
|
||||
paraview_dc->SetPrefixPath("ParaView");
|
||||
paraview_dc->SetLevelsOfDetail(1);
|
||||
paraview_dc->SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc->SetHighOrderOutput(true);
|
||||
// paraview_dc->RegisterField("u", &x_gf);
|
||||
paraview_dc->RegisterField("u", &xcopy_gf);
|
||||
paraview_dc->SetCycle(0);
|
||||
paraview_dc->SetTime(double(0));
|
||||
paraview_dc->Save();
|
||||
}
|
||||
socketstream sol_sock;
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
sol_sock.open(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
}
|
||||
|
||||
|
||||
ParGridFunction ref_coords(prob->GetFESpace());
|
||||
ParGridFunction new_coords(prob->GetFESpace());
|
||||
pmesh->GetNodes(new_coords);
|
||||
pmesh->GetNodes(ref_coords);
|
||||
|
||||
Vector xref(x_gf.GetTrueVector().Size());
|
||||
|
||||
double p = 1;
|
||||
ConstantCoefficient f(p);
|
||||
|
||||
double pseudotime = 1.0 / ((double) nsteps);
|
||||
if (testNo == 6)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
f.constant = -p * pseudotime;
|
||||
prob->SetNeumanPressureData(f,ess_bdr);
|
||||
// prob->SetNeumanData(0,3,-p*(i+1)/nsteps);
|
||||
}
|
||||
else if (testNo == 4 || testNo == 40 || testNo == 5 || testNo == 51)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
ess_values = 0.0;
|
||||
//ess_values[2] = 4.0 / 7.0 * pseudotime;
|
||||
ess_values[2] = 1.0/1.4 * pseudotime;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
else if (testNo == 41)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_values[0] = 0.5 * pseudotime; //0.5/nsteps*(i+1);
|
||||
// ess_values[0] = 0.0;
|
||||
essbdr_attr = 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = 6;
|
||||
ess_values = 0.0;
|
||||
// ess_values[0] = -0.5/nsteps*(i+1);
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "ess_values[0] = " << ess_values[0] << endl;
|
||||
}
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
|
||||
|
||||
/* ------- finite difference check -------- */
|
||||
Vector x0(fes->GetTrueVSize()); x0 = 0.0;
|
||||
//x0 = 2.0;
|
||||
//x0.Randomize(); x0 *= 1.e-2;
|
||||
Array<int> vdofs;
|
||||
for (int i = 0; i < pmesh->GetNE(); i++)
|
||||
{
|
||||
cout << "attribute = " << pmesh->GetAttribute(i) << endl;
|
||||
if (pmesh->GetAttribute(i) == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
for (int j = 0; j < vdofs.Size(); j++)
|
||||
{
|
||||
x0(vdofs[j]) = 0.01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
x_gf.SetFromTrueDofs(x0);
|
||||
add(ref_coords, x_gf, new_coords);
|
||||
|
||||
Vector x1(fes->GetTrueVSize()); x1 = 0.0;
|
||||
Vector xdir(fes->GetTrueVSize()); xdir.Randomize();
|
||||
Vector temp(fes->GetTrueVSize()); temp = 0.0;
|
||||
xdir *= 1.e-2; // scale so as to avoid mesh tangling
|
||||
double eps = 1.0;
|
||||
|
||||
ParContactProblem ref_contact(prob, mortar_attr, nonmortar_attr, &new_coords);
|
||||
int ndofs = ref_contact.GetNumDofs();
|
||||
int nconstraints = ref_contact.GetNumConstraints();
|
||||
Vector g0 = ref_contact.GetGapFunction();
|
||||
g0.Print();
|
||||
HypreParMatrix * J0 = ref_contact.GetJacobian();
|
||||
|
||||
//for (int i = 0; i < 30; i++)
|
||||
//{
|
||||
// x1.Set(1.0, x0); // x1 = x0 + eps * xdir
|
||||
// x1.Add(eps, xdir);
|
||||
// x_gf.SetFromTrueDofs(x1);
|
||||
// add(ref_coords, x_gf, new_coords);
|
||||
// ParContactProblem new_contact(prob, mortar_attr, nonmortar_attr, &new_coords);
|
||||
// Vector g1 = new_contact.GetGapFunction(); // g1 = g(x0 + eps * xdir)
|
||||
// Vector fd_err(g1.Size());
|
||||
|
||||
// // ||J0 * xdir - (g1 - g0) / eps||
|
||||
// J0->Mult(xdir, fd_err);
|
||||
// fd_err.Add(-1.0 / eps, g1);
|
||||
// fd_err.Add(1.0 / eps, g0);
|
||||
// cout << "fd err = " << fd_err.Norml2() << ", eps = " << eps << endl;
|
||||
// eps /= 2.0;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
//for (int i = 0; i < 30; i++)
|
||||
//{
|
||||
//// add(ref_coords,x_gf,new_coords);
|
||||
//
|
||||
//}
|
||||
|
||||
|
||||
//for (int i = 0; i < nsteps; i++)
|
||||
//{
|
||||
// //pseudotime = ((double) (i) / ((double) SQPrepeat) + 1.) / ((double) nsteps);
|
||||
// pseudotime = ((double) (i)) / ((double) nsteps);
|
||||
// for (int j = 0; j < SQPrepeat; j++)
|
||||
// {
|
||||
// paraview_time = pseudotime + j * paraview_subtimestep;
|
||||
|
||||
// //xref.Set(1.0, new_coords.GetTrueVector());
|
||||
// //xref.Add(-1.0, ref_coords.GetTrueVector());
|
||||
// xref.Set(1.0, x_gf.GetTrueVector());
|
||||
// ParContactProblem contact(prob, mortar_attr, nonmortar_attr, &new_coords, doublepass);
|
||||
// QPOptParContactProblem qpopt(&contact, xref);
|
||||
// int numconstr = contact.GetGlobalNumConstraints();
|
||||
// ParInteriorPointSolver optimizer(&qpopt);
|
||||
// optimizer.SetTol(optimizer_tol);
|
||||
// optimizer.SetMaxIter(optimizer_maxit);
|
||||
// optimizer.SetLinearSolver(linsolver);
|
||||
// optimizer.SetLinearSolveRelTol(linsolverrtol);
|
||||
// optimizer.SetLinearSolveAbsTol(linsolveratol);
|
||||
// optimizer.SetLinearSolveRelaxType(relax_type);
|
||||
// if (nocontact)
|
||||
// {
|
||||
// optimizer.EnableNoContactSolve();
|
||||
// }
|
||||
// if (elast)
|
||||
// {
|
||||
// optimizer.SetElasticityOptions(prob->GetFESpace());
|
||||
// }
|
||||
// // ParGridFunction x = prob->GetDisplacementGridFunction();
|
||||
// // x.SetTrueVector();
|
||||
// // Vector x0 = x.GetTrueVector();
|
||||
|
||||
// x_gf.SetTrueVector();
|
||||
// Vector x0 = x_gf.GetTrueVector();
|
||||
// int ndofs = x0.Size();
|
||||
// Vector xf(ndofs); xf = 0.0;
|
||||
// optimizer.Mult(x0, xf);
|
||||
// QPConverged = optimizer.GetConverged();
|
||||
// MFEM_VERIFY(QPConverged, "IPM not converged on QP contact problem");
|
||||
// //optimizer.SaveLambda(i);
|
||||
// //optimizer.SaveZl(i);
|
||||
// Vector xf_copy(xf);
|
||||
// xf_copy+=x0;
|
||||
// double Einitial = contact.E(x0);
|
||||
// // double Efinal = contact.E(xf);
|
||||
// double Efinal = contact.E(xf_copy);
|
||||
// Array<int> & CGiterations = optimizer.GetCGIterNumbers();
|
||||
// int gndofs = prob->GetGlobalNumDofs();
|
||||
// //dgdu = contact.Ddg(xf_copy);
|
||||
// //std::ostringstream dgdu_file_name;
|
||||
// //dgdu_file_name << "Jacobians/J" << i;
|
||||
// //dgdu->Print(dgdu_file_name.str().c_str());
|
||||
// if (Mpi::Root())
|
||||
// {
|
||||
// mfem::out << endl;
|
||||
// mfem::out << " Initial Energy objective = " << Einitial << endl;
|
||||
// mfem::out << " Final Energy objective = " << Efinal << endl;
|
||||
// mfem::out << " Global number of dofs = " << gndofs << endl;
|
||||
// mfem::out << " Global number of constraints = " << numconstr << endl;
|
||||
// mfem::out << " Optimizer number of iterations = " <<
|
||||
// optimizer.GetNumIterations() << endl;
|
||||
// if (linsolver == 2 || linsolver == 3 || linsolver == 4)
|
||||
// {
|
||||
// mfem::out << " CG iteration numbers = " ;
|
||||
// CGiterations.Print(mfem::out, CGiterations.Size());
|
||||
// }
|
||||
// if (nocontact)
|
||||
// {
|
||||
// Array<int> & CGNoContactIterations = optimizer.GetCGNoContactIterNumbers();
|
||||
// mfem::out << " CG no Contact iteration numbers = " ;
|
||||
// CGNoContactIterations.Print(mfem::out, CGNoContactIterations.Size());
|
||||
// }
|
||||
// if (outputfiles)
|
||||
// {
|
||||
// ostringstream file_name;
|
||||
// file_name << "output/Testno-"<<testNo<<"-ref-"<<sref+pref << "-step-" << i;
|
||||
// OutputData(file_name, Einitial, Efinal, gndofs,numconstr, optimizer.GetNumIterations(), CGiterations);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Vector X_new(xf.GetData(),fes->GetTrueVSize());
|
||||
// // xnew.SetFromTrueDofs(X_new);
|
||||
// // x_gf = xnew;
|
||||
// x_gf.SetFromTrueDofs(xf);
|
||||
// // mfem::out << "x_gf norm = " << x_gf.Norml2() << endl;
|
||||
// // cin.get();
|
||||
// // pmesh->MoveNodes(xnew);
|
||||
// // pmesh_copy.MoveNodes(xnew);
|
||||
// // pmesh_copy.MoveNodes(xnew);
|
||||
// add(ref_coords,x_gf,new_coords);
|
||||
// // mfem::out << " ref_coords norm " << ref_coords.Norml2() << endl;
|
||||
// // mfem::out << " x_gf norm " << x_gf.Norml2() << endl;
|
||||
// // mfem::out << " new_coords norm " << new_coords.Norml2() << endl;
|
||||
// // pmesh_copy.SetNodes(new_coords);
|
||||
// pmesh_copy.SetNodes(new_coords);
|
||||
// xcopy_gf = x_gf;
|
||||
// // pmesh_copy.MoveNodes(x_gf);
|
||||
// // pmesh_copy.SetNodes(x_gf);
|
||||
// if (paraview && ((i+1) % paraview_plot_every == 0 ))
|
||||
// {
|
||||
// paraview_cycle += 1;
|
||||
// paraview_dc->SetCycle(paraview_cycle) ;
|
||||
// paraview_dc->SetTime(paraview_time);
|
||||
// paraview_dc->Save();
|
||||
// }
|
||||
|
||||
// if (visualization)
|
||||
// {
|
||||
// sol_sock << "parallel " << num_procs << " " << myid << "\n"
|
||||
// << "solution\n" << pmesh_copy << x_gf << flush;
|
||||
//
|
||||
// if (i == nsteps - 1 && j == SQPrepeat - 1)
|
||||
// {
|
||||
// pmesh->MoveNodes(x_gf);
|
||||
// char vishost[] = "localhost";
|
||||
// int visport = 19916;
|
||||
// socketstream sol_sock1(vishost, visport);
|
||||
// sol_sock1 << "parallel " << num_procs << " " << myid << "\n";
|
||||
// sol_sock1.precision(8);
|
||||
// sol_sock1 << "solution\n" << *pmesh << x_gf << flush;
|
||||
// }
|
||||
// }
|
||||
// if (i == nsteps - 1 && j == SQPrepeat) break;
|
||||
|
||||
// prob->UpdateStep();
|
||||
// if (testNo == 6 )
|
||||
// {
|
||||
// double area_new = GetBdrArea(3,*pmesh);
|
||||
// if (myid == 0)
|
||||
// {
|
||||
// mfem::out << "New area = " << area_new << endl;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
delete prob;
|
||||
delete pmesh;
|
||||
delete mesh;
|
||||
return 0;
|
||||
}
|
||||
@@ -15,11 +15,11 @@
|
||||
//
|
||||
// Sample runs
|
||||
//
|
||||
// acoustics -ref 4 -o 1 -rnum 1.0
|
||||
// acoustics -m ../../data/inline-tri.mesh -ref 4 -o 2 -sc -rnum 3.0
|
||||
// acoustics -m ../../data/amr-quad.mesh -ref 3 -o 3 -sc -rnum 4.5 -prob 1
|
||||
// acoustics -m ../../data/inline-quad.mesh -ref 2 -o 4 -sc -rnum 11.5 -prob 1
|
||||
// acoustics -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
|
||||
// acoustics -ref 4 -o 1 -rnum 1.0
|
||||
// acoustics -m ../../data/inline-tri.mesh -ref 4 -o 2 -sc -rnum 3.0
|
||||
// acoustics -m ../../data/amr-quad.mesh -ref 3 -o 3 -sc -rnum 4.5 -prob 1
|
||||
// acoustics -m ../../data/inline-quad.mesh -ref 2 -o 4 -sc -rnum 11.5 -prob 1
|
||||
// acoustics -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
// Compile with: make convection-diffusion
|
||||
//
|
||||
// sample runs
|
||||
// convection-diffusion -m ../../data/star.mesh -o 2 -ref 2 -theta 0.0 -eps 1e-1 -beta '2 3'
|
||||
// convection-diffusion -m ../../data/beam-hex.mesh -o 2 -ref 2 -theta 0.0 -eps 1e0 -beta '1 0 2'
|
||||
// convection-diffusion -m ../../data/inline-tri.mesh -o 3 -ref 2 -theta 0.0 -eps 1e-2 -beta '4 2' -sc
|
||||
// convection-diffusion -m ../../data/star.mesh -o 2 -ref 2 -theta 0.0 -eps 1e-1 -beta '2 3'
|
||||
// convection-diffusion -m ../../data/beam-hex.mesh -o 2 -ref 2 -theta 0.0 -eps 1e0 -beta '1 0 2'
|
||||
// convection-diffusion -m ../../data/inline-tri.mesh -o 3 -ref 2 -theta 0.0 -eps 1e-2 -beta '4 2' -sc
|
||||
|
||||
// AMR runs
|
||||
// convection-diffusion -o 3 -ref 5 -prob 1 -eps 1e-1 -theta 0.75
|
||||
// convection-diffusion -o 2 -ref 9 -prob 1 -eps 1e-2 -theta 0.75
|
||||
// convection-diffusion -o 3 -ref 9 -prob 1 -eps 1e-3 -theta 0.75 -sc
|
||||
// convection-diffusion -o 3 -ref 5 -prob 1 -eps 1e-1 -theta 0.75
|
||||
// convection-diffusion -o 2 -ref 9 -prob 1 -eps 1e-2 -theta 0.75
|
||||
// convection-diffusion -o 3 -ref 9 -prob 1 -eps 1e-3 -theta 0.75 -sc
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
// Compile with: make maxwell
|
||||
//
|
||||
// Sample runs
|
||||
// maxwell -m ../../data/inline-tri.mesh -ref 4 -o 1 -rnum 1.0
|
||||
// maxwell -m ../../data/amr-quad.mesh -ref 3 -o 2 -rnum 1.6 -sc
|
||||
// maxwell -m ../../data/inline-quad.mesh -ref 2 -o 3 -rnum 4.2 -sc
|
||||
// maxwell -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
|
||||
// maxwell -m ../../data/inline-tri.mesh -ref 4 -o 1 -rnum 1.0
|
||||
// maxwell -m ../../data/amr-quad.mesh -ref 3 -o 2 -rnum 1.6 -sc
|
||||
// maxwell -m ../../data/inline-quad.mesh -ref 2 -o 3 -rnum 4.2 -sc
|
||||
// maxwell -m ../../data/inline-hex.mesh -ref 1 -o 2 -sc -rnum 1.0
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve
|
||||
|
||||
+11
-11
@@ -15,19 +15,19 @@
|
||||
//
|
||||
// sample runs
|
||||
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/star.mesh -sref 1 -pref 2 -rnum 1.9 -sc -prob 0
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 1 -pref 2 -rnum 5.2 -sc -prob 1
|
||||
// mpirun -np 4 pacoustics -o 4 -m ../../data/inline-tri.mesh -sref 1 -pref 2 -rnum 7.1 -sc -prob 1
|
||||
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 1.9 -sc -prob 0
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 2 -pref 1 -rnum 7.1 -sc -prob 2
|
||||
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 4.1 -sc -prob 2
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 7.1 -sc -prob 3
|
||||
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 10.1 -sc -prob 4
|
||||
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 12.1 -sc -prob 5
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/star.mesh -sref 1 -pref 2 -rnum 1.9 -sc -prob 0
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 1 -pref 2 -rnum 5.2 -sc -prob 1
|
||||
// mpirun -np 4 pacoustics -o 4 -m ../../data/inline-tri.mesh -sref 1 -pref 2 -rnum 7.1 -sc -prob 1
|
||||
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 1.9 -sc -prob 0
|
||||
// mpirun -np 4 pacoustics -o 3 -m ../../data/inline-quad.mesh -sref 2 -pref 1 -rnum 7.1 -sc -prob 2
|
||||
// mpirun -np 4 pacoustics -o 2 -m ../../data/inline-hex.mesh -sref 0 -pref 1 -rnum 4.1 -sc -prob 2
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 7.1 -sc -prob 3
|
||||
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 10.1 -sc -prob 4
|
||||
// mpirun -np 4 pacoustics -o 4 -m meshes/scatter.mesh -sref 1 -pref 1 -rnum 12.1 -sc -prob 5
|
||||
|
||||
// AMR runs
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 7 -theta 0.75 -rnum 10.1 -sc -prob 3
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 12 -theta 0.75 -rnum 20.1 -sc -prob 3
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 7 -theta 0.75 -rnum 10.1 -sc -prob 3
|
||||
// mpirun -np 4 pacoustics -o 3 -m meshes/scatter.mesh -sref 0 -pref 12 -theta 0.75 -rnum 20.1 -sc -prob 3
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve
|
||||
|
||||
@@ -11,17 +11,17 @@
|
||||
//
|
||||
// MFEM Ultraweak DPG parallel example for convection-diffusion
|
||||
//
|
||||
// Compile with: make pconvection-diffusion
|
||||
// Compile with: make pconvection-diffusion
|
||||
//
|
||||
// sample runs
|
||||
// mpirun -np 4 pconvection-diffusion -o 2 -ref 3 -prob 0 -eps 1e-1 -beta '4 2' -theta 0.0
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 3 -prob 0 -eps 1e-2 -beta '2 3' -theta 0.0
|
||||
// mpirun -np 4 pconvection-diffusion -m ../../data/inline-hex.mesh -o 2 -ref 1 -prob 0 -sc -eps 1e-1 -theta 0.0
|
||||
// mpirun -np 4 pconvection-diffusion -o 2 -ref 3 -prob 0 -eps 1e-1 -beta '4 2' -theta 0.0
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 3 -prob 0 -eps 1e-2 -beta '2 3' -theta 0.0
|
||||
// mpirun -np 4 pconvection-diffusion -m ../../data/inline-hex.mesh -o 2 -ref 1 -prob 0 -sc -eps 1e-1 -theta 0.0
|
||||
|
||||
// AMR runs
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 10 -prob 1 -eps 1e-3 -beta '1 0' -theta 0.7 -sc
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 15 -prob 2 -eps 5e-3 -theta 0.7 -sc
|
||||
// mpirun -np 4 pconvection-diffusion -o 2 -ref 12 -prob 3 -eps 1e-2 -beta '1 2' -theta 0.7 -sc
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 10 -prob 1 -eps 1e-3 -beta '1 0' -theta 0.7 -sc
|
||||
// mpirun -np 4 pconvection-diffusion -o 3 -ref 15 -prob 2 -eps 5e-3 -theta 0.7 -sc
|
||||
// mpirun -np 4 pconvection-diffusion -o 2 -ref 12 -prob 3 -eps 1e-2 -beta '1 2' -theta 0.7 -sc
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve a parallel
|
||||
|
||||
@@ -14,18 +14,18 @@
|
||||
// Compile with: make pdiffusion
|
||||
//
|
||||
// Sample runs
|
||||
// mpirun -np 4 pdiffusion -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 2 -theta 0.0 -prob 0
|
||||
// mpirun -np 4 pdiffusion -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -theta 0.0 -prob 0 -sc
|
||||
// mpirun -np 4 pdiffusion -m ../../data/beam-tet.mesh -o 3 -sref 0 -pref 2 -theta 0.0 -prob 0 -sc
|
||||
// mpirun -np 4 pdiffusion -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 2 -theta 0.0 -prob 0
|
||||
// mpirun -np 4 pdiffusion -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -theta 0.0 -prob 0 -sc
|
||||
// mpirun -np 4 pdiffusion -m ../../data/beam-tet.mesh -o 3 -sref 0 -pref 2 -theta 0.0 -prob 0 -sc
|
||||
|
||||
// L-shape runs
|
||||
// Note: uniform ref are expected to give sub-optimal rate for the L-shape problem (rate = 2/3)
|
||||
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 5 -theta 0.0 -prob 1
|
||||
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 5 -theta 0.0 -prob 1
|
||||
|
||||
// L-shape AMR runs
|
||||
// mpirun -np 4 pdiffusion -o 1 -sref 1 -pref 10 -theta 0.8 -prob 1
|
||||
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 8 -theta 0.75 -prob 1 -sc
|
||||
// mpirun -np 4 pdiffusion -o 3 -sref 1 -pref 6 -theta 0.75 -prob 1 -sc -do 2
|
||||
// mpirun -np 4 pdiffusion -o 1 -sref 1 -pref 10 -theta 0.8 -prob 1
|
||||
// mpirun -np 4 pdiffusion -o 2 -sref 1 -pref 8 -theta 0.75 -prob 1 -sc
|
||||
// mpirun -np 4 pdiffusion -o 3 -sref 1 -pref 6 -theta 0.75 -prob 1 -sc -do 2
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
// Compile with: make pmaxwell
|
||||
//
|
||||
// sample run
|
||||
// mpirun -np 4 pmaxwell -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4
|
||||
// mpirun -np 4 pmaxwell -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0
|
||||
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4
|
||||
|
||||
// AMR run. Note that this is a computationally intensive sample run.
|
||||
// We recommend trying it on a large machine with more mpi ranks
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc
|
||||
// mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc
|
||||
|
||||
// Description:
|
||||
// This example code demonstrates the use of MFEM to define and solve
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -1,124 +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_tau.hpp"
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
real_t FFH92Tau::GetElementSize(ElementTransformation &T)
|
||||
{
|
||||
const DenseMatrix &dxdxi = T.Jacobian();
|
||||
row.SetSize(dim);
|
||||
h.SetSize(dim);
|
||||
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
dxdxi.GetRow(i, row);
|
||||
h[i] = row.Norml2();
|
||||
}
|
||||
switch (dim)
|
||||
{
|
||||
case 1:
|
||||
return h[0];
|
||||
case 2:
|
||||
return h[0]*h[1]*sqrt(2.0/(h[0]*h[0] + h[1]*h[1]));
|
||||
case 3:
|
||||
return h[0]*h[1]*h[2]*(3.0/(h[0]*h[0] + h[1]*h[1] + h[2]*h[2]));
|
||||
}
|
||||
mfem_error("Wrong dim!");
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
real_t FFH92Tau::GetInverseEstimate(ElementTransformation &T,
|
||||
const IntegrationPoint &ip, real_t scale)
|
||||
{
|
||||
if (Ci>0.0)
|
||||
{
|
||||
return 1.0/Ci;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1.0/(invEst_cf->Eval(T,ip)*scale);
|
||||
}
|
||||
}
|
||||
|
||||
real_t FFH92Tau::Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
real_t k = kappa->Eval(T, ip);
|
||||
adv->Eval(a, T, ip);
|
||||
real_t hk = GetElementSize(T);
|
||||
real_t ci = GetInverseEstimate(T, ip, hk*hk);
|
||||
real_t mk = std::min(1.0/3.0, 2*ci);
|
||||
real_t ap = a.Normlp(p);
|
||||
// Prevent division by zero
|
||||
ap = std::max(ap,std::numeric_limits<real_t>::min());
|
||||
real_t pe = mk*ap*hk/(k_fac*k); // k_fac = 2 for CD and k_fac = 4 for NS
|
||||
real_t xi = std::min(pe,1.0);
|
||||
real_t tau = hk*xi/(2*ap);
|
||||
|
||||
if (print)
|
||||
{
|
||||
std::cout<<"\n==========================\n";
|
||||
std::cout<<" kappa = "<<k <<std::endl;
|
||||
std::cout<<" adv = "; a.Print(std::cout);
|
||||
std::cout<<" h = "<<hk <<std::endl;
|
||||
std::cout<<" Ci = "<<ci<<" "
|
||||
<<( (Ci<0) ? "(Computed)" :"(Specified)")<<std::endl;
|
||||
std::cout<<" 1/Ci = "<<1.0/ci<<std::endl;
|
||||
std::cout<<" mk = "<<mk <<std::endl;
|
||||
std::cout<<" |a|_p = "<<ap <<std::endl;
|
||||
std::cout<<" Pe = "<<pe <<std::endl;
|
||||
std::cout<<" xi = "<<xi <<std::endl;
|
||||
std::cout<<" tau = "<<tau<<std::endl;
|
||||
std::cout<<" tau = "<<mk*hk*hk/(8*k)<<std::endl;
|
||||
std::cout<<"==========================\n\n";
|
||||
print = false;
|
||||
}
|
||||
|
||||
return tau;
|
||||
}
|
||||
|
||||
real_t FF91Delta::Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
real_t k = kappa->Eval(T, ip);
|
||||
adv->Eval(a, T, ip);
|
||||
real_t hk = GetElementSize(T);
|
||||
real_t ci = GetInverseEstimate(T, ip, hk*hk);
|
||||
real_t mk = std::min(1.0/3.0, 2*ci);
|
||||
real_t ap = a.Normlp(p); // Preventing division by zero not necessary
|
||||
real_t pe = mk*ap*hk/(k_fac*k);
|
||||
real_t xi = std::min(pe,1.0);
|
||||
real_t delta = lambda*ap*hk*xi;
|
||||
|
||||
if (print)
|
||||
{
|
||||
std::cout<<"\n==========================\n";
|
||||
std::cout<<" kappa = "<<k <<std::endl;
|
||||
std::cout<<" adv = "; a.Print(std::cout);
|
||||
std::cout<<" h = "<<hk <<std::endl;
|
||||
std::cout<<" Ci = "<<ci<<" "
|
||||
<<( (Ci<0) ? "(Computed)" :"(Specified)")<<std::endl;
|
||||
std::cout<<" 1/Ci = "<<1.0/ci<<std::endl;
|
||||
std::cout<<" mk = "<<mk <<std::endl;
|
||||
std::cout<<" |a|_p = "<<ap <<std::endl;
|
||||
std::cout<<" Pe = "<<pe <<std::endl;
|
||||
std::cout<<" xi = "<<xi <<std::endl;
|
||||
std::cout<<" lambda = "<<lambda <<std::endl;
|
||||
std::cout<<" delta = "<<delta<<std::endl;
|
||||
std::cout<<"==========================\n\n";
|
||||
print = false;
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
@@ -1,298 +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_TAU_HPP
|
||||
#define MFEM_STAB_TAU_HPP
|
||||
|
||||
#include "mfem.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Enumerate to indicate the stabilisation type.
|
||||
enum StabType
|
||||
{
|
||||
GALERKIN = -2,
|
||||
SUPG = 0,
|
||||
GLS = -1,
|
||||
VMS = 1
|
||||
};
|
||||
|
||||
/// This Class defines a generic stabilisation parameter.
|
||||
class Tau: public Coefficient
|
||||
{
|
||||
protected:
|
||||
/// The advection field
|
||||
VectorCoefficient *adv;
|
||||
/// The diffusion parameter field
|
||||
Coefficient *kappa;
|
||||
/// Dimension of the problem
|
||||
int dim;
|
||||
/// Velocity vector
|
||||
Vector a;
|
||||
|
||||
public:
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a a the convection velocity
|
||||
- @a d the diffusion coefficient*/
|
||||
Tau (VectorCoefficient *a_, Coefficient *k) : adv(a_), kappa(k)
|
||||
{
|
||||
dim = adv->GetVDim();
|
||||
a.SetSize(dim);
|
||||
};
|
||||
/// Simple Constructor
|
||||
Tau () : adv(nullptr), kappa(nullptr) {};
|
||||
|
||||
/// Set the convection coefficient
|
||||
virtual void SetConvection(VectorCoefficient *a_)
|
||||
{
|
||||
adv = a_;
|
||||
dim = adv->GetVDim();
|
||||
a.SetSize(dim);
|
||||
};
|
||||
|
||||
/// Set the convection coefficient
|
||||
virtual void SetDiffusion(Coefficient *k_) { kappa = k_; };
|
||||
|
||||
/// Flag for printing
|
||||
bool print = true;
|
||||
};
|
||||
|
||||
/** This Class defines the stabilisation parameter for the multi-dimensional
|
||||
convection-diffusion problem.
|
||||
When @a k_fac =2 the parameter is defined as given in:
|
||||
|
||||
Franca, L.P., Frey, S.L., & Hughes, T.J.R.
|
||||
Stabilized finite element methods:
|
||||
I. Application to the advective-diffusive model.
|
||||
Computer Methods in Applied Mechanics and Engineering, 95(2), 253-276.
|
||||
|
||||
This also works for the convection-diffusion part of the navier-Stokes problem.
|
||||
When @a k_fac = 4 the parameter is defined as given in:
|
||||
|
||||
Franca, L.P., Frey, S.L.,
|
||||
Stabilized finite element methods:
|
||||
II. The incompressible Navier-Stokes equations.
|
||||
Computer Methods in Applied Mechanics and Engineering, 99(2-3), 209-233.
|
||||
*/
|
||||
class FFH92Tau: public Tau
|
||||
{
|
||||
protected:
|
||||
/// User provided inverse estimate of the elements
|
||||
real_t Ci = -1.0;
|
||||
|
||||
/// If @a Ci is negative the is inverse estimate computed
|
||||
Coefficient *invEst_cf = nullptr;
|
||||
bool own_ie = false;
|
||||
|
||||
// Routine to get the inverse estimate at each point
|
||||
real_t GetInverseEstimate(ElementTransformation &T,
|
||||
const IntegrationPoint &ip, real_t scale = 1.0);
|
||||
|
||||
/// The norm used for the velocity vector
|
||||
real_t p = 2.0;
|
||||
|
||||
/// The facor used for computing the element Peclet/Reynolds number
|
||||
real_t k_fac = 2.0;
|
||||
|
||||
/// Temp variable
|
||||
Vector row;
|
||||
|
||||
/// Element size in different directions
|
||||
Vector h;
|
||||
|
||||
/** Returns element size according to:
|
||||
|
||||
Harari, I, & Hughes, T.J.R.
|
||||
What are C and h?: Inequalities for the analysis and design of
|
||||
finite element methods.
|
||||
Computer methods in applied mechanics and engineering 97(2), 157-192.
|
||||
*/
|
||||
real_t GetElementSize(ElementTransformation &T);
|
||||
|
||||
public:
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a a the convection velocity
|
||||
- @a d the diffusion coefficient
|
||||
- @a ie_cf for computing the inverse estimates
|
||||
- @a f factor for computing the element Pe/Re number (default = 2)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2) */
|
||||
FFH92Tau (VectorCoefficient *a, Coefficient *k, Coefficient *ie_cf,
|
||||
real_t f = 2.0, real_t norm_p = 2.0)
|
||||
: Tau(a,k), invEst_cf(ie_cf), Ci(-1.0), k_fac(f), p(norm_p) {};
|
||||
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a a the convection velocity
|
||||
- @a d the diffusion coefficient
|
||||
- @a fes to provide to coefficient for computing the inverse estimates
|
||||
- @a f factor for computing the element Pe/Re number (default = 2)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2) */
|
||||
FFH92Tau (VectorCoefficient *a, Coefficient *k,
|
||||
FiniteElementSpace *fes,
|
||||
real_t f = 2.0, real_t norm_p = 2.0)
|
||||
: Tau(a,k), Ci(-1.0), k_fac(f), p(norm_p)
|
||||
{
|
||||
invEst_cf = new InverseEstimateCoefficient(fes);
|
||||
own_ie = true;
|
||||
};
|
||||
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a a the convection velocity
|
||||
- @a d the diffusion coefficient
|
||||
- @a c_explicity provided inverse estimate (default = 1.0/12.0)
|
||||
- @a f factor for computing the element Pe/Re number (default = 2)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2)*/
|
||||
FFH92Tau (VectorCoefficient *a, Coefficient *k,
|
||||
real_t c_ = 1.0/12.0, real_t f = 2.0, real_t norm_p = 2.0)
|
||||
: Tau(a,k), Ci(c_), k_fac(f), p(norm_p)
|
||||
{
|
||||
invEst_cf = NULL;
|
||||
};
|
||||
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a ie_cf for computing the inverse estimatestes
|
||||
- @a f factor for Pe/Re definition (default = 2)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2)
|
||||
Convection and diffusion need to be specified later using
|
||||
SetConvection and SetDiffusion, respectivly*/
|
||||
FFH92Tau (Coefficient *ie_cf,
|
||||
real_t f = 2.0, real_t norm_p = 2.0)
|
||||
: invEst_cf(ie_cf), Ci(-1.0), k_fac(f) , p(norm_p) {};
|
||||
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a fes to provide to coefficient for computing the inverse estimates
|
||||
- @a f factor for Pe/Re definition (default = 2)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2)
|
||||
Convection and diffusion need to be specified later using
|
||||
SetConvection and SetDiffusion, respectivly*/
|
||||
FFH92Tau (FiniteElementSpace *fes,
|
||||
real_t f = 2.0, real_t norm_p = 2.0)
|
||||
: Ci(-1.0), k_fac(f) , p(norm_p)
|
||||
{
|
||||
invEst_cf = new InverseEstimateCoefficient(fes);
|
||||
own_ie = true;
|
||||
};
|
||||
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a c_explicity provided inverse estimate (default = 1.0/12.0)
|
||||
- @a f factor for computing the element Pe/Re number (default = 2)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2)
|
||||
Convection and diffusion need to be specified later using
|
||||
SetConvection and SetDiffusion, respectivly*/
|
||||
FFH92Tau (real_t c_ = 1.0/12.0, real_t f = 2.0, real_t norm_p = 2.0)
|
||||
: Ci(c_), k_fac(f), p(norm_p)
|
||||
{
|
||||
invEst_cf = NULL;
|
||||
};
|
||||
|
||||
/// Evaluate the coefficient at @a ip.
|
||||
virtual real_t Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip) override;
|
||||
|
||||
// Destructor
|
||||
~FFH92Tau()
|
||||
{ if (own_ie) { delete invEst_cf; } }
|
||||
};
|
||||
|
||||
/** This Class defines the stabilisation parameter for the multi-dimensional
|
||||
convection-diffusion problem.
|
||||
|
||||
This also works for the convection-diffusion part of the navier-Stokes problem.
|
||||
|
||||
Franca, L.P., Frey, S.L.,
|
||||
Stabilized finite element methods:
|
||||
II. The incompressible Navier-Stokes equations.
|
||||
Computer Methods in Applied Mechanics and Engineering, 99(2-3), 209-233.
|
||||
*/
|
||||
class FF91Delta: public FFH92Tau
|
||||
{
|
||||
protected:
|
||||
/// Overall scalling parameter
|
||||
real_t lambda = 1.0;
|
||||
|
||||
public:
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a a the convection velocity
|
||||
- @a d the diffusion coefficient
|
||||
- @a ie_cf for computing the inverse estimates
|
||||
- @a f factor for computing the element Pe/Re number (default = 2)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2) */
|
||||
FF91Delta (VectorCoefficient *a, Coefficient *k, Coefficient *ie_cf,
|
||||
real_t l = 1.0, real_t f = 2.0, real_t norm_p = 2.0)
|
||||
: FFH92Tau(a,k,ie_cf,f,norm_p), lambda(l){};
|
||||
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a a the convection velocity
|
||||
- @a d the diffusion coefficient
|
||||
- @a fes for computing the inverse estimates
|
||||
- @a l overall scalling factor for delta (default = 1)
|
||||
- @a f factor for computing the element Pe/Re number (default = 4)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2) */
|
||||
FF91Delta (VectorCoefficient *a, Coefficient *k,
|
||||
FiniteElementSpace *fes,
|
||||
real_t l = 1.0,
|
||||
real_t f = 4.0, real_t norm_p = 2.0)
|
||||
: FFH92Tau(a,k,fes,f,norm_p), lambda(l){};
|
||||
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a a the convection velocity
|
||||
- @a d the diffusion coefficient
|
||||
- @a c_explicity provided inverse estimate (default = 1.0/12.0)
|
||||
- @a l overall scalling factor for delta (default = 1)
|
||||
- @a f factor for computing the element Pe/Re number (default = 4)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2)*/
|
||||
FF91Delta (VectorCoefficient *a, Coefficient *k,
|
||||
real_t c_ = 1.0/12.0, real_t l = 1.0,
|
||||
real_t f = 4.0, real_t norm_p = 2.0)
|
||||
: FFH92Tau(a,k,c_,f,norm_p), lambda(l){};
|
||||
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a ie_cf for computing the inverse estimatestes
|
||||
- @a f factor for Pe/Re definition (default = 2)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2)
|
||||
Convection and diffusion need to be specified later using
|
||||
SetConvection and SetDiffusion, respectivly*/
|
||||
FF91Delta (Coefficient *ie_cf,
|
||||
real_t l = 1.0, real_t f = 2.0, real_t norm_p = 2.0)
|
||||
: FFH92Tau(ie_cf,f,norm_p), lambda(l){};
|
||||
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a fes for computing the inverse estimates
|
||||
- @a f factor for Pe/Re definition (default = 2)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2)
|
||||
Convection and diffusion need to be specified later using
|
||||
SetConvection and SetDiffusion, respectivly*/
|
||||
FF91Delta (FiniteElementSpace *fes,
|
||||
real_t l = 1.0, real_t f = 4.0, real_t norm_p = 2.0)
|
||||
: FFH92Tau(fes,f,norm_p), lambda(l){};
|
||||
|
||||
/** Construct a stabilized confection-diffusion integrator with:
|
||||
- @a c_explicity provided inverse estimate (default = 1.0/12.0)
|
||||
- @a l overall scalling factor for delta (default = 1)
|
||||
- @a f factor for computing the element Pe/Re number (default = 4)
|
||||
- @a p which norm to use for the velocity magnitude (default = 2)
|
||||
Convection and diffusion need to be specified later using
|
||||
SetConvection and SetDiffusion, respectivly*/
|
||||
FF91Delta (real_t c_ = 1.0/12.0, real_t l = 1.0,
|
||||
real_t f = 2.0, real_t norm_p = 2.0)
|
||||
: FFH92Tau(c_,f,norm_p), lambda(l){};
|
||||
|
||||
/// Evaluate the coefficient at @a ip.
|
||||
virtual real_t Eval(ElementTransformation &T,
|
||||
const IntegrationPoint &ip) override;
|
||||
|
||||
// Destructor
|
||||
~FF91Delta(){};
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,453 @@
|
||||
// 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.
|
||||
//
|
||||
// -----------------------------------------
|
||||
// Tribol Miniapp: Mortar contact patch test
|
||||
// -----------------------------------------
|
||||
//
|
||||
//
|
||||
// Command line options:
|
||||
// - -r, --refine: number of uniform refinements of the mesh (default: 2)
|
||||
//
|
||||
|
||||
#include "mfem.hpp"
|
||||
|
||||
#include "axom/slic.hpp"
|
||||
|
||||
#include "tribol/interface/tribol.hpp"
|
||||
#include "tribol/interface/mfem_tribol.hpp"
|
||||
|
||||
// Define MPI_REAL_T
|
||||
#if defined(MFEM_USE_DOUBLE)
|
||||
#define MPI_REAL_T MPI_DOUBLE
|
||||
#else
|
||||
#error "Tribol requires MFEM built with double precision!"
|
||||
#endif
|
||||
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
class ContactObj
|
||||
{
|
||||
protected:
|
||||
HypreParMatrix * Jacobian = nullptr;
|
||||
mfem::Vector gap;
|
||||
std::unique_ptr<mfem::BlockOperator> A_blk;
|
||||
ParMesh * mesh = nullptr;
|
||||
ParGridFunction * coords = nullptr;
|
||||
std::set<int> mortar_attrs;
|
||||
std::set<int> nonmortar_attrs;
|
||||
public:
|
||||
ContactObj(ParMesh * mesh_,
|
||||
const std::set<int> & mortar_attrs_,
|
||||
const std::set<int> & nonmortar_attrs_,
|
||||
ParGridFunction * coords_);
|
||||
void GetGap(mfem::Vector & g) const;
|
||||
mfem::HypreParMatrix * GetJacobian() const;
|
||||
virtual ~ContactObj();
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Initialize MPI
|
||||
mfem::Mpi::Init();
|
||||
|
||||
// Initialize logging with axom::slic
|
||||
axom::slic::SimpleLogger logger;
|
||||
axom::slic::setIsRoot(mfem::Mpi::Root());
|
||||
|
||||
// Define command line options
|
||||
int ref_levels = 2; // number of times to uniformly refine the serial mesh
|
||||
double u0shift = 0.0;
|
||||
bool outputfiles = false;
|
||||
// Parse command line options
|
||||
mfem::OptionsParser args(argc, argv);
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly.");
|
||||
args.AddOption(&u0shift, "-u0shift", "--u0shift", "magnitude (inf norm) of random displacement where finite difference test is evaluated");
|
||||
args.AddOption(&outputfiles, "-out", "--output", "-no-out",
|
||||
"--no-ouput",
|
||||
"Enable or disable ouput to files.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
args.PrintUsage(std::cout);
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
args.PrintOptions(std::cout);
|
||||
}
|
||||
|
||||
// Fixed options
|
||||
// two block mesh; bottom block = [0,1]^3 and top block = [0,1]x[0,1]x[0.99,1.99]
|
||||
std::string mesh_file = "modified-two-hex.mesh";
|
||||
// Problem dimension (NOTE: Tribol's mortar only works in 3D)
|
||||
constexpr int dim = 3;
|
||||
// FE polynomial degree (NOTE: only 1 works for now)
|
||||
constexpr int order = 1;
|
||||
// z=1 plane of bottom block (contact plane)
|
||||
std::set<int> mortar_attrs({4});
|
||||
// z=0.99 plane of top block (contact plane)
|
||||
std::set<int> nonmortar_attrs({5});
|
||||
// per-dimension sets of boundary attributes with homogeneous Dirichlet BCs.
|
||||
// allows transverse deformation of the blocks while precluding rigid body
|
||||
// rotations/translations.
|
||||
std::vector<std::set<int>> fixed_attrs(dim);
|
||||
fixed_attrs[0] = {1}; // x=0 plane of both blocks
|
||||
fixed_attrs[1] = {2}; // y=0 plane of both blocks
|
||||
fixed_attrs[2] = {3, 6}; // 3: z=0 plane of bottom block; 6: z=1.99 plane of top block
|
||||
|
||||
// Read the mesh, refine, and create a mfem::ParMesh
|
||||
mfem::Mesh serial_mesh(mesh_file);
|
||||
for (int i = 0; i < ref_levels; ++i)
|
||||
{
|
||||
serial_mesh.UniformRefinement();
|
||||
}
|
||||
mfem::ParMesh mesh(MPI_COMM_WORLD, serial_mesh);
|
||||
mfem::ParMesh mesh_copy(mesh);
|
||||
|
||||
serial_mesh.Clear();
|
||||
|
||||
MFEM_ASSERT(dim == mesh.Dimension(),
|
||||
"This miniapp must be run with the supplied two-hex.mesh file.");
|
||||
|
||||
// Create an H1 finite element space on the mesh for displacements/forces
|
||||
mfem::H1_FECollection fec(order, dim);
|
||||
mfem::ParFiniteElementSpace fespace(&mesh, &fec, dim);
|
||||
auto n_displacement_dofs = fespace.GlobalTrueVSize();
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of displacement unknowns: " << n_displacement_dofs <<
|
||||
std::endl;
|
||||
}
|
||||
|
||||
// Create coordinate and displacement grid functions
|
||||
mfem::ParGridFunction coords(&fespace);
|
||||
mesh.SetNodalGridFunction(&coords);
|
||||
mfem::ParGridFunction displacement(&fespace);
|
||||
displacement = 0.0;
|
||||
|
||||
// Find true dofs with homogeneous Dirichlet BCs
|
||||
mfem::Array<int> ess_tdof_list;
|
||||
{
|
||||
mfem::Array<int> ess_vdof_marker(fespace.GetVSize());
|
||||
ess_vdof_marker = 0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
mfem::Array<int> ess_bdr(mesh.bdr_attributes.Max());
|
||||
ess_bdr = 0;
|
||||
for (auto xfixed_attr : fixed_attrs[i])
|
||||
{
|
||||
ess_bdr[xfixed_attr-1] = 1;
|
||||
}
|
||||
mfem::Array<int> new_ess_vdof_marker;
|
||||
fespace.GetEssentialVDofs(ess_bdr, new_ess_vdof_marker, i);
|
||||
for (int j = 0; j < new_ess_vdof_marker.Size(); ++j)
|
||||
{
|
||||
ess_vdof_marker[j] = ess_vdof_marker[j] || new_ess_vdof_marker[j];
|
||||
}
|
||||
}
|
||||
mfem::Array<int> ess_tdof_marker;
|
||||
fespace.GetRestrictionMatrix()->BooleanMult(ess_vdof_marker, ess_tdof_marker);
|
||||
mfem::FiniteElementSpace::MarkerToList(ess_tdof_marker, ess_tdof_list);
|
||||
}
|
||||
|
||||
// #1: Initialize Tribol contact library
|
||||
tribol::initialize(dim, MPI_COMM_WORLD);
|
||||
|
||||
|
||||
/* Begin Tucker addition
|
||||
* finite difference check of the gap function Jacobian at u = u0
|
||||
* we evaluate the norm of the finite difference residual
|
||||
* err(eps) = || (g(u0 + eps * udir) - g(u0)) / eps - J(u0) * udir ||_2
|
||||
* which in the absence of finite-precision
|
||||
* err(eps) = O(eps) when the gap is not linear
|
||||
* err(eps) = 0, when the gap is linear
|
||||
*/
|
||||
int dimU = fespace.GetTrueVSize();
|
||||
Vector u0(dimU); u0 = 0.0;
|
||||
Vector u1(dimU); u1 = 0.0;
|
||||
Vector udir(dimU); udir = 0.0; udir.Randomize(); udir *= 1.e-2;
|
||||
|
||||
Array<int> vdofs;
|
||||
for (int i = 0; i < mesh.GetNBE(); i++)
|
||||
{
|
||||
const int attr = (mesh.GetBdrElement(i))->GetAttribute();
|
||||
if (attr == 4)
|
||||
{
|
||||
fespace.GetBdrElementVDofs(i, vdofs);
|
||||
for (int j = 0; j < vdofs.Size(); j++)
|
||||
{
|
||||
if (j / 4 == 2)
|
||||
{
|
||||
u0(vdofs[j]) = -1.0 * u0shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ParGridFunction new_coords(&fespace);
|
||||
mesh.GetNodes(new_coords);
|
||||
|
||||
// evaluate the gap and gap Jacobian at u = u0
|
||||
u1.Set(1.0, u0);
|
||||
displacement.SetFromTrueDofs(u1);
|
||||
add(coords, displacement, new_coords);
|
||||
|
||||
ContactObj contact0(&mesh, mortar_attrs, nonmortar_attrs, &new_coords);
|
||||
HypreParMatrix * J0 = contact0.GetJacobian();
|
||||
int dimG = J0->Height();
|
||||
|
||||
Vector g0(dimG); g0 = 0.0; contact0.GetGap(g0);
|
||||
Vector g1(dimG); g1 = 0.0;
|
||||
|
||||
// finite difference residual
|
||||
Vector fdres(dimG); fdres = 0.0;
|
||||
|
||||
// J0udir = J(u0) * udir
|
||||
Vector J0udir(dimG); J0->Mult(udir, J0udir);
|
||||
|
||||
// output various configurations
|
||||
// to visualize u = u0, u = u0 + eps * udir
|
||||
// use linear adjustment for eps here
|
||||
std::ostringstream paraview_file_name;
|
||||
paraview_file_name << "BlockConfigurations_ref_" << ref_levels << "shift" << u0shift;
|
||||
ParaViewDataCollection * paraview_dc = new ParaViewDataCollection(paraview_file_name.str(), &mesh_copy);
|
||||
paraview_dc->SetPrefixPath("ParaView");
|
||||
paraview_dc->SetLevelsOfDetail(1);
|
||||
paraview_dc->SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc->SetHighOrderOutput(true);
|
||||
paraview_dc->SetCycle(0);
|
||||
paraview_dc->SetTime(double(0));
|
||||
paraview_dc->Save();
|
||||
|
||||
std::ofstream fdepsStream;
|
||||
std::ostringstream fdeps_file_name;
|
||||
fdeps_file_name << "data/fdeps.dat";
|
||||
|
||||
std::ofstream fderrStream;
|
||||
std::ostringstream fderr_file_name;
|
||||
fderr_file_name << "data/fderr.dat";
|
||||
|
||||
// write new configuration (reference coordinates + displacement u0) to file
|
||||
u1.Set(1.0, u0);
|
||||
displacement.SetFromTrueDofs(u1);
|
||||
add(coords, displacement, new_coords);
|
||||
|
||||
Vector config(u0.Size()); config = 0.0;
|
||||
new_coords.GetTrueDofs(config);
|
||||
|
||||
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
fdepsStream.open(fdeps_file_name.str(), std::ios::out | std::ios::trunc);
|
||||
fderrStream.open(fderr_file_name.str(), std::ios::out | std::ios::trunc);
|
||||
}
|
||||
|
||||
double eps = 1.0;
|
||||
int neps = 40;
|
||||
for (int i = 0; i < neps; i++) // eps_min = 0.5^(39) \approx 10^(-12)
|
||||
{
|
||||
// compute g1 = g(u1), u1 = u0 + eps * udir
|
||||
u1.Set(1.0, u0);
|
||||
u1.Add(eps, udir);
|
||||
displacement.SetFromTrueDofs(u1);
|
||||
add(coords, displacement, new_coords);
|
||||
ContactObj contact1(&mesh, mortar_attrs, nonmortar_attrs, &new_coords);
|
||||
contact1.GetGap(g1);
|
||||
|
||||
// determine finite difference residual: fdres = (g1 - g0) / eps - J0 * udir
|
||||
fdres.Set(1. / eps, g1);
|
||||
fdres.Add(-1. / eps, g0);
|
||||
fdres.Add(-1, J0udir);
|
||||
double fderr_l2norm = GlobalLpNorm(2, fdres.Norml2(), MPI_COMM_WORLD);
|
||||
double udir_l2norm = GlobalLpNorm(2, udir.Norml2(), MPI_COMM_WORLD);
|
||||
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "--------------------------------------------\n\n";
|
||||
std::cout << "||(g(u0 + eps * udir) - g(u0)) / eps - J(u0) * udir|| = " << fderr_l2norm << ", eps = " << eps << "\n\n";
|
||||
std::cout << "||(g(u0 + eps * udir) - g(u0)) / eps - J(u0) * udir||_2 / ||udir||_2 = " << fderr_l2norm / udir_l2norm << std::endl;
|
||||
}
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
fdepsStream << eps << std::endl;
|
||||
fderrStream << fderr_l2norm << std::endl;
|
||||
}
|
||||
eps /= 2.0;
|
||||
}
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
fdepsStream.close();
|
||||
fderrStream.close();
|
||||
}
|
||||
|
||||
|
||||
/* What follows we linearly modify epsilon
|
||||
* output the gap, in order to check for discontinuities
|
||||
* and also output the various states u0 + eps * udir to file
|
||||
* in order to visualize the mesh configurations *
|
||||
* */
|
||||
eps = 1.0;
|
||||
neps = 100;
|
||||
double deps = eps / ((double) neps);
|
||||
std::ofstream epsStream;
|
||||
std::ostringstream eps_file_name;
|
||||
eps_file_name << "data/eps_ref_" << ref_levels << ".dat";
|
||||
|
||||
std::ofstream gapStream;
|
||||
std::ostringstream gap_file_name;
|
||||
gap_file_name << "data/gap_ref_" << ref_levels << ".dat";
|
||||
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
epsStream.open(eps_file_name.str(), std::ios::out | std::ios::trunc);
|
||||
gapStream.open(gap_file_name.str(), std::ios::out | std::ios::trunc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i < neps; i++)
|
||||
{
|
||||
// compute g1 = g(u1), u1 = u0 + eps * udir
|
||||
u1.Set(1.0, u0);
|
||||
u1.Add(eps, udir);
|
||||
displacement.SetFromTrueDofs(u1);
|
||||
add(coords, displacement, new_coords);
|
||||
ContactObj contact1(&mesh, mortar_attrs, nonmortar_attrs, &new_coords);
|
||||
contact1.GetGap(g1);
|
||||
double gap_l2norm = GlobalLpNorm(2, g1.Norml2(), MPI_COMM_WORLD);
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
epsStream << eps << std::endl;
|
||||
gapStream << g1.Norml2() << std::endl;
|
||||
}
|
||||
|
||||
// update mesh according to u1 and write to Paraview for visualization
|
||||
mesh_copy.SetNodes(new_coords);
|
||||
paraview_dc->SetCycle(i+1) ;
|
||||
paraview_dc->SetTime((double) (i+1));
|
||||
paraview_dc->Save();
|
||||
|
||||
// linear update to eps: eps = eps - deps
|
||||
eps -= deps;
|
||||
}
|
||||
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
epsStream.close();
|
||||
gapStream.close();
|
||||
}
|
||||
|
||||
// #7: Tribol cleanup: deletes coupling schemes and clears associated memory
|
||||
tribol::finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ContactObj::ContactObj(ParMesh * mesh_, const std::set<int> & mortar_attrs_,
|
||||
const std::set<int> & nonmortar_attrs_,
|
||||
ParGridFunction * coords_) :
|
||||
mesh(mesh_), mortar_attrs(mortar_attrs_),
|
||||
nonmortar_attrs(nonmortar_attrs_),
|
||||
coords(coords_)
|
||||
{
|
||||
// #2: Create a Tribol coupling scheme: defines contact surfaces and enforcement
|
||||
int coupling_scheme_id = 0;
|
||||
// NOTE: While there is a single mfem ParMesh for this problem, Tribol
|
||||
// defines a mortar and a nonmortar contact mesh, each with a unique mesh ID.
|
||||
// The Tribol mesh IDs for each contact surface are defined here.
|
||||
int mesh1_id = 0;
|
||||
int mesh2_id = 1;
|
||||
tribol::registerMfemCouplingScheme(
|
||||
coupling_scheme_id, mesh1_id, mesh2_id,
|
||||
*mesh, *coords, mortar_attrs, nonmortar_attrs,
|
||||
tribol::SURFACE_TO_SURFACE,
|
||||
tribol::NO_CASE,
|
||||
tribol::SINGLE_MORTAR,
|
||||
tribol::FRICTIONLESS,
|
||||
tribol::LAGRANGE_MULTIPLIER,
|
||||
tribol::BINNING_GRID
|
||||
);
|
||||
|
||||
// #3: Set additional options/access pressure grid function on contact surfaces
|
||||
// Access Tribol's pressure grid function (on the contact surface). The
|
||||
// pressure ParGridFunction is created upon calling
|
||||
// registerMfemCouplingScheme(). It's lifetime coincides with the lifetime of
|
||||
// the coupling scheme, so the host code can reference and update it as
|
||||
// needed.
|
||||
auto& pressure = tribol::getMfemPressure(coupling_scheme_id);
|
||||
|
||||
// Set Tribol options for Lagrange multiplier enforcement
|
||||
tribol::setLagrangeMultiplierOptions(
|
||||
coupling_scheme_id,
|
||||
tribol::ImplicitEvalMode::MORTAR_RESIDUAL_JACOBIAN
|
||||
);
|
||||
|
||||
// #4: Update contact mesh decomposition so the on-rank Tribol meshes
|
||||
// coincide with the current configuration of the mesh. This must be called
|
||||
// before tribol::update().
|
||||
tribol::updateMfemParallelDecomposition();
|
||||
|
||||
// #5: Update contact gaps, forces, and tangent stiffness contributions
|
||||
int cycle = 1; // pseudo cycle
|
||||
mfem::real_t t = 1.0; // pseudo time
|
||||
mfem::real_t dt = 1.0; // pseudo dt
|
||||
tribol::update(cycle, t, dt);
|
||||
|
||||
|
||||
// #6a: Return contact contribution to the tangent stiffness matrix as a
|
||||
// block operator. See documentation for getMfemBlockJacobian() for block
|
||||
// definitions.
|
||||
//auto A_blk = tribol::getMfemBlockJacobian(coupling_scheme_id);
|
||||
A_blk = tribol::getMfemBlockJacobian(coupling_scheme_id);
|
||||
Jacobian = (HypreParMatrix *)(& A_blk->GetBlock(1, 0));
|
||||
|
||||
|
||||
mfem::BlockVector B_blk(A_blk->RowOffsets());
|
||||
B_blk = 0.0;
|
||||
|
||||
// Fill with initial nodal gaps.
|
||||
// Note forces from contact are currently zero since pressure is zero prior
|
||||
// to first solve.
|
||||
mfem::Vector gap_temp;
|
||||
// #6b: Return computed gap constraints on the contact surfaces
|
||||
tribol::getMfemGap(coupling_scheme_id, gap_temp); // gap on ldofs
|
||||
auto& P_submesh = *pressure.ParFESpace()->GetProlongationMatrix();
|
||||
//auto& gap_true = B_blk.GetBlock(1); // gap tdof vectorParFESpace()
|
||||
// gap is a dual vector, so (gap tdof vector) = P^T * (gap ldof vector)
|
||||
gap.SetSize(P_submesh.Width()); gap = 0.0;
|
||||
|
||||
P_submesh.MultTranspose(gap_temp, gap);
|
||||
}
|
||||
|
||||
void ContactObj::GetGap(mfem::Vector & g) const
|
||||
{
|
||||
g.SetSize(gap.Size());
|
||||
g.Set(1.0, gap);
|
||||
}
|
||||
|
||||
|
||||
mfem::HypreParMatrix * ContactObj::GetJacobian() const
|
||||
{
|
||||
return Jacobian;
|
||||
}
|
||||
|
||||
ContactObj::~ContactObj()
|
||||
{
|
||||
}
|
||||
@@ -22,7 +22,7 @@ MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
ifeq ($(MFEM_USE_TRIBOL)$(MFEM_USE_MPI),YESYES)
|
||||
MINIAPPS = contact-patch-test
|
||||
MINIAPPS = contact-patch-test contact-patch-finite-difference-test
|
||||
else
|
||||
MINIAPPS =
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
# two unit cubes occupying [0,1]^3 and [0,1]x[0,1]x[0.99,1.99]
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
2
|
||||
1 5 0 1 3 2 4 5 7 6
|
||||
1 5 8 9 11 10 12 13 15 14
|
||||
|
||||
boundary
|
||||
12
|
||||
3 3 2 3 1 0
|
||||
2 3 0 1 5 4
|
||||
7 3 3 2 6 7
|
||||
1 3 2 0 4 6
|
||||
4 3 4 5 7 6
|
||||
7 3 1 3 7 5
|
||||
5 3 10 11 9 8
|
||||
2 3 8 9 13 12
|
||||
7 3 11 10 14 15
|
||||
1 3 10 8 12 14
|
||||
6 3 12 13 15 14
|
||||
7 3 9 11 15 13
|
||||
|
||||
vertices
|
||||
16
|
||||
3
|
||||
0.25 0.25 0
|
||||
0.75 0.25 0
|
||||
0.25 0.75 0
|
||||
0.75 0.75 0
|
||||
0.25 0.25 1
|
||||
0.75 0.25 1
|
||||
0.25 0.75 1
|
||||
0.75 0.75 1
|
||||
0 0 1.00
|
||||
1 0 1.00
|
||||
0 1 1.00
|
||||
1 1 1.00
|
||||
0 0 2.00
|
||||
1 0 2.00
|
||||
0 1 2.00
|
||||
1 1 2.00
|
||||
@@ -47,11 +47,11 @@ vertices
|
||||
1 0 1
|
||||
0 1 1
|
||||
1 1 1
|
||||
0 0 0.99
|
||||
1 0 0.99
|
||||
0 1 0.99
|
||||
1 1 0.99
|
||||
0 0 1.01
|
||||
1 0 1.01
|
||||
0 1 1.01
|
||||
1 1 1.01
|
||||
0 0 1.99
|
||||
1 0 1.99
|
||||
0 1 1.99
|
||||
1 1 1.99
|
||||
1 1 1.99
|
||||
|
||||
@@ -1,298 +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 "unit_tests.hpp"
|
||||
#include "mfem.hpp"
|
||||
|
||||
using namespace mfem;
|
||||
namespace hptransfer_test
|
||||
{
|
||||
|
||||
int order=1;
|
||||
|
||||
double u(const Vector & x)
|
||||
{
|
||||
return pow(x.Sum(),order);
|
||||
}
|
||||
|
||||
void vecu(const Vector & x, Vector & U)
|
||||
{
|
||||
for (int i = 0; i<x.Size(); i++)
|
||||
{
|
||||
U[i] = pow(x[i], order);
|
||||
}
|
||||
}
|
||||
|
||||
void RandomPRefinement(FiniteElementSpace & fes)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
for (int i = 0; i < mesh->GetNE(); i++)
|
||||
{
|
||||
if ((double) rand() / RAND_MAX < 0.5)
|
||||
{
|
||||
const int eorder = fes.GetElementOrder(i);
|
||||
fes.SetElementOrder(i,eorder+1);
|
||||
}
|
||||
}
|
||||
fes.Update(false);
|
||||
}
|
||||
|
||||
/* This function randomly selects elements to be de-refined and sets the
|
||||
order of the elements that share the same parent to their minimum */
|
||||
void PreprocessRandomDerefinement(FiniteElementSpace & fes, Array<int> &drefs,
|
||||
double prob=0.5)
|
||||
{
|
||||
Mesh * mesh = fes.GetMesh();
|
||||
const Table & dereftable = mesh->ncmesh->GetDerefinementTable();
|
||||
int dref = dereftable.Size();
|
||||
for (int i = 0; i < dref; i++)
|
||||
{
|
||||
if ((double) rand() / RAND_MAX < prob)
|
||||
{
|
||||
drefs.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Go through the possible derefinements and set the orders to minimum
|
||||
Array<int> row;
|
||||
for (int i = 0; i<drefs.Size(); i++)
|
||||
{
|
||||
dereftable.GetRow(drefs[i], row);
|
||||
int minorder = 100;
|
||||
for (int j = 0; j<row.Size(); j++)
|
||||
{
|
||||
minorder = std::min(minorder, fes.GetElementOrder(row[j]));
|
||||
}
|
||||
// set the min order
|
||||
for (int j = 0; j<row.Size(); j++)
|
||||
{
|
||||
fes.SetElementOrder(row[j],minorder);
|
||||
}
|
||||
}
|
||||
fes.Update(false);
|
||||
}
|
||||
|
||||
void Derefine(Mesh &mesh, const Array<int> &drefs)
|
||||
{
|
||||
const Table & dereftable = mesh.ncmesh->GetDerefinementTable();
|
||||
|
||||
Array<int> row;
|
||||
Vector errors(mesh.GetNE()); errors = infinity();
|
||||
for (int i = 0; i<drefs.Size(); i++)
|
||||
{
|
||||
dereftable.GetRow(drefs[i], row);
|
||||
for (int j = 0; j<row.Size(); j++)
|
||||
{
|
||||
errors[row[j]] = 0.0;
|
||||
}
|
||||
}
|
||||
mesh.DerefineByError(errors,1.0);
|
||||
}
|
||||
|
||||
enum class Space {H1, L2, VectorH1, VectorL2};
|
||||
|
||||
TEST_CASE("hpTransfer", "[hpTransfer]")
|
||||
{
|
||||
auto space = GENERATE(Space::H1, Space::L2, Space::VectorH1, Space::VectorL2);
|
||||
int dim = GENERATE(2,3);
|
||||
auto simplex = GENERATE(false, true);
|
||||
order = GENERATE(1,2);
|
||||
auto relax_conformity = GENERATE(false, true);
|
||||
|
||||
/* No need to distinguish between relaxed and full conformity in the DG case*/
|
||||
if ((space == Space::L2 || space == Space::VectorL2) && relax_conformity) { return; }
|
||||
|
||||
constexpr int ne = 3;
|
||||
|
||||
CAPTURE(space, dim, simplex, order, relax_conformity);
|
||||
|
||||
Mesh mesh;
|
||||
if (dim == 2)
|
||||
{
|
||||
Element::Type type = simplex ? Element::TRIANGLE : Element::QUADRILATERAL;
|
||||
mesh = Mesh::MakeCartesian2D(ne, ne, type, 1, 1.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Element::Type type = simplex ? Element::TETRAHEDRON : Element::HEXAHEDRON;
|
||||
mesh = Mesh::MakeCartesian3D(ne, ne, ne, type, 1.0, 1.0, 1.0);
|
||||
}
|
||||
mesh.EnsureNCMesh(true);
|
||||
|
||||
// 1. Set up initial state by randomly h- and p- refinement
|
||||
mesh.RandomRefinement(0.5);
|
||||
|
||||
FiniteElementCollection * fec = nullptr;
|
||||
if (space == Space::H1 || space == Space::VectorH1)
|
||||
{
|
||||
fec = new H1_FECollection(order, dim);
|
||||
}
|
||||
else
|
||||
{
|
||||
fec = new L2_FECollection(order, dim);
|
||||
}
|
||||
|
||||
int dimc = (space<=Space::L2) ? 1 : dim;
|
||||
FiniteElementSpace fes(&mesh, fec, dimc);
|
||||
fes.SetRelaxedHpConformity(relax_conformity);
|
||||
RandomPRefinement(fes);
|
||||
|
||||
// 2. Set up a GridFunction on the initial hp-mesh
|
||||
FunctionCoefficient f(u);
|
||||
VectorFunctionCoefficient vf(dim,vecu);
|
||||
GridFunction gf(&fes); gf = 0.0;
|
||||
if (space<=Space::L2)
|
||||
{
|
||||
gf.ProjectCoefficient(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
gf.ProjectCoefficient(vf);
|
||||
}
|
||||
|
||||
// 3. Randomly h-refine the mesh and transfer the GridFunction
|
||||
mesh.RandomRefinement(0.5);
|
||||
fes.Update();
|
||||
gf.Update();
|
||||
|
||||
GridFunction err_gf(&fes);
|
||||
if (space<=Space::L2)
|
||||
{
|
||||
err_gf.ProjectCoefficient(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
err_gf.ProjectCoefficient(vf);
|
||||
}
|
||||
err_gf-= gf;
|
||||
|
||||
if (fes.GetHpRestrictionMatrix())
|
||||
{
|
||||
Vector tmp0(fes.GetHpRestrictionMatrix()->Height());
|
||||
fes.GetHpRestrictionMatrix()->Mult(err_gf,tmp0);
|
||||
fes.GetProlongationMatrix()->Mult(tmp0,err_gf);
|
||||
}
|
||||
|
||||
// 3a. Check if the prolonged GridFunction to the h-refined
|
||||
// mesh exactly reproduces the polynomial GridFunction
|
||||
REQUIRE(err_gf.Norml2() < 1e-11);
|
||||
|
||||
// 4. Randomly p-refine the mesh and transfer the GridFunction
|
||||
Mesh cmesh(mesh);
|
||||
FiniteElementSpace cfes(&cmesh, fec, dimc);
|
||||
cfes.SetRelaxedHpConformity(relax_conformity);
|
||||
for (int i = 0; i<cmesh.GetNE(); i++)
|
||||
{
|
||||
cfes.SetElementOrder(i,fes.GetElementOrder(i));
|
||||
}
|
||||
cfes.Update(false);
|
||||
|
||||
RandomPRefinement(fes);
|
||||
PRefinementTransferOperator T(cfes, fes);
|
||||
|
||||
GridFunction hpgf(&fes);
|
||||
T.Mult(gf,hpgf);
|
||||
|
||||
err_gf.SetSpace(&fes);
|
||||
if (space<=Space::L2)
|
||||
{
|
||||
err_gf.ProjectCoefficient(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
err_gf.ProjectCoefficient(vf);
|
||||
}
|
||||
err_gf-= hpgf;
|
||||
|
||||
if (fes.GetHpRestrictionMatrix())
|
||||
{
|
||||
Vector tmp(fes.GetHpRestrictionMatrix()->Height());
|
||||
fes.GetHpRestrictionMatrix()->Mult(err_gf,tmp);
|
||||
fes.GetProlongationMatrix()->Mult(tmp,err_gf);
|
||||
}
|
||||
|
||||
// 4a. Check if the prolonged GridFunction to the p-refined
|
||||
// mesh exactly reproduces the polynomial GridFunction
|
||||
REQUIRE(err_gf.Norml2() < 1e-11);
|
||||
|
||||
// 5. Before randomly de-refining the mesh ensure that the elements
|
||||
// (of the same parent) that are going to be de-refined
|
||||
// have the same order
|
||||
Mesh fmesh(mesh);
|
||||
FiniteElementSpace ffes(&fmesh, fec, dimc);
|
||||
ffes.SetRelaxedHpConformity(relax_conformity);
|
||||
for (int i = 0; i<fmesh.GetNE(); i++)
|
||||
{
|
||||
ffes.SetElementOrder(i,fes.GetElementOrder(i));
|
||||
}
|
||||
ffes.Update(false);
|
||||
|
||||
Array<int> drefs;
|
||||
// lower the order of the children to their minimum
|
||||
PreprocessRandomDerefinement(fes, drefs);
|
||||
PRefinementTransferOperator T2(ffes, fes);
|
||||
gf.SetSpace(&fes);
|
||||
T2.Mult(hpgf, gf);
|
||||
|
||||
err_gf.SetSpace(&fes);
|
||||
if (space<=Space::L2)
|
||||
{
|
||||
err_gf.ProjectCoefficient(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
err_gf.ProjectCoefficient(vf);
|
||||
}
|
||||
err_gf-= gf;
|
||||
|
||||
if (fes.GetHpRestrictionMatrix())
|
||||
{
|
||||
Vector temp(fes.GetHpRestrictionMatrix()->Height());
|
||||
fes.GetHpRestrictionMatrix()->Mult(err_gf,temp);
|
||||
fes.GetProlongationMatrix()->Mult(temp,err_gf);
|
||||
}
|
||||
|
||||
// 5a. Check if the restricted GridFunction to the p-derefined
|
||||
// mesh exactly reproduces the polynomial GridFunction
|
||||
REQUIRE(err_gf.Norml2() < 1e-11);
|
||||
|
||||
// 6. De-refine the mesh and transfer the GridFunction
|
||||
Derefine(mesh,drefs);
|
||||
|
||||
fes.Update();
|
||||
gf.Update();
|
||||
|
||||
err_gf.SetSpace(&fes); err_gf = 0.0;
|
||||
if (space<=Space::L2)
|
||||
{
|
||||
err_gf.ProjectCoefficient(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
err_gf.ProjectCoefficient(vf);
|
||||
}
|
||||
|
||||
err_gf-= gf;
|
||||
|
||||
if (fes.GetHpRestrictionMatrix())
|
||||
{
|
||||
Vector temp(fes.GetHpRestrictionMatrix()->Height());
|
||||
fes.GetHpRestrictionMatrix()->Mult(err_gf,temp);
|
||||
fes.GetProlongationMatrix()->Mult(temp,err_gf);
|
||||
}
|
||||
|
||||
// 6a. Check if the restricted GridFunction to the de-refined
|
||||
// mesh exactly reproduces the polynomial GridFunction
|
||||
REQUIRE(err_gf.Norml2() < 1e-11);
|
||||
delete fec;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -686,7 +686,7 @@ TEST_CASE("Exponential", "[DenseMatrix]")
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
|
||||
enum class TestCase { GenEigSPD, GenEigGE, SVD, NULLSPACE};
|
||||
enum class TestCase { GenEigSPD, GenEigGE, SVD};
|
||||
std::string TestCaseName(TestCase testcase)
|
||||
{
|
||||
switch (testcase)
|
||||
@@ -697,8 +697,6 @@ std::string TestCaseName(TestCase testcase)
|
||||
return "Generalized Eigenvalue problem for a general matrix";
|
||||
case TestCase::SVD:
|
||||
return "Singular Value Decomposition for a general matrix";
|
||||
case TestCase::NULLSPACE:
|
||||
return "NULL space for a general matrix";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -707,7 +705,7 @@ TEST_CASE("Eigensystem Problems",
|
||||
"[DenseMatrix]")
|
||||
{
|
||||
auto testcase = GENERATE(TestCase::GenEigSPD, TestCase::GenEigGE,
|
||||
TestCase::SVD, TestCase::NULLSPACE);
|
||||
TestCase::SVD);
|
||||
|
||||
CAPTURE(TestCaseName(testcase));
|
||||
|
||||
@@ -842,37 +840,6 @@ TEST_CASE("Eigensystem Problems",
|
||||
REQUIRE(USVt.MaxMaxNorm() == MFEM_Approx(0.));
|
||||
}
|
||||
break;
|
||||
case TestCase::NULLSPACE:
|
||||
{
|
||||
|
||||
Vector ev, ev2;
|
||||
DenseMatrix evect, evect2;
|
||||
DenseMatrix A(M);
|
||||
A.Symmetrize();
|
||||
|
||||
A.Eigenvalues( ev, evect);
|
||||
mfem::out<<"ev = "; ev.Print(mfem::out,4);
|
||||
int N = M.Width();
|
||||
|
||||
DenseMatrix ns;
|
||||
int nss;
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
AddMult_a_VVt(-ev[i], Vector(evect.GetColumn(i),N), A);
|
||||
|
||||
A.Eigenvalues( ev2, evect2);
|
||||
mfem::out<<"ev = "; ev2.Print(mfem::out,4);
|
||||
A.NullSpace(ns, 1e-9);
|
||||
mfem::out<<"null = "; ev2.Print(mfem::out,4);
|
||||
REQUIRE(ns.Width() == i+1);
|
||||
REQUIRE(A.Eigenvalue() - ev2(3) == MFEM_Approx(0.));
|
||||
REQUIRE(A.Eigenvalue(0) - ev2(0) == MFEM_Approx(0.));
|
||||
REQUIRE(A.Eigenvalue(1) - ev2(1) == MFEM_Approx(0.));
|
||||
REQUIRE(A.Eigenvalue(2) - ev2(2) == MFEM_Approx(0.));
|
||||
REQUIRE(A.Eigenvalue(3) - ev2(3) == MFEM_Approx(0.));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user