v0.15.0
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.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);
258 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
259 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
260 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
262 };
263
264 // Solve second problem
265 auto solve_second = [&]() {
268
269 // Note that DOFs on pinch nodes are removed from the problem
270 auto prb_mng = mField.getInterface<ProblemsManager>();
271 CHKERR prb_mng->removeDofsOnEntities(simple->getProblemName(), "U",
272 pinchNodes, 0, 1);
273
274 auto *pipeline_mng = mField.getInterface<PipelineManager>();
275
276 auto solver = pipeline_mng->createKSP();
277 CHKERR KSPSetFromOptions(solver);
278 CHKERR KSPSetUp(solver);
279
280 auto dm = simpleInterface->getDM();
281 auto D = createDMVector(dm);
282 auto F = vectorDuplicate(D);
283
284 CHKERR KSPSolve(solver, F, D);
285 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
286 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
287 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
289 };
290
291 // Post-process results
292 auto post_proc = [&](const std::string out_name) {
295 auto tmp_lhs_fe = pipeline_mng->getDomainLhsFE();
296 auto tmp_rhs_fe = pipeline_mng->getDomainRhsFE();
297 auto det_ptr = boost::make_shared<VectorDouble>();
298 auto jac_ptr = boost::make_shared<MatrixDouble>();
299 auto inv_jac_ptr = boost::make_shared<MatrixDouble>();
300 pipeline_mng->getDomainLhsFE().reset();
301 pipeline_mng->getDomainRhsFE().reset();
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->getDomainRhsFE() = post_proc_fe;
332 CHKERR pipeline_mng->loopFiniteElements();
333 CHKERR post_proc_fe->writeFile(out_name);
334 tmp_lhs_fe = pipeline_mng->getDomainLhsFE() = tmp_lhs_fe;
335 tmp_rhs_fe = pipeline_mng->getDomainRhsFE() = tmp_rhs_fe;
337 };
338
339 set_domain_general(pipeline_mng->getOpDomainLhsPipeline());
340 set_domain_general(pipeline_mng->getOpDomainRhsPipeline());
341 set_domain_lhs_first(pipeline_mng->getOpDomainLhsPipeline());
342 set_domain_rhs_first(pipeline_mng->getOpDomainRhsPipeline());
343
344 CHKERR solve_first();
345 CHKERR post_proc("out_heat_method_first.h5m");
346
347 pipeline_mng->getOpDomainLhsPipeline().clear();
348 pipeline_mng->getOpDomainRhsPipeline().clear();
349
350 set_domain_general(pipeline_mng->getOpDomainLhsPipeline());
351 set_domain_general(pipeline_mng->getOpDomainRhsPipeline());
352 set_domain_lhs_second(pipeline_mng->getOpDomainLhsPipeline());
353 set_domain_rhs_second(pipeline_mng->getOpDomainRhsPipeline());
354
355 CHKERR solve_second();
356 CHKERR post_proc("out_heat_method_second.h5m");
357
359};
360//! [Push operators to pipeline]
361
362//! [Solve]
366}
367//! [Solve]
368
369//! [Postprocess results]
373}
374//! [Postprocess results]
375
376//! [Check results]
380}
381//! [Check results]
382
383int main(int argc, char *argv[]) {
384
385 // Initialisation of MoFEM/PETSc and MOAB data structures
386 const char param_file[] = "param_file.petsc";
387 MoFEM::Core::Initialize(&argc, &argv, param_file, help);
388
389 // Add logging channel for example
390 auto core_log = logging::core::get();
391 core_log->add_sink(
393 LogManager::setLog("EXAMPLE");
394 MOFEM_LOG_TAG("EXAMPLE", "example");
395
396 try {
397
398 //! [Register MoFEM discrete manager in PETSc]
399 DMType dm_name = "DMMOFEM";
400 CHKERR DMRegister_MoFEM(dm_name);
401 //! [Register MoFEM discrete manager in PETSc
402
403 //! [Create MoAB]
404 moab::Core mb_instance; ///< mesh database
405 moab::Interface &moab = mb_instance; ///< mesh database interface
406 //! [Create MoAB]
407
408 //! [Create MoFEM]
409 MoFEM::Core core(moab); ///< finite element database
410 MoFEM::Interface &m_field = core; ///< finite element database insterface
411 //! [Create MoFEM]
412
413 //! [Example]
414 Example ex(m_field);
415 CHKERR ex.runProblem();
416 //! [Example]
417 }
419
421}
422
423Example::OpRhs::OpRhs(boost::shared_ptr<MatrixDouble> u_grad_ptr)
424 : DomainEleOp("U", DomainEleOp::OPROW), uGradPtr(u_grad_ptr) {}
425
426MoFEMErrorCode Example::OpRhs::doWork(int side, EntityType type,
429
430 FTensor::Index<'i', 3> i;
431
432 auto nb_dofs = data.getIndices().size();
433 if (nb_dofs) {
434
435 auto t_grad = getFTensor1FromMat<3>(*uGradPtr);
436
437 auto nb_base_functions = data.getN().size2();
438 auto nb_gauss_pts = getGaussPts().size2();
439 std::array<double, MAX_DOFS_ON_ENTITY> nf;
440 std::fill(nf.begin(), &nf[nb_dofs], 0);
441
442 auto t_diff_base = data.getFTensor1DiffN<3>();
443 auto t_w = getFTensor0IntegrationWeight();
444 auto a = getMeasure();
445
446 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
447 double alpha = t_w * a;
448
449 const auto l2 = t_grad(i) * t_grad(i);
451 if (l2 > std::numeric_limits<double>::epsilon())
452 t_one(i) = t_grad(i) / std::sqrt(l2);
453 else
454 t_one(i) = 0;
455
456 size_t bb = 0;
457 for (; bb != nb_dofs; ++bb) {
458 nf[bb] -= alpha * t_diff_base(i) * t_one(i);
459 ++t_diff_base;
460 }
461
462 for (; bb < nb_base_functions; ++bb) {
463 ++t_diff_base;
464 }
465
466 ++t_grad;
467 }
468
469 CHKERR VecSetValues<MoFEM::EssentialBcStorage>(getKSPf(), data, &nf[0],
470 ADD_VALUES);
471 }
472
474}
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
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)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:514
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:1234
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.
@ 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:144
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:216
MoFEMErrorCode boundaryCondition()
MoFEMErrorCode assembleSystem()
MoFEMErrorCode readMesh()
MoFEMErrorCode setIntegrationRules()
MoFEMErrorCode checkResults()
MoFEMErrorCode solveSystem()
MoFEMErrorCode createCommonData()
Example(MoFEM::Interface &m_field)
Simple * simpleInterface
Definition helmholtz.cpp:41
Range pinchNodes
MoFEMErrorCode runProblem()
MoFEM::Interface & mField
Reference to MoFEM interface.
Definition plastic.cpp:226
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: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:118
Deprecated interface functions.
static UId getUniqueIdCalculate(const DofIdx dof, UId ent_uid)
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 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.
boost::shared_ptr< FEMethod > & getDomainRhsFE()
Get domain right-hand side finite element.
boost::shared_ptr< FEMethod > & getDomainLhsFE()
Get domain left-hand side finite element.
MoFEM::FaceElementForcesAndSourcesCore FaceEle
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:800
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:736
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.