def SVO_passband(pb, pbzp=None, List = False): """ Read a SVO passband using https://github.com/hover2pi/svo_filters. Parameters ---------- pb : str pysynphot obsmode or obsmode listed in `pbzptmag.txt` pbzp : float, optional AB magnitude zeropoint of the passband List : Bool, optional List all filters available through SVO Returns ------- pb : :py:class:`pysynphot.ArrayBandpass` or :py:class:`pysynphot.obsbandpass.ObsModeBandpass` The passband data. Has ``dtype=[('wave', '<f8'), ('throughput', '<f8')]`` pbzp : float passband AB zeropoint - potentially NaN if this was not supplied. If NaN this can be computed assuming an AB source - i.e. a source with a flux density of 3631 jy has magnitude = 0 in the bandpass. Notes ----- Note that this is a straight read of a single passband from a file. The zeropoint returned is whatever was provided (even if the value is not useful) or NaN. To load the passband and get the correct zeropoint, use :py:func:`source_synphot.passband.load_pbs` See Also -------- :py:func:`astropy.table.Table.read` :py:func:`pysynphot.ObsBandpass` """ from svo_filters import svo from astropy import units as u if List: print(list(svo.filters()['Band'])) if pbzp is None: pbzp = np.nan try: pbdata = svo.Filter(pb) wav = pbdata.wave.to(u.Angstrom).flatten().value wav, ind = np.unique(wav, return_index=True) out = S.ArrayBandpass(wav, pbdata.throughput.flatten()[ind], waveunits='Angstrom', name=pb) except (OSError,IOError) as e: message = 'No passband called {} in SVO'.format(pb) out = None if out is None: raise ValueError(message) return out, pbzp
def limb_darkening(): """The limb darkening form page. """ # Load default form form = fv.LimbDarkeningForm() # Reload page with stellar data from ExoMAST if form.resolve_submit.data: if form.targname.data.strip() != '': try: # Resolve the target in exoMAST form.targname.data = get_canonical_name(form.targname.data) data, target_url = get_target_data(form.targname.data) # Update the form data form.feh.data = data.get('Fe/H') form.teff.data = data.get('Teff') form.logg.data = data.get('stellar_gravity') form.target_url.data = str(target_url) except: form.target_url.data = '' form.targname.errors = [ "Sorry, could not resolve '{}' in exoMAST.".format( form.targname.data) ] # Send it back to the main page return render_template('limb_darkening.html', form=form) # Reload page with appropriate filter data if form.filter_submit.data: kwargs = {} if form.bandpass.data == 'tophat': kwargs['n_bins'] = 1 kwargs['pixels_per_bin'] = 100 kwargs['wave_min'] = 1 * u.um kwargs['wave_max'] = 2 * u.um # Get the filter bandpass = svo.Filter(form.bandpass.data, **kwargs) # Update the form data form.wave_min.data = bandpass.wave_min.value form.wave_max.data = bandpass.wave_max.value # Send it back to the main page return render_template('limb_darkening.html', form=form) # Update validation values after a model grid is selected if form.modelgrid_submit.data: # Load the modelgrid mg = ModelGrid(form.modeldir.data, resolution=500) teff_rng = mg.Teff_vals.min(), mg.Teff_vals.max() logg_rng = mg.logg_vals.min(), mg.logg_vals.max() feh_rng = mg.FeH_vals.min(), mg.FeH_vals.max() # Update the validation parameters by setting validator attributes setattr(form.teff.validators[1], 'min', teff_rng[0]) setattr(form.teff.validators[1], 'max', teff_rng[1]) setattr( form.teff.validators[1], 'message', 'Effective temperature must be between {} and {}'.format( *teff_rng)) setattr(form.logg.validators[1], 'min', logg_rng[0]) setattr(form.logg.validators[1], 'max', logg_rng[1]) setattr(form.logg.validators[1], 'message', 'Surface gravity must be between {} and {}'.format(*logg_rng)) setattr(form.feh.validators[1], 'min', feh_rng[0]) setattr(form.feh.validators[1], 'max', feh_rng[1]) setattr(form.feh.validators[1], 'message', 'Metallicity must be between {} and {}'.format(*feh_rng)) # Send it back to the main page return render_template('limb_darkening.html', form=form) # Validate form and submit for results if form.validate_on_submit() and form.calculate_submit.data: # Get the stellar parameters star_params = [ float(form.teff.data), float(form.logg.data), float(form.feh.data) ] # Log the form inputs try: log_exoctk.log_form_input(request.form, 'limb_darkening', DB) except: pass # Load the model grid model_grid = ModelGrid(form.modeldir.data, resolution=500) form.modeldir.data = [ j for i, j in form.modeldir.choices if i == form.modeldir.data ][0] # Grism details if '.G' in form.bandpass.data.upper( ) and 'GAIA' not in form.bandpass.data.upper(): kwargs = { 'n_bins': form.n_bins.data, 'pixels_per_bin': form.n_pix.data, 'wl_min': form.wave_min.data * u.um, 'wl_max': form.wave_max.data * u.um } else: kwargs = {} # Make filter object and plot bandpass = svo.Filter(form.bandpass.data, **kwargs) bp_name = bandpass.name bk_plot = bandpass.plot(draw=False) bk_plot.plot_width = 580 bk_plot.plot_height = 280 js_resources = INLINE.render_js() css_resources = INLINE.render_css() filt_script, filt_plot = components(bk_plot) # Trim the grid to nearby grid points to speed up calculation full_rng = [ model_grid.Teff_vals, model_grid.logg_vals, model_grid.FeH_vals ] trim_rng = find_closest(full_rng, star_params, n=1, values=True) # Calculate the coefficients for each profile ld = lf.LDC(model_grid) for prof in form.profiles.data: ld.calculate(*star_params, prof, mu_min=float(form.mu_min.data), bandpass=bandpass) # Draw a figure for each wavelength bin tabs = [] for wav in np.unique(ld.results['wave_eff']): # Plot it TOOLS = 'box_zoom, box_select, crosshair, reset, hover' fig = figure(tools=TOOLS, x_range=Range1d(0, 1), y_range=Range1d(0, 1), plot_width=800, plot_height=400) ld.plot(wave_eff=wav, fig=fig) # Plot formatting fig.legend.location = 'bottom_right' fig.xaxis.axis_label = 'mu' fig.yaxis.axis_label = 'Intensity' tabs.append(Panel(child=fig, title=str(wav))) final = Tabs(tabs=tabs) # Get HTML script, div = components(final) # Store the tables as a string file_as_string = str(ld.results[[ c for c in ld.results.dtype.names if ld.results.dtype[c] != object ]]) # Make a table for each profile with a row for each wavelength bin profile_tables = [] for profile in form.profiles.data: # Make LaTeX for polynomials latex = lf.ld_profile(profile, latex=True) poly = '\({}\)'.format(latex).replace('*', '\cdot').replace('\e', 'e') # Make the table into LaTeX table = filter_table(ld.results, profile=profile) co_cols = [ c for c in ld.results.colnames if (c.startswith('c') or c.startswith('e')) and len(c) == 2 and not np.all([np.isnan(i) for i in table[c]]) ] table = table[['wave_min', 'wave_max'] + co_cols] table.rename_column('wave_min', '\(\lambda_\mbox{min}\hspace{5px}(\mu m)\)') table.rename_column('wave_max', '\(\lambda_\mbox{max}\hspace{5px}(\mu m)\)') # Add the results to the lists html_table = '\n'.join(table.pformat(max_width=500, html=True))\ .replace('<table', '<table id="myTable" class="table table-striped table-hover"') # Add the table title header = '<br></br><strong>{}</strong><br><p>\(I(\mu)/I(\mu=1)\) = {}</p>'.format( profile, poly) html_table = header + html_table profile_tables.append(html_table) return render_template('limb_darkening_results.html', form=form, table=profile_tables, script=script, plot=div, file_as_string=repr(file_as_string), filt_plot=filt_plot, filt_script=filt_script, js=js_resources, css=css_resources) return render_template('limb_darkening.html', form=form)
def generate_SOSS_ldcs(wavelengths, ld_profile, params, model_grid='ACES', subarray='SUBSTRIP256', n_bins=100): """ Generate a lookup table of limb darkening coefficients for full SOSS wavelength range Parameters ---------- wavelengths: sequence The wavelengths at which to calculate the LDCs ld_profile: str A limb darkening profile name supported by `ExoCTK.ldc.ldcfit.ld_profile()` params: sequence The stellar parameters [Teff, logg, FeH] model_grid: modelgrid.ModelGrid The grid of stellar intensity models to calculate LDCs from subarray: str The name of the subarray to use, ['SUBSTRIP96', 'SUBSTRIP256', 'FULL'] n_bins: int The number of bins to break up the grism into Returns ------- np.ndarray An array of limb darkening coefficients for each wavelength Example ------- from mirage.psf import soss_trace as st lookup = st.generate_SOSS_ldcs(np.linspace(1., 2., 3), 'quadratic', [3300, 4.5, 0]) """ try: from exoctk import modelgrid from exoctk.limb_darkening import limb_darkening_fit as lf from svo_filters import svo # Break the bandpass up into n_bins pieces bandpass = svo.Filter('NIRISS.GR700XD.1', n_bins=n_bins, verbose=False) # Calculate the LDCs ldcs = lf.LDC(model_grid=model_grid) ldcs.calculate(params[0], params[1], params[2], ld_profile, mu_min=0.08, bandpass=bandpass, verbose=False) # Interpolate the LDCs to the desired wavelengths # TODO: Propagate errors coeff_cols = [col for col in ldcs.results.colnames if col.startswith('c') and len(col) == 2] coeff_errs = [err for err in ldcs.results.colnames if err.startswith('e') and len(err) == 2] coeffs = [[np.interp(wav, list(ldcs.results['wave_eff']), list(ldcs.results[c])) for c in coeff_cols] for wav in wavelengths] coeffs = np.array(coeffs) del ldcs except Exception as exc: print(exc) print('There was a problem computing those limb darkening coefficients. Using all zeros.') n_coeffs = 1 if ld_profile in ['uniform', 'linear'] else 3 if ld_profile == '3-parameter' else 4 if ld_profile == '4-parameter' else 2 coeffs = np.zeros((len(wavelengths), n_coeffs)) return coeffs
class LimbDarkeningForm(BaseForm): """Form validation for the limb_darkening tool""" # Model grid modelgrid_dir = get_env_variables()['modelgrid_dir'] default_modelgrid = os.path.join(modelgrid_dir, 'ATLAS9/') mg = ModelGrid(default_modelgrid, resolution=500) teff_rng = mg.Teff_vals.min(), mg.Teff_vals.max() logg_rng = mg.logg_vals.min(), mg.logg_vals.max() feh_rng = mg.FeH_vals.min(), mg.FeH_vals.max() modeldir = RadioField( 'modeldir', default=default_modelgrid, choices=[(os.path.join(modelgrid_dir, 'ATLAS9/'), 'Kurucz ATLAS9'), (os.path.join(modelgrid_dir, 'ACES/'), 'Phoenix ACES')], validators=[InputRequired('A model grid is required!')]) # Stellar parameters teff = DecimalField( 'teff', default=3500, validators=[ InputRequired('An effective temperature is required!'), NumberRange( min=float(teff_rng[0]), max=float(teff_rng[1]), message= 'Effective temperature must be between {} and {} for this model grid' .format(*teff_rng)) ]) logg = DecimalField( 'logg', default=4.5, validators=[ InputRequired('A surface gravity is required!'), NumberRange( min=float(logg_rng[0]), max=float(logg_rng[1]), message= 'Surface gravity must be between {} and {} for this model grid' .format(*logg_rng)) ]) feh = DecimalField( 'feh', default=0.0, validators=[ InputRequired('A surface gravity is required!'), NumberRange( min=float(feh_rng[0]), max=float(feh_rng[1]), message= 'Metallicity must be between {} and {} for this model grid'. format(*feh_rng)) ]) mu_min = DecimalField('mu_min', default=0.1, validators=[ InputRequired('A minimum mu value is required!'), NumberRange( min=0.0, max=1.0, message='Minimum mu must be between 0 and 1') ]) # LD profile profiles = MultiCheckboxField( 'profiles', choices=[(x, x) for x in PROFILES], validators=[InputRequired('At least one profile is required!')]) # Bandpass default_filter = 'Kepler.K' defilt = svo.Filter(default_filter) bandpass = SelectField('bandpass', default=default_filter, choices=[('tophat', 'Top Hat')] + [(filt, filt) for filt in FILTERS_LIST], validators=[InputRequired('A filter is required!')]) wave_min = DecimalField( 'wave_min', default=defilt.wave_min.value, validators=[ NumberRange( min=0, max=30, message='Minimum wavelength must be between 0 and 30 microns!') ]) wave_max = DecimalField( 'wave_max', default=defilt.wave_max.value, validators=[ NumberRange( min=0, max=30, message='Maximum wavelength must be between 0 and 30 microns!') ]) n_bins = IntegerField('n_bins', default=1) # Form submits calculate_submit = SubmitField('Calculate Coefficients') filter_submit = SubmitField('Filter Selected') modelgrid_submit = SubmitField('Model Grid Selected')
def calculate(self, Teff, logg, FeH, profile, mu_min=0.05, ld_min=0.01, bandpass=None, name=None, color=None, **kwargs): """ Calculates the limb darkening coefficients for a given synthetic spectrum. If the model grid does not contain a spectrum of the given parameters, the grid is interpolated to those parameters. Reference for limb-darkening laws: http://www.astro.ex.ac.uk/people/sing/David_Sing/Limb_Darkening.html Parameters ---------- Teff: int The effective temperature of the model logg: float The logarithm of the surface gravity FeH: float The logarithm of the metallicity profile: str The name of the limb darkening profile function to use, including 'uniform', 'linear', 'quadratic', 'square-root', 'logarithmic', 'exponential', and '4-parameter' mu_min: float The minimum mu value to consider ld_min: float The minimum limb darkening value to consider bandpass: svo_filters.svo.Filter() (optional) The photometric filter through which the limb darkening is to be calculated name: str (optional) A name for the calculation color: str (optional) A color for the plotted result """ # Define the limb darkening profile function ldfunc = ld_profile(profile) if not ldfunc: raise ValueError("No such LD profile:", profile) # Get the grid point grid_point = self.model_grid.get(Teff, logg, FeH) # Retrieve the wavelength, flux, mu, and effective radius wave = grid_point.get('wave') flux = grid_point.get('flux') mu = grid_point.get('mu').squeeze() # Use tophat oif no bandpass if bandpass is None: units = self.model_grid.wave_units bandpass = svo.Filter('tophat', wave_min=np.min(wave) * units, wave_max=np.max(wave) * units) # Check if a bandpass is provided if not isinstance(bandpass, svo.Filter): raise TypeError("Invalid bandpass of type", type(bandpass)) # # Make sure the bandpass has coverage # bp_min = bandpass.wave_min.value # bp_max = bandpass.wave_max.value # mg_min = self.model_grid.wave_rng[0].value # mg_max = self.model_grid.wave_rng[-1].value # if bp_min < mg_min or bp_max > mg_max: # raise ValueError('Bandpass {} not covered by model grid of\ # wavelength range {}'.format(bandpass.filterID, # self.model_grid # .wave_rng)) # Apply the filter try: flux, _ = bandpass.apply([wave, flux]) # Sometimes this returns a tuple except ValueError: flux = bandpass.apply([wave, flux]) # Sometimes it returns one value # Make rsr curve 3 dimensions if there is only one # wavelength bin, then get wavelength only bp = bandpass.rsr if bp.ndim == 2: bp = bp[None, :] wave = bp[:, 0, :] # Calculate mean intensity vs. mu wave = wave[None, :] if wave.ndim == 1 else wave flux = flux[None, :] if flux.ndim == 2 else flux mean_i = np.nanmean(flux, axis=-1) mean_i[mean_i == 0] = np.nan # Calculate limb darkening, I[mu]/I[1] vs. mu ld = mean_i / mean_i[:, np.where(mu == max(mu))].squeeze(axis=-1) # Rescale mu values to make f(mu=0)=ld_min # for the case where spherical models extend beyond limb ld_avg = np.nanmean(ld, axis=0) muz = np.interp(ld_min, ld_avg, mu) if any(ld_avg < ld_min) else 0 mu = (mu - muz) / (1 - muz) # Trim to useful mu range imu, = np.where(mu > mu_min) scaled_mu, scaled_ld = mu[imu], ld[:, imu] # Get effective wavelengths wave_effs = np.mean(bandpass.wave, axis=1) # Fit limb darkening coefficients for each wavelength bin for n, ldarr in enumerate(scaled_ld): # Get effective wavelength of bin wave_eff = wave_effs[n] try: # Fit polynomial to data coeffs, cov = curve_fit(ldfunc, scaled_mu, ldarr, method='lm') # Calculate errors from covariance matrix diagonal errs = np.sqrt(np.diag(cov)) # Make a dictionary or the results result = {} # Check the count result['name'] = name or 'Calculation {}'.format(self.count) self.count += 1 if bandpass.wave.shape[0] == len(scaled_ld) and name is None: result['name'] = '{:.3f}'.format(wave_eff) # Set a color if possible result['color'] = color or self.ld_color[profile] # Add the results result['Teff'] = Teff result['logg'] = logg result['FeH'] = FeH result['filter'] = bandpass.filterID result['models'] = self.model_grid.path result['raw_mu'] = mu result['raw_ld'] = ld[n] result['scaled_mu'] = scaled_mu result['scaled_ld'] = ldarr result['flux'] = flux[n] result['wave'] = wave[n] result['mu_min'] = mu_min result['bandpass'] = bandpass result['ldfunc'] = ldfunc result['coeffs'] = coeffs result['errors'] = errs result['profile'] = profile result['n_bins'] = bandpass.n_bins result['pixels_per_bin'] = bandpass.pixels_per_bin result['wave_min'] = wave[n, 0].round(5) result['wave_eff'] = wave_eff result['wave_max'] = wave[n, -1].round(5) # Add the coeffs for n, (coeff, err) in enumerate(zip(coeffs, errs)): cname = 'c{}'.format(n + 1) ename = 'e{}'.format(n + 1) result[cname] = coeff.round(3) result[ename] = err.round(3) # Add the coefficient column to the table if not present if cname not in self.results.colnames: self.results[cname] = [np.nan] * len(self.results) self.results[ename] = [np.nan] * len(self.results) # Add the new row to the table result = { i: j for i, j in result.items() if i in self.results.colnames } self.results.add_row(result) except ValueError: print( "Could not calculate coefficients at {}".format(wave_eff))
def limb_darkening(): """The limb darkening form page""" # Get all the available filters filters = svo.filters()['Band'] # Make HTML for filters filt_list = '\n'.join(['<option value="{0}"{1}> {0}</option>'.format(b, ' selected' if b == 'Kepler.K' else '') for b in filters]) if request.method == 'POST': if request.form['submit'] == "Retrieve Parameters": target_name = request.form['targetname'] data = get_target_data(target_name) feh = data['Fe/H'] teff = data['Teff'] logg = data['stellar_gravity'] limbVars = {'targname':target_name, 'feh': feh, 'teff':teff, 'logg':logg} return render_template('limb_darkening.html', limbVars=limbVars, filters=filt_list) elif request.form['submit'] == "Calculate Coefficients": # Log the form inputs try: log_exoctk.log_form_input(request.form, 'limb_darkening', DB) except: pass # Get the input from the form modeldir = request.form['modeldir'] profiles = list(filter(None, [request.form.get(pf) for pf in PROFILES])) bandpass = request.form['bandpass'] # protect against injection attempts bandpass = bandpass.replace('<', '<') profiles = [str(p).replace('<', '<') for p in profiles] # Get models from local directory if necessary if modeldir == 'default': modeldir = MODELGRID_DIR # Throw error if input params are invalid try: teff = float(request.form['teff']) logg = float(request.form['logg']) feh = float(request.form['feh']) mu_min = float(request.form['mu_min']) except IOError: teff = str(request.form['teff']).replace('<', '<') logg = str(request.form['logg']).replace('<', '<') feh = str(request.form['feh']).replace('<', '<') message = 'Could not calculate limb darkening for those parameters.' return render_template('limb_darkening_error.html', teff=teff, logg=logg, feh=feh, band=bandpass or 'None', profile=', '.join(profiles), models=modeldir, message=message) n_bins = request.form.get('n_bins') pixels_per_bin = request.form.get('pixels_per_bin') wl_min = request.form.get('wave_min') wl_max = request.form.get('wave_max') model_grid = ModelGrid(modeldir, resolution=500) # No data, redirect to the error page if not hasattr(model_grid, 'data'): message = 'Could not find a model grid to load. Please check the path.' return render_template('limb_darkening_error.html', teff=teff, logg=logg, feh=feh, band=bandpass or 'None', profile=', '.join(profiles), models=model_grid.path, message=message) else: if len(model_grid.data) == 0: message = 'Could not calculate limb darkening with those parameters.' return render_template('limb_darkening_error.html', teff=teff, logg=logg, feh=feh, band=bandpass or 'None', profile=', '.join(profiles), models=model_grid.path, message=message) # Trim the grid to the correct wavelength # to speed up calculations, if a bandpass is given min_max = model_grid.wave_rng try: kwargs = {'n_bins': int(n_bins)} if n_bins else \ {'pixels_per_bin': int(pixels_per_bin)} if pixels_per_bin else\ {} if wl_min and wl_max: kwargs['wl_min'] = float(wl_min) * u.um kwargs['wl_max'] = float(wl_max) * u.um # Make filter object bandpass = svo.Filter(bandpass, **kwargs) bp_name = bandpass.name bk_plot = bandpass.plot(draw=False) bk_plot.plot_width = 580 bk_plot.plot_height = 280 min_max = (bandpass.wave_min.value, bandpass.wave_max.value) n_bins = bandpass.n_bins js_resources = INLINE.render_js() css_resources = INLINE.render_css() filt_script, filt_plot = components(bk_plot) except: message = 'Insufficient filter information. Please complete the form and try again!' return render_template('limb_darkening_error.html', teff=teff, logg=logg, feh=feh, band=bandpass or 'None', profile=', '.join(profiles), models=model_grid.path, message=message) # Trim the grid to nearby grid points to speed up calculation full_rng = [model_grid.Teff_vals, model_grid.logg_vals, model_grid.FeH_vals] trim_rng = find_closest(full_rng, [teff, logg, feh], n=1, values=True) if not trim_rng: message = 'Insufficient models grid points to calculate coefficients.' return render_template('limb_darkening_error.html', teff=teff, logg=logg, feh=feh, band=bp_name, profile=', '.join(profiles), models=model_grid.path, message=message) elif not profiles: message = 'No limb darkening profiles have been selected. Please select at least one.' return render_template('limb_darkening_error.html', teff=teff, logg=logg, feh=feh, band=bp_name, profile=', '.join(profiles), models=model_grid.path, message=message) else: try: model_grid.customize(Teff_rng=trim_rng[0], logg_rng=trim_rng[1], FeH_rng=trim_rng[2], wave_rng=min_max) except: message = 'Insufficient wavelength coverage to calculate coefficients.' return render_template('limb_darkening_error.html', teff=teff, logg=logg, feh=feh, band=bp_name, profile=', '.join(profiles), models=model_grid.path, message=message) # Calculate the coefficients for each profile ld = lf.LDC(model_grid) for prof in profiles: ld.calculate(teff, logg, feh, prof, mu_min=mu_min, bandpass=bandpass) # Draw a figure for each wavelength bin tabs = [] for wav in np.unique(ld.results['wave_eff']): # Plot it TOOLS = 'box_zoom, box_select, crosshair, reset, hover' fig = figure(tools=TOOLS, x_range=Range1d(0, 1), y_range=Range1d(0, 1), plot_width=800, plot_height=400) ld.plot(wave_eff=wav, fig=fig) # Plot formatting fig.legend.location = 'bottom_right' fig.xaxis.axis_label = 'mu' fig.yaxis.axis_label = 'Intensity' tabs.append(Panel(child=fig, title=str(wav))) final = Tabs(tabs=tabs) # Get HTML script, div = components(final) # Store the tables as a string file_as_string = str(ld.results[[c for c in ld.results.dtype.names if ld.results.dtype[c] != object]]) r_eff = mu_eff = '' # Make a table for each profile with a row for each wavelength bin profile_tables = [] for profile in profiles: # Make LaTeX for polynomials latex = lf.ld_profile(profile, latex=True) poly = '\({}\)'.format(latex).replace('*', '\cdot').replace('\e', 'e') # Make the table into LaTeX table = filter_table(ld.results, profile=profile) co_cols = [c for c in ld.results.colnames if (c.startswith('c') or c.startswith('e')) and len(c) == 2 and not np.all([np.isnan(i) for i in table[c]])] table = table[['wave_min', 'wave_max'] + co_cols] table.rename_column('wave_min', '\(\lambda_\mbox{min}\hspace{5px}(\mu m)\)') table.rename_column('wave_max', '\(\lambda_\mbox{max}\hspace{5px}(\mu m)\)') # Add the results to the lists html_table = '\n'.join(table.pformat(max_width=500, html=True))\ .replace('<table', '<table id="myTable" class="table table-striped table-hover"') # Add the table title header = '<br></br><strong>{}</strong><br><p>\(I(\mu)/I(\mu=1)\) = {}</p>'.format(profile, poly) html_table = header + html_table profile_tables.append(html_table) return render_template('limb_darkening_results.html', teff=teff, logg=logg, feh=feh, band=bp_name, mu=mu_eff, profile=', '.join(profiles), r=r_eff, models=model_grid.path, table=profile_tables, script=script, plot=div, file_as_string=repr(file_as_string), filt_plot=filt_plot, filt_script=filt_script, js=js_resources, css=css_resources) return render_template('limb_darkening.html', limbVars={}, filters=filt_list)
def generate_SOSS_ldcs(wavelengths, ld_profile, grid_point, model_grid='', subarray='SUBSTRIP256', n_bins=100, plot=False, save=''): """ Generate a lookup table of limb darkening coefficients for full SOSS wavelength range Parameters ---------- wavelengths: sequence The wavelengths at which to calculate the LDCs ld_profile: str A limb darkening profile name supported by `ExoCTK.ldc.ldcfit.ld_profile()` grid_point: dict, sequence The stellar parameters [Teff, logg, FeH] or stellar model dictionary from `ExoCTK.modelgrid.ModelGrid.get()` n_bins: int The number of bins to break up the grism into save: str The path to save to file to Example ------- from awesimsoss.sim2D import awesim lookup = awesim.soss_ldc('quadratic', [3300, 4.5, 0]) """ # Get the model grid if not isinstance(model_grid, modelgrid.ModelGrid): model_grid = modelgrid.ModelGrid(os.environ['MODELGRID_DIR'], resolution=700) # Load the model grid model_grid = modelgrid.ModelGrid(os.environ['MODELGRID_DIR'], resolution=700, wave_rng=(0.6, 2.8)) # Get the grid point if isinstance(grid_point, (list, tuple, np.ndarray)): grid_point = model_grid.get(*grid_point) # Abort if no stellar dict if not isinstance(grid_point, dict): print( 'Please provide the grid_point argument as [Teff, logg, FeH] or ExoCTK.modelgrid.ModelGrid.get(Teff, logg, FeH).' ) return # Break the bandpass up into n_bins pieces bandpass = svo.Filter('NIRISS.GR700XD', n_bins=n_bins, verbose=False) # Calculate the LDCs ldc_results = lf.ldc(None, None, None, model_grid, [ld_profile], bandpass=bandpass, grid_point=grid_point.copy(), mu_min=0.08, verbose=False) # Interpolate the LDCs to the desired wavelengths coeff_table = ldc_results[ld_profile]['coeffs'] coeff_cols = [c for c in coeff_table.colnames if c.startswith('c')] coeffs = [ np.interp(wavelengths, coeff_table['wavelength'], coeff_table[c]) for c in coeff_cols ] # Compare if plot: plt.figure() plt.scatter(coeff_table['c1'], coeff_table['c2'], c=coeff_table['wavelength'], marker='x') plt.scatter(coeffs[0], coeffs[1], c=wavelengths, marker='o') return np.array(coeffs).T