Add some more comments

This commit is contained in:
Chris Hodapp 2021-06-07 07:57:10 -04:00
parent 14db67426e
commit fb30ca862e
2 changed files with 44 additions and 22 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ pom.xml.asc
/.lein-* /.lein-*
/.nrepl-port /.nrepl-port
*~ *~
*/__pycache__

View File

@ -13,32 +13,40 @@ from vispy.scene import visuals
import opensimplex import opensimplex
def gradient(fn, eps=1e-3): def curl_3d(grads: np.array) -> np.array:
eps_inv = 1.0 / eps """Computes curl from an array of gradients.
# Numerical gradient by finite differences
def _grad(x, y, z):
p = fn(x, y, z)
p_dx = fn(x+eps, y, z)
p_dy = fn(x, y+eps, z)
p_dz = fn(x, y, z+eps)
return (p_dx - p)*eps_inv, (p_dy - p)*eps_inv, (p_dz - p)*eps_inv
return _grad
def curl_3d(grads): 'grads' should have shape (N1, N2, ..., 3, 3). Each 3x3 matrix in
# 'grads' should be of shape (..., 3, 3). Each 3x3 matrix should should be the Jacobian of the function at some point.
# be the Jacobian of the potential.
Each output vector is the (x,y,z) coordinates of the curl at that
corresponding point.
Parameters:
grads -- numpy array of gradients, shape (..., 3, 3)
Returns:
numpy array of shape (..., 3) containing curl vectors
"""
cx = grads[..., 2, 1] - grads[..., 1, 2] cx = grads[..., 2, 1] - grads[..., 1, 2]
cy = grads[..., 0, 2] - grads[..., 2, 0] cy = grads[..., 0, 2] - grads[..., 2, 0]
cz = grads[..., 1, 0] - grads[..., 0, 1] cz = grads[..., 1, 0] - grads[..., 0, 1]
return np.stack((cx, cy, cz), axis=-1) return np.stack((cx, cy, cz), axis=-1)
# TODO: Make VectorField class that defines grad and curl?
class Potential(object): class Potential(object):
"""Represents a potential function for a vector field."""
def __init__(self): def __init__(self):
self.x_spx = opensimplex.OpenSimplex(seed=0) self.x_spx = opensimplex.OpenSimplex(seed=0)
self.y_spx = opensimplex.OpenSimplex(seed=12345) self.y_spx = opensimplex.OpenSimplex(seed=12345)
self.z_spx = opensimplex.OpenSimplex(seed=45678) self.z_spx = opensimplex.OpenSimplex(seed=45678)
def eval(self, x, y, z): def eval(self, x: float, y: float, z: float) -> np.array:
y2 = y# + 0.5*math.sin(3*x) + 0.5*math.sin(2.5*z) """Evaluates potential function at a single point (x,y,z).
Returns a numpy array of the 3-dimensional vector.
"""
y2 = y + 0.2*math.sin(1*x) + 0.2*math.sin(1.25*z)
x2 = x x2 = x
z2 = z z2 = z
f1 = np.array([ f1 = np.array([
@ -48,13 +56,26 @@ class Potential(object):
]) ])
f2 = np.array([z*0.5, 0, 0]) f2 = np.array([z*0.5, 0, 0])
return f1# + f2 return f1# + f2
def grad(self, x, y, z, eps=1e-3): def grad(self, x: float, y: float, z: float, eps: float=1e-3) -> np.array:
# Returns gradients in matrix form. """Returns an array with this potential function's gradients.
#
# Element (i, j) is gradient of i'th component with respect to Like eval() this works only at a single point. The gradients
# j'th component, where components are (x,y,z) - i.e. row 0 is are computed numerically using finite differences
# (d/dx Px, d/dy Px, d/dz Px). I'm fairly sure this is just
# the Jacobian. In the returned array, element (i, j) is gradient of i'th
component with respect to j'th component, where components are
(X,Y,Z) - i.e. row 0 is (d/dx P_x, d/dy P_x, d/dz P_x). This
should be equivalent to the Jacobian evaluated at (x, y, z).
Parameters:
x -- X coordinate
y -- Y coordinate
z -- Z coordinate
eps -- Optional delta to compute numerical gradient (default 1e-3)
Returns:
(3,3) numpy array containing gradients at (x,y,z)
"""
p = self.eval(x, y, z) p = self.eval(x, y, z)
p_dx = self.eval(x+eps, y, z) p_dx = self.eval(x+eps, y, z)
p_dy = self.eval(x, y+eps, z) p_dy = self.eval(x, y+eps, z)