|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# -*- coding: utf-8 -*- |
| 3 | +""" |
| 4 | +
|
| 5 | +Example code demonstrating the use of the PolSpectra class. |
| 6 | +
|
| 7 | +
|
| 8 | +Created on Thu Jun 23 11:37:23 2022 |
| 9 | +
|
| 10 | +@author: cvaneck |
| 11 | +""" |
| 12 | + |
| 13 | +import numpy as np |
| 14 | +import polspectra |
| 15 | + |
| 16 | + |
| 17 | +def Faraday_thin_complex_polarization(freq_array,RM,Polint,initial_angle): |
| 18 | + """Function to produce Stokes Q/U spectra for Faraday simple source. |
| 19 | + freq_array = channel frequencies in Hz |
| 20 | + RM = source RM in rad m^-2 |
| 21 | + Polint = polarized intensity in whatever units |
| 22 | + initial angle = pre-rotation polarization angle (in degrees)""" |
| 23 | + l2_array=(299792458./freq_array)**2 |
| 24 | + Q=Polint*np.cos(2*(np.outer(l2_array,RM)+np.deg2rad(initial_angle))) |
| 25 | + U=Polint*np.sin(2*(np.outer(l2_array,RM)+np.deg2rad(initial_angle))) |
| 26 | + return np.squeeze(np.transpose(Q+1j*U)) |
| 27 | + |
| 28 | + |
| 29 | +#Set up channel frequencies for all sources. |
| 30 | +N_chan=288 |
| 31 | +freq_arr=np.linspace(800e6,1088e6,num=N_chan) |
| 32 | + |
| 33 | +N_spectra=100 |
| 34 | + |
| 35 | +#Creating random spectra. This produces lists of arrays for each Stokes parameter. |
| 36 | +I_spectra=[] |
| 37 | +Q_spectra=[] |
| 38 | +U_spectra=[] |
| 39 | +noise_amplitude=0.001 |
| 40 | +for i in range(N_spectra): |
| 41 | + #Stokes I spectra are power laws with random brightnesses. |
| 42 | + Ivalues=np.random.lognormal(mean=-2,sigma=1,size=N_chan)*(freq_arr/np.mean(freq_arr))**-0.7 |
| 43 | + polarization=Faraday_thin_complex_polarization(freq_arr,RM=np.random.uniform(-1000,1000), #Random RM |
| 44 | + Polint=np.random.uniform(0,0.7), #Random fractional polarization |
| 45 | + initial_angle=np.random.uniform(0,180)) #Random angle |
| 46 | + I_spectra.append(Ivalues+noise_amplitude*np.random.normal(0,1,N_chan)) |
| 47 | + Q_spectra.append(Ivalues*polarization.real+noise_amplitude*np.random.normal(0,1,N_chan)) |
| 48 | + U_spectra.append(Ivalues*polarization.imag+noise_amplitude*np.random.normal(0,1,N_chan)) |
| 49 | + |
| 50 | +#Make the corresponding Stokes uncertainty arrays, for each source. |
| 51 | +I_errors=[np.repeat(noise_amplitude,N_chan) for x in range(N_spectra)] |
| 52 | +Q_errors=[np.repeat(noise_amplitude,N_chan) for x in range(N_spectra)] |
| 53 | +U_errors=[np.repeat(noise_amplitude,N_chan) for x in range(N_spectra)] |
| 54 | + |
| 55 | +#Random coordinates: |
| 56 | +ra_array=np.random.uniform(0,360,N_spectra) |
| 57 | +dec_array=np.random.uniform(-90,90,N_spectra) |
| 58 | + |
| 59 | + |
| 60 | +#Create the PolSpectra table. |
| 61 | +#Note that freq_arr is a single 1D array; the code knows it should be 2D |
| 62 | +#or a list of arrays, so it assumes all sources have the same frequency |
| 63 | +#values and expands it to the appropriate dimensions. |
| 64 | +#Setting the source_number column using range(N_spectra) gives each source |
| 65 | +#a unique ID number. Quantities that are common to all sources, such as the |
| 66 | +#beam size, can be set for all sources using single values. |
| 67 | +#Optional channels defined in the standard (such as coordinate_system and |
| 68 | +#channel_width) can also be added. |
| 69 | +spectrumtable=polspectra.from_arrays(ra_array,dec_array,freq_arr, |
| 70 | + I_spectra,I_errors,Q_spectra,Q_errors,U_spectra,U_errors, |
| 71 | + source_number_array=range(N_spectra), |
| 72 | + beam_maj=0.01,beam_min=0.01,beam_pa=0, |
| 73 | + coordinate_system='icrs',channel_width=1e6) |
| 74 | + |
| 75 | + |
| 76 | +#Including an extra column, that isn't part of the standard: |
| 77 | +extra_column=np.random.randint(0,100,size=N_spectra) |
| 78 | +spectrumtable.add_column(extra_column,name='random_integer', |
| 79 | + description='A random integer for each source',units='') |
| 80 | + |
| 81 | +#Manipulate table, extracting columns and rows: |
| 82 | +print(spectrumtable[10]) |
| 83 | +print(spectrumtable['ra']) |
| 84 | + |
| 85 | + |
| 86 | + |
| 87 | +print(spectrumtable.columns) |
| 88 | + |
| 89 | + |
| 90 | +#Extract all data for a specific source: |
| 91 | +print(spectrumtable[spectrumtable['source_number'] == 5]) |
| 92 | + |
| 93 | + |
| 94 | +#A verification function is provided which confirms that all columns |
| 95 | +#have consistent numbers of channels (per row), and provides warnings |
| 96 | +#if certain parameters (frequencies, beam sizes) seem like they may |
| 97 | +#have the wrong units. |
| 98 | +spectrumtable.verify_table() |
| 99 | + |
| 100 | + |
| 101 | +spectrumtable.write_FITS('example_polspectra.fits',overwrite=True) |
| 102 | +table_from_file=polspectra.from_FITS('example_polspectra.fits') |
| 103 | + |
| 104 | + |
| 105 | + |
| 106 | + |
0 commit comments