I’m currently making a python app that simulates a set of coupled ordinary differentials equations that depends on a variable, let’s call it « X ».
As for now, I’m basically simulating this set of ODE with RK4 for given time then I’m plotting the graph on an animated plot with « matplotlib animation » embedded in tkinter.
The fact is that I would like to be able to modify « X » as the equations are resolved so that the simulation can change as we modify this variable.
The solution changes from that time on. To put things in context, these are the equations for the xenon and iodine abundance as well as neutrons flow in a nuclear reactor. The variable that change is "big sigma_b" that governs the control bars.
xenon and iodine abundance ODE :
To summarize, « X » belongs to the range [1.0, 2.0], let’s say we want to run 400 hours of simulations :
Hopefully, it’s clear enough. How could I do that ?
Translating the ideas of the comments into a mockup gives some code to experiment with
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import matplotlib.animation as anim
import numpy as np
from scipy.integrate import odeint
# model is dampened oscillation with control variable u
# representing the equilibrium position
# x'' + 0.4*x + x == u
def model(x,u): return np.array([x[1], u - 0.4*x[1] - x[0]])
# integrate over about 10 periods
N=250
t = np.linspace(0, 12*np.pi, N+1) # time
# arrays to hold the computed values
X = np.zeros([N+1,2])
U = np.zeros([N+1])
# initial values
X[0] = [3, 2]
U[0] = 2;
# initialize plot
fig, ax = plt.subplots()
plt.subplots_adjust(left=0.25, bottom=0.25)
# initialize graphs
l1, = plt.plot(t[0], X[0,0], '-+b', ms=2 )
l2, = plt.plot(t[0], U[0], '-or', ms=2, lw=1 )
plt.xlim(t[0], t[-1]); plt.ylim(-1,3)
# construct slider
axcolor = 'black'
ax_U = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=axcolor)
sU = Slider(ax_U, 'U', 1.0, 2.0, valinit=U[0])
def animate(i):
# read the slider value
U[i] = sU.val
# integrate over the sub-interval
X[i] = odeint(lambda x,t: model(x,U[i]), X[i-1], [t[i-1],t[i]], atol=1e-4, rtol=1e-8)[-1];
# set the data to plot
l1.set_data(t[0:i+1],X[0:i+1,0]);
l2.set_data(t[0:i+1],U[0:i+1]);
return l1,l2
# start the animation, one should set the parameter to keep it from repeating
anim = anim.FuncAnimation(fig, animate, frames = range(1,N+1), blit=True, interval = 100 )
plt.show()