Process reference: soft_x_rays
Generated from the docstrings of vaft.process.soft_x_rays:
10 public functions. Each entry is what
vaft.process.describe("soft_x_rays.<name>") prints.
All process categories
Overview
Ported from the validated VEST SXR Viewer analysis tool (vest_sxr_viewer.py
v5, module-level science functions; provenance: the 2026 VEST SXR thesis
presentation). The 455xx SXR campaign acquires both digitizers – 22577 at the
4 o’clock port (toroidal 0 deg) and 17592 at the 12 o’clock port (120 deg) – at
125 MHz / 128 = 976562.5 Hz starting at the 285 ms trigger.
Every routine here takes plain arrays (time in seconds, data shaped
(n_channels, n_samples)); nothing reads a CSV or an ODS except the explicit
ODS pairing helper. Vacuum-shot PF-noise removal is a standalone optional
step (sxr_subtract_vacuum_reference): no other routine applies it, so
the main processing path is always baseline -> window -> filter on exactly the
data the caller supplied.
Generic spectral analysis (PSD, spectral index, spectrogram) is not here –
use vaft.process.fluctuation on any prepared channel.
The forward direction is here too: synthetic_island_soft_x_rays turns a
prescribed magnetic island on an equilibrium into chord signals (issue #886),
through vaft.process.magnetic_island and
vaft.process.line_of_sight. It is machine-independent; VEST chords come
from vaft.machine_mapping.soft_x_rays.sxr_sightlines.
Functions
hilbert_instantaneous_phase | Instantaneous phase and envelope of a band-limited signal at one time. Convention |
load_te_ratio_calibration | Load a ratio-to-temperature table and build its interpolator. Convention |
rank_toroidal_mode_numbers | Rank candidate toroidal mode numbers from phases measured at two locations. Convention |
sxr_band_signals | Baseline, window and band-pass chord signals into named frequency bands. Convention |
sxr_baseline_correction | Zero each channel against the quiet tail after the plasma. Convention |
sxr_cwt_spectrogram | Continuous-wavelet magnitude scalogram of one trace. Convention |
sxr_electron_temperature | Electron temperature from the two-filter signal ratio, chord by chord. Convention |
sxr_subtract_vacuum_reference | Subtract a low-passed vacuum shot to remove poloidal-field pickup. Convention |
sxr_te_pairs_from_ods | Pair the two filters’ channels of one array by the chord they view. Convention |
synthetic_island_soft_x_rays | Line-integrated soft-X-ray signals of a rotating island on an equilibrium. |
No function matches.
hilbert_instantaneous_phase
Machine-independentConvention-sensitive
source
hilbert_instantaneous_phase(signal, time, t_eval)
Show source vaft/process/soft_x_rays.py, lines 708–759
def hilbert_instantaneous_phase(signal, time, t_eval: float):
"""Instantaneous phase and envelope of a band-limited signal at one time.
Parameters
----------
signal : array_like
A band-passed, roughly monochromatic trace [V].
time : array_like
Its time base [s].
t_eval : float
Time at which to report the phase [s].
Returns
-------
tuple
The phase in degrees and the envelope in volts at the nearest sample, that
sample's index, and the full phase and envelope series [-].
Convention
----------
Phase comes from the analytic signal and is wrapped to the principal branch,
so it runs within a full turn and jumps rather than accumulating. The sample
nearest the requested time is used; no interpolation.
Applicability
-------------
Machine-independent.
Limitations
-----------
**Meaningful only for a band-passed input.** The analytic signal of a
broadband trace has a phase that does not correspond to any single mode, so
filter first with :func:`sxr_band_signals`. The Hilbert transform is also
poorly behaved at the record edges, so a time near either end is unreliable.
Provenance
----------
.. [1] The analytic-signal phase estimate used by the validated VEST SXR
viewer's mode analysis.
"""
time = np.asarray(time, dtype=float)
analytic = hilbert(np.asarray(signal, dtype=float))
index = int(np.argmin(np.abs(time - float(t_eval))))
phase_series = np.degrees(np.angle(analytic))
envelope_series = np.abs(analytic)
return (
float(phase_series[index]),
float(envelope_series[index]),
index,
phase_series,
envelope_series,
)Instantaneous phase and envelope of a band-limited signal at one time.
| Name | Type | Unit | Description |
|---|---|---|---|
signal | array_like | V | A band-passed, roughly monochromatic trace. |
time | array_like | s | Its time base. |
t_eval | float | s | Time at which to report the phase. |
| Returns | |||
| — | tuple | - | The phase in degrees and the envelope in volts at the nearest sample, that sample’s index, and the full phase and envelope series. |
Convention
Phase comes from the analytic signal and is wrapped to the principal branch, so it runs within a full turn and jumps rather than accumulating. The sample nearest the requested time is used; no interpolation.
Applicability · Limitations · Provenance
Applicability
Machine-independent.
Limitations
Meaningful only for a band-passed input. The analytic signal of a
broadband trace has a phase that does not correspond to any single mode, so
filter first with sxr_band_signals. The Hilbert transform is also
poorly behaved at the record edges, so a time near either end is unreliable.
Provenance
- The analytic-signal phase estimate used by the validated VEST SXR viewer’s mode analysis.
load_te_ratio_calibration
Machine-independentConvention-sensitive
source
load_te_ratio_calibration(path=None)
Show source vaft/process/soft_x_rays.py, lines 383–449
def load_te_ratio_calibration(path=None):
"""Load a ratio-to-temperature table and build its interpolator.
Parameters
----------
path : str or path-like, optional
Calibration table with ``te`` and ``ratio`` columns. Defaults to the
packaged VEST beryllium/aluminium table [-].
Returns
-------
tuple
The interpolator mapping ratio to temperature, the temperature column in
electron-volts, and the ratio column, dimensionless [-].
Raises
------
ValueError
The table lacks either column, or holds fewer than two valid points.
Convention
----------
**The interpolator extrapolates rather than clipping**, so a ratio outside the
table returns an extrapolated temperature, not the nearest tabulated one. A
caller that needs out-of-range samples rejected must test the ratio itself.
Column names are matched case-insensitively after stripping.
Defaults
--------
The packaged VEST beryllium/aluminium table is a diagnostic calibration,
shipped with the package and described in the data directory's own notes.
Applicability
-------------
Machine-independent. The table is an argument; only the packaged default is
the VEST filter pair, and a different filter combination supplies its own.
Limitations
-----------
Non-finite rows are dropped silently. The two-filter method assumes a thermal
spectrum, so the temperature it returns is meaningless for a non-thermal one.
Provenance
----------
.. [1] The packaged VEST beryllium/aluminium ratio calibration,
``vaft/data/legacy/sxr_te_ratio_be_al.csv``.
"""
if path is None:
from vaft.data.resources import data_path
path = data_path(TE_RATIO_TABLE)
table = pd.read_csv(path)
columns = {c.strip().lower(): c for c in table.columns}
if "te" not in columns or "ratio" not in columns:
raise ValueError(
"the calibration table needs 'te' and 'ratio' columns; "
f"found {list(table.columns)}"
)
te = table[columns["te"]].to_numpy(dtype=float)
ratio = table[columns["ratio"]].to_numpy(dtype=float)
good = np.isfinite(te) & np.isfinite(ratio)
if good.sum() < 2:
raise ValueError("the calibration table holds fewer than two valid points.")
interpolator = interp1d(
ratio[good], te[good], fill_value="extrapolate", bounds_error=False
)
return interpolator, te[good], ratio[good]Load a ratio-to-temperature table and build its interpolator.
| Name | Type | Unit | Description |
|---|---|---|---|
path | str or path-like, optional | - | Calibration table with |
| Returns | |||
| — | tuple | - | The interpolator mapping ratio to temperature, the temperature column in electron-volts, and the ratio column, dimensionless. |
Convention
The interpolator extrapolates rather than clipping, so a ratio outside the table returns an extrapolated temperature, not the nearest tabulated one. A caller that needs out-of-range samples rejected must test the ratio itself. Column names are matched case-insensitively after stripping.
Raises
ValueErrorThe table lacks either column, or holds fewer than two valid points.
Defaults · Applicability · Limitations · Provenance
Defaults
The packaged VEST beryllium/aluminium table is a diagnostic calibration, shipped with the package and described in the data directory’s own notes.
Applicability
Machine-independent. The table is an argument; only the packaged default is the VEST filter pair, and a different filter combination supplies its own.
Limitations
Non-finite rows are dropped silently. The two-filter method assumes a thermal spectrum, so the temperature it returns is meaningless for a non-thermal one.
Provenance
- The packaged VEST beryllium/aluminium ratio calibration,
vaft/data/legacy/sxr_te_ratio_be_al.csv.
rank_toroidal_mode_numbers
Machine-independentConvention-sensitive
source
rank_toroidal_mode_numbers(theta_a_deg, phase_a_deg, theta_b_deg, phase_b_deg, n_max)
Rank candidate toroidal mode numbers from phases measured at two locations.
| Name | Type | Unit | Description |
|---|---|---|---|
theta_a_deg | float | deg | Toroidal angle of the first observation point. |
phase_a_deg | float | deg | Measured phase there. |
theta_b_deg | float | deg | Toroidal angle of the second point. |
phase_b_deg | float | deg | Measured phase there. |
n_max | int | - | Largest magnitude of mode number to consider. |
| Returns | |||
| — | tuple of ToroidalModeCandidate | deg | Every candidate with its anchor offset and wrapped residual, best first |
Convention
For each candidate the wrapped phase-versus-angle line is anchored exactly at the first point and scored by the wrapped residual at the second. Zero is excluded, since it carries no toroidal structure. Candidates sort by absolute residual, then by absolute mode number, and a positive mode number wins a remaining tie over its negative counterpart, which is a tie-break, not physics.
Raises
ValueErrorThe two points share a toroidal angle, so no mode number can be inferred.
Applicability · Limitations · Provenance
Applicability
Machine-independent. The port angles are arguments; the VEST pair used in practice is a worked example, not a built-in.
Limitations
Two points cannot resolve aliasing. A candidate and one differing by
360/|dtheta| produce identical residuals; for the VEST ports at zero and
120 degrees that period is three. Every degenerate candidate is returned with
an equal residual and none is physically privileged; choosing among them
needs independent information such as frequency scaling, mode structure, or a
third port.
The phases must come from the same band and the same filtering convention, or the residual compares two different quantities.
Provenance
- The two-point toroidal mode-number estimate of the validated VEST SXR viewer, and its documented aliasing degeneracy.
sxr_band_signals
Machine-independentConvention-sensitive
source
sxr_band_signals(time, data, *, baseline_start, bands, fs, order=2, time_range=None, channels=None, dead_channels=(), zero_phase=True)
Baseline, window and band-pass chord signals into named frequency bands.
| Name | Type | Unit | Description |
|---|---|---|---|
time | array_like | s | Sample times, shared by every channel. |
data | array_like | V | Signals as |
baseline_start | float or None | s | Start of the quiet tail, or |
bands | mapping of str to sequence of float | Hz | Named |
fs | float | Hz | Sample rate. |
order | int, optional | - | Butterworth order for every band. |
time_range | sequence of float, optional | s | Analysis window as |
channels | sequence of int, optional | - | Row indices to process; all rows when omitted. |
dead_channels | sequence of int, optional | - | Rows whose band output is forced to zero. |
zero_phase | bool, optional | - |
|
| Returns | |||
| — | SXRBandResult | V | The windowed time base, the raw windowed signals, one array per band, and the channel indices selected. |
Convention
The band-pass is zero phase by default (zero_phase=True), so no
feature moves in time. That matters because the phase read off this output by
hilbert_instantaneous_phase feeds a toroidal mode number. Pass
zero_phase=False if causal filtering is explicitly required.
A dead channel’s band output is zeroed but its raw trace is kept, so it stays visible in a raw map instead of disappearing.
Raises
ValueErrorThe time range selects no samples.
Processing steps · Defaults · Applicability · Limitations · Provenance
Processing steps
- Baseline-correct, unless the caller says the data already is.
- Restrict to the analysis window.
- Select the requested channels.
- Band-pass each into every named band, substituting zeros for dead channels.
Defaults
order = 2 is a numerical convenience.
Applicability
Machine-independent.
Limitations
Vacuum-reference correction is not applied; run
sxr_subtract_vacuum_reference first when it is wanted. Band edges are
passed straight to the filter, so a band reaching the Nyquist frequency raises
from SciPy rather than being clipped. Filtering is applied directly to the
windowed segment (preserving legacy viewer parity); under zero_phase=True,
boundary transients occur at both edges of time_range extending over the
filter settling time. Windows shorter than the filter padding length
(3 * (2 * order + 1) samples, 15 for order 2) raise from SciPy under
zero_phase=True.
Provenance
- The validated VEST SXR viewer’s band decomposition.
sxr_baseline_correction
Machine-independentConvention-sensitive
source
sxr_baseline_correction(time, data, baseline_start)
Show source vaft/process/soft_x_rays.py, lines 96–156
def sxr_baseline_correction(time, data, baseline_start: float) -> np.ndarray:
"""Zero each channel against the quiet tail after the plasma.
Parameters
----------
time : array_like
Sample times, shared by every channel [s].
data : array_like
Signals as ``(n_channels, n_samples)``, or one trace [V].
baseline_start : float
Time from which the record is taken to be quiet [s].
Returns
-------
np.ndarray
The signals with each channel's own zero level removed [V].
Raises
------
ValueError
The time base and the sample axis disagree in length.
Convention
----------
The zero level is per channel, not shared, because the detectors have
different dark levels. The mean of the tail is used, not a fitted trend, so a
drift through the shot survives.
Defaults
--------
When no sample lies at or beyond *baseline_start* the last 1000 samples are
used instead. That fallback is a validated-workflow default carried from the
VEST SXR viewer.
Applicability
-------------
Machine-independent.
Limitations
-----------
Assumes the tail is genuinely quiet. A record that ends while the plasma is
still radiating has its baseline biased by that signal, and the fallback makes
that silent rather than an error.
Provenance
----------
.. [1] The validated VEST SXR viewer, whose baseline convention and
last-1000-sample fallback this reproduces.
"""
time = np.asarray(time, dtype=float)
values = _as_channel_matrix(data)
if time.size != values.shape[1]:
raise ValueError(
f"time and data must share the sample axis; got {time.size} and {values.shape[1]}"
)
mask = time >= float(baseline_start)
if np.any(mask):
baseline = values[:, mask].mean(axis=1, keepdims=True)
else:
baseline = values[:, -1000:].mean(axis=1, keepdims=True)
return values - baselineZero each channel against the quiet tail after the plasma.
| Name | Type | Unit | Description |
|---|---|---|---|
time | array_like | s | Sample times, shared by every channel. |
data | array_like | V | Signals as |
baseline_start | float | s | Time from which the record is taken to be quiet. |
| Returns | |||
| — | np.ndarray | V | The signals with each channel’s own zero level removed. |
Convention
The zero level is per channel, not shared, because the detectors have different dark levels. The mean of the tail is used, not a fitted trend, so a drift through the shot survives.
Raises
ValueErrorThe time base and the sample axis disagree in length.
Defaults · Applicability · Limitations · Provenance
Defaults
When no sample lies at or beyond baseline_start the last 1000 samples are used instead. That fallback is a validated-workflow default carried from the VEST SXR viewer.
Applicability
Machine-independent.
Limitations
Assumes the tail is genuinely quiet. A record that ends while the plasma is still radiating has its baseline biased by that signal, and the fallback makes that silent rather than an error.
Provenance
- The validated VEST SXR viewer, whose baseline convention and last-1000-sample fallback this reproduces.
sxr_cwt_spectrogram
Machine-independentConvention-sensitive
source
sxr_cwt_spectrogram(signal, fs, f0, f1, n_freq)
Show source vaft/process/soft_x_rays.py, lines 849–919
def sxr_cwt_spectrogram(signal, fs: float, f0: float, f1: float, n_freq: int):
"""Continuous-wavelet magnitude scalogram of one trace.
Parameters
----------
signal : array_like
The trace [V].
fs : float
Sample rate [Hz].
f0 : float
Lowest frequency of the scalogram [Hz].
f1 : float
Highest frequency [Hz].
n_freq : int
Number of frequencies between them [-].
Returns
-------
tuple of np.ndarray
The frequency axis, ascending, and the magnitude as
``(n_freq, n_samples)`` [-].
Raises
------
ImportError
The optional wavelet package is not installed.
Convention
----------
Frequencies are returned ascending, which reverses the underlying library's
own descending order, and the magnitude rows are reversed to match. A wavelet
transform trades frequency resolution for time resolution as frequency rises,
unlike the fixed-window short-time transform.
Defaults
--------
Single-threaded execution is a numerical convenience, keeping the call
deterministic and avoiding a thread pool inside a per-channel loop.
Applicability
-------------
Machine-independent.
Limitations
-----------
Needs an optional package that is not a VAFT dependency. The short-time
transform in :func:`vaft.process.fluctuation.compute_spectrogram` covers the
default time-frequency need without it. The input is cast to single precision
by that library.
Provenance
----------
.. [1] The optional ``fcwt`` continuous-wavelet implementation; the
alternative path is :mod:`vaft.process.fluctuation`.
"""
try:
import fcwt as fcwt_lib
except ImportError as error:
raise ImportError(
"the optional 'fcwt' package is not installed; run 'pip install fcwt' "
"or use vaft.process.fluctuation.compute_spectrogram (STFT) instead."
) from error
frequencies, out = fcwt_lib.cwt(
np.asarray(signal, dtype=np.float32),
int(fs),
float(f0),
float(f1),
int(n_freq),
nthreads=1,
)
return np.asarray(frequencies)[::-1], np.abs(out[::-1, :])Continuous-wavelet magnitude scalogram of one trace.
| Name | Type | Unit | Description |
|---|---|---|---|
signal | array_like | V | The trace. |
fs | float | Hz | Sample rate. |
f0 | float | Hz | Lowest frequency of the scalogram. |
f1 | float | Hz | Highest frequency. |
n_freq | int | - | Number of frequencies between them. |
| Returns | |||
| — | tuple of np.ndarray | - | The frequency axis, ascending, and the magnitude as |
Convention
Frequencies are returned ascending, which reverses the underlying library’s own descending order, and the magnitude rows are reversed to match. A wavelet transform trades frequency resolution for time resolution as frequency rises, unlike the fixed-window short-time transform.
Raises
ImportErrorThe optional wavelet package is not installed.
Defaults · Applicability · Limitations · Provenance
Defaults
Single-threaded execution is a numerical convenience, keeping the call deterministic and avoiding a thread pool inside a per-channel loop.
Applicability
Machine-independent.
Limitations
Needs an optional package that is not a VAFT dependency. The short-time
transform in vaft.process.fluctuation.compute_spectrogram covers the
default time-frequency need without it. The input is cast to single precision
by that library.
Provenance
- The optional
fcwtcontinuous-wavelet implementation; the alternative path isvaft.process.fluctuation.
sxr_electron_temperature
Machine-independentConvention-sensitive
source
sxr_electron_temperature(time, data, pairs, *, calibration, baseline_start, fs, lowpass_cutoff=50000.0, al_gain=1.07, al_threshold=0.1, detrend_window=400, order=2, zero_phase=True, time_range=None)
Semantics: produces electron_temperature (ontology)
Electron temperature from the two-filter signal ratio, chord by chord.
| Name | Type | Unit | Description |
|---|---|---|---|
time | array_like | s | Sample times, shared by every channel. |
data | array_like | V | Signals as |
pairs | sequence of sequence of int | - |
|
calibration | callable | - | Maps a signal ratio to a temperature; see |
baseline_start | float or None | s | Start of the quiet tail, or |
fs | float | Hz | Sample rate. |
lowpass_cutoff | float, optional | Hz | Conditioning low-pass cut-off. |
al_gain | float, optional | - | Relative sensitivity of the aluminium channel. |
al_threshold | float, optional | V | Conditioned aluminium level below which a sample is invalid. |
detrend_window | int, optional | - | Width of the centred rolling trend, in samples. |
order | int, optional | - | Butterworth order. |
zero_phase | bool, optional | - |
|
time_range | sequence of float, optional | s | Analysis window as |
| Returns | |||
| — | SXRTemperatureResult | - | The windowed time base, the temperature per chord in electron-volts, and its percentage deviation from the rolling trend. |
Convention
The low pass is zero phase by default (zero_phase=True), matching
the convention of sxr_band_signals and preserving exact temporal
alignment with other diagnostics and fast MHD events. Pass
zero_phase=False to reproduce legacy causal filtering behavior
with filter group delay.
The relative fluctuation is a percentage of the rolling trend, and the trend is centred, so it uses samples on both sides.
Processing steps · Defaults · Applicability · Limitations · Provenance
Processing steps
- Baseline-correct, unless the caller says the data already is.
- Restrict to the analysis window.
- Low-pass both channels of each pair.
- Scale the aluminium channel by its relative sensitivity.
- Take the ratio and map it through the calibration.
- Subtract a centred rolling trend to get the relative fluctuation.
- Invalidate samples whose conditioned aluminium level is at or below the threshold.
Defaults
The 50 kHz cut-off, the 1.07 aluminium gain, the 0.10 V threshold and the
400-sample trend window are validated-workflow defaults, the settings of the
validated VEST viewer. order = 2 is a numerical convenience.
Applicability
Machine-independent. The defaults are VEST viewer practice and the calibration is supplied by the caller.
Limitations
The two-filter method assumes a thermal spectrum. Invalid samples are NaN rather than removed, so a caller must honour them. Vacuum-reference correction is not applied here.
Provenance
- The validated VEST SXR viewer, whose conditioning settings, validity threshold and detrending this reproduces.
sxr_subtract_vacuum_reference
Machine-independentConvention-sensitive
source
sxr_subtract_vacuum_reference(data, reference_data, *, cutoff, fs, order=2, zero_phase=True)
Subtract a low-passed vacuum shot to remove poloidal-field pickup.
An optional step. Nothing else in this module calls it, so the main path is always baseline, then window, then filter, on exactly the data the caller supplied.
| Name | Type | Unit | Description |
|---|---|---|---|
data | array_like | V | Plasma-shot signals as |
reference_data | array_like | V | Vacuum-shot signals with the same channel count. |
cutoff | float | Hz | Low-pass cut-off applied to the reference. |
fs | float | Hz | Sample rate. |
order | int, optional | - | Butterworth order. |
zero_phase | bool, optional | - |
|
| Returns | |||
| — | np.ndarray | V | The plasma signals with the pickup removed, truncated to the shorter record. |
Convention
Pickup from the poloidal field coil ramps appears identically in a vacuum shot, so low-passing that record and subtracting it channel-wise removes the common drive while leaving plasma fluctuations untouched.
The low pass is zero phase by default (zero_phase=True), preserving
exact temporal alignment with the un-delayed plasma shot. Pass
zero_phase=False to reproduce legacy causal filtering behavior.
Both inputs should already be baseline-corrected.
Raises
ValueErrorThe two inputs have different channel counts.
Defaults · Applicability · Limitations · Provenance
Defaults
order = 2 is a numerical convenience matching the rest of the module’s
conditioning.
Applicability
Machine-independent.
Limitations
Assumes the vacuum shot reproduces the plasma shot’s coil programme. Records
are truncated to the shorter of the two rather than aligned in time, so two
records with different start triggers are subtracted misaligned. The reference
is truncated to length n before filtering, so both leading and trailing
edges are subject to filter boundary transients. Inputs shorter than the
filter padding length (3 * (order + 1) samples for low-pass) raise from
SciPy under zero_phase=True.
Provenance
- The validated VEST SXR viewer’s optional PF-noise removal step.
sxr_te_pairs_from_ods
VEST-specificConvention-sensitive
source
sxr_te_pairs_from_ods(ods, array)
Show source vaft/process/soft_x_rays.py, lines 452–522
def sxr_te_pairs_from_ods(ods: Any, array: str) -> tuple[tuple[int, int], ...]:
"""Pair the two filters' channels of one array by the chord they view.
Parameters
----------
ods : ODS
Carries ``soft_x_rays.channel`` with the identifiers the VEST mapper
writes [-].
array : str
Which array to pair within [-].
Returns
-------
tuple of tuple of int
One ``(beryllium_index, aluminium_index)`` pair per shared chord, ordered
by chord number [-].
Raises
------
ValueError
No chord in that array carries both filters.
Convention
----------
Channel identifiers are ``{daq}:{array}:{filter}:{chord}``, written by the
VEST digitizer mapper. Pairing on the chord number rather than on position in
the channel list is what absorbs a per-block wiring reversal: the two filter
blocks need not be ordered the same way.
Returns index pairs, not data, so it changes no measurement.
Applicability
-------------
VEST-specific. Depends on the identifier grammar and the filter names written
by :func:`vaft.machine_mapping.soft_x_rays.soft_x_rays_from_digitizer_csv`;
another machine's mapper would need its own pairing rule.
Limitations
-----------
A channel whose identifier does not split into four parts, or whose chord is
not an integer, is skipped silently, so a mis-mapped channel is absent from
the result rather than reported.
Provenance
----------
.. [1] :func:`vaft.machine_mapping.soft_x_rays.soft_x_rays_from_digitizer_csv`,
which writes the identifiers this parses.
"""
be: dict[int, int] = {}
al: dict[int, int] = {}
channels = ods["soft_x_rays.channel"]
for index in range(len(channels)):
identifier = str(channels[index]["identifier"])
parts = identifier.split(":")
if len(parts) != 4 or parts[1] != str(array):
continue
try:
chord = int(parts[3])
except ValueError:
continue
if parts[2] == "Be":
be[chord] = index
elif parts[2] == "Al":
al[chord] = index
shared = sorted(set(be) & set(al))
if not shared:
raise ValueError(
f"array {array!r} has no chords with both Be and Al channels; "
"is this a two-filter array mapped by soft_x_rays_from_digitizer_csv?"
)
return tuple((be[chord], al[chord]) for chord in shared)Pair the two filters’ channels of one array by the chord they view.
| Name | Type | Unit | Description |
|---|---|---|---|
ods | ODS | - | Carries |
array | str | - | Which array to pair within. |
| Returns | |||
| — | tuple of tuple of int | - | One |
Convention
Channel identifiers are {daq}:{array}:{filter}:{chord}, written by the
VEST digitizer mapper. Pairing on the chord number rather than on position in
the channel list is what absorbs a per-block wiring reversal: the two filter
blocks need not be ordered the same way.
Returns index pairs, not data, so it changes no measurement.
Raises
ValueErrorNo chord in that array carries both filters.
Applicability · Limitations · Provenance
Applicability
VEST-specific. Depends on the identifier grammar and the filter names written
by vaft.machine_mapping.soft_x_rays.soft_x_rays_from_digitizer_csv;
another machine’s mapper would need its own pairing rule.
Limitations
A channel whose identifier does not split into four parts, or whose chord is not an integer, is skipped silently, so a mis-mapped channel is absent from the result rather than reported.
Provenance
vaft.machine_mapping.soft_x_rays.soft_x_rays_from_digitizer_csv, which writes the identifiers this parses.
synthetic_island_soft_x_rays
Machine-independent
source
synthetic_island_soft_x_rays(equilibrium, island, sightlines, *, time=0.0, emissivity_profile=None, model='flatten', domain=None, amplitude=1.0, smoothing=0.1, hard_mask=False, keep_fields=True)
Line-integrated soft-X-ray signals of a rotating island on an equilibrium.
| Name | Type | Unit | Description |
|---|---|---|---|
equilibrium | EquilibriumData or source | - | The axisymmetric equilibrium, the only source of plasma geometry; anything |
island | MagneticIslandSpec | - | Mode numbers, outboard-midplane full width, phase and rotation. |
sightlines | Sightlines | - | The chords, each in the poloidal plane at its own toroidal angle. |
time | float or array_like, optional | s | Times at which to evaluate the island phase. |
emissivity_profile | callable or tuple of array_like, optional | emissivity unit | Axisymmetric background |
model | str, optional | - |
|
domain | tuple of array_like, optional | m |
|
amplitude | float, optional | - or emissivity unit | Island amplitude |
smoothing | float, optional | - | Width of the island mask edge in helical-flux units. |
hard_mask | bool, optional | - | Use a binary island mask. |
keep_fields | bool, optional | - | Keep the emissivity fields on the result; |
| Returns | |||
| — | SyntheticSXRResult | emissivity unit times m | Time, the chord planes’ toroidal angles, the emissivity and its island part on the equilibrium grid per time and plane, and the chord brightness per time and channel. |
Raises
ValueErrorThe island cannot be placed on the equilibrium, or the emissivity model or profile is invalid.
Processing steps · Input semantics · Output semantics · Applicability · Limitations · Provenance
Processing steps
- Build the island topology once, which fixes the resonant surface, the straight-field-line angle and the displacement.
- Group the chords by toroidal angle and build one path-length operator per plane, clipped to the domain.
- For every time and plane, rephase the island, form the emissivity, and integrate it along that plane’s chords.
Input semantics
A prescribed island on a reconstructed or analytic equilibrium, and chord geometry from the machine mapping; no measured signal enters.
Output semantics
Synthetic chord brightness in the emissivity’s unit times metres, before any detector, filter or etendue response, comparable to measured signals only up to a per-channel calibration.
Applicability
Machine-independent.
Limitations
A forward model only: no inversion, no noise, pencil-beam chords. Each chord is assumed to lie in one poloidal plane. The island rotates rigidly at a fixed width.
Provenance
- Le, T. X. K. et al., Plasma Phys. Control. Fusion 68, 065003 (2026), a rotating-island SXR forward model of the same scope.
- Dreval, M. B. et al., Plasma Phys. Control. Fusion 63, 065006 (2021) and 65, 035001 (2023), for SXR forward modelling of MHD modes.
- Jang, J. Y. et al., Rev. Sci. Instrum. 93, 093506 (2022), the VEST SXR arrays.