|
| 1 | +# ------------------------------------------------------------------------- |
| 2 | +# Sparse Identification of Nonlinear Dynamics (SINDy) |
| 3 | +# ------------------------------------------------------------------------- |
| 4 | +# |
| 5 | +# This script applies the SINDy method of Proctor, Brunton, & Kutz (PNAS, |
| 6 | +# 2016) to data collected from the Lorenz or Rossler chaotic systems. The |
| 7 | +# script is broken into three parts: using a quadratic library, a cubic |
| 8 | +# library, and then using the weak/integral SINDy formulation with a |
| 9 | +# quadratic library. |
| 10 | +# |
| 11 | +# This script accompanies Section 3.1 of Data-Driven Methods for |
| 12 | +# Dynamic Systems. |
| 13 | +# |
| 14 | +# To reproduce the noisy computations in the book load LorenzNoise.mat to |
| 15 | +# get the noisy Lorenz data. |
| 16 | +# |
| 17 | +# This script was adapted from the MATLAB version by Jason J. Bramburger |
| 18 | +# |
| 19 | +# Author: Mohit Sahu |
| 20 | +# ------------------------------------------------------------------------- |
| 21 | + |
| 22 | +using DifferentialEquations, Plots, LinearAlgebra |
| 23 | + |
| 24 | +function lorenz!(du, u, p, t) |
| 25 | + x, y, z = u |
| 26 | + σ, ρ, β = p |
| 27 | + du[1] = dx = σ * (y - x) |
| 28 | + du[2] = dy = x * (ρ - z) - y |
| 29 | + du[3] = dz = x * y - β * z |
| 30 | +end |
| 31 | + |
| 32 | +function Rossler!(du, u, p, t) |
| 33 | + x,y,z = u |
| 34 | + a,b,c = p |
| 35 | + du[1] = -y -z; |
| 36 | + du[2] = x + a * y; |
| 37 | + du[3] = b + z * (x - c) |
| 38 | +end |
| 39 | + |
| 40 | +# Simulating Lorenz system |
| 41 | +dt = 0.0001; |
| 42 | +tspan = (0.0, 100.0) |
| 43 | +σ = 10.0; |
| 44 | +β = 8/3; |
| 45 | +ρ = 28.0; |
| 46 | +p = [σ, ρ, β] |
| 47 | +u0 = [1.0; 2.0; ρ-1] |
| 48 | + |
| 49 | +prob = ODEProblem(lorenz!, u0, tspan,p) |
| 50 | + |
| 51 | +# simulating Rossler system |
| 52 | +# a = 0.1; |
| 53 | +# b = 0.1; |
| 54 | +# c = 18; |
| 55 | +# p = [a,b,c] |
| 56 | +# u0 = [0 -15 0]; |
| 57 | + |
| 58 | +# prob = ODEProblem(Rossler!, u0, tspan,p) |
| 59 | + |
| 60 | +xsol = solve(prob, abstol=1e-12, reltol=1e-12, saveat=dt) |
| 61 | + |
| 62 | +# Add noise |
| 63 | +var = 0.0; # noise variance |
| 64 | +xsol .= xsol .+ sqrt(var)*randn(size(xsol)); |
| 65 | + |
| 66 | +# or directly read the file from saved noisy data to reproduce the text |
| 67 | +using MAT |
| 68 | +file = matopen("D:/Study/Intelligence And Learning/PIM/Learning/My Code/DataDrivenDynSyst-main/Identifying Nonlinear Dynamics/LorenzNoise.mat") |
| 69 | +xsol = read(file, "xsol") |
| 70 | +close(file) |
| 71 | + |
| 72 | +# plot(xsol[1,:], xsol[2,:], xsol[3,:]) # do this if loaded from LorenzNoise.mat file |
| 73 | +plot(xsol, idxs=(1,2,3)) |
| 74 | + |
| 75 | +# Estimated Derivatives |
| 76 | +dxdt = (xsol[:,2:end] .- xsol[:,1:end-1]) ./ dt; # Y matrix |
| 77 | +x = xsol[:,1:end-1]; #X matrix |
| 78 | + |
| 79 | +Θ = ones(10,length(x[1,:])); # constant term |
| 80 | +Θ[2:4,:] .= x; #linear term |
| 81 | +Θ[5,:] = x[1,:].^2; # x^2 term |
| 82 | +Θ[6,:] = x[1,:].*x[2,:]; # xy term |
| 83 | +Θ[7,:] = x[1,:].*x[3,:]; # xz term |
| 84 | +Θ[8,:] = x[2,:].^2; # y^2 term |
| 85 | +Θ[9,:] = x[2,:].*x[3,:]; # yz term |
| 86 | +Θ[10,:] = x[3,:].^2; # z^2 term |
| 87 | + |
| 88 | +dxdt = reshape(dxdt, (3,size(dxdt)[2])) # to change dxdt from vector to matrix |
| 89 | + |
| 90 | +function sindy(dxdt, Θ, lam) |
| 91 | + Xi = dxdt * pinv(Θ); |
| 92 | + |
| 93 | + k=1; |
| 94 | + Xi_new = Xi; |
| 95 | + |
| 96 | + while sum(abs.(Xi - Xi_new)) > 0 || k == 1 |
| 97 | + |
| 98 | + Xi = deepcopy(Xi_new); |
| 99 | + |
| 100 | + # loop over all 3 variables |
| 101 | + for ind=1:3 |
| 102 | + # find all the big indexes, means they should be above some threshold |
| 103 | + biginds = findall(x-> abs(x) > lam, Xi[ind,:]) |
| 104 | + smallinds = setdiff(1:length(Xi[ind,:]), biginds) |
| 105 | + |
| 106 | + Xi_new[ind,smallinds] .= 0.0; |
| 107 | + |
| 108 | + # Find coefficients for reduced library |
| 109 | + Xi_new[ind, biginds] = reshape(dxdt[ind,:],(1, length(dxdt[ind,:]))) * pinv(Θ[biginds, :]) |
| 110 | + end |
| 111 | + |
| 112 | + k+=1; |
| 113 | + |
| 114 | + end |
| 115 | + |
| 116 | + return Xi_new |
| 117 | +end |
| 118 | + |
| 119 | +# Printing the model |
| 120 | +Xi_new = sindy(dxdt, Θ, 1e-1) |
| 121 | +mons2 = ["" "x" "y" "z" "x^2" "xy" "xz" "y^2" "yz" "z^2"] |
| 122 | + |
| 123 | +function print_model(Xi_new, mons,print_f=["dx/dt", "dy/dt", "dz/dt"]) |
| 124 | + println("Discovered Model using SINDy: ") |
| 125 | + for ind = 1:3 |
| 126 | + println(print_f[ind] * " = ") |
| 127 | + bigcoeffs = abs.(Xi_new[ind,:]) .> 1e-3; # chosen small just to weed out zero coefficients |
| 128 | + for jnd = eachindex(bigcoeffs) |
| 129 | + if bigcoeffs[jnd] == 1 |
| 130 | + # Print the model by excluding zeroed out terms |
| 131 | + if Xi_new[ind,jnd] < 0 |
| 132 | + print("-" * string(round(abs.(Xi_new[ind, jnd]), digits=4),mons[jnd])) |
| 133 | + #print('- %s ', strcat(Xi_new[ind,jnd],mons[jnd])); |
| 134 | + else |
| 135 | + print("+"*string(round(abs.(Xi_new[ind,jnd]), digits=4),mons[jnd])) |
| 136 | + # print('+ %s', strcat(Xi_new[ind,jnd],mons[jnd])); |
| 137 | + end |
| 138 | + |
| 139 | + end |
| 140 | + end |
| 141 | + print("\n") |
| 142 | + end |
| 143 | +end |
| 144 | +print_model(Xi_new, mons2) |
| 145 | + |
| 146 | + |
| 147 | +# Adding cubic terms to the library |
| 148 | +Θ = [Θ; x[1,:]'.^3]; # x^3 term |
| 149 | +Θ = [Θ; x[1,:]'.*x[1,:]'.*x[2,:]']; # xxy term |
| 150 | +Θ = [Θ; x[1,:]'.*x[2,:]'.*x[2,:]']; # xyy term |
| 151 | +Θ = [Θ; x[1,:]'.*x[2,:]'.*x[3,:]']; # xyz term |
| 152 | +Θ = [Θ; x[1,:]'.*x[3,:]'.*x[3,:]']; # xzz term |
| 153 | +Θ = [Θ; x[2,:]'.*x[2,:]'.*x[2,:]']; # y^3 term |
| 154 | +Θ = [Θ; x[2,:]'.*x[2,:]'.*x[3,:]']; # yyz term |
| 155 | +Θ = [Θ; x[2,:]'.*x[3,:]'.*x[3,:]']; # yzz term |
| 156 | +Θ = [Θ; x[3,:]'.*x[3,:]'.*x[3,:]']; # z^3 term |
| 157 | + |
| 158 | +Xi_new = sindy(dxdt, Θ, 1e-1) |
| 159 | +mons3 = ["" "x" "y" "z" "x^2" "xy" "xz" "y^2" "yz" "z^2" "x^3" "x^2y" "xy^2" "xyz" "xz^2" "y^3" "y^2z" "yz^2" "z^3"]; |
| 160 | +print_model(Xi_new, mons3) |
| 161 | + |
| 162 | +# Now using Integrals instead of derivatives to counter noise |
| 163 | +x = xsol[:,1:end] |
| 164 | +Y = xsol[:, 2:end] .- xsol[:,1] |
| 165 | +∫Θ = zeros(size(Θ[1:10,:])); # Just keep quadratic terms |
| 166 | + |
| 167 | +# Intialize ThetaInt |
| 168 | +∫Θ[:,1] = dt .* Θ[1:10,1]; |
| 169 | + |
| 170 | +for n = 2:length(Θ[1,:]) |
| 171 | + ∫Θ[:,n] = ∫Θ[:,n-1] + dt * Θ[1:10, n]; |
| 172 | +end |
| 173 | + |
| 174 | +Xi_new = sindy(Y, ∫Θ,1e-1) |
| 175 | +print_model(Xi_new, mons2) |
0 commit comments