From d91a204965ca9613ffa1483c06bb21443acf28aa Mon Sep 17 00:00:00 2001 From: Gilles Orban de Xivry Date: Thu, 4 Jan 2018 16:23:53 +0100 Subject: [PATCH 1/5] fix bugs for LGS --- soapy/confParse.py | 1 + soapy/wfs/base.py | 4 ++-- soapy/wfs/shackhartmann.py | 12 ++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/soapy/confParse.py b/soapy/confParse.py index 98e6ccd2..4289dd41 100755 --- a/soapy/confParse.py +++ b/soapy/confParse.py @@ -907,6 +907,7 @@ def calcParams(self): self.wavelength = float(self.wavelength) self.height = float(self.height) + self.launchPosition = numpy.array(self.launchPosition) class DmConfig(ConfigObj): """ diff --git a/soapy/wfs/base.py b/soapy/wfs/base.py index dcbdeac8..ee5642db 100644 --- a/soapy/wfs/base.py +++ b/soapy/wfs/base.py @@ -83,7 +83,7 @@ import aotools -from .. import AOFFT, LGS, logger, lineofsight_legacy +from .. import AOFFT, LGS, logger, lineofsight_legacy, interp # xrange now just "range" in python3. # Following code means fastest implementation used in 2 and 3 @@ -287,7 +287,7 @@ def calcElongPhaseAddition(self, elongLayer): h = self.elongHeights[elongLayer] dh = h - self.config.GSHeight H = float(self.lgsConfig.height) - d = numpy.array(self.lgsLaunchPos).astype('float32') * self.los.telDiam/2. + d = numpy.array(self.lgsLaunchPos).astype('float32') * self.los.telescope_diameter/2. D = self.telescope_diameter theta = (d.astype("float")/H) - self.config.GSPosition diff --git a/soapy/wfs/shackhartmann.py b/soapy/wfs/shackhartmann.py index ebe1332b..2e29395e 100644 --- a/soapy/wfs/shackhartmann.py +++ b/soapy/wfs/shackhartmann.py @@ -199,9 +199,9 @@ def initFFTs(self): (self.n_subaps, self.subapFFTPadding, self.subapFFTPadding), dtype=CDTYPE) self.iFFT = pyfftw.FFTW( self.ifft_input_data, self.ifft_output_data, axes=(-2, -1), - threads=self.threads, flags=(self.config.fftwFlag, "FFTW_DESTROY_INPUT"), - direction="FFTW_BACKWARD" - ) + threads=self.threads, flags=(self.config.fftwFlag, "FFTW_DESTROY_INPUT")) #, + # direction="FFTW_BACKWARD" + # ) self.lgs_ifft_input_data = pyfftw.empty_aligned( (self.subapFFTPadding, self.subapFFTPadding), dtype=CDTYPE) @@ -209,9 +209,9 @@ def initFFTs(self): (self.subapFFTPadding, self.subapFFTPadding), dtype=CDTYPE) self.lgs_iFFT = pyfftw.FFTW( self.lgs_ifft_input_data, self.lgs_ifft_output_data, axes=(0, 1), - threads=self.threads, flags=(self.config.fftwFlag, "FFTW_DESTROY_INPUT"), - direction="FFTW_BACKWARD" - ) + threads=self.threads, flags=(self.config.fftwFlag, "FFTW_DESTROY_INPUT")) #, + # direction="FFTW_BACKWARD" + # ) def initLGS(self): super(ShackHartmann, self).initLGS() From 2423fadc965548a288ebda6ebb5d53b04df4cf64 Mon Sep 17 00:00:00 2001 From: Gilles Orban de Xivry Date: Thu, 4 Jan 2018 17:27:12 +0100 Subject: [PATCH 2/5] WIP to implement uplink TT correction --- soapy/wfs/base.py | 19 ++++++++++++++++++- soapy/wfs/shackhartmann.py | 13 +++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/soapy/wfs/base.py b/soapy/wfs/base.py index ee5642db..b452f870 100644 --- a/soapy/wfs/base.py +++ b/soapy/wfs/base.py @@ -161,6 +161,17 @@ def __init__( self.calcTiltCorrect() self.getStatic() + # Set up array for tip-tilt uplink compensation + self._upTTCommand = numpy.array([0, 0]) + + self._nx_elements = int(round(self.pupil_size)) + coords = numpy.linspace( + -1, 1, self._nx_elements) + self.tip1arcsec, self.tilt1arcsec = numpy.meshgrid(coords, coords) + tt_amp = -(ASEC2RAD * self.soapy_config.tel.telDiam/2.) * 1e9 + self.tip1arcsec *= tt_amp + self.tilt1arcsec *= tt_amp + ############################################################ # Initialisation routines @@ -429,7 +440,7 @@ def frame(self, scrns, phase_correction=None, read=True, iMatFrame=False): self.uncorrectedPhase = self.los.phase.copy()/self.los.phs2Rad if phase_correction is not None: self.los.performCorrection(phase_correction) - + self.calcFocalPlane() if read: @@ -481,6 +492,12 @@ def makeDetectorPlane(self): def LGSUplink(self): pass + def correctUplinkTilt(self, phase): + self._upTTCommand += self.config.uplinkgain * self._tiptilt + + phase -= self._upTTCommand[0] * self.tip1arcsec + phase -= self._upTTCommand[1] * self.tilt1arcsec + def calculateSlopes(self): self.slopes = self.los.EField diff --git a/soapy/wfs/shackhartmann.py b/soapy/wfs/shackhartmann.py index 2e29395e..e9c0fec2 100644 --- a/soapy/wfs/shackhartmann.py +++ b/soapy/wfs/shackhartmann.py @@ -74,7 +74,7 @@ def calcInitParams(self): self.SUBAP_OVERSIZE = 1 else: self.SUBAP_OVERSIZE = 2 - + self.nx_detector_pixels = self.nx_subaps * (self.nx_subap_pixels + self.nx_guard_pixels) + self.nx_guard_pixels self.nx_subap_interp *= self.SUBAP_OVERSIZE @@ -442,8 +442,13 @@ def calculateSlopes(self): self.slopes[:] = slopes.reshape(self.n_subaps * 2) if self.config.removeTT == True: - self.slopes[:self.n_subaps] -= self.slopes[:self.n_subaps].mean() - self.slopes[self.n_subaps:] -= self.slopes[self.n_subaps:].mean() + _tip = self.slopes[:self.n_subaps].mean() + _tilt = self.slopes[self.n_subaps:].mean() + self._tiptilt = numpy.array([_tip, _tilt]) + self.slopes[:self.n_subaps] -= self._tiptilt[0] + # self.slopes[:self.n_subaps].mean() + self.slopes[self.n_subaps:] -= self._tiptilt[1] + # self.slopes[self.n_subaps:].mean() if self.config.angleEquivNoise and not self.iMat: pxlEquivNoise = ( @@ -579,4 +584,4 @@ def photons_per_mag(mag, mask, phase_scale, exposureTime, zeropoint): # N photons for mag and exposure time n_photons *= (10**(-float(mag)/2.5)) * exposureTime - return n_photons \ No newline at end of file + return n_photons From 8cbf24546f1b7ad3059dae3eb1c763cbcee9beed Mon Sep 17 00:00:00 2001 From: Gilles Orban de Xivry Date: Fri, 5 Jan 2018 09:58:09 +0100 Subject: [PATCH 3/5] LGS tip-tilt correction implemented. NB: LGS effects deactivated during IMAT (e.g. no spot elongation) --- soapy/confParse.py | 7 ++++++ soapy/wfs/base.py | 44 +++++++++++++++++++++++++++----------- soapy/wfs/shackhartmann.py | 6 +++--- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/soapy/confParse.py b/soapy/confParse.py index 4289dd41..c6b3f2a1 100755 --- a/soapy/confParse.py +++ b/soapy/confParse.py @@ -871,6 +871,10 @@ class LgsConfig(ConfigObj): ``naProfile`` list: The relative sodium layer strength for each elongation layer. If None, all equal. ``None`` + ``correctLgsTT`` bool: correct the LGS tip-tilt on ``False`` + the sensor. Required 'removeTT' + == True and 'uplinkgain>0' + ``uplinkgain`` float: LGS tip-tilt gain 0 ==================== ================================= =========== """ @@ -888,6 +892,8 @@ class LgsConfig(ConfigObj): ("elongationLayers", 10), ("launchPosition", numpy.array([0,0])), ("naProfile", None), + ("correctLgsTT", False), + ("uplinkgain", 0) ] calculatedParams = ["position"] @@ -908,6 +914,7 @@ def calcParams(self): self.wavelength = float(self.wavelength) self.height = float(self.height) self.launchPosition = numpy.array(self.launchPosition) + self.uplinkgain = float(self.uplinkgain) class DmConfig(ConfigObj): """ diff --git a/soapy/wfs/base.py b/soapy/wfs/base.py index b452f870..8c9aa63e 100644 --- a/soapy/wfs/base.py +++ b/soapy/wfs/base.py @@ -162,15 +162,27 @@ def __init__( self.getStatic() # Set up array for tip-tilt uplink compensation - self._upTTCommand = numpy.array([0, 0]) - - self._nx_elements = int(round(self.pupil_size)) - coords = numpy.linspace( - -1, 1, self._nx_elements) - self.tip1arcsec, self.tilt1arcsec = numpy.meshgrid(coords, coords) - tt_amp = -(ASEC2RAD * self.soapy_config.tel.telDiam/2.) * 1e9 - self.tip1arcsec *= tt_amp - self.tilt1arcsec *= tt_amp + if self.config.lgs: + if self.lgsConfig.correctLgsTT: + self._upTTCommand = numpy.array([0, 0], dtype='float') + self._tiptilt = numpy.array([0, 0], dtype='float') + self._nx_elements = int(round(self.sim_size)) + fact = self.sim_size / self.pupil_size + coords = numpy.linspace( + -1 * fact, 1 * fact, self._nx_elements) / 2 + self.tip1arcsec, self.tilt1arcsec = numpy.meshgrid(coords, + coords) + + tt_amp = -(ASEC2RAD * self.soapy_config.tel.telDiam/2.) * 1e9 + self.tip1arcsec *= tt_amp + self.tilt1arcsec *= tt_amp + + if self.config.removeTT == 0: + logger.warning("LGS tiptilt correction will not work: " + "correctLgs==1 but removeTT==0") + if self.lgsConfig.uplinkgain == 0: + logger.warning("LGS tiptilt correction will not work: " + "correctLgs==1 but uplinkgain==0") ############################################################ # Initialisation routines @@ -421,6 +433,8 @@ def frame(self, scrns, phase_correction=None, read=True, iMatFrame=False): self.iMat = True removeTT = self.config.removeTT self.config.removeTT = False + lgsDic = self.config.lgs + self.config.lgs = None photonNoise = self.config.photonNoise self.config.photonNoise = False eReadNoise = self.config.eReadNoise @@ -429,6 +443,9 @@ def frame(self, scrns, phase_correction=None, read=True, iMatFrame=False): self.zeroData(detector=read, FP=False) self.los.frame(scrns) + if self.config.lgs: + if self.lgsConfig.correctLgsTT: + self.correctUplinkTilt() # If LGS elongation simulated if self.config.lgs and self.elong!=0: @@ -452,6 +469,7 @@ def frame(self, scrns, phase_correction=None, read=True, iMatFrame=False): if iMatFrame: self.iMat=False self.config.removeTT = removeTT + self.config.lgs = lgsDic self.config.photonNoise = photonNoise self.config.eReadNoise = eReadNoise @@ -492,11 +510,11 @@ def makeDetectorPlane(self): def LGSUplink(self): pass - def correctUplinkTilt(self, phase): - self._upTTCommand += self.config.uplinkgain * self._tiptilt + def correctUplinkTilt(self): + self._upTTCommand += self.lgsConfig.uplinkgain * self._tiptilt - phase -= self._upTTCommand[0] * self.tip1arcsec - phase -= self._upTTCommand[1] * self.tilt1arcsec + self.los.phase -= self._upTTCommand[0] * self.tip1arcsec + self.los.phase -= self._upTTCommand[1] * self.tilt1arcsec def calculateSlopes(self): self.slopes = self.los.EField diff --git a/soapy/wfs/shackhartmann.py b/soapy/wfs/shackhartmann.py index e9c0fec2..b5ca8b87 100644 --- a/soapy/wfs/shackhartmann.py +++ b/soapy/wfs/shackhartmann.py @@ -444,11 +444,11 @@ def calculateSlopes(self): if self.config.removeTT == True: _tip = self.slopes[:self.n_subaps].mean() _tilt = self.slopes[self.n_subaps:].mean() - self._tiptilt = numpy.array([_tip, _tilt]) - self.slopes[:self.n_subaps] -= self._tiptilt[0] + self.slopes[:self.n_subaps] -= _tip # self.slopes[:self.n_subaps].mean() - self.slopes[self.n_subaps:] -= self._tiptilt[1] + self.slopes[self.n_subaps:] -= _tilt # self.slopes[self.n_subaps:].mean() + self._tiptilt = numpy.array([_tip, _tilt]) * self.pixel_scale if self.config.angleEquivNoise and not self.iMat: pxlEquivNoise = ( From 4b51f31650d15d98823fd4950896c35e386b1d7e Mon Sep 17 00:00:00 2001 From: Gilles Orban de Xivry Date: Wed, 10 Jan 2018 13:34:34 +0100 Subject: [PATCH 4/5] LGS uplink correction of sign --- soapy/wfs/shackhartmann.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soapy/wfs/shackhartmann.py b/soapy/wfs/shackhartmann.py index b5ca8b87..1f169afc 100644 --- a/soapy/wfs/shackhartmann.py +++ b/soapy/wfs/shackhartmann.py @@ -399,7 +399,7 @@ def applyLgsUplink(self): self.lgs.getLgsPsf(self.los.scrns) - self.lgs_ifft_input_data[:] = self.lgs.psf[::-1, ::-1] + self.lgs_ifft_input_data[:] = self.lgs.psf #self.lgs.psf[::-1, ::-1] self.lgs_iFFT() self.ifft_input_data[:] = self.subap_focus_intensity From cae302d105643800452b152918977164e1516a40 Mon Sep 17 00:00:00 2001 From: Gilles Orban de Xivry Date: Tue, 13 Nov 2018 13:16:48 +0100 Subject: [PATCH 5/5] revert to LGS FFTW backward for iFFT --- soapy/wfs/shackhartmann.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/soapy/wfs/shackhartmann.py b/soapy/wfs/shackhartmann.py index 1f169afc..e5445151 100644 --- a/soapy/wfs/shackhartmann.py +++ b/soapy/wfs/shackhartmann.py @@ -199,9 +199,8 @@ def initFFTs(self): (self.n_subaps, self.subapFFTPadding, self.subapFFTPadding), dtype=CDTYPE) self.iFFT = pyfftw.FFTW( self.ifft_input_data, self.ifft_output_data, axes=(-2, -1), - threads=self.threads, flags=(self.config.fftwFlag, "FFTW_DESTROY_INPUT")) #, - # direction="FFTW_BACKWARD" - # ) + threads=self.threads, flags=(self.config.fftwFlag, "FFTW_DESTROY_INPUT"), + direction="FFTW_BACKWARD") self.lgs_ifft_input_data = pyfftw.empty_aligned( (self.subapFFTPadding, self.subapFFTPadding), dtype=CDTYPE) @@ -209,9 +208,8 @@ def initFFTs(self): (self.subapFFTPadding, self.subapFFTPadding), dtype=CDTYPE) self.lgs_iFFT = pyfftw.FFTW( self.lgs_ifft_input_data, self.lgs_ifft_output_data, axes=(0, 1), - threads=self.threads, flags=(self.config.fftwFlag, "FFTW_DESTROY_INPUT")) #, - # direction="FFTW_BACKWARD" - # ) + threads=self.threads, flags=(self.config.fftwFlag, "FFTW_DESTROY_INPUT"), + direction="FFTW_BACKWARD") def initLGS(self): super(ShackHartmann, self).initLGS()