Theory
Bases and variance, the tensor products, Kelvin-Mandel storage, rotations, and the symmetry classes with their Walpole algebra.
Bases and variance, structured tensor types, symmetry projection, and differential operators in curvilinear coordinates — symbolic or numeric, one implementation.

TensND.jl is registered in Julia's General registry. In the Julia REPL, press ] for the Pkg mode and add it:
pkg> add TensNDthen load it:
using TensNDNothing else is installed by hand. The symbolic backend, SymPy, is reached through SymPyPythonCall.jl: on the first using TensND, CondaPkg.jl installs a private Python with the sympy module into the .CondaPkg folder of the active environment. This needs an internet connection once; the next loads are offline.
Offline afterwards, or behind a proxy that blocks it: run the first load once where the connection works, or set JULIA_CONDAPKG_OFFLINE=true once the environment exists.
An existing Python of your own (it must have sympy): set JULIA_CONDAPKG_BACKEND=Null and JULIA_PYTHONCALL_EXE=/path/to/python before loading TensND, or store them as preferences of the environment, in its LocalPreferences.toml:
[CondaPkg]
backend = "Null"
[PythonCall]
exe = "/path/to/python"(the PreferenceTools package writes them from the Pkg prompt). See the CondaPkg and PythonCall documentation.
Symbols of your own: to write symbolic tensors, add the symbolic front end as well (pkg> add SymPyPythonCall) and load it next to TensND (using TensND, SymPyPythonCall); it provides @syms, symbols and Sym.
Coming from SymPy.jl: write using SymPyPythonCall instead of using SymPy. The symbols of SymPy.jl (Sym{PyObject}) are another type than those of SymPyPythonCall (Sym{Py}), which TensND uses.
TensND handles tensors of any order in any coordinate system. A basis carries its metric, so covariant and contravariant components are related rather than assumed; the differential operators follow from the chart, symbolically or by automatic differentiation.
Three structured types — TensISO, TensTI and TensCubic, TensOrtho — store the 2, 5, 3 and 9 scalars a symmetry class really has, and compute products and inverses in closed form; rand draws any of them, or a generic tensor, with uniformly random orientations. The same code runs on Float64, ForwardDiff.Dual, SymPyPythonCall.Sym and Symbolics.Num.
The design is inspired by the Maple library Tens3d of Jean Garrigues.
using TensND, SymPyPythonCall
Spherical = coorsys_spherical()
θ, ϕ, r = get_coords(Spherical)
𝐞ᶿ, 𝐞ᵠ, 𝐞ʳ = unitvec(Spherical)
@set_coorsys Spherical
σʳʳ = SymFunction("σʳʳ", real = true)(r)
σᶿᶿ = SymFunction("σᶿᶿ", real = true)(r)
𝛔 = σʳʳ * 𝐞ʳ ⊗ 𝐞ʳ + σᶿᶿ * (𝐞ᶿ ⊗ 𝐞ᶿ + 𝐞ᵠ ⊗ 𝐞ᵠ)
pprint(divergence(𝛔))(Derivative(σʳʳ(r), r) + 2*σʳʳ(r)/r - 2*σᶿᶿ(r)/r)𝐞ʳThe equilibrium equation of a spherically symmetric stress state, derived rather than transcribed.