264 {
266
268
269 auto rule = [](
int,
int,
int p) ->
int {
return 2 * p; };
272 auto &evaluation_pipeline = pipeline_mng->getOpEvaluationPipeline();
273
274 auto add_base_ops = [&](auto &pipeline) {
275 auto det_ptr = boost::make_shared<VectorDouble>();
276 auto jac_ptr = boost::make_shared<MatrixDouble>();
277 auto inv_jac_ptr = boost::make_shared<MatrixDouble>();
281 };
282
283 auto u_vals_ptr = boost::make_shared<VectorDouble>();
284 auto u_grad_ptr = boost::make_shared<MatrixDouble>();
285
286 add_base_ops(evaluation_pipeline);
287 evaluation_pipeline.push_back(
289 evaluation_pipeline.push_back(
291
292 enum NORMS {
L2 = 0, SEMI_NORM,
H1, LAST_NORM };
293 std::array<int, LAST_NORM> error_indices;
294 for (
int i = 0;
i != LAST_NORM; ++
i)
295 error_indices[
i] =
i;
298
300 error_op->doWorkRhsHook = [&](
DataOperator *op_ptr,
int side, EntityType
type,
304
306
307 if (const size_t nb_dofs = data.getIndices().size()) {
308
309 const int nb_integration_pts = o->getGaussPts().size2();
310 auto t_w = o->getFTensor0IntegrationWeight();
312 auto t_grad = getFTensor1FromMat<2>(*u_grad_ptr);
313 auto t_coords = o->getFTensor1CoordsAtGaussPts();
314
315 std::array<double, LAST_NORM> error;
316 std::fill(error.begin(), error.end(), 0);
317
318 for (int gg = 0; gg != nb_integration_pts; ++gg) {
319
320 const double alpha = t_w * o->getMeasure();
321 const double diff =
322 t_val -
u_exact(t_coords(0), t_coords(1), t_coords(2));
323
324 auto t_exact_grad =
u_grad_exact(t_coords(0), t_coords(1), t_coords(2));
325
326 const double diff_grad =
327 (t_grad(
i) - t_exact_grad(
i)) * (t_grad(
i) - t_exact_grad(
i));
328
329 error[
L2] += alpha * pow(diff, 2);
330 error[SEMI_NORM] += alpha * diff_grad;
331
332 ++t_w;
333 ++t_val;
334 ++t_grad;
335 ++t_coords;
336 }
337
338 error[
H1] = error[
L2] + error[SEMI_NORM];
339
341 ADD_VALUES);
342 }
343
345 };
346
347 auto side_fe_ptr = boost::make_shared<FaceSideEle>(
mField);
348 add_base_ops(side_fe_ptr->getOpPtrVector());
349 side_fe_ptr->getOpPtrVector().push_back(
351 std::array<VectorDouble, 2> side_vals;
352 std::array<double, 2> area_map;
353 std::array<EntityHandle, 2> side_ents = {0, 0};
354
356 side_vals_op->doWorkRhsHook = [&](
DataOperator *op_ptr,
int side,
361
362 const auto nb_in_loop = o->getFEMethod()->nInTheLoop;
363 area_map[nb_in_loop] = o->getMeasure();
364 side_vals[nb_in_loop] = *u_vals_ptr;
365 side_ents[nb_in_loop] = o->getFEEntityHandle();
366 if (!nb_in_loop) {
367 area_map[1] = 0;
368 side_vals[1].clear();
369 side_ents[1] = 0;
370 }
371
373 };
374 side_fe_ptr->getOpPtrVector().push_back(side_vals_op);
375
376 auto do_work_rhs_error = [&](
DataOperator *op_ptr,
int side, EntityType
type,
380
381 CHKERR o->loopSideFaces(
"dFE", *side_fe_ptr);
382 const auto in_the_loop = side_fe_ptr->nInTheLoop;
383 if (in_the_loop) {
384 if (auto side_ptr_fe = o->getSidePtrFE()) {
385 if (side_ptr_fe->numeredEntFiniteElementPtr->getEnt() != side_ents[0]) {
387 }
388 }
389 }
390
391#ifndef NDEBUG
392 const std::array<std::string, 2> ele_type_name = {"BOUNDARY", "SKELETON"};
394 << "do_work_rhs_error in_the_loop " << ele_type_name[in_the_loop];
395#endif
396
397 const double s = o->getMeasure() / (area_map[0] + area_map[1]);
399
400 std::array<double, LAST_NORM> error;
401 std::fill(error.begin(), error.end(), 0);
402
403 const int nb_integration_pts = o->getGaussPts().size2();
404
405 if (!in_the_loop) {
406 side_vals[1].resize(nb_integration_pts, false);
407 auto t_coords = o->getFTensor1CoordsAtGaussPts();
409 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
410 t_val_m =
u_exact(t_coords(0), t_coords(1), t_coords(2));
411 ++t_coords;
412 ++t_val_m;
413 }
414 }
415
418 auto t_w = o->getFTensor0IntegrationWeight();
419
420 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
421
422 const double alpha = o->getMeasure() * t_w;
423 const auto diff = t_val_p - t_val_m;
424 error[SEMI_NORM] += alpha * p * diff * diff;
425
426 ++t_w;
427 ++t_val_p;
428 ++t_val_m;
429 }
430
431
432 error[
H1] = error[SEMI_NORM];
434 ADD_VALUES);
435
437 };
438
440 skeleton_error_op->doWorkRhsHook = do_work_rhs_error;
442 boundary_error_op->doWorkRhsHook = do_work_rhs_error;
443
444 evaluation_pipeline.push_back(error_op);
445
446 auto add_side_error_op = [&](const std::string &fe_name, auto error_op) {
449 op_loop_side->getSideFEPtr()->getRuleHook = rule_2;
450 op_loop_side->getOpPtrVector().push_back(error_op);
451 evaluation_pipeline.push_back(op_loop_side);
452 };
453
456
457 CHKERR pipeline_mng->loopFiniteElementsEvaluation();
458
459 CHKERR VecAssemblyBegin(l2_vec);
460 CHKERR VecAssemblyEnd(l2_vec);
461
463 const double *array;
464 CHKERR VecGetArrayRead(l2_vec, &array);
465 MOFEM_LOG_C(
"SELF", Sev::inform,
"Error Norm L2 %6.4e",
466 std::sqrt(array[
L2]));
467 MOFEM_LOG_C(
"SELF", Sev::inform,
"Error Norm Energetic %6.4e",
468 std::sqrt(array[SEMI_NORM]));
469 MOFEM_LOG_C(
"SELF", Sev::inform,
"Error Norm H1 %6.4e",
470 std::sqrt(array[
H1]));
471
473 constexpr double eps = 1e-12;
474 if (std::sqrt(array[
H1]) >
eps)
476 }
477
478 CHKERR VecRestoreArrayRead(l2_vec, &array);
483 }
484
486}
#define MOFEM_LOG_C(channel, severity, format,...)
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ L2
field with C-1 continuity
@ MOFEM_ATOM_TEST_INVALID
#define CHKERR
Inline error check.
PetscErrorCode DMMoFEMGetProblemPtr(DM dm, const MoFEM::Problem **problem_ptr)
Get pointer to problem data structure.
#define MOFEM_LOG(channel, severity)
Log.
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
static auto getFTensor0FromVec(V &data)
Get tensor rank 0 (scalar) form data vector.
MoFEMErrorCode VecSetValues(Vec V, const EntitiesFieldData::EntData &data, const double *ptr, InsertMode iora)
Assemble PETSc vector.
FTensor::Index< 'i', SPACE_DIM > i
DomainEle::UserDataOperator DomainEleOp
BoundaryEle::UserDataOperator BoundaryEleOp
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
base operator to do operations at Gauss Pt. level
Data on single entity (This is passed as argument to DataOperator::doWork)
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for double precision scalar field values calculation.
Element used to execute operators on side of the element.
MoFEMErrorCode setEvaluationIntegrationRule(RuleHookFun rule)
Set integration rule for domain evaluation finite element.
keeps basic data about problem
DofIdx getNbDofsRow() const
const std::string getBoundaryFEName() const
Get the Boundary FE Name.
const std::string getSkeletonFEName() const
Get the Skeleton FE Name.
MoFEMErrorCode getDM(DM *dm)
Get DM.