Config-Driven Builders
The build_* functions in src/Builders/ turn flat, namespaced parameter dictionaries into the numerical objects of the package. They exist so that a wrapper (or a test suite) does not have to re-implement the symbol-to-type mapping for every scheme, tableau, limiter and strategy, and so that this mapping is updated together with the types it names.
The physics side is deliberately not here. PDEs, initial conditions and source terms are built by the wrapper, which fills context[:Equation], [:D], [:M] and the source tuples before calling the builders. In HyperCloud.jl, the runners such as run_direct_simulation call the builders below in this order, and the configuration keys are listed in its Configuration Reference.
using HyperCloudCore
context = Dict{Symbol, Any}(:T => Float64, :D => 1, :M => 1, :Equation => eq,
:ExplicitSources => (), :ImplicitSources => ())
context[:WeightConf] = Dict(:name => :exponential, :range => 2.5, :alpha => 1.0)
context[:Domain] = build_domain(Dict(:domain => :rectangular, :mins => (-1.0,), :maxs => (1.0,), :periodic => true), context)
pg = build_particle_grid(Dict(:Ns => (200,), :mover => :lagrangian), context)
context[:Flux] = build_flux(Dict(:name => :Rusanov), context)
context[:Limiter] = build_limiter(Dict(:name => :none), context)
context[:MOOD] = build_mood(Dict(:criterion => :U2, :strategy => :EPD1, :delta_relax => 1e-4), context)
context[:Scheme] = build_scheme(Dict(:name => :MUSCL, :order => 3), context)
context[:Tableau] = build_tableau(Dict(:stepper => :RK3), context)
ts = build_timestepper(context)
adaptivity = build_adaptivity(Dict(:enabled => true), context)Every builder is build_x(conf::Dict, context::Dict), where conf holds the keys of one namespace with the prefix stripped (:Scheme_order becomes :order; in HyperCloud, extract_namespace does the stripping). The builder dispatches on Val(conf[:name]) (or the namespace's selector key), so adding a variant means defining one more method:
HyperCloudCore.build_flux(::Val{:HLL}, conf::Dict, context::Dict) = MyHLLFlux()An unknown name raises an error that names the missing method.
Context keys
The context::Dict{Symbol, Any} carries everything that is already built:
| Key | Set by | Read by |
|---|---|---|
:T (legacy :Type) | caller | all (via real_type) |
:Equation, :D, :M | caller (PDE builder) | grid, schemes, time stepper, domains |
:Domain | build_domain | build_particle_grid, build_mover |
:WeightConf | caller (Weight namespace) | build_particle_grid → build_weights |
:max_dx, :interp_range | build_particle_grid, build_weights | |
:Grid | build_particle_grid | build_mood_criterion, memory reservation |
:Flux, :Limiter, :MOOD, :Scheme, :Tableau | the respective builders | build_scheme, build_timestepper |
:ExplicitSources, :ImplicitSources | caller | build_timestepper |
:VolumeEstimator (optional) | caller | build_timestepper |
:Storage (array type, default Array) | caller | build_particle_grid (device_grid), build_scheme, build_timestepper |
:MemoryLimit (bytes), :MemoryTolerance, :SlotsPerParticle | caller | build_timestepper (reserve!; stores the reservation in :Memory) |
:Storage and :MemoryLimit are how a run is put on a GPU and given a memory budget; see Execution backends and the GPU roadmap.
Selectors
| Builder | Namespace | Selector | Values |
|---|---|---|---|
build_domain | Grid | :domain | :rectangular, :spherical |
build_weights | Weight | :name | :exponential, :inverse |
build_mover | Grid | :mover | :none, :lagrangian, :scaled_lagrangian, :sinusoidal |
build_volume_estimator | Grid | :volumes | :shepard, :mls |
build_flux | Flux | :name | :Rusanov, :Upwind |
build_limiter | Limiter | :name | :none, :minmod, :superbee, :VK, :BJ (+ :mode) |
build_mood | MOOD | :criterion, :strategy | :none/:only/:U1/:U2; :EPD0/:SEPD0/:EPD1/:EPD2 |
build_scheme | Scheme | :name | :MUSCL, :Upwind, :Central, :WENO |
build_tableau | Time | :stepper | :Euler, :RK2, :RK2Ralston, :RK3, :RK4, :IMEXEuler, :ARS222, :ARS233, :PRSSP3, :SSP332 |
build_adaptivity | Adapt | :enabled | true/false (+ the ParticleAdaptivity knobs) |
build_particle_grid calls build_weights, build_mover and build_volume_estimator itself, and build_domain resolves the boundary conditions with parse_bc. The per-builder keys are listed in the docstrings below.
Reference
HyperCloudCore.real_type — Method
real_type(context) -> DataTypeThe floating-point type of the run: context[:T], or the legacy key context[:Type], else Float64.
HyperCloudCore.storage_type — Method
storage_type(context) -> TypeThe array type the run lives on: context[:Storage], else Array. With a device array type (e.g. ROCArray) the grid builder returns a device_grid and the scheme and time stepper builders allocate their buffers there (see docs/src/gpu_roadmap.md).
HyperCloudCore.build_weights — Function
build_weights(weight_conf, context) -> MLSWeightFunction
build_weights(::Val{name}, weight_conf, context)Weight namespace. Selector :name: :exponential (ExponentialWeightFunction) or :inverse (InverseWeightFunction), both with the required shape parameter :alpha. :range (required) is the support radius in multiples of context[:max_dx] (set by build_particle_grid, which calls this builder); the absolute radius is stored in context[:interp_range].
Add a weight function with a method build_weights(::Val{:my_weight}, weight_conf, context).
HyperCloudCore.build_domain — Function
build_domain(domain_conf, context) -> GeometricDomain
build_domain(::Val{name}, domain_conf, context)Grid namespace. Selector :domain (a Symbol or String):
:rectangular:get_rectangular_domainon the box:mins,:maxs;:spherical:get_spherical_domainwith the midpoint of the box as centre and half its first extent as radius (needscontext[:D]).
Both read :periodic (Bool or NTuple{D, Bool}, default false) and the boundary conditions (:bc, see parse_bc). A GeometricDomain among the values of domain_conf is returned as it is, so a pre-built domain can be passed through the configuration.
HyperCloudCore.parse_bc — Function
parse_bc(domain_conf) -> Dict{Int, AbstractBoundaryCondition}The bc_map of a domain from domain_conf[:bc] (or :bc_map): a dictionary tag => bc, where bc is an AbstractBoundaryCondition instance, :outflow/:OutflowBC, :fixed_dirichlet/:FixedDirichlet, or the name of a zero-argument constructor defined in HyperCloudCore or in Main. A string is parsed and evaluated as Julia code first. Without the key the map is empty.
HyperCloudCore.SinusoidalVelocity — Type
SinusoidalVelocity{D, T}(A, mins, Ls)w_d(x) = A sin(2π (x_d - mins_d) / Ls_d): the velocity field of the :sinusoidal mover. A bits-type callable (a closure capturing T or D as values would not be isbits and could not enter a GPU kernel).
HyperCloudCore.build_mover — Function
build_mover(grid_conf, context) -> GridMover
build_mover(::Val{name}, grid_conf, context)Grid namespace. Selector :mover (default :none):
:mover | Mover | Keys |
|---|---|---|
:none | NoGridMover | |
:lagrangian | LagrangianMover | |
:scaled_lagrangian | ScaledLagrangianMover | :mover_alpha |
:sinusoidal | PrescribedMover with SinusoidalVelocity | :mover_amplitude (needs context[:Domain]) |
The :sinusoidal velocity, $w_d(x) = A \sin(2\pi (x_d - \mathrm{min}_d) / L_d)$, is periodic on the domain. Called by build_particle_grid.
HyperCloudCore.build_volume_estimator — Function
build_volume_estimator(grid_conf, context) -> VolumeEstimator
build_volume_estimator(::Val{name}, grid_conf, context)Grid namespace. Selector :volumes (default :shepard): :shepard (ShepardVolumes, optional :volumes_sweeps, default 1) or :mls (MLSVolumes, optional :volumes_degree, default 2, and :volumes_samples_per_dx, default 2). Called by build_particle_grid.
HyperCloudCore.build_particle_grid — Function
build_particle_grid(grid_conf, context) -> ParticleGridGrid namespace. Requires real_type(context), [:D], [:M], [:Domain] and [:WeightConf] (the Weight namespace).
| Key | Meaning |
|---|---|
:Ns | Particles per direction (tuple, required); the lattice spacing is (maxs - mins) ./ Ns |
:randomness_factor | Jitter per direction as a fraction of the spacing (default 0) |
:seed (legacy :SEED) | Seed of the MersenneTwister for the jitter (default 42) |
:mover, :mover_* | Grid mover, see build_mover |
:volumes, :volumes_* | Volume estimator, see build_volume_estimator |
Stores the largest spacing in context[:max_dx], builds the weight function with build_weights(context[:WeightConf], context) and sets context[:Grid]. The grid is built on the host and moved to storage_type(context) with device_grid if that is not Array.
HyperCloudCore.build_limiter — Function
build_limiter(limiter_conf, context) -> AbstractSlopeLimiter
build_limiter(::Val{name}, limiter_conf, context)Limiter namespace. Selector :name (default :none): :none (NoLimiter()), :minmod, :superbee (1-D only), :VK (Venkatakrishnan) or :BJ (Barth–Jespersen). Every limiter except :none requires :mode (:hard limits all reconstruction coefficients, :soft only the first-order ones). See MUSCL Reconstruction and Limiting.
HyperCloudCore.build_mood — Function
build_mood(mood_conf, context) -> MOODMOOD namespace. :criterion and :strategy (both default :none) select build_mood_criterion and build_mood_strategy; with both :none MOOD is disabled (MOOD()), otherwise both have to be set. See Multi-Dimensional Optimal Order Detection (MOOD).
HyperCloudCore.build_mood_criterion — Function
build_mood_criterion(::Val{name}, mood_conf, context) -> MOODCriterionThe criterion of build_mood for :criterion = name: :none (NoMOOD), :only (OnlyMOOD), :U1 (MOODu1) or :U2 (MOODu2). :U1 and :U2 require :delta_relax, which is multiplied by the cell volume prod(context[:Grid].meta.dx), so they need the grid.
HyperCloudCore.build_mood_strategy — Function
build_mood_strategy(::Val{name}, mood_conf, context) -> MOODStrategyThe strategy of build_mood for :strategy = name: :EPD0 (EPD0), :SEPD0 (StrictEPD0), :EPD1 (EPD1) or :EPD2 (EPD2).
HyperCloudCore.build_flux — Function
build_flux(flux_conf, context) -> NumericalFluxFunction
build_flux(::Val{name}, flux_conf, context)Flux namespace. Selector :name: :Rusanov (RusanovFlux) or :Upwind (UpwindFlux).
HyperCloudCore.build_scheme — Function
build_scheme(scheme_conf, context) -> DivergenceInterpolator
build_scheme(::Val{name}, scheme_conf, context)Scheme namespace. Requires real_type(context), [:D] and [:M]. Selector :name:
:name | Scheme | Also reads |
|---|---|---|
:MUSCL | MUSCL | context[:Flux], context[:Limiter]; allocates on storage_type(context) |
:Upwind | UpwindDivergence | context[:Flux]; :upwind_alg_nd (:Classic, :Tiwari or :Praveen) |
:Central | CentralDivergence | |
:WENO | WENO |
All take the consistency order :order (required) and the divergence order :MLS_order (the div_order keyword, default 0: follow the particle's order).
Add a scheme with a method build_scheme(::Val{:my_scheme}, scheme_conf, context) returning a DivergenceInterpolator (see API Contracts).
HyperCloudCore.build_tableau — Function
build_tableau(time_conf, context) -> IMEXButcherTableauSelector :stepper: :Euler, :RK2 (SSP), :RK2Ralston, :RK3 (SSP), :RK4, :ARS222, :ARS233, :PRSSP3, :SSP332, :IMEXEuler. Explicit tableaus are returned as IMEXButcherTableaus with a zero implicit part.
HyperCloudCore.build_timestepper — Function
build_timestepper(context; time_conf = Dict()) -> GeneralRKTimeStepperRequires context[:Equation], [:Scheme], [:MOOD], [:Tableau], [:ExplicitSources], [:ImplicitSources]. Optional Time keys: reset_orders_per_stage, full_search_per_stage; the volume estimator comes from context[:VolumeEstimator] if set (otherwise the stepper default), the stage buffers live on storage_type(context). With context[:MemoryLimit] (bytes) the buffers of the grid, the scheme and the stepper are reserved under that limit (reserve!, with the optional context[:MemoryTolerance] and context[:SlotsPerParticle]); the reservation is stored in context[:Memory].
HyperCloudCore.build_adaptivity — Function
build_adaptivity(adapt_conf, context) -> Union{ParticleAdaptivity, Nothing}Adapt namespace. nothing unless :enabled is true; then a ParticleAdaptivity with the optional keys :max_gap (1.6), :min_gap (0.5), :clearance (0.7), :samples_per_dx (2) and :exclude_reduced_order (true), see Particle insertion and merging.