You can edit almost every page by Creating an account. Otherwise, see the FAQ.

Matrix and tensor objects for numerical simulations

From EverybodyWiki Bios & Wiki

Introduction[edit]

Numerical methods involving matrices and tensors provide a framework for reliable models and practical applications in physics and specifically in engineering. From these, mathematical-numerical methods are derived to simulate physical processes and design technical structures on digital computers.

The following presents a concept that integrates tensor calculus, matrix algebra, and programming with object-oriented methods for mathematical objects of higher order.

Traditional matrix calculus is based on a concept with a schema of two-dimensional arrangement of computation quantities, originating from a time before digital computers existed. However, it is now standard in computer science to use multidimensional arrays to dynamically store and process numerical values and text. To optimize these resources, it is necessary to extend matrix calculus to multidimensional matrices and apply suitable syntax and semantics in programming that align with mathematical methods.

The well-established tensor calculus in index notation provides an ideal form for this purpose; because indexed quantities of higher order can also be processed in the same way as matrices. This leads to a unified concept of programming with classes and associated member functions.

Unfortunately, there are few programming languages that implement syntax and semantics for the direct processing of matrix elements and associated matrix arithmetic. However, this can be addressed by using object-oriented methods for modeling matrix/tensor algorithms. Here, users have the opportunity to declare their own matrix and tensor objects and associated methods, allowing for a unified concept for processing different tensor/matrix types. In this article, the programming language C++ is used for this purpose; as it also allows for overloading standard operators for arithmetic and functions of tensor and matrix operations, enabling the implementation of conventional matrix arithmetic also for multidimensional objects, as e.g.

resp. C = A + B

or

resp. f = k * v (?),

in a clear manner and leveraging the properties of tensor calculus.

This approach is presented in [1], with class and member function declarations in source code, and detailed explanations using application examples. The complete documentation is available in the Hardcover and eBook publications. Additional software can be downloaded from the World Wide Web for academic and personal use [2]. This compact presentation is provided to introduce the new concept of the integrated tensor/matrix calculus for hihger order objects and to illustrate its advantageous and consistent use by object-oriented methods. A comprehensive introduction to the programming language C++ can be found in [3].

The concept has been specifically developed under a research project, sponsored by the German Research Foundation (DFG) and was approved for lectures and exercises on numerical and finite element methods at the Technical University Darmstadt, aiming to provide students with a clear understanding of theoretical tensor and practical matrix methods, as well as object-oriented modeling.

Theory on selected matrix and tensor algebra, prototypes of classes and member functions, and computational tests for effectiveness and accuracy are presented in a synthetic manner.

Matrix objects and elementary operators[edit]

The following assumes that rectangular matrices are stored \textbf{\textit{column-wise}}, as is customary in scientific and technical applications and algorithmic programming languages such as FORTRAN.

with dimensions (.

Here, the first index runs over the rows, and the second index runs over the columns of matrix .

Internally, matrices are stored by assigning matrix elements in sequential order to a one-dimensional vector field:

with dimension N_{z} = N_{i} * N_{k},

similar to how it is done internally in von Neumann computer architectures.

The corresponding bijective mappings are defined as follows:

The mapping

is given by ,

and the inverse mapping

is given by and .

The object descriptor for representing the matrix is independent of the internal sequential storage of elements and only controls the external display of the matrix form.

If matrix M is reduced to a single row, it becomes a row vector ; the same applies for a column vector . This demonstrates that it is possible to incorporate \textbf{0-indices} into the notation without changing the storage of vectors or matrices.

This holds true for vector V as well: and for any matrices M:

The MATRIX M constructor defines the mathematical form of a rectangular matrix in the program code by choosing the dimensions. Currently, up to four dimensions are permitted, which are generally sufficient for engineering applications. Additionally, adjacent indices can be combined using the mappings, as utilized in the program code.


The following C++ program example explains how the matrix classes are handled to create corresponding matrix objects (instances). \newline The constructors of the VEKTOR, MATRIX, delta_MATRIX, e_MATRIX classes can be used to create static or dynamic objects with elements of type 'double'. Using a C-style array notation, vector and matrix elements can be preloaded with numerical values. Input/output is facilitated through overloaded standard operators '>>' and '<<'.


Prototyping of new object-oriented classes and methods: Creation of Matrix Objects and Handling of overloaded Operators

cout << endl

    << "1.0 - Matrix Objects and elementary operators" << endl
    << "=============================================" << endl <<endl; 

// Preallocate of C-array with values

// ----------------------------------

double F[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

cout << "C-Vector F(10) ="; for (int j = 0; j < 10; j++) cout << " " << F[j]; // printing

cout << endl << endl;


// Creating a static instance of the class VEKTOR using constructor

// ----------------------------------------------------------------

VEKTOR V(F, 6); // (1x6)-vector V is preloaded with F

cout << "(1x6) Vector V := F = " << V << endl; // overloaded operator '<<'

// Creating a static instance of the class MATRIX using constructor

MATRIX M(3, 3); // (3x3)-matrix, assignment of V to M

// Exception: type casting by M := V for demonstration

M = V; // overloaded operator '='

cout << "(3x3) Matrix M := V = " << M << endl; // printing

// Creating a static instance of class delta_MATRIX using constructor

delta_MATRIX d(2, 2); // (2x2)-delta-matrix

cout << "(2x2) delta-Matrix d = " << d << endl; // printing

// Creating a static instance of the MATRIX class using constructor

MATRIX A(2, 2); // (2x2)-matrix

cout << "(2x2) Matrix A = " << A << endl; // printing


Testing effectiveness and accuracy: Matrix Objects and elementary Operators

C-Vector F(10) = 0 1 2 3 4 5 6 7 8 9

(1x6) Vector V := F = [ (1x6) * (1x1) ]-MATRIX:

Columns 0 to 5

0.000e+00  1.000e+00  2.000e+00  3.000e+00  4.000e+00  5.000e+00  

Pause -> Enter a character:�

(3x3) Matrix M := V = [ (3x3) * (1x1) ]-MATRIX:

Columns 0 to 2

0.000e+00  3.000e+00  0.000e+00 
1.000e+00  4.000e+00  0.000e+00 
2.000e+00  5.000e+00  0.000e+00 

Pause -> Enter a character:� (2x2) delta-Matrix d = [ (2x2) * (1x1) ]-MATRIX:

Columns 0 to 1

1.000e+00  0.000e+00 
0.000e+00  1.000e+00 

Pause -> Enter a character:�

(2x2) Matrix A = [ (2x2) * (1x1) ]-MATRIX:

Columns 0 to 1

0.000e+00  0.000e+00 
0.000e+00  0.000e+00


The initially defined dimensions of a matrix object M can, however, be temporarily modified in the present concept for the meaningful execution of overloaded operators. This is done by calling the member function M.dimension bound to the object, and applies only until the end of the respective operation!

This function is especially important for implementing the general matrix multiplication - as will be shown later.


The following example first demonstrates elementary applications of the overloaded arithmetic member functions '+', '-', '=', as well as the determinant member function with the declared binding to the defined class instances (objects).

Prototyping of new object-oriented classes and methods: Addition and Subtraction

cout << endl

    << "1.1 - Addition und Subtraction" << endl
    << "==============================" << endl << endl;

// Matrix M is temporarily resized by the member function dimension !

// Matrix Addition M(i,k) + A(i,k)

A = M.dimension(2,2) + d; // overloaded operator '+'

cout << "Matrix A = A + d = " << A << endl; // print

cout << "Original (3x3) Matrix preserved: M = " << M << endl; // print

//

// Matrix Subtraction A(i,k) - d(i,k)

// ----------------------------------

A = A - d; // overloaded operator '-'

cout << "Matrix A = A - d = " << A << endl; // print

// Determinant of Matrix A

double S;

S = A.determinant(2);

cout << "Determinant det(A) = " << S << endl << endl;

Testing effectiveness and accuracy: Addition and Subtraction

Pause -> Enter a character:�

Matrix A = A + d = [ (2x2) * (1x1) ]-MATRIX:

Columns 0 to 1

1.000e+00 2.000e+00 1.000e+00 4.000e+00

Pause -> Zeichen eingeben:�

Original (3x3)-Matrix preserved: M = [ (3*3) * (1*1) ]-MATRIX:

Columns 0 to 2

0.000e+00  3.000e+00  0.000e+00 
1.000e+00  4.000e+00  0.000e+00 
2.000e+00  5.000e+00  0.000e+00

Pause -> Enter a character:�

Matrix A = A - d = [ (2x2) * (1x1) ]-MATRIX:

Columns 0 to 1

0.000e+00 2.000e+00 1.000e+00 3.000e+00

Pause -> Enter a character:�

Determinant det(A) = -2

Cartesian basis and matrix vector multiplications[edit]

For the multiplication of two rectangular matrices A and B, there are generally several variants, such as A * B, A{^T} * B, A * B^T, A^T * B^T, which usually require different procedures.

These variants are summarized here in the general matrix multiplication with the four-dimensional result matrix C

where the summation index \textbf{s} is to be summed over.


The corresponding instruction in the C++ program has the simple form, with the matrix dimensions properly agreed upon in the constructor and the overloaded arithmetic operator '*':

For general cases where the dimensions need to be adjusted, the modification of this instruction typically involves using the \textbf{member function dimension} as follows:

= * ,

where its dimensions are preloaded with and the application is optional.


When using this algorithm on vectors and matrices with different dimensions, it is important to observe the following rules:

as already explained, adjacent indices can be temporarily combined using the dimension function - only for the execution of these operations - without changing the original dimensions or the internal storage of the matrix elements. This allows any matrices to be adapted to this schema. The same applies to the summation index,

for individual indices, the 0-index can also be used. This means that at this point, Dimension 1 is set and assigned to the matrix. This measure also does not change the internal storage scheme,

both measures ensure that the summation index s is always placed in the middle position,

- due to the temporary change of dimensions with the dimension function and also due to the sequence of multiple multiplications determined by the compiler, this general multiplication should not be chained and typically needs to be executed with a single statement,

- Vectors of the VEKTOR class v(N_i) are derived from the MATRIX class and are always internally defined as row vectors v(1,N_i). This measure simplifies scalar products, as it presets the summation index to the middle position - optimizing handling. The use of the dimension function is also permissible here.


The basis vectors of a Cartesian reference system (usually referred to as an x-y-z system) are denoted by Latin indices:

with components :, and

are arranged in the following manner in this spatial reference system:

and

The \textbf{scalar product} of the vectors is then

while the \textbf{dyadic product} is obtained from the multiplication:

The Levi-Civita symbol - also known as the e-matrix in the Cartesian system - is defined as follows by the antisymmetric -matrix or -matrix with numerical values ±1:

or

Using the e-matrix, the cross product of vectors and in the Cartesian system can be determined as follows:

\newline

As examples of typical matrix multiplications, the following operations with rectangular matrices are selected:

and

Another example concerns the Grassmann identity, cf. [4]

which leads to the delta matrix of the 4th order.

The following program code illustrates these examples using multidimensional multiplications with corresponding VEKTOR and MATRIX objects.

Prototyping of new object-oriented classes and methods: Cartesian basis and matrix vector multiplications

cout << endl

    << "2.0 - " Cartesian basis and matrix vector multiplications"<< endl
    << "=========================================================" << endl << end; 

// => Vectors v(i) are internally treated as matrices v(0,i) with N(0) = 1,

// in order to build scalar products rather easy !

// -----------------------------------------------------------------

// Creating three Cartesian reference vectors

VEKTOR e0(3), e1(3), e2(3); // (1x3)-Vektoren

e0(0) = 1.0; e1(1) = 1.0;

std::cout << "(1x3) Vektor e0 = " << e0 << endl; // print

std::cout << "(1x3) Vektor e1 = " << e1 << endl; // print

// Creating two physical vectors

VEKTOR v0(3), v1(3); // (1x3)-Vectors

v0(0) = 6.0; v0(1) = 2.0;

std::cout << "(1x3) Vektor v0 = " << v0 << endl; // print

v1(0) = 1.0; v1(1) = 2.0;

std::cout << "(1x3) Vektor v1 = " << v1 << endl; // print

// Calculating the scalar product s = v0(0,s) * v1(0,s)

// ----------------------------------------------------

double s;

s = v0 * v1;

std::cout << "Scalar s = v0 * v1 = " << s << endl << // print

// Calculating the dyadic product M(i,k) = v0(i) * v1(k)

// ------------------------------------------------------

M = v0.dimension(3) * v1.dimension(3);

std::cout << "Dyadic product M = v0 * v1 = " << M << endl; // print

// Calculating the vector product // e2(0,i) = e(ikl) * e0(0,k) * e1(0,l)

// ----------------------------------------------------------------

// Creating a static instance of the class e_MATRIX // using the constructor

e_MATRIX e(3,3,3); // (3x3x3)-e-Matrix

std::cout << "(3x3x3) e-Matrix e = " << e << endl; // print

// Chained multiplication without member function dimension

e2 = (e * e0) * e1;

std::cout << "(1x3) vector e2 = e0 x e1 = " << e2 << endl; // print

// General matrix product C(i,k,l,m) = A(i,s,k) * B(l,s,m)

// -------------------------------------------------------

// Using the member function M.dimension(N{i}, N{k}, N{l}, N{m}),

// => Matrix M(s,k) can be temporarily extended by a 0-Index

// M(s,k) =: M(0,s,k) mit N{0} = 1,

// => Matrix indices M(i,k,l) can be bundled up to M(IK,s,l)

// M(i,k,s,l) =: M(IK,s,l) mit N{IK} = N{i} * N{k},

// => in order to bring the index s in the centered position M(i,s,l) !

// --------------------------------------------------------------------

std::cout << "(2x2) Matrix A = " << A << endl; // print

// Creating the matrices C and B

MATRIX C(2,2), B(2,2); // (2x2) Matrices

              B = d;   B(0,1) = 0.5;

std::cout << "(2x2) Matrix B = " << B << endl; // print

// Matrix multiplication C(i,k) = A(i,s) * B(0,s,k)

// ------------------------------------------------

C = A * B.dimension(1, 2, 2);

std::cout << "(2x2) Matrix C = A * B = " << C << endl; // print

// Matrix multiplication C(i,k) = A(0,s,i) * B(0,s,k)

// --------------------------------------------------

C = A.dimension(1,2,2) * B.dimension(1, 2, 2);

std::cout << "(2x2) Matrix C = A(T) * B = " << C << endl; // print

// Grassmann Identity

// ------------------

// delta-Matrix(i,k,l,m) = e-Matrix(i,k,s) * e-Matrix(l,m,s)

// Creating a static instance of the class MATRIX using the constructor

MATRIX D4(3,3,3,3); // (3x3x3x3) Matrix

D4 = e.dimension(3 * 3, 3) * e.dimension(3 * 3, 3);

std::cout << "(3x3x3x3) delta-Matrix of 4. order D4(i,k,l,m) = " << D4 << endl; // print

// Test

// ----

// Creating a dynamic instance of the class delta_MATRIX using the constructor

//*** delta_MATRIX& d4 = *new delta_MATRIX(3, 3, 3, 3); // (3x3x3x3) delta-Matrix

//*** std::cout<<"Test: (3x3x3x3) delta-Matrix of 4. order d4(i,k,l,m) = " << d4 << endl; // print

// Release the dynamic matrix d4

//*** delete& d4; // delete using destructor '~'

// -------------------------------------------------------------------

Testing effectiveness and accuracy: Cartesian basis and matrix vector multiplications

Pause -> Enter a character:�

(1x3) Vector e0 = [ (1*3) * (1*1) ]-MATRIX:

Columns 0 to 2

1.000e+00  0.000e+00  0.000e+00 

Pause -> Enter a character:�

(1x3) Vector e1 = [ (1*3) * (1*1) ]-MATRIX:

Columns 0 to 2

0.000e+00  1.000e+00  0.000e+00

Pause -> Zeichen eingeben:�

(1x3) Vektor v0 = [ (1*3) * (1*1) ]-MATRIX:

Columns 0 to 2

6.000e+00  2.000e+00  0.000e+00 

Pause -> Zeichen eingeben:�

(1x3) Vektor v1 = [ (1*3) * (1*1) ]-MATRIX:

Columns 0 to 2

1.000e+00  2.000e+00  0.000e+00 

Pause -> Enter a character:�

Skalar S = e0 * e1 = 10

Dyadic product M = e0 * e1 = [ (3*3) * (1*1) ]-MATRIX:

Columns 0 to 2

6.000e+00  1.200e+01  0.000e+00 
2.000e+00  4.000e+00  0.000e+00 
0.000e+00  0.000e+00  0.000e+00 

Pause -> Enter a character:�

(3x3x3) e-Matrix e = [ (3*3) * (3*1) ]-MATRIX:

Columns 0 to 2

0.000e+00  0.000e+00  0.000e+00 
0.000e+00  0.000e+00 -1.000e+00 
0.000e+00  1.000e+00  0.000e+00 
0.000e+00  0.000e+00  1.000e+00 
0.000e+00  0.000e+00  0.000e+00 

-1.000e+00 0.000e+00 0.000e+00

0.000e+00 -1.000e+00  0.000e+00 
1.000e+00  0.000e+00  0.000e+00 
0.000e+00  0.000e+00  0.000e+00  

Pause -> Enter a character:�

(1x3) Vector e2 = e0 x e1 = [ (1*3) * (1*1) ]-MATRIX:

Columns 0 to 2

0.000e+00  0.000e+00  1.000e+01 

Pause -> Enter a character:�

(2x2) Matrix A = [ (2*2) * (1*1) ]-MATRIX:

Columns 0 to 1

0.000e+00  2.000e+00 
1.000e+00  3.000e+00 

Pause -> Enter a character:�

(2x2) Matrix B = [ (2*2) * (1*1) ]-MATRIX:

Columns 0 to 1

1.000e+00  5.000e-01 
0.000e+00  1.000e+00 

Pause -> Enter a character:�

(2x2) Matrix C = A * B = [ (2*2) * (1*1) ]-MATRIX:

Columns 0 to 1

0.000e+00  2.000e+00 
1.000e+00  3.500e+00 

Pause -> Enter a character:�

(2x2) Matrix C = A(T) * B = [ (2*2) * (1*1) ]-MATRIX:

Columns 0 to 1

0.000e+00  1.000e+00 
2.000e+00  4.000e+00 

Pause -> Enter a character:�

(3x3x3x3) delta-Matrix of 4. Order D4(i,k,l,m) = [ (3*3) * (3*3) ]-MATRIX:

Columns 0 to 5

0.000e+00  0.000e+00  0.000e+00  0.000e+00  0.000e+00  0.000e+00 
0.000e+00  1.000e+00  0.000e+00 -1.000e+00  0.000e+00  0.000e+00 
0.000e+00  0.000e+00  1.000e+00  0.000e+00  0.000e+00  0.000e+00 
0.000e+00 -1.000e+00  0.000e+00  1.000e+00  0.000e+00  0.000e+00 
0.000e+00  0.000e+00  0.000e+00  0.000e+00  0.000e+00  0.000e+00 
0.000e+00  0.000e+00  0.000e+00  0.000e+00  0.000e+00  1.000e+00 
0.000e+00  0.000e+00 -1.000e+00  0.000e+00  0.000e+00  0.000e+00 
0.000e+00  0.000e+00  0.000e+00  0.000e+00  0.000e+00 -1.000e+00 
0.000e+00  0.000e+00  0.000e+00  0.000e+00  0.000e+00  0.000e+00 

Columns 6 to 8

0.000e+00  0.000e+00  0.000e+00 
0.000e+00  0.000e+00  0.000e+00 

-1.000e+00 0.000e+00 0.000e+00

0.000e+00  0.000e+00  0.000e+00 
0.000e+00  0.000e+00  0.000e+00 
0.000e+00 -1.000e+00  0.000e+00 
1.000e+00  0.000e+00  0.000e+00 
0.000e+00  1.000e+00  0.000e+00 
0.000e+00  0.000e+00  0.000e+00

Basis vectors and metrics in Euclidian space[edit]

For tensor calculus, two dual, non-normalized orthogonal reference systems are used, each with covariant basis vectors

on one hand, and contravariant basis vectors

on the other hand, embedded in the Cartesian reference system :.

All notations of the orthogonal objects are now marked with Greek letters for distinction from the Cartesian system. \newline

The two orthogonal reference systems are oriented orthogonally to each other via the unit matrix :

The numerical values are taken here in the program code from the physical vectors and .

Next, the covariant metric (measure tensor)

is determined. The volume form g is obtained from the determinant

The contravariant metric is obtained by inverting the covariant metric

From this, the contravariant basis vectors are finally determined as

The following program code explains typical examples of BASIS objects.

Prototyping of new object-oriented classes and methods: Calculation of Basis Vectors and Metrics in Euclidian Space

cout << endl

    << "3.0 - Basis Vectors and Metrics in Euklidian Space" << endl
    << "==================================================" << endl << endl;

// Covariant basis vectors

VEKTOR g0(3), g1(3);

g0 = v0; //.dimension(3);

g1 = v1; //.dimension(3);

// Create a dynamic instance of the class BASIS using constructor

// --------------------------------------------------------------

BASIS& basis = *new BASIS(g0,g1);

// Covariant basis vectors // ------------------------

MATRIX cov_basis(3,2); // (3x2)-Matrix

// cov_basis = covariante_basis(); // upcoming

   cov_basis = basis.kovariante_basis();

std::cout << "Covariant basis vectors: (3x2) Matrix cov_basis = "

    << cov_basis << endl;                                     // print

// Covariant metric

// -----------------

MATRIX cov_metrik(2,2); // (2x2) Matrix

// double g = basis.covariante_metrik(cov_metrik); // upcoming

   double g = basis.kovariante_metrik(cov_metrik);

std::cout << "Covariant metric: (2x2) Matrix cov_metrik = "

    << cov_metrik << endl;  // print

std::cout << "Covariant metric: Determinant g = " << g << endl << endl;

                                                             // print

// Contravariant metric

// ---------------------

MATRIX contra_metrik(2,2); // (2x2) Matrix

// basis.contravariante_metrik(contra_metrik); // upcoming

   basis.kontravariante_metrik(contra_metrik);

std::cout << "Contravariant metric: (2x2) Matrix contra_metrik "

    << contra_metrik << endl;                                // print

// Test -> Identity matrix

// -----------------------

MATRIX& Einh = *new MATRIX(2, 2);

Einh = cov_metrik.dimension(1,2,2) * contra_metrik.dimension(1,2,2);

std::cout << "Test: Identity matrix = cov_metrik * contra_metrik "

    << Einh << endl;                                         // print

// Contravariant basis vectors

// ----------------------------

MATRIX contra_basis(3, 2); // (3x2) Matrix

// contra_basis = basis.contravariante_basis(); // upcoming

   contra_basis = basis.kontravariante_basis();

std::cout << "Contravariant basis vectors: (3x2) Matrix contra_basis = "

    << contra_basis << endl;                                 // print

// Test -> Identity matrix

// ------------------------

Einh = *new MATRIX(2, 2); // dynamic (2x2) Matrix

Einh = cov_basis.dimension(1,3,2) * contra_basis.dimension(1,3,2);

std::cout << "Test: Identity matrix = cov_basis * contra_basis "

    << Einh << endl;                                          // print

// Release dynamic objects

// -----------------------

delete& basis; // delete using destructor '~'

delete& Einh; // delete using destructor '~'

// -------------------------------------------------------------------

Testing effectiveness and accuracy: 4.0 - Basis Vectors and Metrics in Euclidian Space

Pause -> Enter a character:�

Covariant basis vectors: (3x2) Matrix cov_Basis = [ (3*2) * (1*1) ]-MATRIX:

Columns 0 to 1

6.000e+00  1.000e+00 
2.000e+00  2.000e+00 
0.000e+00  0.000e+00 

Pause -> Enter a character:�

Covariant metric: (2x2) Matrix cov_metrik = [ (2*2) * (1*1) ]-MATRIX:

Columns 0 to 1

4.000e+01  1.000e+01 
1.000e+01  5.000e+00 

Pause -> Enter a character:�

Covariant metric: Determinant g = 100

Contravariant metric: (2x2) Matrix contra_metrik [ (2*2) * (1*1) ]-MATRIX:

Columns 0 to 1

5.000e-02 -1.000e-01 

-1.000e-01 4.000e-01

Pause -> Enter a character:�

Test: Identity matrix = cov_metrix * contra_metric [ (2*2) * (1*1) ]-MATRIX:

Columns 0 to 1

1.000e+00  0.000e+00 
2.220e-16  1.000e+00 

Pause -> Enter a character:�

Contravariant basis vectors: (3x2) Matrix contra_basis = [ (3*2) * (1*1) ]-MATRIX:

Columns 0 to 1

2.000e-01 -2.000e-01 

-1.000e-01 6.000e-01

0.000e+00  0.000e+00 

Pause -> Enter a character:�

Test: Identity matrix = cov_basis * contra_basis [ (2*2) * (1*1) ]-MATRIX:

Columns 0 to 1

1.000e+00 -4.441e-16 
5.551e-17  1.000e+00 

Tensor transformations[edit]

The transformation of tensor components between Cartesian reference systems and skew-angled reference systems is performed using the components

resp.

of the covariant and contravariant basis vectors

resp.

Following this rule, each index of a tensor is transformed individually as needed. Thus, tensors of nth order transform according to this rule as

resp.

and

resp.

n times.

The covariant and contravariant Levi-Civita tensors ($\varepsilon$-tensor) in the skew-angled reference system are derived accordingly, but simplified from the e-matrices by multiplication with the volume form

resp. and resp.

The following program code explains typical examples of tensor transformations.

Prototyping of new object-oriented classes and methods: Tensor Transformation

cout << endl

    << "4.0 - Tensor Transformations" << endl
    << "============================" << endl << endl;

VEKTOR v(3); // (1x3)-Vektor

// Vector in cartesian reference system e0-e1-e2 v(0) = 0.0; v(1) = 5.0;

cout << "Cartesian system: Vector v(i) = " << v << endl; // print

// Transform vector v(i) into skew-angled reference system g0-g1

// -------------------------------------------------------------

VEKTOR v_cov(2); // (1x2) vector

// v_cov(0,alpha) = cov_basis(0,i,alpha) * v(0,i) //


v_cov = cov_basis.dimension(1,3,2) * v;

cout << "Skew-angled system: Covariant vector v(alpha) = " << v_cov << endl; // print

// Transform vector v_schief(alpha) from skew-angled to Cartesian system

// --------------------------------------------------------------------

// v(0,i) = contra_basis(i,alpha) * v_cov(0,alpha)

v = contra_basis * v_cov;

cout << "Test: Cartesian system: Vector v(i) = " << v << endl; // print

// Transform 4th-order tensor

// --------------------------

// Elasticity tensor E in Cartesian coordinate system e0-e1

// Allocated C-field with fictious values row by row (!)

// --------------------------------------------------------

double F16[16] = { 1,0,0,0, 0,0.5,0.5,0, 0, 0.5, 0.5, 0, 0,0,0,1 };

// Create a static instance of the MATRIX class using constructor

// ----------------------------------------------------------------

MATRIX E(F16,2, 2, 2, 2); // (2x2x2x2) matrix pre-filled with F16

cout << "(2x2x2x2) Elasticity tensor E := F16 = " << E <<endl; // print

MATRIX E_contra(2, 2, 2, 2); // (2x2x2x2)-Matrix

// Transform tensor E(i,k,l,m) into skew-angled reference system g0-g1

// -------------------------------------------------------------------

// Reduce contravariant basis to (2x2) matrix - eliminate third row

// contra_basis = contra_basis.submatrix_out(0,2,0,2); // upcoming

  contra_basis = contra_basis.untermatrix_heraus(0,2,0,2);    

cout << "Contravariant basis vectors: (2x2) Matrix contra_basis = " << contra_basis.dimension(2,2) << endl; // print

// E_contra(i,k, gamma,delta) = (E(IK,l,m) * contra_basis(1,l,gamma)) * contra_basis(0,m,delta) // with N{IK} = N{i}*N{k}

E_contra = E.dimension(2 * 2, 2, 2) * contra_basis.dimension(1, 2, 2);

E_contra = E_contra.dimension(2 * 2, 2, 2) * contra_basis.dimension(1, 2, 2);

// E_contra(alpha,beta, gamma,delta) = contra_basis(0,i,alpha) * contra_basis(0,k,beta) * E_contra(i,k,GD) // with N{GD} = N{gamma}*N{delta}

E_contra = contra_basis.dimension(1, 2, 2) * E_contra.dimension(2, 2, 2 * 2);

E_contra = contra_basis.dimension(1, 2, 2) * E_contra.dimension(2, 2, 2 * 2);

cout <<"Skew-angled system: Tensor E_contra(alpha,beta,gamma,delta) = " << E_contra << endl; // print

// Generate contravariant (2x2) Levi-Civita tensor using class e_MATRIX

// --------------------------------------------------------------------

e_MATRIX epsilon_Tensor(2,2,sqrt(g));

cout<< "Skew-angled system: Contravariant epsilon-Ttensor = " << epsilon_Tensor << endl; // print

// -------------------------------------------------------------------

Testing effectiveness and accuracy: 5.0 - Tensor Transformations

==============================================[edit]

Pause -> Enter a character:�

Cartesian system: Vector v(i) = [ (1*3) * (1*1) ]-MATRIX:

Columnn 0 to 2

0.000e+00  5.000e+00  0.000e+00 

Pause -> Enter a character:�

Skew-angled system: Covariante vector v(alpha) = [ (1*2) * (1*1) ]-MATRIX:

Columnn 0 to 1

1.000e+01  1.000e+01 

Pause -> Enter a character:�

Test: Cartesian system: Vector v(i) = [ (1*3) * (1*1) ]-MATRIX:

Columnn 0 to 2

-4.441e-16 5.000e+00 0.000e+00

Pause -> Enter a character:�

(2x2x2x2) Elasticity tensor E := F16 = [ (2*2) * (2*2) ]-MATRIX:

Columnn 0 to 3

1.000e+00  0.000e+00  0.000e+00  0.000e+00 
0.000e+00  5.000e-01  5.000e-01  0.000e+00 
0.000e+00  5.000e-01  5.000e-01  0.000e+00 
0.000e+00  0.000e+00  0.000e+00  1.000e+00 

Pause -> Enter a character:�

Contravariant basis vectors: (2x2) Matrix contra_Basis = [ (2*2) * (1*1) ]-MATRIX:

Columnn 0 to 1

2.000e-01 -2.000e-01 

-1.000e-01 6.000e-01

Pause -> Enter a character:�

Skew-angled system: Tensor E_contra(alpha,beta,gamma,delta) = [ (2*2) * (2*2) ]-MATRIX:

Columnn 0 to 3

2.500e-03 -5.000e-03 -5.000e-03  1.000e-02 

-5.000e-03 1.500e-02 1.500e-02 -4.000e-02 -5.000e-03 1.500e-02 1.500e-02 -4.000e-02

1.000e-02 -4.000e-02 -4.000e-02  1.600e-01 

Pause -> Enter a character:�

Skew-angled system: Contravariant epsilon-Tensor = [ (2*2) * (1*1) ]-MATRIX:

Columnn 0 to 1

0.000e+00  1.000e-01 

-1.000e-01 0.000e+00

References[edit]

  1. Meissner, Udo F. (2024). Tensor Calculus with Object-Oriented Matrices for Numerical Methods in Mechanics and Engineering. Springer. doi:10.1007/978-3-658-39881-1. ISBN 978-3-658-39881-1. Search this book on
  2. Meissner, Udo F. (2004). "Object-Oriented Tensor- and Matrix-Classes".
  3. Breymann, Ulrich. (1997). C++ - Eine Einfuehrung (in Deutsch). Carl Hanser, Munich. ISBN 3-446-19233-6. Search this book on
  4. Meissner, Udo F. (2004). "Tensor Calculus".


This article "Matrix and tensor objects for numerical simulations" is from Wikipedia. The list of its authors can be seen in its historical and/or the page Edithistory:Matrix and tensor objects for numerical simulations. Articles copied from Draft Namespace on Wikipedia could be seen on the Draft Namespace of Wikipedia and not main one.