def test_R18(const): def odefun(X, u, p, const): return -X[0] / const[0] def quadfun(X, u, p, const): return X[0] def bcfun(X0, q0, u0, Xf, qf, uf, p, ndp, const): return q0[0] - 1, qf[0] - np.exp(-1 / const[0]) algo = Shooting(odefun, quadfun, bcfun) solinit = Trajectory() solinit.t = np.linspace(0, 1, 2) solinit.y = np.array([[1], [1]]) solinit.q = np.array([[0], [0]]) solinit.const = np.array([const]) sol = algo.solve(solinit)['sol'] e1 = np.exp(-sol.t / sol.const[0]) e2 = -1 / (sol.const[0] * np.exp(sol.t / sol.const[0])) assert all(e1 - sol.q[:, 0] < tol) assert all(e2 - sol.y[:, 0] < tol)
def test_Shooting_4(): # This problem contains a quad and tests if the bvp solver correctly # integrates the quadfun. Also tests multiple shooting. def odefun(x, u, p, const): return -x[1], x[0] def quadfun(x, u, p, const): return x[0] def bcfun(X0, q0, u0, Xf, qf, uf, params, ndp, const): return X0[0], X0[1] - 1, qf[0] - 1.0 algo = Shooting(odefun, quadfun, bcfun, num_arcs=4) solinit = Trajectory() solinit.t = np.linspace(0, np.pi / 2, 2) solinit.y = np.array([[1, 0], [1, 0]]) solinit.q = np.array([[0], [0]]) solinit.const = np.array([]) out = algo.solve(solinit)['sol'] assert (out.y[0, 0] - 0) < tol assert (out.y[0, 1] - 1) < tol assert (out.q[0, 0] - 2) < tol assert (out.q[-1, 0] - 1) < tol
def test_R8(const): def odefun(X, u, p, const): return -X[0] / const[0] def quadfun(X, u, p, const): return X[0] def bcfun(X0, q0, u0, Xf, qf, uf, p, ndp, const): return q0[0] - 1, qf[0] - 2 algo = Shooting(odefun, quadfun, bcfun) solinit = Trajectory() solinit.t = np.linspace(0, 1, 2) solinit.y = np.array([[1], [1]]) solinit.q = np.array([[0], [0]]) solinit.const = np.array([const]) sol = algo.solve(solinit)['sol'] e1 = (1.e0 - np.exp( (sol.t - 1.e0) / sol.const)) / (1.e0 - np.exp(-1.e0 / sol.const)) e2 = np.exp((sol.t - 1) / sol.const) / (sol.const * (1 / np.exp(1 / sol.const) - 1)) assert all(e1 - sol.q[:, 0] < tol) assert all(e2 - sol.y[:, 0] < tol)
def solve(self, solinit, **kwargs): solinit = copy.deepcopy(solinit) nstates = solinit.y.shape[1] def return_nil(*args, **kwargs): return np.array([]) if solinit.q.size > 0: nquads = solinit.q.shape[1] else: nquads = 0 self.quadrature_function = return_nil ndyn = solinit.dynamical_parameters.size nnondyn = solinit.nondynamical_parameters.size def _fun(t, y, params=np.array([]), const=solinit.const): y = y.T o1 = np.vstack([ self.derivative_function(yi[:nstates], np.array([]), params[:ndyn], const) for yi in y ]) o2 = np.vstack([ self.quadrature_function(yi[:nstates], np.array([]), params[:ndyn], const) for yi in y ]) return np.hstack((o1, o2)).T # TODO: The way parameters are used is inconsitent def _bc(ya, yb, params=np.array([]), const=solinit.const): return self.boundarycondition_function( ya[:nstates], ya[nstates:nstates + nquads], np.array( ()), yb[:nstates], yb[nstates:nstates + nquads], np.array(()), params[:ndyn], params[ndyn:ndyn + nnondyn], const) if self.derivative_function_jac is not None: def _fun_jac(t, y, params=np.array([]), const=solinit.const): y = y.T df_dy = np.zeros((y[0].size, y[0].size, t.size)) df_dp = np.zeros((y[0].size, ndyn + nnondyn, t.size)) for ii, yi in enumerate(y): df_dy[:, :, ii], _df_dp = self.derivative_function_jac( yi, np.array([]), params[:ndyn], const) if nstates > 1 and len(_df_dp.shape) == 1: _df_dp = np.array([_df_dp]).T df_dp[:, :, ii] = np.hstack( (_df_dp, np.zeros((nstates, nnondyn)))) if ndyn + nnondyn == 0: return df_dy else: return df_dy, df_dp else: _fun_jac = None if self.boundarycondition_function_jac is not None: def _bc_jac(ya, yb, params=np.array([]), const=solinit.const): dbc_dya, dbc_dyb, dbc_dp = self.boundarycondition_function_jac( ya, yb, np.array([]), params, const) return dbc_dya, dbc_dyb, dbc_dp else: _bc_jac = None if nquads > 0: opt = solve_bvp(_fun, _bc, solinit.t, np.hstack((solinit.y, solinit.q)).T, np.hstack((solinit.dynamical_parameters, solinit.nondynamical_parameters)), max_nodes=self.max_nodes, fun_jac=_fun_jac, bc_jac=_bc_jac) else: opt = solve_bvp(_fun, _bc, solinit.t, solinit.y.T, np.hstack((solinit.dynamical_parameters, solinit.nondynamical_parameters)), max_nodes=self.max_nodes, fun_jac=_fun_jac, bc_jac=_bc_jac) sol = Trajectory(solinit) sol.t = opt['x'] sol.y = opt['y'].T[:, :nstates] sol.q = opt['y'].T[:, nstates:nstates + nquads] sol.dual = np.zeros_like(sol.y) if opt['p'] is not None: sol.dynamical_parameters = opt['p'][:ndyn] sol.nondynamical_parameters = opt['p'][ndyn:ndyn + nnondyn] else: sol.dynamical_parameters = np.array([]) sol.nondynamical_parameters = np.array([]) sol.converged = opt['success'] out = BVPResult(sol=sol, success=opt['success'], message=opt['message'], rms_residuals=opt['rms_residuals'], niter=opt['niter']) return out