Skip to content

Draft: Add FieldTensor and DynamicTensor containers based on mdarray and a TensorSpan based of mdspan

Simon Praetorius requested to merge feature/tensor-datastructures into master


This MR brings the dune interface to mdarray and mdspan, by providing a CRTP base class DenseTensor (similar to DenseMatrix and DenseVector) and derived classes DynamicTensor and FieldTensor. Additionally, the MR provides a TensorSpan, i.e. an mdspan-like class with DenseTensor interface.


The Std::mdarray and Std::mdspan classes are based on the corresponding std c++ library proposals and implementations. Those are pure container-adapters and container-views. They can be used like they are, but do not provide the usual Dune interfaces as found in DynamicMatrix and FieldMatrix, for example. This MR provides these datastructures in the regular Dune:: namespace, to be used by Dune algorithms.

Limitations and Design Decisions

The DynamicTensor is not (yet) a replacement for DynamicMatrix and DynamicVector, but goes in this direction. The FieldTensor is (unlike the FieldXYZ classes) not meant to be a container for field types only, but a container for "arbitrary" types (that still have to fulfill some requirements).

Currently the interface provided by DenseTensor is very minimal. It essentially just provides the nested operator[i][j][...] operator, for rank-2 tensors the rows() and cols() Member functions, and the exists(i0,i1...) method. Especially, there are no arithmetic operators yet implemented.

A rank-0 tensor behaves like a scalar, i.e., it can be compared against a scalar, and it can be converted implicitly into a scalar. The other dune-ish scalar-specialization is not implemented (i.e. tensors with all extents 1 are not considered a scalar).


The DynamicTensor is a multi-dimensional container with dynamic extents:

template <class Value, std::size_t rank>
class DynamicTensor;

The extents are given in the constructor, plus an optional default value for the entries:

DynamicTensor<double,2> matrix1(10,10);
DynamicTensor<double,2> matrix2(10,10, 42.0);

using E = std::dextents<int,2>;
DynamicTensor<double,2> matrix3(E{2,2}, {{1.0, 2.0}, {3.0,4.0}});


The FieldTensor is a multi-dimensional container with static extents:

template <class Value, int... extents>
class FieldTensor;

The extents are given as template parameters, thus don't need to be specified in the constructor. An optional default value for the entries is possible:

FieldTensor<double,10,10> matrix1;
FieldTensor<double,10,10> matrix2(42.0);
FieldTensor<double,2,2> matrix3{{1.0, 1.0}, {3.0, 4.0}}; // constructor with nested initializer list

matrix3[std::array{0,1}] = 42.0; // bracket operator access with array of indices
matrix3(1,0) = 7.0;   // round bracket operator

assert(matrix3.cols() == 2);  // provide special functions for matrices
assert(matrix3[0].size() == 2); // the operator[] return sub-mdspans

Both containers provide also constructors that take the Std::extents<...> object as first argument and additionally a constructor with nested initializer lists.

Edited by Simon Praetorius

Merge request reports