Skip to content

Commit e455ad2

Browse files
authored
Merge pull request #6515 from bangerth/compat
Add some compatibility classes.
2 parents 6fe4f2d + ef5fb38 commit e455ad2

File tree

1 file changed

+216
-0
lines changed

1 file changed

+216
-0
lines changed

include/aspect/compat.h

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,220 @@ namespace aspect
213213

214214
#endif
215215

216+
217+
// deal.II version 9.7 introduces a new class VectorFunctionFromTensorFunctionObject
218+
// that we would like to use also for earlier versions
219+
#if !DEAL_II_VERSION_GTE(9,7,0)
220+
221+
namespace aspect
222+
{
223+
using namespace dealii;
224+
225+
/**
226+
* This class is built as a means of translating the <code>Tensor<1,dim,
227+
* RangeNumberType> </code> values produced by function objects that
228+
* for a given point return a tensor,
229+
* and returning them as a multiple component version of the same thing as a
230+
* Vector for use in, for example, the VectorTools::interpolate or the many
231+
* other functions taking Function objects. It allows the user to place the
232+
* desired components into an <tt>n_components</tt> long vector starting at
233+
* the <tt>selected_component</tt> location in that vector and have all other
234+
* components be 0.
235+
*
236+
* For example: Say you created a function object that returns the gravity
237+
* (here, a radially inward pointing vector of magnitude 9.81):
238+
* @code
239+
* const auto gravity
240+
* = [](const Point<dim> &p) -> Tensor<1,dim> { return -9.81 * (p /
241+
* p.norm()); }
242+
* @endcode
243+
* and you want to interpolate this onto your mesh using the
244+
* VectorTools::interpolate function, with a finite element for the
245+
* DoFHandler object has 3 copies of a finite element with <tt>dim</tt>
246+
* components, for a total of 3*dim components. To interpolate onto that
247+
* DoFHandler, you need an object of type Function that has 3*dim vector
248+
* components. Creating such an object from the existing <code>gravity</code>
249+
* object is done using this piece of code:
250+
* @code
251+
* VectorFunctionFromTensorFunctionObject<dim, RangeNumberType>
252+
* gravity_vector_function(gravity, 0, 3*dim);
253+
* @endcode
254+
* where the <code>dim</code> components of the `gravity` function are placed
255+
* into the first <code>dim</code> components of the function object.
256+
*
257+
* @ingroup functions
258+
*/
259+
template <int dim, typename RangeNumberType = double>
260+
class VectorFunctionFromTensorFunctionObject
261+
: public Function<dim, RangeNumberType>
262+
{
263+
public:
264+
/**
265+
* Given a function object that takes a <tt>Point</tt> and returns a
266+
* <tt>Tensor<1,dim, RangeNumberType></tt> value, convert this into an object
267+
* that matches the Function@<dim@> interface.
268+
*
269+
* By default, create a Vector object of the same size as
270+
* <tt>tensor_function</tt> returns, i.e., with <tt>dim</tt> components.
271+
*
272+
* @param tensor_function_object The TensorFunction that will form `dim` components of
273+
* the resulting Vector Function object.
274+
* @param n_components The total number of vector components of the
275+
* resulting TensorFunction object. This clearly has to be at least `dim`.
276+
* @param selected_component The first component that should be filled by
277+
* the first argument. This should be such that the entire tensor_function
278+
* fits inside the <tt>n_component</tt> length return vector.
279+
*/
280+
explicit VectorFunctionFromTensorFunctionObject(
281+
const std::function<Tensor<1, dim, RangeNumberType>(const Point<dim> &)>
282+
&tensor_function_object,
283+
const unsigned int selected_component = 0,
284+
const unsigned int n_components = dim);
285+
286+
/**
287+
* This destructor is defined as virtual so as to coincide with all other
288+
* aspects of class.
289+
*/
290+
virtual ~VectorFunctionFromTensorFunctionObject() override = default;
291+
292+
/**
293+
* Return a single component of a vector-valued function at a given point.
294+
*/
295+
virtual RangeNumberType
296+
value(const Point<dim> &p, const unsigned int component = 0) const override;
297+
298+
/**
299+
* Return all components of a vector-valued function at a given point.
300+
*
301+
* <tt>values</tt> shall have the right size beforehand, i.e. #n_components.
302+
*/
303+
virtual void
304+
vector_value(const Point<dim> &p,
305+
Vector<RangeNumberType> &values) const override;
306+
307+
/**
308+
* Return all components of a vector-valued function at a list of points.
309+
*
310+
* <tt>value_list</tt> shall be the same size as <tt>points</tt> and each
311+
* element of the vector will be passed to vector_value() to evaluate the
312+
* function
313+
*/
314+
virtual void
315+
vector_value_list(
316+
const std::vector<Point<dim>> &points,
317+
std::vector<Vector<RangeNumberType>> &value_list) const override;
318+
319+
private:
320+
/**
321+
* The TensorFunction object which we call when this class's vector_value()
322+
* or vector_value_list() functions are called.
323+
*/
324+
const std::function<Tensor<1, dim, RangeNumberType>(const Point<dim> &)>
325+
tensor_function_object;
326+
327+
/**
328+
* The first vector component whose value is to be filled by the given
329+
* TensorFunction. The values will be placed in components
330+
* selected_component to selected_component+dim-1 for a
331+
* <tt>TensorFunction<1,dim, RangeNumberType></tt> object.
332+
*/
333+
const unsigned int selected_component;
334+
};
335+
336+
337+
template <int dim, typename RangeNumberType>
338+
VectorFunctionFromTensorFunctionObject<dim, RangeNumberType>::
339+
VectorFunctionFromTensorFunctionObject(
340+
const std::function<Tensor<1, dim, RangeNumberType>(const Point<dim> &)>
341+
&tensor_function_object,
342+
const unsigned int selected_component,
343+
const unsigned int n_components)
344+
: Function<dim, RangeNumberType>(n_components)
345+
, tensor_function_object(tensor_function_object)
346+
, selected_component(selected_component)
347+
{
348+
// Verify that the Tensor<1,dim,RangeNumberType> will fit in the given length
349+
// selected_components and not hang over the end of the vector.
350+
AssertIndexRange(selected_component + dim - 1, this->n_components);
351+
}
352+
353+
354+
355+
template <int dim, typename RangeNumberType>
356+
inline RangeNumberType
357+
VectorFunctionFromTensorFunctionObject<dim, RangeNumberType>::value(
358+
const Point<dim> &p,
359+
const unsigned int component) const
360+
{
361+
AssertIndexRange(component, this->n_components);
362+
363+
// if the requested component is out of the range selected, then we can
364+
// return early
365+
if ((component < selected_component) ||
366+
(component >= selected_component + dim))
367+
return 0;
368+
369+
// otherwise retrieve the values from the <tt>tensor_function</tt> to be
370+
// placed at the <tt>selected_component</tt> to
371+
// <tt>selected_component + dim - 1</tt> elements of the <tt>Vector</tt>
372+
// values and pick the correct one
373+
const Tensor<1, dim, RangeNumberType> tensor_value =
374+
tensor_function_object(p);
375+
376+
return tensor_value[component - selected_component];
377+
}
378+
379+
380+
template <int dim, typename RangeNumberType>
381+
inline void
382+
VectorFunctionFromTensorFunctionObject<dim, RangeNumberType>::vector_value(
383+
const Point<dim> &p,
384+
Vector<RangeNumberType> &values) const
385+
{
386+
Assert(values.size() == this->n_components,
387+
ExcDimensionMismatch(values.size(), this->n_components));
388+
389+
// Retrieve the values from the <tt>tensor_function</tt> to be placed at
390+
// the <tt>selected_component</tt> to
391+
// <tt>selected_component + dim - 1</tt> elements of the <tt>Vector</tt>
392+
// values.
393+
const Tensor<1, dim, RangeNumberType> tensor_value =
394+
tensor_function_object(p);
395+
396+
// First we make all elements of values = 0
397+
values = 0;
398+
399+
// Second we adjust the desired components to take on the values in
400+
// <tt>tensor_value</tt>.
401+
for (unsigned int i = 0; i < dim; ++i)
402+
values(i + selected_component) = tensor_value[i];
403+
}
404+
405+
406+
/**
407+
* Member function <tt>vector_value_list </tt> is the interface for giving a
408+
* list of points (<code>vector<Point<dim>></code>) of which to evaluate
409+
* using the <tt>vector_value</tt> member function. Again, this function is
410+
* written so as to not replicate the function definition but passes each
411+
* point on to <tt>vector_value</tt> to be evaluated.
412+
*/
413+
template <int dim, typename RangeNumberType>
414+
void
415+
VectorFunctionFromTensorFunctionObject<dim, RangeNumberType>::vector_value_list(
416+
const std::vector<Point<dim>> &points,
417+
std::vector<Vector<RangeNumberType>> &value_list) const
418+
{
419+
Assert(value_list.size() == points.size(),
420+
ExcDimensionMismatch(value_list.size(), points.size()));
421+
422+
const unsigned int n_points = points.size();
423+
424+
for (unsigned int p = 0; p < n_points; ++p)
425+
VectorFunctionFromTensorFunctionObject<dim, RangeNumberType>::vector_value(
426+
points[p], value_list[p]);
427+
}
428+
}
429+
430+
#endif
431+
216432
#endif

0 commit comments

Comments
 (0)