---
title: "Tensor Fields"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Tensor Fields}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
```
{ricci} has limited support for [tensor fields](https://en.wikipedia.org/wiki/Tensor_field). Non-constant tensor fields in {ricci} are modeled by `array()`s whose elements are character strings, each string containing a mathematical expression (which are interpreted as functions of manifold coordinates).
This approach implies that only subset of all tensor fields can be modeled:
- Only mathematical expressions that are understood by R are allowed.
- If derivatives are involved only expressions where R's `deriv()` knows the derivative of are allowed.
- Not all tensor fields can be expressed in closed-form expressions to begin with.
Nevertheless, the subset of tensor fields that {ricci} does currently support can still be nontrivial and we still consider this feature useful to this extent.
### Covariant derivative
The main usage of tensor fields in {ricci} is to calculate covariant derivatives, i.e. to make use of the function `covd()`. Similar to the product operator `*` which unifies products by making use of the index structure, `covd()` unifies various differential operators, like e.g. the "gradient", "divergence", "curl", the "Hessian" and the "Laplacian", in any dimension on any (pseudo-) Riemannian manifold and in any coordinate system.
`covd()` requires two main ingredients: a tensor field it can act upon, and a metric tensor field. This tensor field and the metric tensor are thought to exist on the same manifold and they are required to be specified in the same coordinate system.
#### Examples
{ricci} already provides a couple of standard metric tensors, the standard Euclidean metric tensor $g$ in Cartesian coordinates $(x_1,x_2,x_3)$ is simply the identity matrix, while in spherical coordinates $(r, \phi_1, \phi_2)$ the metric tensor appears more complicated:
```{r setup}
library(ricci)
# enable optional simplfying procedures
# (takes a toll on performance)
options(ricci.auto_simplify = TRUE)
g_eucl_cart(3)
g_eucl_sph(3)
```
Equipped with such metrics, we can for example pick a simple tensor field, namely a scalar function $f(r, \phi_1, \phi_2) = r^{-1}$, and calculate our first gradient:
```{r}
"1/r" |> covd(.(k), g = g_eucl_sph(3))
```
The argument `.(k)` is nothing special but simply defines a name for the new rank of the array.
The Hessian could be computed in similar fashion:
```{r}
"1/r" |> covd(.(k, l), g = g_eucl_sph(3))
```
The operation above can be set into the context of electrodynamics where $f$ is an electrostatic potential, and its gradient is the electric field. For the same electrostatic potential we can very simply calculate the electromagnetic tensor too after forming the electromagnetic potential $A_\mu$:
```{r}
# electromagnetic potential
A <- c("1/r", "0", "0", "0")
A %_% .(m) |>
covd(.(n), g = g_mink_sph(4)) |>
asym(m, n)
```
We can also chain multiple covariant derivatives in any way we'd like. A well known second-order differential operator, the Laplacian $\Delta = \nabla_k \nabla^k$ can easily be written down:
```{r}
# on scalar field
"1/r" |> covd(.(k, +k), g = g_mink_sph(4))
# on a vector field
A %_% .(i) |> covd(.(k, +k), g = g_mink_sph(4))
```
One property of the metric tensor is that the (Levi Civita) covariant derivative of the metric tensor vanishes. We can test this easily:
```{r}
g <- g_eucl_sph(3)
g %_% .(i, j) |>
covd(.(k), g = g) |>
as_a(i, j, k)
```