Source code for pylorenzmie.analysis.cupyOptimizer
from pylorenzmie.analysis import Optimizer
from pylorenzmie.theory.cupyLorenzMie import cupyLorenzMie
import cupy as cp
[docs]
class cupyOptimizer(Optimizer):
'''GPU-accelerated optimizer using CuPy.
Subclass of :class:`Optimizer` that keeps hologram computation and
residual evaluation on the GPU. Only the final residual vector is
transferred to the CPU for scipy's Levenberg-Marquardt solver.
Inherits from :class:`~pylorenzmie.analysis.Optimizer`.
Parameters
----------
double_precision : bool, optional
If True (default), use double-precision arithmetic on the GPU.
*args, **kwargs
Passed to :class:`Optimizer`.
Notes
-----
The ``method`` attribute is ``'cupy'``, which is a substring of
``cupyLorenzMie.method = 'cupy numpy'``, satisfying the optimizer
compatibility check.
'''
method: str = 'cupy'
def __init__(self, *args,
double_precision: bool = True,
**kwargs) -> None:
super().__init__(*args, **kwargs)
self.model.double_precision = double_precision
@property
def data(self):
return self._data
@data.setter
def data(self, data) -> None:
self._data = data
self.devicedata = (cp.asarray(data, dtype=self.model.dtype)
if data is not None else None)
def _residuals(self, values: list[float]) -> cupyLorenzMie.Image:
'''Compute residuals on the GPU; return numpy array to scipy.'''
self.model.properties = dict(zip(self.variables, values))
noise = self.model.instrument.noise
residuals = (self.model.hologram(device=True) - self.devicedata) / noise
return residuals.get()
if __name__ == '__main__': # pragma: no cover
print('SINGLE PRECISION')
cupyOptimizer.example(double_precision=False)
print('\nDOUBLE PRECISION')
cupyOptimizer.example()