def process_Rfwhm(Rfwhm, wa, model, models): """ Convolve the input models using the Rfwhm option Return the new models. wa: wavelength array, shape (N,) model: model flux array, shape (N,) models: list of model flux arrays each with shape (N,) Rfwhm is one of: 'convolve_with_COS_FOS' a float an array floats with shape (N,) Returns ------- new_model, new_models """ model_out = None models_out = [] #import pdb; pdb.set_trace() if Rfwhm is None: return model, models elif Rfwhm == 'convolve_with_COS_FOS': #print 'convolving with COS/FOS instrument profile' #import pdb; pdb.set_trace() model_out = convolve_with_COS_FOS(model, wa, use_COS_nuv=True) for m in models: #if m.min() < (1 - 1e-2): m = convolve_with_COS_FOS(m, wa, use_COS_nuv=True) models_out.append(m) elif isinstance(Rfwhm, float): #print 'Convolving with fwhm %.2f km/s' % Rfwhm # use a pixel velocity width 4 times smaller than the FWHM ndiv = 4. try: wa_dv = make_constant_dv_wa_scale(wa[0], wa[-1], Rfwhm / ndiv) except: import pdb pdb.set_trace() model_out = convolve_constant_dv(wa, model, wa_dv, ndiv) # do the same to every model if there's more than one for m in models: #if m.min() < (1 - 1e-2): m = convolve_constant_dv(wa, m, wa_dv, ndiv) models_out.append(m) else: raise ValueError('Unknown value for Rfwhm option') return model_out, models_out
def ymodel(wa, pars): """Generate the model normalised flux array for every region. Note this needs the global variables `lines_vary` and `regions` to be defined. """ linepars = pars dz = 0 if options['wa_vary']: linepars, regpars = pars[:-len(regions)], pars[-len(regions):] lines = copy_par_to_lines(linepars, lines_vary) fl = [] for ireg, (wa, tau0, sp, (i, j),tname) in enumerate(regions): tau = tau0.copy() for l in lines: if options['wa_vary']: dz = regpars[ireg] / wa[len(wa)//2] * (l.z + 1) trans = atom[l.name.strip()] tau += calc_iontau(wa, trans, l.z+1 + dz, l.logN, l.b) dwpix = wa[1] - wa[0] flmodel0 = convolve_with_COS_FOS(np.exp(-tau), wa, dwpix) flmodel = np.interp(sp.wa[i:j], wa, flmodel0) fl.extend(flmodel) return fl
def process_Rfwhm(Rfwhm, wa, model, models): """ Convolve the input models using the Rfwhm option Return the new models. wa: wavelength array, shape (N,) model: model flux array, shape (N,) models: list of model flux arrays each with shape (N,) Rfwm is one of: 'convolve_with_COS_FOS' a float Returns ------- new_model, new_models """ model_out = None models_out = [] if Rfwhm is None: return model, models elif Rfwhm == 'convolve_with_COS_FOS': print 'convolving with COS/FOS instrument profile' model_out = convolve_with_COS_FOS(model, wa, wa[1] - wa[0]) models_out = [convolve_with_COS_FOS(m, wa, wa[1] - wa[0]) for m in models] elif isinstance(Rfwhm, float): print 'Convolving with fwhm %.2f km/s' % Rfwhm # use a pixel velocity width 4 times smaller than the FWHM ndiv = 4. wa_dv = make_constant_dv_wa_scale(wa[0], wa[-1], Rfwhm / ndiv) model_out = convolve_constant_dv(wa, model, wa_dv, ndiv) # do the same to every model if there's more than one for m in models: models_out.append(convolve_constant_dv(wa, m, wa_dv, ndiv)) else: raise ValueError('Unknown value for Rfwhm option') return model_out, models_out
def plot_model(pars): """ `regions`, `x` must be defined in the model.py module namespace """ from run_emcee.plot_mcmc import get_fig_axes, get_nrows_ncols linepars = pars dz = 0 if options['wa_vary']: linepars, regpars = pars[:-len(regions)], pars[-len(regions):] lines = copy_par_to_lines(linepars, lines_vary) nrows, ncols = get_nrows_ncols(len(regions)) fig, axes = get_fig_axes(nrows, ncols, len(regions), width=8.2) fig.subplots_adjust(wspace=1e-6, hspace=1e-6, right=1, top=1, left=0.07, bottom=0.06) z0 = lines.z[1] zp1 = lines.z.mean() colours = dict(J0='purple',J1='g',J2='r',J3='b') for ind, (wa, tau0, sp, (i, j), tname) in enumerate(regions): tau = tau0.copy() for l in lines: if options['wa_vary']: #import pdb; pdb.set_trace() dz = regpars[ind] / wa[len(wa)//2] * (l.z + 1) #print l.z, dz, l.logN trans = atom[l.name.strip()] tau += calc_iontau(wa, trans, l.z+1 + dz, l.logN, l.b) dwpix = wa[1] - wa[0] flmodel0 = convolve_with_COS_FOS(np.exp(-tau), wa, dwpix) ymod = np.interp(sp.wa[i:j], wa, flmodel0) ax = axes[ind] i1 = max(i-50, 0) j1 = min(j+50, len(sp.wa)-1) nfl = sp.fl[i1:j1] / sp.co[i1:j1] ner = sp.er[i1:j1] / sp.co[i1:j1] tstr, t = findtrans(tname, atom) obswa = t.wa * (1 + z0) dv = c_kms * (sp.wa[i:j] / obswa - 1) dv1 = c_kms * (sp.wa[i1:j1] / obswa - 1) tstr = tstr[2:] ax.axhline(0, color='0.5',lw=0.5) ax.axhline(1, color='k', lw=0.5, ls='--') ax.fill_between([-150, 150], -0.35, -0.15, color='0.9') ax.axhline(-0.25, color='k', lw=0.25) ax.plot(dv1, nfl, color='0.7', lw=0.5, drawstyle='steps-mid') ax.plot(dv, sp.fl[i:j]/sp.co[i:j], 'k', lw=0.5, drawstyle='steps-mid') ax.plot(dv, ymod, color='0.3') #ax.axvline(0, color='0.5', lw=0.5) ax.plot([-23]*2, [1.1, 1.4], '0.5') ax.plot([0]*2, [1.1, 1.4], '0.5') puttext(0.95, 0.95, tstr, ax, fontsize=9, va='top', ha='right', color=colours[tstr[:2]]) resid = (sp.fl[i:j]/sp.co[i:j] - ymod) / sp.er[i:j] * sp.co[i:j] ax.plot(dv, -0.25 + resid*0.1, '.', color='0.3', ms=2) ax.set_ylim(-0.5, 1.9) ax.set_xlim(-120, 120) ax.set_yticks([0, 0.5, 1, 1.5]) ax.set_yticklabels(['0.0', '0.5', '1.0', '1.5']) ax.set_xticks([-100, -50, 0, 50, 100]) ax.set_xticklabels(['', '-50', '0', '50', '']) if ind+1 < (ncols*(nrows-1)): ax.set_xticklabels([]) if ind % ncols: ax.set_yticklabels([]) fig.text(0.5, 0.00, 'Velocity offset (km/s)', fontsize=12, ha='center',va='bottom') fig.text(0.015, 0.5, 'Transmission', fontsize=12, rotation=90,va='center') ndf = len(ydata) - len(pars) print (((ydata - ymodel(x, pars))/ ysigma) **2).sum() / ndf pl.savefig('fig/model.pdf') pl.savefig('fig/model.png',dpi=300) return fig
def _get_models(self, absorbers, system_width, resolution, convolve_with_cos_fuv, convolve_with_cos_nuv, oversample, plot_components): # Subdivide wavelength array if we are oversampling: if oversample > 1: dw = ((self.wavelength[1] - self.wavelength[0]) / oversample) self.model_wavelength = np.arange( self.wavelength[0], self.wavelength[-1], dw) else: self.model_wavelength = self.wavelength # Gaussian kernel with a pixel velocity width 4 times smaller than # the FWHM: ndiv = 4 kernel = Gaussian1DKernel(ndiv / 2.354820046) # Calculate quantities for Gaussian convolution if they are required: if not convolve_with_cos_fuv and not convolve_with_cos_nuv: if isinstance(resolution, dict): scales = [] low = 0 wmax = resolution.keys().sort() for w in wmax: high = self.model_wavelength.searchsorted(w) dlogw = np.log10(1 + resolution[w] / (ndiv * c_kms)) npts = int(np.log10(self.model_wavelength[high] / self.model_wavelength[low]) / dlogw) scales.append(self.model_wavelength[low] * 10 ** (np.arange(npts) * dlogw)) low = high scale = np.concatenate(scales) else: dlogw = np.log10(1 + resolution / (ndiv * c_kms)) npts = int(np.log10(self.model_wavelength[-1] / self.model_wavelength[0]) / dlogw) scale = (self.model_wavelength[0] * 10 ** (np.arange(npts) * dlogw)) self.system_components, self.blend_components = [], [] self.ticks = defaultdict(list) # We want to create models for absorbers with different covering # fractions separately, so we'll store them with key access in a # dictionary. We'll take the product of all models with the same # covering fractions in the loop below, then apply zero offsets # (for covering fractions < 1) to those models at the end, before # combining them into a single model: models = dict() # Loop over absorbers: for absorber in absorbers: # Calculate the optical depth profile: tau = absorber.optical_depth( self.model_wavelength).astype('float64') # Add this to the total model appropriate for the covering # fraction of this absorber. Don't apply any zero offsets yet - # we'll do this at the end: if absorber.covering_fraction not in models.keys(): models[absorber.covering_fraction] = np.exp(-tau) else: models[absorber.covering_fraction] *= np.exp(-tau) # Log wavelengths of transitions that contribute to the model if # the optical depth at the line centre is > 0.001: for transition in absorber.transitions: if tau_peak(transition, absorber.logn, absorber.b) > 0.001: self.ticks['wavelength'].append( transition.wavelength.value * (1 + absorber.redshift)) self.ticks['transition'].append(transition.name) # Only calculate the individual model components if we are # plotting them (expensive otherwise): if plot_components: # Ensure zero offsets are applied (for covering fractions < 1): component = (np.exp(-tau) * absorber.covering_fraction + 1 - absorber.covering_fraction) # Convolve with the instrument LSF: if convolve_with_cos_fuv or convolve_with_cos_nuv: try: from COS import convolve_with_COS_FOS except: raise ImportError('COS module not installed') if convolve_with_cos_nuv: if self.model_wavelength[0] > 1600: component = convolve_with_COS_FOS( component, self.model_wavelength, use_cos_nuv=True, cos_nuv_only=True) else: component = convolve_with_COS_FOS( component, self.model_wavelength, use_cos_nuv=True) else: component = convolve_with_COS_FOS( component, self.model_wavelength) else: # Interpolate onto constant velocity scale: component0 = np.interp( scale, self.model_wavelength, component) # Do the convolution: component = np.interp( self.model_wavelength, scale, convolve(component0, kernel)) dz = system_width * (1 + self.redshift) / c_kms # Add components to the appropriate lists, depending on the # adopted system width: if ((absorber.redshift > self.redshift - dz / 2) & (absorber.redshift < self.redshift + dz / 2)): self.system_components.append(component) else: self.blend_components.append(component) # Ensure that zero offsets are applied (for covering fractions < 1): for key in models.keys(): covering_fraction = key models[key] = (models[key] * covering_fraction + 1 - covering_fraction) # Combine the models: model = np.product([models[key] for key in models.keys()], axis=0) # Cast line lists as NumPy arrays: self.ticks['wavelength'] = np.array(self.ticks['wavelength']) self.ticks['transition'] = np.array(self.ticks['transition']) # Convolve the models with the instrument LSF: if convolve_with_cos_fuv or convolve_with_cos_nuv: try: from COS import convolve_with_COS_FOS except: raise ImportError('convolve_with_COS_FOS not available') if convolve_with_cos_nuv: if self.model_wavelength[0] > 1600: self.model = convolve_with_COS_FOS( model, self.model_wavelength, use_cos_nuv=True, cos_nuv_only=True) else: self.model = convolve_with_COS_FOS( model, self.model_wavelength, use_cos_nuv=True) else: self.model = convolve_with_COS_FOS( model, self.model_wavelength) else: # Interpolate onto a constant velocity scale: model0 = np.interp(scale, self.model_wavelength, model) # Do the convolution: self.model = np.interp( self.model_wavelength, scale, convolve(model0, kernel)) # Combined model on coarse wavelength grid # (same as `model` if `oversample` = 1): if oversample == 1: self.coarse_model = self.model else: self.coarse_model = np.interp( self.wavelength, self.model_wavelength, self.model)