Parameter sweeping

lume-ace3p has two main use-cases: parameter sweeping and optimization. For both, an ACE3P workflow is evaluated many times according to parameters set in a YAML file. A parameter sweep is a mode (type: parameter_sweep) that drives the declarative workflow: chain over the full tensor product of the swept input axes. The examples below are intended as templates.

To set up a parameter sweep, provide in the lume-ace3p input file:

  • a workflow: list — the ordered module chain to run (e.g. cubit omega3p acdtool, or cubit s3p). Solver settings (tasks, cores, opts, the input file) live on the module entries.

  • mode: with type: parameter_sweep and an output_file for the result table.

  • input_parameters — the swept input space, organized into per-code sub-blocks so every variable’s home is explicit:

    • cubit: — names and vector values for Cubit journal (geometry) knobs.

    • ace3p: (optional) — parameters inside the ACE3P input file.

    • geant4: (optional) — overrides for the Geant4 input file.

    A single sweep can span all three sub-blocks at once (the full tensor product of every array-valued leaf across them). The old flat keys (cubit_input_parameters, ace3p_input_parameters, geant4_input_parameters, and a bare input_parameters treated as the cubit block) are still accepted for back-compat, but the nested notation is the standard and is used throughout the examples below.

  • output_parameters (optional) — output quantities to extract into the result table.

Once these are defined in the .yaml file, the parameter sweep is run with the run-lume-ace3p entry point.

Omega3P parameter sweep example

This example (based on the rounded-top pillbox from the ACE3P tutorials, shipped as examples/omega3p_sweep) configures lume-ace3p to run a parameter sweep over cavity radius and cavity wall ellipticity. The goal is to automate the entire mesh-generation, Omega3P calculation, and mode postprocessing pipeline into a single job submitted to HPC resources.

The script begins with the workflow-level settings, the module chain, and the mode:

workflow_parameters :
  'workdir' : 'lume-ace3p_omega3p_workdir'
  'workdir_mode' : 'auto'

workflow :
  - module : cubit
    journal : 'pillbox-rtop.jou'
  - module : omega3p
    input : 'pillbox-rtop.omega3p'
    tasks : 16
    cores : 16
    opts : '--cpu-bind=cores'
  - module : acdtool
    input : 'pillbox-rtop.rfpost'

mode :
  type : parameter_sweep
  output_file : 'omega3p_sweep_output.txt'

workflow_parameters holds only directory settings here: workflows are run in separate sub-directories (workdir_mode: auto, auto-named from input values). Each module entry names its own input file and, for the solver, its MPI settings (16 tasks × 16 cores/task with --cpu-bind=cores). The mode block enables the result table written to output_file. See YAML configuration reference for full details.

Next, Cubit input parameters:

input_parameters :
  cubit :
    'cav_radius' :
      'min' : 90.0
      'max' : 120.0
      'num' : 4
    'ellipticity' :
      'min' : 0.5
      'max' : 1.25
      'num' : 4

The cubit: sub-block is a key-value mapping where each key is the exact name of a variable defined in the Cubit journal file, and each value is either a list of numeric inputs or a nested dict with min, max, num (linearly spaced).

ACE3P input parameters live in the ace3p: sub-block of the same input_parameters mapping:

input_parameters :
  ace3p :
    'ModelInfo' :
        'SurfaceMaterial' :
            'ReferenceNumber' : 6
            'Sigma' : [5.8e7, 1.04e7]

The ace3p: sub-block is a nested mapping organized by ACE3P file hierarchy. Here the swept parameter is the conductivity of the surface with ReferenceNumber 6. Values can use min/max/num, a list, or a single value if not swept. (In practice the cubit: and ace3p: sub-blocks are written under one input_parameters: header — see examples/omega3p_ace3p_param_sweep.)

In this example cav_radius and ellipticity are length-4 vectors, and Sigma has two values, giving 4 × 4 × 2 = 32 workflow evaluations. Because workdir_mode is auto, each evaluation creates a folder named from the workdir base plus the swept scalar values (e.g. lume-ace3p_omega3p_workdir_90.0_0.5_58000000.0) for a total of 32 folders. The full cubit omega3p acdtool chain — including the in-cubit meshconvert — re-runs in each folder.

Then, output parameters:

output_parameters :
  'R/Q' : {module: acdtool, section: RoverQ, quantity: RoQ, at: {mode: 0}}
  'Mode_freq' : {module: omega3p, quantity: Frequency, at: {mode: 0}}
  'E_max' : {module: acdtool, section: maxFieldsOnSurface, quantity: Emax, at: {surface: 6}}
  'loc_x' : {module: acdtool, section: maxFieldsOnSurface, quantity: Emax_location, component: x, at: {surface: 6}}
  'loc_y' : {module: acdtool, section: maxFieldsOnSurface, quantity: Emax_location, component: y, at: {surface: 6}}
  'loc_z' : {module: acdtool, section: maxFieldsOnSurface, quantity: Emax_location, component: z, at: {surface: 6}}

output_parameters maps user-chosen labels to an extraction spec naming the module, the thing wanted, and — for an indexed result — which index. R/Q and E_max come from acdtool, which reads them out of rfpost.out; Mode_freq comes from Omega3P’s own eigenmode output, so it needs no postprocessing block at all. Dropping the at: from a mode-indexed acdtool spec asks for every mode instead of one, which is what a dispersion curve or an HOM catalog wants. The full spec grammar is in output_parameters; the .rfpost block surface is in acdtool reference.

The output_file is a tab-delimited table with one column per input or output, one row per workflow evaluation.

In this example the table has 9 columns — one per swept axis (cav_radius, ellipticity, and the swept ACE3P leaf, whose column is labeled by its path ace3p:ModelInfo.SurfaceMaterial.Sigma) followed by the 6 declared outputs (R/Q, Mode_freq, E_max, loc_x, loc_y, loc_z) — with one row per workflow evaluation. See YAML configuration reference for the full list of supported output sections.

If no output dict is specified, the parameter sweep still runs but rfpost.out data will not be parsed or tabulated (useful when only the per-combination output folders are wanted).

Each workflow evaluation is run serially. Future versions may allow concurrent evaluations.

Resuming a sweep that was cut off

A sweep of long solves rarely fits in one allocation, and a point interrupted partway used to be lost entirely — the next run rebuilt its mesh and re-solved from scratch. Two additions change that: every evaluation records what it did in a run manifest in its own workdir, and mode: {resume: true} reads that record back.

workflow_parameters :
  'workdir' : 'lume-ace3p_omega3p_workdir'
  'workdir_mode' : 'indexed'      # per-point directories: _0, _1, _2, …

mode :
  type : parameter_sweep
  resume : True
  output_file : 'omega3p_sweep_output.txt'

Re-run the same command after a job dies and the sweep picks up where it stopped: finished points contribute their rows without launching a single solver, a point that died halfway restarts at the step that did not finish, and points that never started run normally. The result table is the same table it would have been, so resuming is not a different kind of run — it is the same sweep, minus the work already done.

Before re-running, --status shows what is there:

$ run-lume-ace3p --status omega3p_sweep.yaml
 - 32 point(s) implied by this configuration: 19 complete, 1 failed, 12 absent

Two requirements. workdir_mode must not be manual (points must have their own directories to have their own state — resume: true with manual is refused, naming indexed), and resume is opt-in: a sweep that silently adopted whatever was lying in its workdirs would be worse than no resume at all. Each point’s manifest also carries a hash of the resolved configuration, so a point whose module settings or input values have changed since is re-run, and says so.

The full per-point rules, including what happens when a completed point’s output files have been deleted, are in resume — picking a campaign up where it stopped.

S3P parameter sweep example

This example (based on a 90-degree bend from the ACE3P tutorials) runs a parameter sweep over outer corner cut radius and inner corner rounding radius. The S-parameter results are stored in a text file with all combinations of parameters and frequencies.

workflow_parameters :
  'workdir' : 'lume-ace3p_s3p_workdir'
  'workdir_mode' : 'auto'

workflow :
  - module : cubit
    journal : 'bend-90degree.jou'
  - module : s3p
    input : 'bend-90degree.s3p'
    tasks : 32
    cores : 4
    opts : '--cpu-bind=cores'

mode :
  type : parameter_sweep
  output_file : 's3p_sweep_output.txt'
input_parameters :
  cubit :
    'cornercut' :
      'min' : 12.0
      'max' : 16.0
      'num' : 5
    'rcorner2' :
      'min' : 4.0
      'max' : 16.0
      'num' : 3

Note

Frequencies to scan with S3P are not “inputs” set here — they are set in the .s3p input file directly.

In this example cornercut and rcorner2 are length 5 and 3, giving 5 × 3 = 15 workflow evaluations and 15 distinct folders.

S3P exposes a frequency field index, so its sweep table is emitted in long format: one row per (grid-point, frequency) rather than one row per grid point. output_parameters are optional here — even with none declared, the per-frequency S-parameters are tabulated because the frequency index alone drives the long-format rows.

In the example, S3P scans 13 frequencies for each of the 15 workflow evaluations, giving 195 rows in output_file. Each row has cornercut, rcorner2, and Frequency, followed by the four S-parameters of the 2-port system (S(0,0), S(0,1), S(1,0), S(1,1)).

S3P parameter sweep with no separate ACE3P file

Identical to the previous example, except no .s3p file is submitted. All S3P parameters are specified in the ace3p: sub-block of input_parameters. Modify the S3P sweep .batch file to run s3p_sweep_no_s3p_file.yaml.

input_parameters :
  ace3p :
    'ModelInfo' :
      'File' : './bend-90degree.ncdf'

      'BoundaryCondition' :
        'Exterior' : 6
        'Waveguide' : 7,8

    'FiniteElement' :
      'Order' : 2
      'CurvedSurfaces' : 'on'

    'FrequencyScan':
      'Start' : 9.424e+9
      'End' : 12.424e+9
      'Interval' : 0.25e+9

    'Port':
      'ReferenceNumber' : 7
      'NumberOfModes' : 1

    'Port' :
      'ReferenceNumber': 8
      'NumberOfModes' : 1

Note the two 'Port' blocks at the same indentation level. ACE3P allows duplicate-named sibling sections (one per port, surface, boundary condition, …), and the ace3p: parser preserves them verbatim — entries are matched positionally with the ACE3P input file rather than collapsed into a Python dict. See input_parameters.ace3p for details.

This functions exactly the same as the previous example. Errors may arise if a necessary ACE3P input parameter is missing.

Viewing S3P parameter sweep output

A simple plotting tool is included with lume-ace3p which reads the S3P sweep result table (the mode.output_file) and plots the results in an interactive plot. To use it, run s3p_sweep_plot.py and load the appropriate S3P output_file from the file prompt. Try s3p_demo_sweep_output.txt in the plotting folder for an interactive demo. See Plotting tools for details.

Gaussian-process (low-fidelity) parameter sweep

lume-ace3p also supports a Bayesian-exploration sweep mode that fits a Gaussian Process to the simulator output and then samples the GP posterior mean on a tensor grid — useful for cheaply exploring parameter space without running every grid point through the solver. The mode is selected with mode: {type: gp_parameter_sweep}.

Three sections must be supplied in addition to the workflow: chain:

  • sweep_parameters — the tensor grid the trained GP is evaluated on.

  • vocs_parameters — Xopt VOCS for the exploration phase. The objectives block maps an output_parameters name to 'explore'.

  • xopt_parameters — Xopt driver settings. max_steps caps the GP-guided exploration steps; num_random (default 5) controls the random-seeding phase; improvement_threshold (default 0.01) and patience (default 5) configure early stopping.

A complete example is shipped as examples/s3p_bayesian_sweep/s3p_bayesian_sweep.yaml:

workflow_parameters :
    'workdir' : 'lume-ace3p_mf_workdir'

workflow :
  - module : cubit
    journal : 'bend-90degree_mf.jou'
  - module : s3p
    input : 'bend-90degree_mf.s3p'
    tasks : 16
    cores : 4
    opts : '--cpu-bind=cores'

mode :
    type : gp_parameter_sweep
    output_file : 'sim_output.txt'
    sweep_output_file : 'sweep_output.txt'

output_parameters :
    'S(1,1)_12.0e+09' : { module: s3p, quantity: 'S(1,1)', at: { frequency: 12.0e+09 } }

sweep_parameters :
    'cornercut' :
        min : 12.5
        max : 13.5
        num : 10
    'wgwidth' :
        min : 21
        max : 22
        num : 10

vocs_parameters :
    'variables' :
        'cornercut': [12.5, 13.5]
        'wgwidth':   [21, 22]
    'objectives' :
        'S(1,1)_12.0e+09': 'explore'

xopt_parameters :
    max_steps : 3

The explored objective (S(1,1)_12.0e+09) is an output_parameters name, so the driver pulls it from the workflow generically. The GP posterior-mean grid is written to the sweep_output_file; the actual S3P evaluations performed during exploration are logged to the output_file trajectory table.

Track3P particle weighting

Field-emission particle weighting is the particles module — a post-processing step that reads a Track3P particle dump, filters by impact order / face id, bins by axial position, and writes a weighted-particle file suitable as a Geant4 source. There is no ACE3P solver in this chain; the external dump is supplied by a track3p_source module and the whole thing runs in single mode (the weighting is pure Python). This is examples/track3p_particle_weight:

workflow_parameters :
  'workdir' : 'lume-ace3p_track3p_workdir'
  'workdir_mode' : 'manual'

workflow :
  - module : track3p_source
    file : 'sample_track3p_particles.txt'
  - module : particles
    impact_order : 1
    impact_face_id : 4
    work_function : 4.5
    dt : 1.0e-10
    num_bins : 8
    beta : [50, 55, 60, 65, 65, 60, 55, 50]
    output_format : 'track3p'
    output : 'track3p_particles_weighted.txt'

mode :
  type : single

output_format: 'track3p' writes the weighted-Track3P dump (all filtered columns plus Bin and ParticleWeight); the module default 'geant4' instead writes the 10-column Geant4 source file. See particles module keys for the full key list.

Geant4 dose-calculation workflow

The geant4 module drives a Geant4 application using a single plain-text input file (key = value lines, # comments) that names its own geometry STL files, scoring mesh, thread count, and output files. The particle source is supplied by an upstream module in the chain — either a particles weighting step (fed by a track3p_source) or a particle_source module naming a prebuilt Geant4-format file directly. The geant4 module writes the source filename into the input file (the executable auto-derives the event count from the particle file), stages the STL files it names into each working directory, and reads the dose / energy-deposit output files after the run. STLs named in the input file are located next to it by default; when they live elsewhere (e.g. a shared assets/ directory), list them under geant4_geometry_files so the module can find and stage them.

The full runnable chain (track3p_source particles geant4) is shipped as examples/geant4_track3p_beta (a beta sweep) and examples/geant4_dose_single (a single evaluation). A minimal skeleton:

workflow_parameters :
  'workdir' : 'lume-ace3p_dose_workdir'
  'workdir_mode' : 'manual'

workflow :
  - module : track3p_source
    file : 'sample_track3p_particles.txt'
  - module : particles
    impact_order : 1
    impact_face_id : 6
    work_function : 4.5
    dt : 1.0e-10
    num_bins : 8
    beta : [50, 55, 60, 65, 65, 60, 55, 50]
    output_format : 'geant4'
    output : 'particles.data'      # must match the 'particles = ...' line in the Geant4 input
  - module : geant4
    geant4_input : 'input_7cell.geant4'

mode :
  type : single
  output_file : 'dose_single_output.txt'

output_parameters :
  'total_dose' : {module: geant4, section: dose, quantity: total}
  'peak_dose'  : {module: geant4, section: dose, quantity: peak}
  'total_edep' : {module: geant4, section: edep, quantity: total}

Optional Geant4 input-file overrides go in the geant4: sub-block of input_parameters (plain keys, no /); a swept override there becomes an additional sweep axis alongside any cubit:/ace3p: axes. Geant4 paths are resolved through the same precedence chain as ACE3P — see Executable paths. If GEANT4_APP_PATH / GEANT4_APP_EXE (or YAML / site-default equivalents) are unset, dry-run mode is auto-enabled (the particles weighting still runs for real; only the Geant4 binary is skipped).