slmsuite.holography.algorithms.CompressedSpotHologram#

class CompressedSpotHologram(spot_vectors, basis='kxy', spot_amp=None, cameraslm=None, **kwargs)[source]#

Bases: CompressedSpotHologram

Holography optimized for the generation of optical focal arrays (kernel-based).

Is a subclass of FeedbackHologram, but falls back to non-camera-feedback routines if cameraslm is not passed.

Note

Changes to the SLM (e.g. change of wavelength) will not necessarily propagate to values cached in SpotHologram. Reinitialize the hologram to correctly populate the caches.

spot_zernike#

Spot position vectors with shape (D, N), where D is the dimension of the Zernike basis and N is the number of spots.

Type:

numpy.ndarray

zernike_basis#

The ANSI indices of the Zernike basis.

Type:

numpy.ndarray

spot_ij#

Lateral spot position vectors in the camera basis with shape (2, N).

Type:

numpy.ndarray OR None

external_spot_amp#

When using "external_spot" feedback or the "external_spot" stat group, the user must supply external data. This data is transferred through this attribute. For iterative feedback, have the callback() function set external_spot_amp dynamically. By default, this variable is set to even distribution of amplitude.

Type:

numpy.ndarray

spot_integration_width_ij#

For spot-specific feedback methods, better SNR is achieved when integrating over many camera pixels. This variable stores the width of the integration region in "ij" (camera) space.

Type:

int

cuda#

Whether the custom CUDA kernel is used for optimization (option 2).

Type:

bool

Methods

get_farfield

Collects the current complex DFT farfield, potentially with transformations.

get_mempool_limit

Helper function to get the cupy memory pool size.

get_padded_shape

Vestigial from Hologram, but unneeded here.

get_phase

Collects the current nearfield phase from the GPU with cupy.ndarray.get().

ijcam_to_knmslm

Convert an image in the camera domain to computational SLM k-space using, in part, the affine transformation stored in a cameraslm's Fourier calibration.

load_stats

Uses save_h5() to import the statistics hierarchy from a given h5 file.

measure

Method to request a measurement to occur.

optimize

Optimizers to solve the "phase problem": approximating the nearfield phase that transforms a known nearfield source amplitude to a desired farfield target amplitude.

optimize_cg

Conjugate Gradient (CG) iterative phase retrieval.

optimize_gs

GPU-accelerated Gerchberg-Saxton (GS) iterative phase retrieval.

plot_farfield

Plots an overview (left) and zoom (right) view of source.

plot_nearfield

Plots the amplitude (left) and phase (right) of the nearfield (plane of the SLM).

plot_stats

Plots the statistics contained in the given dictionary.

refine_offset

(NotImplemented) Hones the position of the produced image to the desired target image to compensate for Fourier calibration imperfections.

remove_vortices

Spot holograms do not need to consider vortices.

reset

Resets the hologram to an initial state.

reset_phase

Resets the hologram to a provided phase, to a random state, or to a quadratic phase which overlaps with the target pattern.

reset_weights

Resets the hologram weights to the target defaults.

save_stats

Uses save_h5() to export the statistics hierarchy to a given h5 file.

set_mempool_limit

set_target

Change the target to something new.

update_target

Change the target to something new.

__init__(spot_vectors, basis='kxy', spot_amp=None, cameraslm=None, **kwargs)[source]#

Initializes a CompressedSpotHologram targeting given spots at spot_vectors. This class makes use of so-called ‘compressed’ methods. Instead of effectively evaluating a blazing nearfield-farfield transformation kernel \(\phi(x,y,k_x,k_y) = k_xx + k_yy\) at every point in the grid of a discrete Fourier transform, this class ‘compresses’ the effort to evaluate such kernels only when the target farfield amplitude is non-zero.

For focal arrays, the majority of the DFT grid is zero, so only processing the non-zero points can be faster. Importantly, each kernel is no longer bound to a grid, so \(k_x, k_y\) can be defined as free floating points. More importantly, we are not restricted to the linear shearing that the standard Fourier kernel imposes. Rather, quadratic focusing terms or more complicated summations of Zernike polynomials can be employed to focus or correct for aberration.

This CompressedSpotHologram focusses on arrays of spots, each spot having an individualized Zernike calibration. This calibration of course includes steering in the \(x\), \(y\), and \(z\) directions with the 2nd, 1st, and 4th Zernike polynomials, respectively (tilt and focus).

Important

This class supports two options for generating compressed spot arrays.

  1. First, a numpy/cupy method directly caches the kernels and plays tricks to vectorize the farfield transformation operations. This method makes ample use of memory and is inefficient for very large spot arrays. The caches are unique to a specific spot_zernike, and are updated when a change to spot_zernike is detected. More general or complicated functionality requires full use of the GPU and thus the following option requires cupy and underlying CUDA.

  2. (This feature is currently disabled until 0.1.3 due to discovered instability on different systems.) A custom CUDA kernel loaded into cupy. Above a certain number of spots (\(O(10^3)\)), saving and transporting a set of Zernike polynomial kernels would consume unacceptable amounts of memory and memory bandwidth. Instead, this kernel dynamically constructs all the Zernike polynomials in the given basis locally on the GPU, using this data to apply the nearfield-farfield transformation before returning only the result of the transformation. Such computation requires only the data of the input and output, along with efficient ‘compressed’ information defining the construction of the polynomial kernels. This kernel bases itself upon spot_zernike, which is moved to the GPU every tick.

The chosen option is selected dynamically. Option 2 is the highest preference. If the kernel fails to load or cupy is unavailable, the option will downgrade to option 1. The choice is stored in cuda.

Parameters:
  • spot_vectors (array_like) – Spot position vectors with shape (D, N), where D is the dimension of the parameters of each spot. The processed values of this array are stored in spot_zernike in the "zernike" basis.

  • basis (str OR array_like of int) –

    The spots can be in any of the following bases:

    • "kxy" for centered normalized SLM \(k\)-space (radians), for dimension D of 2 and 3. This is the default.

    • "ij" for camera coordinates (pixels), for dimension D of 2 and 3.

    • "zernike" for applying Zernike terms to each spot (radians), for dimension D equal to the length of zernike_basis. The provided coefficients are multiplied directly on the the normalized Zernike polynomials on the unit disk. See zernike_sum().

      The assumed Zernike basis depends on the dimensionality of the provided spots:

      • If D == 2, then the basis is assumed to be [2,1] corresponding to the \(x = Z_2 = Z_1^1\) and \(y = Z_1 = Z_1^{-1}\) tilt terms.

      • If D == 3, then the basis is assumed to be [2,1,4] corresponding to the previous, with the addition of the \(Z_4 = Z_2^0\) focus term.

      • If D > 3, then the basis is assumed to be [2,1,4,3,5,6...,D]. The piston term (Zernike index 0) is ignored as this constant phase is not relevant.

      See the next option to customize the Zernike basis beyond these defaults.

    • array_like of int for applying a custom Zernike basis. List of D indices corresponding to Zernike polynomials using ANSI indexing. See convert_zernike_index(). The index -1 (outside Zernike indexing) is used as a special case to add a vortex waveplate with amplitude \(2\pi\) to the system (see laguerre_gaussian()).

  • spot_amp (array_like OR None) – The amplitude to target for each spot. See spot_amp. If None, all spots are assumed to have the same amplitude. Normalization is performed automatically; the user is not required to normalize. MRAF functionality still works by setting elements of spot_amp to np.nan, denoting ‘noise’ points where amplitude can be dumped.

  • cameraslm (FourierSLM) – Must be passed. The default of None with throw an error and is only optional such that we can retain the same argument ordering as SpotHologram.

  • **kwargs – Passed to FeedbackHologram.__init__().

get_farfield(shape=None, propagation_kernel=None, affine=None, get=True)[source]#

Collects the current complex DFT farfield, potentially with transformations. This includes collecting the data from the GPU with cupy.ndarray.get().

Parameters:
  • shape ((int, int)) – Shape of the DFT. Useful to change the resolution of the farfield. If None, defaults to shape, and falls back to slm_shape.

  • propagation_kernel (array_like) – Used to check the result of the hologram at different depths. See propagation_kernel. If None, defaults to propagation_kernel if one is present. Otherwise, no kernel is applied. Zeroing can force no kernel to be applied and yield the raw DFT.

  • affine (dict) – Affine transformation to apply to farfield data (in the form of a dictionary with keys "M" and "b"). If None, no transformation is applied.

  • get (bool) – Whether or not to convert the cupy array to a numpy array if cupy is used. This is ignored if numpy is used.

Returns:

Current farfield expected from the current phase.

Return type:

numpy.ndarray

static get_mempool_limit(device=0)[source]#

Helper function to get the cupy memory pool size.

Parameters:

device (int) – Which GPU to set the limit on. Passed to cupy.cuda.Device().

Returns:

Current memory pool limit in bytes

Return type:

int

get_padded_shape()[source]#

Vestigial from Hologram, but unneeded here. CompressedSpotHologram does not use a DFT grid and does not need padding.

get_phase(include_propagation=False)[source]#

Collects the current nearfield phase from the GPU with cupy.ndarray.get(). Also shifts the \([-\pi, \pi]\) range of numpy.arctan2() to \([0, 2\pi]\) for faster writing to the SLM (see set_phase()).

Parameters:

include_propagation (bool) – Whether to include the propagation_kernel, if available.

Returns:

Current nearfield phase of the optimization.

Return type:

numpy.ndarray

ijcam_to_knmslm(img, out=None, blur_ij=None, order=3)[source]#

Convert an image in the camera domain to computational SLM k-space using, in part, the affine transformation stored in a cameraslm’s Fourier calibration.

Note

This includes two transformations:

  • The affine transformation "ij" -> "kxy" (camera pixels to normalized k-space).

  • The scaling "kxy" -> "knm" (normalized k-space to computational k-space pixels).

Parameters:
  • img (numpy.ndarray OR cupy.ndarray) – Image to transform. This should be the same shape as images returned by the camera.

  • out (numpy.ndarray OR cupy.ndarray OR None) – If out is not None, this array will be used to write the memory in-place.

  • blur_ij (int OR None) – Applies a blur_ij pixel-width Gaussian blur to img. If None, defaults to the "blur_ij" flag if present; otherwise zero.

  • order (int) – Order of interpolation used for transformation. Defaults to 3 (cubic).

Returns:

Image transformed into "knm" space.

Return type:

numpy.ndarray OR cupy.ndarray

load_stats(file_path, include_state=True)[source]#

Uses save_h5() to import the statistics hierarchy from a given h5 file.

Tip

Enabling the "raw_stats" flag will export feedback data from each iteration instead of only derived statistics. Consider enabling this to save more detailed information upon export.

Parameters:
  • file_path (str) – Full path to the file to read the data from.

  • include_state (bool) – If True, also overwrite all other attributes of Hologram except for dtype and amp_ff.

measure(basis='ij')[source]#

Method to request a measurement to occur. If img_ij is None, then a new image will be grabbed from the camera (this is done automatically in algorithms).

Parameters:

basis (str) –

The cached image to be sure to fill with new data. Can be "ij" or "knm".

  • If "knm", then img_ij and img_knm are filled.

  • If "ij", then img_ij is filled, and img_knm is ignored.

This is useful to avoid (expensive) transformation from the "ij" to the "knm" basis if img_knm is not needed.

optimize(method='GS', maxiter=20, verbose=True, callback=None, feedback=None, stat_groups=[], **kwargs)[source]#

Optimizers to solve the “phase problem”: approximating the nearfield phase that transforms a known nearfield source amplitude to a desired farfield target amplitude. Supported optimization methods include:

  • Gerchberg-Saxton (GS) phase retrieval.

    • 'GS'

      An iterative algorithm for phase retrieval, accomplished by moving back and forth between the imaging and Fourier domains, with amplitude corrections applied to each. This is usually implemented using fast discrete Fourier transforms, potentially GPU-accelerated.

  • Weighted Gerchberg-Saxton (WGS) phase retrieval algorithms of various flavors. Improves the uniformity of GS-computed focus arrays using weighting methods and techniques from literature. The method keywords are:

    • 'WGS-Leonardo'

      The original WGS algorithm. Weights the target amplitudes by the ratio of mean amplitude to computed amplitude, which amplifies weak spots while attenuating strong spots. Uses the following weighting function:

      \[\mathcal{W} = \mathcal{W}\left(\frac{\mathcal{T}}{\mathcal{F}}\right)^p\]

      where \(\mathcal{W}\), \(\mathcal{T}\), and \(\mathcal{F}\) are the weight amplitudes, target (goal) amplitudes, and feedback (measured) amplitudes, and \(p\) is the power passed as "feedback_exponent" in flags (see kwargs). The power \(p\) defaults to .8 if not passed. In general, smaller \(p\) will lead to slower yet more stable optimization.

    • 'WGS-Kim'

      Improves the convergence of WGS-Leonardo by fixing the farfield phase strictly after a desired number of net iterations specified by "fix_phase_iteration" or after exceeding a desired efficiency (fraction of farfield energy at the desired points) specified by "fix_phase_efficiency"

    • 'WGS-Nogrette'

      Weights target intensities by a tunable gain factor.

      \[\mathcal{W} = \mathcal{W}/\left(1 - f\left(1 - \mathcal{F}/\mathcal{T}\right)\right)\]

      where \(f\) is the gain factor passed as "feedback_factor" in flags (see kwargs). The factor \(f\) defaults to .1 if not passed.

      Note that while Nogrette et al compares powers, this implementation compares amplitudes for speed. These are identical to first order.

    • 'WGS-Wu'

      Weights using an exponential function, which is less sensitive to near-zero values of \(\mathcal{F}\) or \(\mathcal{T}\).

      \[\mathcal{W} = \mathcal{W}\exp\left( p (\mathcal{T} - \mathcal{F}) \right)\]

      The speed of correction is controlled by \(p\), the power passed as "feedback_exponent".

    • 'WGS-tanh'

      Weights by hyperbolic tangent, commonly used as an activation function in machine learning.

      \[\mathcal{W} = \mathcal{W}\left[1 + f\text{tanh}\left( p (\mathcal{T} - \mathcal{F}) \right) \right]\]

      This weighting limits each update to a relative change of \(\pm f\), passed as "feedback_factor", which is useful to prevent large changes. The speed of correction is controlled by \(p\), the power passed as "feedback_exponent".

  • Conjugate Gradient (CG) phase retrieval.

    • 'CG'

      (This feature is experimental.)

      Some holography—especially that with more complicated holographic objectives—can be better treated with gradient-based methods. In these cases, the phase is guided to an optimized state by following the back-propagated gradients (with respect to phase) of given objective loss which is passed as one of the flags to optimize(). Weighting different components of the objective leads to tradeoffs between those components: for instance a tradeoff between power guided into a given pattern and the uniformity of the realized pattern. slmsuite uses pytorch as a backend for gradient computation. Notably, memory is still owned and initialized by cupy, but gradients can be calculated by using pytorch-cupy interoperability.

      The objective loss is expected to be a torch.nn.Module and defaults to a complex variant of torch.nn.MSELoss(). loss is called in the style of pytorch, using (as arguments) the computed farfield (with gradient tree intact) and the target values for the farfield. Internally, this looks like:

      result = loss(      # The user provides this nn.Module to .optimize()
          farfield,       # The farfield (with gradients), calculated from `phase` by slmsuite
          target          # The target, initialized by the user and processed by slmsuite
      )
      result.backward()   # Gradients are back-propagated to the input `phase`.
      

      For FeedbackHologram and subclasses, the gradients are computed computationally, but the computational values are then replaced with the experimental results. This allows optimization of the experimental results using the computational gradients (correct to first order) as a guide. Currently, feedback is not supported for spot arrays with "experimental_spot" or "computational_spot" feedback (WGS probably works better for such spot array objectives anyway).

      Creating a custom objective is as simple as making a custom torch.nn.Module.forward() method. These methods can be as simple as a single expression or as complicated as a full neural network operating on the input parameters. However, remember to use pytorch methods because the arguments are of type torch.Tensor. Here’s an example of a custom torch.nn.Module.forward() which implements the Huber loss:

      # Define the loss as a class.
      class HuberLoss(nn.Module):
          def __init__(self, delta=1.0):
              super(HuberLoss, self).__init__()
              self.delta = delta
      
          def forward(self, farfield, target):
              residual = torch.abs(farfield - target)
              quadratic = torch.clamp(residual, max=self.delta)
              linear = residual - quadratic
              loss = 0.5 * quadratic ** 2 + self.delta * linear
      
              return torch.mean(loss)
      
      # Initialize the class. Remember that we can pass arguments (delta) here.
      loss = HuberLoss(delta=2.0)
      
      # Pass the loss to the hologram by one of two methods:
      hologram.optimize(..., loss=loss)       # 1. Pass as **kwarg.
      hologram.flags["loss"] = loss           # 2. Set directly.
      

      MRAF (next section), if desired, needs to be handled by the loss function. MRAF information is encoded in the target, with the noise region being nan.

  • The option for Mixed Region Amplitude Freedom (MRAF) feedback. In standard iterative algorithms, the entire Fourier-domain unpatterned field is replaced with zeros. This is disadvantageous because a desired farfield pattern might not be especially compatible with a given nearfield amplitude, or otherwise. MRAF enables “noise regions” where some fraction of the given farfield is not replaced with zeros and instead is allowed to vary. In practice, MRAF is enabled by setting parts of the target to nan; these regions act as the noise regions. The "mraf_factor" flag in flags allows the user to partially attenuate the noise regions. A factor of 0 fully attenuates the noise region (normal WGS behavior). A factor of 1 does not attenuate the noise region at all (the default). Middle ground is recommended, but is application-dependent as a tradeoff between improving pattern fidelity and maintaining pattern efficiency.

    As examples, consider two cases where MRAF can be useful:

    • Sloping a top hat. Suppose we want very flat amplitude on a beam. Requesting a sharp edge to this beam can lead to fringing effects at the boundary which mitigate flatness both inside and outside the beam. If instead a noise region is defined in a band surrounding the beam, the noise region will be filled with whatever slope best enables the desired flat beam.

    • Mitigating diffractive orders. Without MRAF, spot patterns with high crystallinity often have “ghost” diffractive orders which continue the pattern past the edges of requested spots. Even though these orders are attenuated during each phase retrieval iteration, they remain part of the best solution for the recovered phase. With MRAF, a noise region can help solve for retrieved phase which does not generate these undesired orders.

Caution

Requesting stat_groups will slow the speed of optimization due to the overhead of processing and saving statistics, especially in the case of GPU-accelerated optimization where significant time cost is incurred by moving these statistics to the CPU. This is especially apparent in the case of fully-computational holography, where this effect can slow what is otherwise a fully-GPU-contained loop by an order magnitude.

Tip

This function uses a parameter naming convention borrowed from scipy.optimize.minimize() and other functions in scipy.optimize. The parameters method, maxiter, and callback have the same functionality as the equivalently-named parameters in scipy.optimize.minimize().

Parameters:
  • method (str) – Optimization method to use. See the list of optimization methods above.

  • maxiter (int) – Number of iterations to optimize before terminating.

  • verbose (bool OR int) – Whether to display tqdm progress bars. These bars are also not displayed for maxiter <= 1. If verbose is greater than 1, then flags are printed as a preamble.

  • callback (callable OR None) – Same functionality as the equivalently-named parameter in scipy.optimize.minimize(). callback must accept a Hologram or Hologram subclass as the single argument. If callback returns True, then the optimization exits. Ignored if None.

  • feedback (str OR None) –

    Type of feedback to use during optimization, for instance when weighting in "WGS". For direct instances of Hologram, this can only be "computational" feedback. Subclasses support more types of feedback. Supported feedback options include the following:

    • "computational" Uses the the projected farfield pattern (transform of the complex nearfield) as feedback.

    • "experimental" Uses a camera contained in a passed cameraslm as feedback. Specific to subclasses of FeedbackHologram.

    • "computational_spot" Takes the computational result (the projected farfield pattern) and integrates regions around the expected positions of spots in an optical focus array. More stable than "computational" for spots. Specific to subclasses of SpotHologram.

    • "experimental_spot" Takes the experimental result (the image from a camera) and integrates regions around the expected positions of spots in an optical focus array. More stable than "experimental" for spots. Specific to subclasses of SpotHologram.

    • "external_spot" Uses some external user-provided metric for spot feedback. See external_spot_amp. Specific to subclasses of SpotHologram.

  • stat_groups (list of str OR None) – Strings representing types of feedback (data gathering) upon which statistics should be derived. These strings correspond to valid types of feedback (see above). For instance, if "experimental" is passed as a stat group, statistics on the pixels in the experimental feedback image will automatically be computed and stored for each iteration of optimization. However, this comes with overhead (see above warning).

  • **kwargs (dict, optional) – Various weight keywords and values to pass depending on the weight method. These are passed into flags. See options documented in the constructor.

optimize_cg(iterations, callback)[source]#

Conjugate Gradient (CG) iterative phase retrieval.

(This feature is experimental.)

Solves the “phase problem”: approximates the nearfield phase that transforms a known nearfield source amplitude to a desired farfield target amplitude.

Caution

This function should be called through optimize() and not called directly. It is left as a public function exposed in documentation to clarify how the internals of optimize() work.

Parameters:
  • iterations (iterable) – Number of loop iterations to run. Is an iterable to pass a tqdm iterable.

  • callback (callable OR None) – See optimize().

optimize_gs(iterations, callback)[source]#

GPU-accelerated Gerchberg-Saxton (GS) iterative phase retrieval.

Solves the “phase problem”: approximates the nearfield phase that transforms a known nearfield source amplitude to a desired farfield target amplitude.

Caution

This function should be called through optimize() and not called directly. It is left as a public function exposed in documentation to clarify how the internals of optimize() work.

Note

Default FFTs are not in-place in this algorithm. In both non-cupy and cupy implementations, numpy.fft does not support in-place operations. However, scipy.fft does in both. In the future, we may move to the scipy implementation. However, neither numpy or scipy fftshift support in-place movement (for obvious reasons). For even faster computation, algorithms should consider not shifting the FFT result, and instead shifting measurement data / etc to this unshifted basis. We might also implement get_fft_plan for even faster FFTing. However, in practice, speed is limited by other peripherals (especially feedback and stats) rather than FFT speed or memory.

Parameters:
  • iterations (iterable) – Number of loop iterations to run. Is an iterable to pass a tqdm iterable.

  • callback (callable OR None) – See optimize().

plot_farfield(source=None, title='', limits=None, units='knm', limit_padding=0.1, figsize=(8, 4), cbar=False)[source]#

Plots an overview (left) and zoom (right) view of source.

Parameters:
  • source (array_like OR None) – Should have shape equal to shape. If None, defaults to amp_ff.

  • title (str) – Title of the plots. If "phase" is a substring of title, then the source is treated as a phase.

  • limits (((float, float), (float, float)) OR None) – \(x\) and \(y\) limits for the zoom plot in "knm" space. If None, limits are autocomputed as the smallest bounds that show all non-zero values (plus limit_padding). Note that autocomputing on target will perform well, as zero values are set to actually be zero. However, doing so on computational or experimental outputs (e.g. amp_ff) will likely perform poorly, as values in the field deviate slightly from zero and artificially expand the limits.

  • units (str) – Far-field units for plots (see convert_vector() for options). If units requiring a SLM are desired, the attribute cameraslm must be filled.

  • limit_padding (float) – Fraction of the width and height to expand the limits of the zoom plot by, only if the passed limits is None (autocompute).

  • figsize (tuple) – Size of the plot.

  • cbar (bool) – Whether to add colorbars to the plots. Defaults to False.

Returns:

Used limits, which may be autocomputed. Autocomputed limits are returned as integers.

Return type:

((float, float), (float, float))

plot_nearfield(source=None, title='', padded=False, figsize=(8, 4), cbar=False)[source]#

Plots the amplitude (left) and phase (right) of the nearfield (plane of the SLM). The amplitude is assumed (whether uniform, or experimentally computed) while the phase is the result of optimization.

Parameters:
  • title (str) – Title of the plots.

  • padded (bool) – If True, shows the full computational nearfield of shape shape. Otherwise, shows the region at the center of the computational space of size slm_shape corresponding to the unpadded SLM.

  • figsize (tuple) – Size of the plot.

  • cbar (bool) – Whether to add colorbars to the plots. Defaults to False.

plot_stats(stats_dict=None, stat_groups=[], ylim=None, show=False)[source]#

Plots the statistics contained in the given dictionary.

Parameters:
  • stats_dict (dict OR None) – Stats to plot in dictionary form. If None, defaults to stats.

  • stat_groups (list of str OR None) – Which statistics groups to plot. If empty or None is provided, defaults to all groups present in stats.

  • ylim ((int, int) OR None) – Allows the user to pass in desired y limits. If None, the default y limits are used.

  • show (bool) – Whether or not to immediately show the plot. Defaults to false.

refine_offset(*args, **kwargs)[source]#

(NotImplemented) Hones the position of the produced image to the desired target image to compensate for Fourier calibration imperfections. Works either by moving the desired camera target to align where the image ended up (basis="ij") or by moving the \(k\)-space image to target the desired camera target (basis="knm"/basis="kxy"). This should be run at the user’s request inbetween optimize() iterations.

Parameters:
  • img (numpy.ndarray) – Image measured by the camera.

  • basis (str) – The correction can be in any of the following bases: - "ij" changes the pixel that the spot is expected at, - "kxy" or "knm" changes the k-vector which the SLM targets. Defaults to "kxy" if None.

Returns:

Euclidean pixel error in the "ij" basis for each spot.

Return type:

numpy.ndarray

remove_vortices()[source]#

Spot holograms do not need to consider vortices.

reset(reset_phase=True, reset_flags=False)[source]#

Resets the hologram to an initial state. Does not restore the preconditioned phase that may have been passed to the constructor (as this information is lost upon optimization). Instead, phase is randomized if reset_phase=True. Also uses the current target rather than the target that may have been passed to the constructor (e.g. includes current refine_offset() changes, etc).

Parameters:
  • reset_phase (bool) – Whether to additionally call reset_phase().

  • reset_flags (bool:) – Whether to erase the information (including passed kwargs) stored in flags.

reset_phase(custom_phase=None, random_phase=None, quadratic_phase=None)[source]#

Resets the hologram to a provided phase, to a random state, or to a quadratic phase which overlaps with the target pattern.

Parameters:
  • custom_phase (array_like OR None) – Custom nearfield initial phase. If not None, then all other parameters are ignored. See phase. phase should only be passed if the user wants to precondition the optimization. Of shape slm_shape.

  • random_phase (float OR None) – Sets the phase to uniformly random phase, scaled to \(2\pi\). Setting random_phase to a fraction of 1 likewise scales the randomness. If None, looks for "random_phase" in flags. This adds with the quadratic_phase parameter.

  • quadratic_phase (bool OR float OR None) – We can also precondition the phase analytically (with a lens and blaze) to roughly the size of the target hologram, according to the first and second order image_moments(). This quadratic preconditioning is thought to help reduce the formation of optical vortices or speckle compared to random initialization, as the analytic distribution is smooth in phase. If None, looks for "quadratic_phase" in flags. If a float is provided, the size of the beam in the farfield is scaled accordingly. This feature is ignored if phase is not None.

reset_weights()[source]#

Resets the hologram weights to the target defaults.

save_stats(file_path, include_state=True)[source]#

Uses save_h5() to export the statistics hierarchy to a given h5 file.

Parameters:
  • file_path (str) – Full path to the file to read the data from.

  • include_state (bool) – If True, also includes all other attributes of Hologram except for dtype (cannot pickle) and amp_ff (can regenerate). These attributes are converted to numpy if necessary. Note that the intent is not to produce a runnable Hologram by default (as this would require pickling hardware interfaces), but rather to provide extra information for debugging.

static set_mempool_limit(device=0, size=None, fraction=None)[source]#

Helper function to set the cupy memory pool size.

Parameters:
  • device (int) – Which GPU to set the limit on. Passed to cupy.cuda.Device().

  • size (int) – Desired number of bytes in the pool. Passed to cupy.cuda.MemoryPool.set_limit().

  • fraction (float) – Fraction of available memory to use. Passed to cupy.cuda.MemoryPool.set_limit().

set_target(new_target=None, reset_weights=False)[source]#

Change the target to something new. This method handles cleaning and normalization.

Parameters:
  • new_target (array_like OR None) – A list with N elements corresponding to the target intensities of each of the N spots. If None, sets the target spot amplitudes the contents of spot_amp.

  • reset_weights (bool) – Whether to overwrite weights with target.

update_target(new_target_ij, null_region=None, null_region_radius_frac=None, reset_weights=False)[source]#

Change the target to something new. This method handles cleaning and normalization.

Parameters:
  • new_target_ij (array_like OR None) – New target_ij to optimize towards in the camera basis. should be of the same shape as the camera. Also updates target using the stored Fourier calibration.

  • null_region (array_like OR None) – Array of shape shape. Where True, sets the background to zero instead of nan. If None, has no effect.

  • null_region_radius_frac (float OR None) – Helper function to set the null_region to zero for Fourier space radius fractions above null_region_radius_frac. This is useful to prevent power being deflected to very high orders, which are unlikely to be properly represented in practice on a physical SLM. If None, defaults to 1 and there is no null region.

  • reset_weights (bool) – Whether to update the weights to this new target.