DUNE PDELab (2.7)

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 
21 namespace 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());
86  Dune::FieldVector<RF,dim> gradu(0.0);
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
derived_type & axpy(const field_type &a, const DenseVector< Other > &x)
vector space axpy operation ( *this += a x )
Definition: densevector.hh:576
FieldTraits< value_type >::real_type two_norm() const
two norm sqrt(sum over squared values of entries)
Definition: densevector.hh:642
vector space out of a tensor product of fields.
Definition: fvector.hh:96
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_DEPRECATED macro for the case that config.h is not available.
unspecified value type referenceElement(T &&... t)
Returns a reference element for the objects t....
auto max(ADLTag< 0 >, const V &v1, const V &v2)
implements binary Simd::max()
Definition: defaults.hh:79
Dune namespace.
Definition: alignedallocator.hh:14
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 16, 22:29, 2024)