Skip to content
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

[WIP] Use cupy, in which case all operations are performed on GPU #259

Open
wants to merge 36 commits into
base: development
Choose a base branch
from

Conversation

RemiLehe
Copy link
Member

@RemiLehe RemiLehe commented Jul 16, 2024

This PR adds a new file backend.py, that defines a quantity xp to be:

  • cupy if cupy installed
  • numpy otherwise
    Almost all array operations in lasy then use xp (e.g. to allocate the fields array, to perform the FFT, etc.)

Note that, in the current state of the PR, the user has no control of whether cupy will be used or not: as long as cupy is installed, lasy will automatically use it. At this point, there is also no message telling the user whether cupy or numpy is used (but the user can always print lasy.backend.use_cupy).

The getters for temporal_field and spectral_field have also been adapted, so as to be able to get the fields on CPU. This is used e.g. for the functions show (plotting with matplotlib) and write_to_file (dumping to disk with openPMD), as well as in several tests.

lasy/__init__.py Fixed Show fixed Hide fixed
lasy/__init__.py Fixed Show fixed Hide fixed
lasy/backend.py Fixed Show fixed Hide fixed
lasy/backend.py Fixed Show fixed Hide fixed
lasy/utils/laser_utils.py Dismissed Show dismissed Hide dismissed
lasy/__init__.py Outdated
@@ -1 +1,8 @@
__version__ = "0.4.0"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be discussed: right now, LASY automatically detects whether cupy is available and always uses it if it is.

@RemiLehe RemiLehe changed the title [WIP] Cupy backend [WIP] Use cupy, in which case all operations are performed on GPU Jul 17, 2024
lasy/laser.py Fixed Show fixed Hide fixed
lasy/laser.py Fixed Show fixed Hide fixed
lasy/laser.py Show resolved Hide resolved
lasy/laser.py Outdated Show resolved Hide resolved
if self.dim == "rt":
# Construct the propagator (check if exists)
if not hasattr(self, "prop"):
spatial_axes = (self.grid.axes[0],)
self.prop = []
if use_cupy:
# Move quantities to CPU to create propagator
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hightower8083 Would it be possible to modify the PropagatorResampling, so that it can take cupy arrays as input?
Right now, if don't move k and spatial_axes to the CPU, I get the following error:

lasy/laser.py:254: in propagate
    PropagatorResampling(
.../python-3.11/lib/python3.11/site-packages/axiprop/lib.py:242: in __init__
    self.init_kr(self.Rmax, self.Nr)
.../python-3.11/lib/python3.11/site-packages/axiprop/common.py:113: in init_kr
    self.kr = self.alpha / Rmax

Note that I am using this branch of axiprop

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well there is no need to have k and spatial_axes on GPU -- spatial axes are used to make transverse wave-numbers k_r that are transferred to GPU by axiprop and k is used per-element in the loop as scalars

@@ -737,9 +738,12 @@ def export_to_z(dim, grid, omega0, z_axis=None, z0=0.0, t0=0.0, backend="NP"):
time_axis_indx = -1

t_axis = grid.axes[time_axis_indx]
if use_cupy:
t_axis = xp.asnumpy(t_axis)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I don't do this, I later get:

lasy/utils/laser_utils.py:744: in export_to_z
    FieldAxprp = ScalarFieldEnvelope(omega0 / c, t_axis)
.../python-3.11/lib/python3.11/site-packages/axiprop/containers.py:101: in __init__
    self.k_freq_base = 2 * np.pi * np.fft.fftfreq(self.Nt, c*self.dt)
.../lib/python3.11/site-packages/numpy/fft/helper.py:169: in fftfreq
    return results * val
cupy/_core/core.pyx:1697: in cupy._core.core._ndarray_base.__array_ufunc__
    ???
cupy/_core/_kernel.pyx:1283: in cupy._core._kernel.ufunc.__call__
    ???
cupy/_core/_kernel.pyx:159: in cupy._core._kernel._preprocess_args
    ???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???
E   TypeError: Unsupported type <class 'numpy.ndarray'>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t_axis is actually not needed on GPU as all propagation in done in the spectral domain -- as soon as we do FFT we don't have time. self.k_freq_base can remain on the host

@@ -783,10 +787,10 @@ def export_to_z(dim, grid, omega0, z_axis=None, z0=0.0, t0=0.0, backend="NP"):
verbose=False,
)
# Convert the spectral image to the spatial field representation
FieldAxprp.import_field(np.moveaxis(field, -1, 0).copy())
FieldAxprp.import_field(xp.moveaxis(field, -1, 0).copy())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am currently getting an error of the form:

lasy/utils/laser_utils.py:790: in export_to_z
    FieldAxprp.import_field(xp.moveaxis(field, -1, 0).copy())
.../python-3.11/lib/python3.11/site-packages/axiprop/containers.py:369: in import_field
    self.time_to_frequency()
.../python-3.11/lib/python3.11/site-packages/axiprop/containers.py:439: in time_to_frequency
    self.Field_ft[:] = np.fft.ifft(self.Field, axis=0, norm="backward")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should get rid of the axiprop Containers -- they currently only have CPU implementation for spectral transforms. I assume we are doing FFT now with lasy portable methods, so lets stick to this

@@ -0,0 +1,10 @@
try:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re backend control: #259 (comment)

We could do a similar control as done in matplotlib, e.g.,

import lasy
lasy.use("numpy")  # default: "auto"

https://matplotlib.org/stable/users/explain/figure/backends.html

The logic could be, using the usual precedence of options:

  • check if this option was set (on the module aka the current process), otherwise
  • check env variable to use default, otherwise
  • use cupy if found, otherwise
  • use numpy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants