dynamicslab / pysindy

A package for the sparse identification of nonlinear dynamical systems from data
https://pysindy.readthedocs.io/en/latest/
Other
1.36k stars 304 forks source link

[Help] Identify PDE by svd #434

Open Junang-Wang opened 7 months ago

Junang-Wang commented 7 months ago

Hi there. I am a beginner for PySindy. I am currently working on identifying a nonlinear partial differential equation (PDE). The state vector x contains 10 physical variables in a 1D spatial grid with 40 discrete points. Since the number of variables is large, I am using singular value decomposition (SVD) to capture the first 6 modes as basis vectors for my new coordinate system. By converting my data to this new basis, I aim to solve the equation. However, when I plot the Pareto curve, I observe that the error decreases as the threshold lambda increases. Moreover, the error becomes significantly large. Does anyone have any suggestions on how to solve these problems?

Thanks in advance.

Junang-Wang commented 7 months ago

The following is my code snapshot:

load data and svd

x = x.transpose([0,2,1]).reshape(n_elemn_var,tsize) # state vectors: origin shape (n_elem, tsize, n_var) shape: n_elemn_var, tsize U, S, V = scipy.linalg.svd(x) u = u[0] # shape tsize, control_features

change to new basis

r = 6 # Truncate the first 6 modes Ur = U[:,:r] # each col is the mode we focused on New_var = (Ur.T @ x).T # shape: (tsize,r) # variables in new basis

train_time = 3000 V_train = New_var[:train_time,:] V_test = New_var[train_time:,:] t_test = tspan[:tsize-train_time] u_train = u[:train_time] u_test = u[:tsize-train_time] poly_order = 5 threshold_scan = np.linspace(0, 100, 10) coefs = []

plot pareto curve

poly_library = ps.PolynomialLibrary(degree=poly_order)

for i, threshold in enumerate(threshold_scan): sparse_regression_optimizer = ps.STLSQ(threshold=threshold,normalize_columns=True) model = ps.SINDy(feature_library=poly_library, optimizer=sparse_regression_optimizer) model.fit(V_train, t=dt, u= u_train, quiet=True) coefs.append(model.coefficients())

plot_pareto(coefs, sparse_regression_optimizer, model, threshold_scan, V_test, t_test, u_test)

image

Jacob-Stevens-Haas commented 7 months ago

The only thing I notice about your code is that, when fitting an SVD, you should just use the right singular vectors. I.e. in $$A = U S V^T$$

You want to fit $V^T$ with SINDy, not $U^T A = S V^T$. This keeps all your variables on the same scale.

I don't know what plot_pareto is doing, so I can't tell what's going wrong. All I can say is that $10^{15}$ is a big number

It generally helps to make sure your code works on a simple, known problem (like the heat equation) if something isn't working with custom data. This identifies if the problem is truly idiosyncratic to your data or just a coding error.

Junang-Wang commented 7 months ago

Hi, @Jacob-Stevens-Haas

Thank you for your prompt response. I appreciate your suggestion to fix the code for a simple and well-known problem. Do you know any good examples, such as papers, codes, or tutorials, that demonstrate the use of SVD and addressing modes with SINDy?I really appreciate for your sharing.

Thank you so much for the help.

Jacob-Stevens-Haas commented 7 months ago

Try the examples folder here. Alternatively, you can simulate a 1D heat equation as an ODE by using the fourier transform. See an example in the tests of this repo

Junang-Wang commented 7 months ago

@Jacob-Stevens-Haas. Thank you so much!