ztf_sim_introduction

This notebook illustrates basic use of the ztf_sim modules.


In [2]:
# hack to get the path right
import sys
sys.path.append('..')

In [4]:
import ztf_sim
from astropy.time import Time
import pandas as pd
import numpy as np
import astropy.units as u
import pylab as plt

First we'll generate a test field grid. You only need to do this the first time you run the simulator.


In [7]:
ztf_sim.fields.generate_test_field_grid()

Let's load the Fields object with the default field grid. Fields is a thin wrapper around a pandas DataFrame containing the field information.


In [3]:
f = ztf_sim.fields.Fields()

The raw fieldid and coordinates are stored as a pandas Dataframe in the .fields attribute:


In [5]:
f.fields.head()


Out[5]:
ra dec l b ecliptic_lon ecliptic_lat gridid
fieldid
1 24.71429 -85.93846 301.9583 -31.0998 279.8749 -67.9653 0
2 76.14286 -85.93846 298.7880 -28.8932 272.9102 -70.4811 0
3 127.57143 -85.93846 298.8484 -25.3715 262.8704 -69.6372 0
4 179.00000 -85.93846 301.8744 -23.1810 259.8520 -66.3010 0
5 230.42857 -85.93846 305.6390 -23.8833 264.2344 -63.3114 0

Now let's calculate their altitude and azimuth at a specific time using the astropy.time.Time object:


In [7]:
f.alt_az(Time.now()).head()


Out[7]:
alt az
fieldid
1 -31.134010 175.873088
2 -34.626053 175.327344
3 -37.135161 178.378502
4 -36.638405 182.738308
5 -33.548102 184.803689

Demonstrating low-level access to fields by the fieldid index (usually not required):


In [5]:
f.fields.loc[853]


Out[5]:
ra              141.50000
dec              66.36923
l               146.99200
b                39.82990
ecliptic_lon    117.86480
ecliptic_lat     47.84160
gridid            0.00000
Name: 853, dtype: float64

We can select fields with conditionals:


In [8]:
f.fields['dec'] > -30.


Out[8]:
fieldid
1       False
2       False
3       False
4       False
5       False
6       False
7       False
8       False
9       False
10      False
11      False
12      False
13      False
14      False
15      False
16      False
17      False
18      False
19      False
20      False
21      False
22      False
23      False
24      False
25      False
26      False
27      False
28      False
29      False
30      False
        ...  
1877     True
1878     True
1879     True
1880     True
1881     True
1882     True
1883     True
1884     True
1885     True
1886     True
1887     True
1888     True
1889     True
1890     True
1891     True
1892     True
1893     True
1894     True
1895     True
1896     True
1897     True
1898     True
1899     True
1900     True
1901     True
1902     True
1903     True
1904     True
1905     True
1906     True
Name: dec, dtype: bool

It's easier to use the select_fields convenience function, though. It returns a boolean Series indexed by fieldid that we can use to do calculations on subsets of the field grid.


In [15]:
cuts = f.select_fields(dec_range=[0,10],gridid=0,ecliptic_lat_range=[-5,5])
cuts.head()


Out[15]:
fieldid
1    False
2    False
3    False
4    False
5    False
dtype: bool

Calculate the current altitude and azimuth of the selected fields:


In [13]:
f.alt_az(Time.now(),cuts=cuts)


Out[13]:
alt az
fieldid
454 49.138756 128.947449
455 44.316111 121.449922
456 39.119046 115.075923
476 -52.241055 350.229286
477 -50.685836 339.194556
478 -48.112472 329.112148
479 -44.696989 320.172906

Calculating the overhead time (max of ha, dec, dome slews and readout time):


In [12]:
f.overhead_time(853,Time.now())


Out[12]:
overhead_time
fieldid
1 133.923075
2 133.923075
3 133.923075
4 133.923075
5 133.923075
6 133.923075
7 133.923075
8 128.153842
9 128.153842
10 128.153842
11 128.153842
12 128.153842
13 128.153842
14 128.153842
15 128.153842
16 128.153842
17 128.153842
18 128.153842
19 128.153842
20 128.153842
21 122.384617
22 122.384617
23 122.384617
24 122.384617
25 122.384617
26 122.384617
27 122.384617
28 122.384617
29 122.384617
30 122.384617
... ...
1877 31.329051
1878 43.171157
1879 55.013263
1880 66.855370
1881 78.697470
1882 90.539576
1883 102.381682
1884 114.223788
1885 110.785957
1886 98.943851
1887 84.368957
1888 67.061263
1889 49.753570
1890 32.445876
1891 21.225958
1892 21.225958
1893 31.329051
1894 48.636745
1895 65.944438
1896 83.252126
1897 100.559820
1898 117.867513
1899 101.676645
1900 76.951370
1901 44.808513
1902 26.692308
1903 31.329051
1904 63.471907
1905 95.614763
1906 109.094232

1812 rows × 1 columns


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:
f = ztf_sim.fields.Fields()
Exposure_time = 60*u.second
Night_length=9*u.h


time0 = Time('2015-09-10 20:00:00') + 7*u.h
time = time0
f.fields = f.fields.join(pd.DataFrame(np.zeros(len(f.fields)),columns=['observed']))
f.fields = f.fields.join(pd.DataFrame(np.zeros(len(f.fields)),columns=['possibleToObserve']))

def observe(f, nightStart):
    time=nightStart
    goodAltitude = f.alt_az(time)['alt'] > 20
    shouldObserve = f.fields['observed'] == 0
    good = goodAltitude & shouldObserve #& f.alt_az(time+1*u.h)['alt'] < 20 # start with a field which won't be observable later
    
    if np.all(good) is False:
        good = goodAltitude & shouldObserve
        
    fid = f.fields[good].iloc[0].name
    f.fields['observed'][fid]+=1
    f.fields['possibleToObserve'][goodAltitude] = 1
    time += Exposure_time

    while time < nightStart + Night_length:
        goodAltitude = f.alt_az(time)['alt'] > 20
        shouldObserve = f.fields['observed'] == 0
        good = goodAltitude & shouldObserve
        f.fields['possibleToObserve'][goodAltitude] = 1
        
        if not np.any(good):
            time += 60*u.s
            continue
            
        slewTime = f.overhead_time(fid,time)[good]
        fid = int(slewTime.idxmin())
        # print slewTime['overhead_time'][fid]
        time += Exposure_time + slewTime['overhead_time'][fid]*u.second
        f.fields['observed'][fid]+=1
        # print time-7*u.h
        

# First night
observe(f,time)
fieldsPossible = np.sum(f.fields['possibleToObserve'])
print fieldsPossible
fieldsObserved = np.sum(f.fields['observed'])
print fieldsObserved
meanTime = (Night_length.to(u.s)-fieldsObserved*Exposure_time)/(fieldsObserved-1)
print meanTime

# Second night
time=time0+24*u.h
observe(f,time)
fieldsPossible = np.sum(f.fields['possibleToObserve'])
print fieldsPossible
fieldsObserved = np.sum(f.fields['observed'])
print fieldsObserved
meanTime = (2*Night_length.to(u.s)-fieldsObserved*Exposure_time)/(fieldsObserved-1)
print meanTime

In [ ]:
for dec in np.append(np.linspace(-90,90,10),0):
    ra=np.linspace(0, 360,1000)
    x,y = raDec2xy(ra,dec)
    plt.plot(x,y,'k')
    
for ra in np.linspace(0,360,10):
    dec=np.linspace(-90, 90,1000)
    x,y = raDec2xy(ra,dec)
    plt.plot(x,y,'k')
    
x,y = raDec2xy(f.fields['ra'],f.fields['dec'])
plt.plot(x,y,'o',color=(.8,.8,.8))    
plt.show()

In [6]:
def raDec2xy(ra,dec):
    # Using Aitoff projections (from Wiki) returns x-y coordinates on a plane of RA and Dec
    theta = np.deg2rad(dec)
    phi = np.deg2rad(ra)-np.pi #the range is [-pi,pi]
    alpha=np.arccos(np.cos(theta)*np.cos(phi/2))
    x=2*np.cos(theta)*np.sin(phi/2)/np.sinc(alpha/np.pi) # The python's sinc is normalazid, hence the /pi
    y=np.sin(theta)/np.sinc(alpha/np.pi)
    return x,y

In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]: