Commit 0adbd844 authored by Thomas Steinreiter's avatar Thomas Steinreiter
Browse files

refactoring

parent 0ebca407
......@@ -28,9 +28,9 @@ if (MPI_FOUND)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -xHost -std=c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -xHost -std=c++14")
endif()
set_target_properties(${NAME} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES)
set_target_properties(${NAME} PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED YES)
target_link_libraries(${NAME} ${LIBMESH_LIBRARY} ${MPI_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
install(TARGETS ${NAME} DESTINATION bin)
message("** Enabling '${NAME}': with MPI")
......
......@@ -48,36 +48,38 @@
#include "libmesh/euler_solver.h"
#include "libmesh/steady_solver.h"
// Bring in everything from the libMesh namespace
using namespace libMesh;
// user defined literal for libmesh's Real
constexpr auto operator"" _r(long double n) { return libMesh::Real(n); }
// The main program.
int main(int argc, char** argv) {
// Initialize libMesh.
LibMeshInit init(argc, argv);
libMesh::LibMeshInit init{argc, argv};
#ifndef LIBMESH_ENABLE_AMR
libmesh_example_requires(false, "--enable-amr");
#else
// This doesn't converge with Eigen BICGSTAB for some reason...
libmesh_example_requires(libMesh::default_solver_package() != EIGEN_SOLVERS,
libmesh_example_requires(libMesh::default_solver_package() !=
libMesh::EIGEN_SOLVERS,
"--enable-petsc");
// This doesn't converge without at least double precision
libmesh_example_requires(sizeof(Real) > 4, "--disable-singleprecision");
libmesh_example_requires(sizeof(libMesh::Real) > 4,
"--disable-singleprecision");
// Parse the input file
GetPot infile("../fem_system_ex4.in");
GetPot infile{"../fem_system_ex4.in"};
// Read in parameters from the input file
const Real global_tolerance = infile("global_tolerance", 0.);
const unsigned int nelem_target = infile("n_elements", 400);
const Real deltat = infile("deltat", 0.005);
const unsigned int coarsegridsize = infile("coarsegridsize", 20);
const unsigned int coarserefinements = infile("coarserefinements", 0);
const unsigned int max_adaptivesteps = infile("max_adaptivesteps", 10);
const unsigned int dim = infile("dimension", 2);
const auto& global_tolerance{infile("global_tolerance", 0._r)};
const auto& nelem_target{infile("n_elements", 400u)};
const auto& deltat{infile("deltat", 0.005_r)};
const auto& coarsegridsize{infile("coarsegridsize", 20u)};
const auto& coarserefinements{infile("coarserefinements", 0u)};
const auto& max_adaptivesteps{infile("max_adaptivesteps", 10u)};
const auto& dim{infile("dimension", 2u)};
// Skip higher-dimensional examples on a lower-dimensional libMesh build
libmesh_example_requires(dim <= LIBMESH_DIM, "2D/3D support");
......@@ -87,10 +89,10 @@ int main(int argc, char** argv) {
// Create a mesh, with dimension to be overridden later, distributed
// across the default MPI communicator.
Mesh mesh(init.comm());
libMesh::Mesh mesh{init.comm()};
// And an object to refine it
MeshRefinement mesh_refinement(mesh);
libMesh::MeshRefinement mesh_refinement{mesh};
mesh_refinement.coarsen_by_parents() = true;
mesh_refinement.absolute_global_tolerance() = global_tolerance;
mesh_refinement.nelem_target() = nelem_target;
......@@ -101,30 +103,22 @@ int main(int argc, char** argv) {
// Use the MeshTools::Generation mesh generator to create a uniform
// grid on the square or cube. We crop the domain at y=2/3 to allow
// for a homogeneous Neumann BC in our benchmark there.
boundary_id_type bcid = 3; // +y in 3D
libMesh::boundary_id_type bcid{3}; // +y in 3D
mesh.read("../meshes/bridge.xda");
{
// Add boundary elements corresponding to the +y boundary of our
// volume mesh
std::set<boundary_id_type> bcids;
bcids.insert(bcid);
mesh.get_boundary_info().add_elements(bcids, mesh);
mesh.prepare_for_use();
}
// Add boundary elements corresponding to the +y boundary of our
// volume mesh
mesh.get_boundary_info().add_elements({bcid}, mesh);
mesh.prepare_for_use();
// To work around ExodusII file format limitations, we need elements
// of different dimensionality to belong to different subdomains.
// Our interior elements defaulted to subdomain id 0, so we'll set
// boundary elements to subdomain 2.
{
const MeshBase::element_iterator end_el = mesh.elements_end();
for (MeshBase::element_iterator el = mesh.elements_begin();
el != end_el; ++el) {
Elem* elem = *el;
if (elem->dim() < dim) elem->subdomain_id() = 2;
}
}
std::for_each(mesh.elements_begin(), mesh.elements_end(), [&](auto elem) {
if (elem->dim() < dim) elem->subdomain_id() = 2;
});
mesh_refinement.uniformly_refine(coarserefinements);
......@@ -132,13 +126,14 @@ int main(int argc, char** argv) {
mesh.print_info();
// Create an equation systems object.
EquationSystems equation_systems(mesh);
libMesh::EquationSystems equation_systems{mesh};
// Declare the system "Heat" and its variables.
HeatSystem& system = equation_systems.add_system<HeatSystem>("Heat");
auto& system = equation_systems.add_system<HeatSystem>("Heat");
// Solve this as a steady system
system.time_solver = UniquePtr<TimeSolver>(new SteadySolver(system));
system.time_solver = libMesh::UniquePtr<libMesh::TimeSolver>(
new libMesh::SteadySolver(system));
// Initialize the system
equation_systems.init();
......@@ -147,34 +142,32 @@ int main(int argc, char** argv) {
system.deltat = deltat;
// And the nonlinear solver options
DiffSolver& solver = *(system.time_solver->diff_solver().get());
auto& solver = *(system.time_solver->diff_solver().get());
solver.quiet = infile("solver_quiet", true);
solver.verbose = !solver.quiet;
solver.max_nonlinear_iterations = infile("max_nonlinear_iterations", 15);
solver.relative_step_tolerance = infile("relative_step_tolerance", 1.e-3);
solver.max_nonlinear_iterations = infile("max_nonlinear_iterations", 15u);
solver.relative_step_tolerance = infile("relative_step_tolerance", 1.e-3_r);
solver.relative_residual_tolerance =
infile("relative_residual_tolerance", 0.0);
infile("relative_residual_tolerance", 0.0_r);
solver.absolute_residual_tolerance =
infile("absolute_residual_tolerance", 0.0);
infile("absolute_residual_tolerance", 0.0_r);
// And the linear solver options
solver.max_linear_iterations = infile("max_linear_iterations", 50000);
solver.initial_linear_tolerance = infile("initial_linear_tolerance", 1.e-3);
solver.max_linear_iterations = infile("max_linear_iterations", 50000u);
solver.initial_linear_tolerance =
infile("initial_linear_tolerance", 1.e-3_r);
// Print information about the system to the screen.
equation_systems.print_info();
// Adaptively solve the steady solution
unsigned int a_step = max_adaptivesteps;
auto a_step = max_adaptivesteps;
for (; a_step != max_adaptivesteps; ++a_step) {
system.solve();
system.postprocess();
ErrorVector error;
UniquePtr<ErrorEstimator> error_estimator;
libMesh::UniquePtr<libMesh::ErrorEstimator> error_estimator;
// To solve to a tolerance in this problem we
// need a better estimator than Kelly
if (global_tolerance != 0.) {
......@@ -182,11 +175,12 @@ int main(int argc, char** argv) {
// size at once
libmesh_assert_equal_to(nelem_target, 0);
UniformRefinementEstimator* u = new UniformRefinementEstimator;
libMesh::UniformRefinementEstimator* u{
new libMesh::UniformRefinementEstimator};
// The lid-driven cavity problem isn't in H1, so
// lets estimate L2 error
u->error_norm = L2;
u->error_norm = libMesh::L2;
error_estimator.reset(u);
} else {
......@@ -198,21 +192,22 @@ int main(int argc, char** argv) {
// not in H1 - if we were doing more than a few
// timesteps we'd need to turn off or limit the
// maximum level of our adaptivity eventually
error_estimator.reset(new KellyErrorEstimator);
error_estimator.reset(new libMesh::KellyErrorEstimator);
}
libMesh::ErrorVector error;
error_estimator->estimate_error(system, error);
// Print out status at each adaptive step.
Real global_error = error.l2_norm();
libMesh::out << "Adaptive step " << a_step << ": " << std::endl;
libMesh::out << "Adaptive step " << a_step << ": " << '\n';
const auto& global_error = error.l2_norm();
if (global_tolerance != 0.)
libMesh::out << "Global_error = " << global_error << std::endl;
libMesh::out << "Global_error = " << global_error << '\n';
if (global_tolerance != 0.)
libMesh::out << "Worst element error = " << error.maximum()
<< ", mean = " << error.mean() << std::endl;
<< ", mean = " << error.mean() << '\n';
if (global_tolerance != 0.) {
// If we've reached our desired tolerance, we
......@@ -236,8 +231,7 @@ int main(int argc, char** argv) {
libMesh::out << "Refined mesh to " << mesh.n_active_elem()
<< " active elements and "
<< equation_systems.n_active_dofs() << " active dofs."
<< std::endl;
<< equation_systems.n_active_dofs() << " active dofs.\n";
}
// Do one last solve if necessary
if (a_step == max_adaptivesteps) {
......@@ -247,26 +241,27 @@ int main(int argc, char** argv) {
}
#ifdef LIBMESH_HAVE_EXODUS_API
ExodusII_IO(mesh).write_equation_systems("out.e", equation_systems);
libMesh::ExodusII_IO(mesh).write_equation_systems("out.e",
equation_systems);
#endif // #ifdef LIBMESH_HAVE_EXODUS_API
#ifdef LIBMESH_HAVE_GMV
GMVIO(mesh).write_equation_systems("out.gmv", equation_systems);
libMesh::GMVIO(mesh).write_equation_systems("out.gmv", equation_systems);
#endif // #ifdef LIBMESH_HAVE_GMV
#ifdef LIBMESH_HAVE_FPARSER
// Check that we got close to the analytic solution
ExactSolution exact_sol(equation_systems);
libMesh::ExactSolution exact_sol(equation_systems);
const std::string exact_str =
(dim == 2) ? "sin(pi*x)*sin(pi*y)" : "sin(pi*x)*sin(pi*y)*sin(pi*z)";
ParsedFunction<Number> exact_func(exact_str);
libMesh::ParsedFunction<libMesh::Number> exact_func(exact_str);
exact_sol.attach_exact_value(0, &exact_func);
exact_sol.compute_error("Heat", "T");
Number err = exact_sol.l2_error("Heat", "T");
libMesh::Number err{exact_sol.l2_error("Heat", "T")};
// Print out the error value
libMesh::out << "L2-Error is: " << err << std::endl;
libMesh::out << "L2-Error is: " << err << '\n';
libmesh_assert_less(libmesh_real(err), 2e-3);
......
......@@ -13,17 +13,17 @@
#include "libmesh/zero_function.h"
using namespace libMesh;
// user defined literal for libmesh's Real
constexpr auto operator"" _r(long double n) { return libMesh::Real(n); }
void HeatSystem::init_data() {
T_var = this->add_variable("T", static_cast<Order>(_fe_order),
Utility::string_to_enum<FEFamily>(_fe_family));
std::set<boundary_id_type> bdys{0, 1, 2};
std::vector<unsigned int> T_only(1, T_var);
ZeroFunction<Number> zero;
this->get_dof_map().add_dirichlet_boundary(
DirichletBoundary(bdys, T_only, &zero));
DirichletBoundary({0, 1, 2}, {T_var}, &zero));
// Do the parent's initialization after variables are defined
FEMSystem::init_data();
......@@ -32,16 +32,12 @@ void HeatSystem::init_data() {
}
void HeatSystem::init_context(DiffContext& context) {
FEMContext& c = libmesh_cast_ref<FEMContext&>(context);
auto& c = libmesh_cast_ref<FEMContext&>(context);
const std::set<unsigned char>& elem_dims = c.elem_dimensions();
for (std::set<unsigned char>::const_iterator dim_it = elem_dims.begin();
dim_it != elem_dims.end(); ++dim_it) {
const unsigned char dim = *dim_it;
FEBase* fe = libmesh_nullptr;
const auto& elem_dims = c.elem_dimensions();
for (const auto& dim : elem_dims) {
FEBase* fe = nullptr;
c.get_element_fe(T_var, fe, dim);
fe->get_JxW(); // For integration
......@@ -55,31 +51,31 @@ void HeatSystem::init_context(DiffContext& context) {
bool HeatSystem::element_time_derivative(bool request_jacobian,
DiffContext& context) {
FEMContext& c = libmesh_cast_ref<FEMContext&>(context);
auto& c = libmesh_cast_ref<FEMContext&>(context);
const unsigned int mesh_dim = c.get_system().get_mesh().mesh_dimension();
const auto& mesh_dim = c.get_system().get_mesh().mesh_dimension();
// First we get some references to cell-specific data that
// will be used to assemble the linear system.
const unsigned int dim = c.get_elem().dim();
FEBase* fe = libmesh_nullptr;
const auto& dim = c.get_elem().dim();
FEBase* fe = nullptr;
c.get_element_fe(T_var, fe, dim);
// Element Jacobian * quadrature weights for interior integration
const std::vector<Real>& JxW = fe->get_JxW();
const auto& JxW = fe->get_JxW();
const std::vector<Point>& xyz = fe->get_xyz();
const auto& xyz = fe->get_xyz();
const std::vector<std::vector<Real>>& phi = fe->get_phi();
const auto& phi = fe->get_phi();
const std::vector<std::vector<RealGradient>>& dphi = fe->get_dphi();
const auto& dphi = fe->get_dphi();
// The number of local degrees of freedom in each variable
const unsigned int n_T_dofs = c.get_dof_indices(T_var).size();
const auto& n_T_dofs = c.get_dof_indices(T_var).size();
// The subvectors and submatrices we need to fill:
DenseSubMatrix<Number>& K = c.get_elem_jacobian(T_var, T_var);
DenseSubVector<Number>& F = c.get_elem_residual(T_var);
auto& K = c.get_elem_jacobian(T_var, T_var);
auto& F = c.get_elem_residual(T_var);
// Now we will build the element Jacobian and residual.
// Constructing the residual requires the solution and its
......@@ -87,33 +83,31 @@ bool HeatSystem::element_time_derivative(bool request_jacobian,
// calculated at each quadrature point by summing the
// solution degree-of-freedom values by the appropriate
// weight functions.
unsigned int n_qpoints = c.get_element_qrule().n_points();
auto n_qpoints = c.get_element_qrule().n_points();
for (unsigned int qp = 0; qp != n_qpoints; qp++) {
for (std::size_t qp{0}; qp != n_qpoints; qp++) {
// Compute the solution gradient at the Newton iterate
Gradient grad_T = c.interior_gradient(T_var, qp);
const Number k = _k[dim];
const Point& p = xyz[qp];
const auto& k = _k[dim];
const Number u_exact = +1.0;
const auto& u_exact = +1.0_r;
// Only apply forcing to interior elements
const Number forcing =
const auto& forcing =
(dim == mesh_dim) ? -k * u_exact * (dim * libMesh::pi * libMesh::pi)
: 0;
const Number JxWxNK = JxW[qp] * -k;
const auto& JxWxNK = JxW[qp] * -k;
for (unsigned int i = 0; i != n_T_dofs; i++)
for (std::size_t i{0}; i != n_T_dofs; i++)
F(i) += JxWxNK * (grad_T * dphi[i][qp] + forcing * phi[i][qp]);
if (request_jacobian) {
const Number JxWxNKxD =
const auto& JxWxNKxD =
JxWxNK * context.get_elem_solution_derivative();
for (unsigned int i = 0; i != n_T_dofs; i++)
for (unsigned int j = 0; j != n_T_dofs; ++j)
for (std::size_t i{0}; i != n_T_dofs; i++)
for (std::size_t j{0}; j != n_T_dofs; ++j)
K(i, j) += JxWxNKxD * (dphi[i][qp] * dphi[j][qp]);
}
} // end of the quadrature point qp-loop
......
......@@ -37,9 +37,9 @@ class HeatSystem : public libMesh::FEMSystem {
libMesh::Real _k[4];
// The FE type to use
std::string _fe_family;
unsigned int _fe_order;
std::string _fe_family{};
unsigned int _fe_order{};
// The variable index (yes, this will be 0...)
unsigned int T_var;
unsigned int T_var{};
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment