Working with Data
Integrating real-world data with your Dyad models is essential for creating accurate simulations and performing model validation. The DyadData package provides the tools you need to incorporate experimental data, historical measurements, and lookup tables into your Dyad components and analyses.
DyadData offers three main types of datasets:
DyadTimeseries: For time-series data with an independent variable (typically time) and one or more dependent variables. Use this for driving model inputs over time or validating model outputs against experimental data.DyadTable: For general tabular data with named columns, useful for steady-state calibration data or multi-row tables.DyadInterpolationTable2D: For 2D lookup tables where a value depends on two independent variables (e.g., damper force as a function of velocity and temperature).
Setup: Creating a Component Library
To use datasets in your Dyad models, you'll need to create a component library (which is a Julia package) and place your data files in the assets/ folder. This allows you to reference data using the portable dyad:// URI scheme.
Here's the recommended directory structure:
.
└── InterpolationDemo/
├── dyad/
│ └── models.dyad # Your Dyad component definitions
├── assets/
│ ├── force_time.csv # Time-series data files
│ └── damper_table.csv # 2D lookup table files
├── src/
│ ├── InterpolationDemo.jl
│ └── generated/
├── test/
└── Project.tomlThe assets/ folder is where you place CSV files and other data. When you reference data with dyad://InterpolationDemo/force_time.csv, Dyad looks for the file at InterpolationDemo/assets/force_time.csv.
For more help on creating a component library, see the Getting Started instructions.
Data Sources
Datasets can be loaded from multiple sources using URI strings:
| URI Scheme | Example | Description |
|---|---|---|
dyad:// | "dyad://MyPackage/data.csv" | Recommended. References files in a package's assets/ folder. Portable across machines. |
file:// | "file://data.csv" or "file:///absolute/path/data.csv" | Local files. Supports both relative and absolute paths, but less portable than dyad://. |
dyad+juliahub:// | "dyad+juliahub://juliahub.com/datasets/user/name" | JuliaHub datasets for collaborative work. |
Recommendation
Use dyad:// URIs for production code. This ensures your models work correctly regardless of where the package is installed, making your code more portable and easier to share.
Interpolation Components
The BlockComponents library provides interpolation components to use datasets in your models:
| Component | Use Case |
|---|---|
Interpolation | 1D interpolation from a dataset. The interpolator is fixed at construction time. |
ParameterizedInterpolation | 1D interpolation from a dataset, with data exposed as tunable parameters for runtime modification. |
InterpolatedTable | 2D interpolation for lookup tables with two independent variables. |
Interpolation Types (1D)
The Interpolation and ParameterizedInterpolation components accept an interpolation_type parameter from the InterpolationType enum. These types map to interpolation methods from DataInterpolations.jl:
| Type | Description |
|---|---|
ConstantInterpolation() | Step-wise constant interpolation. Maintains the value from the left data point until the next point. |
SmoothedConstantInterpolation() | Similar to constant interpolation but with smooth transitions between values. Continuously differentiable. |
LinearInterpolation() | Linear interpolation between adjacent data points. The most common choice for general-purpose interpolation. |
QuadraticInterpolation() | Fits parabolas through nearest points. Continuously differentiable. |
LagrangeInterpolation(n) | Fits a polynomial of degree n through the data points. Higher degrees capture more complex patterns but may oscillate. |
QuadraticSpline() | Piecewise quadratic curves that pass through all data points exactly. Continuous first derivative. |
CubicSpline() | Cubic spline interpolation. Twice continuously differentiable. Good balance of smoothness and accuracy. |
AkimaInterpolation() | Piecewise cubic polynomials using only neighboring points. Avoids overshooting and oscillation common in global methods. |
Extrapolation Types
Both Interpolation and ParameterizedInterpolation accept an optional extrapolation_type parameter that controls behavior when the input is outside the data range. The default is ExtrapolationType.None().
| Type | Description |
|---|---|
ExtrapolationType.None() | Throws an error when the input is outside the data range. (Default) |
ExtrapolationType.Constant() | Extends the interpolation with the boundary values of the data. |
ExtrapolationType.Linear() | Extends the interpolation with a linear continuation, making it C¹ smooth at the data boundaries. |
ExtrapolationType.Extension() | Extends the interpolation with a continuation of the boundary interval expression for maximum smoothness. |
ExtrapolationType.Periodic() | Wraps the interpolation periodically, so A(t + T) == A(t) where T is the data range. |
ExtrapolationType.Reflective() | Mirrors the interpolation at the data boundaries. |
Interpolation Dimensions (2D)
The InterpolatedTable component uses InterpolationDimension to specify the interpolation method for each axis. These types map to methods from DataInterpolationsND.jl:
| Type | Description |
|---|---|
LinearInterpolationDimension() | Linear interpolation along this axis. The most common choice. |
ConstantInterpolationDimension() | Step-wise constant interpolation along this axis. |
BSplineInterpolationDimension(n) | B-spline interpolation with maximum derivative order n. Provides smooth curves with configurable smoothness. |
Example 1: Time-Based Boundary Condition
The Interpolation component creates a fixed interpolator from a dataset at construction time. This example shows a spring-damper system driven by a time-varying force loaded from a CSV file.
Setting Up the Component Library
Create a component library named InterpolationDemo with the following structure:
.
└── InterpolationDemo/
├── dyad/
│ └── spring_damper.dyad
├── assets/
│ └── force_time.csv
├── src/
│ ├── InterpolationDemo.jl
│ └── generated/
└── Project.tomlData File
Create the force profile in assets/force_time.csv:
timestamp,force
0.0,0.0
0.5,5.0
1.0,10.0
1.5,10.0
2.0,5.0
2.5,0.0
3.0,-5.0
3.5,-5.0
4.0,0.0
5.0,0.0Model Definition
Create dyad/spring_damper.dyad:
component SpringDamperSystem
# Parameters
parameter m::Mass = 1.0
parameter c::TranslationalSpringConstant = 10.0
parameter d::TranslationalDampingConstant = 2.0
# State variables
variable x::Position
variable v::Velocity
# Load force vs time data from file
structural parameter force_dataset::DyadData.DyadTimeseries = DyadData.DyadTimeseries(
"dyad://InterpolationDemo/force_time.csv",
independent_var = "timestamp",
dependent_vars = ["force"]
)
# Create interpolation block from dataset
force_interp = BlockComponents.Interpolation(
interpolation_type = BlockComponents.InterpolationType.LinearInterpolation(),
dataset = force_dataset
)
variable F_applied::Force
relations
F_applied = force_interp.y
force_interp.u = time
# Kinematics
v = der(x)
# Dynamics: m*a = F_applied - c*x - d*v
m * der(v) = F_applied - c * x - d * v
endKey points:
The
DyadTimeseriesloads the CSV and specifies which columns to useThe
Interpolationcomponent takes adatasetparameter and extracts the columns internallyConnect
force_interp.utotimeand read the interpolated value fromforce_interp.yThe interpolator is computed once at construction time and cannot be changed at runtime
Running the Analysis
Add the test component and analysis to the same file:
test component TestSpringDamperSystem
system = SpringDamperSystem()
relations
initial system.x = 0.0
initial system.v = 0.0
end
analysis SpringDamperTransient
extends TransientAnalysis(stop=5.0, saveat=0.01)
model = TestSpringDamperSystem()
endAfter compiling the library, run the analysis in Julia:
using InterpolationDemo
result = SpringDamperTransient()
plot(result)Example 2: Parameterized Interpolation
The ParameterizedInterpolation component also takes a dataset, but unlike Interpolation, it exposes the data and independent variable as tunable symbolic parameters. This allows you to modify the interpolation data at runtime through analysis parameters.
Using the same InterpolationDemo library and force_time.csv data file:
component ParamSpringDamperSystem
parameter m::Mass = 1.0
parameter c::TranslationalSpringConstant = 10.0
parameter d::TranslationalDampingConstant = 2.0
variable x::Position
variable v::Velocity
# Load force vs time data from file
structural parameter input_file::String = "dyad://InterpolationDemo/force_time.csv"
structural parameter force_dataset::DyadData.DyadTimeseries = DyadData.DyadTimeseries(
input_file,
independent_var = "timestamp",
dependent_vars = ["force"]
)
# Create interpolation block with dataset interface
force_interp = BlockComponents.ParameterizedInterpolation(
interpolation_type = BlockComponents.InterpolationType.LinearInterpolation(),
dataset = force_dataset
)
variable F_applied::Force
relations
F_applied = force_interp.y
force_interp.u = time
v = der(x)
m * der(v) = F_applied - c * x - d * v
endKey differences from Interpolation:
Both components take a
datasetparameter, butParameterizedInterpolationadditionally exposesdataandindependent_varas tunable symbolic parametersThe interpolation data can be overridden at runtime (e.g., from an analysis), while
Interpolationfixes the interpolator at construction time
Runtime Data Modification
You can pass different data through the test component and analysis:
test component TestParamSpringDamperSystem
parameter data::Force[10]
system = ParamSpringDamperSystem(force_interp(data=data))
relations
initial system.x = 0.0
initial system.v = 0.0
end
analysis ParamSpringDamperTransient
extends TransientAnalysis(stop=5.0, saveat=0.01)
parameter data::Force[10] = rand(10)
model = TestParamSpringDamperSystem(data=data)
endusing InterpolationDemo
# Use default random data
result1 = ParamSpringDamperTransient()
# Override with custom data
result2 = ParamSpringDamperTransient(data=zeros(10))
result3 = ParamSpringDamperTransient(data=ones(10))
plot(result1)
plot(result2)
plot(result3)Limitation
The size of the data array cannot be changed at runtime. The array size is fixed when the model is compiled.
Example 3: 2D Table Interpolation
The InterpolatedTable component handles 2D lookup tables where a value depends on two independent variables. This is useful for modeling components whose behavior depends on multiple operating conditions.
Data File Format
2D tables use a special CSV format:
axis2 values (columns)
↓ ↓ ↓ ↓
┌────┬─────┬─────┬─────┬─────┐
│ │250.0│300.0│350.0│400.0│ ← header row
├────┼─────┼─────┼─────┼─────┤
axis1 → │-5.0│-125 │-100 │ -75 │ -50 │
values │-2.0│ -50 │ -40 │ -30 │ -20 │
(rows) │ 0.0│ 0 │ 0 │ 0 │ 0 │ ← data matrix
│ 2.0│ 50 │ 40 │ 30 │ 20 │
│ 5.0│ 125 │ 100 │ 75 │ 50 │
└────┴─────┴─────┴─────┴─────┘
↑
first column = axis1 valuesFirst row: axis2 values (e.g., temperature) as column headers
First column: axis1 values (e.g., velocity)
Remaining cells: data values (e.g., damping force)
Create assets/damper_table.csv:
,250.0,300.0,350.0,400.0
-5.0,-125.0,-100.0,-75.0,-50.0
-2.0,-50.0,-40.0,-30.0,-20.0
0.0,0.0,0.0,0.0,0.0
2.0,50.0,40.0,30.0,20.0
5.0,125.0,100.0,75.0,50.0This represents damping force as a function of velocity (rows: -5 to 5 m/s) and temperature (columns: 250 to 400 K).
Model Definition
component TemperatureDependentDamper
parameter m::Mass = 1.0
parameter k::TranslationalSpringConstant = 100.0
variable x::Position
variable v::Velocity
variable T::Temperature
variable F_damper::Force
# Load 2D lookup table
structural parameter input_file::String = "dyad://InterpolationDemo/damper_table.csv"
structural parameter damper_table::DyadData.DyadInterpolationTable2D = DyadData.DyadInterpolationTable2D(
input_file,
axis1_name = "velocity",
axis2_name = "temperature",
data_name = "damping_force"
)
# 2D interpolation
damper_interp = BlockComponents.InterpolatedTable(
axis1 = damper_table["velocity"],
axis2 = damper_table["temperature"],
data = damper_table["damping_force"],
interpolation_dim1 = BlockComponents.InterpolationDimension.LinearInterpolationDimension(),
interpolation_dim2 = BlockComponents.InterpolationDimension.LinearInterpolationDimension()
)
relations
damper_interp.u1 = v
damper_interp.u2 = T
F_damper = damper_interp.y
# Temperature varies with time
T = 300.0 + 50.0 * sin(2*pi*0.1*time)
v = der(x)
m * der(v) = -k * x - F_damper
endKey points:
DyadInterpolationTable2Dspecifies names for the two axes and the dataAccess using string indexing:
damper_table["velocity"],damper_table["temperature"],damper_table["damping_force"]InterpolatedTablehas two inputs (u1,u2) and one output (y)Each dimension can have its own interpolation method
Running the Analysis
test component TestTemperatureDamper
system = TemperatureDependentDamper()
relations
initial system.x = 1.0
initial system.v = 0.0
end
analysis DamperTransient
extends TransientAnalysis(stop=10.0, saveat=0.01)
model = TestTemperatureDamper()
endusing InterpolationDemo
result = DamperTransient()
plot(result)Using Datasets in Analyses
Calibration Analysis
Datasets are commonly used in calibration analyses to fit model parameters against experimental data. For a complete guide, see Calibration Analysis.
using DyadModelOptimizer: CalibrationAnalysis
using DyadData: DyadTimeseries
analysis MyCalibrationAnalysis
extends CalibrationAnalysis(
data=DyadTimeseries("dyad://MyComponentLibrary/data/measurements.csv",
independent_var = "time",
dependent_vars = ["measured_current"]),
N_cols=1,
depvars_cols=["measured_current"],
depvars_names=["sensor.i"],
N_tunables = 2,
search_space_names=["resistor.R", "capacitor.C"],
search_space_lb=[1.0, 1e-6],
search_space_ub=[100.0, 1e-3],
optimizer_maxiters=100
)
model = MyCircuit()
endUsing DyadData in Julia
DyadTimeseries
For time-series data with an independent variable and dependent variables.
URI-based constructor:
ts = DyadTimeseries(
"dyad://PackageName/data/measurements.csv";
independent_var = "timestamp",
dependent_vars = ["x", "y"]
)From raw data:
data = rand(10, 3)
ts = DyadTimeseries(data; independent_var="time", dependent_vars=["x", "y"])Accessing columns:
time_values = ts["timestamp"]
x_values = ts["x"]DyadTable
For general tabular data with named columns.
URI-based constructor:
tbl = DyadTable(
"dyad://PackageName/calibration.csv";
columns = ["param1", "param2", "param3"]
)From raw data:
# Single row (e.g., steady-state data)
steady_state = DyadTable([1.0, 2.0, 3.0]; columns=["x", "y", "z"])
# Multiple rows
data = rand(10, 3)
tbl = DyadTable(data; columns=["x", "y", "z"])Accessing columns:
param1_values = tbl["param1"]DyadInterpolationTable2D
For 2D lookup tables with two independent variables.
URI-based constructor:
tbl = DyadInterpolationTable2D(
"dyad://PackageName/damper.csv";
axis1_name = "velocity",
axis2_name = "temperature",
data_name = "damping_force"
)From raw data:
velocity = [-5.0, -2.0, 0.0, 2.0, 5.0]
temperature = [250.0, 300.0, 350.0, 400.0]
forces = [-125.0 -100.0 -75.0 -50.0;
-50.0 -40.0 -30.0 -20.0;
0.0 0.0 0.0 0.0;
50.0 40.0 30.0 20.0;
125.0 100.0 75.0 50.0]
tbl = DyadInterpolationTable2D(velocity, temperature, forces;
axis1_name="velocity",
axis2_name="temperature",
data_name="damping_force")Accessing data:
velocity_values = tbl["velocity"] # Vector of axis1 values
temp_values = tbl["temperature"] # Vector of axis2 values
force_matrix = tbl["damping_force"] # Matrix of data valuesWorking with Tables
Use build_table() to get a TypedTables Table for advanced operations:
ts = DyadTimeseries("file:///path/to/data.csv";
independent_var="time",
dependent_vars=["x", "y"])
table = build_table(ts) # Returns a Table from TypedTables.jlFor advanced table operations like filtering, joining, or aggregation, see the TypedTables.jl documentation.
CSV Options
Pass additional keyword arguments to customize CSV reading:
ts = DyadTimeseries("file:///path/to/data.tsv";
independent_var="time",
dependent_vars=["x", "y"],
delim='\t') # Tab-separated valuesSee the CSV.jl documentation for available options.
Helper Functions
# DyadTimeseries
get_independent_var(ts) # Returns the independent variable name
get_dependent_vars(ts) # Returns the dependent variable names
# DyadTable
get_columns(tbl) # Returns the column namesAPI Reference
DyadData.DyadTimeseries Type
DyadTimeseries(
uri::AbstractString;
independent_var::AbstractString,
dependent_vars::Vector{<:AbstractString},
kwargs...)Represent a timeseries-like dataset specified by a URI.
Supported URI schemes
file:///absolute/path- local file with absolute pathdyad://package_name/local_path- dyad package asset (relative to assets/ folder)dyad+juliahub://juliahub.com/datasets/username/dataset_name- JuliaHub dataset
Keyword arguments
independent_var: the name of the column that represents the independent variable (usually the time)dependent_vars: a vector of the names of the columns for the dependent variables
When reading CSV files, additional keyword arguments will be passed to CSV.read. This can help with changing settings such as the delimiter used in the file. See https://csv.juliadata.org/stable/reading.html for more details.
Examples
# Local file
ds = DyadTimeseries("file:///home/user/data.csv";
independent_var="timestamp",
dependent_vars=["x", "y"])
# Dyad package asset
ds = DyadTimeseries("dyad://DyadData/lotka.csv";
independent_var="timestamp",
dependent_vars=["x(t)", "y(t)"])
# JuliaHub dataset
ds = DyadTimeseries("dyad+juliahub://juliahub.com/datasets/user/dataset_name";
independent_var="time",
dependent_vars=["var1", "var2"])DyadTimeseries(
data::AbstractMatrix;
independent_var::AbstractString,
dependent_vars::Vector{<:AbstractString})Represent a timeseries-like dataset that is backed by raw data (matrix).
Keyword arguments
independent_var: the name of the column that represents the independent variable (usually the time)dependent_vars: a vector of the names of the columns for the dependent variables
Example
data = rand(10, 3)
ds = DyadTimeseries(data; independent_var="time", dependent_vars=["x", "y"])DyadData.DyadTable Type
DyadTable(
uri::AbstractString;
columns::Vector{<:AbstractString},
kwargs...)Represent a table specified by a URI.
Supported URI schemes
file:///absolute/path- local file with absolute pathdyad://package_name/local_path- dyad package asset (relative to assets/ folder)dyad+juliahub://juliahub.com/datasets/username/dataset_name- JuliaHub dataset
Keyword arguments
columns: a vector of the names of the columns
When reading CSV files, additional keyword arguments will be passed to CSV.read. This can help with changing settings such as the delimiter used in the file. See https://csv.juliadata.org/stable/reading.html for more details.
Examples
# Local file
tbl = DyadTable("file:///home/user/data.csv";
columns=["var1", "var2", "var3"])
# Dyad package asset
tbl = DyadTable("dyad://DyadData/data.csv";
columns=["s1(t)", "s1s2(t)", "s2(t)"])
# JuliaHub dataset
tbl = DyadTable("dyad+juliahub://juliahub.com/datasets/user/dataset_name";
columns=["x", "y", "z"])DyadTable(
data::AbstractMatrix;
columns::Vector{<:AbstractString})Represent a table that is backed by raw data (e.g. a vector for a single row).
Keyword arguments
columns: a vector of the names of the columns
Example
data = [1.0, 2.0, 3.0]
tbl = DyadTable(data; columns=["x", "y", "z"])DyadTable(
data;
columns::Vector{<:AbstractString})Represent a table that is backed by raw data (e.g. a matrix).
Keyword arguments
columns: a vector of the names of the columns
Example
data = rand(10, 3)
tbl = DyadTable(data; columns=["x", "y", "z"])DyadData.DyadInterpolationTable2D Type
DyadInterpolationTable2D(
uri::AbstractString;
axis1_name::AbstractString,
axis2_name::AbstractString,
data_name::AbstractString,
kwargs...)Represent a 2D interpolation table specified by a URI.
The CSV file should have the following format:
First row: column headers (first cell empty or ignored, then axis2 values)
Subsequent rows: first column is axis1 values, remaining columns are data matrix
Example CSV:
,250.0,300.0,350.0,400.0
-5.0,-125.0,-100.0,-75.0,-50.0
-2.0,-50.0,-40.0,-30.0,-20.0
0.0,0.0,0.0,0.0,0.0
2.0,50.0,40.0,30.0,20.0
5.0,125.0,100.0,75.0,50.0Supported URI schemes
file:///absolute/path- local file with absolute pathdyad://package_name/local_path- dyad package asset (relative to assets/ folder)dyad+juliahub://juliahub.com/datasets/username/dataset_name- JuliaHub dataset
Keyword arguments
axis1_name: the name for the first axis (row labels, e.g., "velocity")axis2_name: the name for the second axis (column labels, e.g., "temperature")data_name: the name for the data values (e.g., "damping_force")
When reading CSV files, additional keyword arguments will be passed to CSV.read.
Examples
# Local file
tbl = DyadInterpolationTable2D("file:///home/user/damper.csv";
axis1_name="velocity",
axis2_name="temperature",
data_name="damping_force")
# Dyad package asset
tbl = DyadInterpolationTable2D("dyad://MyPackage/damper.csv";
axis1_name="velocity",
axis2_name="temperature",
data_name="damping_force")
# Access the data
velocity_values = tbl["velocity"] # Vector of axis1 values
temp_values = tbl["temperature"] # Vector of axis2 values
force_matrix = tbl["damping_force"] # Matrix of data valuesDyadInterpolationTable2D(
axis1_values::AbstractVector,
axis2_values::AbstractVector,
data_matrix::AbstractMatrix;
axis1_name::AbstractString,
axis2_name::AbstractString,
data_name::AbstractString)Represent a 2D interpolation table backed by raw data.
Arguments
axis1_values: vector of values for the first axisaxis2_values: vector of values for the second axisdata_matrix: matrix of data values (size: length(axis1_values) × length(axis2_values))
Keyword arguments
axis1_name: the name for the first axis (e.g., "velocity")axis2_name: the name for the second axis (e.g., "temperature")data_name: the name for the data values (e.g., "damping_force")
Example
velocity = [-5.0, -2.0, 0.0, 2.0, 5.0]
temperature = [250.0, 300.0, 350.0, 400.0]
forces = [-125.0 -100.0 -75.0 -50.0;
-50.0 -40.0 -30.0 -20.0;
0.0 0.0 0.0 0.0;
50.0 40.0 30.0 20.0;
125.0 100.0 75.0 50.0]
tbl = DyadInterpolationTable2D(velocity, temperature, forces;
axis1_name="velocity",
axis2_name="temperature",
data_name="damping_force")DyadData.build_table Function
build_table(d::DyadTimeseries)Build a Table from TypedTables.jl out of the specified timeseries dataset. The column names will correspond to the names of the independent variable & the ones for the dependent variables.
Note that the order of the columns is dictated by the order in the file, not by the order inside the dependent_vars argument for DyadTimeseries. The dependent_vars argument only specifies the available columns to use, not their order.
Example
ds = DyadTimeseries("file:///path/to/data.csv";
independent_var="time",
dependent_vars=["x", "y"])
table = build_table(ds)build_table(d::DyadTable)Build a Table from TypedTables.jl out of the specified table dataset. The column names will correspond to the columns.
Example
tbl = DyadTable("file:///path/to/data.csv";
columns=["x", "y", "z"])
table = build_table(tbl)build_table(d::DyadInterpolationTable2D)Read the full table from the dataset (all columns). This delegates to the appropriate build_table method for the dataset type.
source