v0.16.3
Loading...
Searching...
No Matches
MixTransportElement.hpp
Go to the documentation of this file.
1/** \file MixTransportElement.hpp
2 * \brief Mix implementation of transport element
3 *
4 * \ingroup mofem_mix_transport_elem
5 *
6 */
7
8#ifndef _MIX_TRANPORT_ELEMENT_HPP_
9#define _MIX_TRANPORT_ELEMENT_HPP_
10
11#include <MoFEM.hpp>
12#include <cholesky.hpp>
13
14using namespace MoFEM;
15
16namespace MixTransport {
17
18/** \brief Mix transport problem
19 \ingroup mofem_mix_transport_elem
20
21 Note to solve this system you need to use direct solver or proper
22 preconditioner for saddle problem.
23
24 It is based on \cite arnold2006differential \cite arnold2012mixed \cite
25 reviartthomas1996
26 <https://www.researchgate.net/profile/Richard_Falk/publication/226454406_Differential_Complexes_and_Stability_of_Finite_Element_Methods_I._The_de_Rham_Complex/links/02e7e5214f0426ff77000000.pdf>
27
28 General problem have form,
29 \f[
30 \mathbf{A} \boldsymbol\sigma + \textrm{grad}[u] = \mathbf{0} \; \textrm{on} \;
31 \Omega \\ \textrm{div}[\boldsymbol\sigma] = f \; \textrm{on} \; \Omega \f]
32
33*/
35
37
38 /**
39 * \brief definition of volume element
40
41 * It is used to calculate volume integrals. On volume element we set-up
42 * operators to calculate components of matrix and vector.
43
44 */
50
51 MyVolumeFE feVol; ///< Instance of volume element
52
53 /** \brief definition of surface element
54
55 * It is used to calculate surface integrals. On volume element are operators
56 * evaluating natural boundary conditions.
57
58 */
62 int getRule(int order) { return 2 * order + 1; };
63 };
64
65 MyTriFE feTri; ///< Instance of surface element
66
67 /**
68 * \brief construction of this data structure
69 */
71 : mField(m_field), feVol(m_field), feTri(m_field){};
72
73 /**
74 * \brief destructor
75 */
77
78 VectorDouble valuesAtGaussPts; ///< values at integration points on element
80 valuesGradientAtGaussPts; ///< gradients at integration points on element
82 divergenceAtGaussPts; ///< divergence at integration points on element
83 MatrixDouble fluxesAtGaussPts; ///< fluxes at integration points on element
84
85 set<int> bcIndices;
86
87 /**
88 * \brief get dof indices where essential boundary conditions are applied
89 * @param is indices
90 * @return error code
91 */
94 std::vector<int> ids;
95 ids.insert(ids.begin(), bcIndices.begin(), bcIndices.end());
96 IS is_local;
97 CHKERR ISCreateGeneral(mField.get_comm(), ids.size(),
98 ids.empty() ? PETSC_NULLPTR : &ids[0],
99 PETSC_COPY_VALUES, &is_local);
100 CHKERR ISAllGather(is_local, is);
101 CHKERR ISDestroy(&is_local);
103 }
104
105 /**
106 * \brief set source term
107 * @param ent handle to entity on which function is evaluated
108 * @param x coord
109 * @param y coord
110 * @param z coord
111 * @param flux reference to source term set by function
112 * @return error code
113 */
114 virtual MoFEMErrorCode getSource(const EntityHandle ent, const double x,
115 const double y, const double z,
116 double &flux) {
118 flux = 0;
120 }
121
122 /**
123 * \brief natural (Dirichlet) boundary conditions (set values)
124 * @param ent handle to finite element entity
125 * @param x coord
126 * @param y coord
127 * @param z coord
128 * @param value reference to value set by function
129 * @return error code
130 */
131 virtual MoFEMErrorCode getResistivity(const EntityHandle ent, const double x,
132 const double y, const double z,
133 MatrixDouble3by3 &inv_k) {
135 inv_k.clear();
136 for (int dd = 0; dd < 3; dd++) {
137 inv_k(dd, dd) = 1;
138 }
140 }
141
142 /**
143 * \brief evaluate natural (Dirichlet) boundary conditions
144 * @param ent entity on which bc is evaluated
145 * @param x coordinate
146 * @param y coordinate
147 * @param z coordinate
148 * @param value vale
149 * @return error code
150 */
151 virtual MoFEMErrorCode getBcOnValues(const EntityHandle ent, const int gg,
152 const double x, const double y,
153 const double z, double &value) {
155 value = 0;
157 }
158
159 /**
160 * \brief essential (Neumann) boundary condition (set fluxes)
161 * @param ent handle to finite element entity
162 * @param x coord
163 * @param y coord
164 * @param z coord
165 * @param flux reference to flux which is set by function
166 * @return [description]
167 */
168 virtual MoFEMErrorCode getBcOnFluxes(const EntityHandle ent, const double x,
169 const double y, const double z,
170 double &flux) {
172 flux = 0;
174 }
175
176 /** \brief data for evaluation of het conductivity and heat capacity elements
177 * \ingroup mofem_thermal_elem
178 */
179 struct BlockData {
181 double cApacity;
182 Range tEts; ///< constatins elements in block set
183 };
184 std::map<int, BlockData>
185 setOfBlocks; ///< maps block set id with appropriate BlockData
186
187 /**
188 * \brief Add fields to database
189 * @param values name of the fields
190 * @param fluxes name of field for fluxes
191 * @param order order of approximation
192 * @return error code
193 */
194 MoFEMErrorCode addFields(const std::string &values, const std::string &fluxes,
195 const int order) {
197 // Fields
200
201 // meshset consisting all entities in mesh
202 EntityHandle root_set = mField.get_moab().get_root_set();
203 // add entities to field
204 CHKERR mField.add_ents_to_field_by_type(root_set, MBTET, fluxes);
206 CHKERR mField.set_field_order(root_set, MBTET, fluxes, order + 1);
207 CHKERR mField.set_field_order(root_set, MBTRI, fluxes, order + 1);
208 CHKERR mField.set_field_order(root_set, MBTET, values, order);
210 }
211
212 /// \brief add finite elements
213 MoFEMErrorCode addFiniteElements(const std::string &fluxes_name,
214 const std::string &values_name) {
216
217 // Set up volume element operators. Operators are used to calculate
218 // components of stiffness matrix & right hand side, in essence are used to
219 // do volume integrals over tetrahedral in this case.
220
221 // Define element "MIX". Note that this element will work with fluxes_name
222 // and values_name. This reflect bilinear form for the problem
230
231 // Define finite element to integrate over skeleton, we need that to
232 // evaluate error
233 CHKERR mField.add_finite_element("MIX_SKELETON", MF_ZERO);
235 fluxes_name);
237 fluxes_name);
239 fluxes_name);
240
241 // Look for all BLOCKSET which are MAT_THERMALSET, takes entities from those
242 // BLOCKSETS and add them to "MIX" finite element. In addition get data form
243 // that meshset and set conductivity which is used to calculate fluxes from
244 // gradients of concentration or gradient of temperature, depending how you
245 // interpret variables.
248
249 Mat_Thermal temp_data;
250 CHKERR it->getAttributeDataStructure(temp_data);
251 setOfBlocks[it->getMeshsetId()].cOnductivity =
252 temp_data.data.Conductivity;
253 setOfBlocks[it->getMeshsetId()].cApacity = temp_data.data.HeatCapacity;
254 CHKERR mField.get_moab().get_entities_by_type(
255 it->meshset, MBTET, setOfBlocks[it->getMeshsetId()].tEts, true);
257 setOfBlocks[it->getMeshsetId()].tEts, MBTET, "MIX");
258
259 Range skeleton;
260 CHKERR mField.get_moab().get_adjacencies(
261 setOfBlocks[it->getMeshsetId()].tEts, 2, false, skeleton,
262 moab::Interface::UNION);
264 "MIX_SKELETON");
265 }
266
267 // Define element to integrate natural boundary conditions, i.e. set values.
268 CHKERR mField.add_finite_element("MIX_BCVALUE", MF_ZERO);
270 fluxes_name);
272 fluxes_name);
274 fluxes_name);
276 values_name);
277
278 // Define element to apply essential boundary conditions.
281 fluxes_name);
283 fluxes_name);
285 fluxes_name);
287 values_name);
289 }
290
291 /**
292 * \brief Build problem
293 * @param ref_level mesh refinement on which mesh problem you like to built.
294 * @return error code
295 */
298 // build field
300 // get tetrahedrons which has been build previously and now in so called
301 // garbage bit level
302 Range done_tets;
303 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
304 BitRefLevel().set(0), BitRefLevel().set(), MBTET, done_tets);
305 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
306 BitRefLevel().set(BITREFLEVEL_SIZE - 1), BitRefLevel().set(), MBTET,
307 done_tets);
308 // get tetrahedrons which belong to problem bit level
309 Range ref_tets;
310 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
311 ref_level, BitRefLevel().set(), MBTET, ref_tets);
312 ref_tets = subtract(ref_tets, done_tets);
313 CHKERR mField.build_finite_elements("MIX", &ref_tets, 2);
314 // get triangles which has been build previously and now in so called
315 // garbage bit level
316 Range done_faces;
317 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
318 BitRefLevel().set(0), BitRefLevel().set(), MBTRI, done_faces);
319 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
320 BitRefLevel().set(BITREFLEVEL_SIZE - 1), BitRefLevel().set(), MBTRI,
321 done_faces);
322 // get triangles which belong to problem bit level
323 Range ref_faces;
324 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
325 ref_level, BitRefLevel().set(), MBTRI, ref_faces);
326 ref_faces = subtract(ref_faces, done_faces);
327 // build finite elements structures
328 CHKERR mField.build_finite_elements("MIX_BCFLUX", &ref_faces, 2);
329 CHKERR mField.build_finite_elements("MIX_BCVALUE", &ref_faces, 2);
330 CHKERR mField.build_finite_elements("MIX_SKELETON", &ref_faces, 2);
331 // Build adjacencies of degrees of freedom and elements
333 // Define problem
335 // set refinement level for problem
337 // Add element to problem
339 CHKERR mField.modify_problem_add_finite_element("MIX", "MIX_SKELETON");
340 // Boundary conditions
342 CHKERR mField.modify_problem_add_finite_element("MIX", "MIX_BCVALUE");
343 // build problem
344
345 ProblemsManager *prb_mng_ptr;
346 CHKERR mField.getInterface(prb_mng_ptr);
347 CHKERR prb_mng_ptr->buildProblem("MIX", true);
348 // mesh partitioning
349 // partition
350 CHKERR prb_mng_ptr->partitionProblem("MIX");
351 CHKERR prb_mng_ptr->partitionFiniteElements("MIX");
352 // what are ghost nodes, see Petsc Manual
353 CHKERR prb_mng_ptr->partitionGhostDofs("MIX");
355 }
356
359 moab::Interface &postProcMesh;
360 std::vector<EntityHandle> &mapGaussPts;
361 OpPostProc(moab::Interface &post_proc_mesh,
362 std::vector<EntityHandle> &map_gauss_pts)
364 "VALUES", UserDataOperator::OPCOL),
365 postProcMesh(post_proc_mesh), mapGaussPts(map_gauss_pts) {}
366 MoFEMErrorCode doWork(int side, EntityType type,
369 if (type != MBTET)
371 EntityHandle fe_ent = getNumeredEntFiniteElementPtr()->getEnt();
372 Tag th_error_flux;
373 CHKERR getVolumeFE()->mField.get_moab().tag_get_handle("ERROR_FLUX",
374 th_error_flux);
375 double *error_flux_ptr;
376 CHKERR getVolumeFE()->mField.get_moab().tag_get_by_ptr(
377 th_error_flux, &fe_ent, 1, (const void **)&error_flux_ptr);
378
379 Tag th_error_div;
380 CHKERR getVolumeFE()->mField.get_moab().tag_get_handle("ERROR_DIV",
381 th_error_div);
382 double *error_div_ptr;
383 CHKERR getVolumeFE()->mField.get_moab().tag_get_by_ptr(
384 th_error_div, &fe_ent, 1, (const void **)&error_div_ptr);
385
386 Tag th_error_jump;
387 CHKERR getVolumeFE()->mField.get_moab().tag_get_handle("ERROR_JUMP",
388 th_error_jump);
389 double *error_jump_ptr;
390 CHKERR getVolumeFE()->mField.get_moab().tag_get_by_ptr(
391 th_error_jump, &fe_ent, 1, (const void **)&error_jump_ptr);
392
393 {
394 double def_val = 0;
395 Tag th_error_flux;
396 CHKERR postProcMesh.tag_get_handle(
397 "ERROR_FLUX", 1, MB_TYPE_DOUBLE, th_error_flux,
398 MB_TAG_CREAT | MB_TAG_SPARSE, &def_val);
399 for (vector<EntityHandle>::iterator vit = mapGaussPts.begin();
400 vit != mapGaussPts.end(); vit++) {
401 CHKERR postProcMesh.tag_set_data(th_error_flux, &*vit, 1,
402 error_flux_ptr);
403 }
404
405 Tag th_error_div;
406 CHKERR postProcMesh.tag_get_handle(
407 "ERROR_DIV", 1, MB_TYPE_DOUBLE, th_error_div,
408 MB_TAG_CREAT | MB_TAG_SPARSE, &def_val);
409 for (vector<EntityHandle>::iterator vit = mapGaussPts.begin();
410 vit != mapGaussPts.end(); vit++) {
411 CHKERR postProcMesh.tag_set_data(th_error_div, &*vit, 1,
412 error_div_ptr);
413 }
414
415 Tag th_error_jump;
416 CHKERR postProcMesh.tag_get_handle(
417 "ERROR_JUMP", 1, MB_TYPE_DOUBLE, th_error_jump,
418 MB_TAG_CREAT | MB_TAG_SPARSE, &def_val);
419 for (vector<EntityHandle>::iterator vit = mapGaussPts.begin();
420 vit != mapGaussPts.end(); vit++) {
421 CHKERR postProcMesh.tag_set_data(th_error_jump, &*vit, 1,
422 error_jump_ptr);
423 }
424 }
426 }
427 };
428
429 /**
430 * \brief Post process results
431 * @return error code
432 */
433 MoFEMErrorCode postProc(const string out_file) {
435
437 mField);
438
439 CHKERR AddHOOps<3, 3, 3>::add(post_proc.getOpPtrVector(), {HDIV, L2});
440
441 auto values_ptr = boost::make_shared<VectorDouble>();
442 auto grad_ptr = boost::make_shared<MatrixDouble>();
443 auto flux_ptr = boost::make_shared<MatrixDouble>();
444
445 post_proc.getOpPtrVector().push_back(
446 new OpCalculateScalarFieldValues("VALUES", values_ptr));
447 post_proc.getOpPtrVector().push_back(
448 new OpCalculateScalarFieldGradient<3>("VALUES", grad_ptr));
449 post_proc.getOpPtrVector().push_back(
450 new OpCalculateHVecVectorField<3>("FLUXES", flux_ptr));
451
453
454 post_proc.getOpPtrVector().push_back(
455
456 new OpPPMap(post_proc.getPostProcMesh(), post_proc.getMapGaussPts(),
457
458 {{"VALUES", values_ptr}},
459
460 {{"GRAD", grad_ptr}, {"FLUXES", flux_ptr}},
461
462 {}, {}
463
464 ));
465
466 post_proc.getOpPtrVector().push_back(new OpPostProc(
467 post_proc.getPostProcMesh(), post_proc.getMapGaussPts()));
468
469 CHKERR mField.loop_finite_elements("MIX", "MIX", post_proc);
470
471 CHKERR post_proc.writeFile(out_file.c_str());
473 }
474
475 Vec D, D0, F;
476 Mat Aij;
477
478 /// \brief create matrices
482 ->createMPIAIJWithArrays<PetscGlobalIdx_mi_tag>("MIX", &Aij);
483 CHKERR mField.getInterface<VecManager>()->vecCreateGhost("MIX", COL, &D);
484 CHKERR mField.getInterface<VecManager>()->vecCreateGhost("MIX", COL, &D0);
485 CHKERR mField.getInterface<VecManager>()->vecCreateGhost("MIX", ROW, &F);
487 }
488
489 /**
490 * \brief solve problem
491 * @return error code
492 */
495 CHKERR MatZeroEntries(Aij);
496 CHKERR VecZeroEntries(F);
497 CHKERR VecGhostUpdateBegin(F, INSERT_VALUES, SCATTER_FORWARD);
498 CHKERR VecGhostUpdateEnd(F, INSERT_VALUES, SCATTER_FORWARD);
499 CHKERR VecZeroEntries(D0);
500 CHKERR VecGhostUpdateBegin(D0, INSERT_VALUES, SCATTER_FORWARD);
501 CHKERR VecGhostUpdateEnd(D0, INSERT_VALUES, SCATTER_FORWARD);
502 CHKERR VecZeroEntries(D);
503 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
504 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
505
506 CHKERR mField.getInterface<VecManager>()->setGlobalGhostVector(
507 "MIX", COL, D, INSERT_VALUES, SCATTER_REVERSE);
508
509 // Calculate essential boundary conditions
510
511 // clear essential bc indices, it could have dofs from other mesh refinement
512 bcIndices.clear();
513 // clear operator, just in case if some other operators are left on this
514 // element
515 feTri.getOpPtrVector().clear();
517 // set operator to calculate essential boundary conditions
518 feTri.getOpPtrVector().push_back(new OpEvaluateBcOnFluxes(*this, "FLUXES"));
519 CHKERR mField.loop_finite_elements("MIX", "MIX_BCFLUX", feTri);
520 CHKERR VecGhostUpdateBegin(D0, INSERT_VALUES, SCATTER_REVERSE);
521 CHKERR VecGhostUpdateEnd(D0, INSERT_VALUES, SCATTER_REVERSE);
522 CHKERR VecAssemblyBegin(D0);
523 CHKERR VecAssemblyEnd(D0);
524
525 // set operators to calculate matrix and right hand side vectors
526 feVol.getOpPtrVector().clear();
527 CHKERR AddHOOps<3, 3, 3>::add(feVol.getOpPtrVector(), {HDIV, L2});
528 feVol.getOpPtrVector().push_back(new OpL2Source(*this, "VALUES", F));
529 feVol.getOpPtrVector().push_back(
530 new OpFluxDivergenceAtGaussPts(*this, "FLUXES"));
531 feVol.getOpPtrVector().push_back(new OpValuesAtGaussPts(*this, "VALUES"));
532 feVol.getOpPtrVector().push_back(
533 new OpDivTauU_HdivL2(*this, "FLUXES", "VALUES", F));
534 feVol.getOpPtrVector().push_back(
535 new OpTauDotSigma_HdivHdiv(*this, "FLUXES", Aij, F));
536 feVol.getOpPtrVector().push_back(
537 new OpVDivSigma_L2Hdiv(*this, "VALUES", "FLUXES", Aij, F));
538 CHKERR mField.loop_finite_elements("MIX", "MIX", feVol);
539
540 // calculate right hand side for natural boundary conditions
541 feTri.getOpPtrVector().clear();
543 feTri.getOpPtrVector().push_back(new OpRhsBcOnValues(*this, "FLUXES", F));
544 CHKERR mField.loop_finite_elements("MIX", "MIX_BCVALUE", feTri);
545
546 // assemble matrices
547 CHKERR MatAssemblyBegin(Aij, MAT_FINAL_ASSEMBLY);
548 CHKERR MatAssemblyEnd(Aij, MAT_FINAL_ASSEMBLY);
549 CHKERR VecGhostUpdateBegin(F, ADD_VALUES, SCATTER_REVERSE);
550 CHKERR VecGhostUpdateEnd(F, ADD_VALUES, SCATTER_REVERSE);
551 CHKERR VecAssemblyBegin(F);
552 CHKERR VecAssemblyEnd(F);
553
554 {
555 double nrm2_F;
556 CHKERR VecNorm(F, NORM_2, &nrm2_F);
557 PetscPrintf(PETSC_COMM_WORLD, "nrm2_F = %6.4e\n", nrm2_F);
558 }
559
560 // CHKERR MatMultAdd(Aij,D0,F,F); ;
561
562 // for ksp solver vector is moved into rhs side
563 // for snes it is left ond the left
564 CHKERR VecScale(F, -1);
565
566 IS essential_bc_ids;
567 CHKERR getDirichletBCIndices(&essential_bc_ids);
568 CHKERR MatZeroRowsColumnsIS(Aij, essential_bc_ids, 1, D0, F);
569 CHKERR ISDestroy(&essential_bc_ids);
570
571 // {
572 // double norm;
573 // CHKERR MatNorm(Aij,NORM_FROBENIUS,&norm); ;
574 // PetscPrintf(PETSC_COMM_WORLD,"mat norm = %6.4e\n",norm);
575 // }
576
577 {
578 double nrm2_F;
579 CHKERR VecNorm(F, NORM_2, &nrm2_F);
580 PetscPrintf(PETSC_COMM_WORLD, "With BC nrm2_F = %6.4e\n", nrm2_F);
581 }
582
583 // MatView(Aij,PETSC_VIEWER_DRAW_WORLD);
584 // MatView(Aij,PETSC_VIEWER_STDOUT_WORLD);
585 // std::string wait;
586 // std::cin >> wait;
587
588 // MatView(Aij,PETSC_VIEWER_DRAW_WORLD);
589 // std::cin >> wait;
590
591 // Solve
592 KSP solver;
593 CHKERR KSPCreate(PETSC_COMM_WORLD, &solver);
594 CHKERR KSPSetOperators(solver, Aij, Aij);
595 CHKERR KSPSetFromOptions(solver);
596 CHKERR KSPSetUp(solver);
597 CHKERR KSPSolve(solver, F, D);
598 CHKERR mField.getInterface<TestingInterface>()->checkSolver(
599 solver, "unsaturated transport");
600 CHKERR KSPDestroy(&solver);
601
602 {
603 double nrm2_D;
604 CHKERR VecNorm(D, NORM_2, &nrm2_D);
605 ;
606 PetscPrintf(PETSC_COMM_WORLD, "nrm2_D = %6.4e\n", nrm2_D);
607 }
608 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
609 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
610
611 // copy data form vector on mesh
612 CHKERR mField.getInterface<VecManager>()->setGlobalGhostVector(
613 "MIX", COL, D, INSERT_VALUES, SCATTER_REVERSE);
614
616 }
617
618 /// \brief calculate residual
621 CHKERR VecZeroEntries(F);
622 CHKERR VecGhostUpdateBegin(F, INSERT_VALUES, SCATTER_FORWARD);
623 CHKERR VecGhostUpdateEnd(F, INSERT_VALUES, SCATTER_FORWARD);
624 CHKERR VecAssemblyBegin(F);
625 CHKERR VecAssemblyEnd(F);
626 // calculate residuals
627 feVol.getOpPtrVector().clear();
628 CHKERR AddHOOps<3, 3, 3>::add(feVol.getOpPtrVector(), {HDIV, L2});
629 feVol.getOpPtrVector().push_back(new OpL2Source(*this, "VALUES", F));
630 feVol.getOpPtrVector().push_back(
631 new OpFluxDivergenceAtGaussPts(*this, "FLUXES"));
632 feVol.getOpPtrVector().push_back(new OpValuesAtGaussPts(*this, "VALUES"));
633 feVol.getOpPtrVector().push_back(
634 new OpDivTauU_HdivL2(*this, "FLUXES", "VALUES", F));
635 feVol.getOpPtrVector().push_back(
636 new OpTauDotSigma_HdivHdiv(*this, "FLUXES", PETSC_NULLPTR, F));
637 feVol.getOpPtrVector().push_back(
638 new OpVDivSigma_L2Hdiv(*this, "VALUES", "FLUXES", PETSC_NULLPTR, F));
639 CHKERR mField.loop_finite_elements("MIX", "MIX", feVol);
640 feTri.getOpPtrVector().clear();
641 feTri.getOpPtrVector().push_back(new OpRhsBcOnValues(*this, "FLUXES", F));
642 CHKERR mField.loop_finite_elements("MIX", "MIX_BCVALUE", feTri);
643 CHKERR VecGhostUpdateBegin(F, ADD_VALUES, SCATTER_REVERSE);
644 CHKERR VecGhostUpdateEnd(F, ADD_VALUES, SCATTER_REVERSE);
645 CHKERR VecAssemblyBegin(F);
646 CHKERR VecAssemblyEnd(F);
647 // CHKERR VecAXPY(F,-1.,D0);
648 // CHKERR MatZeroRowsIS(Aij,essential_bc_ids,1,PETSC_NULLPTR,F);
649 {
650 std::vector<int> ids;
651 ids.insert(ids.begin(), bcIndices.begin(), bcIndices.end());
652 std::vector<double> vals(ids.size(), 0);
653 CHKERR VecSetValues(F, ids.size(), &*ids.begin(), &*vals.begin(),
654 INSERT_VALUES);
655 CHKERR VecAssemblyBegin(F);
656 CHKERR VecAssemblyEnd(F);
657 }
658 {
659 double nrm2_F;
660 CHKERR VecNorm(F, NORM_2, &nrm2_F);
661 PetscPrintf(PETSC_COMM_WORLD, "nrm2_F = %6.4e\n", nrm2_F);
662 const double eps = 1e-8;
663 if (nrm2_F > eps) {
664 // SETERRQ(PETSC_COMM_SELF,MOFEM_ATOM_TEST_INVALID,"problem with
665 // residual");
666 }
667 }
669 }
670
671 /** \brief Calculate error on elements
672
673 \todo this functions runs serial, in future should be parallel and work on
674 distributed meshes.
675
676 */
679 errorMap.clear();
680 sumErrorFlux = 0;
681 sumErrorDiv = 0;
682 sumErrorJump = 0;
683 feTri.getOpPtrVector().clear();
684 feTri.getOpPtrVector().push_back(new OpSkeleton(*this, "FLUXES"));
685 CHKERR mField.loop_finite_elements("MIX", "MIX_SKELETON", feTri, 0,
686 mField.get_comm_size());
687 feVol.getOpPtrVector().clear();
688 CHKERR AddHOOps<3, 3, 3>::add(feVol.getOpPtrVector(), {HDIV, L2});
689 feVol.getOpPtrVector().push_back(
690 new OpFluxDivergenceAtGaussPts(*this, "FLUXES"));
691 feVol.getOpPtrVector().push_back(
692 new OpValuesGradientAtGaussPts(*this, "VALUES"));
693 feVol.getOpPtrVector().push_back(new OpError(*this, "VALUES"));
694 CHKERR mField.loop_finite_elements("MIX", "MIX", feVol, 0,
695 mField.get_comm_size());
696 const Problem *problem_ptr;
697 CHKERR mField.get_problem("MIX", &problem_ptr);
698 PetscPrintf(mField.get_comm(),
699 "Nb dofs %d error flux^2 = %6.4e error div^2 = %6.4e error "
700 "jump^2 = %6.4e error tot^2 = %6.4e\n",
701 problem_ptr->getNbDofsRow(), sumErrorFlux, sumErrorDiv,
702 sumErrorJump, sumErrorFlux + sumErrorDiv + sumErrorJump);
704 }
705
706 /// \brief destroy matrices
709 CHKERR MatDestroy(&Aij);
710 ;
711 CHKERR VecDestroy(&D);
712 ;
713 CHKERR VecDestroy(&D0);
714 ;
715 CHKERR VecDestroy(&F);
716 ;
718 }
719
720 /**
721 \brief Assemble \f$\int_\mathcal{T} \mathbf{A} \boldsymbol\sigma \cdot
722 \boldsymbol\tau \textrm{d}\mathcal{T}\f$
723
724 \ingroup mofem_mix_transport_elem
725 */
728
730 Mat Aij;
731 Vec F;
732
734 const std::string flux_name, Mat aij, Vec f)
736 flux_name, flux_name,
737 UserDataOperator::OPROWCOL | UserDataOperator::OPCOL),
738 cTx(ctx), Aij(aij), F(f) {
739 sYmm = true;
740 }
741
742 MatrixDouble NN, transNN;
745
746 /**
747 * \brief Assemble matrix
748 * @param row_side local index of row entity on element
749 * @param col_side local index of col entity on element
750 * @param row_type type of row entity, f.e. MBVERTEX, MBEDGE, or MBTET
751 * @param col_type type of col entity, f.e. MBVERTEX, MBEDGE, or MBTET
752 * @param row_data data for row
753 * @param col_data data for col
754 * @return error code
755 */
756 MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type,
757 EntityType col_type,
759 EntitiesFieldData::EntData &col_data) {
761 if (Aij == PETSC_NULLPTR)
763 if (row_data.getIndices().size() == 0)
765 if (col_data.getIndices().size() == 0)
767 EntityHandle fe_ent = getNumeredEntFiniteElementPtr()->getEnt();
768 int nb_row = row_data.getIndices().size();
769 int nb_col = col_data.getIndices().size();
770 NN.resize(nb_row, nb_col, false);
771 NN.clear();
772 FTensor::Index<'i', 3> i;
773 FTensor::Index<'j', 3> j;
774 invK.resize(3, 3, false);
775 // get access to resistivity data by tensor rank 2
777 &invK(0, 0), &invK(0, 1), &invK(0, 2), &invK(1, 0), &invK(1, 1),
778 &invK(1, 2), &invK(2, 0), &invK(2, 1), &invK(2, 2));
779 // Get base functions
780 auto t_n_hdiv_row = row_data.getFTensor1N<3>();
782 int nb_gauss_pts = row_data.getN().size1();
783 for (int gg = 0; gg != nb_gauss_pts; gg++) {
784 // get integration weight and multiply by element volume
785 double w = getGaussPts()(3, gg) * getVolume();
786 const double x = getCoordsAtGaussPts()(gg, 0);
787 const double y = getCoordsAtGaussPts()(gg, 1);
788 const double z = getCoordsAtGaussPts()(gg, 2);
789 // calculate receptivity (invers of conductivity)
790 CHKERR cTx.getResistivity(fe_ent, x, y, z, invK);
791 for (int kk = 0; kk != nb_row; kk++) {
793 &col_data.getVectorN<3>(gg)(0, HVEC0),
794 &col_data.getVectorN<3>(gg)(0, HVEC1),
795 &col_data.getVectorN<3>(gg)(0, HVEC2), 3);
796 t_row(j) = w * t_n_hdiv_row(i) * t_inv_k(i, j);
797 for (int ll = 0; ll != nb_col; ll++) {
798 NN(kk, ll) += t_row(j) * t_n_hdiv_col(j);
799 ++t_n_hdiv_col;
800 }
801 ++t_n_hdiv_row;
802 }
803 }
804 Mat a = (Aij != PETSC_NULLPTR) ? Aij : getFEMethod()->ts_B;
805 CHKERR MatSetValues(a, nb_row, &row_data.getIndices()[0], nb_col,
806 &col_data.getIndices()[0], &NN(0, 0), ADD_VALUES);
807 // matrix is symmetric, assemble other part
808 if (row_side != col_side || row_type != col_type) {
809 transNN.resize(nb_col, nb_row);
810 noalias(transNN) = trans(NN);
811 CHKERR MatSetValues(a, nb_col, &col_data.getIndices()[0], nb_row,
812 &row_data.getIndices()[0], &transNN(0, 0),
813 ADD_VALUES);
814 }
815
817 }
818
819 /**
820 * \brief Assemble matrix
821 * @param side local index of row entity on element
822 * @param type type of row entity, f.e. MBVERTEX, MBEDGE, or MBTET
823 * @param data data for row
824 * @return error code
825 */
826 MoFEMErrorCode doWork(int side, EntityType type,
829 if (F == PETSC_NULLPTR)
831 int nb_row = data.getIndices().size();
832 if (nb_row == 0)
834
835 EntityHandle fe_ent = getNumeredEntFiniteElementPtr()->getEnt();
836 Nf.resize(nb_row);
837 Nf.clear();
838 FTensor::Index<'i', 3> i;
839 FTensor::Index<'j', 3> j;
840 invK.resize(3, 3, false);
841 Nf.resize(nb_row);
842 Nf.clear();
843 // get access to resistivity data by tensor rank 2
845 &invK(0, 0), &invK(0, 1), &invK(0, 2), &invK(1, 0), &invK(1, 1),
846 &invK(1, 2), &invK(2, 0), &invK(2, 1), &invK(2, 2));
847 // get base functions
848 auto t_n_hdiv = data.getFTensor1N<3>();
849 auto t_flux = getFTensor1FromMat<3>(cTx.fluxesAtGaussPts);
850 int nb_gauss_pts = data.getN().size1();
851 for (int gg = 0; gg < nb_gauss_pts; gg++) {
852 double w = getGaussPts()(3, gg) * getVolume();
853 const double x = getCoordsAtGaussPts()(gg, 0);
854 const double y = getCoordsAtGaussPts()(gg, 1);
855 const double z = getCoordsAtGaussPts()(gg, 2);
856 CHKERR cTx.getResistivity(fe_ent, x, y, z, invK);
857 for (int ll = 0; ll != nb_row; ll++) {
858 Nf[ll] += w * t_n_hdiv(i) * t_inv_k(i, j) * t_flux(j);
859 ++t_n_hdiv;
860 }
861 ++t_flux;
862 }
863 CHKERR VecSetValues(F, nb_row, &data.getIndices()[0], &Nf[0], ADD_VALUES);
864
866 }
867 };
868
869 /** \brief Assemble \f$ \int_\mathcal{T} u \textrm{div}[\boldsymbol\tau]
870 * \textrm{d}\mathcal{T} \f$
871 */
874
876 Vec F;
877
878 OpDivTauU_HdivL2(MixTransportElement &ctx, const std::string flux_name_row,
879 string val_name_col, Vec f)
881 flux_name_row, val_name_col, UserDataOperator::OPROW),
882 cTx(ctx), F(f) {
883 // this operator is not symmetric setting this variable makes element
884 // operator to loop over element entities (sub-simplices) without
885 // assumption that off-diagonal matrices are symmetric.
886 sYmm = false;
887 }
888
890
891 MoFEMErrorCode doWork(int side, EntityType type,
894 if (data.getFieldData().size() == 0)
896 int nb_row = data.getIndices().size();
897 Nf.resize(nb_row);
898 Nf.clear();
899 divVec.resize(data.getN().size2() / 3, 0);
900 if (divVec.size() != data.getIndices().size()) {
901 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
902 "data inconsistency");
903 }
904 int nb_gauss_pts = data.getN().size1();
905
906 FTensor::Index<'i', 3> i;
907 auto t_base_diff_hdiv = data.getFTensor2DiffN<3, 3>();
908
909 int gg = 0;
910 for (; gg < nb_gauss_pts; gg++) {
911 double w = getGaussPts()(3, gg) * getVolume();
912 for (auto &v : divVec) {
913 v = t_base_diff_hdiv(i, i);
914 ++t_base_diff_hdiv;
915 }
916 noalias(Nf) -= w * divVec * cTx.valuesAtGaussPts[gg];
917 }
918 CHKERR VecSetValues(F, nb_row, &data.getIndices()[0], &Nf[0], ADD_VALUES);
919 ;
920
922 }
923 };
924
925 /** \brief \f$ \int_\mathcal{T} \textrm{div}[\boldsymbol\sigma] v
926 * \textrm{d}\mathcal{T} \f$
927 */
930
932 Mat Aij;
933 Vec F;
934
935 /**
936 * \brief Constructor
937 */
938 OpVDivSigma_L2Hdiv(MixTransportElement &ctx, const std::string val_name_row,
939 string flux_name_col, Mat aij, Vec f)
941 val_name_row, flux_name_col,
942 UserDataOperator::OPROW | UserDataOperator::OPROWCOL),
943 cTx(ctx), Aij(aij), F(f) {
944
945 // this operator is not symmetric setting this variable makes element
946 // operator to loop over element entities without
947 // assumption that off-diagonal matrices are symmetric.
948 sYmm = false;
949 }
950
951 MatrixDouble NN, transNN;
953
954 /**
955 * \brief Do calculations
956 * @param row_side local index of entity on row
957 * @param col_side local index of entity on column
958 * @param row_type type of row entity
959 * @param col_type type of col entity
960 * @param row_data row data structure carrying information about base
961 * functions, DOFs indices, etc.
962 * @param col_data column data structure carrying information about base
963 * functions, DOFs indices, etc.
964 * @return error code
965 */
966 MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type,
967 EntityType col_type,
969 EntitiesFieldData::EntData &col_data) {
971 if (Aij == PETSC_NULLPTR)
973 if (row_data.getFieldData().size() == 0)
975 if (col_data.getFieldData().size() == 0)
977 int nb_row = row_data.getFieldData().size();
978 int nb_col = col_data.getFieldData().size();
979 NN.resize(nb_row, nb_col);
980 NN.clear();
981 divVec.resize(nb_col, false);
982
983 FTensor::Index<'i', 3> i;
984 auto t_base_diff_hdiv = col_data.getFTensor2DiffN<3, 3>();
985
986 int nb_gauss_pts = row_data.getN().size1();
987 for (int gg = 0; gg < nb_gauss_pts; gg++) {
988 double w = getGaussPts()(3, gg) * getVolume();
989 for (auto &v : divVec) {
990 v = t_base_diff_hdiv(i, i);
991 ++t_base_diff_hdiv;
992 }
993 noalias(NN) += w * outer_prod(row_data.getN(gg), divVec);
994 }
995 CHKERR MatSetValues(Aij, nb_row, &row_data.getIndices()[0], nb_col,
996 &col_data.getIndices()[0], &NN(0, 0), ADD_VALUES);
997 transNN.resize(nb_col, nb_row);
998 ublas::noalias(transNN) = -trans(NN);
999 CHKERR MatSetValues(Aij, nb_col, &col_data.getIndices()[0], nb_row,
1000 &row_data.getIndices()[0], &transNN(0, 0),
1001 ADD_VALUES);
1003 }
1004
1005 MoFEMErrorCode doWork(int side, EntityType type,
1008 if (data.getIndices().size() == 0)
1010 if (data.getIndices().size() != data.getN().size2()) {
1011 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1012 "data inconsistency");
1013 }
1014 int nb_row = data.getIndices().size();
1015 Nf.resize(nb_row);
1016 Nf.clear();
1017 int nb_gauss_pts = data.getN().size1();
1018 for (int gg = 0; gg < nb_gauss_pts; gg++) {
1019 double w = getGaussPts()(3, gg) * getVolume();
1020 noalias(Nf) += w * data.getN(gg) * cTx.divergenceAtGaussPts[gg];
1021 }
1022 CHKERR VecSetValues(F, nb_row, &data.getIndices()[0], &Nf[0], ADD_VALUES);
1023 ;
1025 }
1026 };
1027
1028 /** \brief Calculate source therms, i.e. \f$\int_\mathcal{T} f v
1029 * \textrm{d}\mathcal{T}\f$
1030 */
1034 Vec F;
1035
1036 OpL2Source(MixTransportElement &ctx, const std::string val_name, Vec f)
1038 val_name, UserDataOperator::OPROW),
1039 cTx(ctx), F(f) {}
1040
1042 MoFEMErrorCode doWork(int side, EntityType type,
1045 if (data.getFieldData().size() == 0)
1047 EntityHandle fe_ent = getNumeredEntFiniteElementPtr()->getEnt();
1048 int nb_row = data.getFieldData().size();
1049 Nf.resize(nb_row, false);
1050 Nf.clear();
1051 int nb_gauss_pts = data.getN().size1();
1052 for (int gg = 0; gg < nb_gauss_pts; gg++) {
1053 double w = getGaussPts()(3, gg) * getVolume();
1054 const double x = getCoordsAtGaussPts()(gg, 0);
1055 const double y = getCoordsAtGaussPts()(gg, 1);
1056 const double z = getCoordsAtGaussPts()(gg, 2);
1057 double flux = 0;
1058 CHKERR cTx.getSource(fe_ent, x, y, z, flux);
1059 noalias(Nf) += w * data.getN(gg) * flux;
1060 }
1061 CHKERR VecSetValues(F, nb_row, &data.getIndices()[0], &Nf[0], ADD_VALUES);
1062 ;
1064 }
1065 };
1066
1067 /**
1068 * \brief calculate \f$ \int_\mathcal{S} {\boldsymbol\tau} \cdot \mathbf{n}u
1069 \textrm{d}\mathcal{S} \f$
1070
1071 * This terms comes from differentiation by parts. Note that in this Dirichlet
1072 * boundary conditions are natural.
1073
1074 */
1077
1079 Vec F;
1080
1081 /**
1082 * \brief Constructor
1083 */
1084 OpRhsBcOnValues(MixTransportElement &ctx, const std::string fluxes_name,
1085 Vec f)
1087 fluxes_name, UserDataOperator::OPROW),
1088 cTx(ctx), F(f) {}
1089
1091
1092 /**
1093 * \brief Integrate boundary condition
1094 * @param side local index of entity
1095 * @param type type of entity
1096 * @param data data on entity
1097 * @return error code
1098 */
1099 MoFEMErrorCode doWork(int side, EntityType type,
1102 if (data.getFieldData().size() == 0)
1104 EntityHandle fe_ent = getNumeredEntFiniteElementPtr()->getEnt();
1105 nF.resize(data.getIndices().size());
1106 nF.clear();
1107 int nb_gauss_pts = data.getN().size1();
1108 for (int gg = 0; gg < nb_gauss_pts; gg++) {
1109 const double x = getCoordsAtGaussPts()(gg, 0);
1110 const double y = getCoordsAtGaussPts()(gg, 1);
1111 const double z = getCoordsAtGaussPts()(gg, 2);
1112
1113 double value;
1114 CHKERR cTx.getBcOnValues(fe_ent, gg, x, y, z, value);
1115 ;
1116 double w = getGaussPts()(2, gg) * 0.5;
1117 if (getNormalsAtGaussPts().size1() == (unsigned int)nb_gauss_pts) {
1118 noalias(nF) +=
1119 w * prod(data.getVectorN<3>(gg), getNormalsAtGaussPts(gg)) *
1120 value;
1121 } else {
1122 noalias(nF) += w * prod(data.getVectorN<3>(gg), getNormal()) * value;
1123 }
1124 }
1125 Vec f = (F != PETSC_NULLPTR) ? F : getFEMethod()->ts_F;
1126 CHKERR VecSetValues(f, data.getIndices().size(), &data.getIndices()[0],
1127 &nF[0], ADD_VALUES);
1128
1130 }
1131 };
1132
1133 /**
1134 * \brief Evaluate boundary conditions on fluxes.
1135 *
1136 * Note that Neumann boundary conditions here are essential. So it is opposite
1137 * what you find in displacement finite element method.
1138 *
1139
1140 * Here we have to solve for degrees of freedom on boundary such base
1141 functions
1142 * approximate flux.
1143
1144 *
1145 */
1149 OpEvaluateBcOnFluxes(MixTransportElement &ctx, const std::string flux_name)
1151 flux_name, UserDataOperator::OPROW),
1152 cTx(ctx) {}
1153
1157
1158 MoFEMErrorCode doWork(int side, EntityType type,
1161 if (data.getFieldData().size() == 0)
1163 EntityHandle fe_ent = getNumeredEntFiniteElementPtr()->getEnt();
1164 int nb_dofs = data.getFieldData().size();
1165 int nb_gauss_pts = data.getN().size1();
1166 if (3 * nb_dofs != static_cast<int>(data.getN().size2())) {
1167 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
1168 "wrong number of dofs");
1169 }
1170 NN.resize(nb_dofs, nb_dofs);
1171 Nf.resize(nb_dofs);
1172 NN.clear();
1173 Nf.clear();
1174
1175 // Get normal vector. Note that when higher order geometry is set, then
1176 // face element could be curved, i.e. normal can be different at each
1177 // integration point.
1178 double *normal_ptr;
1179 if (getNormalsAtGaussPts().size1() == (unsigned int)nb_gauss_pts) {
1180 // HO geometry
1181 normal_ptr = &getNormalsAtGaussPts(0)[0];
1182 } else {
1183 // Linear geometry, i.e. constant normal on face
1184 normal_ptr = &getNormal()[0];
1185 }
1186 // set tensor from pointer
1187 FTensor::Tensor1<const double *, 3> t_normal(normal_ptr, &normal_ptr[1],
1188 &normal_ptr[2], 3);
1189 // get base functions
1190 auto t_n_hdiv_row = data.getFTensor1N<3>();
1191
1192 double nrm2 = 0;
1193
1194 // loop over integration points
1195 for (int gg = 0; gg < nb_gauss_pts; gg++) {
1196
1197 // get integration point coordinates
1198 const double x = getCoordsAtGaussPts()(gg, 0);
1199 const double y = getCoordsAtGaussPts()(gg, 1);
1200 const double z = getCoordsAtGaussPts()(gg, 2);
1201
1202 // get flux on fece for given element handle and coordinates
1203 double flux;
1204 CHKERR cTx.getBcOnFluxes(fe_ent, x, y, z, flux);
1205 ;
1206 // get weight for integration rule
1207 double w = getGaussPts()(2, gg);
1208 if (gg == 0) {
1209 nrm2 = sqrt(t_normal(i) * t_normal(i));
1210 }
1211
1212 // set tensor of rank 0 to matrix NN elements
1213 // loop over base functions on rows and columns
1214 for (int ll = 0; ll != nb_dofs; ll++) {
1215 // get column on shape functions
1217 &data.getVectorN<3>(gg)(0, HVEC0),
1218 &data.getVectorN<3>(gg)(0, HVEC1),
1219 &data.getVectorN<3>(gg)(0, HVEC2), 3);
1220 for (int kk = 0; kk <= ll; kk++) {
1221 NN(ll, kk) += w * t_n_hdiv_row(i) * t_n_hdiv_col(i);
1222 ++t_n_hdiv_col;
1223 }
1224 // right hand side
1225 Nf[ll] += w * t_n_hdiv_row(i) * t_normal(i) * flux / nrm2;
1226 ++t_n_hdiv_row;
1227 }
1228
1229 // If HO geometry increment t_normal to next integration point
1230 if (getNormalsAtGaussPts().size1() == (unsigned int)nb_gauss_pts) {
1231 ++t_normal;
1232 nrm2 = sqrt(t_normal(i) * t_normal(i));
1233 }
1234 }
1235 // get global dofs indices on element
1236 cTx.bcIndices.insert(data.getIndices().begin(), data.getIndices().end());
1237 // factor matrix
1239 // solve local problem
1240 cholesky_solve(NN, Nf, ublas::lower());
1241
1242 // set solution to vector
1243 CHKERR VecSetOption(cTx.D0, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE);
1244 CHKERR VecSetValues(cTx.D0, nb_dofs, &*data.getIndices().begin(),
1245 &*Nf.begin(), INSERT_VALUES);
1246 for (int dd = 0; dd != nb_dofs; ++dd)
1247 data.getFieldDofs()[dd]->getFieldData() = Nf[dd];
1248
1250 }
1251 };
1252
1253 /**
1254 * \brief Calculate values at integration points
1255 */
1258
1260
1262 const std::string val_name = "VALUES")
1264 val_name, UserDataOperator::OPROW),
1265 cTx(ctx) {}
1266
1268
1269 MoFEMErrorCode doWork(int side, EntityType type,
1272 if (data.getFieldData().size() == 0)
1274
1275 int nb_gauss_pts = data.getN().size1();
1276 cTx.valuesAtGaussPts.resize(nb_gauss_pts);
1277 for (int gg = 0; gg < nb_gauss_pts; gg++) {
1278 cTx.valuesAtGaussPts[gg] =
1279 inner_prod(trans(data.getN(gg)), data.getFieldData());
1280 }
1281
1283 }
1284 };
1285
1286 /**
1287 * \brief Calculate gradients of values at integration points
1288 */
1291
1293
1295 const std::string val_name = "VALUES")
1297 val_name, UserDataOperator::OPROW),
1298 cTx(ctx) {}
1300
1301 MoFEMErrorCode doWork(int side, EntityType type,
1304 if (data.getFieldData().size() == 0)
1306 int nb_gauss_pts = data.getDiffN().size1();
1307 cTx.valuesGradientAtGaussPts.resize(3, nb_gauss_pts);
1308 for (int gg = 0; gg < nb_gauss_pts; gg++) {
1309 ublas::matrix_column<MatrixDouble> values_grad_at_gauss_pts(
1310 cTx.valuesGradientAtGaussPts, gg);
1311 noalias(values_grad_at_gauss_pts) =
1312 prod(trans(data.getDiffN(gg)), data.getFieldData());
1313 }
1315 }
1316 };
1317
1318 /**
1319 * \brief calculate flux at integration point
1320 */
1323
1325
1331
1333 MoFEMErrorCode doWork(int side, EntityType type,
1336
1337 if (data.getFieldData().size() == 0)
1339 int nb_gauss_pts = data.getDiffN().size1();
1340 int nb_dofs = data.getFieldData().size();
1341 cTx.fluxesAtGaussPts.resize(nb_gauss_pts, 3);
1342 cTx.divergenceAtGaussPts.resize(nb_gauss_pts);
1343 if (type == MBTRI && side == 0) {
1344 cTx.divergenceAtGaussPts.clear();
1345 cTx.fluxesAtGaussPts.clear();
1346 }
1347 divVec.resize(nb_dofs);
1348
1349 FTensor::Index<'i', 3> i;
1350 auto t_base_diff_hdiv = data.getFTensor2DiffN<3, 3>();
1351
1352 for (int gg = 0; gg < nb_gauss_pts; gg++) {
1353 for (auto &v : divVec) {
1354 v = t_base_diff_hdiv(i, i);
1355 ++t_base_diff_hdiv;
1356 }
1357 cTx.divergenceAtGaussPts[gg] += inner_prod(divVec, data.getFieldData());
1358 ublas::matrix_row<MatrixDouble> flux_at_gauss_pt(cTx.fluxesAtGaussPts,
1359 gg);
1360 flux_at_gauss_pt +=
1361 prod(trans(data.getVectorN<3>(gg)), data.getFieldData());
1362 }
1364 }
1365 };
1366
1367 map<double, EntityHandle> errorMap;
1371
1372 /** \brief calculate error evaluator
1373 */
1374 struct OpError
1376
1378
1383 virtual ~OpError() {}
1384
1387
1388 MoFEMErrorCode doWork(int side, EntityType type,
1391 if (type != MBTET)
1393 invK.resize(3, 3, false);
1394 int nb_gauss_pts = data.getN().size1();
1395 EntityHandle fe_ent = getNumeredEntFiniteElementPtr()->getEnt();
1396 double def_val = 0;
1397 Tag th_error_flux, th_error_div;
1398 CHKERR cTx.mField.get_moab().tag_get_handle(
1399 "ERROR_FLUX", 1, MB_TYPE_DOUBLE, th_error_flux,
1400 MB_TAG_CREAT | MB_TAG_SPARSE, &def_val);
1401 double *error_flux_ptr;
1402 CHKERR cTx.mField.get_moab().tag_get_by_ptr(
1403 th_error_flux, &fe_ent, 1, (const void **)&error_flux_ptr);
1404
1405 CHKERR cTx.mField.get_moab().tag_get_handle(
1406 "ERROR_DIV", 1, MB_TYPE_DOUBLE, th_error_div,
1407 MB_TAG_CREAT | MB_TAG_SPARSE, &def_val);
1408 double *error_div_ptr;
1409 CHKERR cTx.mField.get_moab().tag_get_by_ptr(
1410 th_error_div, &fe_ent, 1, (const void **)&error_div_ptr);
1411
1412 Tag th_error_jump;
1413 CHKERR cTx.mField.get_moab().tag_get_handle(
1414 "ERROR_JUMP", 1, MB_TYPE_DOUBLE, th_error_jump,
1415 MB_TAG_CREAT | MB_TAG_SPARSE, &def_val);
1416 double *error_jump_ptr;
1417 CHKERR cTx.mField.get_moab().tag_get_by_ptr(
1418 th_error_jump, &fe_ent, 1, (const void **)&error_jump_ptr);
1419 *error_jump_ptr = 0;
1420
1421 /// characteristic size of the element
1422 const double h = pow(getVolume() * 12 / std::sqrt(2), (double)1 / 3);
1423
1424 for (int ff = 0; ff != 4; ff++) {
1425 EntityHandle face;
1426 CHKERR cTx.mField.get_moab().side_element(fe_ent, 2, ff, face);
1427 double *error_face_jump_ptr;
1428 CHKERR cTx.mField.get_moab().tag_get_by_ptr(
1429 th_error_jump, &face, 1, (const void **)&error_face_jump_ptr);
1430 *error_face_jump_ptr = (1 / sqrt(h)) * sqrt(*error_face_jump_ptr);
1431 *error_face_jump_ptr = pow(*error_face_jump_ptr, 2);
1432 *error_jump_ptr += *error_face_jump_ptr;
1433 }
1434
1435 *error_flux_ptr = 0;
1436 *error_div_ptr = 0;
1437 deltaFlux.resize(3, false);
1438 for (int gg = 0; gg < nb_gauss_pts; gg++) {
1439 double w = getGaussPts()(3, gg) * getVolume();
1440 const double x = getCoordsAtGaussPts()(gg, 0);
1441 const double y = getCoordsAtGaussPts()(gg, 1);
1442 const double z = getCoordsAtGaussPts()(gg, 2);
1443 double flux;
1444 CHKERR cTx.getSource(fe_ent, x, y, z, flux);
1445 ;
1446 *error_div_ptr += w * pow(cTx.divergenceAtGaussPts[gg] - flux, 2);
1447 CHKERR cTx.getResistivity(fe_ent, x, y, z, invK);
1448 ;
1449 ublas::matrix_row<MatrixDouble> flux_at_gauss_pt(cTx.fluxesAtGaussPts,
1450 gg);
1451 ublas::matrix_column<MatrixDouble> values_grad_at_gauss_pts(
1452 cTx.valuesGradientAtGaussPts, gg);
1453 noalias(deltaFlux) =
1454 prod(invK, flux_at_gauss_pt) + values_grad_at_gauss_pts;
1455 *error_flux_ptr += w * inner_prod(deltaFlux, deltaFlux);
1456 }
1457 *error_div_ptr = h * sqrt(*error_div_ptr);
1458 *error_div_ptr = pow(*error_div_ptr, 2);
1459 cTx.errorMap[sqrt(*error_flux_ptr + *error_div_ptr + *error_jump_ptr)] =
1460 fe_ent;
1461 // Sum/Integrate all errors
1462 cTx.sumErrorFlux += *error_flux_ptr * getVolume();
1463 cTx.sumErrorDiv += *error_div_ptr * getVolume();
1464 // FIXME: Summation should be while skeleton is calculated
1465 cTx.sumErrorJump +=
1466 *error_jump_ptr * getVolume(); /// FIXME: this need to be fixed
1468 }
1469 };
1470
1471 /**
1472 * \brief calculate jump on entities
1473 */
1476
1477 /**
1478 * \brief volume element to get values from adjacent tets to face
1479 */
1481
1482 /** store values at integration point, key of the map is sense of face in
1483 * respect to adjacent tetrahedra
1484 */
1485 map<int, VectorDouble> valMap;
1486
1487 /**
1488 * \brief calculate values on adjacent tetrahedra to face
1489 */
1492 map<int, VectorDouble> &valMap;
1493 OpVolSide(map<int, VectorDouble> &val_map)
1495 "VALUES", UserDataOperator::OPROW),
1496 valMap(val_map) {}
1497 MoFEMErrorCode doWork(int side, EntityType type,
1500 if (data.getFieldData().size() == 0)
1502 const auto nb_gauss_pts = data.getN().size1();
1503 valMap[getSkeletonSense()].resize(nb_gauss_pts);
1504 for (auto gg = 0; gg != nb_gauss_pts; gg++) {
1505 valMap[getSkeletonSense()][gg] =
1506 inner_prod(trans(data.getN(gg)), data.getFieldData());
1507 }
1509 }
1510 };
1511
1513
1514 OpSkeleton(MixTransportElement &ctx, const std::string flux_name)
1516 flux_name, UserDataOperator::OPROW),
1517 volSideFe(ctx.mField), cTx(ctx) {
1518 volSideFe.getOpPtrVector().push_back(new OpSkeleton::OpVolSide(valMap));
1519 }
1520
1521 MoFEMErrorCode doWork(int side, EntityType type,
1524
1525 if (type == MBTRI) {
1526 EntityHandle fe_ent = getNumeredEntFiniteElementPtr()->getEnt();
1527
1528 double def_val = 0;
1529 Tag th_error_jump;
1530 CHKERR cTx.mField.get_moab().tag_get_handle(
1531 "ERROR_JUMP", 1, MB_TYPE_DOUBLE, th_error_jump,
1532 MB_TAG_CREAT | MB_TAG_SPARSE, &def_val);
1533 double *error_jump_ptr;
1534 CHKERR cTx.mField.get_moab().tag_get_by_ptr(
1535 th_error_jump, &fe_ent, 1, (const void **)&error_jump_ptr);
1536 *error_jump_ptr = 0;
1537
1538 // check if this is essential boundary condition
1539 EntityHandle essential_bc_meshset =
1540 cTx.mField.get_finite_element_meshset("MIX_BCFLUX");
1541 if (cTx.mField.get_moab().contains_entities(essential_bc_meshset,
1542 &fe_ent, 1)) {
1543 // essential bc, np jump then, exit and go to next face
1545 }
1546
1547 // calculate values form adjacent tets
1548 valMap.clear();
1549 CHKERR loopSideVolumes("MIX", volSideFe);
1550 ;
1551
1552 int nb_gauss_pts = data.getN().size1();
1553
1554 // it is only one face, so it has to be bc natural boundary condition
1555 if (valMap.size() == 1) {
1556 if (static_cast<int>(valMap.begin()->second.size()) != nb_gauss_pts) {
1557 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
1558 "wrong number of integration points");
1559 }
1560 for (int gg = 0; gg != nb_gauss_pts; gg++) {
1561 const double x = getCoordsAtGaussPts()(gg, 0);
1562 const double y = getCoordsAtGaussPts()(gg, 1);
1563 const double z = getCoordsAtGaussPts()(gg, 2);
1564 double value;
1565 CHKERR cTx.getBcOnValues(fe_ent, gg, x, y, z, value);
1566 double w = getGaussPts()(2, gg);
1567 if (static_cast<int>(getNormalsAtGaussPts().size1()) ==
1568 nb_gauss_pts) {
1569 w *= norm_2(getNormalsAtGaussPts(gg)) * 0.5;
1570 } else {
1571 w *= getArea();
1572 }
1573 *error_jump_ptr += w * pow(value - valMap.begin()->second[gg], 2);
1574 }
1575 } else if (valMap.size() == 2) {
1576 for (int gg = 0; gg != nb_gauss_pts; gg++) {
1577 double w = getGaussPts()(2, gg);
1578 if (getNormalsAtGaussPts().size1() == (unsigned int)nb_gauss_pts) {
1579 w *= norm_2(getNormalsAtGaussPts(gg)) * 0.5;
1580 } else {
1581 w *= getArea();
1582 }
1583 double delta = valMap.at(1)[gg] - valMap.at(-1)[gg];
1584 *error_jump_ptr += w * pow(delta, 2);
1585 }
1586 } else {
1587 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
1588 "data inconsistency, wrong number of neighbors "
1589 "valMap.size() = %zu",
1590 valMap.size());
1591 }
1592 }
1593
1595 }
1596 };
1597};
1598
1599} // namespace MixTransport
1600
1601#endif //_MIX_TRANPORT_ELEMENT_HPP_
1602
1603/***************************************************************************/
1604/**
1605 * \defgroup mofem_mix_transport_elem Mix transport element
1606 * \ingroup user_modules
1607 ******************************************************************************/
std::string type
SmartPetscObj< Vec > values
constexpr double a
static const double eps
cholesky decomposition
void cholesky_solve(const TRIA &L, VEC &x, ublas::lower)
solve system L L^T x = b inplace
Definition cholesky.hpp:221
size_t cholesky_decompose(const MATRIX &A, TRIA &L)
decompose the symmetric positive definit matrix A into product L L^T.
Definition cholesky.hpp:52
@ COL
@ ROW
@ MF_ZERO
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ DEMKOWICZ_JACOBI_BASE
Definition definitions.h:66
#define BITREFLEVEL_SIZE
max number of refinements
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ L2
field with C-1 continuity
Definition definitions.h:88
@ HDIV
field with continuous normal traction
Definition definitions.h:87
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MAT_THERMALSET
block name is "MAT_THERMAL"
@ BLOCKSET
@ HVEC0
@ HVEC1
@ HVEC2
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
constexpr int order
@ F
virtual const Problem * get_problem(const std::string problem_name) const =0
Get the problem object.
virtual MoFEMErrorCode add_finite_element(const std::string &fe_name, enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
add finite element
virtual EntityHandle get_finite_element_meshset(const std::string name) const =0
virtual MoFEMErrorCode build_finite_elements(int verb=DEFAULT_VERBOSITY)=0
Build finite elements.
virtual MoFEMErrorCode modify_finite_element_add_field_col(const std::string &fe_name, const std::string name_row)=0
set field col which finite element use
virtual MoFEMErrorCode add_ents_to_finite_element_by_type(const EntityHandle entities, const EntityType type, const std::string name, const bool recursive=true)=0
add entities to finite element
virtual MoFEMErrorCode modify_finite_element_add_field_row(const std::string &fe_name, const std::string name_row)=0
set field row which finite element use
virtual MoFEMErrorCode modify_finite_element_add_field_data(const std::string &fe_name, const std::string name_field)=0
set finite element field data
virtual MoFEMErrorCode build_fields(int verb=DEFAULT_VERBOSITY)=0
virtual MoFEMErrorCode set_field_order(const EntityHandle meshset, const EntityType type, const std::string &name, const ApproximationOrder order, int verb=DEFAULT_VERBOSITY)=0
Set order approximation of the entities in the field.
virtual MoFEMErrorCode add_ents_to_field_by_type(const Range &ents, const EntityType type, const std::string &name, int verb=DEFAULT_VERBOSITY)=0
Add entities to field meshset.
virtual MoFEMErrorCode loop_finite_elements(const std::string problem_name, const std::string &fe_name, FEMethod &method, boost::shared_ptr< NumeredEntFiniteElement_multiIndex > fe_ptr=nullptr, MoFEMTypes bh=MF_EXIST, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr(), int verb=DEFAULT_VERBOSITY)=0
Make a loop over finite elements.
#define _IT_CUBITMESHSETS_BY_BCDATA_TYPE_FOR_LOOP_(MESHSET_MANAGER, CUBITBCTYPE, IT)
Iterator that loops over a specific Cubit MeshSet in a moFEM field.
MoFEMErrorCode partitionGhostDofs(const std::string name, int verb=VERBOSE)
determine ghost nodes
MoFEMErrorCode buildProblem(const std::string name, const bool square_matrix, int verb=VERBOSE)
build problem data structures
MoFEMErrorCode partitionProblem(const std::string name, int verb=VERBOSE)
partition problem dofs (collective)
MoFEMErrorCode partitionFiniteElements(const std::string name, bool part_from_moab=false, int low_proc=-1, int hi_proc=-1, int verb=VERBOSE)
partition finite elements
virtual MoFEMErrorCode add_problem(const std::string &name, enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
Add problem.
virtual MoFEMErrorCode modify_problem_ref_level_set_bit(const std::string &name_problem, const BitRefLevel &bit)=0
set ref level for problem
virtual MoFEMErrorCode modify_problem_add_finite_element(const std::string name_problem, const std::string &fe_name)=0
add finite element to problem, this add entities assigned to finite element to a particular problem
FTensor::Index< 'i', SPACE_DIM > i
double D
const double v
phase velocity of light in medium (cm/ns)
FTensor::Index< 'j', 3 > j
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
std::bitset< BITREFLEVEL_SIZE > BitRefLevel
Bit structure attached to each entity identifying to what mesh entity is attached.
Definition Types.hpp:40
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
MoFEMErrorCode MatSetValues(Mat M, const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, const double *ptr, InsertMode iora)
Assemble PETSc matrix.
MoFEMErrorCode VecSetValues(Vec V, const EntitiesFieldData::EntData &data, const double *ptr, InsertMode iora)
Assemble PETSc vector.
double h
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
constexpr auto field_name
static constexpr double delta
data for evaluation of het conductivity and heat capacity elements
Range tEts
constatins elements in block set
OpDivTauU_HdivL2(MixTransportElement &ctx, const std::string flux_name_row, string val_name_col, Vec f)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpError(MixTransportElement &ctx, const std::string field_name)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpEvaluateBcOnFluxes(MixTransportElement &ctx, const std::string flux_name)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpFluxDivergenceAtGaussPts(MixTransportElement &ctx, const std::string field_name)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpL2Source(MixTransportElement &ctx, const std::string val_name, Vec f)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpPostProc(moab::Interface &post_proc_mesh, std::vector< EntityHandle > &map_gauss_pts)
OpRhsBcOnValues(MixTransportElement &ctx, const std::string fluxes_name, Vec f)
Constructor.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Integrate boundary condition.
calculate values on adjacent tetrahedra to face
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpSkeleton(MixTransportElement &ctx, const std::string flux_name)
VolumeElementForcesAndSourcesCoreOnSide volSideFe
volume element to get values from adjacent tets to face
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type, EntityType col_type, EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
Assemble matrix.
OpTauDotSigma_HdivHdiv(MixTransportElement &ctx, const std::string flux_name, Mat aij, Vec f)
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Assemble matrix.
MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type, EntityType col_type, EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
Do calculations.
OpVDivSigma_L2Hdiv(MixTransportElement &ctx, const std::string val_name_row, string flux_name_col, Mat aij, Vec f)
Constructor.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpValuesAtGaussPts(MixTransportElement &ctx, const std::string val_name="VALUES")
Calculate gradients of values at integration points.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
OpValuesGradientAtGaussPts(MixTransportElement &ctx, const std::string val_name="VALUES")
MoFEMErrorCode postProc(const string out_file)
Post process results.
MoFEMErrorCode destroyMatrices()
destroy matrices
MoFEMErrorCode evaluateError()
Calculate error on elements.
MoFEMErrorCode solveLinearProblem()
solve problem
MoFEMErrorCode getDirichletBCIndices(IS *is)
get dof indices where essential boundary conditions are applied
MoFEMErrorCode createMatrices()
create matrices
MatrixDouble valuesGradientAtGaussPts
gradients at integration points on element
virtual MoFEMErrorCode getBcOnFluxes(const EntityHandle ent, const double x, const double y, const double z, double &flux)
essential (Neumann) boundary condition (set fluxes)
MoFEMErrorCode calculateResidual()
calculate residual
MoFEMErrorCode addFiniteElements(const std::string &fluxes_name, const std::string &values_name)
add finite elements
VectorDouble valuesAtGaussPts
values at integration points on element
MyTriFE feTri
Instance of surface element.
virtual MoFEMErrorCode getBcOnValues(const EntityHandle ent, const int gg, const double x, const double y, const double z, double &value)
evaluate natural (Dirichlet) boundary conditions
MyVolumeFE feVol
Instance of volume element.
MoFEMErrorCode addFields(const std::string &values, const std::string &fluxes, const int order)
Add fields to database.
virtual MoFEMErrorCode getResistivity(const EntityHandle ent, const double x, const double y, const double z, MatrixDouble3by3 &inv_k)
natural (Dirichlet) boundary conditions (set values)
MixTransportElement(MoFEM::Interface &m_field)
construction of this data structure
std::map< int, BlockData > setOfBlocks
maps block set id with appropriate BlockData
VectorDouble divergenceAtGaussPts
divergence at integration points on element
virtual MoFEMErrorCode getSource(const EntityHandle ent, const double x, const double y, const double z, double &flux)
set source term
MatrixDouble fluxesAtGaussPts
fluxes at integration points on element
MoFEMErrorCode buildProblem(BitRefLevel &ref_level)
Build problem.
Add operators pushing bases from local to physical configuration.
Managing BitRefLevels.
virtual int get_comm_size() const =0
virtual moab::Interface & get_moab()=0
virtual MoFEMErrorCode build_adjacencies(const Range &ents, int verb=DEFAULT_VERBOSITY)=0
build adjacencies
virtual MoFEMErrorCode add_field(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_EXCL, int verb=DEFAULT_VERBOSITY)=0
Add field.
virtual MPI_Comm & get_comm() const =0
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
FTensor::Tensor2< FTensor::PackPtr< double *, Tensor_Dim0 *Tensor_Dim1 >, Tensor_Dim0, Tensor_Dim1 > getFTensor2DiffN(FieldApproximationBase base)
Get derivatives of base functions for Hdiv space.
MatrixDouble & getDiffN(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 VectorDouble & getFieldData() const
Get DOF values on entity.
const MatrixAdaptor getVectorN(const FieldApproximationBase base, const int gg)
get Hdiv of base functions at Gauss pts
auto getFTensor1N(FieldApproximationBase base)
Get base functions for Hdiv/Hcurl spaces.
const VectorDofs & getFieldDofs() const
Get DOF data structures (const version)
const VectorInt & getIndices() const
Get global indices of degrees of freedom on entity.
boost::shared_ptr< const NumeredEntFiniteElement > getNumeredEntFiniteElementPtr() const
Return raw pointer to NumeredEntFiniteElement.
@ OPCOL
operator doWork function is executed on FE columns
boost::ptr_deque< UserDataOperator > & getOpPtrVector()
Use to push back operator for row operator.
Thermal material data structure.
Matrix manager is used to build and partition problems.
Get vector field for H-div approximation.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for double precision scalar field values calculation.
Post post-proc data at points from hash maps.
keeps basic data about problem
DofIdx getNbDofsRow() const
Problem manager is used to build and partition problems.
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
Vector manager is used to create vectors \mofem_vectors.
VolumeElementForcesAndSourcesCore * getVolumeFE() const
return pointer to Generic Volume Finite Element object