Skip to content

Commit 70a7c21

Browse files
committed
Added example code blocks
1 parent fe49bd9 commit 70a7c21

File tree

3 files changed

+127
-1
lines changed

3 files changed

+127
-1
lines changed

.DS_Store

8 KB
Binary file not shown.

docs/src/examples/pde/boussinesq.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ where $P$ are the physical parameters, $\overline{T}$ is the averaged temperatur
2121

2222
## Generating Data for Training
2323

24-
To train the neural network, we can generate data using the function $\overline{wT} = cos(sin(T^3)) + sin(cos(T^2))$ with $N$ spatial points discretized by a finite difference method, with the time domain $t \in [0,1.5]$ and Neumann zero-flux boundary conditions, meaning $\frac{\partial \overline{T}}{\partial z} = 0$ at the edges.
24+
To train the neural network, we can generate data using the function:
25+
26+
$$\overline{wT} = {cos(sin(T^3)) + sin(cos(T^2))}$$
27+
28+
with $N$ spatial points discretized by a finite difference method, with the time domain $t \in [0,1.5]$ and Neumann zero-flux boundary conditions, meaning $\frac{\partial \overline{T}}{\partial z} = 0$ at the edges.
2529

2630

2731
## Training Neural Network

docs/src/examples/pde/test.jl

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using OrdinaryDiffEq, SciMLSensitivity
2+
using Lux, Optimization, OptimizationOptimisers, ComponentArrays
3+
using Random, Statistics, LinearAlgebra
4+
5+
# ==========================================
6+
# 1. Problem Setup & Data Generation
7+
# ==========================================
8+
const N = 32 # Number of spatial points
9+
const L = 1.0f0 # Length of vertical domain
10+
const dx = L / N # Grid spacing
11+
const κ = 0.01f0 # Thermal diffusivity (kappa)
12+
const tspan = (0.0f0, 1.5f0) # Time domain
13+
14+
# "True" closure term: wT = cos(sin(T^3)) + sin(cos(T^2))
15+
function true_flux_closure(T)
16+
cos(sin(T^3)) + sin(cos(T^2))
17+
end
18+
19+
# Discretized PDE (Method of Lines)
20+
function boussinesq_pde!(du, u, p, t, flux_model)
21+
# Calculate Flux Term (wT)
22+
# flux_model can be the true function or the Neural Network
23+
wT = flux_model(u, p)
24+
25+
# Finite Difference Scheme
26+
# Equation: ∂T/∂t = κ * ∂²T/∂z² - ∂(wT)/∂z
27+
28+
# Interior Points (2 to N-1)
29+
for i in 2:N-1
30+
# Diffusion: Central Difference
31+
diffusion = κ * (u[i+1] - 2u[i] + u[i-1]) / (dx^2)
32+
33+
# Advection/Flux: Central Difference
34+
advection = (wT[i+1] - wT[i-1]) / (2dx)
35+
36+
du[i] = diffusion - advection
37+
end
38+
39+
# Boundary Conditions: Neumann Zero-Flux (∂T/∂z = 0)
40+
# Implies T[0] = T[2] and T[N+1] = T[N-1] (Mirror ghost points)
41+
# At boundaries, if T is flat, wT(T) is flat, so ∂(wT)/∂z = 0
42+
43+
# Left Boundary (z=0)
44+
du[1] = κ * (2(u[2] - u[1])) / (dx^2)
45+
46+
# Right Boundary (z=L)
47+
du[N] = κ * (2(u[N-1] - u[N])) / (dx^2)
48+
end
49+
50+
# Initial Condition: A simple curve (e.g., Gaussian or linear gradient)
51+
u0 = Float32[exp(-(x-0.5)^2 / 0.1) for x in range(0, L, length=N)]
52+
53+
# wrapper for the "True" solver
54+
function pde_true!(du, u, p, t)
55+
# Helper to map function over vector u
56+
wrapper(u_in, p_in) = true_flux_closure.(u_in)
57+
boussinesq_pde!(du, u, p, t, wrapper)
58+
end
59+
60+
# Generate Training Data
61+
prob_true = ODEProblem(pde_true!, u0, tspan)
62+
sol_true = solve(prob_true, Tsit5(), saveat=0.1)
63+
training_data = Array(sol_true)
64+
65+
# ==========================================
66+
# 2. Define the Universal Differential Equation
67+
# ==========================================
68+
# Neural Network to approximate wT = U(T)
69+
# Input: 1 (Temperature), Output: 1 (Flux)
70+
rng = Random.default_rng()
71+
nn = Lux.Chain(
72+
Lux.Dense(1, 8, tanh),
73+
Lux.Dense(8, 8, tanh),
74+
Lux.Dense(8, 1)
75+
)
76+
p_nn, st = Lux.setup(rng, nn)
77+
78+
# Wrapper for NN to fit the pde function signature
79+
function nn_closure(u, p)
80+
# Lux expects (Features, Batch). Reshape u to (1, N)
81+
u_in = reshape(u, 1, :)
82+
pred = nn(u_in, p, st)[1]
83+
return reshape(pred, :) # Return as vector
84+
end
85+
86+
function pde_ude!(du, u, p, t)
87+
boussinesq_pde!(du, u, p, t, nn_closure)
88+
end
89+
90+
prob_ude = ODEProblem(pde_ude!, u0, tspan, p_nn)
91+
92+
# ==========================================
93+
# 3. Training Loop
94+
# ==========================================
95+
function loss(p)
96+
# Solve UDE with current NN parameters
97+
# Use InterpolatingAdjoint for memory efficiency with stiff PDEs
98+
sol_pred = solve(prob_ude, Tsit5(), p=p, saveat=0.1,
99+
sensealg=InterpolatingAdjoint(autojacvec=ReverseDiffVJP(true)))
100+
101+
# Calculate MSE against training data
102+
if sol_pred.retcode != :Success
103+
return Inf
104+
end
105+
return mean(abs2, Array(sol_pred) .- training_data)
106+
end
107+
108+
# Define Optimization Problem
109+
adtype = Optimization.AutoZygote()
110+
optf = Optimization.OptimizationFunction((x, p) -> loss(x), adtype)
111+
optprob = Optimization.OptimizationProblem(optf, ComponentVector(p_nn))
112+
113+
# Training Stage 1: ADAM with lr=1e-2 for 200 iterations
114+
println("Starting Training Phase 1...")
115+
res1 = Optimization.solve(optprob, OptimizationOptimisers.Adam(0.01), maxiters=200)
116+
117+
# Training Stage 2: ADAM with lr=1e-3 for 1000 iterations
118+
println("Starting Training Phase 2...")
119+
optprob2 = Optimization.OptimizationProblem(optf, res1.u)
120+
res2 = Optimization.solve(optprob2, OptimizationOptimisers.Adam(0.001), maxiters=1000)
121+
122+
println("Final Loss: ", loss(res2.u))

0 commit comments

Comments
 (0)