diff options
Diffstat (limited to 'interacticle/visual/plot.py')
-rw-r--r-- | interacticle/visual/plot.py | 248 |
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) |