"""This example shows how you can parallelize ODE integration of a generated ODE function using joblib. The example shows how you can both evaluate the right hand side function and integrate the equations of motion with different model parameters while spreading the independent computations over the number of CPUs on the computer. For example, this could be useful in genetic algorithm optimization routines to parallelize the evaluation of the cost function at each iteration.""" import numpy as np from scipy.integrate import odeint from joblib import Parallel, delayed from pydy.models import n_link_pendulum_on_cart print('Generating equations of motion') sys = n_link_pendulum_on_cart(10, False, False) print('Defining numerical values') x = np.random.random(len(sys.states)) t = np.linspace(0.0, 10.0, 100000) p_set = np.random.random((16, len(sys.constants_symbols))) print('Generating the ODE function') rhs = sys.generate_ode_function(generator='cython') print('Defining wrapper functions') # These two wrapper functions seem to be required for things to pickle in # Joblib and I'm not sure why. This is not the case if the rhs function was # defined as a normal Python function instead of being generated with # lambdify or cython.
import os import time import sys sys.path = ["../sympy", "../pydy", "../symengine.py"] + sys.path import sympy import symengine import pydy from pydy.models import n_link_pendulum_on_cart print(sympy.__file__) print(symengine.__file__) print(pydy.__file__) if (len(sys.argv) > 1): n = int(sys.argv[1]) else: n = 4 start = time.time() sys = n_link_pendulum_on_cart(n, cart_force=False) end = time.time() print("%s s" % (end-start)) #print(sys.eom_method.mass_matrix)
def run_benchmark(max_num_links, num_time_steps=1000): """Runs the n link pendulum derivation, code generation, and integration for each n up to the max number provided and generates a plot of the results.""" methods = ['lambdify', 'theano', 'cython'] link_numbers = range(1, max_num_links + 1) derivation_times = zeros(len(link_numbers)) integration_times = zeros((max_num_links, len(methods))) code_generation_times = zeros_like(integration_times) for j, n in enumerate(link_numbers): title = "Pendulum with {} links.".format(n) print(title) print('=' * len(title)) start = time.time() sys = n_link_pendulum_on_cart(n, cart_force=False) m = symbols('m:{}'.format(n + 1)) l = symbols('l:{}'.format(n)) g = symbols('g') derivation_times[j] = time.time() - start print('The derivation took {:1.5f} seconds.\n'.format(derivation_times[j])) # Define the numerical values: parameters, time, and initial conditions arm_length = 1. / n bob_mass = 0.01 / n parameter_vals = [9.81, 0.01 / n] for i in range(n): parameter_vals += [arm_length, bob_mass] times = linspace(0, 10, num_time_steps) sys.times = times x0 = hstack( (0, pi / 2 * ones(len(sys.coordinates) - 1), 1e-3 * ones(len(sys.speeds)))) sys.initial_conditions = dict(zip(sys.states, x0)) constants = [g, m[0]] for i in range(n): constants += [l[i], m[i + 1]] sys.constants = dict(zip(constants, array(parameter_vals))) for k, method in enumerate(methods): subtitle = "Generating with {} method.".format(method) print(subtitle) print('-' * len(subtitle)) start = time.time() sys.generate_ode_function(generator=method) code_generation_times[j, k] = time.time() - start print('The code generation took {:1.5f} seconds.'.format( code_generation_times[j, k])) start = time.time() sys.integrate() integration_times[j, k] = time.time() - start print('ODE integration took {:1.5f} seconds.\n'.format( integration_times[j, k])) del sys # plot the results fig, ax = plt.subplots(3, 1, sharex=True) ax[0].plot(link_numbers, derivation_times) ax[0].set_title('Symbolic Derivation Time') ax[1].plot(link_numbers, code_generation_times) ax[1].set_title('Code Generation Time') ax[1].legend(methods, loc=2) ax[2].plot(link_numbers, integration_times) ax[2].set_title('Integration Time') ax[2].legend(methods, loc=2) for a in ax.flatten(): a.set_ylabel('Time [s]') ax[-1].set_xlabel('Number of links') plt.tight_layout() fig.savefig('benchmark-results.png')
The script outputs the average time taken to numerically evaluate the right hand side of the first order differential equation for each of the 12 permutations. """ import timeit import numpy as np import sympy as sm from pydy import models from pydy.codegen.ode_function_generators import LambdifyODEFunctionGenerator sys = models.n_link_pendulum_on_cart(3, True, True) right_hand_side = sys.eom_method.rhs() constants = list(sm.ordered(sys.constants_symbols)) specifieds = list(sm.ordered(sys.specifieds_symbols)) constants_arg_types = ['array', 'dictionary'] specifieds_arg_types = ['array', 'function', 'dictionary'] p_array = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]) p_dct = dict(zip(constants, p_array)) p = {}
def run_benchmark(max_num_links, num_time_steps=1000): """Runs the n link pendulum derivation, code generation, and integration for each n up to the max number provided and generates a plot of the results.""" methods = ['lambdify', 'theano', 'cython'] link_numbers = range(1, max_num_links + 1) derivation_times = zeros(len(link_numbers)) integration_times = zeros((max_num_links, len(methods))) code_generation_times = zeros_like(integration_times) for j, n in enumerate(link_numbers): title = "Pendulum with {} links.".format(n) print(title) print('=' * len(title)) start = time.time() sys = n_link_pendulum_on_cart(n, cart_force=False) derivation_times[j] = time.time() - start print('The derivation took {:1.5f} seconds.\n'.format(derivation_times[j])) # Define the numerical values: parameters, time, and initial conditions arm_length = 1. / n bob_mass = 0.01 / n parameter_vals = [9.81, 0.01 / n] for i in range(n): parameter_vals += [arm_length, bob_mass] # odeint arguments x0 = hstack((0, pi / 2 * ones(len(results[3]) - 1), 1e-3 * ones(len(results[4])))) args = {'constants': dict(zip(results[2], array(parameter_vals)))} t = linspace(0, 10, num_time_steps) for k, method in enumerate(methods): subtitle = "Generating with {} method.".format(method) print(subtitle) print('-' * len(subtitle)) start = time.time() evaluate_ode = generate_ode_function(*results, generator=method) code_generation_times[j, k] = time.time() - start print('The code generation took {:1.5f} seconds.'.format( code_generation_times[j, k])) start = time.time() odeint(evaluate_ode, x0, t, args=(args,)) integration_times[j, k] = time.time() - start print('ODE integration took {:1.5f} seconds.\n'.format( integration_times[j, k])) del results, evaluate_ode # clean up the cython crud files = glob.glob('multibody_system*') for f in files: os.remove(f) shutil.rmtree('build') # plot the results fig, ax = plt.subplots(3, 1, sharex=True) ax[0].plot(link_numbers, derivation_times) ax[0].set_title('Symbolic Derivation Time') ax[1].plot(link_numbers, code_generation_times) ax[1].set_title('Code Generation Time') ax[1].legend(methods, loc=2) ax[2].plot(link_numbers, integration_times) ax[2].set_title('Integration Time') ax[2].legend(methods, loc=2) for a in ax.flatten(): a.set_ylabel('Time [s]') ax[-1].set_xlabel('Number of links') plt.tight_layout() fig.savefig('benchmark-results.png')