def est_lyapunov(kf, noise_level): # T = 1 T = 10 x0 = 0.05 z0 = 9.0 v0 = 0.85 tol = 1e-8 diff = 1e-10 dt = 0.002 nbr_itr = math.floor(T / dt) lyapunov = 0 u = np.array([x0, z0, v0]) v = np.array([x0 + diff, z0, v0]) for i in range(0, nbr_itr): flow_diff = np.random.normal(loc=0, scale=noise_level) gf = GyorgyiFieldModel(kf + kf * flow_diff) solver = DOP853(gf.rhs, 0, u, dt, atol=tol, rtol=tol) while solver.status == "running": solver.step() u = solver.y solver = DOP853(gf.rhs, 0, v, dt, atol=tol, rtol=tol) while solver.status == "running": solver.step() v = solver.y delta = v - u d = np.linalg.norm(delta) if i >= 200: lyapunov += np.log(d / diff) v = u + diff * delta / d lyapunov = lyapunov / (dt * (nbr_itr - 200)) return lyapunov
def reset(self): if self.has_integrator: if self.integrator_type == Integrators.lsoda: self.integrator = LSODA(self.dydt, self.t0, self.dydt_y0, np.inf, max_step=self.dydt_max_step, **self.dydt_solver_args) elif self.integrator_type == Integrators.dop853: self.integrator = DOP853(lambda t, y: self.dydt_y0, self.t0, self.dydt_y0, np.inf, max_step=self.dydt_max_step, **self.dydt_solver_args) self.integrator.fun = self.dydt elif self.integrator_type == Integrators.rk45: self.integrator = RK45(lambda t, y: self.dydt_y0, self.t0, self.dydt_y0, np.inf, max_step=self.dydt_max_step, **self.dydt_solver_args) self.integrator.fun = self.dydt elif self.integrator_type == Integrators.implicit_midpoint: self.integrator = ImplicitMidpoint(self.dydt, self.t0, self.dydt_y0, np.inf, max_step=self.dydt_max_step, **self.dydt_solver_args) else: raise ValueError( f'Unsupported integrator type: {self.integrator_type}') for sys in self.systems[IterationMode.cvx] + self.systems[ IterationMode.map]: sys.reset() self.discrete_y[sys.uuid] = sys._y.copy() for sys in self.systems[IterationMode.traj]: sys.reset()
def auto_test_Lorenz63(dt, N, lam, deriv, initial_state, lib_combos, nnoise=0, vis=False): t0 = 0 t_bound = dt * N solver_obj = DOP853(Lorenz63, t0, initial_state, t_bound, max_step=dt, first_step=dt) X = np.zeros((N + 1, 3)) X[0] = initial_state #compute output for i in range(N): solver_obj.step() X[i + 1] = solver_obj.y X_dot = np.zeros((N + 1, 3)) for i in range(3): X_dot[:, i] = deriv(X[:, i], dt) sdsX = np.std(X) sdsXdot = np.std(X_dot) X_n = X + nnoise * sdsX * np.random.randn(N + 1, 3) X_dot_n = X_dot + nnoise * sdsXdot * np.random.randn(N + 1, 3) Theta = gen_Theta(lib_combos, N, X_n) Xi = xlstsq(Theta, X_dot_n) Xi = STLS(lam, Xi, X_dot_n, Theta) #print(Xi) (fx, fy, fz) = ret_eq(lib_combos, Xi) print_eq(lib_combos, Xi) def Lorenz_Reco(t, vals): x, y, z = vals[0], vals[1], vals[2] return [fx(x, y, z), fy(x, y, z), fz(x, y, z)] t0 = 0 t_bound = dt * N #create solver object solver_obj_reco = DOP853(Lorenz_Reco, t0, initial_state, t_bound, max_step=dt, first_step=dt) #set up data matrix X_reco = np.zeros((N + 1, 3)) X_reco[0] = initial_state #compute output for i in range(N): solver_obj_reco.step() X_reco[i + 1] = solver_obj_reco.y if solver_obj_reco.status != 'running': break #transient and error time trans = int(2 / dt) end_t = int(10 / dt) + trans + 1 errors = np.mean(np.abs(X[trans:end_t, :] - X_reco[trans:end_t, :]), axis=0) #plots if vis: # this is whats used to generate the reconstructed trajectory and attractor plots # uncomment as required etc. # num_dim = 1 # #time series # times = np.arange(0,dt*N+dt,dt) # t**s = ['x','y','z'] # for i in range(num_dim): # plt.subplot(3,1,i+1) # plt.plot(times[trans:end_t], X[trans:end_t,i],'k', lw = 2, label = 'true TS') # plt.plot(times[trans:end_t], X_reco[trans:end_t,i],'--r', lw = 1, label = 'reco TS') # plt.xlabel('time') # plt.legend(loc='best') # plt.ylabel(t**s[i]) # plt.show() # or attractor plt.rcParams["figure.figsize"] = (12, 12) plt.rcParams.update({'font.size': 16}) fig = plt.figure() ax = plt.axes(projection='3d') ax.plot3D(X_reco[:, 0], X_reco[:, 1], X_reco[:, 2], lw=0.4, label='Traj 1') ax.plot3D(initial_state[0], initial_state[1], initial_state[2], '*', label='IC 1') ax.set(xlabel='x', ylabel='y', zlabel='z') ax.legend(loc='best') plt.show() return np.mean(errors)
plt.plot(tests, fd_der, label='Finite Diff', lw=3) plt.plot(tests, testsder, label='Analytical') plt.xlabel('x') plt.ylabel('y') plt.legend(loc='best') #%% # Butterfly attractor plot (with two trajectories) dt = 0.02 N = 10000 initial_state = [2, 10, 5] initial_state_2 = [2.05, 9.95, 5.05] t0 = 0 t_bound = dt * N solver_obj = DOP853(Lorenz63, t0, initial_state, t_bound, max_step=dt, first_step=dt) solver_obj_2 = DOP853(Lorenz63, t0, initial_state_2, t_bound, max_step=dt, first_step=dt) #set up data matrix X = np.zeros((N + 1, 3)) X[0] = initial_state #compute output for i in range(N): solver_obj.step() X[i + 1] = solver_obj.y
def __init__(self, *systems: Tuple[fds]): assert len(systems) >= 1, 'Pass one or more systems to couple' assert all([sys.t == 0. for sys in systems ]), 'All systems must be at zero-time initial conditions.' assert all([sys.iter_mode != IterationMode.none for sys in systems ]), 'All systems must have evolution laws.' self.t0 = 0. for sys in systems: sys.uuid = shortuuid.uuid() # Hacky.. self.systems = { IterationMode.dydt: list( filter(lambda sys: sys.iter_mode is IterationMode.dydt, systems)), IterationMode.cvx: list( filter(lambda sys: sys.iter_mode is IterationMode.cvx, systems)), IterationMode.map: list( filter(lambda sys: sys.iter_mode is IterationMode.map, systems)), IterationMode.traj: list( filter(lambda sys: sys.iter_mode is IterationMode.traj, systems)), } # Common state for discrete systems self.discrete_t = self.t0 self.discrete_y = { sys.uuid: sys.y0 for sys in self.systems[IterationMode.cvx] + self.systems[IterationMode.map] } # Common state for continuous systems self.has_integrator = len(self.systems[IterationMode.dydt]) > 0 if self.has_integrator: self.integrator_type = self.systems[ IterationMode.dydt][0].integrator_type assert all([ sys.integrator_type is self.integrator_type for sys in self.systems[IterationMode.dydt] ]), 'All continuous dynamics must use the same integrator.' dydt_systems = self.systems[IterationMode.dydt] self.dydt_max_step = min([sys.max_step for sys in dydt_systems]) self.dydt_solver_args = merge_dicts( [sys.solver_args for sys in dydt_systems]) self.dydt_y0 = np.concatenate( [sys.y0 for sys in self.systems[IterationMode.dydt]]) if self.integrator_type == Integrators.lsoda: self.integrator = LSODA(self.dydt, self.t0, self.dydt_y0, np.inf, max_step=self.dydt_max_step, **self.dydt_solver_args) elif self.integrator_type == Integrators.dop853: self.integrator = DOP853(lambda t, y: self.dydt_y0, self.t0, self.dydt_y0, np.inf, max_step=self.dydt_max_step, **self.dydt_solver_args) self.integrator.fun = self.dydt elif self.integrator_type == Integrators.rk45: self.integrator = RK45(lambda t, y: self.dydt_y0, self.t0, self.dydt_y0, np.inf, max_step=self.dydt_max_step, **self.dydt_solver_args) self.integrator.fun = self.dydt elif self.integrator_type == Integrators.implicit_midpoint: self.integrator = ImplicitMidpoint(self.dydt, self.t0, self.dydt_y0, np.inf, max_step=self.dydt_max_step, **self.dydt_solver_args) else: raise ValueError( f'Unsupported integrator type: {self.integrator_type}') # Attach views to state last_index = 0 for sys in self.systems[IterationMode.dydt]: sys.view = slice(last_index, last_index + sys.y0.size) attach_dyn_props( sys, { 'y': lambda sys: self.integrator.y[sys.view], 't': lambda _: self.t }) last_index += sys.y0.size for sys in self.systems[IterationMode.cvx]: attach_dyn_props(sys, { 'y': lambda sys: self.discrete_y[sys.uuid], 't': lambda _: self.t }) for sys in self.systems[IterationMode.map]: attach_dyn_props(sys, { 'y': lambda sys: self.discrete_y[sys.uuid], 't': lambda _: self.t })
def set_evolution( self, dydt: Callable[[Time, np.ndarray], np.ndarray] = None, order: int = 1, max_step: float = 1e-3, integrator=Integrators.lsoda, solver_args: Dict = {}, lhs: Callable[[Time, np.ndarray], np.ndarray] = None, cost: Callable[[Time, np.ndarray], float] = None, refresh_cvx: float = True, map_fun: Callable[[Time, np.ndarray], np.ndarray] = None, dt: float = 1.0, traj_t: Iterable[Time] = None, traj_y: Iterable[np.ndarray] = None, nil: bool = False, ): ''' Define evolution law for the dynamics. Option 1: As a PDE dydt: Callable[Time] RHS of differential equation [uses LSODA for stiffness detection; falls back to DOP853 if not available] order: int [optional] Order of time-difference; if greater than one, automatically creates (order*ndim) state vector max_step: float [optional] Maximum allowed step size in the solver; default 1e-3 solver_args: Dict [optional] Additional arguments to be passed to the solver Option 2: As a convex program lhs: Callable[Time] RHS of an equation set to 0 cost: Callable[time] RHS of a disciplined-convex cost function (either array-like or scalar) solver_args: Dict [optional] Additional arguments to be passed to the solver refresh_cvx: bool (TODO) whether the problem is time-dependent. Option 3: As a recurrence relation map_fun: Callable[time] RHS of recurrence relation dt: float [default 1.0] time delta for stepping Option 4: As a data-derived trajectory traj_t: Iterable[Time] traj_y: Iterable[np.ndarray] Option 5: As a nil-evolution (time-invariant system) nil: bool ''' assert oneof([ dydt != None, lhs != None, cost != None, map_fun != None, traj_t != None, nil ]), 'Exactly one evolution law must be specified' if dydt != None: self.iter_mode = IterationMode.dydt self.dydt_fun = dydt self.max_step = max_step self._dt = self.max_step self.order = order self.solver_args = solver_args self.y0 = np.zeros(self.ndim * order) self.integrator_type = integrator if self.integrator_type == Integrators.lsoda: self.integrator = LSODA(self.dydt, self.t0, self.y0, np.inf, max_step=max_step, **solver_args) elif self.integrator_type == Integrators.dop853: self.integrator = DOP853(lambda t, y: self.y0, self.t0, self.y0, np.inf, max_step=max_step, **solver_args) self.integrator.fun = self.dydt elif self.integrator_type == Integrators.rk45: self.integrator = RK45(lambda t, y: self.y0, self.t0, self.y0, np.inf, max_step=max_step, **solver_args) self.integrator.fun = self.dydt elif self.integrator_type == Integrators.implicit_midpoint: self.integrator = ImplicitMidpoint(self.dydt, self.t0, self.y0, np.inf, max_step=max_step, **solver_args) else: raise ValueError( f'Unsupported integrator type: {self.integrator_type}') elif lhs != None or cost != None: if lhs != None: cost = lambda t, y: cp.sum_squares(lhs(t, y)) self.iter_mode = IterationMode.cvx self.cost_fun = cost self.solver_args = solver_args self.refresh_cvx = refresh_cvx self.initialized = False self.y0 = np.zeros(self.ndim) self._t = self.t0 self._y = self.y0.copy() self._t_prb = cp.Parameter(nonneg=True) self._y_prb = cp.Variable(self._y.size) _cost = cost(self._t_prb, self._y_prb) assert _cost.shape == (), 'Cost is not scalar' assert _cost.is_dcp(), 'Problem is not disciplined-convex' self._prb = cp.Problem(cp.Minimize(_cost), []) elif map_fun != None: self.iter_mode = IterationMode.map self.map_fun = map_fun self.y0 = np.zeros(self.ndim) self._dt = dt self._t = self.t0 self._n = self._t self._y = self.t0.copy() elif traj_t != None: assert traj_t[0] == self.t0, 'Ensure trajectory starts at t=0' self.iter_mode = IterationMode.traj self.traj_t, self.traj_y = traj_t, traj_y self._t = self.t0 self._i = 0 elif nil: self.iter_mode = IterationMode.nil self._t = 0 self._y = np.zeros(self.ndim) self.y0 = np.zeros(self.ndim)
noise_level = 0.1 dt = 0.0002 n_itr = math.floor(T / dt) sol_x = [0] * n_itr sol_z = [0] * n_itr sol_v = [0] * n_itr for i in range(0, n_itr): flow_diff = np.random.normal(loc=0, scale=noise_level) gf = GyorgyiFieldModel(kf + kf * flow_diff) solver = DOP853(gf.rhs, 0, np.array([x0, z0, v0]), dt, atol=tol, rtol=tol) while solver.status == "running": solver.step() x0 = solver.y[0] z0 = solver.y[1] v0 = solver.y[2] sol_x[i] = solver.y[0] sol_z[i] = solver.y[1] sol_v[i] = solver.y[2] fig = plt.figure() ax = plt.axes(projection="3d") ax.plot( np.log10(np.abs(sol_x)),
x, y, z = vals[0], vals[1], vals[2] return [10 * (y - x), 28 * x - y - x * z, -8 / 3 * z + x * y] #%% #set up initial conditions dt = 0.02 N = 10000 initial_state = [2, 10, 5] t0 = 0 t_bound = dt * N #create solver object solver_obj = DOP853(Lorenz63, t0, initial_state, t_bound, max_step=dt, first_step=dt) #set up data matrix X = np.zeros((N + 1, 3)) X[0] = initial_state #%% #compute output for i in range(N): solver_obj.step() X[i + 1] = solver_obj.y #%% initial_state_2 = [2.05, 9.95, 5.05] t0 = 0 t_bound = dt * N