# Curl of a second-order tensor

In Mathematica 9.0, the documentation for the Curl function states that in n-dimensions "the resulting curl is an array with depth n-k-1 of dimensions". Accordingly, if a 2-dimensional array is feeded in the Curl function in 3-D space, it returns a scalar value.

However, it does not agree with the definition I met in other sources! $$\mathbf{\nabla}\times\mathbf{S}=e_{ijk}S_{mj,i}\mathbf{e}_k\otimes\mathbf{e}_m$$ where the curl of a second-order tensor is also a second order tensor. Is it possible to calculate in Mathematica the curl according to the above equation?

• Welcome to Mathematica.SE! I hope you will become a regular contributor. To get started, 1) take the introductory tour now, 2) when you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge, 3) remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign, and 4) give help too, by answering questions in your areas of expertise. – bbgodfrey Oct 7 '15 at 22:07

Assuming that by $e_{ijk}$ you mean the totally anti-symmetric tensor $\epsilon_{ijk}$, the expression you cite only is valid in three dimensions (since only in three dimensions $\epsilon_{ijk}$ has three indices). With the above assumption, the equation you provide can be implemented as follows

twotensorCurl3D[S_List] := Module[{},
Id = IdentityMatrix;
eps = LeviCivitaTensor;
var = Table[x[i], {i, 1, 3}];
Sum[eps[[i, j, k]] D[S[[m, j]], var[[i]]] TensorProduct[Id[[All, k]],Id[[All, m]]], {i, 1, 3}, {j, 1, 3}, {k, 1, 3}, {m, 1, 3}]
]


The bits of code mean the following. twotensorCurl3D[S_List] defines a function name and makes sure that only a list can be passed to the function. := as opposed to simply = makes sure that the right hand side is only evaluated once the function is actually called with a specific input. Module[{},...] is simply a wrapper that allows several computational steps to be done within the function before the results are put out. You could define local variables in the {} like {a,b,c}. We write the three dimensional identity matrix into the variable Id. Then the unit vectors $e_i$ can be accessed through the columns of this matrix: Id[[All,i]]. The position variables, in respect to which the nabla is taking derivatives, are defined as x[i] with i=1,2,3. The remaining code is self explanatory. The result of the last line in the Module is given back by the function after evaluation because it is not suppressed by use of ; at the end of the line.

• Thank you for this answer. I've used a modified version of the code you provided and it works fine: twotensorCurl[secondOrderTensor_, variables_] := Total[Flatten[ Table[LeviCivitaTensor[[i, j, k]]* D[secondOrderTensor[[m, j]], variables[[i]]]* Normal[SparseArray[{{k, m} -> 1}, {3, 3}]], {k, 1, 3}, {m, 1, 3}, {i, 1, 3}, {j, 1, 3}], 3]]  It looks like Mathematica does not provide in-built function for the curl as defined in my question, which is a pity, becuse other in-build vector calculus operators can be calculated in different coordinate syst. – Paweł Hermanowicz Oct 14 '15 at 21:22
• Note that this definition of Curl is equivalent to Transpose[Map[Curl[#, vars] &, S]]. In other words, this definition of Curl is still working on individual vectors of the matrix S. More clearly: Transpose[{Curl[S[], vars], Curl[S[], vars], Curl[S[], vars]}]. – jose Jun 5 '17 at 22:35
• @jose: Hi there. :) Can you tell me what is the definition of the curl that Mathematica uses for a tensor of arbitrary rank? I couldn't get anything from the documentation. Also, what is the motivation for such a definition? – Hosein Rahnama Feb 9 '19 at 13:31
• Given any array A with dimensions {d, ..., d} (where there are n d's) containing functions of variables x1, ..., xd then Curl[A, {x1, ..., xd}] is defined (modulo a constant factor) as HodgeDual[Grad[A, {x1, ..., xd}]]. A has depth n, so Grad[A, ...] has depth n+1, and then its Hodge dual has depth d - n - 1. This is a powerful definition that generalizes the standard d=3, n=1 curl to any dimension d and any depth n. It is consistent with Cross, which also works with vectors of any dimension. And it is an intrinsic operation on the whole A, not on its individual parts, so it is more geometric. – jose Feb 9 '19 at 22:38
• @jose: Thanks for your elaboration. Recently, I asked a question about this. I will be happy to have your answer here I now may want to know what is HodgeDual! Sorry my knowledge is limited to a usual course on vector and tensor calculus. :) – Hosein Rahnama Feb 12 '19 at 18:09

Recently, I communicated with wolfram support about this issue and they send me back an illustrative notebook which compares the definition that you got from wikipedia with that of Mathematica. I will put the notebook here so you can download it and hope it will be useful for future readers of this post. Here is also some parts of the notebook

(*The constant vector c in wikipedia definition*)

c = {c1, c2, c3}

(*A function which constructs tensor fields of rank n*)

A[n_] := Array[Subscript[a, ##][x, y, z] &, ConstantArray[3, n]]

(*The curl definition for a 3 dimensional space with the use Mathematica's Curl command*)

Curl3D[array_, vars_] :=
With[{n = ArrayDepth[array]},
Transpose[Map[Curl[#, vars] &, array, {n - 1}], Reverse[Range[n]]]]

(*Checking the recursive identities that wikipedia used for defining curl*)

Expand[Curl3D[A, {x, y, z}].c] === Div[Cross[A, c], {x, y, z}]

Expand[Curl3D[A, {x, y, z}].c] === Expand[Curl3D[c.A, {x, y, z}]]

Expand[Curl3D[A, {x, y, z}].c] === Expand[Curl3D[c.A, {x, y, z}]]

(*Curl of a second order tensor in Cartesian coordinates*)

Expand[Curl3D[A, {x, y, z}]] // TableForm


The curl of a tensor field

Alas, the example for the curl of a tensor field in Mathematica 12 is not what is defined in the literature for continuum mechanics. The scalar result they have is the negative of half the trace of the curl.

Mathematica has sufficient functions to correctly compute the curl of a vector or tensor if the definitions given in the attached file are followed. For a second-order tensor, a single line command:

Transpose[Div[Dot[T[x,y,z], LeviCivitaTensor], {x, y, z}]]


is all you need after defining the tensor T,

For example:

T[x_,y_,z_] := {{x y, x y^2, x y^3}, {x^2  y, x^2 y^2, x^2 y^3}, {x^3  y, x^3 y^2, x^3  y^3}}


using the example in Mathematica 12.