DUNE PDELab (git)

convectiondiffusionfem.hh
1// -*- tab-width: 2; indent-tabs-mode: nil -*-
2#ifndef DUNE_PDELAB_LOCALOPERATOR_CONVECTIONDIFFUSIONFEM_HH
3#define DUNE_PDELAB_LOCALOPERATOR_CONVECTIONDIFFUSIONFEM_HH
4
5#include<vector>
6#include<type_traits>
7
9
10#include<dune/geometry/referenceelements.hh>
11
12#include<dune/pdelab/common/quadraturerules.hh>
13#include<dune/pdelab/localoperator/pattern.hh>
14#include<dune/pdelab/localoperator/flags.hh>
15#include<dune/pdelab/localoperator/idefault.hh>
16#include<dune/pdelab/localoperator/defaultimp.hh>
17#include<dune/pdelab/finiteelement/localbasiscache.hh>
18
19#include"convectiondiffusionparameter.hh"
20
21namespace Dune {
22 namespace PDELab {
23
38 template<typename T, typename FiniteElementMap>
40 public Dune::PDELab::NumericalJacobianApplyVolume<ConvectionDiffusionFEM<T,FiniteElementMap> >,
41 public Dune::PDELab::NumericalJacobianApplyBoundary<ConvectionDiffusionFEM<T,FiniteElementMap> >,
42 public Dune::PDELab::NumericalJacobianVolume<ConvectionDiffusionFEM<T,FiniteElementMap> >,
43 public Dune::PDELab::NumericalJacobianBoundary<ConvectionDiffusionFEM<T,FiniteElementMap> >,
46 public Dune::PDELab::InstationaryLocalOperatorDefaultMethods<typename T::Traits::RangeFieldType>
47 {
48 public:
49 // pattern assembly flags
50 enum { doPatternVolume = true };
51
52 // residual assembly flags
53 enum { doAlphaVolume = true };
54 enum { doAlphaBoundary = true };
55
56 ConvectionDiffusionFEM (T& param_, int intorderadd_=0)
57 : param(param_), intorderadd(intorderadd_)
58 {
59 }
60
61 // volume integral depending on test and ansatz functions
62 template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
63 void alpha_volume (const EG& eg, const LFSU& lfsu, const X& x, const LFSV& lfsv, R& r) const
64 {
65 // Define types
66 using RF = typename LFSU::Traits::FiniteElementType::
67 Traits::LocalBasisType::Traits::RangeFieldType;
68 using size_type = typename LFSU::Traits::SizeType;
69
70 // dimensions
71 const int dim = EG::Entity::dimension;
72
73 // Reference to cell
74 const auto& cell = eg.entity();
75
76 // Get geometry
77 auto geo = eg.geometry();
78
79 // evaluate diffusion tensor at cell center, assume it is constant over elements
80 auto ref_el = referenceElement(geo);
81 auto localcenter = ref_el.position(0,0);
82 auto tensor = param.A(cell,localcenter);
83
84 // Initialize vectors outside for loop
85 std::vector<Dune::FieldVector<RF,dim> > gradphi(lfsu.size());
87 Dune::FieldVector<RF,dim> Agradu(0.0);
88
89 // Transformation matrix
90 typename EG::Geometry::JacobianInverseTransposed jac;
91
92 // loop over quadrature points
93 auto intorder = intorderadd+2*lfsu.finiteElement().localBasis().order();
94 for (const auto& ip : quadratureRule(geo,intorder))
95 {
96 // update all variables dependent on A if A is not cell-wise constant
97 if (!Impl::permeabilityIsConstantPerCell<T>(param))
98 {
99 tensor = param.A(cell, ip.position());
100 }
101
102 // evaluate basis functions
103 auto& phi = cache.evaluateFunction(ip.position(),lfsu.finiteElement().localBasis());
104
105 // evaluate u
106 RF u=0.0;
107 for (size_type i=0; i<lfsu.size(); i++)
108 u += x(lfsu,i)*phi[i];
109
110 // evaluate gradient of shape functions (we assume Galerkin method lfsu=lfsv)
111 auto& js = cache.evaluateJacobian(ip.position(),lfsu.finiteElement().localBasis());
112
113 // transform gradients of shape functions to real element
114 jac = geo.jacobianInverseTransposed(ip.position());
115 for (size_type i=0; i<lfsu.size(); i++)
116 jac.mv(js[i][0],gradphi[i]);
117
118 // compute gradient of u
119 gradu = 0.0;
120 for (size_type i=0; i<lfsu.size(); i++)
121 gradu.axpy(x(lfsu,i),gradphi[i]);
122
123 // compute A * gradient of u
124 tensor.mv(gradu,Agradu);
125
126 // evaluate velocity field, sink term and source term
127 auto b = param.b(cell,ip.position());
128 auto c = param.c(cell,ip.position());
129 auto f = param.f(cell,ip.position());
130
131 // integrate (A grad u)*grad phi_i - u b*grad phi_i + c*u*phi_i
132 RF factor = ip.weight() * geo.integrationElement(ip.position());
133 for (size_type i=0; i<lfsu.size(); i++)
134 r.accumulate(lfsu,i,( Agradu*gradphi[i] - u*(b*gradphi[i]) + (c*u-f)*phi[i] )*factor);
135 }
136 }
137
138 // jacobian of volume term
139 template<typename EG, typename LFSU, typename X, typename LFSV, typename M>
140 void jacobian_volume (const EG& eg, const LFSU& lfsu, const X& x, const LFSV& lfsv,
141 M& mat) const
142 {
143 // Define types
144 using RF = typename LFSU::Traits::FiniteElementType::
145 Traits::LocalBasisType::Traits::RangeFieldType;
146 using size_type = typename LFSU::Traits::SizeType;
147
148 // dimensions
149 const int dim = EG::Entity::dimension;
150
151 // Reference to cell
152 const auto& cell = eg.entity();
153
154 // Get geometry
155 auto geo = eg.geometry();
156
157 // evaluate diffusion tensor at cell center, assume it is constant over elements
158 auto ref_el = referenceElement(geo);
159 auto localcenter = ref_el.position(0,0);
160 auto tensor = param.A(cell,localcenter);
161
162 // Initialize vectors outside for loop
163 std::vector<Dune::FieldVector<RF,dim> > gradphi(lfsu.size());
164 std::vector<Dune::FieldVector<RF,dim> > Agradphi(lfsu.size());
165
166 // Transformation matrix
167 typename EG::Geometry::JacobianInverseTransposed jac;
168
169 // loop over quadrature points
170 auto intorder = intorderadd+2*lfsu.finiteElement().localBasis().order();
171 for (const auto& ip : quadratureRule(geo,intorder))
172 {
173 // update all variables dependent on A if A is not cell-wise constant
174 if (!Impl::permeabilityIsConstantPerCell<T>(param))
175 {
176 tensor = param.A(cell, ip.position());
177 }
178
179 // evaluate gradient of shape functions (we assume Galerkin method lfsu=lfsv)
180 auto& js = cache.evaluateJacobian(ip.position(),lfsu.finiteElement().localBasis());
181
182 // transform gradient to real element
183 jac = geo.jacobianInverseTransposed(ip.position());
184 for (size_type i=0; i<lfsu.size(); i++)
185 {
186 jac.mv(js[i][0],gradphi[i]);
187 tensor.mv(gradphi[i],Agradphi[i]);
188 }
189
190 // evaluate basis functions
191 auto& phi = cache.evaluateFunction(ip.position(),lfsu.finiteElement().localBasis());
192
193 // evaluate velocity field, sink term and source term
194 auto b = param.b(cell,ip.position());
195 auto c = param.c(cell,ip.position());
196
197 // integrate (A grad phi_j)*grad phi_i - phi_j b*grad phi_i + c*phi_j*phi_i
198 RF factor = ip.weight() * geo.integrationElement(ip.position());
199 for (size_type j=0; j<lfsu.size(); j++)
200 for (size_type i=0; i<lfsu.size(); i++)
201 mat.accumulate(lfsu,i,lfsu,j,( Agradphi[j]*gradphi[i]-phi[j]*(b*gradphi[i])+c*phi[j]*phi[i] )*factor);
202 }
203 }
204
205 // boundary integral
206 template<typename IG, typename LFSU, typename X, typename LFSV, typename R>
207 void alpha_boundary (const IG& ig,
208 const LFSU& lfsu_s, const X& x_s, const LFSV& lfsv_s,
209 R& r_s) const
210 {
211 // Define types
212 using RF = typename LFSV::Traits::FiniteElementType::
213 Traits::LocalBasisType::Traits::RangeFieldType;
214 using size_type = typename LFSV::Traits::SizeType;
215
216 // Reference to the inside cell
217 const auto& cell_inside = ig.inside();
218
219 // Get geometry
220 auto geo = ig.geometry();
221
222 // Get geometry of intersection in local coordinates of cell_inside
223 auto geo_in_inside = ig.geometryInInside();
224
225 // evaluate boundary condition type
226 auto ref_el = referenceElement(geo_in_inside);
227 auto local_face_center = ref_el.position(0,0);
228 auto intersection = ig.intersection();
229 auto bctype = param.bctype(intersection,local_face_center);
230
231 // skip rest if we are on Dirichlet boundary
232 if (bctype==ConvectionDiffusionBoundaryConditions::Dirichlet) return;
233
234 // loop over quadrature points and integrate normal flux
235 auto intorder = intorderadd+2*lfsu_s.finiteElement().localBasis().order();
236 for (const auto& ip : quadratureRule(geo,intorder))
237 {
238 // position of quadrature point in local coordinates of element
239 auto local = geo_in_inside.global(ip.position());
240
241 // evaluate shape functions (assume Galerkin method)
242 auto& phi = cache.evaluateFunction(local,lfsu_s.finiteElement().localBasis());
243
244 if (bctype==ConvectionDiffusionBoundaryConditions::Neumann)
245 {
246 // evaluate flux boundary condition
247 auto j = param.j(intersection,ip.position());
248
249 // integrate j
250 auto factor = ip.weight()*geo.integrationElement(ip.position());
251 for (size_type i=0; i<lfsu_s.size(); i++)
252 r_s.accumulate(lfsu_s,i,j*phi[i]*factor);
253 }
254
255 if (bctype==ConvectionDiffusionBoundaryConditions::Outflow)
256 {
257 // evaluate u
258 RF u=0.0;
259 for (size_type i=0; i<lfsu_s.size(); i++)
260 u += x_s(lfsu_s,i)*phi[i];
261
262 // evaluate velocity field and outer unit normal
263 auto b = param.b(cell_inside,local);
264 auto n = ig.unitOuterNormal(ip.position());
265
266 // evaluate outflow boundary condition
267 auto o = param.o(intersection,ip.position());
268
269 // integrate o
270 auto factor = ip.weight()*geo.integrationElement(ip.position());
271 for (size_type i=0; i<lfsu_s.size(); i++)
272 r_s.accumulate(lfsu_s,i,( (b*n)*u + o)*phi[i]*factor);
273 }
274 }
275 }
276
277 // jacobian contribution from boundary
278 template<typename IG, typename LFSU, typename X, typename LFSV, typename M>
279 void jacobian_boundary (const IG& ig,
280 const LFSU& lfsu_s, const X& x_s, const LFSV& lfsv_s,
281 M& mat_s) const
282 {
283 // Define types
284 using size_type = typename LFSV::Traits::SizeType;
285
286 // Reference to the inside cell
287 const auto& cell_inside = ig.inside();
288
289 // Get geometry
290 auto geo = ig.geometry();
291
292 // Get geometry of intersection in local coordinates of cell_inside
293 auto geo_in_inside = ig.geometryInInside();
294
295 // evaluate boundary condition type
296 auto ref_el = referenceElement(geo_in_inside);
297 auto local_face_center = ref_el.position(0,0);
298 auto intersection = ig.intersection();
299 auto bctype = param.bctype(intersection,local_face_center);
300
301 // skip rest if we are on Dirichlet or Neumann boundary
302 if (bctype==ConvectionDiffusionBoundaryConditions::Dirichlet) return;
303 if (bctype==ConvectionDiffusionBoundaryConditions::Neumann) return;
304
305 // loop over quadrature points and integrate normal flux
306 auto intorder = intorderadd+2*lfsu_s.finiteElement().localBasis().order();
307 for (const auto& ip : quadratureRule(geo,intorder))
308 {
309 // position of quadrature point in local coordinates of element
310 auto local = geo_in_inside.global(ip.position());
311
312 // evaluate shape functions (assume Galerkin method)
313 auto& phi = cache.evaluateFunction(local,lfsu_s.finiteElement().localBasis());
314
315 // evaluate velocity field and outer unit normal
316 auto b = param.b(cell_inside,local);
317 auto n = ig.unitOuterNormal(ip.position());
318
319 // integrate
320 auto factor = ip.weight()*geo.integrationElement(ip.position());
321 for (size_type j=0; j<lfsu_s.size(); j++)
322 for (size_type i=0; i<lfsu_s.size(); i++)
323 mat_s.accumulate(lfsu_s,i,lfsu_s,j,(b*n)*phi[j]*phi[i]*factor);
324 }
325 }
326
327
329 void setTime (double t)
330 {
331 param.setTime(t);
332 }
333
334 private:
335 T& param;
336 int intorderadd;
337 using LocalBasisType = typename FiniteElementMap::Traits::FiniteElementType::Traits::LocalBasisType;
339 };
340
341
342
358 template<typename T>
361 {
362 enum { dim = T::Traits::GridViewType::dimension };
363
364 using Real = typename T::Traits::RangeFieldType;
365 using BCType = typename ConvectionDiffusionBoundaryConditions::Type;
366
367 public:
368 // pattern assembly flags
369 enum { doPatternVolume = false };
370 enum { doPatternSkeleton = false };
371
372 // residual assembly flags
373 enum { doAlphaVolume = true };
374 enum { doAlphaSkeleton = true };
375 enum { doAlphaBoundary = true };
376
379 : param(param_)
380 {}
381
382 // volume integral depending on test and ansatz functions
383 template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
384 void alpha_volume (const EG& eg, const LFSU& lfsu, const X& x, const LFSV& lfsv, R& r) const
385 {
386 // Define types
387 using RF = typename LFSU::Traits::FiniteElementType::
388 Traits::LocalBasisType::Traits::RangeFieldType;
389 using RangeType = typename LFSU::Traits::FiniteElementType::
390 Traits::LocalBasisType::Traits::RangeType;
391 using size_type = typename LFSU::Traits::SizeType;
392
393 // Reference to cell
394 const auto& cell = eg.entity();
395
396 // Get geometry
397 auto geo = eg.geometry();
398
399 // Initialize vectors outside for loop
400 std::vector<RangeType> phi(lfsu.size());
401
402 // loop over quadrature points
403 RF sum(0.0);
404 auto intorder = 2*lfsu.finiteElement().localBasis().order();
405 for (const auto& ip : quadratureRule(geo,intorder))
406 {
407 // evaluate basis functions
408 lfsu.finiteElement().localBasis().evaluateFunction(ip.position(),phi);
409
410 // evaluate u
411 RF u=0.0;
412 for (size_type i=0; i<lfsu.size(); i++)
413 u += x(lfsu,i)*phi[i];
414
415 // evaluate reaction term
416 auto c = param.c(cell,ip.position());
417
418 // evaluate right hand side parameter function
419 auto f = param.f(cell,ip.position());
420
421 // integrate f^2
422 auto factor = ip.weight() * geo.integrationElement(ip.position());
423 sum += (f*f-c*c*u*u)*factor;
424 }
425
426 // accumulate cell indicator
427 auto h_T = diameter(geo);
428 r.accumulate(lfsv,0,h_T*h_T*sum);
429 }
430
431
432 // skeleton integral depending on test and ansatz functions
433 // each face is only visited ONCE!
434 template<typename IG, typename LFSU, typename X, typename LFSV, typename R>
435 void alpha_skeleton (const IG& ig,
436 const LFSU& lfsu_s, const X& x_s, const LFSV& lfsv_s,
437 const LFSU& lfsu_n, const X& x_n, const LFSV& lfsv_n,
438 R& r_s, R& r_n) const
439 {
440 // Define types
441 using RF = typename LFSU::Traits::FiniteElementType::
442 Traits::LocalBasisType::Traits::RangeFieldType;
443 using JacobianType = typename LFSU::Traits::FiniteElementType::
444 Traits::LocalBasisType::Traits::JacobianType;
445 using size_type = typename LFSU::Traits::SizeType;
446
447 // dimensions
448 const int dim = IG::Entity::dimension;
449
450 // References to inside and outside cells
451 const auto& cell_inside = ig.inside();
452 const auto& cell_outside = ig.outside();
453
454 // Get geometries
455 auto geo = ig.geometry();
456 auto geo_inside = cell_inside.geometry();
457 auto geo_outside = cell_outside.geometry();
458
459 // Get geometry of intersection in local coordinates of cell_inside and cell_outside
460 auto geo_in_inside = ig.geometryInInside();
461 auto geo_in_outside = ig.geometryInOutside();
462
463 // evaluate permeability tensors
464 auto ref_el_inside = referenceElement(geo_inside);
465 auto ref_el_outside = referenceElement(geo_outside);
466 auto local_inside = ref_el_inside.position(0,0);
467 auto local_outside = ref_el_outside.position(0,0);
468 auto A_s = param.A(cell_inside,local_inside);
469 auto A_n = param.A(cell_outside,local_outside);
470
471 // tensor times normal
472 auto n_F = ig.centerUnitOuterNormal();
474 A_s.mv(n_F,An_F_s);
476 A_n.mv(n_F,An_F_n);
477
478 // Initialize vectors outside for loop
479 std::vector<JacobianType> gradphi_s(lfsu_s.size());
480 std::vector<JacobianType> gradphi_n(lfsu_n.size());
481 std::vector<Dune::FieldVector<RF,dim> > tgradphi_s(lfsu_s.size());
482 std::vector<Dune::FieldVector<RF,dim> > tgradphi_n(lfsu_n.size());
483 Dune::FieldVector<RF,dim> gradu_s(0.0);
484 Dune::FieldVector<RF,dim> gradu_n(0.0);
485
486 // Transformation matrix
487 typename IG::Entity::Geometry::JacobianInverseTransposed jac;
488
489 // loop over quadrature points and integrate normal flux
490 RF sum(0.0);
491 auto intorder = 2*lfsu_s.finiteElement().localBasis().order();
492 for (const auto& ip : quadratureRule(geo,intorder))
493 {
494 // update all variables dependent on A if A is not cell-wise constant
495 if (!Impl::permeabilityIsConstantPerCell<T>(param))
496 {
497 // local normal
498 auto n_F_local = ig.unitOuterNormal(ip.position());
499
500 A_s = param.A(cell_inside,geo_in_inside.global(ip.position()));
501 A_n = param.A(cell_outside,geo_in_outside.global(ip.position()));
502 A_s.mv(n_F_local,An_F_s);
503 A_n.mv(n_F_local,An_F_n);
504 }
505
506 // position of quadrature point in local coordinates of elements
507 auto iplocal_s = geo_in_inside.global(ip.position());
508 auto iplocal_n = geo_in_outside.global(ip.position());
509
510 // evaluate gradient of basis functions
511 lfsu_s.finiteElement().localBasis().evaluateJacobian(iplocal_s,gradphi_s);
512 lfsu_n.finiteElement().localBasis().evaluateJacobian(iplocal_n,gradphi_n);
513
514 // transform gradients of shape functions to real element
515 jac = geo_inside.jacobianInverseTransposed(iplocal_s);
516 for (size_type i=0; i<lfsu_s.size(); i++) jac.mv(gradphi_s[i][0],tgradphi_s[i]);
517 jac = geo_outside.jacobianInverseTransposed(iplocal_n);
518 for (size_type i=0; i<lfsu_n.size(); i++) jac.mv(gradphi_n[i][0],tgradphi_n[i]);
519
520 // compute gradient of u
521 gradu_s = 0.0;
522 for (size_type i=0; i<lfsu_s.size(); i++)
523 gradu_s.axpy(x_s(lfsu_s,i),tgradphi_s[i]);
524 gradu_n = 0.0;
525 for (size_type i=0; i<lfsu_n.size(); i++)
526 gradu_n.axpy(x_n(lfsu_n,i),tgradphi_n[i]);
527
528 // integrate
529 auto factor = ip.weight() * geo.integrationElement(ip.position());
530 auto jump = (An_F_s*gradu_s)-(An_F_n*gradu_n);
531 sum += 0.25*jump*jump*factor;
532 }
533
534 // accumulate indicator
535 // DF h_T = diameter(ig.geometry());
536 auto h_T = std::max(diameter(geo_inside),diameter(geo_outside));
537 r_s.accumulate(lfsv_s,0,h_T*sum);
538 r_n.accumulate(lfsv_n,0,h_T*sum);
539 }
540
541
542 // boundary integral depending on test and ansatz functions
543 // We put the Dirchlet evaluation also in the alpha term to save some geometry evaluations
544 template<typename IG, typename LFSU, typename X, typename LFSV, typename R>
545 void alpha_boundary (const IG& ig,
546 const LFSU& lfsu_s, const X& x_s, const LFSV& lfsv_s,
547 R& r_s) const
548 {
549 // Define types
550 using RF = typename LFSU::Traits::FiniteElementType::
551 Traits::LocalBasisType::Traits::RangeFieldType;
552 using JacobianType = typename LFSU::Traits::FiniteElementType::
553 Traits::LocalBasisType::Traits::JacobianType;
554 using size_type = typename LFSU::Traits::SizeType;
555
556 // dimensions
557 const int dim = IG::Entity::dimension;
558
559 // References to the inside cell
560 const auto& cell_inside = ig.inside();
561
562 // Get geometries
563 auto geo = ig.geometry();
564 auto geo_inside = cell_inside.geometry();
565
566 // evaluate permeability tensors
567 auto ref_el_inside = referenceElement(geo_inside);
568 auto local_inside = ref_el_inside.position(0,0);
569 auto A_s = param.A(cell_inside,local_inside);
570
571 // tensor times normal
572 auto n_F = ig.centerUnitOuterNormal();
574 A_s.mv(n_F,An_F_s);
575
576 // get geometry of intersection in local coordinates of cell_inside
577 auto geo_in_inside = ig.geometryInInside();
578
579 // evaluate boundary condition
580 auto ref_el_in_inside = referenceElement(geo_in_inside);
581 auto face_local = ref_el_in_inside.position(0,0);
582 auto bctype = param.bctype(ig.intersection(),face_local);
583 if (bctype != ConvectionDiffusionBoundaryConditions::Neumann)
584 return;
585
586 // Initialize vectors outside for loop
587 std::vector<JacobianType> gradphi_s(lfsu_s.size());
588 std::vector<Dune::FieldVector<RF,dim> > tgradphi_s(lfsu_s.size());
589 Dune::FieldVector<RF,dim> gradu_s(0.0);
590
591 // Transformation matrix
592 typename IG::Entity::Geometry::JacobianInverseTransposed jac;
593
594 // loop over quadrature points and integrate normal flux
595 RF sum(0.0);
596 auto intorder = 2*lfsu_s.finiteElement().localBasis().order();
597 for (const auto& ip : quadratureRule(geo,intorder))
598 {
599 // update all variables dependent on A if A is not cell-wise constant
600 if (!Impl::permeabilityIsConstantPerCell<T>(param))
601 {
602 // local normal
603 auto n_F_local = ig.unitOuterNormal(ip.position());
604
605 A_s = param.A(cell_inside,geo_in_inside.global(ip.position()));
606 A_s.mv(n_F_local,An_F_s);
607 }
608
609 // position of quadrature point in local coordinates of elements
610 auto iplocal_s = geo_in_inside.global(ip.position());
611
612 // evaluate gradient of basis functions
613 lfsu_s.finiteElement().localBasis().evaluateJacobian(iplocal_s,gradphi_s);
614
615 // transform gradients of shape functions to real element
616 jac = geo_inside.jacobianInverseTransposed(iplocal_s);
617 for (size_type i=0; i<lfsu_s.size(); i++) jac.mv(gradphi_s[i][0],tgradphi_s[i]);
618
619 // compute gradient of u
620 gradu_s = 0.0;
621 for (size_type i=0; i<lfsu_s.size(); i++)
622 gradu_s.axpy(x_s(lfsu_s,i),tgradphi_s[i]);
623
624 // evaluate flux boundary condition
625 auto j = param.j(ig.intersection(),ip.position());
626
627 // integrate
628 auto factor = ip.weight() * geo.integrationElement(ip.position());
629 auto jump = j+(An_F_s*gradu_s);
630 sum += jump*jump*factor;
631 }
632
633 // accumulate indicator
634 //DF h_T = diameter(ig.geometry());
635 auto h_T = diameter(geo_inside);
636 r_s.accumulate(lfsv_s,0,h_T*sum);
637 }
638
639 private:
640 T& param; // two phase parameter class
641
642 template<class GEO>
643 typename GEO::ctype diameter (const GEO& geo) const
644 {
645 using DF = typename GEO::ctype;
646 DF hmax = -1.0E00;
647 const int dim = GEO::coorddimension;
648 for (int i=0; i<geo.corners(); i++)
649 {
650 Dune::FieldVector<DF,dim> xi = geo.corner(i);
651 for (int j=i+1; j<geo.corners(); j++)
652 {
653 Dune::FieldVector<DF,dim> xj = geo.corner(j);
654 xj -= xi;
655 hmax = std::max(hmax,xj.two_norm());
656 }
657 }
658 return hmax;
659 }
660
661 };
662
663
679 template<typename T>
683 {
684 enum { dim = T::Traits::GridViewType::dimension };
685
686 using Real = typename T::Traits::RangeFieldType;
687 using BCType = typename ConvectionDiffusionBoundaryConditions::Type;
688
689 public:
690 // pattern assembly flags
691 enum { doPatternVolume = false };
692 enum { doPatternSkeleton = false };
693
694 // residual assembly flags
695 enum { doAlphaVolume = true };
696
698 // supply time step from implicit Euler scheme
699 ConvectionDiffusionTemporalResidualEstimator1 (T& param_, double time_, double dt_)
700 : param(param_), time(time_), dt(dt_), cmax(0)
701 {}
702
703 // volume integral depending on test and ansatz functions
704 template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
705 void alpha_volume (const EG& eg, const LFSU& lfsu, const X& x, const LFSV& lfsv, R& r) const
706 {
707 // Define types
708 using RF = typename LFSU::Traits::FiniteElementType::
709 Traits::LocalBasisType::Traits::RangeFieldType;
710 using RangeType = typename LFSU::Traits::FiniteElementType::
711 Traits::LocalBasisType::Traits::RangeType;
712 using size_type = typename LFSU::Traits::SizeType;
713
714 // Reference to the cell
715 const auto& cell = eg.entity();
716
717 // Get geometry
718 auto geo = eg.geometry();
719
720 // Initialize vectors outside for loop
721 std::vector<RangeType> phi(lfsu.size());
722
723 // loop over quadrature points
724 RF sum(0.0);
725 RF fsum_up(0.0);
726 RF fsum_mid(0.0);
727 RF fsum_down(0.0);
728 auto intorder = 2*lfsu.finiteElement().localBasis().order();
729 for (const auto& ip : quadratureRule(geo,intorder))
730 {
731 // evaluate basis functions
732 lfsu.finiteElement().localBasis().evaluateFunction(ip.position(),phi);
733
734 // evaluate u
735 RF u=0.0;
736 for (size_type i=0; i<lfsu.size(); i++)
737 u += x(lfsu,i)*phi[i];
738
739 // integrate f^2
740 auto factor = ip.weight() * geo.integrationElement(ip.position());
741 sum += u*u*factor;
742
743 // evaluate right hand side parameter function
744 param.setTime(time);
745 auto f_down = param.f(cell,ip.position());
746 param.setTime(time+0.5*dt);
747 auto f_mid = param.f(cell,ip.position());
748 param.setTime(time+dt);
749 auto f_up = param.f(cell,ip.position());
750 auto f_average = (1.0/6.0)*f_down + (2.0/3.0)*f_mid + (1.0/6.0)*f_up;
751
752 // integrate f-f_average
753 fsum_down += (f_down-f_average)*(f_down-f_average)*factor;
754 fsum_mid += (f_mid-f_average)*(f_mid-f_average)*factor;
755 fsum_up += (f_up-f_average)*(f_up-f_average)*factor;
756 }
757
758 // accumulate cell indicator
759 auto h_T = diameter(geo);
760 r.accumulate(lfsv,0,(h_T*h_T/dt)*sum); // h^2*k_n||jump/k_n||^2
761 r.accumulate(lfsv,0,h_T*h_T * dt*((1.0/6.0)*fsum_down+(2.0/3.0)*fsum_mid+(1.0/6.0)*fsum_up) ); // h^2*||f-time_average(f)||^2_0_s_t
762 }
763
764 void clearCmax ()
765 {
766 cmax = 0;
767 }
768
769 double getCmax () const
770 {
771 return cmax;
772 }
773
774 private:
775 T& param; // two phase parameter class
776 double time;
777 double dt;
778 mutable double cmax;
779
780 template<class GEO>
781 typename GEO::ctype diameter (const GEO& geo) const
782 {
783 using DF = typename GEO::ctype;
784 DF hmax = -1.0E00;
785 const int dim = GEO::coorddimension;
786 for (int i=0; i<geo.corners(); i++)
787 {
788 Dune::FieldVector<DF,dim> xi = geo.corner(i);
789 for (int j=i+1; j<geo.corners(); j++)
790 {
791 Dune::FieldVector<DF,dim> xj = geo.corner(j);
792 xj -= xi;
793 hmax = std::max(hmax,xj.two_norm());
794 }
795 }
796 return hmax;
797 }
798
799 };
800
801 // a functor that can be used to evaluate rhs parameter function in interpolate
802 template<typename T, typename EG>
803 class CD_RHS_LocalAdapter
804 {
805 public:
806 CD_RHS_LocalAdapter (const T& t_, const EG& eg_) : t(t_), eg(eg_)
807 {}
808
809 template<typename X, typename Y>
810 inline void evaluate (const X& x, Y& y) const
811 {
812 y[0] = t.f(eg.entity(),x);
813 }
814
815 private:
816 const T& t;
817 const EG& eg;
818 };
819
835 template<typename T>
839 {
840 enum { dim = T::Traits::GridViewType::dimension };
841
842 using Real = typename T::Traits::RangeFieldType;
843 using BCType = typename ConvectionDiffusionBoundaryConditions::Type;
844
845 public:
846 // pattern assembly flags
847 enum { doPatternVolume = false };
848 enum { doPatternSkeleton = false };
849
850 // residual assembly flags
851 enum { doAlphaVolume = true };
852 enum { doAlphaBoundary = true };
853
855 // supply time step from implicit Euler scheme
856 ConvectionDiffusionTemporalResidualEstimator (T& param_, double time_, double dt_)
857 : param(param_), time(time_), dt(dt_)
858 {}
859
860 // volume integral depending on test and ansatz functions
861 template<typename EG, typename LFSU, typename X, typename LFSV, typename R>
862 void alpha_volume (const EG& eg, const LFSU& lfsu, const X& x, const LFSV& lfsv, R& r) const
863 {
864 // Define types
865 using RF = typename LFSU::Traits::FiniteElementType::
866 Traits::LocalBasisType::Traits::RangeFieldType;
867 using RangeType = typename LFSU::Traits::FiniteElementType::
868 Traits::LocalBasisType::Traits::RangeType;
869 using size_type = typename LFSU::Traits::SizeType;
870 using JacobianType = typename LFSU::Traits::FiniteElementType::
871 Traits::LocalBasisType::Traits::JacobianType;
872
873 // dimensions
874 const int dim = EG::Geometry::mydimension;
875
876 // Get geometry
877 auto geo = eg.geometry();
878
879 // interpolate f as finite element function to compute the gradient
880 CD_RHS_LocalAdapter<T,EG> f_adapter(param,eg);
881 std::vector<RF> f_up, f_down, f_mid;
882 param.setTime(time);
883 lfsu.finiteElement().localInterpolation().interpolate(f_adapter,f_down);
884 param.setTime(time+0.5*dt);
885 lfsu.finiteElement().localInterpolation().interpolate(f_adapter,f_mid);
886 param.setTime(time+dt);
887 lfsu.finiteElement().localInterpolation().interpolate(f_adapter,f_up);
888
889 // Initialize vectors outside for loop
890 std::vector<JacobianType> js(lfsu.size());
891 std::vector<Dune::FieldVector<RF,dim> > gradphi(lfsu.size());
892 Dune::FieldVector<RF,dim> gradu(0.0);
893 Dune::FieldVector<RF,dim> gradf_down(0.0);
894 Dune::FieldVector<RF,dim> gradf_mid(0.0);
895 Dune::FieldVector<RF,dim> gradf_up(0.0);
896 Dune::FieldVector<RF,dim> gradf_average(0.0);
897
898 // Transformation matrix
899 typename EG::Geometry::JacobianInverseTransposed jac;
900
901 // loop over quadrature points
902 RF sum(0.0);
903 RF sum_grad(0.0);
904 RF fsum_grad_up(0.0);
905 RF fsum_grad_mid(0.0);
906 RF fsum_grad_down(0.0);
907 auto intorder = 2*lfsu.finiteElement().localBasis().order();
908 for (const auto& ip : quadratureRule(geo,intorder))
909 {
910 // evaluate basis functions
911 std::vector<RangeType> phi(lfsu.size());
912 lfsu.finiteElement().localBasis().evaluateFunction(ip.position(),phi);
913
914 // evaluate u
915 RF u=0.0;
916 for (size_type i=0; i<lfsu.size(); i++)
917 u += x(lfsu,i)*phi[i];
918
919 // integrate jump
920 auto factor = ip.weight() * geo.integrationElement(ip.position());
921 sum += u*u*factor;
922
923 // evaluate gradient of shape functions (we assume Galerkin method lfsu=lfsv)
924 lfsu.finiteElement().localBasis().evaluateJacobian(ip.position(),js);
925
926 // transform gradients of shape functions to real element
927 jac = geo.jacobianInverseTransposed(ip.position());
928 for (size_type i=0; i<lfsu.size(); i++)
929 jac.mv(js[i][0],gradphi[i]);
930
931 // compute gradient of u
932 gradu = 0.0;
933 for (size_type i=0; i<lfsu.size(); i++)
934 gradu.axpy(x(lfsu,i),gradphi[i]);
935
936 // integrate jump of gradient
937 sum_grad += (gradu*gradu)*factor;
938
939 // compute gradients of f
940 gradf_down = 0.0;
941 for (size_type i=0; i<lfsu.size(); i++) gradf_down.axpy(f_down[i],gradphi[i]);
942 gradf_mid = 0.0;
943 for (size_type i=0; i<lfsu.size(); i++) gradf_mid.axpy(f_mid[i],gradphi[i]);
944 gradf_up = 0.0;
945 for (size_type i=0; i<lfsu.size(); i++) gradf_up.axpy(f_up[i],gradphi[i]);
946 gradf_average = 0.0;
947 for (size_type i=0; i<lfsu.size(); i++)
948 gradf_average.axpy((1.0/6.0)*f_down[i]+(2.0/3.0)*f_mid[i]+(1.0/6.0)*f_up[i],gradphi[i]);
949
950 // integrate grad(f-f_average)
951 gradf_down -= gradf_average;
952 fsum_grad_down += (gradf_down*gradf_down)*factor;
953 gradf_mid -= gradf_average;
954 fsum_grad_mid += (gradf_mid*gradf_mid)*factor;
955 gradf_up -= gradf_average;
956 fsum_grad_up += (gradf_up*gradf_up)*factor;
957 }
958
959 // accumulate cell indicator
960 auto h_T = diameter(geo);
961 r.accumulate(lfsv,0,dt * sum_grad); // k_n*||grad(jump)||^2
962 r.accumulate(lfsv,0,dt*dt * dt*((1.0/6.0)*fsum_grad_down+(2.0/3.0)*fsum_grad_mid+(1.0/6.0)*fsum_grad_up)); // k_n^2*||grad(f-time_average(f))||^2_s_t
963 }
964
965 // boundary integral depending on test and ansatz functions
966 // We put the Dirchlet evaluation also in the alpha term to save some geometry evaluations
967 template<typename IG, typename LFSU, typename X, typename LFSV, typename R>
968 void alpha_boundary (const IG& ig,
969 const LFSU& lfsu_s, const X& x_s, const LFSV& lfsv_s,
970 R& r_s) const
971 {
972 // Define types
973 using RF = typename LFSU::Traits::FiniteElementType::
974 Traits::LocalBasisType::Traits::RangeFieldType;
975
976 // Reference to the inside cell
977 const auto& cell_inside = ig.inside();
978
979 // Get geometry
980 auto geo = ig.geometry();
981 auto geo_inside = cell_inside.geometry();
982
983 // Get geometry of intersection in local coordinates of cell_inside
984 auto geo_in_inside = ig.geometryInInside();
985
986 // evaluate boundary condition
987 auto ref_el_in_inside = referenceElement(geo_in_inside);
988 auto face_local = ref_el_in_inside.position(0,0);
989 auto bctype = param.bctype(ig.intersection(),face_local);
990 if (bctype != ConvectionDiffusionBoundaryConditions::Neumann)
991 return;
992
993 // loop over quadrature points and integrate
994 RF sum_up(0.0);
995 RF sum_down(0.0);
996 const int intorder = 2*lfsu_s.finiteElement().localBasis().order();
997 for (const auto& ip : quadratureRule(geo,intorder))
998 {
999 // evaluate flux boundary condition
1000 param.setTime(time);
1001 auto j_down = param.j(ig.intersection(),ip.position());
1002 param.setTime(time+0.5*dt);
1003 auto j_mid = param.j(ig.intersection(),ip.position());
1004 param.setTime(time+dt);
1005 auto j_up = param.j(ig.intersection(),ip.position());
1006
1007 // integrate
1008 auto factor = ip.weight() * geo.integrationElement(ip.position());
1009 sum_down += (j_down-j_mid)*(j_down-j_mid)*factor;
1010 sum_up += (j_up-j_mid)*(j_up-j_mid)*factor;
1011 }
1012
1013 // accumulate indicator
1014 //DF h_T = diameter(ig.geometry());
1015 auto h_T = diameter(geo_inside);
1016 r_s.accumulate(lfsv_s,0,(h_T+dt*dt/h_T)*dt*0.5*(sum_down+sum_up));
1017 }
1018
1019 private:
1020 T& param; // two phase parameter class
1021 double time;
1022 double dt;
1023
1024 template<class GEO>
1025 typename GEO::ctype diameter (const GEO& geo) const
1026 {
1027 using DF = typename GEO::ctype;
1028 DF hmax = -1.0E00;
1029 const int dim = GEO::coorddimension;
1030 for (int i=0; i<geo.corners(); i++)
1031 {
1032 Dune::FieldVector<DF,dim> xi = geo.corner(i);
1033 for (int j=i+1; j<geo.corners(); j++)
1034 {
1035 Dune::FieldVector<DF,dim> xj = geo.corner(j);
1036 xj -= xi;
1037 hmax = std::max(hmax,xj.two_norm());
1038 }
1039 }
1040 return hmax;
1041 }
1042
1043 };
1044
1045 } // end namespace PDELab
1046} // end namespace Dune
1047#endif // DUNE_PDELAB_LOCALOPERATOR_CONVECTIONDIFFUSIONFEM_HH
FieldTraits< value_type >::real_type two_norm() const
two norm sqrt(sum over squared values of entries)
Definition: densevector.hh:641
derived_type & axpy(const field_type &a, const DenseVector< Other > &x)
vector space axpy operation ( *this += a x )
Definition: densevector.hh:575
vector space out of a tensor product of fields.
Definition: fvector.hh:91
Definition: convectiondiffusionfem.hh:361
ConvectionDiffusionFEMResidualEstimator(T &param_)
constructor: pass parameter object
Definition: convectiondiffusionfem.hh:378
Definition: convectiondiffusionfem.hh:47
void setTime(double t)
set time in parameter class
Definition: convectiondiffusionfem.hh:329
Definition: convectiondiffusionfem.hh:683
ConvectionDiffusionTemporalResidualEstimator1(T &param_, double time_, double dt_)
constructor: pass parameter object
Definition: convectiondiffusionfem.hh:699
Definition: convectiondiffusionfem.hh:839
ConvectionDiffusionTemporalResidualEstimator(T &param_, double time_, double dt_)
constructor: pass parameter object
Definition: convectiondiffusionfem.hh:856
sparsity pattern generator
Definition: pattern.hh:14
Default class for additional methods in instationary local operators.
Definition: idefault.hh:90
store values of basis functions and gradients in a cache
Definition: localbasiscache.hh:18
Default flags for all local operators.
Definition: flags.hh:19
Implements linear and nonlinear versions of jacobian_apply_boundary() based on alpha_boundary()
Definition: numericaljacobianapply.hh:287
Implements linear and nonlinear versions of jacobian_apply_volume() based on alpha_volume()
Definition: numericaljacobianapply.hh:34
Implement jacobian_boundary() based on alpha_boundary()
Definition: numericaljacobian.hh:251
Implement jacobian_volume() based on alpha_volume()
Definition: numericaljacobian.hh:32
Definition of the DUNE_NO_DEPRECATED_* macros.
unspecified value type referenceElement(T &&... t)
Returns a reference element for the objects t....
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:484
Dune namespace.
Definition: alignedallocator.hh:13
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 23, 23:29, 2024)