Use your own data
This example builds a dataset from two coordinate arrays and one field array, which is the form most simulation output and most gridded measurements already have. The other examples start from a dataset shipped with KD.
The field below is generated with NumPy to give the example concrete data. Substituting your own arrays requires no other change.
Build the dataset
kd.PDEDataset.from_arrays needs three things: one 1-D array per coordinate
axis, one field array shaped to those axes in order, and the name of the term
that goes on the left-hand side. The full contract is under
Data requirements.
import numpy as np
import kd
k = 0.1
x = np.linspace(0.0, 1.0, 128)
t = np.linspace(0.0, 0.5, 101)
X, T = np.meshgrid(x, t, indexing="ij")
u = np.exp(-(np.pi**2) * k * T) * np.sin(np.pi * X) + 0.5 * np.exp(
-4 * (np.pi**2) * k * T
) * np.sin(2 * np.pi * X)
dataset = kd.PDEDataset.from_arrays(
coords={"x": x, "t": t},
fields={"u": u},
lhs="u_t",
name="my-data",
)
kd.preview(dataset)
Dataset: my-data
Axes:
x | n=128 | range [0.000, 1.000] | step 0.007874 (uniform)
t | n=101 | range [0.000, 0.500] | step 0.005 (uniform)
Fields:
u | dtype=float64 | shape=(128, 101) | min=0.000 max=1.299 mean=0.499 (NaN=0)
LHS: u_t (field='u', axis='t')
Status: ready to fit
kd.preview reports what KD read: the axes and their spacing, the field and
its range, and the left-hand side it will fit. Status: ready to fit means
the dataset satisfies the contract.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6.4, 3.0), dpi=90)
ax.pcolormesh(t, x, u, shading="auto")
ax.set(xlabel="t", ylabel="x", title="my-data: u(x, t)")
fig.tight_layout()
plt.show()

Fit an algorithm
Fitting is a single call. seed makes the run reproducible, and generations
sets the search budget.
model = kd.Model(algorithm="sga", generations=20, seed=2, verbose=False).fit(dataset)
print(f"Discovered : {model.best_expr_}")
print(f"Score : {model.best_score_:.4g} (SGA-PDE AIC, lower is better)")
Discovered : u_t = 0.09998*diff2_x(u)
Score : -24.38 (SGA-PDE AIC, lower is better)
diff2_x(u) is KD's notation for the second derivative in x, so the
recovered law reads as the heat equation the field was built from. Every
algorithm writes its answer in this notation; the term vocabulary is under
Equation representation.
Render the report
kd.VizEngine.render_all writes every figure that applies to this run, plus
one HTML page collecting them.
from pathlib import Path
report = kd.VizEngine(output_dir=Path("../out/my_data")).render_all(
model.result_, algorithm=model.algorithm_, dataset=dataset
)
print(f"Report : {report.report}")
print(f"Figures : {len(report.figures)}")
Report : ../out/my_data/report.html
Figures : 15
Measured data
The derivatives above came from finite differences on the grid, which suits
clean simulation output. For measured data, pass derivatives="autograd" to
kd.Model: KD then fits a smooth surrogate to the field and differentiates
that, which handles noise and points that are not evenly spaced. The two
routes are compared under Derivative sources.
Next steps
- Getting started -- the same workflow on a bundled benchmark, with more of the result surface explained.
- Breaking waves -- a published result reproduced on real wave-tank measurements.
- Algorithms -- what each of the seven searches, and a worked example for each.