API Reference

The complete public API of PDEStudioCore.jl.

PDEStudioCore.PDEStudioCore — Module
PDEStudioCore

A headless-safe backend for running, storing and analysing PDE simulations.

Provides strictly typed Eulerian (ESimData) and Lagrangian (LSimData) datasets of any dimension, deterministic parameter hashing with atomic on-disk caching, parameter sweeps through SimulationConfig, and a multithreaded statistics pipeline.

source
PDEStudioCore.AbstractSimData — Type
AbstractSimData{D, DS, M, T <: Real}

Root type of all simulation datasets.

  • D: total (spacetime) dimensions, DS: spatial dimensions (D == DS for static data),
  • M: number of field components, T: floating point precision.
source
PDEStudioCore.DomainInfo — Type
DomainInfo{D, T <: Real}

Metadata describing the bounding box and dimension layout of a dataset.

Fields

  • dim_keys::NTuple{D, Symbol}: ordered axis identifiers, e.g. (:x, :y, :t).
  • mins, maxs::SVector{D, T}: bounding box of the domain.
  • spacing::SVector{D, T}: mean node spacing per axis (used as integration measure).
  • time_dim::Union{Nothing, Symbol}: the time axis (always the last one), or nothing for static data.
  • stat_registry::StatRegistry: the dimensions kept by each statistic of this dataset.

The constructor validates the layout, copies the registry (datasets never share registries) and always registers :Solution => :all.

source
PDEStudioCore.ESimData — Type
ESimData{D, DS, M, T} <: AbstractSimData{D, DS, M, T}

Eulerian data: fields on a structured tensor grid (time, if present, is the last axis).

Fields

  • params::ParamDict: the parameters that produced the data (copied on construction).
  • domain::DomainInfo{D, T}: bounding box, dimension names and statistic registry.
  • axes::NTuple{D, Vector{T}}: coordinate vector of every axis.
  • u::Array{SVector{M, T}, D}: the solution tensor.
  • stats: a StatsView of all statistics. :Solution is always present and is u; derived statistics are stored alongside it.

Prefer create_sim_data for construction; the inner constructor validates that the axes match the solution and that DS matches the domain.

source
PDEStudioCore.LSimData — Type
LSimData{D, DS, M, T} <: AbstractSimData{D, DS, M, T}

Lagrangian data: particle positions and states recorded at discrete times.

Fields

  • params::ParamDict: the parameters that produced the data (copied on construction).
  • domain::DomainInfo{D, T}: bounding box, dimension names and statistic registry.
  • t::Vector{T}: recording times (a single 0 for static data).
  • x::Vector{Vector{SVector{DS, T}}}: particle positions per time step.
  • u::Vector{Vector{SVector{M, T}}}: particle states per time step.
  • stats: a StatsView; :Solution is always present and is u.
source
PDEStudioCore.NoSimData — Type
NoSimData()

Placeholder returned by solvers or the pipeline when no data was produced (or the run was skipped).

source
PDEStudioCore.SimulationConfig — Type
SimulationConfig

Blueprint of a batch of simulation runs.

Fields

  • shared::ParamDict: baseline parameters of every run (usually contains :sim_func_name).
  • methods::MethodDict: per-method parameter overrides (:ignore => [...] drops shared keys).
  • defaults::Vector{Symbol}: the methods run_all_simulations executes.
  • varied::VariedDict: the parameter sweep (Cartesian product).
  • reference::Union{Symbol, Nothing}: name of a reference factory params -> (x -> u_exact).
  • postprocess::Union{Symbol, Nothing}: name of a function data -> Bool (return true to save).
  • sources::Vector{String}: files included into the target module before running.
source
PDEStudioCore.StatDict — Type
StatDict{M, T}

Alias for Dict{Symbol, AbstractStatTensor{M, T}}, the storage type of derived statistics.

source
PDEStudioCore.StatRegistry — Type
StatRegistry

Alias for Dict{Symbol, Union{Symbol, Vector{Symbol}}}: maps a statistic name to the dimensions it keeps (:all, :space, :time, a single dimension name, or a vector of dimension names).

source
PDEStudioCore.StatsView — Type
StatsView{M, T, S} <: AbstractDict{Symbol, AbstractStatTensor{M, T}}

Dictionary view returned by data.stats. It behaves like a Dict, but :Solution is always present and always refers to data.u (reading, writing and iterating it go through the solution field), so the solution can never be missing from or out of sync with the statistics. All other entries are the dataset's derived statistics. copy(data.stats) returns a plain Dict snapshot.

source
PDEStudioCore.VariedDict — Type
VariedDict

Alias for Dict{Symbol, Vector}: the parameter sweep. The pipeline runs the Cartesian product of all vectors. Keys of the form :Ns__x/:Ns__1 sweep a single entry of the tuple parameter :Ns, :Ns__xy several entries and :Ns__all every entry at once (see generate_method_tasks).

source
PDEStudioCore.add_stat! — Method
add_stat!(data::AbstractSimData, name::Symbol, value, kept_dims)

Attaches a pre-computed statistic and records the dimensions it keeps (:all, :space, :time, dimension names, or Symbol[] for a scalar) so that conversions and frontends can slice it. Numbers and arrays of numbers are converted to SVectors with the dataset's component count, and shapes are checked against the kept axes (Eulerian) or time steps and particles (Lagrangian).

calculate_all_stats! leaves such statistics alone, unless the same name is registered globally (then it is recomputed with force_overwrite = true or when the kept dimensions differ).

source
PDEStudioCore.assemble_params — Method
assemble_params(shared::AbstractDict, methods::AbstractDict, method_name::Symbol)

Shared parameters (minus the method's ignored keys) overridden by the method's own parameters. The :ignore entry itself only controls the assembly and is not part of the result (or the hash).

source
PDEStudioCore.calc_stat — Method
calc_stat(::Val{name}, fixed_coords, u, ana, domain)

Extension point for statistics registered with register_stat!. Called once per retained slice: fixed_coords holds the coordinates of the kept dimensions, u/ana iterate the numerical and reference values of the slice (ana is NaN without a reference function). Must return an SVector{M}. The fallback returns NaNs, which removes the statistic.

source
PDEStudioCore.calculate_all_stats! — Function
calculate_all_stats!(sim_data::AbstractSimData, ref_func = nothing; force_overwrite = false, save = true)

Evaluates every statistic of the global registry (see register_stat!) that is missing from the dataset (or all of them with force_overwrite = true). ref_func(x) is the exact solution at the spacetime point x::SVector{D}; it is evaluated once per node/particle. Statistics that come out all-NaN (e.g. errors without a reference) are dropped. Statistics added with add_stat! are never touched. Saves the dataset when save = true. Returns sim_data.

source
PDEStudioCore.calculate_hash — Method
calculate_hash(params::AbstractDict)

SHA-256 hash (hex string) of the parameters, computed from the sorted key => val2str(value) pairs.

source
PDEStudioCore.check_data — Method
check_data(data::ESimData; per_step = false)
check_data(data::LSimData)

Summarises the numerical health of a dataset as a DataFrame with the columns Time, then C<c>_Min, C<c>_Max, C<c>_Mean, C<c>_NaNs for every component c. Eulerian data is aggregated into a single row (Time = NaN) unless per_step = true; Lagrangian data gets one row per time step.

source
PDEStudioCore.convert_to_eulerian — Method
convert_to_eulerian(ldata::LSimData, res::Tuple; spatial_interp = :scatter)

Scatters Lagrangian particles onto a grid with the spacetime resolution res (spatial entries, then the number of time slices). Particle field statistics are scattered as well, time series are resampled to the output times and other statistics are copied. Output times are evenly spaced between the first and last recording time; each takes the nearest recorded particle snapshot (the native times are kept when the number of slices matches).

source
PDEStudioCore.convert_to_lagrangian — Method
convert_to_lagrangian(data::ESimData)

Turns grid nodes into stationary particles (all time steps share one position vector). Full fields become per-particle statistics, purely spatial fields are repeated for every time step and all other statistics are copied.

source
PDEStudioCore.create_sim_data — Method
create_sim_data(space, u, t, params; dims, time_dim = :t, xmins, xmaxs, tmin, tmax)   # transient Eulerian
create_sim_data(space, u, params; dims, xmins, xmaxs)                                 # static Eulerian
create_sim_data(x, u, t, params; dims, time_dim = :t, xmins, xmaxs, tmin, tmax)       # transient Lagrangian
create_sim_data(x, u, params; dims, xmins, xmaxs)                                     # static Lagrangian

Builds an ESimData or LSimData of any spatial dimension. The global statistic registry is copied into the dataset and :Solution is coupled to u automatically.

Eulerian input

  • space: a coordinate vector (1D), a tuple of axis vectors (x, y, z, ...), or a tuple of ndgrid-style coordinate arrays (x_grid[i, j] == x[i]).
  • u: an array with one dimension per spatial axis (plus a trailing time dimension when t is given) whose elements are SVectors, numbers (a scalar field) or vectors. A numeric array with one extra trailing dimension is read as components-last (u[i, j, n, c]).
  • t: the time vector (time is always the last axis).

Lagrangian input

  • x: particle positions, Vector{Vector{SVector{DS}}} (one vector per time step) or a single Vector{SVector{DS}} for static data.
  • u: particle states with the same layout (SVectors or numbers).

Keywords

  • dims: names of the spatial axes (default (:x, :y, :z), or (:x1, :x2, ...) beyond 3D).
  • time_dim: name of the time axis (default :t).
  • xmins, xmaxs, tmin, tmax: override the bounding box (defaults: extent of the data). The integration measure (domain.spacing) is always derived from the axes themselves.

The parameters are copied, so later changes to params do not affect the dataset.

Examples

create_sim_data(x, u, t, params)                       # 1D + time, u[i, n]::SVector{M}
create_sim_data((x, y), u, t, params)                  # 2D + time, u[i, j, n]
create_sim_data((x, y, z), ρ, params; dims = (:r, :θ, :φ))   # static 3D scalar field
create_sim_data((x_grid, y_grid), u, t, params)        # ndgrid coordinate arrays
create_sim_data(x_traj, u_traj, t, params)             # particles over time
source
PDEStudioCore.delete_sim_data — Method
delete_sim_data(match_params::AbstractDict; dry_run = false)

Deletes every data file whose stored parameters contain all the given key-value pairs (the files find_sim_data lists). Returns the paths of the (would-be) deleted files. An empty filter is rejected because it would match every file.

julia> delete_sim_data(Dict(:N => 100, :scheme => "upwind"))
source
PDEStudioCore.delete_stat! — Method
delete_stat!(name::Symbol)
delete_stat!(data::AbstractSimData, name::Symbol)

Removes a statistic from the global registry, or removes a statistic (value and registry entry) from a single dataset. :Solution cannot be removed.

source
PDEStudioCore.does_sim_data_exist — Method
does_sim_data_exist(params)
does_sim_data_exist(params, Val(:raw))
does_sim_data_exist(params, Val(:eulerian), res)
does_sim_data_exist(params, Val(:lagrangian))

Checks (without loading the data) whether the native dataset, or a representation that can be loaded without recomputation, exists on disk.

source
PDEStudioCore.find_sim_data — Function
find_sim_data(match_params = Dict(); io = stdout, verbose = true)

Lists the data files whose stored parameters contain all the given key-value pairs, i.e. any subset of a run's parameters (keys may be strings or symbols; an empty filter lists every file). Only the lightweight params metadata is read. Prints one line per file (newest first) with the parameters that were not part of the filter, and returns the file paths.

julia> find_sim_data(Dict("N" => 100));
2 data files with N = 100:
  2026-10-21_17-45-00_123_3f9a….jld2   cfl = 0.5, scheme = upwind, sim_func_name = :advection_solver_1d
  2026-10-21_17-44-58_907_b02c….jld2   cfl = 0.5, scheme = lax_friedrichs, sim_func_name = :advection_solver_1d
source
PDEStudioCore.generate_method_tasks — Method
generate_method_tasks(base_params, active_keys, active_values; ignore_keys = Symbol[])

Expands one method's parameters over the Cartesian product of active_values. Keys of the form :Ns__x/:Ns__1 (__y/__2, __z/__3, __<n>) set one entry of the tuple parameter :Ns; :Ns__xy (__xz, __yz, __xyz) sets several entries and :Ns__all every entry of the tuple to the same swept value. Varied keys that are absent from base_params (or ignored) are not applied to this method. Returns (tasks, grid_indices).

source
PDEStudioCore.generate_reference_simdata — Method
generate_reference_simdata(ref_func, params, template_domain, res, Val(:eulerian))
generate_reference_simdata(ref_func, params, template_domain, res, Val(:lagrangian))
generate_reference_simdata(ref_func, params, template_domain, res, kind::Symbol)

Evaluates the exact solution ref_func(x::SVector{D}) on a uniform grid spanning the bounding box of template_domain with spacetime resolution res, as Eulerian data or as stationary particles.

source
PDEStudioCore.generate_tasks — Method
generate_tasks(config::SimulationConfig)

All parameter sets run_all_simulations would execute (reference methods skipped, duplicates removed). Handy to load the results of a sweep: [load_sim_data(p) for p in generate_tasks(config)].

source
PDEStudioCore.get_clean_params — Method
get_clean_params(params::AbstractDict)
get_clean_params(data::AbstractSimData)

Returns the normalised copy of the parameters, exactly as it is stored on disk and hashed.

source
PDEStudioCore.get_kept_dims — Method
get_kept_dims(stat::Symbol, domain::DomainInfo)

Resolves the registry entry of stat (aliases :all, :space, :time, a dimension name or a vector of names) into the dimension names it keeps, in domain order (the order of the dimensions of the statistic's array, whatever order the registry lists them in). :Solution always keeps all dimensions.

source
PDEStudioCore.has_time — Method
has_time(domain::DomainInfo)
has_time(data::AbstractSimData)

true if the dataset is transient (has a time axis).

source
PDEStudioCore.is_reference_method — Method
is_reference_method(m_name::Symbol)

true if a word of the method name (split at _, - and non-alphanumerics) starts with "analytic", "reference", "exact", "baseline" or "true" (e.g. :analytic, :exact_solution). Reference methods are skipped by run_all_simulations.

source
PDEStudioCore.load_sim_data — Method
load_sim_data(params)
load_sim_data(params, Val(:raw))
load_sim_data(params, Val(:eulerian), res)
load_sim_data(params, Val(:lagrangian))
load_sim_data(params, kind::Symbol, args...)

Loads the dataset matching params. :raw returns the native data; :eulerian returns a grid at the spacetime resolution res (resampled or scattered from particles if needed); :lagrangian returns particle data (grid nodes become stationary particles). Conversions are computed on the fly and cached in the file when enable_cache! is on.

source
PDEStudioCore.load_sim_data — Method
load_sim_data(hash_prefix::AbstractString; index = 1, key = nothing)

Loads a file by (a prefix of) its parameter hash or by its file name, newest first. Returns the Dict of all stored entries, or only the entry key (e.g. "raw") when given.

source
PDEStudioCore.register_stat! — Method
register_stat!(name::Symbol, kept_dims)

Registers a statistic evaluated through a calc_stat overload. kept_dims lists the dimensions that are retained; all others are integrated out. Valid values: :all, :space, :time, a single dimension name (e.g. :x) or a vector of dimension names (e.g. [:x, :t]; Symbol[] gives a scalar).

:Solution is always registered (keeping all dimensions); registering it is a no-op.

julia> register_stat!(:l2error, :time)
source
PDEStudioCore.rehash_sim_data — Method
rehash_sim_data(target_path; delete_old = true, filter_pairs = nothing, remove_keys = Symbol[], prompt_keys = Symbol[])

Re-normalises the parameters of a .jld2 file (or of every .jld2 file below a directory), recomputes the hash and stores the data under its new name. Use it after renaming or removing parameters, or after changes to the hashing.

Keywords

  • delete_old: remove the old file once the new one has been written.
  • filter_pairs: only process files whose parameters contain these exact pairs.
  • remove_keys: parameter keys to drop before rehashing.
  • prompt_keys: interactively ask (in the REPL) for new values of these keys for every file.

Returns a vector of old_path => new_path pairs.

source
PDEStudioCore.resample_eulerian — Method
resample_eulerian(data::ESimData, res::Tuple)

Resamples the solution and all statistics that keep spatial/temporal dimensions to the spacetime resolution res. Space is interpolated linearly, time with nearest-neighbour (constant) interpolation to avoid cross-fading between snapshots. Resampled axes are uniform and span the old axes' node range; axes whose resolution does not change are kept as they are. Returns data itself if it already has the requested resolution.

source
PDEStudioCore.resolve_dynamic_function — Function
resolve_dynamic_function(name, provided = nothing)

Looks up the function called name (a Symbol or String) in the target module (see set_target_module!). A function passed as provided (or as name) is returned directly. Returns nothing (with a warning) if the name cannot be resolved.

source
PDEStudioCore.run_all_simulations — Method
run_all_simulations(config::SimulationConfig; force_overwrite = false, calculate_stats = false,
                    force_stats = false, post_process = true, parallel = false)

Runs the complete pipeline for a SimulationConfig:

  1. includes config.sources into the target module,
  2. runs every task of generate_tasks whose data is not on disk yet (all of them with force_overwrite), in parallel over Julia threads with parallel = true,
  3. with calculate_stats = true, evaluates missing statistics using the reference factory config.reference (params -> (x -> u_exact)); statistics that were dropped earlier for lack of a reference are evaluated again once a reference is configured. force_stats = true recomputes every registered statistic without rerunning the simulations,
  4. with post_process = true, calls config.postprocess(data) for every dataset and saves the data when it returns true.

Failures of individual tasks are logged and do not abort the batch.

source
PDEStudioCore.run_smart_simulation — Method
run_smart_simulation(sim_func, params; force_overwrite = false, metadata = Dict())

Runs sim_func(params) unless a dataset for params already exists (then returns NoSimData()). The solver receives a copy of the parameters; the result is always stored under the task parameters so it can be found again. Returns the produced data (or NoSimData()).

source
PDEStudioCore.save_sim_data — Method
save_sim_data(sim_data::AbstractSimData; overwrite = false, verbose = true, metadata = Dict())

Saves the dataset under the hash of its (normalised) parameters and returns the file path. An existing file is only replaced when overwrite = true (which also drops stale conversion caches). Writes are atomic: data is written to a temporary file that is then renamed into place. Extra metadata entries are stored as top-level keys of the file.

source
PDEStudioCore.set_save_path! — Method
set_save_path!(path::AbstractString)

Sets the root directory for saved data and creates its data and figures subdirectories. Returns true on success.

source
PDEStudioCore.set_stat_preset! — Method
set_stat_preset!(name::AbstractString)

Loads a predefined set of statistics (registrations and calc_stat overloads) from presets/<name>.jl.

julia> set_stat_preset!("hyperbolic")
source
PDEStudioCore.str2val — Method
str2val(val_str::AbstractString)

Inverse of val2str: parses literals (numbers, strings, symbols, types, tuples, typed or untyped vectors, reshape(T[...], dims), Dict{K, V}(...), Val{...}(), and arithmetic on numbers such as 2π or 1/3). Anything else is returned as a (cleaned) string. Arbitrary code is never evaluated.

source
PDEStudioCore.val2str — Method
val2str(v; top_level::Bool = true)

Converts a value into a Julia-literal-like string (the basis of the parameter hash). Top-level strings are written unquoted, strings inside containers are quoted, functions become "Closure", enum values are written as TypeName.value and custom structs as TypeName(field=value, ...).

source