-->

Etiquetas

Change of curvilinear coordinates with Python SymPy

Curvilinear coordinates with Python SymPy

This post comes from my interest to continue studying the properties of the cosmic microwave background. The usual method for the analysis of their anisotropies requires working in spherical coordinates decomposing the signal into a series of spherical harmonics. Therefore I'm now beginning some posts devoted to the subject of spherical harmonics. These come as the angular component of the solution to Laplace's equation:

$$\nabla^2 f = \frac{\partial^2 f}{\partial x^2} + \frac{\partial^2 f}{\partial y^2} + \frac{\partial^2 f}{\partial z^2} = 0$$

when this is expressed in spherical coordinates. So the first step, which is the subject of this post, is to write the Laplacian operator in spherical coordinates. Of course the result can be found easily on the internet and textbooks, but I thought it might be interesting to do it using the SymPy symbolic math library for Python as an exercise.

This article has been written entirely using the Notebook of IPython.

Imports and references

In [1]:
from __future__ import division
import sympy as sym
sym.init_printing()

# This IPython magic generates a table with version information
#https://github.com/jrjohansson/version_information
%load_ext version_information
%version_information sympy
Out[1]:
SoftwareVersion
Python2.7.9 64bit [GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]
IPython3.1.0
OSLinux 3.13.0 49 generic x86_64 with debian jessie sid
sympy0.7.6
Tue Apr 21 19:49:45 2015 CEST

This article is heavily inspired by the following example: Example of changing variables in curvilinear coordinates with SymPy

Also useful the metric tensor article on Wikipedia

And, as will be seen below, we'll also need the definition of the Laplace-Beltrami operator

Some theory

Let's address the expression of the Lagrangian in coordinates different of the cartesian ones. We'll begin with some theory taking as a first example the conversion of cartesian coordinates to polar coordinates in the plane.

The metric tensor

Let's begin with the case of the plane $\mathbb{R}^2$.A coordinate system, possibly curvilinear, $(u, v)$ on the plane, is an application $\varphi(\mathbf p) = (u,v)$ which associates to each point $\mathbf p$ of the plane a pair of real numbers $(u, v)$, for example, its polar coordinates.

Given a coordinate system, we can associate to each point $\mathbf p$ in the plane, two vectors called coordinate tangent vectors

$$\vec r_u = \frac{\partial \varphi^{-1}}{\partial u}(\varphi(\mathbf p)) $$$$\vec r_v = \frac{\partial \varphi^{-1}}{\partial v}(\varphi(\mathbf p)) $$

Example: polar coordinates

For example, the polar coordinate system associate to each point $\mathbf p = (x, y)$ in the plane two real numbers $(\rho, \theta)$ defined in the usual manner.

$$\varphi(x, y) = (\rho, \theta)$$

The inverse coordinates application will be given by:

$$ \varphi^{-1}(\rho, \theta) = (x, y) = (\rho \cos \theta, \rho \sin \theta)$$

That is simply expressed by the equations:

$$x = \rho \cos \theta $$$$y = \rho \sin \theta $$

The coordinate tangent vectors will therefore be:

$$ \vec r_\rho = \frac{\partial \varphi^{-1}}{\partial \rho} = \left( \frac{\partial x}{\partial \rho} , \frac{\partial y}{\partial \rho} \right) = (\cos \theta, \sin \theta)$$$$ \vec r_\theta = \frac{\partial \varphi^{-1}}{\partial \theta} = \left( \frac{\partial x}{\partial \theta} , \frac{\partial y}{\partial \theta} \right) = (-r \sin \theta, r \cos \theta)$$

Definition of the metric tensor in the plane

Returning to the general case of any $(u, v)$ coordinates, taking the coordinate tangent vectors and using the dot product of $\mathbb{R}^2$, we can define the following quantities:

$E = \vec r_u \cdot \vec r_u \quad , \quad F = \vec r_u \cdot \vec r_v \quad , \quad G = \vec r_v \cdot \vec r_v $

And from them we can define the metric tensor as the matrix:

$$ g = \left( g_{ij} \right) = \begin{pmatrix} E & F \\ F & G \end{pmatrix} $$

For example, in the case of polar coordinates, calculating the scalar products with the tangent vectors $ \vec r_\rho , \vec r_\theta $ obtained above, the metric tensor is:

$$ g_{\: \text{polar}}= \begin{pmatrix} 1 & 0 \\ 0 & \rho^2 \end{pmatrix} $$

Change of coordinates

The metric tensor is indeed a tensor by the way it is transformed in a change of coordinates. Indeed, suppose that we have another coordinate system $(u', v')$.

$$\varphi: (x, y) \longrightarrow (u, v)$$$$\psi: (x, y) \longrightarrow (u', v')$$

We can make the old coordinates dependent on the new ones by the transformation:

$$\varphi \circ \psi^{-1}: (u', v') \longrightarrow (u, v)$$

Whose Jacobian matrix is

$$ J = \begin{pmatrix} \frac{\partial u}{\partial u'} & \frac{\partial u}{\partial v'} \\ \frac{\partial v}{\partial u'} & \frac{\partial v}{\partial v'} \end{pmatrix} $$

And applying the rules of derivation it can be seen that the metric tensor expressed in the new coordinates is:

$$ \begin{pmatrix} E' & F' \\ F' & G' \end{pmatrix} = J^T \begin{pmatrix} E & F \\ F & G \end{pmatrix} J $$

Getting the metric tensor in polar coordinates

Now, as an application of the above, we will check that, by a change of coordinates from the metric tensor in cartesian coordinates (the unit matrix), we can get the metric tensor in polar coordinates:

In [2]:
from sympy import symbols, sin, cos, Matrix, eye, simplify, sqrt, Function, expand, sympify
In [3]:
# In SymPy we must always define the symbols that we will use
theta = symbols('theta', real=True)
rho = symbols('rho', real=True, negative=False)
In [4]:
#coordinate change equations
x = rho * cos(theta)
y = rho * sin(theta)
In [5]:
C = [x, y]    # cartesian coordinates
P = [rho, theta] # polar coordinates
In [6]:
# Calculate the Jacobian of C coordinates with respect to P
J = Matrix(C).jacobian(P) # Matrix() is used to convert C
                        # into a SymPy object with the Jacobian method
J
Out[6]:
$$\left[\begin{matrix}\cos{\left (\theta \right )} & - \rho \sin{\left (\theta \right )}\\\sin{\left (\theta \right )} & \rho \cos{\left (\theta \right )}\end{matrix}\right]$$
In [7]:
eye(2)   # this is the metric tensor in cartesian coordinates
Out[7]:
$$\left[\begin{matrix}1 & 0\\0 & 1\end{matrix}\right]$$
In [8]:
# And this is the metric tensor in polar coordinates
g = simplify(J.T * eye(2) * J)
g
Out[8]:
$$\left[\begin{matrix}1 & 0\\0 & \rho^{2}\end{matrix}\right]$$

Line element

From the metric it can be obtained the element of length $ds$, it's square is defined by the expression:

$$ ds^2 = (du, dv) \begin{pmatrix} E & F \\ F & G \end{pmatrix} \begin{pmatrix} du \\ dv \end{pmatrix} $$

This doesn't depend on the chosen coordinate system. For this reason, $ds^2$ is called first fundamental form.

In [9]:
# Example: line element in polar coordinates:
drho, dtheta = symbols(r'd\rho d\theta')
dP = Matrix([drho, dtheta])
ds2 = dP.T * g * dP
ds2[0]
Out[9]:
$$d\rho^{2} + d\theta^{2} \rho^{2}$$

Differential element of area

The element of area gives another intrinsic element of the surface, which does not depend on the chosen coordinate system. We can express it as:

$$da = \sqrt{\det(g)} \; du \; dv$$
In [10]:
#Example: element of area in polar coordinates:
da = sqrt(g.det())*drho*dtheta
da
Out[10]:
$$d\rho d\theta \rho$$

The Laplace-Beltrami operator

The Laplace-Beltrami operator is a differential operator that generalizes the Laplace operator to be used with a system $(\theta_1, \theta_2, \dots \:)$ of curvilinear coordinates. Its expression is:

$$ \nabla^2 f = \frac{1}{\sqrt{\lvert g \rvert}} \frac{\partial}{\partial \theta_i} \left( \sqrt{\lvert g \rvert} g^{ij} \frac{\partial f}{\partial \theta_j} \right) $$

Where:

  • $g$ is the metric tensor, $\vert g \vert$ the determinant of its matrix.
  • $g^{ij}$ are the components of the inverse of the matrix of the metric tensor.

So, we will use this expression to obtain the Laplacian on a system of coordinates different of the cartesian ones.

The Laplacian in polar coordinates

First we will use the Laplace_Beltrami operator to express the Laplacian operator in polar coordinates $(\rho, \theta)$

In [11]:
f = sym.Function('f')
f = f(*list(P))    # Express f as a function of the polar coordinates
In [12]:
#Computing the inverse of the metric:
g_inv = g.inv()
g_inv
Out[12]:
$$\left[\begin{matrix}1 & 0\\0 & \frac{1}{\rho^{2}}\end{matrix}\right]$$
In [13]:
# And the determinant of the metric:
g_det = g.det()
g_det
Out[13]:
$$\rho^{2}$$
In [14]:
# And finally we can express the Laplace-Beltrami operator following its definition:
L_B_pol = 0
for i in range(2):
    for j in range(2):
        L_B_pol += (sqrt(g_det) * g_inv[i,j] * f.diff(P[j])).diff(P[i])
L_B_pol = expand(L_B_pol / sqrt(g_det))
L_B_pol
Out[14]:
$$\frac{\partial^{2}}{\partial \rho^{2}} f{\left (\rho,\theta \right )} + \frac{1}{\rho} \frac{\partial}{\partial \rho} f{\left (\rho,\theta \right )} + \frac{1}{\rho^{2}} \frac{\partial^{2}}{\partial \theta^{2}} f{\left (\rho,\theta \right )}$$

If you would like to use this expression in another notebook, you can generate a string from it, which could be copied to the clipboard and generate the expression again with sympify()

In [15]:
str(L_B_pol)
Out[15]:
'Derivative(f(rho, theta), rho, rho) + Derivative(f(rho, theta), rho)/rho + Derivative(f(rho, theta), theta, theta)/rho**2'
In [16]:
sympify('Derivative(f(rho, theta), rho, rho) + \
        Derivative(f(rho, theta), rho)/rho +   \
        Derivative(f(rho, theta), theta, theta)/rho**2')
Out[16]:
$$\frac{\partial^{2}}{\partial \rho^{2}} f{\left (\rho,\theta \right )} + \frac{1}{\rho} \frac{\partial}{\partial \rho} f{\left (\rho,\theta \right )} + \frac{1}{\rho^{2}} \frac{\partial^{2}}{\partial \theta^{2}} f{\left (\rho,\theta \right )}$$

The Laplacian in spherical coordinates

In [17]:
# Theta is the co-latitude, phi the longitude
rho, theta, phi = sym.symbols('rho theta phi', real=True, negative=False)
rho, theta, phi
Out[17]:
$$\left ( \rho, \quad \theta, \quad \phi\right )$$
In [18]:
# Change of coordinates equations:
x = rho * sin(theta) * cos(phi)
y = rho * sin(theta) * sin(phi)
z = rho * cos(theta)
In [19]:
C = [x, y, z]    # cartesian coordinates
S = [rho, theta, phi] # spherical coordinates
C
Out[19]:
$$\left [ \rho \sin{\left (\theta \right )} \cos{\left (\phi \right )}, \quad \rho \sin{\left (\phi \right )} \sin{\left (\theta \right )}, \quad \rho \cos{\left (\theta \right )}\right ]$$
In [20]:
# Calculate the Jacobian of C coordinates with respect to S
J = Matrix(C).jacobian(S)
J
Out[20]:
$$\left[\begin{matrix}\sin{\left (\theta \right )} \cos{\left (\phi \right )} & \rho \cos{\left (\phi \right )} \cos{\left (\theta \right )} & - \rho \sin{\left (\phi \right )} \sin{\left (\theta \right )}\\\sin{\left (\phi \right )} \sin{\left (\theta \right )} & \rho \sin{\left (\phi \right )} \cos{\left (\theta \right )} & \rho \sin{\left (\theta \right )} \cos{\left (\phi \right )}\\\cos{\left (\theta \right )} & - \rho \sin{\left (\theta \right )} & 0\end{matrix}\right]$$
In [21]:
# This is the metric tensor in spherical coordinates
g = simplify(J.T * eye(3) * J)
g
Out[21]:
$$\left[\begin{matrix}1 & 0 & 0\\0 & \rho^{2} & 0\\0 & 0 & \rho^{2} \sin^{2}{\left (\theta \right )}\end{matrix}\right]$$
In [22]:
# And the determinant of the metric tensor:
g_det = g.det()
g_det
Out[22]:
$$\rho^{4} \sin^{2}{\left (\theta \right )}$$
In [23]:
#The inverse of the metric:
g_inv = g.inv()
g_inv
Out[23]:
$$\left[\begin{matrix}1 & 0 & 0\\0 & \frac{1}{\rho^{2}} & 0\\0 & 0 & \frac{1}{\rho^{2} \sin^{2}{\left (\theta \right )}}\end{matrix}\right]$$
In [24]:
f = sym.Function('f')
f = f(*list(S))    # express f as a function of the spherical coordinates
f
Out[24]:
$$f{\left (\rho,\theta,\phi \right )}$$
In [25]:
# And finally we get the expression of the Laplace-Beltrami operator:
L_B_esf = 0
for i in range(3):
    for j in range(3):
        L_B_esf += (sqrt(g_det) * g_inv[i,j] * f.diff(S[j])).diff(S[i])
L_B_esf = expand(L_B_esf / sqrt(g_det))
L_B_esf
Out[25]:
$$\frac{\partial^{2}}{\partial \rho^{2}} f{\left (\rho,\theta,\phi \right )} + \frac{2}{\rho} \frac{\partial}{\partial \rho} f{\left (\rho,\theta,\phi \right )} + \frac{\cos{\left (\theta \right )} \frac{\partial}{\partial \theta} f{\left (\rho,\theta,\phi \right )}}{\rho^{2} \left\lvert{\sin{\left (\theta \right )}}\right\rvert} \operatorname{sign}{\left (\sin{\left (\theta \right )} \right )} + \frac{1}{\rho^{2}} \frac{\partial^{2}}{\partial \theta^{2}} f{\left (\rho,\theta,\phi \right )} + \frac{\frac{\partial^{2}}{\partial \phi^{2}} f{\left (\rho,\theta,\phi \right )}}{\rho^{2} \sin^{2}{\left (\theta \right )}}$$

This is the correct result, provided that we notice that the sign and absolute value in sin($\theta$) cancel out (SymPy apparently does not), just letting $\sin(\theta)$ in the denominator.

However, you can simplify this expression by brute force, eliminating the absolute value sign, and replacing the sign by 1:

In [26]:
L_B_esf = L_B_esf.replace(sym.Abs, sym.Id).replace(sym.sign(sin(theta)), 1)
L_B_esf
Out[26]:
$$\frac{\partial^{2}}{\partial \rho^{2}} f{\left (\rho,\theta,\phi \right )} + \frac{2}{\rho} \frac{\partial}{\partial \rho} f{\left (\rho,\theta,\phi \right )} + \frac{1}{\rho^{2}} \frac{\partial^{2}}{\partial \theta^{2}} f{\left (\rho,\theta,\phi \right )} + \frac{\cos{\left (\theta \right )} \frac{\partial}{\partial \theta} f{\left (\rho,\theta,\phi \right )}}{\rho^{2} \sin{\left (\theta \right )}} + \frac{\frac{\partial^{2}}{\partial \phi^{2}} f{\left (\rho,\theta,\phi \right )}}{\rho^{2} \sin^{2}{\left (\theta \right )}}$$

The spherical Laplacian

It is the Laplacian operator (better, the Laplace-Beltrami operator) restricted to the spherical surface of radius $\rho = 1$. In this case we have a differential operator on a surface whose local coordinates are the angular ones: $(\theta, \phi)$. Let us apply the same method as above to obtain its expression in terms of these coordinates:

In [27]:
# Equations of change of coordinates
x = sin(theta) * cos(phi)
y = sin(theta) * sin(phi)
z = cos(theta)

C = [x, y, z]    # cartesian coordinates
S2 = [theta, phi] # Spherical coordinates

J = Matrix(C).jacobian(S2)
g = simplify(J.T * eye(3) * J)
g_det = g.det()
g_inv = g.inv()
In [28]:
f = sym.Function('f')
f = f(*list(S2))    # express f as a function of the spherical coordinates
f
Out[28]:
$$f{\left (\theta,\phi \right )}$$
In [29]:
# Finally we obtain the expression of the Laplace-Beltrami operator on the unit sphere
L_B_s_esf = 0
for i in range(2):
    for j in range(2):
        L_B_s_esf += (sqrt(g_det) * g_inv[i,j] * f.diff(S2[j])).diff(S2[i])
L_B_s_esf = expand(L_B_s_esf / sqrt(g_det))
L_B_s_esf = L_B_s_esf.replace(sym.Abs, sym.Id).replace(sym.sign(sin(theta)), 1)
L_B_s_esf
Out[29]:
$$\frac{\partial^{2}}{\partial \theta^{2}} f{\left (\theta,\phi \right )} + \frac{\frac{\partial}{\partial \theta} f{\left (\theta,\phi \right )}}{\sin{\left (\theta \right )}} \cos{\left (\theta \right )} + \frac{\frac{\partial^{2}}{\partial \phi^{2}} f{\left (\theta,\phi \right )}}{\sin^{2}{\left (\theta \right )}}$$

Cambio de coordenadas curvilineas con Python SymPy

Coordenadas curvilineas con Python SymPy

Este post nace de mi interés de continuar estudiando las propiedades del Fondo Cósmico de Microondas. El método habitual para el análisis de sus anisotropías requiere trabajar en coordenadas esféricas descomponiendo la señal en un desarrollo mediante una serie de armónicos esféricos. Por este motivo inicio ahora unos posts dedicados al tema de los armónicos esféricos. Estos constituyen la parte angular de las soluciones de la ecuación de Laplace:

$$\nabla^2 f = \frac{\partial^2 f}{\partial x^2} + \frac{\partial^2 f}{\partial y^2} + \frac{\partial^2 f}{\partial z^2} = 0$$

Cuando esta se expresa en coordenadas esféricas. De modo que el primer paso, el cual es el objeto de este post, será expresar el operador laplaciano en coordenadas esféricas. Por supuesto el resultado se puede encontrar con facilidad en internet y libros de texto, pero me ha parecido que puede ser un ejercicio interesante para realizar utilizando la librería de matemática simbólica SymPy de Python.

Este artículo está escrito íntegramente utilizando el Notebook de Ipython.

Importaciones y referencias

In [1]:
from __future__ import division
import sympy as sym
sym.init_printing()

# Generar un cuadro con versiones de las librerías utilizadas en este notebook
#https://github.com/jrjohansson/version_information
%load_ext version_information
%version_information sympy
Out[1]:
SoftwareVersion
Python2.7.9 64bit [GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]
IPython3.1.0
OSLinux 3.13.0 49 generic x86_64 with debian jessie sid
sympy0.7.6
Mon Apr 20 23:55:11 2015 CEST

Este artículo está fuertemente inspirado en el siguiente ejemplo: Ejemplo de cambio de variables en coordenadas curvilineas con Sympy

También será de utilidad el Artículo sobre el tensor métrico en la Wikipedia

Y, como se verá más adelante, utilizaremos también la definición del operador de Laplace-Beltrami

Algo de teoría

Vamos a abordar la expresión del lagrangiano, primero en un disco y despues sobre una superficie esférica. Para ello necesitaremos expresar el lagrangiano en diferentes tipos de coordenadas. Comenzaremos con algo de teoría tomando como primer ejemplo la conversión de coordenadas cartesianas a coordenadas polares en el plano.

El tensor métrico

Comenzaremos por el caso del plano $\mathbb{R}^2$. Un sistema de coordenadas, posiblemente curvilineas, $(u, v)$ sobre el plano, será una aplicación $\varphi(\mathbf p) = (u,v)$ que a cada punto $\mathbf p$ del plano le asocia un par de números reales $(u, v)$, por ejemplo, sus coordenadas polares.

Para este sistema de coordenadas, podemos asociar a cada punto $\mathbf p$ del plano, unos llamados vectores tangentes coordenados:

$$\vec r_u = \frac{\partial \varphi^{-1}}{\partial u}(\varphi(\mathbf p)) $$$$\vec r_v = \frac{\partial \varphi^{-1}}{\partial v}(\varphi(\mathbf p)) $$

Ejemplo: coordenadas polares

Por ejemplo, el sistema de coordenadas polares asocia a cada punto $\mathbf p = (x, y)$ del plano el par de números reales $(\rho, \theta)$ definidos de la forma habitual:

$$\varphi(x, y) = (\rho, \theta)$$

La aplicación coordenada inversa vendrá dada por:

$$ \varphi^{-1}(\rho, \theta) = (x, y) = (\rho \cos \theta, \rho \sin \theta)$$

Que normalmente se expresa simplemente con las ecuaciones:

$$x = \rho \cos \theta $$$$y = \rho \sin \theta $$

Los vectores tangentes coordenados serán pues:

$$ \vec r_\rho = \frac{\partial \varphi^{-1}}{\partial \rho} = \left( \frac{\partial x}{\partial \rho} , \frac{\partial y}{\partial \rho} \right) = (\cos \theta, \sin \theta)$$$$ \vec r_\theta = \frac{\partial \varphi^{-1}}{\partial \theta} = \left( \frac{\partial x}{\partial \theta} , \frac{\partial y}{\partial \theta} \right) = (-r \sin \theta, r \cos \theta)$$

Definición del tensor métrico en el plano

Volvamos al caso general de unas corrdenadas cualesquiera $(u, v)$. A partir de los vectores coordenados tangentes $\vec r_u, \vec r_v$ y utilizando el producto escalar de $\mathbb{R}^2$ definiremos las cantidades:

$E = \vec r_u \cdot \vec r_u \quad , \quad F = \vec r_u \cdot \vec r_v \quad , \quad G = \vec r_v \cdot \vec r_v $

Y a partir de ellas definimos el tensor métrico como la matriz:

$$ g = \left( g_{ij} \right) = \begin{pmatrix} E & F \\ F & G \end{pmatrix} $$

Por ejemplo, en el caso de las coordenadas polares, calculando los productos escalares con los vectores tangentes $ \vec r_\rho , \vec r_\theta $ obtenidos antes, resulta el tensor métrico:

$$ g_{\: \text{polares}}= \begin{pmatrix} 1 & 0 \\ 0 & \rho^2 \end{pmatrix} $$

Cambio de coordenadas

El tensor métrico es efectivamente de un tensor por la forma en que se transforma ante un cambio de coordenadas. En efecto, supongamos que definimos otro sistema de coordenadas $(u', v')$.

$$\varphi: (x, y) \longrightarrow (u, v)$$$$\psi: (x, y) \longrightarrow (u', v')$$

Podemos hacer depender las coordenadas antiguas de las nuevas mediante la transformación:

$$\varphi \circ \psi^{-1}: (u', v') \longrightarrow (u, v)$$

Cuya matriz Jacobiana será

$$ J = \begin{pmatrix} \frac{\partial u}{\partial u'} & \frac{\partial u}{\partial v'} \\ \frac{\partial v}{\partial u'} & \frac{\partial v}{\partial v'} \end{pmatrix} $$

Y aplicando las reglas de derivación puede comprobarse que el tensor métrico expresado en las nuevas coordenadas será:

$$ \begin{pmatrix} E' & F' \\ F' & G' \end{pmatrix} = J^T \begin{pmatrix} E & F \\ F & G \end{pmatrix} J $$

Obtención del tensor métrico en coordenadas polares

A continuación, y como aplicación de lo anterior, vamos a comprobar que, mediante un cambio de coordenadas a partir del tensor métrico en coordenadas cartesianas (la matriz unidad), también llegamos a obtener el tensor métrico en coordenadas polares:

In [2]:
from sympy import symbols, sin, cos, Matrix, eye, simplify, sqrt, Function, expand, sympify
In [3]:
# En SymPy siempre hay que definir los símbolos que vamos a utilizar
theta = symbols('theta', real=True)
rho = symbols('rho', real=True, negative=False)
In [4]:
#Ecuaciones del cambio de coordenadas
x = rho * cos(theta)
y = rho * sin(theta)
In [5]:
C = [x, y]    # Coordenadas cartesianas
P = [rho, theta] # coordenadas polares
C
Out[5]:
$$\left [ \rho \cos{\left (\theta \right )}, \quad \rho \sin{\left (\theta \right )}\right ]$$
In [6]:
# Cálculo del Jacobiano de las coordenadas C respecto de las P
J = Matrix(C).jacobian(P) # Matrix se utiliza para convertir C
                        # en un objeto sympy que posea el método Jacobian
J
Out[6]:
$$\left[\begin{matrix}\cos{\left (\theta \right )} & - \rho \sin{\left (\theta \right )}\\\sin{\left (\theta \right )} & \rho \cos{\left (\theta \right )}\end{matrix}\right]$$
In [7]:
eye(2)   # este es el tensor métrico en coordenadas cartesianas
Out[7]:
$$\left[\begin{matrix}1 & 0\\0 & 1\end{matrix}\right]$$
In [8]:
# Y este es el tensor métrico en coordenadas polares
g = simplify(J.T * eye(2) * J)
g
Out[8]:
$$\left[\begin{matrix}1 & 0\\0 & \rho^{2}\end{matrix}\right]$$

Elemento de longitud

A partir de la métrica se puede obtener el elemento de longitud $ds$, Su cuadrado se define mediante la expresión:

$$ ds^2 = (du, dv) \begin{pmatrix} E & F \\ F & G \end{pmatrix} \begin{pmatrix} du \\ dv \end{pmatrix} $$

Y no depende del sistema de coordenadas elegido. Por esta razón, a $ds^2$ se le llama primera forma fundamental.

In [9]:
# Ejemplo: elemento de longitud en coordenadas polares:
drho, dtheta = symbols(r'd\rho d\theta')
dP = Matrix([drho, dtheta])
ds2 = dP.T * g * dP
ds2[0]
Out[9]:
$$d\rho^{2} + d\theta^{2} \rho^{2}$$

Elemento de área

El elemento de área $da$ es otro elemento intrínseco de la superficie, que no depende del sistema de coordenadas elegido. Se obtiene como:

$$da = \sqrt{\det(g)} du dv$$
In [10]:
# Ejemplo: elemento de área en coordenadas polares:
da = sqrt(g.det())*drho*dtheta
da
Out[10]:
$$d\rho d\theta \rho$$

El operador de Laplace-Beltrami

El operador de Laplace-Beltrami es un operador diferencial que generaliza el operador de Laplace para poder ser utilizado en un sistema $(\theta_1, \theta_2, \dots \:)$ de coordenadas curvilineas. Su expresión es:

$$ \nabla^2 f = \frac{1}{\sqrt{\lvert g \rvert}} \frac{\partial}{\partial \theta_i} \left( \sqrt{\lvert g \rvert} g^{ij} \frac{\partial f}{\partial \theta_j} \right) $$

Donde:

  • $g$ es el tensor métrico, $\vert g \vert$ el determinante de su matriz.
  • $g^{ij}$ son las componentes de la matriz inversa de la matriz del tensor métrico.

Así pues, vamos a utilizar esa expresión para obtener el laplaciano en un sistema de coordenadas diferentes de las cartesianas.

El laplaciano en coordenadas polares

En primer lugar vamos a utilizar el operador de Laplace_Beltrami para expresar el operador laplaciano en coordenadas polares $(\rho, \theta)$

In [11]:
f = sym.Function('f')
f = f(*list(P))    # Expresamos f como función de las coordenadas polares
f
Out[11]:
$$f{\left (\rho,\theta \right )}$$
In [12]:
#Calculemos ahora la inversa de la métrica:
g_inv = g.inv()
g_inv
Out[12]:
$$\left[\begin{matrix}1 & 0\\0 & \frac{1}{\rho^{2}}\end{matrix}\right]$$
In [13]:
# Y el determinante de la métrica:
g_det = g.det()
g_det
Out[13]:
$$\rho^{2}$$
In [14]:
# Y finalmente podemos expresar el operador de Laplace-Beltrami siguiendo su definición:
L_B_pol = 0
for i in range(2):
    for j in range(2):
        L_B_pol += (sqrt(g_det) * g_inv[i,j] * f.diff(P[j])).diff(P[i])
L_B_pol = expand(L_B_pol / sqrt(g_det))
L_B_pol
Out[14]:
$$\frac{\partial^{2}}{\partial \rho^{2}} f{\left (\rho,\theta \right )} + \frac{1}{\rho} \frac{\partial}{\partial \rho} f{\left (\rho,\theta \right )} + \frac{1}{\rho^{2}} \frac{\partial^{2}}{\partial \theta^{2}} f{\left (\rho,\theta \right )}$$

En caso de que quisieramos utilizar esta expresión en otro notebook, se puede generar a partir de ella un string, el cual se podría copiar al portapapeles y generar la expresión de nuevo con sympify()

In [15]:
str(L_B_pol)
Out[15]:
'Derivative(f(rho, theta), rho, rho) + Derivative(f(rho, theta), rho)/rho + Derivative(f(rho, theta), theta, theta)/rho**2'
In [16]:
sympify('Derivative(f(rho, theta), rho, rho) + \
        Derivative(f(rho, theta), rho)/rho +   \
        Derivative(f(rho, theta), theta, theta)/rho**2')
Out[16]:
$$\frac{\partial^{2}}{\partial \rho^{2}} f{\left (\rho,\theta \right )} + \frac{1}{\rho} \frac{\partial}{\partial \rho} f{\left (\rho,\theta \right )} + \frac{1}{\rho^{2}} \frac{\partial^{2}}{\partial \theta^{2}} f{\left (\rho,\theta \right )}$$

El laplaciano en coordenadas esféricas

In [17]:
# theta es la colatitud, phi la longitud
rho, theta, phi = sym.symbols('rho theta phi', real=True, negative=False)
rho, theta, phi
Out[17]:
$$\left ( \rho, \quad \theta, \quad \phi\right )$$
In [18]:
# Ecuaciones de cambio de coordenadas
x = rho * sin(theta) * cos(phi)
y = rho * sin(theta) * sin(phi)
z = rho * cos(theta)
In [19]:
C = [x, y, z]    # Coordenadas cartesianas
E = [rho, theta, phi] # Coordenadas esféricas
C
Out[19]:
$$\left [ \rho \sin{\left (\theta \right )} \cos{\left (\phi \right )}, \quad \rho \sin{\left (\phi \right )} \sin{\left (\theta \right )}, \quad \rho \cos{\left (\theta \right )}\right ]$$
In [20]:
# Cálculo del Jacobiano de las coordenadas C respecto de las E
J = Matrix(C).jacobian(E)
J
Out[20]:
$$\left[\begin{matrix}\sin{\left (\theta \right )} \cos{\left (\phi \right )} & \rho \cos{\left (\phi \right )} \cos{\left (\theta \right )} & - \rho \sin{\left (\phi \right )} \sin{\left (\theta \right )}\\\sin{\left (\phi \right )} \sin{\left (\theta \right )} & \rho \sin{\left (\phi \right )} \cos{\left (\theta \right )} & \rho \sin{\left (\theta \right )} \cos{\left (\phi \right )}\\\cos{\left (\theta \right )} & - \rho \sin{\left (\theta \right )} & 0\end{matrix}\right]$$
In [21]:
# Y este es el tensor métrico en coordenadas esféricas
g = simplify(J.T * eye(3) * J)
g
Out[21]:
$$\left[\begin{matrix}1 & 0 & 0\\0 & \rho^{2} & 0\\0 & 0 & \rho^{2} \sin^{2}{\left (\theta \right )}\end{matrix}\right]$$
In [22]:
# Y el determinante del tensor métrico:
g_det = g.det()
g_det
Out[22]:
$$\rho^{4} \sin^{2}{\left (\theta \right )}$$
In [23]:
#Calculemos ahora la inversa de la métrica:
g_inv = g.inv()
g_inv
Out[23]:
$$\left[\begin{matrix}1 & 0 & 0\\0 & \frac{1}{\rho^{2}} & 0\\0 & 0 & \frac{1}{\rho^{2} \sin^{2}{\left (\theta \right )}}\end{matrix}\right]$$
In [24]:
f = sym.Function('f')
f = f(*list(E))    # Expresamos f como función de las coordenadas esféricas
f
Out[24]:
$$f{\left (\rho,\theta,\phi \right )}$$
In [25]:
# Y finalmente podemos obtener la expresión del operador de Laplace-Beltrami siguiendo su definición:
L_B_esf = 0
for i in range(3):
    for j in range(3):
        L_B_esf += (sqrt(g_det) * g_inv[i,j] * f.diff(E[j])).diff(E[i])
L_B_esf = expand(L_B_esf / sqrt(g_det))
L_B_esf
Out[25]:
$$\frac{\partial^{2}}{\partial \rho^{2}} f{\left (\rho,\theta,\phi \right )} + \frac{2}{\rho} \frac{\partial}{\partial \rho} f{\left (\rho,\theta,\phi \right )} + \frac{\cos{\left (\theta \right )} \frac{\partial}{\partial \theta} f{\left (\rho,\theta,\phi \right )}}{\rho^{2} \left\lvert{\sin{\left (\theta \right )}}\right\rvert} \operatorname{sign}{\left (\sin{\left (\theta \right )} \right )} + \frac{1}{\rho^{2}} \frac{\partial^{2}}{\partial \theta^{2}} f{\left (\rho,\theta,\phi \right )} + \frac{\frac{\partial^{2}}{\partial \phi^{2}} f{\left (\rho,\theta,\phi \right )}}{\rho^{2} \sin^{2}{\left (\theta \right )}}$$

Es el resultado correcto, siempre que observemos que el signo y el valor absoluto en sen($\theta$) se cancelan (sympy al parecer no lo hace), quedando simplemente $\sin(\theta)$ en el denominador.

No obstante, se puede llegar a esta expresión mediante fuerza bruta, eliminando el valor absoluto, y sustituyendo el signo por 1:

In [26]:
L_B_esf = L_B_esf.replace(sym.Abs, sym.Id).replace(sym.sign(sin(theta)), 1)
L_B_esf
Out[26]:
$$\frac{\partial^{2}}{\partial \rho^{2}} f{\left (\rho,\theta,\phi \right )} + \frac{2}{\rho} \frac{\partial}{\partial \rho} f{\left (\rho,\theta,\phi \right )} + \frac{1}{\rho^{2}} \frac{\partial^{2}}{\partial \theta^{2}} f{\left (\rho,\theta,\phi \right )} + \frac{\cos{\left (\theta \right )} \frac{\partial}{\partial \theta} f{\left (\rho,\theta,\phi \right )}}{\rho^{2} \sin{\left (\theta \right )}} + \frac{\frac{\partial^{2}}{\partial \phi^{2}} f{\left (\rho,\theta,\phi \right )}}{\rho^{2} \sin^{2}{\left (\theta \right )}}$$

El laplaciano esférico

Es el operador laplaciano (mejor, el operador de Laplace-Beltrami) restringido a la superficie esférica de radio $\rho = 1$. En este caso estamos ante un operador diferencial sobre una superficie cuyas coordenadas locales son $(\theta, \phi)$. Apliquemos el mismo método que antes para obtener su expresión en función de estas coordenadas:

In [27]:
# Ecuaciones de cambio de coordenadas
x = sin(theta) * cos(phi)
y = sin(theta) * sin(phi)
z = cos(theta)

C = [x, y, z]    # Coordenadas cartesianas
E2 = [theta, phi] # Coordenadas esféricas

J = Matrix(C).jacobian(E2)
g = simplify(J.T * eye(3) * J)
g_det = g.det()
g_inv = g.inv()
In [28]:
f = sym.Function('f')
f = f(*list(E2))    # Expresamos f como función de las coordenadas esféricas
f
Out[28]:
$$f{\left (\theta,\phi \right )}$$
In [29]:
# Y finalmente obtenemos la expresión del operador de Laplace-Beltrami sobre la esfera de radio 1
L_B_s_esf = 0
for i in range(2):
    for j in range(2):
        L_B_s_esf += (sqrt(g_det) * g_inv[i,j] * f.diff(E2[j])).diff(E2[i])
L_B_s_esf = expand(L_B_s_esf / sqrt(g_det))
L_B_s_esf = L_B_s_esf.replace(sym.Abs, sym.Id).replace(sym.sign(sin(theta)), 1)
L_B_s_esf
Out[29]:
$$\frac{\partial^{2}}{\partial \theta^{2}} f{\left (\theta,\phi \right )} + \frac{\frac{\partial}{\partial \theta} f{\left (\theta,\phi \right )}}{\sin{\left (\theta \right )}} \cos{\left (\theta \right )} + \frac{\frac{\partial^{2}}{\partial \phi^{2}} f{\left (\theta,\phi \right )}}{\sin^{2}{\left (\theta \right )}}$$

Publishing on GitHub


It's been a while, and the IPhyton notebooks once prepared need a refresher. The reasons are several, but the most urgent is that, as the Python libraries evolve, most of the notebooks presented some problems in its execution. Some of the links in the notebooks had also stopped working, having changed the address of the referenced web page.
But I also understand that it was time to improve them in two ways: firstly, including information about the version used for each library, and also publishing it in some public repository for people interested in downloading them.
So I've posted all the blog notebooks to date on a GitHub repository:

https://github.com/queru49/balbuceos_astropythonicos

Next you'll find a list of all the IPython notebooks published to date with a link to the notebook viewer that provides an static view of the notebook

Publicando en GitHub

Ha pasado un tiempo, y los notebooks de IPython que en su momento preparé necesitan un repaso. Las razones son varias, pero la más perentoria es que, al estar las librerías complementarias de Python en constante evolución,  la mayoría de ellos presentaban problemas en su ejecución, al haber cambiado alguna de las APIs de los módulos utilizados. También algunos de los enlaces incluidos en los notebooks habian dejado de funcionar, al haber cambiado la dirección de la página web a la que apuntaban.

Pero además, entiendo que había llegado la hora de mejorarlos en dos sentidos: por un lado, incluyendo en ellos información de la versión utilizada de cada librería, y por otro permitiendo el acceso a los mismos para su descarga a los que desearais hacerlo.

De manera que he publicado el conjunto completo de los notebooks correspondiente a las entradas del blog escritas hasta la fecha en un repositorio de GitHub:



Finalmente, incluyo a continuación un enlace al visor NBViewer de  cada notebook, con el fin de facilitar una visión fiel, aunque estática, de los notebooks, para aquellos que no deseéis clonar el repositorio en vuestro propio ordenador.