KASKADE 7 development version
advect.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2015-2018 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef ADVECT_HH
14#define ADVECT_HH
15
16#include <cassert>
17#include <utility>
18
19#include "fem/fixdune.hh"
20#include "fem/functionspace.hh"
22
23namespace Kaskade
24{
25
27 namespace AdvectDetail
28 {
42 template <class LocalCoordinate>
43 std::pair<int,double> intersectedFace(Dune::GeometryType const& gt, LocalCoordinate const& xi, LocalCoordinate const& dxi)
44 {
45 using Scalar = typename LocalCoordinate::field_type;
46
47 if (gt.isSimplex())
48 {
49 // Check minimal step size until faces are encountered
50 int imin = -1;
51 double minStep = std::numeric_limits<Scalar>::infinity();
52
53 for (int i=0; i<xi.N(); ++i) // first step through coordinate planes
54 if (dxi[i]<0) // only encountered if direction has negative value in that coordinate
55 {
56 Scalar stepi = -xi[i]/dxi[i]; // compute the step size until intersection
57 if (stepi < minStep) // select the one that is encountered first
58 {
59 imin = i;
60 minStep = stepi;
61 }
62 }
63
64 LocalCoordinate one(1.0); // test the face normal to [1,1,1]
65 Scalar dxione = one*dxi; // normal component of direction
66 if (dxione > 0 && (1-one*xi)/dxione < minStep) // if positive, compute intersection step size
67 { // and check whether this is encountered first
68 minStep = (1-one*xi)/dxione;
69 imin = xi.N();
70 }
71
72 // Make sure we don't return nonsense (like negative entity indices) just becaus we couldn't find
73 // an intersection.
74 if (imin < 0)
75 throw DetailedException("Vanishing direction provided for face-ray intersection.",__FILE__,__LINE__);
76
77 // Find the face subentity index in the reference simplex of Dune
78 if (LocalCoordinate::dimension==1)
79 return std::make_pair(imin,minStep);
80 if (LocalCoordinate::dimension==2)
81 {
82 constexpr int sube[] = { 1, 0, 2 };
83 return std::make_pair(sube[imin],minStep);
84 }
85 if (LocalCoordinate::dimension==3)
86 {
87 constexpr int sube[] = { 2, 1, 0, 3 };
88 return std::make_pair(sube[imin],minStep);
89 }
90 // never get here
91 }
92 else if (gt.isCube())
93 {
94 // not yet implemented
95 abort();
96 }
97
98 // Never get here
99 abort();
100 return std::make_pair(-1,-1.0);
101 }
102
103 }
105
120 template <class Function, class Velocity>
122 {
123 public:
124 using GridView = typename Function::Space::GridView;
126 using Position = GlobalPosition<GridView>;
127
128 private:
129 using GlobalPosition = std::pair<Cell,Position>;
130
131 public:
132
140 AdvectedFunctionView(Function const& f_, Velocity const& v_, double tau_, int n_=1): f(f_), v(v_), tau(tau_), n(n_)
141 {
142 assert(n>=1);
143 }
144
145 typename Function::ValueType value(Cell const& cell, Position const& xi) const
146 {
147 // perform n explicit Euler steps in backwards direction for finding the source point y(-tau)
148 // TODO: consider using a higher order integrator. Is this more efficient? Or do
149 // discontinuities (of higher derivatives) of v at faces prevent this to
150 // achieve higher order? Is a restriction of higher order integration to
151 // single cells more appropriate?
152 GlobalPosition y(cell,xi);
153 for (int i=0; i<n; ++i)
154 y = advectPosition(y,-tau/n*v.value(y.first,y.second));
155
156 // evaluate function
157 return f.value(y.first,y.second);
158 }
159
160 private:
161 Function const& f;
162 Velocity const& v; // velocity field
163 double tau; // integration length
164 int n; // number of Euler steps
165
166 // A single Euler step. As the Euler step can leave the current cell, we have to
167 // search for the cell containing the target point. Currently we follow the
168 // Euler step line through the grid as it passes through the cells.
169 // TODO: For large step sizes relative to cell size this is inefficient, as many cells
170 // have to be crossed. Then, going down to coarser levels with larger cells should
171 // speed up the process, finally going up again with a hierarchic search. Where is
172 // the trade-off?
173 GlobalPosition advectPosition(GlobalPosition const& y, Position const& dy) const
174 {
175 auto const& geo = y.first.geometry();
176
177 auto xi = y.second; // current local point
178 auto dxi = transpose(geo.jacobianInverseTransposed(xi))*dy; // step in reference coordinates
179
180 // TODO: xinext = xi+dxi could be obtained by geo.local(geo.global(xi)+dy). But what happens
181 // if this is outside the cell?
182
183 if (checkInside(geo.type(),xi+dxi) <= 1e-8) // if (almost) inside current cell...
184 return GlobalPosition(y.first,xi+dxi); // ... we've found the target point
185
186 // Now comes the hard part. We've to find the cell containing the target point. First we
187 // identify the face and intersection point.
188 auto encounter = AdvectDetail::intersectedFace(geo.type(),xi,dxi);
189 auto xinext = xi+encounter.second*dxi;
190
191 // Then we find the neighboring cell (if any) and proceed with the
192 for (auto const& face: intersections(f.space().gridView(),y.first))
193 if (face.indexInInside()==encounter.first) // found the face
194 {
195 if (face.neighbor()) // if there is a neighboring cell, step over and go ahead
196 return advectPosition(GlobalPosition(face.outside(),face.geometryInOutside().global(face.geometryInInside().local(xinext))),
197 (1-encounter.second)*dy); // (tail recursion should allow compiler optimization)
198 else // no neighboring cell - we blundered into the domain boundary
199 return GlobalPosition(y.first,xinext); // ... return the boundary point
200 }
201 // never get here
202 abort(); return y;
203 }
204 };
205
206 // -------------------------------------------------------------------------------------------
207
213 template <class Function, class Velocity>
214 auto makeAdvectedFunctionView(Function const& f, Velocity const& v, double tau, int n=1)
215 {
217 }
218
219}
220
221#endif
Function is the interface for evaluatable functions .
Definition: concepts.hh:324
ValueType value(Cell const &cell, Dune::FieldVector< typename Cell::Geometry::ctype, Cell::dimension > const &localCoordinate) const
A weak function view that defines an advected function.
Definition: advect.hh:122
GlobalPosition< GridView > Position
Definition: advect.hh:126
typename Function::Space::GridView GridView
Definition: advect.hh:124
Kaskade::Cell< GridView > Cell
Definition: advect.hh:125
AdvectedFunctionView(Function const &f_, Velocity const &v_, double tau_, int n_=1)
Constructor.
Definition: advect.hh:140
Function::ValueType value(Cell const &cell, Position const &xi) const
Definition: advect.hh:145
This file contains various utility functions that augment the basic functionality of Dune.
FEFunctionSpace and FunctionSpaceElement and the like.
auto makeAdvectedFunctionView(Function const &f, Velocity const &v, double tau, int n=1)
Creates a weak function view for advecting FE functions.
Definition: advect.hh:214
typename GridView::template Codim< 0 >::Entity Cell
The type of cells (entities of codimension 0) in the grid view.
Definition: gridBasics.hh:35
LocalCoordinate::field_type checkInside(Dune::GeometryType const &gt, LocalCoordinate const &x)
Checks whether a point is inside or outside the reference element, and how much.
Definition: fixdune.hh:741
T transpose(T x)