Core Concepts¤
This page explains the main building blocks of f3dasm and how they fit together.
Overview¤
The f3dasm workflow revolves around four core abstractions:
Domain ──> ExperimentData ──> Block(s) ──> Pipeline
│ │ │ │
│ defines │ stores │ processes │ chains blocks
│ parameters │ experiments │ data │ into workflows
- A Domain defines the parameter space for your experiments.
- An ExperimentData object holds all your experimental data (inputs and outputs).
- Blocks are units of computation (sampling, data generation, optimization) that operate on
ExperimentData. - A Pipeline chains multiple Blocks together into an automated workflow.
Domain¤
The Domain defines what parameters your experiment has and their valid ranges. It supports several parameter types:
- Continuous (
add_float) — floating-point values with lower and upper bounds - Discrete (
add_int) — integer values with lower and upper bounds - Categorical (
add_category) — a set of named categories - Constant (
add_constant) — a fixed value - Array (
add_array) — fixed-size numeric arrays
from f3dasm.design import Domain
domain = Domain()
domain.add_float(name='temperature', low=200.0, high=800.0)
domain.add_int(name='num_layers', low=1, high=10)
domain.add_category(name='material', categories=['steel', 'aluminum', 'titanium'])
Learn more: Creating a Domain | API Reference
ExperimentData¤
ExperimentData is the central data container. It stores both the input parameters and the output results of your experiments in a structured way. You can think of it as a smart table where each row is one experiment.
from f3dasm import ExperimentData
data = ExperimentData(domain=domain)
Key capabilities:
- Store experiments to disk and reload them
- Export to pandas DataFrames
- Track experiment status (open, in progress, finished, error)
- Access individual experiments via
ExperimentSample
Learn more: Working with ExperimentData | API Reference
Block¤
A Block is the fundamental unit of computation in f3dasm. Every operation on your data — sampling, evaluation, optimization — is a Block with a uniform signature: call(data: ExperimentData, **kwargs) -> ExperimentData.
Blocks compose with the >> operator into a ChainedBlock, and can be repeated with .loop(n) to produce a LoopBlock. Samplers, data generators, and optimizer update steps are all just Blocks — there's no separate Sampler or Optimizer class hierarchy.
Built-in Blocks:
| Category | Examples |
|---|---|
| Samplers | RandomUniform, Latin, Sobol, Grid (and the factories random, latin, sobol, grid) |
| Data generators | DataGenerator subclasses or the @datagenerator decorator |
| Optimizer update steps | tpesampler(output_name=...) (ask/tell style) |
| One-shot optimizers | cg(...), lbfgsb(...), nelder_mead(...) (scipy's own inner loop) |
You can create your own Block by subclassing:
from f3dasm import Block, ExperimentData
class MyBlock(Block):
def call(self, data: ExperimentData, **kwargs) -> ExperimentData:
# transform data here
return data
Composing Blocks¤
Each Block's call accepts the same **kwargs, which are passed to every block in a chain. Keep sampling and evaluation separate when they need different call-time arguments, and use >> to chain blocks whose call-time arguments are compatible:
from f3dasm import create_optimizer, create_sampler
# Initial design: sample, then evaluate
data = create_sampler("latin", seed=42).call(data, n_samples=20)
data = data_generator.call(data)
# Optimize: chain the ask/tell update step with the data generator and
# wrap the pair in a LoopBlock. create_optimizer returns just the update
# step for ask/tell optimizers (like "tpesampler").
update_step = create_optimizer("tpesampler", output_name="y")
loop = (update_step >> data_generator).loop(50)
loop.arm(data)
data = loop.call(data)
Learn more: Understanding Blocks | Built-in Defaults | API Reference
Pipeline¤
A Pipeline chains Blocks together into a complete workflow. It handles the execution order, data passing between steps, and supports both local execution and HPC clusters via SLURM.
from f3dasm import Pipeline, Step, Loop
pipeline = Pipeline(
steps=[
Step(block=sampler),
Loop(
steps=[
Step(block=evaluator),
Step(block=optimizer),
],
iterations=10,
),
]
)
pipeline.execute(data)
Key features:
- Sequential and looped execution — chain steps or repeat them
- SLURM support — run on HPC clusters with
SlurmCluster - Resumable — pipelines can be interrupted and resumed
- Import path preservation — local Python imports (
from my_script import func) are automatically resolved on SLURM compute nodes via shared filesystem
Learn more: Building a Pipeline | API Reference
How It All Fits Together¤
A typical f3dasm workflow follows this pattern:
- Define your parameter space with a
Domain - Create an
ExperimentDataobject from the domain - Sample initial experiments using a sampler Block
- Evaluate the experiments using a data generation Block
- Optimize by iterating between evaluation and optimization Blocks
- Automate the whole process with a
Pipeline
For a hands-on walkthrough, see the tutorials section or jump straight to the quickstart notebook.