acdtool reference¶
acdtool is ACE3P’s shared pre- and post-processing utility. It is not one
command but nineteen, and its postprocess rf input format has 24 blocks.
Every ACE3P solver reference ends with the same line — “Note: Refer to acdtool
command syntax for postprocessing capabilities.” — and none of them document
their own output formats, so acdtool is the postprocessing layer for all of ACE3P.
This page is a digest of the parts of that surface LUME-ACE3P depends on, with each item’s implementation status in this package. For how to use the wired subset from a YAML config, see acdtool module; this page is the map of what exists, what is reachable, and what is deliberately not.
Note
Sources. The authoritative documents are the eight SLAC ACD command
references committed under references/ (acdtool-commands.pdf plus one per
solver); see references/README.md for provenance. They specify inputs
thoroughly and outputs barely, so every output format below comes from real
runs frozen as fixtures under tests/fixtures/acdtool/ — whose per-block
coverage is recorded in tests/fixtures/acdtool/COVERAGE.md. Where a block has
no real output behind it, this page says so.
The tables here are digests of the two declarative tables in the code —
lume_ace3p.acdtool.COMMANDS and lume_ace3p.acdtool.SECTIONS — which are what
actually drive dispatch and parsing. If the two ever disagree, the code is right.
The 19 commands¶
Three top-level, five mesh subtasks, eleven postprocess subtasks. The
“CW23” column counts invocations across every batch script in the ACE3P tutorial
archive, which is the evidence for what is used in practice.
Command |
Argument form |
Consumes |
CW23 |
Status here |
|---|---|---|---|---|
|
positional |
genesis mesh |
50 |
invocable; mesh producer, not wired — and already run inside the |
|
positional |
genesis mesh |
— |
invocable; mesh producer, not wired |
|
positional |
Omega3P input |
— |
invocable; writes a suggested batch script to stdout / |
|
positional |
mesh |
(implicit) |
invocable; stdout only. Run internally by |
|
positional |
mesh |
(implicit) |
invocable; stdout only. Run internally by |
|
positional |
mesh |
— |
invocable; mesh producer, not wired |
|
positional |
TEM3P deformed mesh |
2 |
invocable; mesh producer, not wired — see below |
|
positional ( |
mesh |
— |
invocable; the filename passes through opaquely, the file is never parsed |
|
input file ( |
Omega3P or S3P results |
16 |
wired — requires |
|
positional |
Omega3P/S3P results |
— |
invocable; writes ParaView |
|
positional |
T3P/PIC3P results |
2 |
wired — requires |
|
positional |
T3P results |
— |
invocable; not wired for lack of a fixture. The longitudinal counterpart of |
|
positional |
T3P results |
— |
invocable; as |
|
positional |
T3P results |
2 |
wired — requires |
|
positional |
T3P results |
2 |
wired — requires |
|
positional |
PIC3P particles |
1 |
invocable; no PIC3P module exists to hang it on |
|
positional |
PIC3P particles |
2 |
invocable; no PIC3P module exists to hang it on |
|
input file ( |
Track3P results |
2 |
not invocable — needs the KVC dialect this wrapper does not parse |
|
positional |
TEM3P results |
— |
invocable; TEM3P is out of scope and the L2 projections go to stdout |
“Wired” means AcdtoolModule accepts it as a workflow: step.
“Invocable” means lume_ace3p.acdtool.Acdtool.run can dispatch it directly
from Python, but no module-layer home exists. An unknown command raises listing
the known ones; a known-but-unwired command raises naming why it is held back,
so the reason reaches the user rather than living only in this file.
Things about dispatch that are easy to get wrong¶
<jobname> is a name, not a path. Every positional postprocess command
takes the producing solver’s job name, defaulting per solver (omega3p_results,
s3p_results, t3p_results, pic3p_results, track3p_results). That directory
is really chosen by the job name in the batch submission script, not by the
solver input file — no solver reference documents a JobName input container, and
no tutorial input file sets one. LUME-ACE3P therefore injects the jobname from the
producing module’s resolved results directory and exposes a results_dir: module
key as the supported override.
postprocess track3p’s second argument is a jobname, not a field level. The
tutorial’s call site is acdtool postprocess track3p Pillbox.acdtool 2.3MV, where
2.3MV is a directory — the example simply names its jobname after the field
level it was run at.
Three input dialects, deliberately not unified.
Dialect |
Files |
Read by |
|---|---|---|
|
|
|
KVC |
|
|
flat |
|
nobody — the filename passes through opaquely |
A .acdtool input handed to this wrapper raises, naming the unsupported
command. It used to parse silently to two empty blocks and then run nothing at
all, which is the actual defect; routing the second dialect is a feature that can
land when selected-particle Trajectory extraction is wanted. Note
postprocess track3p otherwise duplicates Track3P’s own Postprocess: {EnhancementCounter} container, so Trajectory’s explicit ParticleID list is
the only capability the acdtool route genuinely adds.
Serial vs parallel. “acdtool submodules run serially with the exception of
acdtool postprocess volmontomode and acdtool postprocess rf.” The tutorial’s own
invocations match, and run even those two at one rank. So one rank is the
correct default for all 19, and tasks: is forced to 1 for the 17 serial
commands (with a warning rather than a silent override). cores: is not pinned:
the tutorial runs the serial transwake as srun -n 1 -c 256, i.e. one rank over
many threads.
Commands that mutate their producer’s output. transwake, wake_new and
wake_direct write their result over <jobname>/OUTPUT/wakefield.out — the
file T3P itself wrote and the workflow has already parsed. That is by design (the
T3P reference says so: the acdtool wake commands write to the path “where the file
name ‘wakefield’ has been specified in Monitor”). The module layer declares the
mutation and asks the producer to re-read its output afterwards, so t3p stays
the single owner of every wakefield quantity. Without that the workflow would
report the longitudinal loss factor computed before acdtool ran — a
wrong-but-plausible number. coaxsignal writes a new file
(<jobname>/OUTPUT/signal.out) and is unaffected.
A wake is not the only thing t3p owns, though: T3P writes six kinds of
monitor output and all of them are read, so {module: t3p, monitor: <Name>, …}
reaches a Power, Point, ModeVoltage or SurfacePowerLoss monitor with no
acdtool step involved at all. See T3P reference. What that means here is
that the wake commands are a narrower addition than they once looked — they
compute a transverse wake from an on-contour longitudinal one, which no monitor
can do, and nothing else.
Why the mesh commands are not wired. Producing a mesh would make acdtool a
second producer of the mesh artifact, which the one-producer-per-artifact rule
forbids; meshconvert also already lives in lume_ace3p.cubit. mesh deform
additionally duplicates TEM3P’s own MeshDump: {MeshDeformScale, EMMeshInputDir},
which writes the deformed vacuum mesh straight into the EM mesh input directory —
the better route if the TEM3P chain is ever attempted. The acdtool reference itself
calls mesh deform a visualization convenience for small deformations.
Out of scope, and why¶
PIC3P and Gun3P. Both are fully specified in their references, but no module
exists for either, which is what leaves pic3pstats / pic3pconvert unwired.
PIC3P is structurally close to T3P (ModelInfo, FiniteElement, PRegion,
Loading, TimeStepping, Monitor, LinearSolver, CheckPoint), so a PIC3P
module would be a small lift and is the natural next one. Gun3P is structurally
different (DCGunProblem, ElectrostaticProblem, MagnetostaticProblem,
Tracker, Gun3pOutputConverter) and a larger lift.
TEM3P. The multiphysics chain the tutorial exercises
(cubit ×2 → omega3p(vacuum) → tem3p(body) → acdtool mesh deform → omega3p(deformed) → Δf) needs two meshes, two omega3p modules and acdtool
producing a mesh. All three need artifact identity to be per-instance rather
than per-kind, which is a separate foundational effort.
The postprocess rf input: 24 blocks in six output shapes¶
A .rfpost file is one required RFField configuration block plus any number of
postprocess blocks, each switched on by ionoff = 1.
Two block sets, and they disagree. The tutorial’s template carries 19 blocks;
the reference documents 20 functionalities and a 21st (RoverQRoverQT) in its
body without listing it. Neither is a superset of the other:
in the tutorial but absent from the reference:
Track,TrackScan,coaxPort;in the reference but absent from the tutorial’s template:
pointRoverQ,dFSlater,RoverQRoverQT,IMPACTMap,OpenPMD_IMPACT.
The union is 24 blocks, and the tutorial’s template is simply from an older build. So the input parser tolerates unknown blocks and round-trips them untouched rather than enumerating a fixed list — in both directions, since a newer template will carry blocks we have never seen and an older one carries blocks the reference forgot.
Running acdtool postprocess rf with no arguments writes a sample.rfpost
template for the installed build, which is the authoritative source for a
default input — and is what Acdtool.make_default_input uses when no input: is
given, falling back to a hardcoded 2-block subset when no binary is reachable.
The 24 blocks collapse into six output shapes, and there is one reader per shape:
Shape |
Index axis |
Blocks |
Written to |
|---|---|---|---|
Mode-indexed table |
|
|
|
Surface-indexed scalars |
|
|
|
Single-mode scalars |
— (uses |
|
|
Column curves |
position / phase |
|
separate files |
Field maps / grids |
— |
|
separate files |
Run-level scalars |
— |
|
|
(configuration) |
— |
|
emits no output |
The mode-indexed blocks are exactly the ones carrying modeID1/modeID2.
FieldAtPoint is its own shape: unlike ALLFieldAtPoint it has no
modeID1/modeID2 and evaluates only the single mode named in RFField, so it
has no index axis at all.
Column names come from the file — the header row of a column table, the
name = value lines of a scalar block — not from a per-block list of column
positions, so a build that adds or reorders a column is still read correctly. A
block whose output cannot be read warns naming itself
(lume_ace3p.acdtool.AcdtoolOutputWarning) rather than silently vanishing.
Grid output is recorded, not parsed. The filenames a grid block produced are recorded; their contents are not read. Two of the five are binary or HDF5, so this is not a shortcut to “finish” without a concrete use case.
Real-output coverage¶
Only three of the 24 have a real acdtool output frozen behind them: RoverQ,
ALLFieldOnLine and [scaling]. In particular kickFactor and
maxFieldsOnSurface have none — no tutorial run ever enabled either block,
and the reference documents inputs only — yet examples/omega3p_sweep depends on
maxFieldsOnSurface for E_max. Their readers are driven by the file’s own header
row and assignments rather than by an assumed layout, which is a strictly weaker
assumption than the hand-counted column positions they replaced, but the layouts
themselves remain unverified. Nothing short of a real run with those blocks at
ionoff = 1 closes that. See tests/fixtures/acdtool/COVERAGE.md.
Curve and grid filenames differ per block¶
The naming schemes are not uniform, and cannot be inferred from one another:
Block |
Writes |
|---|---|
|
|
|
|
|
|
|
|
|
fixed names |
|
|
|
|
The per-mode suffix is not knowable before the run (modeID2 = -1 means every
mode the solver produced), so these names are globbed rather than predicted —
which also picks up the .ec/.bc siblings in one pass.
They also differ in scaling, which matters for reading the numbers:
FieldOnLine fields are scaled to RFField’s gradient, while ALLFieldOnLine
fields come straight from the eigenmode, normalized to total stored energy. That
is the same distinction [scaling]’s m_factor records.
Input semantics you cannot guess from the files¶
These are the reference’s, not inferences, and each one has bitten a reader of the tutorial files:
|
They mean “use the minimum/maximum z of the computational domain”, not coordinates. This is why the tutorial writes |
|
It selects the point-scaled variant of the |
|
So the tutorial’s |
|
An eigenmode index for Omega3P; a port-mode (excitation) index for S3P, ordered by port then mode. |
|
A zero-based index into the |
|
Unit W, the real part being the average power flow from the complex Poynting vector. It gets the same real/imaginary split as Omega3P’s complex eigenfrequency, not a plain scalar. |
|
It changes how results are grouped in the output — by multipole component or by mode. Only |
|
In the S3P case the block has no closing |
|
Not a path chosen in the input file — see the jobname note above. |
Headerless and oddly-commented outputs¶
postprocess coaxsignal’ssignal.outhas no header row at all; its three columns (t,V,I) are named from the reference.postprocess track3p’sennames its seven columns on a bare uncommented first line.S3P’s
PortRef<n>_<m>.outis%-commented rather than#-commented — the only ACE3P output in the fixture set that is.T3P’s own series monitors (
Point,Power,ModeVoltage) are headerless too, for the same reason and read the same way — see T3P reference.The T3P reference gives the wakefield monitor’s columns as
W(s)in V/C andI(s)in A/m, while the real file header says V/pC and C/m. The file header is authoritative and is what is read; do not “correct” the units to match the document.