In [1]:
from sympy import *
In [2]:
init_session()
In [3]:
def scale_coeff(r_vec, coords):
"""
Compyte scale coefficients for the vector
tranform given by r_vec.
Parameters
=======
r_vec : Matrix (3, 1)
Transform vector (x, y, z) as a functoin of coordinates
u1, u2, u3.
coords : Tupl (3)
Coordinates for the new reference system.
Returns
========
h_vec : Tuple (3)
Scale coefficients.
"""
if type(r_vec) == list:
r_vec = Matrix(r_vec)
u1, u2, u3 = coords
h1 = simplify((r_vec.diff(u1)).norm())
h2 = simplify((r_vec.diff(u2)).norm())
h3 = simplify((r_vec.diff(u3)).norm())
return h1, h2, h3
As an example, the tranformation for Spherical coordinates.
In [4]:
r, theta, phi = symbols("r theta phi", positive=True)
h_vec = scale_coeff([r*sin(theta)*cos(phi),
r*sin(theta)*sin(phi),
r*cos(theta)],
[r, theta, phi])
In [5]:
h_vec
Out[5]:
And, since $\theta$ is in $[0, \pi]$, the last component is $r \sin(\theta)$.
In [6]:
def grad(u, coords=(x, y, z), h_vec=(1, 1, 1)):
"""
Compute the gradient of a scalara function phi.
Parameters
==========
u : SymPy expression
Scalar function to compute the gradient from.
coords : Tuple (3), optional
Coordinates for the new reference system. This is an optional
parameters, and it takes a cartesian (x, y, z), as default.
h_vec : Tuple (3), optional
Scale coefficients for the new coordinate system. It takes
(1, 1, 1), as default.
Returns
========
gradient: Matrix (3, 1)
Column vector with the components of the gradient.
"""
return Matrix(3, 1, lambda i, j: u.diff(coords[i])/h_vec[j])
Let's see an example.
In [7]:
grad(-(cos(x)**2 + cos(y)**2)**2)
Out[7]:
In [8]:
def grad_vec(A, coords=(x, y, z), h_vec=(1, 1, 1)):
"""
Gradient of a vector function A.
Parameters
==========
A : Matrix (3, 1), list
Vector function to compute the gradient from.
coords : Tuple (3), optional
Coordinates for the new reference system. This is an optional parameter
it takes (x, y, z) as default.
h_vec : Tuple (3), optional
Scale coefficients for the new coordinate system. It takes
(1, 1, 1), as default.
Returns
=======
gradient: Matrix (3, 3)
Matrix with the components of the gradient. The position (i, j) has as components
diff(A[i], coords[j].
"""
return Matrix(3, 3, lambda i, j: (S(1)/h_vec[j])*A[i].diff(coords[j]))
Let's see a simple example.
In [9]:
grad_vec([x*y*z, x*y*z, x*y*z])
Out[9]:
In [10]:
def div(A, coords=(x, y, z), h_vec=(1, 1, 1)):
"""
Divergence of the vector function A.
Parameters
==========
A : Matrix, list
Scalar function to compute the divergence from.
coords : Tuple (3), optional
Coordinates for the new reference system. This is an optional parameter
it takes (x, y, z) as default.
h_vec : Tuple (3), optional
Scale coefficients for the new coordinate system. It takes
(1, 1, 1), as default.
Returns
========
divergence: SymPy expression
Divergence of A.
"""
h = h_vec[0]*h_vec[1]*h_vec[2]
aux = simplify((S(1)/h)*sum(diff(A[k]*h/h_vec[k], coords[k])
for k in range(3)))
return aux
Let's see a simple example.
In [11]:
div([x**2 + y*z, y**2+x*z, z**2 + x*y])
Out[11]:
In [12]:
def curl(A, coords=(x, y, z), h_vec=(1, 1, 1)):
"""
Curl of a function vector A.
Parameters
==========
A : Matrix, List
Vector function to compute the curl from.
coords : Tuple (3), optional
Coordinates for the new reference system. This is an optional parameter
it takes (x, y, z) as default.
h_vec : Tuple (3), optional
Scale coefficients for the new coordinate system. It takes
(1, 1, 1), as default.
Returns
=======
curl : Matrix (3, 1)
Column vector with the curl of A.
"""
perm = lambda i, j, k: (i - j)*(j - k)*(k - i)/S(2)
h = h_vec[0]*h_vec[1]*h_vec[2]
aux = [(S(1)/h)*sum(perm(i, j, k)*h_vec[i]*diff(A[k]*h_vec[k], coords[j]) for j in range(3) for k in range(3))
for i in range(3)]
return Matrix(aux)
Let's see an example.
In [13]:
curl([0, -x**2, 0])
Out[13]:
In [14]:
def lap(u, coords=(x, y, z), h_vec=(1, 1, 1)):
"""
Laplacian of the scalar function phi.
Parameters
==========
u : SymPy expression
Scalar function to compute the gradient from.
coords : Tuple (3), optional
Coordinates for the new reference system. This is an optional
parameters, and it takes a cartesian (x, y, z), as default.
h_vec : Tuple (3), optional
Scale coefficients for the new coordinate system. It takes
(1, 1, 1), as default.
Returns
=======
laplacian: Sympy expression
Laplacian of phi.
"""
h = h_vec[0]*h_vec[1]*h_vec[2]
return sum([1/h*diff(h/h_vec[k]**2*u.diff(coords[k]), coords[k]) for k in range(3)])
Hagamos un ejemplo simple
In [15]:
lap(x**2 + y**2 + z**2)
Out[15]:
In [16]:
def lap_vec(A, coords=(x, y, z), h_vec=(1, 1, 1)):
"""
Laplacian of a vector function A.
Parameters
==========
A : Matrix, List
Vector function to compute the curl from.
coords : Tuple (3), optional
Coordinates for the new reference system. This is an optional parameter
it takes (x, y, z) as default.
h_vec : Tuple (3), optional
Scale coefficients for the new coordinate system. It takes
(1, 1, 1), as default.
Devuelve
========
laplacian : Matrix (3, 1)
Column vector with the components of the Laplacian.
"""
return grad(div(A, coords=coords, h_vec=h_vec), coords=coords, h_vec=h_vec) -\
curl(curl(A, coords=coords, h_vec=h_vec), coords=coords, h_vec=h_vec)
Let's check with an example.
In [17]:
lap_vec([x**2, y**2, z**2])
Out[17]:
In [18]:
w = symbols("w", cls=Function)
rho, phi, z = symbols("rho phi z", positive=True)
D, q = symbols("D q")
In [19]:
coords = (rho, phi, z)
h_vec = [1, rho, 1]
In [20]:
L1 = lap(w(rho, phi), coords=coords, h_vec=h_vec)
L1
Out[20]:
In [21]:
L2 = lap(L1, coords=coords, h_vec=h_vec)
L2
Out[21]:
In [22]:
display(expand(D*L2 + q))
In [ ]: