v0.16.3
Loading...
Searching...
No Matches
heat_method.cpp
Go to the documentation of this file.
1/**
2 * \file heat_method.cpp
3 * \example mofem/tutorials/scl-9_heat_method/heat_method.cpp
4 *
5 * Calculating geodetic distances using heat method. For details see,
6 *
7 * K. Crane, C. Weischedel, M. Wardetzky, Geodesics in heat: A new approach to
8 * computing distance based on heat flow, ACM Transactions on Graphics , vol.
9 * 32, no. 5, pp. 152:1-152:11, 2013.
10 *
11 * Interent resources:
12 * http://www.cs.cmu.edu/~kmcrane/Projects/HeatMethod/
13 * http://www.numerical-tours.com/matlab/meshproc_7_geodesic_poisson/
14 *
15 *
16 * Solving two problems in sequence. Show hot to use form integrators and how to
17 * implement user data operator.
18 *
19 */
20
21#include <MoFEM.hpp>
22
23using namespace MoFEM;
24
25static char help[] = "...\n\n";
26
27double dt = 2; // relative to edge length
28
29#include <MoFEM.hpp>
30
32using DomainEleOp = DomainEle::UserDataOperator;
34
35constexpr int SPACE_DIM = 3;
36
37// Use forms iterators for Grad-Grad term
40
41// Use forms for Mass term
44
45struct Example {
46
47 Example(MoFEM::Interface &m_field) : mField(m_field) {}
48
50
51private:
54
56
66
67 /**
68 * Use problem specific implementation for second stage of heat methid
69 */
70 struct OpRhs : public DomainEleOp {
71
72 OpRhs(boost::shared_ptr<MatrixDouble> u_grad_ptr);
73
74 MoFEMErrorCode doWork(int side, EntityType type,
76
77 protected:
78 boost::shared_ptr<MatrixDouble> uGradPtr;
79 };
80};
81
82//! [Run programme]
95}
96//! [Run programme]
97
98//! [Read mesh]
101
105
106 // FIXME: THis part of algorithm is not working in parallel. If you have bit
107 // of free time, feel free to generalise code below.
108
109 Range nodes;
110 CHKERR mField.get_moab().get_entities_by_type(0, MBVERTEX, nodes);
111 // pinchNodes could be get from BLOCKSET
112 pinchNodes.insert(nodes[0]);
113
114 Range edges;
115 CHKERR mField.get_moab().get_adjacencies(pinchNodes, 1, false, edges,
116 moab::Interface::UNION);
117 double l2;
118 for (auto e : edges) {
119 Range nodes;
120 CHKERR mField.get_moab().get_connectivity(Range(e, e), nodes, false);
121 MatrixDouble coords(nodes.size(), 3);
122 CHKERR mField.get_moab().get_coords(nodes, &coords(0, 0));
123 double l2e = 0;
124 for (int j = 0; j != 3; ++j) {
125 l2e += pow(coords(0, j) - coords(1, j), 2);
126 }
127 l2 = std::max(l2, l2e);
128 }
129
130 dt *= std::sqrt(l2);
131
133}
134//! [Read mesh]
135
136//! [Set up problem]
139
140 // Only one field
142 constexpr int order = 1;
145
147}
148//! [Set up problem]
149
150//! [Set integration rule]
153
154 // Set integration order. To 2p is enough to integrate mass matrix exactly.
155 auto rule = [](int, int, int p) -> int { return 2 * p; };
156
157 // Set integration rule for elements assembling matrix and vector. Note that
158 // rule for vector could be 2p-1, but that not change computation time
159 // significantly. So shorter code is better.
161 CHKERR pipeline_mng->setDomainLhsIntegrationRule(rule);
162 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
163
165}
166//! [Set integration rule]
167
168//! [Create common data]
172}
173//! [Create common data]
174
175//! [Boundary condition]
179}
180//! [Boundary condition]
181
182//! [Push operators to pipeline]
186
187 // This will store gradients at integration points on element
188 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
189
190 // Push element from reference configuration to current configuration in 3d
191 // space
192 auto set_domain_general = [&](auto &pipeline) {
193 auto det_ptr = boost::make_shared<VectorDouble>();
194 auto jac_ptr = boost::make_shared<MatrixDouble>();
195 auto inv_jac_ptr = boost::make_shared<MatrixDouble>();
196 pipeline.push_back(new OpCalculateHOJacForFaceEmbeddedIn3DSpace(jac_ptr));
197 pipeline.push_back(new OpInvertMatrix<3>(jac_ptr, det_ptr, inv_jac_ptr));
198 pipeline.push_back(new OpSetInvJacH1ForFaceEmbeddedIn3DSpace(inv_jac_ptr));
199 };
200
201 // Operators for assembling matrix for first stage
202 auto set_domain_lhs_first = [&](auto &pipeline) {
203 auto one = [](double, double, double) -> double { return 1.; };
204 pipeline.push_back(new OpGradGrad("U", "U", one));
205 auto rho = [](double, double, double) -> double { return 1. / dt; };
206 pipeline.push_back(new OpMass("U", "U", rho));
207 };
208
209 // Nothing is assembled for vector for first stage of heat method. Later
210 // simply value of one is set to elements of right hand side vector at pinch
211 // nodes.
212 auto set_domain_rhs_first = [&](auto &pipeline) {};
213
214 // Operators for assembly of left hand side. This time only Grad-Grad
215 // operator.
216 auto set_domain_lhs_second = [&](auto &pipeline) {
217 auto one = [](double, double, double) { return 1.; };
218 pipeline.push_back(new OpGradGrad("U", "U", one));
219 };
220
221 // Now apply on the right hand side vector X = Grad/||Grad||
222 auto set_domain_rhs_second = [&](auto &pipeline) {
223 pipeline.push_back(new OpCalculateScalarFieldGradient<3>("U", grad_u_ptr));
224 pipeline.push_back(new OpRhs(grad_u_ptr));
225 };
226
227 // Solver first problem
228 auto solve_first = [&]() {
231 auto pipeline_mng = mField.getInterface<PipelineManager>();
232
233 auto solver = pipeline_mng->createKSP();
234 CHKERR KSPSetFromOptions(solver);
235 CHKERR KSPSetUp(solver);
236
237 auto dm = simpleInterface->getDM();
238 auto D = createDMVector(dm);
239 auto F = vectorDuplicate(D);
240
241 // Note add one at nodes which are pinch nodes
242 CHKERR VecZeroEntries(F);
243 auto problem_ptr = mField.get_problem(simple->getProblemName());
244 auto bit_number = mField.get_field_bit_number("U");
245 auto dofs_ptr = problem_ptr->getNumeredRowDofsPtr();
246 for (auto v : pinchNodes) {
247 const auto uid = DofEntity::getUniqueIdCalculate(
249 auto dof = dofs_ptr->get<Unique_mi_tag>().find(uid);
250 if (dof != dofs_ptr->end())
251 VecSetValue(F, (*dof)->getPetscGlobalDofIdx(), 1, INSERT_VALUES);
252 }
253 CHKERR VecAssemblyBegin(F);
254 CHKERR VecAssemblyEnd(F);
255
256 // Solve problem
257 CHKERR KSPSolve(solver, F, D);
259 solver, "heat method first solve");
260 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
261 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
262 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
264 };
265
266 // Solve second problem
267 auto solve_second = [&]() {
270
271 // Note that DOFs on pinch nodes are removed from the problem
272 auto prb_mng = mField.getInterface<ProblemsManager>();
273 CHKERR prb_mng->removeDofsOnEntities(simple->getProblemName(), "U",
274 pinchNodes, 0, 1);
275
276 auto *pipeline_mng = mField.getInterface<PipelineManager>();
277
278 auto solver = pipeline_mng->createKSP();
279 CHKERR KSPSetFromOptions(solver);
280 CHKERR KSPSetUp(solver);
281
282 auto dm = simpleInterface->getDM();
283 auto D = createDMVector(dm);
284 auto F = vectorDuplicate(D);
285
286 CHKERR KSPSolve(solver, F, D);
288 solver, "heat method second solve");
289 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
290 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
291 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
293 };
294
295 // Post-process results
296 auto post_proc = [&](const std::string out_name) {
299 auto det_ptr = boost::make_shared<VectorDouble>();
300 auto jac_ptr = boost::make_shared<MatrixDouble>();
301 auto inv_jac_ptr = boost::make_shared<MatrixDouble>();
302 auto post_proc_fe =
303 boost::make_shared<PostProcBrokenMeshInMoab<DomainEle>>(mField);
304
305 post_proc_fe->getOpPtrVector().push_back(
307 post_proc_fe->getOpPtrVector().push_back(
308 new OpInvertMatrix<SPACE_DIM>(jac_ptr, det_ptr, inv_jac_ptr));
309 post_proc_fe->getOpPtrVector().push_back(
311
312 auto u_ptr = boost::make_shared<VectorDouble>();
313 auto grad_ptr = boost::make_shared<MatrixDouble>();
314
315 post_proc_fe->getOpPtrVector().push_back(
316 new OpCalculateScalarFieldValues("U", u_ptr));
317 post_proc_fe->getOpPtrVector().push_back(
319
321
322 post_proc_fe->getOpPtrVector().push_back(new OpPPMap(
323 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
324
325 {{"U", u_ptr}},
326
327 {{"GRAD_U", grad_ptr}},
328
329 {}, {}));
330
331 pipeline_mng->getDomainPostProcFE() = post_proc_fe;
332 CHKERR pipeline_mng->loopFiniteElementsPostProc();
333 CHKERR post_proc_fe->writeFile(out_name);
335 };
336
337 set_domain_general(pipeline_mng->getOpDomainLhsPipeline());
338 set_domain_general(pipeline_mng->getOpDomainRhsPipeline());
339 set_domain_lhs_first(pipeline_mng->getOpDomainLhsPipeline());
340 set_domain_rhs_first(pipeline_mng->getOpDomainRhsPipeline());
341
342 CHKERR solve_first();
343 CHKERR post_proc("out_heat_method_first.h5m");
344
345 pipeline_mng->getOpDomainLhsPipeline().clear();
346 pipeline_mng->getOpDomainRhsPipeline().clear();
347
348 set_domain_general(pipeline_mng->getOpDomainLhsPipeline());
349 set_domain_general(pipeline_mng->getOpDomainRhsPipeline());
350 set_domain_lhs_second(pipeline_mng->getOpDomainLhsPipeline());
351 set_domain_rhs_second(pipeline_mng->getOpDomainRhsPipeline());
352
353 CHKERR solve_second();
354 CHKERR post_proc("out_heat_method_second.h5m");
355
357};
358//! [Push operators to pipeline]
359
360//! [Solve]
364}
365//! [Solve]
366
367//! [Postprocess results]
371}
372//! [Postprocess results]
373
374//! [Check results]
378}
379//! [Check results]
380
381int main(int argc, char *argv[]) {
382
383 // Initialisation of MoFEM/PETSc and MOAB data structures
384 const char param_file[] = "param_file.petsc";
385 MoFEM::Core::Initialize(&argc, &argv, param_file, help);
386
387 // Add logging channel for example
388 auto core_log = logging::core::get();
389 core_log->add_sink(
391 LogManager::setLog("EXAMPLE");
392 MOFEM_LOG_TAG("EXAMPLE", "example");
393
394 try {
395
396 //! [Register MoFEM discrete manager in PETSc]
397 DMType dm_name = "DMMOFEM";
398 CHKERR DMRegister_MoFEM(dm_name);
399 //! [Register MoFEM discrete manager in PETSc
400
401 //! [Create MoAB]
402 moab::Core mb_instance; ///< mesh database
403 moab::Interface &moab = mb_instance; ///< mesh database interface
404 //! [Create MoAB]
405
406 //! [Create MoFEM]
407 MoFEM::Core core(moab); ///< finite element database
408 MoFEM::Interface &m_field = core; ///< finite element database insterface
409 //! [Create MoFEM]
410
411 //! [Example]
412 Example ex(m_field);
413 CHKERR ex.runProblem();
414 //! [Example]
415 }
417
419}
420
421Example::OpRhs::OpRhs(boost::shared_ptr<MatrixDouble> u_grad_ptr)
422 : DomainEleOp("U", DomainEleOp::OPROW), uGradPtr(u_grad_ptr) {}
423
427
428 FTensor::Index<'i', 3> i;
429
430 auto nb_dofs = data.getIndices().size();
431 if (nb_dofs) {
432
433 auto t_grad = getFTensor1FromMat<3>(*uGradPtr);
434
435 auto nb_base_functions = data.getN().size2();
436 auto nb_gauss_pts = getGaussPts().size2();
437 std::array<double, MAX_DOFS_ON_ENTITY> nf;
438 std::fill(nf.begin(), &nf[nb_dofs], 0);
439
440 auto t_diff_base = data.getFTensor1DiffN<3>();
441 auto t_w = getFTensor0IntegrationWeight();
442 auto a = getMeasure();
443
444 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
445 double alpha = t_w * a;
446
447 const auto l2 = t_grad(i) * t_grad(i);
449 if (l2 > std::numeric_limits<double>::epsilon())
450 t_one(i) = t_grad(i) / std::sqrt(l2);
451 else
452 t_one(i) = 0;
453
454 size_t bb = 0;
455 for (; bb != nb_dofs; ++bb) {
456 nf[bb] -= alpha * t_diff_base(i) * t_one(i);
457 ++t_diff_base;
458 }
459
460 for (; bb < nb_base_functions; ++bb) {
461 ++t_diff_base;
462 }
463
464 ++t_grad;
465 }
466
467 CHKERR VecSetValues<MoFEM::EssentialBcStorage>(getKSPf(), data, &nf[0],
468 ADD_VALUES);
469 }
470
472}
std::string type
int main()
constexpr double a
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
#define CATCH_ERRORS
Catch errors.
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
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, RowColData rc=RowColData::COL)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:543
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1250
virtual const Problem * get_problem(const std::string problem_name) const =0
Get the problem object.
boost::ptr_deque< UserDataOperator > & getOpDomainLhsPipeline()
Get the Op Domain Lhs Pipeline object.
MoFEMErrorCode loopFiniteElementsPostProc(SmartPetscObj< DM > dm=nullptr)
Iterate postprocessing finite elements.
boost::ptr_deque< UserDataOperator > & getOpDomainRhsPipeline()
Get the Op Domain Rhs Pipeline object.
@ GAUSS
Gaussian quadrature integration.
@ PETSC
Standard PETSc assembly.
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
FTensor::Index< 'i', SPACE_DIM > i
double dt
static char help[]
constexpr int SPACE_DIM
double D
const double v
phase velocity of light in medium (cm/ns)
FTensor::Index< 'j', 3 > j
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.
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:145
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 1, SPACE_DIM > OpMass
[Only used with Hooke equation (linear material model)]
Definition seepage.cpp:56
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:217
MoFEMErrorCode boundaryCondition()
MoFEMErrorCode assembleSystem()
MoFEMErrorCode readMesh()
MoFEMErrorCode setIntegrationRules()
Simple * simple
MoFEMErrorCode checkResults()
MoFEMErrorCode solveSystem()
MoFEMErrorCode createCommonData()
Example(MoFEM::Interface &m_field)
Range pinchNodes
MoFEMErrorCode runProblem()
MoFEM::Interface & mField
Reference to MoFEM interface.
Definition plastic.cpp:227
MoFEMErrorCode setupProblem()
MoFEMErrorCode outputResults()
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:83
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:68
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:123
Deprecated interface functions.
static UId getUniqueIdCalculate(const DofIdx dof, UId ent_uid)
Data on single entity (This is passed as argument to DataOperator::doWork)
auto 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 degrees of freedom on entity.
UId getLocalUniqueIdCalculate()
Get the Local Unique Id Calculate object.
static boost::shared_ptr< SinkType > createSink(boost::shared_ptr< std::ostream > stream_ptr, std::string comm_filter)
Create a sink object.
static boost::shared_ptr< std::ostream > getStrmWorld()
Get the strm world object.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for double precision scalar field values calculation.
Operator for inverting matrices at integration points.
Post post-proc data at points from hash maps.
PipelineManager interface.
MoFEM::FaceElementForcesAndSourcesCore FaceEle
boost::shared_ptr< FEMethod > & getDomainPostProcFE()
Get domain postprocessing finite element.
MoFEMErrorCode setDomainRhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain right-hand side finite element.
MoFEMErrorCode setDomainLhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain left-hand side finite element.
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:261
MoFEMErrorCode loadFile(const std::string options, const std::string mesh_file_name, LoadFileFunc loadFunc=defaultLoadFileFunc)
Load mesh file.
Definition Simple.cpp:191
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:799
MoFEMErrorCode setFieldOrder(const std::string field_name, const int order, const Range *ents=NULL)
Set field order.
Definition Simple.cpp:575
MoFEMErrorCode setUp(const PetscBool is_partitioned=PETSC_TRUE)
Setup problem.
Definition Simple.cpp:735
const std::string getProblemName() const
Get the Problem Name.
Definition Simple.hpp:450
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.