Coordenadas curvilineas con Python SymPy¶
Autor: Eduardo Martín Calleja
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¶
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
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:
from sympy import symbols, sin, cos, Matrix, eye, simplify, sqrt, Function, expand, sympify
# 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)
#Ecuaciones del cambio de coordenadas
x = rho * cos(theta)
y = rho * sin(theta)
C = [x, y] # Coordenadas cartesianas
P = [rho, theta] # coordenadas polares
C
# 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
eye(2) # este es el tensor métrico en coordenadas cartesianas
# Y este es el tensor métrico en coordenadas polares
g = simplify(J.T * eye(2) * J)
g
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.
# 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]
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$$# Ejemplo: elemento de área en coordenadas polares:
da = sqrt(g.det())*drho*dtheta
da
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)$
f = sym.Function('f')
f = f(*list(P)) # Expresamos f como función de las coordenadas polares
f
#Calculemos ahora la inversa de la métrica:
g_inv = g.inv()
g_inv
# Y el determinante de la métrica:
g_det = g.det()
g_det
# 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
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()
str(L_B_pol)
sympify('Derivative(f(rho, theta), rho, rho) + \
Derivative(f(rho, theta), rho)/rho + \
Derivative(f(rho, theta), theta, theta)/rho**2')
El laplaciano en coordenadas esféricas¶
# theta es la colatitud, phi la longitud
rho, theta, phi = sym.symbols('rho theta phi', real=True, negative=False)
rho, theta, phi
# Ecuaciones de cambio de coordenadas
x = rho * sin(theta) * cos(phi)
y = rho * sin(theta) * sin(phi)
z = rho * cos(theta)
C = [x, y, z] # Coordenadas cartesianas
E = [rho, theta, phi] # Coordenadas esféricas
C
# Cálculo del Jacobiano de las coordenadas C respecto de las E
J = Matrix(C).jacobian(E)
J
# Y este es el tensor métrico en coordenadas esféricas
g = simplify(J.T * eye(3) * J)
g
# Y el determinante del tensor métrico:
g_det = g.det()
g_det
#Calculemos ahora la inversa de la métrica:
g_inv = g.inv()
g_inv
f = sym.Function('f')
f = f(*list(E)) # Expresamos f como función de las coordenadas esféricas
f
# 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
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:
L_B_esf = L_B_esf.replace(sym.Abs, sym.Id).replace(sym.sign(sin(theta)), 1)
L_B_esf
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:
# 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()
f = sym.Function('f')
f = f(*list(E2)) # Expresamos f como función de las coordenadas esféricas
f
# 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
Hola eduardo, te quisiera pedir el gran favor de compartir este codigo en un archivo py ya que seria de gran ayuda para nuestro estudio
ResponderEliminarCon mucho gusto, José Darío. Envíame un email con tu dirección de correo y te hago llegar el fichero.
EliminarHola Eduardo aún tienes el archivo py? y si lo tienes lo podrias compartir porfavor
ResponderEliminarGracias por la información. ¿Tienes algo sobre integrales de volúmenes en los diferentes sistemas de coordenadas. Gracias nuevamente.
ResponderEliminar