plasma_plots.output_accessors
Plots and diagnostics of a whole run, as out.plot and out.analysis.
Importing plasma_plots adds two properties to struphy’s Output (when struphy is
installed; without importing struphy itself, which takes seconds: the properties are attached
when struphy’s output module is imported, before or after plasma_plots): out.plot ([OutputPlots][OutputPlots]) for optional plots that need a whole run, and
out.analysis ([OutputAnalysis][OutputAnalysis]) for spectral diagnostics of its products.
Plots and diagnostics of a single array live on the array, see
PlasmaAccessor:
out.em_fields.phi_log.plasma.plot.slice(...), or from a value returned by
out.evaluate("em_fields/phi_log").
Classes
| Name | Description |
|---|---|
OutputAnalysis | Spectral diagnostics of a run's products, as out.analysis.<kind>(product, ...). |
OutputPlots | Plots of a whole run, as out.plot.<kind>(...), constructed as OutputPlots(out). |
ProfilePlots | Plots of one run's timing regions (out.profile.results), as out.plot.profile.<kind>(...). |
OutputAnalysisclass#
class OutputAnalysis(output: 'Output')Spectral diagnostics of a run’s products, as out.analysis.<kind>(product, ...).
product is a product name ("mhd/velocity", evaluated with out.evaluate) or an
already selected xarray.DataArray. Select a component, slice or time interval before
transforming when you do not need the whole field: the selected values are loaded into
memory. The same diagnostics, and more, are available on any array as
array.plasma.analysis.<kind>(...); see plasma_plots.spectral.
Parameters
| Name | Type | Description |
|---|---|---|
output | Output | The struphy run whose products are analyzed. Usually reached as out.analysis. |
Examples
>>> spectrum = out.analysis.time_fft(phi.isel(eta2=0, eta3=0))>>> modes = out.analysis.mode_spectrum("em_fields/phi_log")fftmethod#
def fft(product, *, dim: str, detrend: bool = False, window: str | None = None)Compute two-sided Fourier coefficients of a product along dim.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
product | str or xarray.DataArray | required | A product name (e.g. "mhd/velocity"), evaluated with out.evaluate, or an
already selected array. |
dim | str | required | The dimension to transform. |
detrend | bool | False | Subtract the mean along dim first. Default: False. |
window | (None, 'hann') | None | Multiply by a periodic Hann window (see [hann()][hann]) first. Default: None (boxcar). |
Returns
xarray.DataArray- Complex coefficients, with
dimreplaced byomega(time) ork_<dim>.
Examples
>>> out.analysis.fft(phi.isel(t=-1, eta2=0, eta3=0), dim="eta1")filter_timemethod#
def filter_time(product, *, dims=None, omega_min: float = 1e-08, pad_bins: int = 0)Reconstruct the dominant temporal frequency band of a product.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
product | str or xarray.DataArray | required | A product name (e.g. "mhd/velocity"), evaluated with out.evaluate, or an
already selected array. |
dims | str or sequence of str | None | Non-time dimensions to sum the power over before choosing the band. Default: all
dimensions except t and component. Pass dims=() for independent filtering at
each point. |
omega_min | float | 1e-08 | Finite, positive lowest frequency considered, which excludes DC. Default: 1e-8. |
pad_bins | int | 0 | Nonnegative number of extra bins on each side of the band. Default: 0. |
Returns
TimeFilterResult- The filtered field and the reduced spectrum with the selected band.
Examples
>>> result = out.analysis.filter_time(phi)>>> result.filtered.plasma.plot.slice(t=-1, eta3=0)linear_mhd_energiesmethod#
def linear_mhd_energies(velocity='mhd/velocity', b_field='em_fields/b_field', pressure='mhd/pressure', gamma: float = 5 / 3)Compute LinearMHD’s energy scalars from fields, as a Dataset of time series.
The scalars are en_U, en_B, en_thermal, en_p and
en_tot = en_U + en_B + en_thermal. Same definitions as the scalars saved during the run
(en_U = 1/2 u^T M2n u, …),
with the run’s domain and equilibrium (n0, p0), but evaluated by quadrature
on the post-processing grid, so they also work for fields that were never simulated:
pass a filtered array (e.g. filter_time(...).filtered) to get the energy in one mode.
Each argument is a raw field name (evaluated at the Gauss points of
quadrature_grid(), in its FEEC space’s own representation), an array in that
representation (on the Gauss grid its weights are exact; elsewhere see
quadrature_weights()), or None to skip it: 2-form
components for velocity and b_field (out.evaluate("mhd/velocity", representation="2")), a 3-form for pressure (representation="3"). The default
post-processing products are in other representations ("norm", "0") and would
give wrong energies. Points where p0 vanishes are left out of en_thermal.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
velocity | (str, xarray.DataArray or None) | 'mhd/velocity' | The velocity as 2-form components (en_U, weighted by n0).
Default: "mhd/velocity". |
b_field | (str, xarray.DataArray or None) | 'em_fields/b_field' | The magnetic field as 2-form components (en_B). Default: "em_fields/b_field". |
pressure | (str, xarray.DataArray or None) | 'mhd/pressure' | The pressure as a 3-form (en_thermal, weighted by 1/p0, and en_p).
Default: "mhd/pressure". |
gamma | float | 5 / 3 | The adiabatic index: en_thermal is normalized by 1/gamma and
en_p = ∫ p / (gamma - 1). Default: 5/3. |
Returns
xarray.Dataset- One time series per computed scalar (only those whose fields were given), plus
en_tot.
Raises
ValueError- If
velocity,b_fieldandpressureare allNone.
Examples
>>> energies = out.analysis.linear_mhd_energies()>>> filtered = out.analysis.filter_time(... out.evaluate("mhd/velocity", representation="2")... ).filtered>>> out.analysis.linear_mhd_energies(... velocity=filtered, b_field=None, pressure=None... )mode_spectrummethod#
def mode_spectrum(product, *, dims=('eta2', 'eta3'), names=('m', 'n'), periods=1.0)Compute complex amplitudes of a product over poloidal/toroidal mode numbers.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
product | str or xarray.DataArray | required | A product name (e.g. "mhd/velocity"), evaluated with out.evaluate, or an
already selected array. |
dims | str or sequence of str | ('eta2', 'eta3') | The periodic dimensions to transform. Default: the two angles of the logical dimensions
(see plasma_plots.arrays.logical_dims()), ("eta2", "eta3") for Struphy. |
names | str or sequence of str | ('m', 'n') | The name of the mode number of each dimension, one per dimension.
Default: ("m", "n"). |
periods | float or sequence of float | 1.0 | Each direction’s period in its coordinate: one number for all, or one per dimension.
Default: the coordinate’s period attribute (see
plasma_plots.arrays.angle_period()), else 1.0. |
Returns
xarray.DataArray- Complex amplitudes over the mode numbers
namesand every remaining dimension.
Examples
>>> out.analysis.mode_spectrum("em_fields/phi_log")>>> out.analysis.mode_spectrum(phi.isel(t=-1), dims="eta3", names="n")quadrature_gridmethod#
def quadrature_grid()Return the run’s Gauss-Legendre quadrature points and weights in each logical direction.
The points (spline degree + 1 per element) and their weights for each of eta1,
eta2, eta3 form the grid on which spline fields squared integrate exactly.
Evaluate a field there (out.evaluate(name, eta1=etas["eta1"], ..., representation="2")), filter it, and linear_mhd_energies or field_energy(..., quadrature=weights) give its energy as the run’s own scalars would.
Returns
etasdict of str to numpy.ndarray- The points in
[0, 1]for"eta1","eta2","eta3". weightsdict of str to numpy.ndarray- The matching quadrature weights, summing to 1 in each direction.
Examples
>>> etas, weights = out.analysis.quadrature_grid()>>> b = out.evaluate(... "em_fields/b_field",... eta1=etas["eta1"],... eta2=etas["eta2"],... eta3=etas["eta3"],... representation="2",... )time_fftmethod#
def time_fft(product, *, detrend: bool = False, window: str | None = None)Compute one-sided temporal Fourier coefficients and per-bin power of a product.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
product | str or xarray.DataArray | required | A product name (e.g. "mhd/velocity"), evaluated with out.evaluate, or an
already selected array. |
detrend | bool | False | Subtract the temporal mean first. Default: False. |
window | (None, 'hann') | None | Multiply by a periodic Hann window (see [hann()][hann]) first. Default: None (boxcar). |
Returns
xarray.Dataset- The complex coefficients and the power over
omega.
Examples
>>> out.analysis.time_fft(phi.isel(eta1=0.5, eta2=0, eta3=0), window="hann")OutputPlotsclass#
class OutputPlots(output: 'Output')Plots of a whole run, as out.plot.<kind>(...), constructed as OutputPlots(out).
They return plotting-library objects with .show()
and .save(path), titled with the run’s numerical parameters. Plots of one product are
methods of that product, e.g. out.kinetic_ions.orbits.plasma.plot.trajectories().
Calling out.plot() itself gives the quick default plot, [scalars()][scalars].
Parameters
| Name | Type | Description |
|---|---|---|
output | Output | The struphy run to plot. |
Examples
>>> out.plot()>>> out.plot.energies(logy=True)>>> out.plot.domain_3d().show()profileproperty#
profile: 'ProfilePlots'Plots of this run’s timing regions, e.g. out.plot.profile.gantt().
Needs the optional scope-profiler extra (pip install "plasma-plots[profiling]")
and a run recorded with sim.run(profiling_activated=True).
Returns
ProfilePlots- The profiling plots of this run.
domain_3dmethod#
def domain_3d(n1: int = 8, n2: int = 32, n3: int = 32, surface: bool = True)Draw a PyVista wireframe of this run’s mapping (out.domain); call .show() on it.
Parameters
Returns
pyvista.Plotter- The scene, not yet shown.
Examples
>>> out.plot.domain_3d().show()>>> out.plot.domain_3d(n3=1).show()energiesmethod#
def energies(parts=None, total: str | None = 'en_tot', groups: dict | None = None, logy: bool = False, backend: Backend | None = None)Plot the run’s energy budget from its energy scalars (en_* or *_energy).
Shows the energy scalars, the relative drift of total, and, with groups
(e.g. {"wave": ["en_U", "en_B", "en_p"], "energetic ions": ["en_fv", "en_fB"]}), the
energy exchanged between them.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
parts | sequence of str | None | The energies drawn in the first panel. Default: the scalars [energy_names()][energy_names]
finds (en_* and *_energy), except total. |
total | str or None | 'en_tot' | The total energy; the second panel is left out if it is None or not among the
scalars. Default: "en_tot", or "total_energy" for a run that names its
energies that way. |
groups | dict of str to list of str | None | A label to the names it sums, e.g.
{"wave": ["en_U", "en_B", "en_p"], "energetic ions": ["en_fv", "en_fB"]}. Default:
no exchange panel. |
logy | bool | False | Use a logarithmic value axis in the first panel. Default: False. |
backend | ('matplotlib', 'plotly', 'tikz') | "matplotlib" | Draw with Matplotlib, as an interactive Plotly figure, or as TikZ/pgfplots code for
LaTeX (in result.fig; needs plotly or maxplotlib, see
plasma_plots.plotly_backend and plasma_plots.tikz_backend). Default:
the one set with plasma_plots.set_backend(), "matplotlib" unless changed. |
Returns
PlotResult- The figure, the axes and the drawn lines, titled with the run’s label.
Examples
>>> out.plot.energies()>>> out.plot.energies(... groups={... "wave": ["en_U", "en_B", "en_p"],... "energetic ions": ["en_fv", "en_fB"],... }... )equilibriummethod#
def equilibrium(ax=None, *, backend: Backend | None = None)Plot radial profiles of this run’s fluid equilibrium (out.equil, out.domain).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
ax | matplotlib.axes.Axes | None | The axes to draw into. Default: a new figure. |
backend | ('matplotlib', 'plotly', 'tikz') | "matplotlib" | Draw with Matplotlib, as an interactive Plotly figure, or as TikZ/pgfplots code for
LaTeX (in result.fig; needs plotly or maxplotlib, see
plasma_plots.plotly_backend and plasma_plots.tikz_backend). Default:
the one set with plasma_plots.set_backend(), "matplotlib" unless changed. |
Returns
PlotResult- The figure, the axes and the drawn lines.
Examples
>>> out.plot.equilibrium()equilibrium_3dmethod#
def equilibrium_3d(scalars: str = 'p0', cmap='viridis')Create a PyVista view of this run’s fluid equilibrium; call .show() on the returned plotter.
Parameters
Returns
pyvista.Plotter- The scene, not yet shown.
Examples
>>> out.plot.equilibrium_3d(scalars="p0").show()scalarsmethod#
def scalars(names=None, *, relative_to: str | None = None, logy: bool = False, backend: Backend | None = None)Overview of the scalar time series in one axes.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
names | list of str | None | Scalars to show; all by default. |
relative_to | str | None | Show every scalar divided by this one. |
logy | bool | False | Logarithmic value axis. |
backend | ('matplotlib', 'plotly', 'tikz') | "matplotlib" | Draw with Matplotlib, as an interactive Plotly figure, or as TikZ/pgfplots code for
LaTeX (in result.fig; needs plotly or maxplotlib, see
plasma_plots.plotly_backend and plasma_plots.tikz_backend). Default:
the one set with plasma_plots.set_backend(), "matplotlib" unless changed. |
Returns
PlotResult- The figure, the axes and the drawn lines, titled with the run’s label.
Examples
>>> out.plot.scalars()>>> out.plot.scalars(["en_U", "en_B"], logy=True)ProfilePlotsclass#
class ProfilePlots(output: 'Output')Plots of one run’s timing regions (out.profile.results), as out.plot.profile.<kind>(...).
Thin pass-throughs to scope-profiler <https://pypi.org/project/scope-profiler/>_’s own
plotting functions – see their docstrings for the full set of keyword arguments (ranks,
include/exclude, backend, filepath, …). Each returns whatever scope-profiler
itself returns: a (fig, axes) pair for the default matplotlib backend, or a Plotly figure
with backend="plotly".
Parameters
| Name | Type | Description |
|---|---|---|
output | Output | The struphy run whose out.profile.results are plotted. Usually reached as
out.plot.profile instead of constructed directly. |
Examples
>>> out.plot.profile.gantt()>>> out.plot.profile.flame(backend="plotly")callgraphmethod#
def callgraph(return_fig: bool = True, verbose: bool = False, **kwargs)The explicit call graph (which region calls which), without timings.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
return_fig | bool | True | Return the rendered figure (scope-profiler’s own default is to return None).
Default: True. |
verbose | bool | False | Let scope-profiler print progress information. Default: False. |
**kwargs | {} | Passed on to scope-profiler’s plot_callgraph
(rank, include/exclude, backend, compact, fluid, …). |
Returns
Examples
>>> out.plot.profile.callgraph()flamemethod#
def flame(return_fig: bool = True, verbose: bool = False, **kwargs)A flame chart reconstructing the call stack from region timings.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
return_fig | bool | True | Return the rendered figure (scope-profiler’s own default is to return None).
Default: True. |
verbose | bool | False | Let scope-profiler print progress information. Default: False. |
**kwargs | {} | Passed on to scope-profiler’s plot_flame
(ranks, include/exclude, backend, filepath, …). |
Returns
Examples
>>> out.plot.profile.flame()ganttmethod#
def gantt(return_fig: bool = True, verbose: bool = False, **kwargs)A timeline of every recorded region, one row per rank.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
return_fig | bool | True | Return the rendered figure (scope-profiler’s own default is to return None).
Default: True. |
verbose | bool | False | Let scope-profiler print progress information. Default: False. |
**kwargs | {} | Passed on to scope-profiler’s plot_gantt
(ranks, include/exclude, backend, filepath, min_duration, …). |
Returns
Examples
>>> out.plot.profile.gantt()