Skip to content

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

NameDescription
OutputAnalysisSpectral diagnostics of a run's products, as out.analysis.<kind>(product, ...).
OutputPlotsPlots of a whole run, as out.plot.<kind>(...), constructed as OutputPlots(out).
ProfilePlotsPlots 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

NameTypeDescription
outputOutputThe 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

NameTypeDefaultDescription
productstr or xarray.DataArrayrequiredA product name (e.g. "mhd/velocity"), evaluated with out.evaluate, or an already selected array.
dimstrrequiredThe dimension to transform.
detrendboolFalseSubtract the mean along dim first. Default: False.
window(None, 'hann')NoneMultiply by a periodic Hann window (see [hann()][hann]) first. Default: None (boxcar).

Returns

xarray.DataArray
Complex coefficients, with dim replaced by omega (time) or k_<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

NameTypeDefaultDescription
productstr or xarray.DataArrayrequiredA product name (e.g. "mhd/velocity"), evaluated with out.evaluate, or an already selected array.
dimsstr or sequence of strNoneNon-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_minfloat1e-08Finite, positive lowest frequency considered, which excludes DC. Default: 1e-8.
pad_binsint0Nonnegative 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

NameTypeDefaultDescription
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".
gammafloat5 / 3The 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_field and pressure are all None.

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

NameTypeDefaultDescription
productstr or xarray.DataArrayrequiredA product name (e.g. "mhd/velocity"), evaluated with out.evaluate, or an already selected array.
dimsstr 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.
namesstr or sequence of str('m', 'n')The name of the mode number of each dimension, one per dimension. Default: ("m", "n").
periodsfloat or sequence of float1.0Each 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 names and 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

NameTypeDefaultDescription
productstr or xarray.DataArrayrequiredA product name (e.g. "mhd/velocity"), evaluated with out.evaluate, or an already selected array.
detrendboolFalseSubtract the temporal mean first. Default: False.
window(None, 'hann')NoneMultiply 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

NameTypeDescription
outputOutputThe 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

NameTypeDefaultDescription
n1int8Grid lines along eta1. Default: 8.
n2int32Grid lines along eta2. Default: 32.
n3int32Grid lines along eta3. Default: 32.
surfaceboolTrueDraw the translucent boundary surface. Default: True.

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

NameTypeDefaultDescription
partssequence of strNoneThe energies drawn in the first panel. Default: the scalars [energy_names()][energy_names] finds (en_* and *_energy), except total.
totalstr 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.
groupsdict of str to list of strNoneA 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.
logyboolFalseUse 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

NameTypeDefaultDescription
axmatplotlib.axes.AxesNoneThe 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

NameTypeDefaultDescription
scalarsstr'p0'One of equil’s profile methods ("p0", "n0", …). Default: "p0".
cmapstr'viridis'The colormap. Default: "viridis".

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

NameTypeDefaultDescription
nameslist of strNoneScalars to show; all by default.
relative_tostrNoneShow every scalar divided by this one.
logyboolFalseLogarithmic 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

NameTypeDescription
outputOutputThe 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

NameTypeDefaultDescription
return_figboolTrueReturn the rendered figure (scope-profiler’s own default is to return None). Default: True.
verboseboolFalseLet scope-profiler print progress information. Default: False.
**kwargs{}Passed on to scope-profiler’s plot_callgraph (rank, include/exclude, backend, compact, fluid, …).

Returns

tuple or plotly.graph_objects.Figure or None
Whatever scope-profiler returns: (fig, axes) for the default matplotlib backend, a Plotly figure with backend="plotly", None with return_fig=False.

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

NameTypeDefaultDescription
return_figboolTrueReturn the rendered figure (scope-profiler’s own default is to return None). Default: True.
verboseboolFalseLet scope-profiler print progress information. Default: False.
**kwargs{}Passed on to scope-profiler’s plot_flame (ranks, include/exclude, backend, filepath, …).

Returns

tuple or plotly.graph_objects.Figure or None
Whatever scope-profiler returns: (fig, axes) for the default matplotlib backend, a Plotly figure with backend="plotly", None with return_fig=False.

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

NameTypeDefaultDescription
return_figboolTrueReturn the rendered figure (scope-profiler’s own default is to return None). Default: True.
verboseboolFalseLet scope-profiler print progress information. Default: False.
**kwargs{}Passed on to scope-profiler’s plot_gantt (ranks, include/exclude, backend, filepath, min_duration, …).

Returns

tuple or plotly.graph_objects.Figure or None
Whatever scope-profiler returns: (fig, axes) for the default matplotlib backend, a Plotly figure with backend="plotly", None with return_fig=False.

Examples

>>> out.plot.profile.gantt()