Wolfram Research

Function Repository Resource:

TensorCoordinateTransform

Source Notebook

Transform components of tensors with arbitrary rank with regard to their transformation behavior under any given mapping

Contributed by: Lars Ulke-Winter

ResourceFunction["TensorCoordinateTransform"][tensor,mat]

transform tensor components according to their transformation behavior matrix mat. All tensor slots are considered to be contravariant and not normalized.

Generally tensor components (with mixed n×m-rank) transform from one system to another (ii') according to:

The mapping from the old system to the new one is described in the matrix for covariant transformation behavior (tensor components with lower indices) and for so-called contravariant tensor components (depicted with superscript indices). Summation must be done for the same but opposing indices about the dimensions of the tensor coordinates. The fundamental relationship of the contrary transformation behavior ensures invariance of the tensor object T in all systems after contracting all opposing indices (e.g. ). Due to this fact, a distinction of covariant and contravariant transformation behavior is not required in transformation relations with J=(J)-T, e.g. at transformations between orthonormal reference systems.
The input tensor can be of any rank and should be a List or an object of StructuredArray.
The resulting format is always a normal List.
Unlike TransformedField, the ResourceFunction["TensorCoordinateTransform"] result is not given with respect to a normalized basis by default. Using the option Normalize True forces a normalized basis.
The matrix mat defines the mapping between two coordinate systems (often their transposed Jacobian).
The following options are supported:
"TransformationBehavior" "AllContravariant" transformation behavior of individual components "AllContravariant" or "AllCovariant" or {"Con","Cov", …}
Normalize False whether the components are represented with respect to a normalized basis

Examples

Basic Examples

Apply a rotation transformation to a tensor:

In[1]:=
ResourceFunction[
 "TensorCoordinateTransform"][{Subscript[v, 1], Subscript[v, 2], Subscript[v, 3]}, ( {
   {Cos[\[Phi]], -Sin[\[Phi]], 0},
   {Sin[\[Phi]], Cos[\[Phi]], 0},
   {0, 0, 1}
  } )]
Out[1]=

Rotate vector components about the three-axes counterclockwise:

In[2]:=
ResourceFunction[
   "TensorCoordinateTransform"][{Subscript[v, 1], Subscript[v, 2], Subscript[v, 3]}, ( {
     {Cos[\[Phi]], -Sin[\[Phi]], 0},
     {Sin[\[Phi]], Cos[\[Phi]], 0},
     {0, 0, 1}
    } )] // Simplify // MatrixForm
Out[2]=

Change the axis:

In[3]:=
ResourceFunction[
  "TensorCoordinateTransform"][{Subscript[v, 1], Subscript[v, 2], Subscript[v, 3]}, ( {
    {0, 1, 0},
    {0, 0, 1},
    {1, 0, 0}
   } )] // MatrixForm
Out[3]=

Rotate the rank-2 tensor about the three-axes counterclockwise:

In[4]:=
ResourceFunction["TensorCoordinateTransform"][( {
     {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
     {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
     {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
    } ), RotationMatrix[\[Theta], {0, 0, 1}]] // Simplify // MatrixForm
Out[4]=

Rotate a rank-4 tensor with three symmetries about the three-axes counterclockwise :

In[5]:=
SeedRandom[314];

t = SymmetrizedArray[
   pos_ :> RandomInteger[10], {3, 3, 3, 3}, {{{2, 1, 3, 4}, 1}, {{1, 2, 4, 3}, 1}, {{3, 4, 1, 2}, 1}}];
tRot = ResourceFunction["TensorCoordinateTransform"][t, RotationMatrix[45 \[Degree], {0, 0, 1}]];
tRot // Simplify // MatrixForm
Out[6]=

Contravariant vector components with respect to covariant bases:

a=vjbj=vi'bi'

Old system is Cartesian (aj=vj):

In[7]:=
a = {2, 8, 7};

Transformation between new ei' and old ej covariant base vectors:

e1'=2 e1+ 3 e2+1e3

e2'=1 e1+ 2 e2+2e3

e3'=1 e1+2e3

Contravariant components vi' regarding the new system:

In[8]:=
vNewCon = ResourceFunction["TensorCoordinateTransform"][vOld = {2, 8, 7}, mappingToNew = ( {
     {2, 3, 1},
     {1, 2, 2},
     {1, 0, 1}
    } )]
Out[8]=

They should be the same vector:

In[9]:=
bNewCov = mappingToNew;
In[10]:=
(\!\(
\*UnderoverscriptBox[\(\[Sum]\), \(i = 1\), \(3\)]\(vNewCon[\([\)\(i\)\(]\)] \
bNewCov[\([\)\(i\)\(]\)]\)\))
Out[10]=
In[11]:=
a == %
Out[11]=

Covariant vector components with respect to contravariant bases: a=vjbj=vi'bj'

In[12]:=
vNewCov = ResourceFunction["TensorCoordinateTransform"][{2, 8, 7}, ( {
    {2, 3, 1},
    {1, 2, 2},
    {1, 0, 1}
   } ), "TransformationBehavior" -> "AllCovariant"]
Out[12]=

Find related contravariant base vectors bi', by transforming the covariant base in contravariant sense (index juggling bi'bi'):

In[13]:=
bNewCon = ResourceFunction["TensorCoordinateTransform"][( {
    {2, 3, 1},
    {1, 2, 2},
    {1, 0, 1}
   } ), ( {
    {2, 3, 1},
    {1, 2, 2},
    {1, 0, 1}
   } ), "TransformationBehavior" -> "AllContravariant"]
Out[13]=
In[14]:=
(\!\(
\*UnderoverscriptBox[\(\[Sum]\), \(i = 1\), \(3\)]\(vNewCov[\([\)\(i\)\(]\)] \
bNewCon[\([\)\(i\)\(]\)]\)\))
Out[14]=
In[15]:=
a == %
Out[15]=

Note: covariant and contravariant base vectors are inverse to each other

In[16]:=
(bNewCon.bNewCov\[Transpose]) // MatrixForm
Out[16]=

Example equation: aibicijklskltjbi=ci'j'k'l'sk'l'tj'bi'ai'bi'invariant

Tensors in Cartesian frame:

In[17]:=
cFourRankOld = RandomInteger[{-5, 5}, {3, 3, 3, 3}];
sTwoRankOld = RandomInteger[{-5, 5}, {3, 3}];
tOneRankOld = RandomInteger[{-5, 5}, {3}];

Cartesian → local torus coordinates (i i' ):

In[18]:=
x[r_, \[Alpha]_, \[Beta]_] := (R + r Cos[\[Beta]]) Cos[\[Alpha]]
y[r_, \[Alpha]_, \[Beta]_] := (R + r Cos[\[Beta]]) Sin[\[Alpha]]
z[r_, \[Alpha]_, \[Beta]_] := r Sin[\[Beta]]

The torus surface at α=β=0⋯2π at R and r constant:

In[19]:=
ParametricPlot3D[({x[r, \[Alpha], \[Beta]], y[r, \[Alpha], \[Beta]], z[r, \[Alpha], \[Beta]]} /. {r -> 1, R -> 3}), {\[Alpha], 0, 2 \[Pi]}, {\[Beta], 0, 2 \[Pi]}]
Out[19]=

Transform tensors’ different ranks regarding the local torus base with respect to transformation behavior (Hint: this is faster than transformation of an entire assembled 7-rank tensor):

In[20]:=
cFourRankNew = ResourceFunction["TensorCoordinateTransform"][cFourRankOld, Transpose@(jacobianTorus = D[{x[r, \[Alpha], \[Beta]], y[r, \[Alpha], \[Beta]], z[r, \[Alpha], \[Beta]]}, {{r, \[Alpha], \[Beta]}}]), "TransformationBehavior" -> "AllContravariant"];
sTwoRankNew = ResourceFunction["TensorCoordinateTransform"][sTwoRankOld, jacobianTorus\[Transpose], "TransformationBehavior" -> "AllCovariant"];
tOneRankNew = ResourceFunction["TensorCoordinateTransform"][tOneRankOld, jacobianTorus\[Transpose], "TransformationBehavior" -> {"Cov"}];

Local covariant base vector bi':

In[21]:=
bNew = Transpose@jacobianTorus;

Assemble the tensor term by contracting the right indices ci'j'k'l'sk'l'tj'biai'bi':

In[22]:=
aNew = TensorContract[
   cFourRankNew\[TensorProduct]sTwoRankNew\[TensorProduct]tOneRankNew,\
 {{2, 7}, {3, 5}, {4, 6}}] // Simplify
Out[22]=
In[23]:=
((\!\(
\*UnderoverscriptBox[\(\[Sum]\), \(i = 1\), \(3\)]\(aNew[\([\)\(i\)\(]\)] bNew[\([\)\(i\)\(]\)]\)\))) \
// Simplify
Out[23]=

The result should be the same in Cartesian system:

In[24]:=
TensorContract[
 cFourRankOld\[TensorProduct]sTwoRankOld\[TensorProduct]tOneRankOld, \
{{2, 7}, {3, 5}, {4, 6}}]
Out[24]=

If the base vectors are not normalized ("Normalize"False), i.e. have local-dependent lengths (and are not orthogonal in general reference systems either), the corresponding tensor components are transformed according to their co- and contravariant transformation behaviors. This leads to different representations of the same tensor object:

Here is an example of all four transforming possibilities of a rank-2 tensor to a local, non-normalized cylindrical system:

In[25]:=
jacobianCylTransposed = Transpose@(CoordinateTransformData["Cylindrical" -> "Cartesian", "MappingJacobian", {r, \[Phi], z}]);

All coordinates transform the contravariant tij (default):

In[26]:=
tConCon = ResourceFunction["TensorCoordinateTransform"][( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ), jacobianCylTransposed] // Simplify[#, r > 0] & // TraditionalForm
Out[26]=

All coordinates transform the covariant tij:

In[27]:=
tCovCov = ResourceFunction["TensorCoordinateTransform"][( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ), jacobianCylTransposed, "TransformationBehavior" -> "AllCovariant"] // Simplify[#, r > 0] & // TraditionalForm
Out[27]=

A tensor object with coordinates of mixed-transformation behavior tij:

In[28]:=
tConCov = ResourceFunction["TensorCoordinateTransform"][( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ), jacobianCylTransposed, "TransformationBehavior" -> {"Cov", "Con"}] // Simplify[#, r > 0] & // TraditionalForm
Out[28]=

A tensor object with coordinates of opposite mixed-transformation behavior tji:

In[29]:=
tCovCon = ResourceFunction["TensorCoordinateTransform"][( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ), jacobianCylTransposed, "TransformationBehavior" -> {"Con", "Cov"}] // Simplify[#, r > 0] & // TraditionalForm
Out[29]=

Nomenclature referencing all indices together or each index separately is interchangeable:

In[30]:=
(ResourceFunction["TensorCoordinateTransform"][( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ), jacobianCylTransposed] == ResourceFunction["TensorCoordinateTransform"][( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ), jacobianCylTransposed, "TransformationBehavior" -> {"Con", "Con"}] == ResourceFunction["TensorCoordinateTransform"][( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ), jacobianCylTransposed, "TransformationBehavior" -> "AllContravariant"]) // Simplify[#, r > 0] &
Out[30]=

This is analogous for the covariant transformation:

In[31]:=
(ResourceFunction["TensorCoordinateTransform"][( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ), jacobianCylTransposed, "TransformationBehavior" -> {"Cov", "Cov"}] == ResourceFunction["TensorCoordinateTransform"][( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ), jacobianCylTransposed, "TransformationBehavior" -> "AllCovariant"]) // Simplify[#, r > 0] &
Out[31]=

Transformed contravariant vector components with respect to normalized base vectors:

In[32]:=
vNewConN = ResourceFunction["TensorCoordinateTransform"][vOld = {2, 8, 7}, mappingToNew = ( {
     {2, 3, 1},
     {1, 2, 2},
     {1, 0, 1}
    } ), "Normalize" -> True]
Out[32]=

The same transformed contravariant vector components with respect to non-normalized base vectors (default):

In[33]:=
ResourceFunction["TensorCoordinateTransform"][vOld, mappingToNew, "Normalize" -> False]
Out[33]=

Transformed covariant normalized base vectors:

In[34]:=
bNewCovN = ResourceFunction["TensorCoordinateTransform"][{e1, e2, e3}, mappingToNew, "TransformationBehavior" -> "AllCovariant", "Normalize" -> True] /. {e1 -> {1, 0, 0}, e2 -> {0, 1, 0}, e3 -> {0, 0, 1}}
Out[34]=

The contraction of the assigned tensors should be produce invariance:

In[35]:=
(\!\(
\*UnderoverscriptBox[\(\[Sum]\), \(i = 1\), \(3\)]\(vNewConN[\([\)\(i\)\(]\)] bNewCovN[\([\)\(i\)\(]\)]\
\)\)) == vOld
Out[35]=

Tensor components with respect to an orthonormal cylindrical system:

In[36]:=
tCylConCon = ResourceFunction["TensorCoordinateTransform"][( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ), Transpose@
     CoordinateTransformData["Cylindrical" -> "Cartesian", "MappingJacobian", {r, \[Phi], z}], "Normalize" -> True] // Simplify[#, r > 0] &;
tCylConCon // TraditionalForm
Out[35]=

TransformedField also assumes a normalized base:

In[37]:=
TransformedField["Cartesian" -> "Cylindrical", ( {
     {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
     {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
     {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
    } ),  {x1, x2, x3} -> {r, \[Phi], z}] // Simplify // TraditionalForm
Out[37]=
In[38]:=
(tCylConCon == TransformedField["Cartesian" -> "Cylindrical", ( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ),  {x1, x2, x3} -> {r, \[Phi], z}]) // Simplify
Out[38]=

With orthonormal reference systems (e.g. normalized cylindrical systems), no distinction between co- and contravariant transformation behavior is required:

In[39]:=
(tCylConCon ==
   ResourceFunction["TensorCoordinateTransform"][( {
      {Subscript[\[Sigma], 11], Subscript[\[Sigma], 12], Subscript[\[Sigma], 13]},
      {Subscript[\[Sigma], 21], Subscript[\[Sigma], 22], Subscript[\[Sigma], 23]},
      {Subscript[\[Sigma], 31], Subscript[\[Sigma], 32], Subscript[\[Sigma], 33]}
     } ), Transpose@
     CoordinateTransformData["Cylindrical" -> "Cartesian", "MappingJacobian", {r, \[Phi], z}], "TransformationBehavior" -> "AllCovariant", "Normalize" -> True]) // Simplify[#, r > 0] &
Out[39]=
In[40]:=
ClearAll[c]

Hook's general law describes a linear relationship between the components of the rank-2 stress tensor σ and the two-stage strain tensor ϵ using the rank-4 tensor Cσij=Cijklϵkl with the symmetries σijji ; ϵkl=ϵlk; Eijkl=Ejikl=Eijlk=Eklij :

Components of the general, fully anisotropic stiffness tensor with initial symmetries:

In[41]:=
cFull = Normal@
   SymmetrizedArray[
    pos_ :> Subscript[c, pos], {3, 3, 3, 3}, {{{2, 1, 3, 4}, 1}, {{1, 2, 4, 3}, 1}, {{3, 4, 1, 2}, 1}}];
cFull // MatrixForm
Out[37]=

The number of independent components:

In[42]:=
SymmetrizedIndependentComponents[{3, 3, 3, 3}, TensorSymmetry[cFull]] // Length
Out[42]=

One plane of symmetry, rotated by 180 degrees, results in the same stiffness:

In[43]:=
rot3 = RotationMatrix[180 \[Degree], {0, 0, 1}];
rot3 // MatrixForm
Out[44]=

This results in a stiffness tensor with fewer independent components:

In[45]:=
monoclinic = cFull /. (Flatten@(Solve[Thread@(
         Flatten@cFull == Flatten@ResourceFunction["TensorCoordinateTransform"][cFull,
             rot3, "TransformationBehavior" -> "AllCovariant"])]));
monoclinic // MatrixForm
Out[20]=

Determination and comparison of different material symmetries:

In[46]:=
orthotrop = Fold[cFull /. (Solve[
        Thread@(Flatten@cFull == Flatten@
            ResourceFunction["TensorCoordinateTransform"][#1, #2, "TransformationBehavior" -> "AllCovariant"])] // Flatten) &, cFull, {RotationMatrix[180 \[Degree], {0, 0, 1}], RotationMatrix[180 \[Degree], {0, 1, 0}]}];
In[47]:=
transversalIso = Fold[cFull /. Quiet@ (* \[Alpha] only between 0\[Degree] and 360\[Degree] \
*)(Solve[Thread@(Flatten@cFull == Flatten@
             ResourceFunction["TensorCoordinateTransform"][#1, #2, "TransformationBehavior" -> "AllCovariant"])] // Flatten) &, cFull, {RotationMatrix[180 \[Degree], {0, 0, 1}], RotationMatrix[180 \[Degree], {0, 1, 0}], RotationMatrix[\[Alpha], {1, 0, 0}]}];
In[48]:=
isotropic = Fold[cFull /. Quiet@(Solve[
         Thread@(Flatten@cFull == Flatten@
             ResourceFunction["TensorCoordinateTransform"][#1, #2, "TransformationBehavior" -> "AllCovariant"])] // Flatten) &, cFull, {RotationMatrix[\[Alpha]1, {1, 0, 0}], RotationMatrix[\[Alpha]2, {0, 1, 0}], RotationMatrix[\[Alpha]3, {0, 0, 1}]}];

Summary:

In[49]:=
(<|"Material behaviour" -> #2, "Stiffness Tensor" -> (#1 // MatrixForm), "Independent Components" -> (Cases[#1, _Subscript, \[Infinity]] //
         Union), "Number of independent components" -> Length[Cases[#1, _Subscript, \[Infinity]] // Union], "Description" -> #3|>) & @@@ {{monoclinic, "Monoclinic", "One symmetric plane"},
   {orthotrop, "Orthotropic", "Two (three) symmetric planes"},
   {transversalIso, "Transversal isotropic", "Two symmetric planes transversal isometric"},
   {isotropic, "Isotropic", "All planes isometric"}} // Dataset
Out[49]=

Resource History

Source Metadata

License Information