113{
114
116
117
119
120
122
123
125
126
127
128 for (const auto & elem : range)
129 {
130
132
133
134
135 Patch patch(
mesh.processor_id());
136
137
138
139
141 continue;
142
143
144
145
148
149
150
151
152
153 std::vector<Real> new_error_per_cell(1, 0.);
155 new_error_per_cell.resize(patch.size(), 0.);
156
157
158
159 for (
unsigned int var=0; var<
n_vars; var++)
160 {
162#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
163#ifdef DEBUG
164 bool is_valid_norm_type =
171 norm_type ==
L_INF ||
175#endif
176#else
178 norm_type ==
L_INF ||
184#endif
185
186#ifdef DEBUG
187 if (var > 0)
188 {
189
190 bool is_valid_norm_combo =
203 ((norm_type ==
L_INF ||
210 }
211#endif
212
213
215
216
217 const FEType & fe_type = dof_map.variable_type (var);
218
219 const Order element_order = fe_type.order + elem->p_level();
220
221
223
224
225 std::unique_ptr<QBase> qrule =
227
228
229 fe->attach_quadrature_rule (qrule.get());
230
231
232 const std::vector<Real> & JxW = fe->get_JxW();
233 const std::vector<Point> & q_point = fe->get_xyz();
234
235
236
237
238
239 const std::vector<std::vector<Real>> * phi = nullptr;
240
241
242
243#ifdef NDEBUG
244 if (norm_type ==
L2 ||
246#endif
247 phi = &(fe->get_phi());
248
249 const std::vector<std::vector<RealGradient>> * dphi = nullptr;
255 dphi = &(fe->get_dphi());
256
257#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
258 const std::vector<std::vector<RealTensor>> * d2phi = nullptr;
261 d2phi = &(fe->get_d2phi());
262#endif
263
264
265 std::vector<dof_id_type> dof_indices;
266
267
268
269 unsigned int matsize = element_order + 1;
271 {
272 matsize *= (element_order + 2);
273 matsize /= 2;
274 }
276 {
277 matsize *= (element_order + 3);
278 matsize /= 3;
279 }
280
281 DenseMatrix<Number> Kp(matsize,matsize);
282 DenseVector<Number> F, Fx, Fy, Fz, Fxy, Fxz, Fyz;
283 DenseVector<Number> Pu_h, Pu_x_h, Pu_y_h, Pu_z_h, Pu_xy_h, Pu_xz_h, Pu_yz_h;
284 if (norm_type ==
L2 ||
286 {
287 F.resize(matsize); Pu_h.resize(matsize);
288 }
293 {
294 Fx.resize(matsize); Pu_x_h.resize(matsize);
295#if LIBMESH_DIM > 1
296 Fy.resize(matsize); Pu_y_h.resize(matsize);
297#endif
298#if LIBMESH_DIM > 2
299 Fz.resize(matsize); Pu_z_h.resize(matsize);
300#endif
301 }
303 {
304 Fx.resize(matsize); Pu_x_h.resize(matsize);
305 }
307 {
309 Fy.resize(matsize); Pu_y_h.resize(matsize);
310 }
312 {
314 Fz.resize(matsize); Pu_z_h.resize(matsize);
315 }
316
317#if LIBMESH_DIM > 1
320 {
321 Fxy.resize(matsize); Pu_xy_h.resize(matsize);
322#if LIBMESH_DIM > 2
323 Fxz.resize(matsize); Pu_xz_h.resize(matsize);
324 Fyz.resize(matsize); Pu_yz_h.resize(matsize);
325#endif
326 }
327#endif
328
329
330
331
332
333 for (const auto & e_p : patch)
334 {
335
336 fe->reinit (e_p);
337
338
339
340 dof_map.dof_indices (e_p, dof_indices, var);
342
343 const unsigned int n_dofs =
344 cast_int<unsigned int>(dof_indices.size());
345 const unsigned int n_qp = qrule->n_points();
346
347
348
349 for (unsigned int qp=0; qp<n_qp; qp++)
350 {
351
352 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[qp], matsize));
353
354 const unsigned int psi_size = cast_int<unsigned int>(psi.size());
355
356
357 const unsigned int m = Kp.m(), n = Kp.n();
358 for (unsigned int i=0; i<m; i++)
359 for (unsigned int j=0; j<n; j++)
360 Kp(i,j) += JxW[qp]*psi[i]*psi[j];
361
362 if (norm_type ==
L2 ||
364 {
365
366
368
369 for (unsigned int i=0; i<n_dofs; i++)
371
372
373 for (unsigned int i=0; i != psi_size; i++)
374 F(i) = JxW[qp]*u_h*psi[i];
375
376 }
379 {
380
381
383
384 for (std::size_t i=0; i<n_dofs; i++)
387
388
389
390
391 for (unsigned int i=0; i != psi_size; i++)
392 {
393 Fx(i) += JxW[qp]*grad_u_h(0)*psi[i];
394#if LIBMESH_DIM > 1
395 Fy(i) += JxW[qp]*grad_u_h(1)*psi[i];
396#endif
397#if LIBMESH_DIM > 2
398 Fz(i) += JxW[qp]*grad_u_h(2)*psi[i];
399#endif
400 }
401 }
403 {
404
405
407
408 for (unsigned int i=0; i<n_dofs; i++)
411
412
413
414
415 for (unsigned int i=0; i != psi_size; i++)
416 {
417 Fx(i) += JxW[qp]*grad_u_h(0)*psi[i];
418 }
419 }
420#if LIBMESH_DIM > 1
422 {
423
424
426
427 for (unsigned int i=0; i<n_dofs; i++)
430
431
432
433
434 for (unsigned int i=0; i != psi_size; i++)
435 {
436 Fy(i) += JxW[qp]*grad_u_h(1)*psi[i];
437 }
438 }
439#endif
440#if LIBMESH_DIM > 2
442 {
443
444
446
447 for (unsigned int i=0; i<n_dofs; i++)
450
451
452
453
454 for (unsigned int i=0; i != psi_size; i++)
455 {
456 Fz(i) += JxW[qp]*grad_u_h(2)*psi[i];
457 }
458 }
459#endif
462 {
463#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
464
465
467
468 for (unsigned int i=0; i<n_dofs; i++)
471
472
473
474
475 for (unsigned int i=0; i != psi_size; i++)
476 {
477 Fx(i) += JxW[qp]*hess_u_h(0,0)*psi[i];
478#if LIBMESH_DIM > 1
479 Fy(i) += JxW[qp]*hess_u_h(1,1)*psi[i];
480 Fxy(i) += JxW[qp]*hess_u_h(0,1)*psi[i];
481#endif
482#if LIBMESH_DIM > 2
483 Fz(i) += JxW[qp]*hess_u_h(2,2)*psi[i];
484 Fxz(i) += JxW[qp]*hess_u_h(0,2)*psi[i];
485 Fyz(i) += JxW[qp]*hess_u_h(1,2)*psi[i];
486#endif
487 }
488#else
489 libmesh_error_msg("ERROR: --enable-second-derivatives is required \nfor _sobolev_order == 2!");
490#endif
491 }
492 else
494 }
495 }
496
497
498
499
500
501
502
503 if (norm_type ==
L2 ||
505 {
506 Kp.lu_solve(F, Pu_h);
507 }
512 {
513 Kp.lu_solve (Fx, Pu_x_h);
514#if LIBMESH_DIM > 1
515 Kp.lu_solve (Fy, Pu_y_h);
516#endif
517#if LIBMESH_DIM > 2
518 Kp.lu_solve (Fz, Pu_z_h);
519#endif
520 }
522 {
523 Kp.lu_solve (Fx, Pu_x_h);
524 }
526 {
527 Kp.lu_solve (Fy, Pu_y_h);
528 }
530 {
531 Kp.lu_solve (Fz, Pu_z_h);
532 }
533
534#if LIBMESH_DIM > 1
537 {
538 Kp.lu_solve(Fxy, Pu_xy_h);
539#if LIBMESH_DIM > 2
540 Kp.lu_solve(Fxz, Pu_xz_h);
541 Kp.lu_solve(Fyz, Pu_yz_h);
542#endif
543 }
544#endif
545
546
547
548
549
550 Patch::const_iterator patch_re_it;
551 Patch::const_iterator patch_re_end;
552
553
554 Patch patch_re(
mesh.processor_id());
555
557 {
558
559 patch_re_it = patch.begin();
560 patch_re_end = patch.end();
561 }
562 else
563 {
564
565
566 patch_re.build_around_element (elem, 0,
568
569
570 patch_re_it = patch_re.begin();
571 patch_re_end = patch_re.end();
572 }
573
574
575
576
577
578
579
580
581
582
583 FEMContext femcontext(
system,
nullptr,
584 false);
586
587
588 for (unsigned int e = 0 ; patch_re_it != patch_re_end; ++patch_re_it, ++e)
589 {
590
591
592
593 const Elem * e_p = *patch_re_it;
594
595
597
598
599 femcontext.pre_fe_reinit(
system, e_p);
600
601
602
603
604
605
607 continue;
608
609
610 fe->reinit (e_p);
611
612
613
614 dof_map.dof_indices (e_p, dof_indices, var);
616
617
618 const unsigned int n_dofs =
619 cast_int<unsigned int>(dof_indices.size());
620
621
622 Real element_error = 0;
623
624 const Order qorder = fe_type.order + e_p->p_level();
625
626
627 QGrid samprule (
dim, qorder);
628
631 fe->attach_quadrature_rule (&samprule);
632
633
634 const unsigned int n_sp =
635 cast_int<unsigned int>(JxW.size());
636
637
638 for (unsigned int sp=0; sp<n_sp; sp++)
639 {
640
641
642 std::vector<Number> temperr(6,0.0);
643
644 if (norm_type ==
L2 ||
646 {
647
649
650 for (unsigned int i=0; i<n_dofs; i++)
652
653
654 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
655 for (unsigned int i=0; i<matsize; i++)
656 {
657 temperr[0] += psi[i]*Pu_h(i);
658 }
659
660 temperr[0] -= u_h;
661 }
664 {
665
667
668 for (unsigned int i=0; i<n_dofs; i++)
671
672
673 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
674
675 for (unsigned int i=0; i<matsize; i++)
676 {
677 temperr[0] += psi[i]*Pu_x_h(i);
678#if LIBMESH_DIM > 1
679 temperr[1] += psi[i]*Pu_y_h(i);
680#endif
681#if LIBMESH_DIM > 2
682 temperr[2] += psi[i]*Pu_z_h(i);
683#endif
684 }
685 temperr[0] -= grad_u_h(0);
686#if LIBMESH_DIM > 1
687 temperr[1] -= grad_u_h(1);
688#endif
689#if LIBMESH_DIM > 2
690 temperr[2] -= grad_u_h(2);
691#endif
692 }
694 {
695
697
698 for (unsigned int i=0; i<n_dofs; i++)
701
702
703 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
704 for (unsigned int i=0; i<matsize; i++)
705 {
706 temperr[0] += psi[i]*Pu_x_h(i);
707 }
708
709 temperr[0] -= grad_u_h(0);
710 }
711#if LIBMESH_DIM > 1
713 {
714
716
717 for (unsigned int i=0; i<n_dofs; i++)
720
721
722 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
723 for (unsigned int i=0; i<matsize; i++)
724 {
725 temperr[1] += psi[i]*Pu_y_h(i);
726 }
727
728 temperr[1] -= grad_u_h(1);
729 }
730#endif
731#if LIBMESH_DIM > 2
733 {
734
736
737 for (unsigned int i=0; i<n_dofs; i++)
740
741
742 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
743 for (unsigned int i=0; i<matsize; i++)
744 {
745 temperr[2] += psi[i]*Pu_z_h(i);
746 }
747
748 temperr[2] -= grad_u_h(2);
749 }
750#endif
753 {
754#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
755
757
758 for (unsigned int i=0; i<n_dofs; i++)
761
762
763 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
764 for (unsigned int i=0; i<matsize; i++)
765 {
766 temperr[0] += psi[i]*Pu_x_h(i);
767#if LIBMESH_DIM > 1
768 temperr[1] += psi[i]*Pu_y_h(i);
769 temperr[3] += psi[i]*Pu_xy_h(i);
770#endif
771#if LIBMESH_DIM > 2
772 temperr[2] += psi[i]*Pu_z_h(i);
773 temperr[4] += psi[i]*Pu_xz_h(i);
774 temperr[5] += psi[i]*Pu_yz_h(i);
775#endif
776 }
777
778 temperr[0] -= hess_u_h(0,0);
779#if LIBMESH_DIM > 1
780 temperr[1] -= hess_u_h(1,1);
781 temperr[3] -= hess_u_h(0,1);
782#endif
783#if LIBMESH_DIM > 2
784 temperr[2] -= hess_u_h(2,2);
785 temperr[4] -= hess_u_h(0,2);
786 temperr[5] -= hess_u_h(1,2);
787#endif
788#else
789 libmesh_error_msg("ERROR: --enable-second-derivatives is required \nfor _sobolev_order == 2!");
790#endif
791 }
792
793
795
796
797
798
799
800 if (norm_type ==
L_INF)
801 element_error = std::max(element_error, std::abs(weight*temperr[0]));
803 for (unsigned int i=0; i != LIBMESH_DIM; ++i)
804 element_error = std::max(element_error, std::abs(weight*temperr[i]));
806 for (unsigned int i=0; i != 6; ++i)
807 element_error = std::max(element_error, std::abs(weight*temperr[i]));
808 else if (norm_type ==
L2)
811 for (unsigned int i=0; i != LIBMESH_DIM; ++i)
820 {
821 for (unsigned int i=0; i != LIBMESH_DIM; ++i)
823
824 for (unsigned int i=3; i != 6; ++i)
826 }
827
828 }
829
830 if (norm_type ==
L_INF ||
834 else if (norm_type ==
L2 ||
841 else
843 }
844
845 }
846
847
848
849
850
851
852
853 Patch::const_iterator patch_re_it;
854 Patch::const_iterator patch_re_end;
855
856
857 Patch current_elem_patch(
mesh.processor_id());
858
860 {
861
862 patch_re_it = patch.begin();
863 patch_re_end = patch.end();
864 }
865 else
866 {
867
868
869 current_elem_patch.build_around_element (elem, 0,
871
872
873 patch_re_it = current_elem_patch.begin();
874 patch_re_end = current_elem_patch.end();
875 }
876
877
878 for (unsigned int i = 0 ; patch_re_it != patch_re_end; ++patch_re_it, ++i)
879 {
880
881 const Elem * e_p = *patch_re_it;
882
883
885
886
893 {
897 (std::sqrt(new_error_per_cell[i]));
898 }
899 else
900 {
907 (new_error_per_cell[i]);
908 }
909
910 }
911
912
913 }
914
915}
SystemNorm error_norm
When estimating the error in a single system, the error_norm is used to control the scaling and norm ...
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
unsigned int mesh_dimension() const
unsigned int target_patch_size
The PatchErrorEstimator will build patches of at least this many elements to perform estimates.
static std::vector< Real > specpoly(const unsigned int dim, const Order order, const Point p, const unsigned int matsize)
Patch::PMF patch_growth_strategy
The PatchErrorEstimator will use this pointer to a Patch member function when growing patches.
int _extra_order
Extra order to use for quadrature rule.
FEMNormType type(unsigned int var) const
Real weight(unsigned int var) const
Real weight_sq(unsigned int var) const
Number current_solution(const dof_id_type global_dof_number) const
Real time
For time-dependent problems, this is the time t at the beginning of the current timestep.
unsigned int n_vars() const
const DofMap & get_dof_map() const
const MeshBase & get_mesh() const
void add_scaled(const TypeTensor< T2 > &, const T &)
Add a scaled tensor to this tensor without creating a temporary.
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
std::vector< FEMFunctionBase< Number > * > weight_functions
Vector of fem function base pointers, the user will fill this in with pointers to the appropriate wei...
spin_mutex spin_mtx
A convenient spin mutex object which can be used for obtaining locks.
std::string enum_to_string(const T e)
DIE A HORRIBLE DEATH HERE typedef float ErrorVectorReal
NumberVectorValue Gradient
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real