corrections to manifest
Add pure-python integrator to verlet chain example
This commit is contained in:
parent
9a951318be
commit
77906fc7a2
@ -1,6 +1,6 @@
|
|||||||
recursive-include pyqtgraph *.py *.ui *.m README *.txt
|
recursive-include pyqtgraph *.py *.ui *.m README *.txt
|
||||||
recursive-include tests *.py *.ui
|
recursive-include tests *.py *.ui
|
||||||
recursive-include examples *.py *.ui
|
recursive-include examples *.py *.ui *.gz *.cfg
|
||||||
recursive-include doc *.rst *.py *.svg *.png *.jpg
|
recursive-include doc *.rst *.py *.svg *.png *.jpg
|
||||||
recursive-include doc/build/html *
|
recursive-include doc/build/html *
|
||||||
recursive-include tools *
|
recursive-include tools *
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import time
|
import time
|
||||||
from .relax import relax
|
from . import relax
|
||||||
|
|
||||||
|
|
||||||
class ChainSim(pg.QtCore.QObject):
|
class ChainSim(pg.QtCore.QObject):
|
||||||
@ -52,7 +52,7 @@ class ChainSim(pg.QtCore.QObject):
|
|||||||
self.mrel1[self.fixed[l2]] = 0
|
self.mrel1[self.fixed[l2]] = 0
|
||||||
self.mrel2 = 1.0 - self.mrel1
|
self.mrel2 = 1.0 - self.mrel1
|
||||||
|
|
||||||
for i in range(100):
|
for i in range(10):
|
||||||
self.relax(n=10)
|
self.relax(n=10)
|
||||||
|
|
||||||
self.initialized = True
|
self.initialized = True
|
||||||
@ -76,6 +76,10 @@ class ChainSim(pg.QtCore.QObject):
|
|||||||
dt = now - self.lasttime
|
dt = now - self.lasttime
|
||||||
self.lasttime = now
|
self.lasttime = now
|
||||||
|
|
||||||
|
# limit amount of work to be done between frames
|
||||||
|
if not relax.COMPILED:
|
||||||
|
dt = self.maxTimeStep
|
||||||
|
|
||||||
if self.lastpos is None:
|
if self.lastpos is None:
|
||||||
self.lastpos = self.pos
|
self.lastpos = self.pos
|
||||||
|
|
||||||
@ -103,8 +107,9 @@ class ChainSim(pg.QtCore.QObject):
|
|||||||
|
|
||||||
|
|
||||||
def relax(self, n=50):
|
def relax(self, n=50):
|
||||||
# speed up with C magic
|
# speed up with C magic if possible
|
||||||
relax(self.pos, self.links, self.mrel1, self.mrel2, self.lengths, self.push, self.pull, n)
|
relax.relax(self.pos, self.links, self.mrel1, self.mrel2, self.lengths, self.push, self.pull, n)
|
||||||
self.relaxed.emit()
|
self.relaxed.emit()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Binary file not shown.
@ -2,9 +2,15 @@ import ctypes
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
so = os.path.join(os.path.dirname(__file__), 'maths.so')
|
so = os.path.join(os.path.dirname(__file__), 'maths.so')
|
||||||
lib = ctypes.CDLL(so)
|
try:
|
||||||
|
lib = ctypes.CDLL(so)
|
||||||
|
COMPILED = True
|
||||||
|
except OSError:
|
||||||
|
COMPILED = False
|
||||||
|
|
||||||
lib.relax.argtypes = [
|
|
||||||
|
if COMPILED:
|
||||||
|
lib.relax.argtypes = [
|
||||||
ctypes.c_void_p,
|
ctypes.c_void_p,
|
||||||
ctypes.c_void_p,
|
ctypes.c_void_p,
|
||||||
ctypes.c_void_p,
|
ctypes.c_void_p,
|
||||||
@ -16,8 +22,49 @@ lib.relax.argtypes = [
|
|||||||
ctypes.c_int,
|
ctypes.c_int,
|
||||||
]
|
]
|
||||||
|
|
||||||
def relax(pos, links, mrel1, mrel2, lengths, push, pull, iters):
|
def relax(pos, links, mrel1, mrel2, lengths, push, pull, iters):
|
||||||
nlinks = links.shape[0]
|
nlinks = links.shape[0]
|
||||||
lib.relax(pos.ctypes, links.ctypes, mrel1.ctypes, mrel2.ctypes, lengths.ctypes, push.ctypes, pull.ctypes, nlinks, iters)
|
lib.relax(pos.ctypes, links.ctypes, mrel1.ctypes, mrel2.ctypes, lengths.ctypes, push.ctypes, pull.ctypes, nlinks, iters)
|
||||||
|
|
||||||
|
else:
|
||||||
|
def relax(pos, links, mrel1, mrel2, lengths, push, pull, iters):
|
||||||
|
lengths2 = lengths**2
|
||||||
|
for i in range(iters):
|
||||||
|
#p1 = links[:, 0]
|
||||||
|
#p2 = links[:, 1]
|
||||||
|
#x1 = pos[p1]
|
||||||
|
#x2 = pos[p2]
|
||||||
|
|
||||||
|
#dx = x2 - x1
|
||||||
|
|
||||||
|
#dist = (dx**2).sum(axis=1)**0.5
|
||||||
|
|
||||||
|
#mask = (npush & (dist < lengths)) | (npull & (dist > lengths))
|
||||||
|
##dist[mask] = lengths[mask]
|
||||||
|
#change = (lengths-dist) / dist
|
||||||
|
#change[mask] = 0
|
||||||
|
|
||||||
|
#dx *= change[:, np.newaxis]
|
||||||
|
#print dx
|
||||||
|
|
||||||
|
##pos[p1] -= mrel2 * dx
|
||||||
|
##pos[p2] += mrel1 * dx
|
||||||
|
#for j in range(links.shape[0]):
|
||||||
|
#pos[links[j,0]] -= mrel2[j] * dx[j]
|
||||||
|
#pos[links[j,1]] += mrel1[j] * dx[j]
|
||||||
|
|
||||||
|
|
||||||
|
for l in range(links.shape[0]):
|
||||||
|
p1, p2 = links[l];
|
||||||
|
x1 = pos[p1]
|
||||||
|
x2 = pos[p2]
|
||||||
|
|
||||||
|
dx = x2 - x1
|
||||||
|
dist2 = (dx**2).sum()
|
||||||
|
|
||||||
|
if (push[l] and dist2 < lengths2[l]) or (pull[l] and dist2 > lengths2[l]):
|
||||||
|
dist = dist2 ** 0.5
|
||||||
|
change = (lengths[l]-dist) / dist
|
||||||
|
dx *= change
|
||||||
|
pos[p1] -= mrel2[l] * dx
|
||||||
|
pos[p2] += mrel1[l] * dx
|
||||||
|
@ -1,26 +1,38 @@
|
|||||||
"""
|
"""
|
||||||
Mechanical simulation of a chain using verlet integration.
|
Mechanical simulation of a chain using verlet integration.
|
||||||
|
|
||||||
|
Use the mouse to interact with one of the chains.
|
||||||
|
|
||||||
|
By default, this uses a slow, pure-python integrator to solve the chain link
|
||||||
|
positions. Unix users may compile a small math library to speed this up by
|
||||||
|
running the `examples/verlet_chain/make` script.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import initExample ## Add path to library (just for examples; you do not need this)
|
import initExample ## Add path to library (just for examples; you do not need this)
|
||||||
|
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from pyqtgraph.Qt import QtCore, QtGui
|
from pyqtgraph.Qt import QtCore, QtGui
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from verlet_chain import ChainSim
|
import verlet_chain
|
||||||
|
|
||||||
sim = ChainSim()
|
sim = verlet_chain.ChainSim()
|
||||||
|
|
||||||
|
if verlet_chain.relax.COMPILED:
|
||||||
|
# Use more complex chain if compiled mad library is available.
|
||||||
|
chlen1 = 80
|
||||||
|
chlen2 = 60
|
||||||
|
linklen = 1
|
||||||
|
else:
|
||||||
|
chlen1 = 10
|
||||||
|
chlen2 = 8
|
||||||
|
linklen = 8
|
||||||
|
|
||||||
chlen1 = 80
|
|
||||||
chlen2 = 60
|
|
||||||
npts = chlen1 + chlen2
|
npts = chlen1 + chlen2
|
||||||
|
|
||||||
sim.mass = np.ones(npts)
|
sim.mass = np.ones(npts)
|
||||||
sim.mass[chlen1-15] = 100
|
sim.mass[int(chlen1 * 0.8)] = 100
|
||||||
sim.mass[chlen1-1] = 500
|
sim.mass[chlen1-1] = 500
|
||||||
sim.mass[npts-1] = 200
|
sim.mass[npts-1] = 200
|
||||||
|
|
||||||
@ -31,8 +43,10 @@ sim.fixed[chlen1] = True
|
|||||||
sim.pos = np.empty((npts, 2))
|
sim.pos = np.empty((npts, 2))
|
||||||
sim.pos[:chlen1, 0] = 0
|
sim.pos[:chlen1, 0] = 0
|
||||||
sim.pos[chlen1:, 0] = 10
|
sim.pos[chlen1:, 0] = 10
|
||||||
sim.pos[:chlen1, 1] = np.arange(chlen1)
|
sim.pos[:chlen1, 1] = np.arange(chlen1) * linklen
|
||||||
sim.pos[chlen1:, 1] = np.arange(chlen2)
|
sim.pos[chlen1:, 1] = np.arange(chlen2) * linklen
|
||||||
|
# to prevent miraculous balancing acts:
|
||||||
|
sim.pos += np.random.normal(size=sim.pos.shape, scale=1e-3)
|
||||||
|
|
||||||
links1 = [(j, i+j+1) for i in range(chlen1) for j in range(chlen1-i-1)]
|
links1 = [(j, i+j+1) for i in range(chlen1) for j in range(chlen1-i-1)]
|
||||||
links2 = [(j, i+j+1) for i in range(chlen2) for j in range(chlen2-i-1)]
|
links2 = [(j, i+j+1) for i in range(chlen2) for j in range(chlen2-i-1)]
|
||||||
@ -55,7 +69,8 @@ sim.push = np.concatenate([push1, push2, np.array([True], dtype=bool)])
|
|||||||
sim.pull = np.ones(sim.links.shape[0], dtype=bool)
|
sim.pull = np.ones(sim.links.shape[0], dtype=bool)
|
||||||
sim.pull[-1] = False
|
sim.pull[-1] = False
|
||||||
|
|
||||||
mousepos = sim.pos[0]
|
# move chain initially just to generate some motion if the mouse is not over the window
|
||||||
|
mousepos = np.array([30, 20])
|
||||||
|
|
||||||
|
|
||||||
def display():
|
def display():
|
||||||
|
Loading…
Reference in New Issue
Block a user