ceo 0.1.0

CUDA Engined Optics
Documentation
% -*- mode: Noweb; noweb-code-mode: python-mode -*-

\section{PXD file}
\label{sec:pxd-file}

<<segmentPistonSensor.pxd>>=
from utilities cimport cuFloatArray, mask, MaskAbstract
from gmtMirrors cimport gmt_m1, GMT_M1
from source cimport complex_amplitude, Complex_amplitude, source, Source
from imaging cimport imaging, Imaging
cdef extern from "segmentPistonSensor.h":
    cdef cppclass segmentPistonSensor:
        int N_LENSLET, N_PX_LENSLET, N_PX, N_PX2, N_PX_IMAGE, N_LAMBDA
        float pixel_scale
        mask lenslet_mask, fft_mask
        complex_amplitude lenslet
        imaging camera, FFT
        void setup(gmt_m1 *, source *, float, float, float)
        void setup(gmt_m1 *, source *, float, float, float, float, int)
        void setup_alt(gmt_m1 *, source *, float, float, float, int)
        void cleanup()
        void cleanup_alt()
        void propagate(source *)
        void propagate(source *, float)
        void propagate_alt(source *)
        void readout(float, float, float)
        void fft()
<<class definition>>
@
\subsection{Class definition}
\label{sec:class-definition}

\index{segmentPistonSensor!python!SegmentPistonSensor}
<<class definition>>=
cdef class SegmentPistonSensor:
    cdef:
        segmentPistonSensor *_c_segmentPistonSensor
        readonly MaskAbstract lenslet_mask, fft_mask
        readonly Complex_amplitude W
        readonly Imaging camera
        readonly cuFloatArray fftlet
        bint MALLOC_DFT
        float middle_mask_width
@
\section{PYX file}
\label{sec:pyx-file}

<<segmentPistonSensor.pyx>>=
from constants import ARCSEC2RAD
cdef class SegmentPistonSensor:
    """
    The segment piston sensor model

    Parameters
    ----------
    M1 : GMT_M1
        The GMT M1 model class
    gs : Source
        The guide star(s) of the segment piston sensor
    lenslet_size: float, optional
        The size of the lenslet; default: 1.5m
    dispersion : float, optional
        The grism dispersion; default: 5arcsec/micron
    field_of_view : float, optional
        The segment piston sensor field-of-view; default: 3 arcsec
    nyquist_factor : float, optional
        The Nyquist sampling factor; default: 1, meaning Nyquist sampling
    middle_mask_width: float, optional
        The width of the band mask in the middle of the lenslet; default: 0

    Attributes
    ----------
    W : Complex_amplitude, read-only
        The piecewise wavefront on the 12 lenslets
    camera : Imaging, read-only
        The detector of the segment piston sensor
    fftlet : cuFloatArray
        The Fourier trasform of the detector framelet
    N_LAMBDA : int
        The number of spectral element
    pixel_Scale : float
        The detector pixel scale

    See also
    --------
    Imaging : the lenslet and detector class
    """
    def __cinit__(self,GMT_M1 M1, Source gs,
                  float lenslet_size=1.5,
                  float dispersion=5.0,
                  float field_of_view=3.0,
                  float nyquist_factor=1.0,
                  int BIN_IMAGE=2,
                  bint MALLOC_DFT=True,
                  float middle_mask_width=0):
        self._c_segmentPistonSensor = new segmentPistonSensor()
        self.MALLOC_DFT = MALLOC_DFT
        self.middle_mask_width = middle_mask_width
        if self.MALLOC_DFT:
            self._c_segmentPistonSensor.setup(M1._c_gmt_m12,
                                              gs._c_source,
                                              lenslet_size,
                                              dispersion*ARCSEC2RAD*1e6,
                                              field_of_view*ARCSEC2RAD,
                                              nyquist_factor,
                                              BIN_IMAGE)
        else:
            self._c_segmentPistonSensor.setup_alt(M1._c_gmt_m12,
                                              gs._c_source,
                                              dispersion*ARCSEC2RAD*1e6,
                                              field_of_view*ARCSEC2RAD,
                                              nyquist_factor,
                                              BIN_IMAGE)

        self.lenslet_mask = MaskAbstract(self._c_segmentPistonSensor.N_PX2)
        self.lenslet_mask._c_mask = &(self._c_segmentPistonSensor.lenslet_mask)
        self.lenslet_mask.f._c_gpu.dev_data = self.lenslet_mask._c_mask.f

        self.W = Complex_amplitude()
        self.W._c_complex_amplitude = &(self._c_segmentPistonSensor.lenslet)
        self.W.__alloc__((self._c_segmentPistonSensor.N_PX,
                          self._c_segmentPistonSensor.N_PX))
        self.camera = Imaging(self._c_segmentPistonSensor.N_LENSLET,
                              self._c_segmentPistonSensor.N_PX_LENSLET,
                              N_PX_IMAGE = self._c_segmentPistonSensor.N_PX_IMAGE,
                              BIN_IMAGE = BIN_IMAGE, isPtr=1)
        self.camera.set_ptr( &(self._c_segmentPistonSensor.camera) )

        self.fft_mask = MaskAbstract( self.camera.N_PX_FRAME**2)
        self.fft_mask._c_mask = &(self._c_segmentPistonSensor.fft_mask)
        self.fft_mask.f._c_gpu.dev_data = self.fft_mask._c_mask.f

        cdef int n
        n = self._c_segmentPistonSensor.FFT.N_SIDE_LENSLET*self._c_segmentPistonSensor.FFT.N_PX_CAMERA
        self.fftlet = cuFloatArray(shape=(n,n))
        self.fftlet._c_gpu.dev_data = self._c_segmentPistonSensor.FFT.d__frame

    def __dealloc__(self):
        if self.MALLOC_DFT:
            self._c_segmentPistonSensor.cleanup()
        else:
            self._c_segmentPistonSensor.cleanup_alt()

    def propagate(self, Source gs):
        """
        Propagates the guide star wavefront from the segment piston sensor pupil plane to the detector in the focal plane

        Parameters
        ----------
        gs : Source
            The segment piston sensor guide star(s)
        """
        if self.MALLOC_DFT:
            if self.middle_mask_width>0:
                self._c_segmentPistonSensor.propagate(gs._c_source, self.middle_mask_width)
            else:
                self._c_segmentPistonSensor.propagate(gs._c_source)
        else:
            self._c_segmentPistonSensor.propagate_alt(gs._c_source)

    def propagate_with_middle_mask(self, Source gs, float mask_bandwidth):
        """
        Propagates the guide star wavefront from the segment piston sensor pupil plane to the detector in the focal plane

        Parameters
        ----------
        gs : Source
            The segment piston sensor guide star(s)
        """
        if self.MALLOC_DFT:
            self._c_segmentPistonSensor.propagate(gs._c_source)
        else:
            self._c_segmentPistonSensor.propagate_alt(gs._c_source)

    def readOut(self, float exposureTime, float readOutNoiseRms, 
                float backgroundMagnitude):
        """
        Reads-out the detector applying photon noise, read-out noise and background noise

        Parameters
        ----------
        exposureTime : float
            The detector exposure time
        readOutNoiseRms : float
            The number of photon-electron rms per pixel
        backgroundMagnitude : float
            The background magnitude per arcsec square
        """
        self._c_segmentPistonSensor.readout(exposureTime, readOutNoiseRms, 
                                            backgroundMagnitude)

    def fft(self):
        """
        Fourier transforms the detector framelets
        """
        self._c_segmentPistonSensor.fft();

    property N_LAMBDA:
        def __get__(self):
            return self._c_segmentPistonSensor.N_LAMBDA

    property N_PX:
        def __get__(self):
            return self._c_segmentPistonSensor.N_PX

    property pixel_scale:
        def __get__(self):
            return self._c_segmentPistonSensor.pixel_scale*2