Analyzing AMReX Outputs From FLEKS

In this demo, we show how to analyze native AMReX field and particle outputs. Example data can be downloaded as follows:

import flekspy
from flekspy.util import download_testfile

url = "https://raw.githubusercontent.com/henry2004y/batsrus_data/master/fleks_particle_small.tar.gz"
download_testfile(url, "data")

Inheriting from the IDL procedures, we can pass strings to limit the plotting range (experimental, may be changed in the future):

ds = flekspy.load("data/fleks_particle_small/3d*amrex")
dc = ds.get_slice("z", 0.001)

f, axes = dc.plot(
    "Bx<(1.5e4)>(-1.5e4) ({rhos0}+{rhos1})<(1.3e21) pS0 uxs0", figsize=(12, 8)
)
dc.add_stream(axes[0], "Bx", "By", color="w")
dc.add_contour(axes[1], "Bx")
yt : [INFO     ] 2025-03-18 17:27:10,662 Parameters: current_time              = 40.0
yt : [INFO     ] 2025-03-18 17:27:10,662 Parameters: domain_dimensions         = [16  8  6]
yt : [INFO     ] 2025-03-18 17:27:10,663 Parameters: domain_left_edge          = [-0.0064 -0.0032 -0.0024]
yt : [INFO     ] 2025-03-18 17:27:10,664 Parameters: domain_right_edge         = [0.0064 0.0032 0.0024]
result=(self.get_variable('rhos0',unit)+self.get_variable('rhos1',unit))
result=(self.get_variable('pxxs0',unit)+self.get_variable('pyys0',unit)+self.get_variable('pzzs0',unit))/3
Plots at z =  0.001 code_length
_images/b1fc47296f8031b38a582552021bdb3907336b6eded64c38730bba505a2ecce0.png

Velocity Space Distributions

from flekspy.util import unit_one

filename = "data/fleks_particle_small/cut_*amrex"
ds = flekspy.load(filename)

# Add a user defined field. See yt document for more information about derived field.
ds.add_field(
    ds.pvar("unit_one"), function=unit_one, sampling_type="particle", units="code_mass"
)

x_field = "p_uy"
y_field = "p_uz"
z_field = "unit_one"
# z_field = "p_w"
xleft = [-0.001, -0.001, -0.001]
xright = [0.001, 0.001, 0.001]

### Select and plot the particles inside a box defined by xleft and xright
region = ds.box(xleft, xright)
pp = ds.plot_phase(
    x_field,
    y_field,
    z_field,
    region=region,
    unit_type="si",
    x_bins=64,
    y_bins=64,
    domain_size=(-0.0002, 0.0002, -0.0002, 0.0002),
)

pp.set_cmap(pp.fields[0], "turbo")

# plot.set_zlim(plot.fields[0], zmin, zmax)
pp.set_xlabel(r"$V_y$")
pp.set_ylabel(r"$V_z$")
# pp.set_colorbar_label(pp.fields[0], "pw")
pp.set_title(pp.fields[0], "Number density")
pp.set_font(
    {
        "size": 34,
        "family": "DejaVu Sans",
    }
)
pp.set_log(pp.fields[0], False)
pp.show()
yt : [INFO     ] 2025-03-18 17:27:12,797 Parameters: current_time              = 40.0
yt : [INFO     ] 2025-03-18 17:27:12,798 Parameters: domain_dimensions         = [16  8  6]
yt : [INFO     ] 2025-03-18 17:27:12,798 Parameters: domain_left_edge          = [-0.0064 -0.0032 -0.0024]
yt : [INFO     ] 2025-03-18 17:27:12,799 Parameters: domain_right_edge         = [0.0064 0.0032 0.0024]

If you need the direct phase space distributions together with the axis,

x, y, w = ds.get_phase(
    x_field,
    y_field,
    z_field,
    region=region,
    x_bins=64,
    y_bins=64,
    domain_size=(-0.0002, 0.0002, -0.0002, 0.0002),
)

To check the newly added field,

ad = ds.all_data()
ad[("particles", "unit_one")]
unyt_array([1., 1., 1., ..., 1., 1., 1.], 'code_mass')

Plot the location of particles that are inside a sphere

center = [0, 0, 0]
radius = 0.001
z_field = "unit_one"
# Object sphere is defined in yt/data_objects/selection_objects/spheroids.py
sp = ds.sphere(center, radius)
pp = ds.plot_particles(
    "p_x", "p_y", z_field, region=sp, unit_type="planet", x_bins=64, y_bins=64
)
pp.show()
yt : [INFO     ] 2025-03-18 17:27:13,805 xlim = -0.006400 0.006400
yt : [INFO     ] 2025-03-18 17:27:13,805 ylim = -0.003200 0.003200
yt : [INFO     ] 2025-03-18 17:27:13,808 xlim = -0.006400 0.006400
yt : [INFO     ] 2025-03-18 17:27:13,808 ylim = -0.003200 0.003200
yt : [INFO     ] 2025-03-18 17:27:13,811 Splatting (('particles', 'unit_one')) onto a 800 by 800 mesh using method 'ngp'

Plot the phase space of particles that are inside a sphere

pp = ds.plot_phase(
    "p_uy", "p_uz", z_field, region=sp, unit_type="planet", x_bins=64, y_bins=64
)
pp.show()

Plot the location of particles that are inside a disk

center = [0, 0, 0]
normal = [1, 1, 0]
radius = 0.0005
height = 0.0004
z_field = "unit_one"
# Object sphere is defined in yt/data_objects/selection_objects/disk.py
disk = ds.disk(center, normal, radius, height)
pp = ds.plot_particles(
    "p_x", "p_y", z_field, region=disk, unit_type="planet", x_bins=64, y_bins=64
)
pp.show()
yt : [INFO     ] 2025-03-18 17:27:14,636 xlim = -0.006400 0.006400
yt : [INFO     ] 2025-03-18 17:27:14,636 ylim = -0.003200 0.003200
yt : [INFO     ] 2025-03-18 17:27:14,639 xlim = -0.006400 0.006400
yt : [INFO     ] 2025-03-18 17:27:14,639 ylim = -0.003200 0.003200
yt : [INFO     ] 2025-03-18 17:27:14,640 Splatting (('particles', 'unit_one')) onto a 800 by 800 mesh using method 'ngp'

Plot the phase space of particles that are inside a disk

pp = ds.plot_phase(
    "p_uy", "p_uz", z_field, region=disk, unit_type="planet", x_bins=64, y_bins=64
)
pp.show()

Transform the velocity coordinates and visualize the phase space distribution

WIP

import flekspy, yt

l = [1, 0, 0]
m = [0, 1, 0]
n = [0, 0, 1]


def _vel_l(field, data):
    res = (
        l[0] * data[("particles", "p_ux")]
        + l[1] * data[("particles", "p_uy")]
        + l[2] * data[("particles", "p_uz")]
    )
    return res


def _vel_m(field, data):
    res = (
        m[0] * data[("particles", "p_ux")]
        + m[1] * data[("particles", "p_uy")]
        + m[2] * data[("particles", "p_uz")]
    )
    return res


def _vel_n(field, data):
    res = (
        n[0] * data[("particles", "p_ux")]
        + n[1] * data[("particles", "p_uy")]
        + n[2] * data[("particles", "p_uz")]
    )
    return res


filename = "data/fleks_particle_small/cut_*amrex"
ds = flekspy.load(filename)

# Add a user defined field. See yt document for more information about derived field.
vl_name = ds.pvar("vel_l")
vm_name = ds.pvar("vel_m")
vn_name = ds.pvar("vel_n")
ds.add_field(vl_name, units="code_velocity", function=_vel_l, sampling_type="particle")
ds.add_field(vm_name, units="code_velocity", function=_vel_m, sampling_type="particle")
ds.add_field(vn_name, units="code_velocity", function=_vel_n, sampling_type="particle")

######## Plot the location of particles that are inside a sphere ###########
center = [0, 0, 0]
radius = 0.001
# Object sphere is defined in yt/data_objects/selection_objects/spheroids.py
sp = ds.sphere(center, radius)

x_field = vl_name
y_field = vm_name
z_field = ds.pvar("p_w")

logs = {x_field: False, y_field: False}
profile = yt.create_profile(
    data_source=sp,
    bin_fields=[x_field, y_field],
    fields=z_field,
    n_bins=[64, 64],
    weight_field=None,
    logs=logs,
)

pp = yt.PhasePlot.from_profile(profile)

pp.set_unit(x_field, "km/s")
pp.set_unit(y_field, "km/s")
pp.set_unit(z_field, "amu")

pp.set_cmap(pp.fields[0], "turbo")
# pp.set_zlim(pp.fields[0], zmin, zmax)
pp.set_xlabel(r"$V_l$")
pp.set_ylabel(r"$V_m$")
pp.set_colorbar_label(pp.fields[0], "colorbar_label")
pp.set_title(pp.fields[0], "Density")
pp.set_font(
    {
        "size": 34,
        "family": "DejaVu Sans",
    }
)
pp.set_log(pp.fields[0], False)
pp.show()
yt : [INFO     ] 2025-03-18 17:27:15,548 Parameters: current_time              = 40.0
yt : [INFO     ] 2025-03-18 17:27:15,548 Parameters: domain_dimensions         = [16  8  6]
yt : [INFO     ] 2025-03-18 17:27:15,549 Parameters: domain_left_edge          = [-0.0064 -0.0032 -0.0024]
yt : [INFO     ] 2025-03-18 17:27:15,550 Parameters: domain_right_edge         = [0.0064 0.0032 0.0024]