Compare commits

..

No commits in common. "895f1f86a7e6963beea6b05fe9eb3a3cf0ed8b90" and "10aa28e4b0e9b0c142128e382f65d46122c65912" have entirely different histories.

100 changed files with 0 additions and 2396 deletions

4
.gitignore vendored
View File

@ -8,7 +8,3 @@ pom.xml.asc
/.lein-* /.lein-*
/.nrepl-port /.nrepl-port
*~ *~
*/__pycache__
clojure/.rebel_readline_history
clojure/resources/public/js/*
clojure/target/*

View File

@ -1,117 +0,0 @@
# -*- coding: utf-8 -*-
# Scratch code which (very slowly) animates 3D flow via curl noise.
import functools
import numpy as np
import vispy
import vispy.scene
from vispy.scene import visuals
import opensimplex
def gradient(fn, eps=1e-3):
eps_inv = 1.0 / eps
# 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 be of shape (..., 3, 3);
# 2nd-to-last dimension is gradient of potential x, y, z.
# Last dimension is gradient of that w.r.t. x, y, and z.
cx = grads[..., 2, 1] - grads[..., 1, 2]
cy = grads[..., 0, 2] - grads[..., 2, 0]
cz = grads[..., 1, 0] - grads[..., 0, 1]
return np.stack((cx, cy, cz), axis=-1)
def generate(grid):
x_spx = opensimplex.OpenSimplex(seed=0)
y_spx = opensimplex.OpenSimplex(seed=12345)
z_spx = opensimplex.OpenSimplex(seed=45678)
grad_x = gradient(x_spx.noise3d)
grad_y = gradient(y_spx.noise3d)
grad_z = gradient(z_spx.noise3d)
# grad_x = gradient(functools.partial(x_spx.noise4d, t))
# grad_y = gradient(functools.partial(y_spx.noise4d, t))
# grad_z = gradient(functools.partial(z_spx.noise4d, t))
# grad_x = gradient(lambda x,y,z: x_spx.noise3d(x + t, y, z))
# grad_y = gradient(lambda x,y,z: y_spx.noise3d(x + t, y, z))
# grad_z = gradient(lambda x,y,z: z_spx.noise3d(x + t, y, z))
grads = np.array([
(grad_x(x,y,z), grad_y(x,y,z), grad_z(x,y,z))
for (x,y,z) in grid
])
curl = curl_3d(grads)
return curl
class Data(object):
def __init__(self, view):
self.view = view
self.visual = vispy.scene.visuals.Line(
color=(1,1,1,0.75),
connect='segments',
)
self.view.add(self.visual)
self.view.camera = 'turntable' # or try 'arcball'
#view.camera = 'arcball'
s = 0.1
count = 9
xs = zs = np.linspace(-s, s, count)
ys = np.array([0])
self.points = np.array([i.flatten() for i in np.meshgrid(xs,ys,zs)]).T
self.points_old = np.zeros((0,3))
self.update()
def update(self, ev=None):
t = 0 if ev is None else ev.elapsed
# Get velocity for current points:
curl = generate(self.points)
#
a1 = self.points
a2 = self.points + curl*0.005
# So I guess if I give argument 'pos', it needs to be of shape
# (2*N, 3) and consist of alternating starting & ending vertices?
# The docs don't say a thing about this.
lines = np.hstack((a1, a2)).reshape(self.points.shape[0]*2, -1)
self.points_old = np.vstack((self.points_old, lines))
maxpoints = self.points.shape[0] * 200
extra = self.points_old.shape[0] - maxpoints
if extra > 0:
self.points_old = self.points_old[extra:]
self.visual.set_data(
pos=self.points_old,
#arrows=np.hstack((a1, a2)),
)
self.points = a2
# self.scatter = visuals.Markers()
# self.scatter.set_data(self.d, edge_color=None, face_color=(1, 0.5, 1, .5), size=4)
# view.add(self.scatter)
#m = np.array([[np.cos(t), np.sin(t*1.01), np.cos(t*1.02)]])
#d2 = self.d*m
#self.scatter.set_data(d2, edge_color=None, face_color=(1, 0.5, 1, .5), size=4)
def main():
#
# Make a canvas and add simple view
#
canvas = vispy.scene.SceneCanvas(keys='interactive', show=True)
view = canvas.central_widget.add_view()
import sys
# add a colored 3D axis for orientation
axis = visuals.XYZAxis(parent=view.scene)
timer = vispy.app.Timer()
da = Data(view)
# Problem is how slow update() is:
timer.connect(da.update)
timer.start(0.05)
if sys.flags.interactive != 1:
vispy.app.run()
if __name__ == '__main__':
main()

View File

@ -1,212 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# (setq python-shell-interpreter (shell-command-to-string "nix-shell --command \"which python3 | tr -d '\n'\""))
import functools
import math
import numpy as np
import vispy
import vispy.scene
from vispy.scene import visuals
import opensimplex
class VectorField(object):
def eval(self, x: float, y: float, z: float) -> np.array:
"""Evaluates potential function at a single point (x,y,z).
Returns a numpy array of the 3-dimensional vector.
"""
raise Exception("Not implemented")
def grad(self, x: float, y: float, z: float, eps: float=1e-3) -> np.array:
"""Returns an array with this potential function's gradients.
Like eval() this works only at a single point. The gradients
are computed numerically using finite differences
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)
"""
# TODO: Why am I not using automatic differentiation here?
p = self.eval(x, y, z)
p_dx = self.eval(x+eps, y, z)
p_dy = self.eval(x, y+eps, z)
p_dz = self.eval(x, y, z+eps)
return (np.stack((p_dx, p_dy, p_dz)) - p).T / eps
@staticmethod
def curl_3d(grads: np.array) -> np.array:
"""Computes curl from an array of gradients.
'grads' should have shape (N1, N2, ..., 3, 3). Each 3x3 matrix in
should be the Jacobian of the function at some point.
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]
cy = grads[..., 0, 2] - grads[..., 2, 0]
cz = grads[..., 1, 0] - grads[..., 0, 1]
return np.stack((cx, cy, cz), axis=-1)
class SimplexPotential(VectorField):
"""Represents a potential function for a vector field."""
def __init__(self):
self.x_spx = opensimplex.OpenSimplex(seed=1)
self.y_spx = opensimplex.OpenSimplex(seed=12346)
self.z_spx = opensimplex.OpenSimplex(seed=45679)
def eval(self, x: float, y: float, z: float) -> np.array:
y2 = y + 0.1*math.sin(1*x) + 0.1*math.sin(1.25*z)
x2 = x
z2 = z
f1 = np.array([
self.x_spx.noise3d(x2, y2, z2),
self.y_spx.noise3d(x2, y2, z2),
self.z_spx.noise3d(x2, y2, z2),
])
f2 = np.array([z*0.5, 0, 0])
return f1 + f2
class TentacleWtf(VectorField):
def eval(self, x: float, y: float, z: float) -> np.array:
x2 = x + 0.05*math.sin(4*y) + 0.2*math.sin(4.25*z)
y2 = y
z2 = 0
f = 1.0
x3 = x2*math.cos(f*y2) - z2*math.sin(f*y2)
z3 = x2*math.sin(f*y2) + z2*math.cos(f*y2)
y3 = y2
f1 = np.array([
x3, y3, z3,
])
return f1
class KindaTwist(VectorField):
def eval(self, x: float, y: float, z: float) -> np.array:
f = 0.0
#x2 = x*math.cos(f*y) - z*math.sin(f*y)
#z2 = x*math.sin(f*y) + z*math.cos(f*y)
#y2 = 0
x3 = z
y3 = y
z3 = 0
f1 = np.array([
x3, y3, z3,
])
return f1
def generate(grid):
p = KindaTwist()
#p = SimplexPotential()
grads = np.array([p.grad(*pt) for pt in grid])
curl = p.curl_3d(grads)
return curl
def twist_xform(pts):
f = 0.3
x, y, z = pts[..., 0], pts[..., 1], pts[..., 2]
x2 = x*np.cos(f*y) - z*np.sin(f*y)
z2 = x*np.sin(f*y) + z*np.cos(f*y)
y2 = y
return np.stack((x2, y2, z2), axis=-1)
class Data(object):
def __init__(self, view):
self.use_tubes = False
self.view = view
s = 0.15
self.s = s
count = 8
xs = zs = np.linspace(-s, s, count)
ys = np.array([0])
self.points = np.array([i.flatten() for i in np.meshgrid(xs,ys,zs)]).T
self.points_old = None
if self.use_tubes:
self.visual = vispy.scene.visuals.Line(
color=(1,1,1,0.75),
connect='segments',
)
self.view.add(self.visual)
self.view.camera = 'turntable'
self.update()
else:
p = self.points
points = [p]
for i in range(200):
print(i)
curl = generate(p)
p2 = p + curl*0.1*s
p = p2
points.append(p)
points = np.stack(points, axis=1) / s
points = twist_xform(points)
# points = (count*count, N, 3) where first dimension chooses which
# trajectory, and second dimension proceeds along time/iterations
# of that trajectory.
for traj in points:
tube = vispy.scene.visuals.Tube(points=traj, radius=0.4*s)
self.view.add(tube)
self.view.camera = 'turntable'
def update(self, ev=None):
if not self.use_tubes:
return
t = 0 if ev is None else ev.elapsed
# Get velocity for current points:
curl = generate(self.points)
a1 = self.points
a2 = self.points + curl*0.1*self.s
lines = np.hstack((a1, a2)).reshape(self.points.shape[0]*2, -1) / self.s
self.points_old = np.vstack((self.points_old, lines))
maxpoints = self.points.shape[0] * 200
extra = self.points_old.shape[0] - maxpoints
if extra > 0:
self.points_old = self.points_old[extra:]
self.visual.set_data(
pos=self.points_old,
#arrows=np.hstack((a1, a2)),
)
self.points = a2
# self.scatter = visuals.Markers()
# self.scatter.set_data(self.d, edge_color=None, face_color=(1, 0.5, 1, .5), size=4)
# view.add(self.scatter)
#m = np.array([[np.cos(t), np.sin(t*1.01), np.cos(t*1.02)]])
#d2 = self.d*m
#self.scatter.set_data(d2, edge_color=None, face_color=(1, 0.5, 1, .5), size=4)
def main():
#
# Make a canvas and add simple view
#
canvas = vispy.scene.SceneCanvas(keys='interactive', show=True)
view = canvas.central_widget.add_view()
import sys
# add a colored 3D axis for orientation
axis = visuals.XYZAxis(parent=view.scene)
timer = vispy.app.Timer()
da = Data(view)
# Problem is how slow update() is:
timer.connect(da.update)
timer.start(0.05)
if sys.flags.interactive != 1:
vispy.app.run()
if __name__ == '__main__':
main()

View File

@ -1,5 +0,0 @@
How I coaxed this into working on ARM64 & Apple Silicon:
- Yes, you need Rosetta.
- Install Conda.
- Run:
conda install -c conda-force python=3.9 vispy pytest pyqt

File diff suppressed because it is too large Load Diff

View File

@ -1,121 +0,0 @@
# -*- coding: utf-8 -*-
# Scratch code for visualizing a 3D vector field with arrows
import functools
import numpy as np
import vispy
import vispy.scene
from vispy.scene import visuals
import opensimplex
def gradient(fn, eps=1e-3):
eps_inv = 1.0 / eps
# 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 be of shape (..., 3, 3);
# 2nd-to-last dimension is gradient of potential x, y, z.
# Last dimension is gradient of that w.r.t. x, y, and z.
cx = grads[..., 2, 1] - grads[..., 1, 2]
cy = grads[..., 0, 2] - grads[..., 2, 0]
cz = grads[..., 1, 0] - grads[..., 0, 1]
return np.stack((cx, cy, cz), axis=-1)
def generate(grid, t=0):
x_spx = opensimplex.OpenSimplex(seed=0)
y_spx = opensimplex.OpenSimplex(seed=12345)
z_spx = opensimplex.OpenSimplex(seed=45678)
# grad_x = gradient(x_spx.noise3d)
# grad_y = gradient(y_spx.noise3d)
# grad_z = gradient(z_spx.noise3d)
# grad_x = gradient(functools.partial(x_spx.noise4d, t))
# grad_y = gradient(functools.partial(y_spx.noise4d, t))
# grad_z = gradient(functools.partial(z_spx.noise4d, t))
grad_x = gradient(lambda x,y,z: x_spx.noise3d(x + t, y, z))
grad_y = gradient(lambda x,y,z: y_spx.noise3d(x + t, y, z))
grad_z = gradient(lambda x,y,z: z_spx.noise3d(x + t, y, z))
grads = np.array([
(grad_x(x,y,z), grad_y(x,y,z), grad_z(x,y,z))
for (x,y,z) in grid
])
curl = curl_3d(grads)
return grid, curl
#pos = np.random.normal(size=(count, 3), scale=0.2)
# one could stop here for the data generation, the rest is just to make the
# data look more interesting. Copied over from magnify.py
#return pos
# centers = np.random.normal(size=(50, 3))
# indexes = np.random.normal(size=count, loc=centers.shape[0]/2.,
# scale=centers.shape[0]/3.)
# indexes = np.clip(indexes, 0, centers.shape[0]-1).astype(int)
# scales = 2**(np.linspace(-2, 0.5, centers.shape[0]))[indexes][:, np.newaxis]
# pos *= scales
# pos += centers[indexes]
# return pos
class Data(object):
def __init__(self, view):
self.view = view
self.visual = vispy.scene.visuals.Arrow(
color=(1,1,1,0.75),
connect='segments',
arrow_size=8,
arrow_type="triangle_30",
)
self.view.add(self.visual)
self.view.camera = 'turntable' # or try 'arcball'
#view.camera = 'arcball'
s = 1
count = 8
xs = zs = np.linspace(-s, s, count)
ys = np.array([0])
self.grid = np.array([i.flatten() for i in np.meshgrid(xs,ys,zs)]).T
self.update()
def update(self, ev=None):
t = 0 if ev is None else ev.elapsed
grid, curl = generate(self.grid, t*0.4)
a1 = grid
a2 = grid + curl*0.1
# So I guess if I give argument 'pos', it needs to be of shape
# (2*N, 3) and consist of alternating starting & ending vertices?
# The docs don't say a thing about this.
self.visual.set_data(
pos=np.hstack((a1, a2)).reshape(grid.shape[0]*2, -1),
arrows=np.hstack((a1, a2)),
)
# self.scatter = visuals.Markers()
# self.scatter.set_data(self.d, edge_color=None, face_color=(1, 0.5, 1, .5), size=4)
# view.add(self.scatter)
#m = np.array([[np.cos(t), np.sin(t*1.01), np.cos(t*1.02)]])
#d2 = self.d*m
#self.scatter.set_data(d2, edge_color=None, face_color=(1, 0.5, 1, .5), size=4)
def main():
#
# Make a canvas and add simple view
#
canvas = vispy.scene.SceneCanvas(keys='interactive', show=True)
view = canvas.central_widget.add_view()
import sys
# add a colored 3D axis for orientation
axis = visuals.XYZAxis(parent=view.scene)
timer = vispy.app.Timer()
da = Data(view)
# Problem is how slow update() is:
timer.connect(da.update)
timer.start(0.05)
if sys.flags.interactive != 1:
vispy.app.run()
if __name__ == '__main__':
main()

View File

@ -1,15 +0,0 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.stdenv.mkDerivation rec {
name = "vispy-test";
# PyQt5 should be fine but seems to have other issues
buildInputs = [
(pkgs.python3.withPackages
(ps: [
ps.vispy
ps.wxPython_4_0
ps.sympy
ps.jupyterlab
]))
];
}