def test_propagation_round_trip(): screen = phasescreen.ft_phase_screen(0.16, 512, 4.2 / 512, 100, 0.01) # Input E Field E = numpy.exp(1j * screen) prop1 = opticalpropagation.angularSpectrum(E, 500e-9, 4.2 / 512, 4.2 / 512, 10000.) prop2 = opticalpropagation.angularSpectrum(prop1, 500e-9, 4.2 / 512, 4.2 / 512, -10000.) assert numpy.allclose(E, prop2)
def test_propagation_conserves_intensity(): screen = phasescreen.ft_phase_screen(0.16, 512, 4.2 / 512, 100, 0.01) # Input E Field E = numpy.exp(1j * screen) Em = E * circle(150, 512) sum1 = (abs(Em) ** 2).sum() prop1 = opticalpropagation.angularSpectrum(Em, 500e-9, 4.2 / 512, 4.2 / 512, 10000.) sum2 = (abs(prop1) ** 2).sum() assert numpy.allclose(sum1, sum2)
def test_propagation_conserves_intensity(): screen = phasescreen.ft_phase_screen(0.16, 512, 4.2 / 512, 100, 0.01) # Input E Field E = numpy.exp(1j * screen) Em = E * circle(150, 512) sum1 = (abs(Em)**2).sum() prop1 = opticalpropagation.angularSpectrum(Em, 500e-9, 4.2 / 512, 4.2 / 512, 10000.) sum2 = (abs(prop1)**2).sum() assert numpy.allclose(sum1, sum2)
def physical_atmosphere_propagation( phase_screens, output_mask, layer_altitudes, source_altitude, wavelength, output_pixel_scale, propagation_direction="up"): ''' Finds total line of sight complex amplitude by propagating light through phase screens Parameters: radii (dict, optional): Radii of each meta pupil of each screen height in pixels. If not given uses pupil radius. apos (ndarray, optional): The angular position of the GS in radians. If not set, will use the config position ''' scrnNo = len(phase_screens) z_total = 0 scrnRange = range(0, scrnNo) nx_output_pixels = phase_screens[0].shape[0] phs2Rad = 2 * numpy.pi / (wavelength * 10 ** 9) # Get initial up/down dependent params if propagation_direction == "up": ht = 0 ht_final = source_altitude if ht_final==0: raise ValueError("Can't propagate up to infinity") scrnAlts = layer_altitudes EFieldBuf = output_mask.copy().astype(CDTYPE) logger.debug("Create EField Buf of mask") else: ht = layer_altitudes[scrnNo-1] ht_final = 0 scrnAlts = layer_altitudes[::-1] phase_screens = phase_screens[::-1] EFieldBuf = numpy.exp( 1j*numpy.zeros((nx_output_pixels,) * 2)).astype(CDTYPE) logger.debug("Create EField Buf of zero phase") # Propagate to first phase screen (if not already there) if ht!=scrnAlts[0]: logger.debug("propagate to first phase screen") z = abs(scrnAlts[0] - ht) z_total += z EFieldBuf[:] = opticalpropagation.angularSpectrum( EFieldBuf, wavelength, output_pixel_scale, output_pixel_scale, z) # Go through and propagate between phase screens for i in scrnRange: phase = phase_screens[i] # print("Got phase") # Convert phase to radians phase *= phs2Rad # Change sign if propagating up if propagation_direction == 'up': phase *= -1 # print("Get distance") # Get propagation distance for this layer if i==(scrnNo-1): z = abs(ht_final - ht) - z_total else: z = abs(scrnAlts[i+1] - scrnAlts[i]) # Update total distance counter z_total += z # print("Make EField") # Apply phase to EField EFieldBuf *= numpy.exp(1j*phase) # Do ASP for last layer to next EFieldBuf[:] = opticalpropagation.angularSpectrum( EFieldBuf, wavelength, output_pixel_scale, output_pixel_scale, z) # logger.debug("Propagation: {}, {} m. Total: {}".format(i, z, z_total)) return EFieldBuf
def physical_atmosphere_propagation( phase_screens, output_mask, layer_altitudes, source_altitude, wavelength, output_pixel_scale, propagation_direction="up"): ''' Finds total line of sight complex amplitude by propagating light through phase screens Parameters: radii (dict, optional): Radii of each meta pupil of each screen height in pixels. If not given uses pupil radius. apos (ndarray, optional): The angular position of the GS in radians. If not set, will use the config position ''' scrnNo = len(phase_screens) z_total = 0 scrnRange = range(0, scrnNo) prop_scrns = phase_screens.copy() nx_output_pixels = phase_screens[0].shape[0] phs2Rad = 2 * numpy.pi / (wavelength * 10 ** 9) # Get initial up/down dependent params if propagation_direction == "up": ht = 0 ht_final = source_altitude if ht_final==0: raise ValueError("Can't propagate up to infinity") scrnAlts = layer_altitudes EFieldBuf = output_mask.copy().astype(CDTYPE) logger.debug("Create EField Buf of mask") else: ht = layer_altitudes[scrnNo-1] ht_final = 0 scrnAlts = layer_altitudes[::-1] prop_scrns = prop_scrns[::-1] EFieldBuf = numpy.exp( 1j*numpy.zeros((nx_output_pixels,) * 2)).astype(CDTYPE) logger.debug("Create EField Buf of zero phase") # Propagate to first phase screen (if not already there) if ht!=scrnAlts[0]: logger.debug("propagate to first phase screen") z = abs(scrnAlts[0] - ht) z_total += z EFieldBuf[:] = opticalpropagation.angularSpectrum( EFieldBuf, wavelength, output_pixel_scale, output_pixel_scale, z) # Go through and propagate between phase screens for i in scrnRange: phase = prop_scrns[i] # print("Got phase") # Convert phase to radians phase *= phs2Rad # Change sign if propagating up if propagation_direction == 'up': phase *= -1 # print("Get distance") # Get propagation distance for this layer if i==(scrnNo-1): z = abs(ht_final - ht) - z_total else: z = abs(scrnAlts[i+1] - scrnAlts[i]) # Update total distance counter z_total += z # print("Make EField") # Apply phase to EField EFieldBuf *= numpy.exp(1j*phase) # Do ASP for last layer to next EFieldBuf[:] = opticalpropagation.angularSpectrum( EFieldBuf, wavelength, output_pixel_scale, output_pixel_scale, z) # logger.debug("Propagation: {}, {} m. Total: {}".format(i, z, z_total)) return EFieldBuf
def physical_atmosphere_propagation(phase_screens, output_mask, layer_altitudes, source_altitude, wavelength, output_pixel_scale, propagation_direction="up", input_efield=None): ''' Finds total line of sight complex amplitude by propagating light through phase screens If the source altitude is infinity (denoted as 0), then the result of the propagation is the Parameters: ''' scrnNo = len(phase_screens) z_total = 0 scrnRange = range(0, scrnNo) nx_output_pixels = phase_screens[0].shape[0] phs2Rad = 2 * numpy.pi / (wavelength * 10**9) if input_efield is None: EFieldBuf = numpy.exp(1j * numpy.zeros( (nx_output_pixels, ) * 2)).astype(CDTYPE) # Get initial up/down dependent params if propagation_direction == "up": ht = 0 ht_final = source_altitude # if ht_final==0: # raise ValueError("Can't propagate up to infinity") scrnAlts = layer_altitudes # If propagating up from telescope, apply mask to the EField EFieldBuf *= output_mask logger.debug("Create EField Buf of mask") else: ht = layer_altitudes[scrnNo - 1] ht_final = 0 scrnAlts = layer_altitudes[::-1] phase_screens = phase_screens[::-1] logger.debug("Create EField Buf of zero phase") # Propagate to first phase screen (if not already there) if ht != scrnAlts[0]: logger.debug("propagate to first phase screen") z = abs(scrnAlts[0] - ht) z_total += z EFieldBuf[:] = opticalpropagation.angularSpectrum( EFieldBuf, wavelength, output_pixel_scale, output_pixel_scale, z) # Go through and propagate between phase screens for i in scrnRange: phase = phase_screens[i] # print("Got phase") # Convert phase to radians phase *= phs2Rad # Apply phase to EField EFieldBuf *= numpy.exp(1j * phase) # Change sign if propagating up # if propagation_direction == 'up': # phase *= -1 # print("Get distance") # Get propagation distance for this layer if i == (scrnNo - 1): if ht_final == 0: # if the final height is infinity, don't propagate any more! continue else: z = abs(ht_final - ht) - z_total else: z = abs(scrnAlts[i + 1] - scrnAlts[i]) # Update total distance counter z_total += z # print("Make EField") # Do ASP for last layer to next EFieldBuf[:] = opticalpropagation.angularSpectrum( EFieldBuf, wavelength, output_pixel_scale, output_pixel_scale, z) # logger.debug("Propagation: {}, {} m. Total: {}".format(i, z, z_total)) return EFieldBuf
def makePhasePhys(self, radii=None, apos=None): ''' Finds total line of sight complex amplitude by propagating light through phase screens Parameters: radii (dict, optional): Radii of each meta pupil of each screen height in pixels. If not given uses pupil radius. apos (ndarray, optional): The angular position of the GS in radians. If not set, will use the config position ''' scrnNo = len(self.scrns) z_total = 0 scrnRange = range(0, scrnNo) # Get initial up/down dependent params if self.propagationDirection == "up": ht = 0 ht_final = self.config.height if ht_final==0: raise ValueError("Can't propagate up to infinity") scrnAlts = self.atmosConfig.scrnHeights self.EFieldBuf = self.outMask.copy().astype(CDTYPE) logger.debug("Create EField Buf of mask") else: ht = self.atmosConfig.scrnHeights[scrnNo-1] ht_final = 0 scrnRange = scrnRange[::-1] scrnAlts = self.atmosConfig.scrnHeights[::-1] self.EFieldBuf = numpy.exp( 1j*numpy.zeros((self.nx_out_pixels,) * 2)).astype(CDTYPE) logger.debug("Create EField Buf of zero phase") # Propagate to first phase screen (if not already there) if ht!=scrnAlts[0]: logger.debug("propagate to first phase screen") z = abs(scrnAlts[0] - ht) self.EFieldBuf[:] = opticalpropagation.angularSpectrum( self.EFieldBuf, self.wavelength, self.out_pixel_scale, self.out_pixel_scale, z) # Go through and propagate between phase screens for i in scrnRange: # Check optional radii and position if radii is None: radius = None else: radius = radii[i] if self.metaPupilPos is None: pos = None else: pos = self.metaPupilPos[i] # Get phase for this layer phase = self.getMetaPupilPhase( self.scrns[i], self.atmosConfig.scrnHeights[i], radius=radius, pos=pos) # Convert phase to radians phase *= self.phs2Rad # Change sign if propagating up if self.propagationDirection == 'up': self.phase *= -1 # Get propagation distance for this layer if i==(scrnNo-1): z = abs(ht_final - ht) - z_total else: z = abs(scrnAlts[i+1] - scrnAlts[i]) # Update total distance counter z_total += z # Apply phase to EField self.EFieldBuf *= numpy.exp(1j*phase) # Do ASP for last layer to next self.EFieldBuf[:] = opticalpropagation.angularSpectrum( self.EFieldBuf, self.wavelength, self.out_pixel_scale, self.out_pixel_scale, z) logger.debug("Propagation: {}, {} m. Total: {}".format(i, z, z_total)) self.EField[:] = self.EFieldBuf return self.EField