API Reference
The complete public API of PDEStudioCore.jl.
PDEStudioCore.PDEStudioCore — Module
PDEStudioCoreA 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.
PDEStudioCore.AbstractSimData — Type
AbstractSimData{D, DS, M, T <: Real}Root type of all simulation datasets.
D: total (spacetime) dimensions,DS: spatial dimensions (D == DSfor static data),M: number of field components,T: floating point precision.
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), ornothingfor 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.
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: aStatsViewof all statistics.:Solutionis always present and isu; 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.
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 single0for 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: aStatsView;:Solutionis always present and isu.
PDEStudioCore.MethodDict — Type
MethodDictAlias for Dict{Symbol, ParamDict}: maps method names (e.g. :upwind) to their parameter overrides.
PDEStudioCore.NoSimData — Type
NoSimData()Placeholder returned by solvers or the pipeline when no data was produced (or the run was skipped).
PDEStudioCore.ParamDict — Type
ParamDictAlias for Dict{Symbol, Any}: the flat, resolved parameters of a single simulation run. Its normalised content is hashed to locate the run on disk (see calculate_hash).
PDEStudioCore.SimFileNotFoundError — Type
SimFileNotFoundError <: ExceptionThrown when no data file matches the requested parameters (or hash), or a requested key is missing.
PDEStudioCore.SimulationConfig — Type
SimulationConfig(shared, methods = Dict(), defaults = all methods;
varied = Dict(), reference = nothing, postprocess = nothing, sources = String[])Builds a SimulationConfig, converting loosely typed dictionaries (string or symbol keys) into ParamDict/MethodDict/VariedDict. Without methods, every run uses the shared parameters only. Functions are referenced by name (resolved in get_target_module).
PDEStudioCore.SimulationConfig — Type
SimulationConfigBlueprint 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 methodsrun_all_simulationsexecutes.varied::VariedDict: the parameter sweep (Cartesian product).reference::Union{Symbol, Nothing}: name of a reference factoryparams -> (x -> u_exact).postprocess::Union{Symbol, Nothing}: name of a functiondata -> Bool(returntrueto save).sources::Vector{String}: files included into the target module before running.
PDEStudioCore.StatDict — Type
StatDict{M, T}Alias for Dict{Symbol, AbstractStatTensor{M, T}}, the storage type of derived statistics.
PDEStudioCore.StatRegistry — Type
StatRegistryAlias 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).
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.
PDEStudioCore.VariedDict — Type
VariedDictAlias 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).
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).
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).
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.
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.
PDEStudioCore.calculate_hash — Method
calculate_hash(params::AbstractDict)SHA-256 hash (hex string) of the parameters, computed from the sorted key => val2str(value) pairs.
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.
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).
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.
PDEStudioCore.create_method_dict — Method
create_method_dict(kv...)Builds a MethodDict; nested dictionaries are converted to ParamDicts.
PDEStudioCore.create_param_dict — Method
create_param_dict(kv...)Builds a ParamDict from pairs or any key-value iterable; String keys become Symbols.
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 LagrangianBuilds 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 whentis given) whose elements areSVectors, 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 singleVector{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 timePDEStudioCore.create_varied_dict — Method
create_varied_dict(kv...)Builds a VariedDict for a parameter sweep. Ranges are collected into vectors.
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"))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.
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.
PDEStudioCore.enable_cache! — Method
enable_cache!(val::Bool)Toggles whether on-the-fly Eulerian/Lagrangian conversions are cached inside the data file.
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_1dPDEStudioCore.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).
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.
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)].
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.
PDEStudioCore.get_file_name — Method
get_file_name(params::AbstractDict)Returns the path of the newest .jld2 file whose hash matches the (normalised) parameters. Throws a SimFileNotFoundError if there is none.
PDEStudioCore.get_ignore_keys — Method
get_ignore_keys(methods::AbstractDict, method_name::Symbol)The shared keys that method_name excludes via its :ignore entry.
PDEStudioCore.get_integration_measure — Method
get_integration_measure(stat::Symbol, domain::DomainInfo)Product of the spacings of all dimensions that stat integrates out (e.g. dx * dy).
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.
PDEStudioCore.get_kept_indices — Method
get_kept_indices(stat::Symbol, domain::DomainInfo)Sorted indices (into domain.dim_keys) of the dimensions kept by stat.
PDEStudioCore.get_save_path — Method
get_save_path()Returns the root directory used for saving (defaults to the working directory at load time).
PDEStudioCore.get_stat_registry — Method
get_stat_registry()Returns the active global statistic registry (a StatRegistry). Datasets copy it on creation and calculate_all_stats! brings them back in sync with it.
PDEStudioCore.get_target_module — Method
get_target_module()Returns the module in which functions referenced by name are resolved (default: Main).
PDEStudioCore.get_time_dim — Method
get_time_dim(data::AbstractSimData)Index of the time axis of a dataset (see get_time_dim(::DomainInfo)); nothing for static data.
PDEStudioCore.get_time_dim — Method
get_time_dim(domain::DomainInfo)Index of the time axis within domain.dim_keys, or nothing for static data.
PDEStudioCore.has_time — Method
has_time(domain::DomainInfo)
has_time(data::AbstractSimData)true if the dataset is transient (has a time axis).
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.
PDEStudioCore.list_available_conversions — Method
list_available_conversions(params::AbstractDict)Returns the conversion keys cached in the matching file (e.g. ["conv_L", "conv_E_100x50"]).
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.
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.
PDEStudioCore.print_clean_params — Method
print_clean_params(data)Prints the normalised parameters (of a dictionary or a dataset) in alphabetical order and returns them.
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)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.
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.
PDEStudioCore.reset_stat_registry! — Method
reset_stat_registry!()Clears the global statistic registry.
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.
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:
- includes
config.sourcesinto the target module, - runs every task of
generate_taskswhose data is not on disk yet (all of them withforce_overwrite), in parallel over Julia threads withparallel = true, - with
calculate_stats = true, evaluates missing statistics using the reference factoryconfig.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 = truerecomputes every registered statistic without rerunning the simulations, - with
post_process = true, callsconfig.postprocess(data)for every dataset and saves the data when it returnstrue.
Failures of individual tasks are logged and do not abort the batch.
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()).
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.
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.
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")PDEStudioCore.set_stat_registry! — Method
set_stat_registry!(new_registry::AbstractDict)Replaces the global statistic registry with a copy of new_registry.
PDEStudioCore.set_target_module! — Method
set_target_module!(target_module::Module)Sets the module in which solver, reference and post-processing functions are looked up by name.
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.
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, ...).