I need to compute covariant derivatives in Mathematica. Searching online I just found the package "Ricci" which only does symbolic computations: I instead need to do actual computations.

This is what I mean: consider $\mathbb{R}^4$ with coordinates $x_1,x_2,x_3,x_4$. In these coordinates I want to define a Riemannian metric by the coefficients $g_{ij}$, $i,j=1,\dots,4$. Then I would like to define two vector fields $u=\sum_iu_i\frac{\partial}{\partial x_i};\ v=\sum_jv_j\frac{\partial}{\partial x_j}$ by their coefficients $u_i,v_j$ (which are functions in coordinates $x_1,x_2,x_3,x_4$). Finally I would like Mathematica to compute the covariant derivative $\nabla_uv.$

Is there some package which will do the computation? If not, can you suggest me an algorithm which will do it?

Thank you


2 Answers 2


Here is some code I wrote a while back:

SetAttributes[Rs, Constant]
$Assumptions = Rs > 0;
Coordinates = {t, r, \[Theta], \[Phi]};
dim = Length[Coordinates];

MetricTensorLL = {{(1 - Rs/r), 0, 0, 0}, {0, -(1 - Rs/r)^-1, 0, 
 0}, {0, 0, -r^2, 0}, {0, 0, 0, -r^2 Sin[\[Theta]]^2}};

MetricTensorUU := MetricTensorUU = Simplify[Inverse[MetricTensorLL]];

ChristoffelSymbolsULL := 
 ChristoffelSymbolsULL = 
   Array[1/2 Sum[
    MetricTensorUU[[#1, \[Lambda]]] (D[
     MetricTensorLL[[#3, \[Lambda]]], Coordinates[[#2]]] + 
      D[MetricTensorLL[[\[Lambda], #2]], Coordinates[[#3]]] - 
       D[MetricTensorLL[[#2, #3]], 
        Coordinates[[\[Lambda]]]]), {\[Lambda], dim}] &, {dim, 
         dim, dim}];

ChristoffelSymbolsLLL := 
 ChristoffelSymbolsLLL = 
   Array[1/2 (D[MetricTensorLL[[#1, #2]], Coordinates[[#3]]] + 
    D[MetricTensorLL[[#1, #3]], Coordinates[[#2]]] - 
     D[MetricTensorLL[[#2, #3]], Coordinates[[#1]]]) &, {dim, dim,

RiemannCurvatureTensorULLL := 
 RiemannCurvatureTensorULLL = 
   Array[D[ChristoffelSymbolsULL[[#1, #2, #4]], Coordinates[[#3]]] - 
    D[ChristoffelSymbolsULL[[#1, #2, #3]], Coordinates[[#4]]] + 
     Sum[ChristoffelSymbolsULL[[#1, #3, \[Epsilon]]] \
      ChristoffelSymbolsULL[[\[Epsilon], #2, #4]], {\[Epsilon], dim}] - 
       Sum[ChristoffelSymbolsULL[[#1, #4, \[Epsilon]]] \
        ChristoffelSymbolsULL[[\[Epsilon], #2, #3]], {\[Epsilon], 
         dim}] &, {dim, dim, dim, dim}];

RiemannCurvatureTensorLLLL := 
 RiemannCurvatureTensorLLLL = 
    MetricTensorLL[[#1, \[Tau]]] \
     RiemannCurvatureTensorULLL[[\[Tau], #2, #3, #4]], {\[Tau], 
      dim}] &, {dim, dim, dim, dim}];

RiemannCurvatureTensorUUUU := 
 RiemannCurvatureTensorUUUU = 
    MetricTensorUU[[#2, \[Alpha]]] MetricTensorUU[[#3, \[Beta]]] \
     MetricTensorUU[[#4, \[Gamma]]] RiemannCurvatureTensorULLL[[#1, \
      \[Alpha], \[Beta], \[Gamma]]], {\[Alpha], dim}, {\[Beta], 
       dim}, {\[Gamma], dim}] &, {dim, dim, dim, dim}];

RiemannCurvatureTensorLL := 
 RiemannCurvatureTensorLL = 
    RiemannCurvatureTensorULLL[[\[Lambda], #1, \[Lambda], #2]], {\
     \[Lambda], dim}] &, {dim, dim}];

RiemannCurvatureTensorUL := 
 RiemannCurvatureTensorUL = 
    MetricTensorUU[[#1, \[Lambda]]] RiemannCurvatureTensorLL[[\
     \[Lambda], #2]], {\[Lambda], dim}] &, {dim, dim}];

ScalarCurvature := ScalarCurvature = Tr[RiemannCurvatureTensorUL];

KretschmannScalar := 
 KretschmannScalar = 
   Sum[RiemannCurvatureTensorLLLL[[\[Alpha], \[Beta], \[Gamma], \
    \[Delta]]] RiemannCurvatureTensorUUUU[[\[Alpha], \[Beta], \[Gamma], \
     \[Delta]]], {\[Alpha], dim}, {\[Beta], dim}, {\[Gamma], 
      dim}, {\[Delta], dim}];

WeylCurvatureTensorLLLL := 
 WeylCurvatureTensorLLLL = 
   Array[If[dim > 3, 
    RiemannCurvatureTensorLLLL[[#1, #2, #3, #4]] - 
      dim - 2) (MetricTensorLL[[#1, #3]] \
       RiemannCurvatureTensorLL[[#4, #2]] + 
        MetricTensorLL[[#2, #4]] RiemannCurvatureTensorLL[[#3, \
         #1]] - MetricTensorLL[[#1, #4]] RiemannCurvatureTensorLL[[#3, #2]] - MetricTensorLL[[#2, #3]] RiemannCurvatureTensorLL[[#4, \
          #1]]) + ScalarCurvature/((dim - 1) (dim - 2)) (MetricTensorLL[[#1, #3]] MetricTensorLL[[#4, #2]] - 
           MetricTensorLL[[#1, #4]] MetricTensorLL[[#3, #2]]), 
            0] &, {dim, dim, dim, dim}];

EinsteinTensor := 
 EinsteinTensor = 
   RiemannCurvatureTensorLL - 1/2 MetricTensorLL ScalarCurvature];

ConformallyFlatSpaceQ := 
 ConformallyFlatSpaceQ = 
  Simplify[Equal[Sequence @@ Flatten@WeylCurvatureTensorLLLL, 0]];

MaximallySymmetricSpaceQ := 
 MaximallySymmetricSpaceQ = 
   And @@ Flatten@
    Map[# == 0 &, 
     RiemannCurvatureTensorLLLL - 
       dim (dim - 
        1)) (MetricTensorLL[[#1, #3]] MetricTensorLL[[#2, #4]] -
          MetricTensorLL[[#1, #4]] MetricTensorLL[[#2, #3]]) &, \
           {dim, dim, dim, dim}], {4}]];

It is hopefully self-explanatory.

In this particular example I am using the Schwarzschild metric. The first line declares Rs, the Schwarzschild radius, to be a constant. We then define the coordinates of the manifold, in this case, $t,r,\theta,\phi$. After that, we input the components of the metric tensor, with its indices lowered (as indicated by the LL tag, meaning "lower-lower").

The rest of tensors are calculated by MMA. For example, ChristoffelSymbolsULL are the components of the Christoffel symbols, with one upper and two lower indices. Similarly, ChristoffelSymbolsLLL are the components of the Christoffel symbols with all indices lowered.

The code also computes the Riemann tensor, the Weyl tensor, and several scalars (Ricci and Kretschmann). Finally, there is a check for whether the manifold is conformally flat and/or maximally symmetric.

To compute covariant derivatives, you can use the known value of the Christoffel symbols, or the expression

Sum[1/Sqrt[Det[MetricTensorLL]] D[Sqrt[Det[MetricTensorLL]] MetricTensorUU[[\[Mu] + 1, \[Nu] + 1]] D[f @@ Coordinates, Coordinates[[\[Nu] + 1]]], Coordinates[[\[Mu] + 1]]], {\[Mu], 0, dim - 1}, {\[Nu], 0, dim - 1}]

where f is an arbitrary scalar function. For higher rank tensor fields, you'll have to make some small modifications to the code.

  • $\begingroup$ thank you! this seems a lot more than what I need. I understand the initial part of definition of the coordinates and of the metric tensor. But where can I define the two vector fields? Also, how can I compute the covariant derivative? $\endgroup$
    – user372511
    Feb 28, 2017 at 14:52
  • $\begingroup$ @AccidentalFourierTransform In your code, how can I choose one specific Christoffel Symbol from the created list? Is there any way to define a function Christoffel[a,b,c] etc? $\endgroup$ Jul 15, 2017 at 3:12

There is undocumented functionality in the SymbolicTensors package, which underlies CoordinateChartData, CoordinateTransformData, and the coordinate-system awareness of Grad, etc. You could add the context to $ContextPath save needing to type everywhere, though I won't do that in the example below.

First, you want to define a "patch". This can be done in various ways, but for a diagonal metric tensor the easiest way is scale factors. Here I'll use Minkowski in spherical coordinates as my example:

vars = {t, r, \[Theta], \[Phi]};
patch = SymbolicTensors`ScaleFactorGeometryPatch[{-1, 1, r, r Sin[\[Theta]]}, vars];

This patch is the equivalent of CoordinateChartData for your custom metric. Take a look at patch["Properties"] for some interesting things it will spit out.

Next, we need to define the two vector fields in the tensor language of the package. I'm just using the SlotSequence notation to save myself some typing, The evaluated form would work just as well for input. Below, TangentBasis is a representation of the coordinated basis for vector fields. There is a CotangentBasis for the space of one-forms. If you wish to use, e.g., an orthonormal basis, the TangentBasis with TransformedBasis and supply the change of basis matrix in the second argument.

v = SymbolicTensors`Tensor[{vt[##], vr[##], v\[Theta][##], 
     v\[CurlyPhi][##]}, {SymbolicTensors`TangentBasis[{##}]}] & @@ vars

u = SymbolicTensors`Tensor[{ut[##], ur[##], u\[Theta][##], 
     u\[CurlyPhi][##]}, {SymbolicTensors`TangentBasis[{##}]}] & @@ vars

Finally, we want to do an actual computation. For this there is a CovariantD which returns $\nabla_b v^a$, using the abstract index notation. CovariantD has the same sytnax as Grad and friends, and all of these take a patch in the third argument. (Note that Grad returns the raised derivative $\nabla^bv^a$.) The covariant derivative along a vector fields is simply $u^b\nabla_bv^a$. Since all differentiation functions in M- add the new slot at the end, this then is simply:

SymbolicTensors`CovariantD[v, vars, patch] . u

If you don't like the fact u comes at the end, you could write this more verbosely as

    TensorProduct[u, SymbolicTensors`CovariantD[v, vars, patch]],
   {1, 3}
  • $\begingroup$ You & I could have used this functionality back in our grad school days. $\endgroup$ Aug 15, 2017 at 15:38
  • 2
    $\begingroup$ @MichaelSeifert Who do you think wrote the package? :) $\endgroup$ Aug 15, 2017 at 23:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.