262 {
264
266
267 auto rule = [](
int,
int,
int p) ->
int {
return 2 * p; };
270 auto &evaluation_pipeline = pipeline_mng->getOpEvaluationPipeline();
271
272 auto add_base_ops = [&](auto &pipeline) {
273 auto det_ptr = boost::make_shared<VectorDouble>();
274 auto jac_ptr = boost::make_shared<MatrixDouble>();
275 auto inv_jac_ptr = boost::make_shared<MatrixDouble>();
279 };
280
281 auto u_vals_ptr = boost::make_shared<VectorDouble>();
282 auto u_grad_ptr = boost::make_shared<MatrixDouble>();
283
284 add_base_ops(evaluation_pipeline);
285 evaluation_pipeline.push_back(
287 evaluation_pipeline.push_back(
289
290 enum NORMS {
L2 = 0, SEMI_NORM,
H1, LAST_NORM };
291 std::array<int, LAST_NORM> error_indices;
292 for (
int i = 0;
i != LAST_NORM; ++
i)
293 error_indices[
i] =
i;
296
298 error_op->doWorkRhsHook = [&](
DataOperator *op_ptr,
int side, EntityType
type,
302
304
305 if (const size_t nb_dofs = data.getIndices().size()) {
306
307 const int nb_integration_pts = o->getGaussPts().size2();
308 auto t_w = o->getFTensor0IntegrationWeight();
310 auto t_grad = getFTensor1FromMat<2>(*u_grad_ptr);
311 auto t_coords = o->getFTensor1CoordsAtGaussPts();
312
313 std::array<double, LAST_NORM> error;
314 std::fill(error.begin(), error.end(), 0);
315
316 for (int gg = 0; gg != nb_integration_pts; ++gg) {
317
318 const double alpha = t_w * o->getMeasure();
319 const double diff =
320 t_val -
u_exact(t_coords(0), t_coords(1), t_coords(2));
321
322 auto t_exact_grad =
u_grad_exact(t_coords(0), t_coords(1), t_coords(2));
323
324 const double diff_grad =
325 (t_grad(
i) - t_exact_grad(
i)) * (t_grad(
i) - t_exact_grad(
i));
326
327 error[
L2] += alpha * pow(diff, 2);
328 error[SEMI_NORM] += alpha * diff_grad;
329
330 ++t_w;
331 ++t_val;
332 ++t_grad;
333 ++t_coords;
334 }
335
336 error[
H1] = error[
L2] + error[SEMI_NORM];
337
339 ADD_VALUES);
340 }
341
343 };
344
345 auto side_fe_ptr = boost::make_shared<FaceSideEle>(
mField);
346 add_base_ops(side_fe_ptr->getOpPtrVector());
347 side_fe_ptr->getOpPtrVector().push_back(
349 std::array<VectorDouble, 2> side_vals;
350 std::array<double, 2> area_map;
351 std::array<EntityHandle, 2> side_ents = {0, 0};
352
354 side_vals_op->doWorkRhsHook = [&](
DataOperator *op_ptr,
int side,
359
360 const auto nb_in_loop = o->getFEMethod()->nInTheLoop;
361 area_map[nb_in_loop] = o->getMeasure();
362 side_vals[nb_in_loop] = *u_vals_ptr;
363 side_ents[nb_in_loop] = o->getFEEntityHandle();
364 if (!nb_in_loop) {
365 area_map[1] = 0;
366 side_vals[1].clear();
367 side_ents[1] = 0;
368 }
369
371 };
372 side_fe_ptr->getOpPtrVector().push_back(side_vals_op);
373
374 auto do_work_rhs_error = [&](
DataOperator *op_ptr,
int side, EntityType
type,
378
379 CHKERR o->loopSideFaces(
"dFE", *side_fe_ptr);
380 const auto in_the_loop = side_fe_ptr->nInTheLoop;
381 if (in_the_loop) {
382 if (auto side_ptr_fe = o->getSidePtrFE()) {
383 if (side_ptr_fe->numeredEntFiniteElementPtr->getEnt() != side_ents[0]) {
385 }
386 }
387 }
388
389#ifndef NDEBUG
390 const std::array<std::string, 2> ele_type_name = {"BOUNDARY", "SKELETON"};
392 << "do_work_rhs_error in_the_loop " << ele_type_name[in_the_loop];
393#endif
394
395 const double s = o->getMeasure() / (area_map[0] + area_map[1]);
397
398 std::array<double, LAST_NORM> error;
399 std::fill(error.begin(), error.end(), 0);
400
401 const int nb_integration_pts = o->getGaussPts().size2();
402
403 if (!in_the_loop) {
404 side_vals[1].resize(nb_integration_pts, false);
405 auto t_coords = o->getFTensor1CoordsAtGaussPts();
407 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
408 t_val_m =
u_exact(t_coords(0), t_coords(1), t_coords(2));
409 ++t_coords;
410 ++t_val_m;
411 }
412 }
413
416 auto t_w = o->getFTensor0IntegrationWeight();
417
418 for (size_t gg = 0; gg != nb_integration_pts; ++gg) {
419
420 const double alpha = o->getMeasure() * t_w;
421 const auto diff = t_val_p - t_val_m;
422 error[SEMI_NORM] += alpha * p * diff * diff;
423
424 ++t_w;
425 ++t_val_p;
426 ++t_val_m;
427 }
428
429
430 error[
H1] = error[SEMI_NORM];
432 ADD_VALUES);
433
435 };
436
438 skeleton_error_op->doWorkRhsHook = do_work_rhs_error;
440 boundary_error_op->doWorkRhsHook = do_work_rhs_error;
441
442 evaluation_pipeline.push_back(error_op);
443
444 auto add_side_error_op = [&](const std::string &fe_name, auto error_op) {
447 op_loop_side->getSideFEPtr()->getRuleHook = rule_2;
448 op_loop_side->getOpPtrVector().push_back(error_op);
449 evaluation_pipeline.push_back(op_loop_side);
450 };
451
454
455 CHKERR pipeline_mng->loopFiniteElementsEvaluation();
456
457 CHKERR VecAssemblyBegin(l2_vec);
458 CHKERR VecAssemblyEnd(l2_vec);
459
461 const double *array;
462 CHKERR VecGetArrayRead(l2_vec, &array);
463 MOFEM_LOG_C(
"SELF", Sev::inform,
"Error Norm L2 %6.4e",
464 std::sqrt(array[
L2]));
465 MOFEM_LOG_C(
"SELF", Sev::inform,
"Error Norm Energetic %6.4e",
466 std::sqrt(array[SEMI_NORM]));
467 MOFEM_LOG_C(
"SELF", Sev::inform,
"Error Norm H1 %6.4e",
468 std::sqrt(array[
H1]));
469
471 constexpr double eps = 1e-12;
472 if (std::sqrt(array[
H1]) >
eps)
474 }
475
476 CHKERR VecRestoreArrayRead(l2_vec, &array);
481 }
482
484}
#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.