-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Profile from openPMD file #151
Changes from all commits
30ff926
14ec5c1
98e02d8
3a42e70
983c5c2
0796f1d
67f80bd
c36c4b0
b27454c
cd32c0e
937038b
b8d3ef2
b4957b8
7f377f8
0e1364d
8023694
06d9c4a
b513d95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Profile read from an openPMD file | ||
================================= | ||
|
||
.. autoclass:: lasy.profiles.from_openpmd_profile.FromOpenPMDProfile | ||
:members: |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,11 @@ | ||
from .combined_profile import CombinedLongitudinalTransverseProfile | ||
from .gaussian_profile import GaussianProfile | ||
from .from_array_profile import FromArrayProfile | ||
from .from_openpmd_profile import FromOpenPMDProfile | ||
|
||
__all__ = [ | ||
"CombinedLongitudinalTransverseProfile", | ||
"GaussianProfile", | ||
"FromArrayProfile", | ||
"FromOpenPMDProfile", | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import numpy as np | ||
from scipy.signal import hilbert | ||
from scipy.constants import c | ||
import openpmd_api as io | ||
from openpmd_viewer import OpenPMDTimeSeries | ||
from .from_array_profile import FromArrayProfile | ||
|
||
|
||
class FromOpenPMDProfile(FromArrayProfile): | ||
r""" | ||
Profile defined from an openPMD file. | ||
|
||
Parameters | ||
---------- | ||
path : string | ||
Path to the openPMD file containing the laser field or envelope. | ||
Passed directly OpenPMDTimeSeries. | ||
|
||
iteration : int | ||
Iteration at which the argument is read. | ||
Passed directly OpenPMDTimeSeries. | ||
|
||
pol : list of 2 complex numbers (dimensionless) | ||
Polarization vector. It corresponds to :math:`p_u` in the above | ||
formula ; :math:`p_x` is the first element of the list and | ||
:math:`p_y` is the second element of the list. Using complex | ||
numbers enables elliptical polarizations. | ||
|
||
field : string | ||
Name of the field containing the laser pulse | ||
Passed directly OpenPMDTimeSeries. | ||
|
||
coord : string | ||
Name of the field containing the laser pulse | ||
Passed directly OpenPMDTimeSeries. | ||
|
||
envelope : boolean | ||
Whether the file represents a laser envelope. | ||
If not, the envelope is obtained from the electric field | ||
using a Hilbert transform | ||
|
||
prefix : string | ||
Prefix of the openPMD file from which the envelope is read. | ||
Only used when envelope=True. | ||
The provided iteration is read from <path>/<prefix>_%T.h5. | ||
""" | ||
|
||
def __init__( | ||
self, path, iteration, pol, field, coord=None, envelope=False, prefix=None | ||
): | ||
ts = OpenPMDTimeSeries(path) | ||
F, m = ts.get_field(iteration=iteration, field=field, coord=coord, theta=None) | ||
assert m.axes in [ | ||
{0: "x", 1: "y", 2: "z"}, | ||
{0: "z", 1: "y", 2: "x"}, | ||
{0: "x", 1: "y", 2: "t"}, | ||
{0: "t", 1: "y", 2: "x"}, | ||
] | ||
|
||
if m.axes in [{0: "z", 1: "y", 2: "x"}, {0: "t", 1: "y", 2: "x"}]: | ||
F = F.swapaxes(0, 2) | ||
|
||
if "z" in m.axes.values(): | ||
t = (m.z - m.z[0]) / c | ||
else: | ||
t = m.t | ||
axes = {"x": m.x, "y": m.y, "t": t} | ||
|
||
# If array does not contain the envelope but the electric field, | ||
# extract the envelope with a Hilbert transform | ||
if envelope == False: | ||
# Assumes z is last dimension! | ||
h = hilbert(F) | ||
|
||
if "z" in m.axes.values(): | ||
# Flip to get complex envelope in t assuming z = -c*t | ||
h = np.flip(h, axis=2) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should probably use converters There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A typical workflow:
Points 2 and 4 are exactly symmetric, which is what we want, and that's easily done with this dummy convertor, so I think it should be like this. But the clean way would be to make this dummy convertor an option of the |
||
|
||
# Get central wavelength from array | ||
phase = np.unwrap(np.angle(h)) | ||
omg0_h = np.average(np.gradient(-phase, t, axis=-1), weights=np.abs(h)) | ||
wavelength = 2 * np.pi * c / omg0_h | ||
array = h * np.exp(1j * omg0_h * t) | ||
else: | ||
s = io.Series(path + "/" + prefix + "_%T.h5", io.Access.read_only) | ||
it = s.iterations[iteration] | ||
omg0 = it.meshes["laserEnvelope"].get_attribute("angularFrequency") | ||
wavelength = 2 * np.pi * c / omg0 | ||
array = F | ||
|
||
axes_order = ["x", "y", "t"] | ||
super().__init__( | ||
wavelength=wavelength, | ||
pol=pol, | ||
array=array, | ||
axes=axes, | ||
axes_order=axes_order, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
axiprop | ||
numpy | ||
openpmd-api | ||
openpmd-viewer | ||
scipy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here you implicitly set t[0]=0, while we usually center beam in time so
t_peak=0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also to be discussed in #155.