v0.14.0
Loading...
Searching...
No Matches
SCL-9: Heat method

Table of Contents

Note
Prerequisites of this tutorial include SCL-1: Poisson's equation (homogeneous BC)


Note
Intended learning outcome:
  • general structure of a program developed using MoFEM
  • idea of Simple Interface in MoFEM and how to use it
  • Solving scalar problem embedded in 3d space
  • How to push the developed UDOs to the Pipeline

Source code

/**
* \file heat_method.cpp \example heat_method.cpp
*
* Calculating geodetic distances using heat method. For details see,
*
* K. Crane, C. Weischedel, M. Wardetzky, Geodesics in heat: A new approach to
* computing distance based on heat flow, ACM Transactions on Graphics , vol.
* 32, no. 5, pp. 152:1-152:11, 2013.
*
* Interent resources:
* http://www.cs.cmu.edu/~kmcrane/Projects/HeatMethod/
* http://www.numerical-tours.com/matlab/meshproc_7_geodesic_poisson/
*
*
* Solving two problems in sequence. Show hot to use form integrators and how to
* implement user data operator.
*
*/
#include <MoFEM.hpp>
using namespace MoFEM;
static char help[] = "...\n\n";
double dt = 2; // relative to edge length
#include <MoFEM.hpp>
using DomainEleOp = DomainEle::UserDataOperator;
constexpr int SPACE_DIM = 3;
// Use forms iterators for Grad-Grad term
// Use forms for Mass term
struct Example {
Example(MoFEM::Interface &m_field) : mField(m_field) {}
private:
/**
* Use problem specific implementation for second stage of heat methid
*/
struct OpRhs : public DomainEleOp {
OpRhs(boost::shared_ptr<MatrixDouble> u_grad_ptr);
MoFEMErrorCode doWork(int side, EntityType type,
protected:
boost::shared_ptr<MatrixDouble> uGradPtr;
};
};
//! [Run programme]
}
//! [Run programme]
//! [Read mesh]
// FIXME: THis part of algorithm is not working in parallel. If you have bit
// of free time, feel free to generalise code below.
Range nodes;
CHKERR mField.get_moab().get_entities_by_type(0, MBVERTEX, nodes);
// pinchNodes could be get from BLOCKSET
pinchNodes.insert(nodes[0]);
Range edges;
CHKERR mField.get_moab().get_adjacencies(pinchNodes, 1, false, edges,
moab::Interface::UNION);
double l2;
for (auto e : edges) {
Range nodes;
CHKERR mField.get_moab().get_connectivity(Range(e, e), nodes, false);
MatrixDouble coords(nodes.size(), 3);
CHKERR mField.get_moab().get_coords(nodes, &coords(0, 0));
double l2e = 0;
for (int j = 0; j != 3; ++j) {
l2e += pow(coords(0, j) - coords(1, j), 2);
}
l2 = std::max(l2, l2e);
}
dt *= std::sqrt(l2);
}
//! [Read mesh]
//! [Set up problem]
// Only one field
constexpr int order = 1;
}
//! [Set up problem]
//! [Set integration rule]
// Set integration order. To 2p is enough to integrate mass matrix exactly.
auto rule = [](int, int, int p) -> int { return 2 * p; };
// Set integration rule for elements assembling matrix and vector. Note that
// rule for vector could be 2p-1, but that not change computation time
// significantly. So shorter code is better.
CHKERR pipeline_mng->setDomainLhsIntegrationRule(rule);
CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
}
//! [Set integration rule]
//! [Create common data]
}
//! [Create common data]
//! [Boundary condition]
}
//! [Boundary condition]
//! [Push operators to pipeline]
// This will store gradients at integration points on element
auto grad_u_ptr = boost::make_shared<MatrixDouble>();
// Push element from reference configuration to current configuration in 3d
// space
auto set_domain_general = [&](auto &pipeline) {
auto det_ptr = boost::make_shared<VectorDouble>();
auto jac_ptr = boost::make_shared<MatrixDouble>();
auto inv_jac_ptr = boost::make_shared<MatrixDouble>();
pipeline.push_back(new OpCalculateHOJacForFaceEmbeddedIn3DSpace(jac_ptr));
pipeline.push_back(new OpInvertMatrix<3>(jac_ptr, det_ptr, inv_jac_ptr));
pipeline.push_back(new OpSetInvJacH1ForFaceEmbeddedIn3DSpace(inv_jac_ptr));
};
// Operators for assembling matrix for first stage
auto set_domain_lhs_first = [&](auto &pipeline) {
auto one = [](double, double, double) -> double { return 1.; };
pipeline.push_back(new OpGradGrad("U", "U", one));
auto rho = [](double, double, double) -> double { return 1. / dt; };
pipeline.push_back(new OpMass("U", "U", rho));
};
// Nothing is assembled for vector for first stage of heat method. Later
// simply value of one is set to elements of right hand side vector at pinch
// nodes.
auto set_domain_rhs_first = [&](auto &pipeline) {};
// Operators for assembly of left hand side. This time only Grad-Grad
// operator.
auto set_domain_lhs_second = [&](auto &pipeline) {
auto one = [](double, double, double) { return 1.; };
pipeline.push_back(new OpGradGrad("U", "U", one));
};
// Now apply on the right hand side vector X = Grad/||Grad||
auto set_domain_rhs_second = [&](auto &pipeline) {
pipeline.push_back(new OpCalculateScalarFieldGradient<3>("U", grad_u_ptr));
pipeline.push_back(new OpRhs(grad_u_ptr));
};
// Solver first problem
auto solve_first = [&]() {
auto pipeline_mng = mField.getInterface<PipelineManager>();
auto solver = pipeline_mng->createKSP();
CHKERR KSPSetFromOptions(solver);
CHKERR KSPSetUp(solver);
auto dm = simpleInterface->getDM();
auto D = createDMVector(dm);
auto F = vectorDuplicate(D);
// Note add one at nodes which are pinch nodes
CHKERR VecZeroEntries(F);
auto problem_ptr = mField.get_problem(simple->getProblemName());
auto bit_number = mField.get_field_bit_number("U");
auto dofs_ptr = problem_ptr->getNumeredRowDofsPtr();
for (auto v : pinchNodes) {
const auto uid = DofEntity::getUniqueIdCalculate(
0, FieldEntity::getLocalUniqueIdCalculate(bit_number, v));
auto dof = dofs_ptr->get<Unique_mi_tag>().find(uid);
if (dof != dofs_ptr->end())
VecSetValue(F, (*dof)->getPetscGlobalDofIdx(), 1, INSERT_VALUES);
}
CHKERR VecAssemblyBegin(F);
CHKERR VecAssemblyEnd(F);
// Solve problem
CHKERR KSPSolve(solver, F, D);
CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
};
// Solve second problem
auto solve_second = [&]() {
// Note that DOFs on pinch nodes are removed from the problem
auto prb_mng = mField.getInterface<ProblemsManager>();
CHKERR prb_mng->removeDofsOnEntities(simple->getProblemName(), "U",
pinchNodes, 0, 1);
auto *pipeline_mng = mField.getInterface<PipelineManager>();
auto solver = pipeline_mng->createKSP();
CHKERR KSPSetFromOptions(solver);
CHKERR KSPSetUp(solver);
auto dm = simpleInterface->getDM();
auto D = createDMVector(dm);
auto F = vectorDuplicate(D);
CHKERR KSPSolve(solver, F, D);
CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
};
// Post-process results
auto post_proc = [&](const std::string out_name) {
auto tmp_lhs_fe = pipeline_mng->getDomainLhsFE();
auto tmp_rhs_fe = pipeline_mng->getDomainRhsFE();
auto det_ptr = boost::make_shared<VectorDouble>();
auto jac_ptr = boost::make_shared<MatrixDouble>();
auto inv_jac_ptr = boost::make_shared<MatrixDouble>();
pipeline_mng->getDomainLhsFE().reset();
pipeline_mng->getDomainRhsFE().reset();
auto post_proc_fe =
boost::make_shared<PostProcBrokenMeshInMoab<DomainEle>>(mField);
post_proc_fe->getOpPtrVector().push_back(
post_proc_fe->getOpPtrVector().push_back(
new OpInvertMatrix<SPACE_DIM>(jac_ptr, det_ptr, inv_jac_ptr));
post_proc_fe->getOpPtrVector().push_back(
auto u_ptr = boost::make_shared<VectorDouble>();
auto grad_ptr = boost::make_shared<MatrixDouble>();
post_proc_fe->getOpPtrVector().push_back(
new OpCalculateScalarFieldValues("U", u_ptr));
post_proc_fe->getOpPtrVector().push_back(
post_proc_fe->getOpPtrVector().push_back(new OpPPMap(
post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
{{"U", u_ptr}},
{{"GRAD_U", grad_ptr}},
{}, {}));
pipeline_mng->getDomainRhsFE() = post_proc_fe;
CHKERR pipeline_mng->loopFiniteElements();
CHKERR post_proc_fe->writeFile(out_name);
tmp_lhs_fe = pipeline_mng->getDomainLhsFE() = tmp_lhs_fe;
tmp_rhs_fe = pipeline_mng->getDomainRhsFE() = tmp_rhs_fe;
};
set_domain_general(pipeline_mng->getOpDomainLhsPipeline());
set_domain_general(pipeline_mng->getOpDomainRhsPipeline());
set_domain_lhs_first(pipeline_mng->getOpDomainLhsPipeline());
set_domain_rhs_first(pipeline_mng->getOpDomainRhsPipeline());
CHKERR solve_first();
CHKERR post_proc("out_heat_method_first.h5m");
pipeline_mng->getOpDomainLhsPipeline().clear();
pipeline_mng->getOpDomainRhsPipeline().clear();
set_domain_general(pipeline_mng->getOpDomainLhsPipeline());
set_domain_general(pipeline_mng->getOpDomainRhsPipeline());
set_domain_lhs_second(pipeline_mng->getOpDomainLhsPipeline());
set_domain_rhs_second(pipeline_mng->getOpDomainRhsPipeline());
CHKERR solve_second();
CHKERR post_proc("out_heat_method_second.h5m");
};
//! [Push operators to pipeline]
//! [Solve]
}
//! [Solve]
//! [Postprocess results]
}
//! [Postprocess results]
//! [Check results]
}
//! [Check results]
int main(int argc, char *argv[]) {
// Initialisation of MoFEM/PETSc and MOAB data structures
const char param_file[] = "param_file.petsc";
MoFEM::Core::Initialize(&argc, &argv, param_file, help);
// Add logging channel for example
auto core_log = logging::core::get();
core_log->add_sink(
LogManager::createSink(LogManager::getStrmWorld(), "EXAMPLE"));
LogManager::setLog("EXAMPLE");
MOFEM_LOG_TAG("EXAMPLE", "example");
try {
//! [Register MoFEM discrete manager in PETSc]
DMType dm_name = "DMMOFEM";
//! [Register MoFEM discrete manager in PETSc
//! [Create MoAB]
moab::Core mb_instance; ///< mesh database
moab::Interface &moab = mb_instance; ///< mesh database interface
//! [Create MoAB]
//! [Create MoFEM]
MoFEM::Core core(moab); ///< finite element database
MoFEM::Interface &m_field = core; ///< finite element database insterface
//! [Create MoFEM]
//! [Example]
Example ex(m_field);
CHKERR ex.runProblem();
//! [Example]
}
}
Example::OpRhs::OpRhs(boost::shared_ptr<MatrixDouble> u_grad_ptr)
: DomainEleOp("U", DomainEleOp::OPROW), uGradPtr(u_grad_ptr) {}
MoFEMErrorCode Example::OpRhs::doWork(int side, EntityType type,
FTensor::Index<'i', 3> i;
auto nb_dofs = data.getIndices().size();
if (nb_dofs) {
auto nb_base_functions = data.getN().size2();
auto nb_gauss_pts = getGaussPts().size2();
std::array<double, MAX_DOFS_ON_ENTITY> nf;
std::fill(nf.begin(), &nf[nb_dofs], 0);
auto t_diff_base = data.getFTensor1DiffN<3>();
auto t_w = getFTensor0IntegrationWeight();
auto a = getMeasure();
for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
double alpha = t_w * a;
const auto l2 = t_grad(i) * t_grad(i);
if (l2 > std::numeric_limits<double>::epsilon())
t_one(i) = t_grad(i) / std::sqrt(l2);
else
t_one(i) = 0;
size_t bb = 0;
for (; bb != nb_dofs; ++bb) {
nf[bb] -= alpha * t_diff_base(i) * t_one(i);
++t_diff_base;
}
for (; bb < nb_base_functions; ++bb) {
++t_diff_base;
}
++t_grad;
}
ADD_VALUES);
}
}
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
static char help[]
int main()
constexpr double a
constexpr int SPACE_DIM
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
[Define dimension]
#define CATCH_ERRORS
Catch errors.
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base nme:nme847.
Definition definitions.h:60
@ H1
continuous field
Definition definitions.h:85
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
constexpr int order
@ F
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:523
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
auto createDMVector(DM dm)
Get smart vector from DM.
Definition DMMoFEM.hpp:1099
virtual const Problem * get_problem(const std::string problem_name) const =0
Get the problem object.
MoFEMErrorCode loopFiniteElements(SmartPetscObj< DM > dm=nullptr)
Iterate finite elements.
boost::ptr_deque< UserDataOperator > & getOpDomainLhsPipeline()
Get the Op Domain Lhs Pipeline object.
boost::ptr_deque< UserDataOperator > & getOpDomainRhsPipeline()
Get the Op Domain Rhs Pipeline object.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
double dt
double D
const double v
phase velocity of light in medium (cm/ns)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
FTensor::Tensor1< FTensor::PackPtr< T *, S >, Tensor_Dim > getFTensor1FromMat(ublas::matrix< T, L, A > &data)
Get tensor rank 1 (vector) form data matrix.
MoFEMErrorCode VecSetValues(Vec V, const EntitiesFieldData::EntData &data, const double *ptr, InsertMode iora)
Assemble PETSc vector.
OpCalculateHOJacForFaceImpl< 3 > OpCalculateHOJacForFaceEmbeddedIn3DSpace
FormsIntegrators< DomainEleOp >::Assembly< A >::BiLinearForm< I >::OpGradGrad< 1, FIELD_DIM, SPACE_DIM > OpGradGrad
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
double rho
Definition plastic.cpp:140
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 1, SPACE_DIM > OpMass
[Only used with Hooke equation (linear material model)]
Definition seepage.cpp:56
FTensor::Index< 'j', 3 > j
FTensor::Index< 'i', 3 > i
boost::shared_ptr< MatrixDouble > uGradPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
OpRhs(boost::shared_ptr< MatrixDouble > u_grad_ptr)
[Example]
Definition plastic.cpp:213
MoFEMErrorCode boundaryCondition()
[Set up problem]
MoFEMErrorCode assembleSystem()
[Push operators to pipeline]
MoFEMErrorCode readMesh()
[Run problem]
MoFEMErrorCode setIntegrationRules()
[Set up problem]
MoFEMErrorCode checkResults()
[Postprocess results]
MoFEMErrorCode solveSystem()
[Solve]
MoFEMErrorCode createCommonData()
[Set up problem]
Definition plastic.cpp:476
Example(MoFEM::Interface &m_field)
Definition plastic.cpp:215
Simple * simpleInterface
Definition helmholtz.cpp:41
Range pinchNodes
MoFEMErrorCode runProblem()
[Run problem]
Definition plastic.cpp:253
MoFEM::Interface & mField
Definition plastic.cpp:223
MoFEMErrorCode setupProblem()
[Run problem]
Definition plastic.cpp:272
MoFEMErrorCode outputResults()
[Solve]
virtual FieldBitNumber get_field_bit_number(const std::string name) const =0
get field bit number
virtual moab::Interface & get_moab()=0
Core (interface) class.
Definition Core.hpp:82
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:72
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:112
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
FTensor::Tensor1< FTensor::PackPtr< double *, Tensor_Dim >, Tensor_Dim > getFTensor1DiffN(const FieldApproximationBase base)
Get derivatives of base functions.
MatrixDouble & getN(const FieldApproximationBase base)
get base functions this return matrix (nb. of rows is equal to nb. of Gauss pts, nb....
const VectorInt & getIndices() const
Get global indices of dofs on entity.
Get field gradients at integration pts for scalar filed rank 0, i.e. vector field.
Get value at integration points for scalar field.
Post post-proc data at points from hash maps.
PipelineManager interface.
boost::shared_ptr< FEMethod > & getDomainRhsFE()
boost::shared_ptr< FEMethod > & getDomainLhsFE()
MoFEMErrorCode setDomainRhsIntegrationRule(RuleHookFun rule)
MoFEMErrorCode setDomainLhsIntegrationRule(RuleHookFun rule)
Problem manager is used to build and partition problems.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode addDomainField(const std::string name, const FieldSpace space, const FieldApproximationBase base, const FieldCoefficientsNumber nb_of_coefficients, const TagType tag_type=MB_TAG_SPARSE, const enum MoFEMTypes bh=MF_ZERO, int verb=-1)
Add field on domain.
Definition Simple.cpp:264
MoFEMErrorCode loadFile(const std::string options, const std::string mesh_file_name, LoadFileFunc loadFunc=defaultLoadFileFunc)
Load mesh file.
Definition Simple.cpp:194
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:829
MoFEMErrorCode setFieldOrder(const std::string field_name, const int order, const Range *ents=NULL)
Set field order.
Definition Simple.cpp:599
MoFEMErrorCode setUp(const PetscBool is_partitioned=PETSC_TRUE)
Setup problem.
Definition Simple.cpp:765
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.