Repository: Project-MONAI/MONAI
File: monai/data/image_reader.py (Python)

Code before:
            In practical use, it's recommended to add a warm up call before the actual loading.
            A related tutorial will be prepared in the future, and the document will be updated accordingly.
        kwargs: additional args for `nibabel.load` API. more details about available args:
            https://github.com/nipy/nibabel/blob/master/nibabel/loadsave.py

    """

    def __init__(
        self,
        channel_dim: str | int | None = None,
        as_closest_canonical: bool = False,
        squeeze_non_spatial_dims: bool = False,
        to_gpu: bool = False,
        **kwargs,
    ):
        super().__init__()
        self.channel_dim = float("nan") if channel_dim == "no_channel" else channel_dim
        self.as_closest_canonical = as_closest_canonical
        self.squeeze_non_spatial_dims = squeeze_non_spatial_dims
        if to_gpu is True:
            if not has_cp:
                warnings.warn("CuPy is not installed, fall back to use cpu load.")
                to_gpu = False
            if not has_kvikio:
                warnings.warn("Kvikio is not installed, fall back to use cpu load.")
                to_gpu = False

        self.to_gpu = to_gpu
        self.kwargs = kwargs

    def verify_suffix(self, filename: Sequence[PathLike] | PathLike) -> bool:
        """
        Verify whether the specified file or files format is supported by Nibabel reader.

        Args:
            filename: file name or a list of file names to read.
                if a list of files, verify all the suffixes.

        """
        suffixes: Sequence[str] = ["nii", "nii.gz"]
        return has_nib and is_supported_format(filename, suffixes)

    def read(self, data: Sequence[PathLike] | PathLike, **kwargs):
        """
        Read image data from specified file or files, it can read a list of images
        and stack them together as multi-channel data in `get_data()`.
        Note that the returned object is Nibabel image object or list of Nibabel image objects.

        Args:
            data: file name or a list of file names to read.
            kwargs: additional args for `nibabel.load` API, will override `self.kwargs` for existing keys.

Review comment (suggestion):
```suggestion
        if to_gpu and (not has_cp or not has_kvikio):
            warnings.warn("NibabelReader: CuPy and/or Kvikio not installed for GPU loading, falling back to CPU loading.")
            to_gpu = False
```
I'd suggest something like this so we have fewer warnings. It's less clear which library is missing, but the user is going to have to sort out their environment anyway so they'll find out which one it is.

Code after:
            A related tutorial will be prepared in the future, and the document will be updated accordingly.
        kwargs: additional args for `nibabel.load` API. more details about available args:
            https://github.com/nipy/nibabel/blob/master/nibabel/loadsave.py

    """

    def __init__(
        self,
        channel_dim: str | int | None = None,
        as_closest_canonical: bool = False,
        squeeze_non_spatial_dims: bool = False,
        to_gpu: bool = False,
        **kwargs,
    ):
        super().__init__()
        self.channel_dim = float("nan") if channel_dim == "no_channel" else channel_dim
        self.as_closest_canonical = as_closest_canonical
        self.squeeze_non_spatial_dims = squeeze_non_spatial_dims
        if to_gpu and (not has_cp or not has_kvikio):
            warnings.warn(
                "NibabelReader: CuPy and/or Kvikio not installed for GPU loading, falling back to CPU loading."
            )
            to_gpu = False

        if to_gpu:
            self.warmup_kvikio()

        self.to_gpu = to_gpu
        self.kwargs = kwargs

    def warmup_kvikio(self):
        """
        Warm up the Kvikio library to initialize the internal buffers, cuFile, GDS, etc.
        This can accelerate the data loading process when `to_gpu` is set to True.
        """
        if has_cp and has_kvikio:
            a = cp.arange(100)
            with tempfile.NamedTemporaryFile() as tmp_file:
                tmp_file_name = tmp_file.name
                f = kvikio.CuFile(tmp_file_name, "w")
                f.write(a)
                f.close()

                b = cp.empty_like(a)
                f = kvikio.CuFile(tmp_file_name, "r")
                f.read(b)

    def verify_suffix(self, filename: Sequence[PathLike] | PathLike) -> bool:
        """
        Verify whether the specified file or files format is supported by Nibabel reader.