Kuramoto Lab: Full Simulation
Module 2: Synchronization and Collective Behaviour
This page is optional. It combines the animation and the bifurcation diagram into one interactive window with sliders and live plots (Kuramoto 2003; Hunter 2007). If you skip it, continue with Finite-Size Effects.
Template
You can start from the template in amlab/odes_coupled/kuramoto_template.py and fill in the missing parts. The template includes the structure for sliders, animation, and order parameter computation, so you can focus on implementing the Kuramoto model dynamics and visualizations.
Alternatively, you can build the full simulation from scratch by following the steps outlined in the previous pages and combining them together.
Order Parameter
Complete the function that computes the order parameter. It returns \(r\), \(\psi\) and the two coordinates \(r\cos\psi\) and \(r\sin\psi\) of the red dot.
def kuramoto_order_parameter(theta: np.ndarray) -> tuple:
# TODO: compute r * exp(i * phi)
order_param = # replace this line
r = np.abs(order_param)
phi = np.angle(order_param)
rcosphi = np.real(order_param)
rsinphi = np.imag(order_param)
return r, phi, rcosphi, rsinphiaxis=0 averages over oscillators, so the same function also works on the 2D array sol.y and returns \(r(t)\).
def kuramoto_order_parameter(theta: np.ndarray) -> tuple:
order_param = np.mean(np.exp(1j * theta), axis=0)
r = np.abs(order_param)
phi = np.angle(order_param)
rcosphi = np.real(order_param)
rsinphi = np.imag(order_param)
return r, phi, rcosphi, rsinphiSliders
Use sliders to update the coupling strength, number of oscillators, and the distribution scale. The template creates the three sliders, slider_coupling, slider_num_oscillators and slider_sigma, inside run_simulation().
Write the callback update_sliders() that reads the slider values, updates the parameters and reinitializes the oscillators. Then attach it to the three sliders.
def update_sliders(_):
# TODO: declare the outer variables you change as nonlocal
# TODO: read the new values from the sliders
# TODO: reinitialize theta and omega
# TODO: attach update_sliders to each slider with on_changed()The callback is defined inside run_simulation(), so you need nonlocal (not global) to change its variables. The number of oscillators must be an integer: use int(slider_num_oscillators.val).
def update_sliders(_):
nonlocal coupling_strength, num_oscillators, sigma, theta, omega
coupling_strength = slider_coupling.val
num_oscillators = int(slider_num_oscillators.val)
sigma = slider_sigma.val
theta, omega = initialize_oscillators(num_oscillators, sigma=sigma)
slider_coupling.on_changed(update_sliders)
slider_num_oscillators.on_changed(update_sliders)
slider_sigma.on_changed(update_sliders)A complete version, which also pauses the animation while the parameters change and restarts the simulation when you press a key, is in amlab/odes_coupled/kuramoto.py. Run it with python amlab/odes_coupled/kuramoto.py.
When you finish, run the full simulation and explore how synchronization changes as you vary \(K\). A good test: set \(K\) just below and just above \(K_c\) and watch how long \(r(t)\) takes to settle.