forked from cjmarvin/crifors
-
Notifications
You must be signed in to change notification settings - Fork 0
/
crifors.py
executable file
·272 lines (243 loc) · 10.9 KB
/
crifors.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#!/usr/bin/env python
"""
CriForS v{0}
CRIRES+ Forward Simulator feeds an input source spectrum into the future ESO
instrument CRIRES+ (Oliva et al. 2014) and outputs a raw 2D image.
Usage:
crifors.py BAND [SOURCE]... [-bnt] [--bglight=BGLIGHT] [--config=CONFIG]
[--dlamb=DLAMB] [--ds9] [--echang=ECHANG] [--factor=FACTOR]
[--model=MODEL] [--nrays=NRAYS] [--nruns=NRUNS] [--outfn=OUTFN]
[--plot | --plot-psf | plot-simple] [--psf=PSF] [--rv=RV]
[--seeing=SEEING] [--slit-width=SLIT] [--verbose=LEVEL]
[--spread] [--polarimeter] [--wavemap]
crifors.py [-h] | [--help] | [--version]
Arguments:
BAND spectral band
SOURCE... input file/s or source spectra [Default: P]
General options:
-h, --help show this help message and exit
--version show version and exit
Simulation options:
-b, --blaze include blaze efficiency
-n, --noise include noise in the simulation
-t, --telluric include telluric lines
-m, --model=MODEL computation model [Default: interp]
--bglight=BGLIGHT background light file
--dlamb=DLAMB wavelength grid resolution in nm [Default: 1e-5]
--echang=ECHANG incident echelle angle [Default: 63.5]
--factor=FACTOR factor to multiply wavelengths to convert to nm
--nrays=NRAYS number of rays [Default: 1e7]
--nruns=NRUNS number of simulation runs [Default: 1]
--psf=PSF psf [Default: gaussian]
--rv=RV radial velocity shift in m/s [Default: 0.0]
--seeing=SEEING seeing in arcseconds [Default: 1.5]
--slit-width=SLIT width of slit in arcseconds [Default: 0.2]
--spread spread out each ray by convolving with a kernel
--polarimeter duplicate each ray with beam splitter separation
--wavemap produce a wavelength map
Other options:
--config=CONFIG simulation config file
--verbose=LEVEL verbosity level [Default: INFO]
--outfn=OUTFN specific output filename
--plot open raytrace plot after simulation and exit
--plot-psf preview slit psf function before simulation and exit
--plot-simple open simple raytrace plot and exit
--ds9 open simulated image in SAO-DS9
Argument details:
BAND
This is a required argument. Must be one of the following spectral
bands: (Y, J, H, K, L, M).
SOURCE...
The input source of the spectrograph.
Input choices:
(p, phoenix) : included PHOENIX synthetic spectrum, T_eff = 3000 K,
[M/H] = 0.0, log(g) = 5.0
This is the default SOURCE argument.
(f, flatfield) : ideal flatfield spectrum. Assumes a flat, uniform
distribution (no lamp emission as of yet).
(<path/to/spectrum.fits/txt>) : path and filename of an input spectrum.
It assumes a 2 column fits or txt file, with wavelengths units in [nm]
in the 1st column and flux in the 2nd column. The filetype can be
either a fits or txt extension.
(<path/to/wavelengths.fits/txt> <path/to/flux.fits/txt>) : paths and
filenames of an input spectrum divided into 2 files.
This assumes 2 fits or txt files, with wavelengths units in [nm]
as the first filepath and flux as the 2nd filepath.
Option details:
-b, --blaze
This flag turns on the option to include blaze efficiency in the
simulation. It should be noted that this is only a rough approximation.
-n, --noise
This flag turns on noise in the simulation. By default, shot noise is
inherent in the raytracing process, but this option is needed to include
dark current and readout noise.
-t, --telluric
This flag adds telluric lines to the input spectrum. Lines are calculated
using LBLRTM code (see Husser & Ulbrich, 2014).
-m, --model=MODEL
The raytracing model to use. This can be of the choices (interp, solve).
Interp is interpolation using Code V output. Solve is solving the physical
model.
--bglight=BGLIGHT
This is the background light file. Not currently supported.
--config=CONFIG
Input configuration file to change instrument or simulation parameters.
--dlamb=DLAMB
The wavelength grid resolution in nm. This typically does not need to be
altered.
--ds9
Calls SAO-DS9 from the shell before exiting.
--echang=ECHANG
The incident echelle angle. If MODEL is 'interp', this can be in
increments of 0.5 from (60.0, 70.0).
--factor=FACTOR
If the wavelengths file is in units other than nm, then supply the factor
to get it in nm.
--nrays=NRAYS
Input number of rays to simulate. Note that due to rays not hitting the
detector, and order overlap, that will not be the exact number of rays
that actually hit the detector. It is only an estimate.
--nruns=NRUNS
Number of simulation iterations. This can be used to increase NRAYS
without sacrificing memory. Also can be used to simulate observing over
time, (ie. tracking, seeing changes, etc.) but this is not yet implemented.
--outfn=OUTFN
Output filename or path.
--plot
Opens an interactive plot of the simulated image and input spectrum
before finishing (N.B. does not automatically write ouput spectrum to fits-file).
--plot-psf
Opens an interactive plot of the slit psf function and exits.
--polarimeter
Adds polarimeter shift to ray coordinates.
--psf=PSF
Point spread function of source. Currently only 'gaussian' is supported.
(point, uniform, gaussian)
--rv=RV
Radial velocity shift in m/s of source.
--seeing=SEEING
Seeing in arcseconds.
--slit-width=SLIT
Width of slit in arcseconds (0.2, 0.4)
--spread
Convolves map of rays with a 2D kernel, boosting signal to noise in order to speed up computation.
--wavemap
Gives output spectrum in wavelength value for each pixel instead of count values.
Examples:
>> python crifors.py J --telluric --noise --nrays=1e9
This will simulate a J band image using the included PHOENIX spectrum.
It will include telluric lines and noise, and will begin with an input
number of rays of 1e9.
>> python crifors.py L ~/Desktop/spectrum.fits --plot
This will create an L band image of the source spectrum in the user's
Desktop, and will open an interactive plot of the image and the spectrum
prior to finishing.
>> python crifors.py K --seeing=2.0 --factor=0.1 ~/documents/waves.txt \
~/documents/flux.fits
This will decrease the seeing to 2 arcseconds, and will convert the
wavelength file, given in Angstroms, to nm.
"""
__author__ = 'Christopher J. Marvin, Mathias Zechmeister'
import numpy as np
import astropy.io.fits as fits
import os
import subprocess
import sys
import time
from version import __version__
import core
from defaults import paths
import logging
# :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# MAIN PROGRAM
# :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
def main():
# PROGRAM START TIME + DATE STAMPS
t0 = time.time()
d0 = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
# PARSE COMMAND LINE ARGUMENTS
_doc_fmt = [__version__]
args = core.docopt(__doc__.format(*_doc_fmt), version=__version__)
log.info("CRIRES+ Forward Simulator (CRIForS) v%s", __version__)
log.info("Start time: %s", d0)
# INITIALIZE INSTRUMENT
instrument = core.Instrument(args)
# INITIALIZE SIMULATION
simulator = core.Simulator(instrument)
# RUN SIMULATION
simulator.run()
# SPREAD OUT EACH RAY
if args["--spread"]:
simulator.spreadout()
# ADD NOISE
if args["--noise"]:
core.noise.add_noise(simulator)
t1 = time.time()
d1 = time.strftime("%Y-%m-%d_%H.%M.%S", time.gmtime())
log.info("End time: %s", d1)
log.info("Run time: %.1f s", t1-t0)
if args["--plot"]:
log.info("Opening plot...")
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure("CRIRES+ Simulation results")
gs = gridspec.GridSpec(2, 1)
ax1 = plt.subplot(gs[0])
ax2 = plt.subplot(gs[1])
if (simulator.wavemap==True):
im= ax1.imshow(simulator.outwaves, origin="lower", interpolation='nearest', cmap="hot",
vmin=simulator.det_wl_lim.min(), vmax=simulator.det_wl_lim.max())
from mpl_toolkits.axes_grid1 import make_axes_locatable # Tool to get axes to colorbar
divider=make_axes_locatable(ax1)
cax=divider.append_axes("right", size="5%", pad=0.05) # Places colorbar next to image with 'nice' size
plt.colorbar(im, ax=ax1, cax=cax) # orientation='horizontal' (remove cax if horizontal bar is desired)
ax1.set_title("CRIRES+ %s-band, echang=%s, Wavemap" % (simulator.band, simulator.echang))
else:
ax1.imshow(simulator.outarr, origin="lower", interpolation='nearest', cmap="hot")
ax1.set_title("CRIRES+ %s-band, echang=%s" % (simulator.band, simulator.echang))
ax2.plot(simulator.source_spectrum[0], simulator.source_spectrum[1])
ax2.set_color_cycle(['yellow', 'gold','goldenrod','orange', 'darkorange', 'OrangeRed',
'red', 'crimson', 'maroon', 'black',])
for mwaves,mpdf in simulator.mwaves_mpdfs:
ax2.plot(mwaves,mpdf)
ax2.set_xlabel("Wavelength (nm)")
ax2.set_ylabel("PDF")
#ax2.set_title("PHOENIX model, Teff=3000K, log(g)=5.0, [M/H]=0.0")
plt.tight_layout()
plt.show()
else:
# WRITE TO FITS FILE
core.write_to_fits(simulator)
# SPAWN FITS OUTPUT IMAGE IN SAO-DS9
if args["--ds9"]:
if os.path.isfile(simulator.outpath + ".fits.gz"):
shell_call = "ds9 %s.fits.gz" % simulator.outpath
elif os.path.isfile(simulator.outpath + ".fits"):
shell_call = "ds9 %s.fits" % simulator.outpath
try:
log.info("Executing '%s'", shell_call)
subprocess.check_call(shell_call.split())
except OSError, e:
log.error(e, exc_info=False)
log.info("Shell call failed. Just run the following line:", exc_info=False)
log.info(shell_call, exc_info=False)
sys.exit(0)
if __name__ == "__main__":
pname = os.path.splitext(os.path.basename(__file__))[0]
log_path = os.path.join(paths.logs_dir, pname)
if not os.path.isdir(log_path):
os.makedirs(log_path)
d0 = time.strftime("%Y-%m-%d_%H.%M.%S", time.gmtime())
fmt = '%(levelname)8s %(asctime)s %(name)16s %(filename)16s:%(lineno)-5s: %(message)s'
logging.basicConfig(level=logging.DEBUG,
format=fmt,
datefmt='%m-%d-%y %H:%M',
filename=os.path.join(log_path, "%s-%s.log" % (pname, d0)),
filemode="w")
log = logging.getLogger(__name__)
formatter = logging.Formatter('%(levelname)8s %(name)16s: %(message)s')
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
main()