-
Notifications
You must be signed in to change notification settings - Fork 31
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
Implementation of CW Temporal Profile and Plane Wave Transverse Profile #373
base: development
Are you sure you want to change the base?
Conversation
for more information, see https://pre-commit.ci
Should add We should change any meaningless number, eg |
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
Had another think about the use of |
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
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.
Looks great, thanks a lot for this PR! See minor comments below. In addition, as a follow-up of our offline discussion yesterday, I would raise a few points:
- Currently, the amplitude of the laser pulse is typically specified with the energy. For symmetry, could we consider the following?
- full profile: energy (J);
- CW wave: power (J/s), as the longitudinal dimension is infinite; -> already the case in this PR.
- plane wave: fluence (J/m^2) as the transverse dimensions are infinite. -> currently intensity is used.
- Likewise, for symmetry and consistency, if we have the 3 input parameters, it would be great to have the corresponding diagnostics, i.e., get_laser_energy (already there), get_peak_power (you added it), get_peak_fluence.
- Should the time domain be 1-second long [-0.5, 0.5] in CW case, such that, numerically, energy [J] == power [J/s]? Likewise for transverse box size of [-0.5, 0.5] meter in plane wave case such that, numerically, energy[J] == fluency [J/m^2]?
- I can envision that, before running the full expensive 3D beamline people check quick CW, then quick plane wave, then full thing. Do you think this is a reasonable workflow? If so, I recommend we make it simpler such that the user only needs to change either the longitudinal profile or the transverse profile. For this to work, we may need to overwrite some values (e.g. enforce 1 cell in transverse direction for plane wave, similar for lo and hi, etc.). What do you think?
"outputs": [], | ||
"source": [ | ||
"tau0_meas = get_duration(laser.grid, laser.dim)\n", | ||
"energy0_meas = compute_laser_energy(laser.dim, laser.grid)\n", |
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.
This may be slightly misleading, as the energy contained in a plane wave is infinite. Should we consider a compute_laser_fluence
there?
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
} |
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.
I think there's an empty cell at the end that can be removed.
Contains the value of the longitudinal envelope at the | ||
specified points. This array has the same shape as the array t. | ||
""" | ||
return np.ones_like(t + 0 * 1j) |
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.
return np.ones_like(t + 0 * 1j) | |
return np.ones_like(t + 0j) |
lasy/utils/grid.py
Outdated
lo[-1] = -1.0 | ||
hi[-1] = 1.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.
Having a box length of 1 in SI (here 1 second) could come in handy to connect energy and power (i.e., the value of the energy in the box in J = the power in J/s).
lo[-1] = -1.0 | |
hi[-1] = 1.0 | |
lo[-1] = -0.5 | |
hi[-1] = 0.5 |
Same can be done below for plane wave in transverse position.
tests/test_special_laser.py
Outdated
This test file verifys the correct implementation of these special cases of the laser object and | ||
additionally checks the implementation of the peak_intensity and peak_power normalizations | ||
as well as some measurement functionality from laser utils |
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.
This test file verifys the correct implementation of these special cases of the laser object and | |
additionally checks the implementation of the peak_intensity and peak_power normalizations | |
as well as some measurement functionality from laser utils | |
Check the implementation of these profiles and peak_intensity and peak_power normalizations, as well as some measurement functionality from laser utils. |
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
for more information, see https://pre-commit.ci
All sounds good, these changes should be in place now |
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.
Thanks for this PR! See minor suggestions below. Just one more change: could you update the logic such that the user can also specify peak_power
and peak_fluence
in all cases to combined_profile and that the profile is normalized accordingly?
"plt.ylim(\n", | ||
" 0,\n", | ||
")\n", |
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.
"plt.ylim(\n", | |
" 0,\n", | |
")\n", | |
"plt.ylim(0, None)\n", |
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Defining and Manipulating a Laser Pulse in Time Only\n", |
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.
"# Defining and Manipulating a Laser Pulse in Time Only\n", | |
"# Laser Pulse in Time Only\n", |
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Defining and Manipulating a Laser Pulse in Space Only\n", |
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.
"# Defining and Manipulating a Laser Pulse in Space Only\n", | |
"# Laser Pulse in Space Only\n", |
"print(\"Final Pulse Duration = %.2f fs\" % (tau1_meas * 1e15))\n", | ||
"print(\"\\n\")\n", |
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.
"print(\"Final Pulse Duration = %.2f fs\" % (tau1_meas * 1e15))\n", | |
"print(\"\\n\")\n", | |
"print(\"Final Pulse Duration = %.2f fs\" % (tau1_meas * 1e15) + "\n")\n", |
"print(\"Expected Final Spot Size = %.2f mm\" % (w1_meas * 1e3))\n", | ||
"print(\"\\n\")\n", |
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.
"print(\"Expected Final Spot Size = %.2f mm\" % (w1_meas * 1e3))\n", | |
"print(\"\\n\")\n", | |
"print(\"Expected Final Spot Size = %.2f mm\" % (w1_meas * 1e3) + "\n")\n", |
field = grid.get_temporal_field() | ||
power = get_laser_power(dim, grid) | ||
input_peak_power = power.max() | ||
if input_peak_power == 0.0: | ||
print("Field is zero everywhere, normalization will be skipped") | ||
else: | ||
field *= np.sqrt(peak_power / input_peak_power) | ||
grid.set_temporal_field(field) |
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.
field = grid.get_temporal_field() | |
power = get_laser_power(dim, grid) | |
input_peak_power = power.max() | |
if input_peak_power == 0.0: | |
print("Field is zero everywhere, normalization will be skipped") | |
else: | |
field *= np.sqrt(peak_power / input_peak_power) | |
grid.set_temporal_field(field) | |
power = get_laser_power(dim, grid) | |
input_peak_power = power.max() | |
if input_peak_power == 0.0: | |
print("Field is zero everywhere, normalization will be skipped") | |
else: | |
field = grid.get_temporal_field() | |
grid.set_temporal_field(field * np.sqrt(peak_power / input_peak_power)) |
This test file verifys the correct implementation of these special cases of the laser object and | ||
additionally checks the implementation of the peak_fluence and peak_power normalizations | ||
as well as some measurement functionality from laser utils |
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.
This test file verifys the correct implementation of these special cases of the laser object and | |
additionally checks the implementation of the peak_fluence and peak_power normalizations | |
as well as some measurement functionality from laser utils | |
This test file verifies the correct implementation of these cases of the laser object and | |
checks the implementation of the peak_fluence and peak_power normalizations | |
as well as some measurement functionality from laser utils |
The total energy of the laser pulse. The amplitude of the laser | ||
field (:math:`E_0` in the above formula) is automatically | ||
calculated so that the pulse has the prescribed energy. | ||
Only used in case where laser is neither a plane wave or a continuous wave laser |
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.
This is still the general case so I would not make a specific case here.
Only used in case where laser is neither a plane wave or a continuous wave laser |
The peak fluence of the laser pulse. The amplitude of the laser | ||
field (:math:`E_0` in the above formula) is automatically | ||
calculated so that the pulse has the prescribed peak fluence. | ||
Only used in case where laser is a continuous wave laser |
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.
I think that is a good option in general and should be usable.
Only used in case where laser is a continuous wave laser | |
Required for a CW (monochromatic) profile. |
The peak power of the laser pulse. The amplitude of the laser | ||
field (:math:`E_0` in the above formula) is automatically | ||
calculated so that the pulse has the prescribed peak power. | ||
Only used in case where laser is a plane wave laser |
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.
Only used in case where laser is a plane wave laser | |
Required for a plane wave profile. |
This PR aims to address the problem raised #371. Ideally one would like to be able to perform fast ~1D or ~2D manipulations of the temporal/spectral profile or the spatial profile respectively. One could approach this by adding more functionality to the respective profiles, but this would bring with it significant overhead. After discussion with @MaxThevenet we thought a more efficient solution would be to keep the laser object as is (together with all the excellent functionality that entails) and instead generate profiles which mimic the effect of a plane wave (in the event that one wants to manipulate just the transverse profile) or a continuous wave laser (in the event that one is interested in manipulating just the transverse profile).
In this PR, you will find implementations of both a Plane Wave Transverse Profile and a Continuous Wave Longitudinal Profile, together with some modifications to the grid object to ensure that smooth operation.
Sample usage for Plane Wave
Here you can see the lo and hi variables have
None
in thex
any
elements. I believe this would be more intuitive for a user than selecting a random set of low and high points.Grid
has been adapted to automatically set the range whenNone
is provided. Of course the user could set thelo
andhi
variables equal to the area of the beam to naturally calculate the correct peak field. However, as can be seen in this example, one can simple overwrite this if needed.Sample usage for Continuous Wave