Files
mfem/miniapps/shifted/extrapolate.cpp
T

220 lines
7.8 KiB
C++

// 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.
//
// ----------------------------------------------
// Extrapolation Miniapp: PDE-based extrapolation
// ----------------------------------------------
//
// This miniapp extrapolates a finite element function from a set of elements
// (known values) to the rest of the domain. The set of elements that contains
// the known values is specified by the positive values of a level set
// Coefficient. The known values are not modified. The miniapp supports two
// PDE-based approaches [1, 2], both of which rely on solving a sequence of
// advection problems in the direction of the unknown parts of the domain.
// The extrapolation can be constant (1st order), linear (2nd order), or
// quadratic (3rd order). These formal orders hold for a limited band around
// the zero level set, see the given references for more info.
//
// [1] Aslam, "A Partial Differential Equation Approach to Multidimensional
// Extrapolation", JCP 193(1), 2004.
// [2] Bochkov, Gibou, "PDE-Based Multidimensional Extrapolation of Scalar
// Fields over Interfaces with Kinks and High Curvatures", SISC 42(4), 2020.
//
// Compile with: make extrapolate
//
// Sample runs:
// mpirun -np 4 extrapolate -m "../../data/inline-segment.mesh" -rs 6 -ed 2
// mpirun -np 4 extrapolate -rs 5 -p 0 -ed 2
// mpirun -np 4 extrapolate -rs 5 -p 1 -ed 2
// mpirun -np 4 extrapolate -rs 5 -p 1 -et 1 -ed 1 -dg 1
// mpirun -np 4 extrapolate -m "../../data/inline-hex.mesh" -ed 1 -rs 1
// mpirun -np 4 extrapolate -m "../../data/inline-hex.mesh" -p 1 -ed 1 -rs 1
#include "extrapolator.hpp"
using namespace std;
using namespace mfem;
int problem = 0;
double domainLS(const Vector &coord)
{
// Map from [0,1] to [-1,1].
const int dim = coord.Size();
const double x = coord(0)*2.0 - 1.0,
y = (dim > 1) ? coord(1)*2.0 - 1.0 : 0.0,
z = (dim > 2) ? coord(2)*2.0 - 1.0 : 0.0;
switch (problem)
{
case 0:
{
// Sphere.
return 0.75 - sqrt(x*x + y*y + z*z + 1e-12);
}
case 1:
{
// Star.
MFEM_VERIFY(dim > 1, "Problem 1 is not applicable to 1D.");
return 0.60 - sqrt(x*x + y*y + z*z + 1e-12) +
0.25 * (y*y*y*y*y + 5.0*x*x*x*x*y - 10.0*x*x*y*y*y) /
pow(x*x + y*y + z*z + 1e-12, 2.5) *
std::cos(0.5*M_PI * z / 0.6);
}
default: MFEM_ABORT("Bad option for --problem!"); return 0.0;
}
}
double solution0(const Vector &coord)
{
// Map from [0,1] to [-1,1].
const int dim = coord.Size();
const double x = coord(0)*2.0 - 1.0 + 0.25,
y = (dim > 1) ? coord(1)*2.0 - 1.0 : 0.0,
z = (dim > 2) ? coord(2)*2.0 - 1.0 : 0.0;
return std::cos(M_PI * x) * std::cos(M_PI * y) * std::cos(M_PI * z);
}
void PrintNorm(int myid, Vector &v, std::string text)
{
double norm = v.Norml1();
MPI_Allreduce(MPI_IN_PLACE, &norm, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
if (myid == 0)
{
std::cout << std::setprecision(12) << std::fixed
<< text << norm << std::endl;
}
}
void PrintIntegral(int myid, ParGridFunction &g, std::string text)
{
ConstantCoefficient zero(0.0);
double norm = g.ComputeL1Error(zero);
if (myid == 0)
{
std::cout << std::setprecision(12) << std::fixed
<< text << norm << std::endl;
}
}
int main(int argc, char *argv[])
{
// Initialize MPI and HYPRE.
Mpi::Init();
int myid = Mpi::WorldRank();;
Hypre::Init();
// Parse command-line options.
const char *mesh_file = "../../data/inline-quad.mesh";
int rs_levels = 2;
Extrapolator::XtrapType ex_type = Extrapolator::ASLAM;
AdvectionOper::AdvectionMode dg_mode = AdvectionOper::HO;
int ex_degree = 1;
int order = 2;
double distance = 0.35;
bool vis_on = true;
int vis_steps_cnt = 50;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&rs_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption((int*)&ex_type, "-et", "--extrap-type",
"Extrapolation type: Aslam (0) or Bochkov (1).");
args.AddOption((int*)&dg_mode, "-dg", "--dg-mode",
"DG advection mode: 0 - Standard High-Order,\n\t"
" 1 - Low-Order Upwind Diffusion.");
args.AddOption(&ex_degree, "-ed", "--extrap-degree",
"Extrapolation degree: 0/1/2 for constant/linear/quadratic.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&distance, "-d", "--distance",
"Extrapolation distance.");
args.AddOption(&problem, "-p", "--problem",
"0 - 2D circle,\n\t"
"1 - 2D star");
args.AddOption(&vis_on, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&vis_steps_cnt, "-vs", "--visualization-steps",
"Visualize every n-th timestep.");
args.Parse();
if (!args.Good())
{
if (myid == 0) { args.PrintUsage(cout); }
return 1;
}
if (myid == 0) { args.PrintOptions(cout); }
// Refine the mesh and distribute.
Mesh mesh(mesh_file, 1, 1);
for (int lev = 0; lev < rs_levels; lev++) { mesh.UniformRefinement(); }
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
const int dim = pmesh.Dimension();
// Input function.
L2_FECollection fec_L2(order, dim);
ParFiniteElementSpace pfes_L2(&pmesh, &fec_L2);
ParGridFunction u(&pfes_L2);
FunctionCoefficient u0_coeff(solution0);
u.ProjectCoefficient(u0_coeff);
// Extrapolate.
Extrapolator xtrap;
xtrap.xtrap_type = ex_type;
xtrap.advection_mode = dg_mode;
xtrap.xtrap_degree = ex_degree;
xtrap.visualization = vis_on;
xtrap.vis_steps = vis_steps_cnt;
FunctionCoefficient ls_coeff(domainLS);
ParGridFunction ux(&pfes_L2);
xtrap.Extrapolate(ls_coeff, u, distance, ux);
PrintNorm(myid, ux, "Solution l1 norm: ");
PrintIntegral(myid, ux, "Solution L1 norm: ");
GridFunctionCoefficient u_exact_coeff(&u);
double err_L1 = ux.ComputeL1Error(u_exact_coeff),
err_L2 = ux.ComputeL2Error(u_exact_coeff);
if (myid == 0)
{
std::cout << "Global L1 error: " << err_L1 << std::endl
<< "Global L2 error: " << err_L2 << std::endl;
}
double loc_error_L1, loc_error_L2, loc_error_LI;
xtrap.ComputeLocalErrors(ls_coeff, u, ux,
loc_error_L1, loc_error_L2, loc_error_LI);
if (myid == 0)
{
std::cout << "Local L1 error: " << loc_error_L1 << std::endl
<< "Local L2 error: " << loc_error_L2 << std::endl
<< "Local Li error: " << loc_error_LI << std::endl;
}
// ParaView output.
ParGridFunction ls_gf(&pfes_L2);
ls_gf.ProjectCoefficient(ls_coeff);
ParaViewDataCollection dacol("ParaViewExtrapolate", &pmesh);
dacol.SetLevelsOfDetail(order);
dacol.RegisterField("Level Set Function", &ls_gf);
dacol.RegisterField("Extrapolated Solution", &ux);
dacol.SetTime(1.0);
dacol.SetCycle(1);
dacol.Save();
return 0;
}