Esempio n. 1
0
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
Esempio n. 2
0
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)
Esempio n. 3
0
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
Esempio n. 4
0
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')
Esempio n. 5
0
    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))
Esempio n. 6
0
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('<', '&lt')
            profiles = [str(p).replace('<', '&lt') 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('<', '&lt')
                logg = str(request.form['logg']).replace('<', '&lt')
                feh = str(request.form['feh']).replace('<', '&lt')
                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)
Esempio n. 7
0
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