Setup

Install package

PacletSiteRegister["https://pacletserver.bhptoolkit.org","Black Hole Perturbation Toolkit Paclet Server"]

PacletSiteUpdate["https://pacletserver.bhptoolkit.org"]

PacletFindRemote["*",<|"Location"->"https://pacletserver.bhptoolkit.org"|>]

PacletInstall["GeneralRelativityTensors"];

How to find documentation

Go to Help -> Wolfram Documentation -> Add-ons and Packages -> GeneralRelativityTensors

Intro to GeneralRelativityTensors

Load package

<<GeneralRelativityTensors`

Metrics

?ToMetric

Built in metric:

gS=ToMetric["Schw"]

Access values

gS[-t,-t]

TensorValues[gS]

Underneath it’s just a list of rules

List@@gS

Defining a new metric and tensor

Tensors always have associated metrics

Give metric values in a form with unknowns

newMetVals={{-f[x,y],0,0},{0,g[x,y](x^2),x y g[x,y]},{0,x y g[x,y],g[x,y](x^2)}};
newMetVals//MatrixForm

Define new metric

gNew=ToMetric[{"NewMetric","(g^new)"},{t,x,y},newMetVals,"Latin"]

t1=ToTensor[{"NewTensor","t"},gNew,{q[t],r[x],s[y]},{-a}]

Raise and lower indices with arguments

t1[a]

t1[a]//TensorValues

t1[x]

t1 is still a covariant tensor

t1

Functions to access info about a tensor

Metric[t1]

MetricQ[t1]
MetricQ[gNew]

Coordinates[t1]

Indices[t1]

PossibleIndices[t1]

Rank[t1]

SpacetimeDimensions[t1]

TensorName[t1]
TensorDisplayName[t1]

Standard GR calculations

Compute a Ricci tensor

Compute (Subscript[(Γ^α), βγ]) associated with that metric

chrS=ChristoffelSymbol[gS]

chrS//TensorValues

ricTenS=RicciTensor[gS]

ricTenS//TensorValues

Use ActWith->Simplify to clean up internal expressions

RicciTensor[gS,ActWith->Simplify]//TensorValues

Merging tensors

Use built in functions to compute Ricci scalar and tensor

ricTS=RicciTensor[gS]
ricSS=RicciScalar[gS]

Compute the Einstein tensor “by hand”

einSExpr=ricTS[-α,-β]-gS[-α,-β] ricSS/2

This is not a single tensor yet

(*MergeTensors[einSExpr]*)

einS=MergeTensors[einSExpr,{"EinsteinSchwarzschild","G"},ActWith->Simplify]

einS//TensorValues

Derivatives

Partial derivatives

D is overloaded to take derivatives with respect to indices

gSDiv=D[gS[α,β],-α]

Indices are not traced until forced

gSDiv//TensorValues//Simplify

Covariant derivatives

gRN=ToMetric["ReissnerNordstrom"]

dgRN=CovariantD[gRN,-γ]

MergeTensors[dgRN,ActWith->Simplify]//TensorValues

Curves

A built in tensor on curve

uS=FourVelocityVector["SchwarzschildGeneric"]

Parallel transport a 4-velocity along itself

covDuS=CovariantD[uS,uS]

vals=TensorValues@MergeTensors[covDuS,ActWith->Simplify]

uSRules=Thread[D[Through[Coordinates[uS][τ]],τ]->TensorValues[uS]]

vals/.uSRules//Simplify

Caching

By default caching is off

$CacheTensorValues

AbsoluteTiming[GS=EinsteinTensor[gS]]

$CacheTensorValues=True

AbsoluteTiming[GS=EinsteinTensor[gS]]

AbsoluteTiming[GS=EinsteinTensor[gS]]

GS//TensorValues //Short

ClearCachedTensorValues[All]

AbsoluteTiming[GS=EinsteinTensor[gS,ActWithNested->Simplify]]

GS//TensorValues

Examples

The scalar wave equation on Schwarzschild

First method - default behavior

Define the metric as usual.

gS=ToMetric["Schwarzschild"]

Define a scalar field.

It is a Tensor with zero indices.

We choose its values to be a function of t & r multiplied by the scalar spherical harmonics.

phi=ToTensor[{"PhiScalar","ϕ"},gS,ϕ[t,r]Ylm[θ,ϕ]]

The wave equation is just two traced covariant derivatives.

Timing[waveScalar1=CovariantD[phi,-α,α]]

Merge the expression into one Tensor with no indices. Note the use of ActWith and a pure function.

Timing[boxPhi1=MergeTensors[waveScalar1,ActWith->(Collect[#,{_[θ,ϕ],_[t,r]},Simplify]&)]]

boxPhi1//TensorValues

In order to simplify this further, we need to make use of the eigenvalue equations for Ylm. This allows us to remove derivatives.

Clear[d2thYRule,dphYRule]
d2thYRule=Derivative[a_/;a≥2,b_][Ylm][θ,ϕ]:>D[(((m^2)/((Sin[θ])^2))-l (1+l))Ylm[θ,ϕ]-((Cos[θ])/(Sin[θ]))D[Ylm[θ,ϕ],θ],{θ,a-2},{ϕ,b}];
dphYRule=Derivative[a_,b_][Ylm][θ,ϕ]:>D[(((I m))^b)Ylm[θ,ϕ],{θ,a}];
removeYlmDerivs[expr_]:=expr//.{d2thYRule,dphYRule};
collectAndSimp[expr_]:=Collect[removeYlmDerivs@expr,{_[θ,ϕ],_[t,r]},Simplify]

Use the function ActOnTensorValues to apply a function to the values of a Tensor.

Timing[boxPhi2=ActOnTensorValues[collectAndSimp,boxPhi1]]

boxPhi2//TensorValues

This is the expected wave equation on Schwarzschild.

Second method - covariant derivatives with merging

CovariantD has the following options;

Options[CovariantD]

Setting Merge -> True will cause the final return value to be merged into one Tensor.

Setting MergeNested -> True merges at each step of a higher-order derivative. This can greatly speed up some calculations.

Timing[waveScalar2=CovariantD[phi,-α,α,MergeNested->True,ActWith->collectAndSimp]]

waveScalar2//TensorValues