This worksheet illustrates some features of SageManifolds (v0.9) on computations regarding elasticity theory in spherical coordinates.
First we set up the notebook to display mathematical objects using LaTeX formatting:
%display latex
We then introduce the Euclidean space as a 3-dimensional differentiable manifold:
M = Manifold(3, 'M', start_index=1)
print M
3-dimensional differentiable manifold M
We shall make use of spherical coordinates $(r,\theta,\phi)$:
spher.<r,th,ph> = M.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
print spher
spher
Chart (M, (r, th, ph))
Spherical coordinates do not form a regular coordinate system of the Euclidean space. So declaring that they span $M$ means that, strictly speaking, the manifold $M$ is not the whole Euclidean space, but the Euclidean space minus some half plane (the azimuthal origin). However, in this worksheet, this difference will not matter.
The natural vector frame of spherical coordinates is
spher.frame()
We shall expand vector and tensor fields on the orthonormal frame $(e_1, e_2, e_3)$ associated with spherical coordinates, which is related to the natural frame $(\partial/\partial r, \partial/\partial\theta, \partial/\partial\phi)$ displayed above by means of the following field of automorphisms:
to_orthonormal = M.automorphism_field()
to_orthonormal[1,1] = 1
to_orthonormal[2,2] = 1/r
to_orthonormal[3,3] = 1/(r*sin(th))
to_orthonormal.display()
In other words, the change-of-basis matrix is
to_orthonormal[:]
We construct the orthonormal frame from the natural frame of spherical coordinates by this change of basis:
e = spher.frame().new_frame(to_orthonormal, 'e')
e
e[1].display()
e[2].display()
e[3].display()
At this stage, the default vector frame on $M$ is the first one introduced, namely the natural frame of spherical coordinates:
M.default_frame()
Since we prefer the orthonormal frame, we declare
M.set_default_frame(e)
Then, by default, all vector and tensor fields are displayed with respect to that frame:
e[3].display()
To get the same output as in Out[10]
, one should specify the frame for display, since this is no longer the default one:
e[3].display(spher.frame())
Let define the displacement vector $U$ in terms of its components w.r.t. the orthonormal spherical frame:
U = M.vector_field(name='U')
U[:] = [function('U_1')(r,th,ph), function('U_2')(r,th,ph), function('U_3')(r,th,ph)]
U.display()
The following computations will involve the metric $g$ of the Euclidean space. At the current stage of SageManifolds, we need to introduce it explicitly, as a Riemannian metric on the manifold $M$ (in a future version of SageManifolds, one shall to declare $M$ as an Euclidean space, and not merely as a manifold, so that it will come equipped with $g$):
g = M.riemannian_metric('g')
print g
Riemannian metric g on the 3-dimensional differentiable manifold M
Since $e$ is supposed to be an orthonormal frame, we declare that the components of $g$ with respect to it are $\mathrm{diag}(1,1,1)$:
g[1,1], g[2,2], g[3,3] = 1, 1, 1
g.display()
The expression of $g$ with respect to the natural frame of spherical coordinates is then
g.display(spher.frame())
The covariant derivative operator $\nabla$ is introduced as the (Levi-Civita) connection associated with $g$:
nabla = g.connection()
print nabla
nabla
Levi-Civita connection nabla_g associated with the Riemannian metric g on the 3-dimensional differentiable manifold M
The connection coefficients with respect to the spherical orthonormal frame $e$ are
nabla.display()
while those with respect to the natural frame of spherical coordinates (Christoffel symbols) are:
nabla.display(spher.frame())
The covariant derivative of the displacement vector $U$ is
nabU = nabla(U)
print nabU
Tensor field nabla_g(U) of type (1,1) on the 3-dimensional differentiable manifold M
nabU.display()
We convert it to a tensor field of type (0,2) (i.e. a bilinear form) by lowering the upper index with $g$:
nabU_form = nabU.down(g)
print nabU_form
Tensor field of type (0,2) on the 3-dimensional differentiable manifold M
nabU_form.display()
The strain tensor $\varepsilon$ is defined as the symmetrized part of this tensor:
E = nabU_form.symmetrize()
print E
Field of symmetric bilinear forms on the 3-dimensional differentiable manifold M
E.set_name('E', latex_name=r'\varepsilon')
E.display()
Let us display the components of $\varepsilon$, skipping those that can be deduced by symmetry:
E.display_comp(only_nonredundant=True)
To form the stress tensor according to Hooke's law, we introduce first the Lamé constants:
var('ll', latex_name=r'\lambda')
var('mu', latex_name=r'\mu')
The trace (with respect to $g$) of the bilinear form $\varepsilon$ is obtained by (i) raising the first index (pos=0
) by means of $g$ and (ii) by taking the trace of the resulting endomorphism:
trE = E.up(g, pos=0).trace()
print trE
Scalar field on the 3-dimensional differentiable manifold M
trE.display()
The stress tensor $S$ is obtained via Hooke's law for isotropic material: $$ S = \lambda \, \mathrm{tr}\varepsilon \; g + 2\mu \, \varepsilon$$
S = ll*trE*g + 2*mu*E
print S
Field of symmetric bilinear forms on the 3-dimensional differentiable manifold M
S.set_name('S')
S.display()
S.display_comp(only_nonredundant=True)
Each component can be accessed individually:
S[1,2]
The divergence of the stress tensor (with respect to $g$) is the 1-form:
$$ f_i = \nabla_j S^j_{\ \, i} $$
In a next version of SageManifolds, there will be a function divergence()
. For the moment, to evaluate $f$,
we first form the tensor $S^j_{\ \, i}$ by raising the first index (pos=0
) of $S$ with $g$:
SU = S.up(g, pos=0)
print SU
Tensor field of type (1,1) on the 3-dimensional differentiable manifold M
The divergence is obtained by taking the trace on the first index (0
) and the third one (2
) of the tensor
$(\nabla S)^j_{\ \, ik} = \nabla_k S^j_{\ \, i}$:
divS = nabla(SU).trace(0,2)
print divS
1-form on the 3-dimensional differentiable manifold M
divS.set_name('f')
divS.display()
divS.display_comp()
Note that $f_1$ is quite badly displayed. We get a better view by displaying the components one by one:
divS[1]
divS[2]
divS[3]