summaryrefslogtreecommitdiff
path: root/interacticle/visual/plot.py
diff options
context:
space:
mode:
Diffstat (limited to 'interacticle/visual/plot.py')
-rw-r--r--interacticle/visual/plot.py248
1 files changed, 248 insertions, 0 deletions
diff --git a/interacticle/visual/plot.py b/interacticle/visual/plot.py
new file mode 100644
index 0000000..60b4937
--- /dev/null
+++ b/interacticle/visual/plot.py
@@ -0,0 +1,248 @@
+from OpenGL.GL import *
+
+import numpy as np
+
+import scipy.stats as stats
+import scipy.constants as const
+from scipy.optimize import minimize
+
+import matplotlib
+import matplotlib.pyplot as plt
+
+from concurrent.futures import Future, ProcessPoolExecutor
+
+def get_histogram(velocities):
+ upper = np.ceil(np.max(velocities) / 100) * 100
+ maxwellian = stats.maxwell.fit(velocities)
+
+ plt.style.use('dark_background')
+
+ fig, ax = plt.subplots(1, figsize=(8,4))
+
+ #plt.ylim(0, 0.004)
+ plt.ylabel('Probability')
+
+ plt.xlim(0, upper)
+ plt.xlabel('Velocity magnitude [m/s]')
+
+ plt.hist(velocities, bins=50, density=True, alpha=0.5, label='Simulated velocities')
+
+ xs = np.linspace(0, upper, 100)
+ ys = stats.maxwell.pdf(xs, *maxwellian)
+ plt.plot(xs, ys, label='Maxwell-Boltzmann distribution')
+
+ plt.legend(loc='upper right')
+
+ fig.canvas.draw()
+ buf = fig.canvas.tostring_rgb()
+ width, height = fig.canvas.get_width_height()
+ texture = np.frombuffer(buf, dtype=np.uint8).reshape(width, height, 3)
+
+ plt.close(fig)
+
+ return (texture, width, height)
+
+
+class VelocityHistogram:
+ def __init__(self, gas, origin, extend):
+ self.gas = gas
+ self.origin = origin
+ self.extend = extend
+ self.steps = -1
+
+ self.pool = ProcessPoolExecutor(max_workers=1)
+ self.plotter = None
+
+ self.tick = False
+ self.mixing = 0.0
+
+ self.vertices = np.array([
+ self.origin[0] , self.origin[1] , 0., 1.,
+ self.origin[0] + self.extend[0], self.origin[1] , 1., 1.,
+ self.origin[0] , self.origin[1] + self.extend[1], 0., 0.,
+ self.origin[0] + self.extend[0], self.origin[1] + self.extend[1], 1., 0.
+ ], dtype=np.float32)
+
+ def setup(self):
+ self.vao = glGenVertexArrays(1)
+ self.vbo = glGenBuffers(1)
+
+ glBindVertexArray(self.vao)
+ glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
+ glBufferData(GL_ARRAY_BUFFER, self.vertices.tostring(), GL_STATIC_DRAW)
+
+ glEnableVertexAttribArray(0)
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*np.dtype(np.float32).itemsize, ctypes.c_void_p(0))
+ glEnableVertexAttribArray(1)
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*np.dtype(np.float32).itemsize, ctypes.c_void_p(2*np.dtype(np.float32).itemsize))
+
+ self.texture_id = glGenTextures(2)
+
+ glBindTexture(GL_TEXTURE_2D, self.texture_id[0])
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glBindTexture(GL_TEXTURE_2D, self.texture_id[1])
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ def shutdown(self):
+ self.pool.shutdown(wait=True)
+
+ def update(self):
+ self.steps = self.steps + 1
+
+ if self.steps % 50 == 0 and self.plotter == None:
+ self.plotter = self.pool.submit(get_histogram, self.gas.get_velocity_norms() * 1000)
+
+ else:
+ if self.plotter != None and self.plotter.done():
+ texture, width, height = self.plotter.result()
+ if self.tick:
+ glBindTexture(GL_TEXTURE_2D, self.texture_id[0])
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture)
+ self.tick = False
+ self.mixing = 1.0
+
+ else:
+ glBindTexture(GL_TEXTURE_2D, self.texture_id[1])
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture)
+ self.tick = True
+ self.mixing = 0.0
+
+ self.plotter = None
+
+ def display_decoration(self, uniform):
+ pass
+
+ def display_window(self, uniform):
+ if self.tick:
+ self.mixing = min(self.mixing+0.05, 1.0);
+ else:
+ self.mixing = max(self.mixing-0.05, 0.0);
+
+ glBindTextures(self.texture_id[0], 2, self.texture_id)
+ glUniform1iv(uniform['picture'], len(self.texture_id), self.texture_id)
+ glUniform1f(uniform['mixing'], self.mixing)
+
+ glBindVertexArray(self.vao);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
+ glBindVertexArray(0)
+
+def get_plot(data):
+ xs = data[0]
+ ys = data[1]
+
+ plt.style.use('dark_background')
+
+ fig, ax = plt.subplots(1, figsize=(8,4))
+
+ plt.ylim(0, 350)
+ plt.ylabel('Temperature [K]')
+
+ plt.xlim(0, 200)
+ plt.xlabel('Time [ps]')
+
+ plt.plot(xs, ys, label='Temperature')
+
+ plt.legend(loc='upper right')
+
+ fig.canvas.draw()
+ buf = fig.canvas.tostring_rgb()
+ width, height = fig.canvas.get_width_height()
+ texture = np.frombuffer(buf, dtype=np.uint8).reshape(width, height, 3)
+
+ plt.close(fig)
+
+ return (texture, width, height)
+
+class TemperaturePlot:
+ def __init__(self, gas, origin, extend):
+ self.gas = gas
+ self.origin = origin
+ self.extend = extend
+ self.steps = -1
+
+ self.pool = ProcessPoolExecutor(max_workers=1)
+ self.plotter = None
+
+ self.tick = False
+ self.mixing = 0.0
+
+ self.xs = []
+ self.ys = []
+
+ self.vertices = np.array([
+ self.origin[0] , self.origin[1] , 0., 1.,
+ self.origin[0] + self.extend[0], self.origin[1] , 1., 1.,
+ self.origin[0] , self.origin[1] + self.extend[1], 0., 0.,
+ self.origin[0] + self.extend[0], self.origin[1] + self.extend[1], 1., 0.
+ ], dtype=np.float32)
+
+ def setup(self):
+ self.vao = glGenVertexArrays(1)
+ self.vbo = glGenBuffers(1)
+
+ glBindVertexArray(self.vao)
+ glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
+ glBufferData(GL_ARRAY_BUFFER, self.vertices.tostring(), GL_STATIC_DRAW)
+
+ glEnableVertexAttribArray(0)
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*np.dtype(np.float32).itemsize, ctypes.c_void_p(0))
+ glEnableVertexAttribArray(1)
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*np.dtype(np.float32).itemsize, ctypes.c_void_p(2*np.dtype(np.float32).itemsize))
+
+ self.texture_id = glGenTextures(2)
+
+ glBindTexture(GL_TEXTURE_2D, self.texture_id[0])
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glBindTexture(GL_TEXTURE_2D, self.texture_id[1])
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ def shutdown(self):
+ self.pool.shutdown(wait=True)
+
+ def update(self):
+ self.steps = self.steps + 1
+
+ if self.steps % 10 == 0 and self.plotter == None:
+ self.xs.append(self.gas.step * self.gas.tau)
+ self.ys.append(self.gas.get_temperature())
+ self.plotter = self.pool.submit(get_plot, (self.xs, self.ys))
+
+ else:
+ if self.plotter != None and self.plotter.done():
+ texture, width, height = self.plotter.result()
+ if self.tick:
+ glBindTexture(GL_TEXTURE_2D, self.texture_id[0])
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture)
+ self.tick = False
+ self.mixing = 1.0
+
+ else:
+ glBindTexture(GL_TEXTURE_2D, self.texture_id[1])
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture)
+ self.tick = True
+ self.mixing = 0.0
+
+ self.plotter = None
+
+ def display_decoration(self, uniform):
+ pass
+
+ def display_window(self, uniform):
+ if self.tick:
+ self.mixing = min(self.mixing+0.05, 1.0);
+ else:
+ self.mixing = max(self.mixing-0.05, 0.0);
+
+ glBindTextures(self.texture_id[0], 2, self.texture_id)
+ glUniform1iv(uniform['picture'], len(self.texture_id), self.texture_id)
+ glUniform1f(uniform['mixing'], self.mixing)
+
+ glBindVertexArray(self.vao);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
+ glBindVertexArray(0)