@@ -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