def test_get_target_data(planet_name, planet_data): """Test that the canonical name of the planet is returned by exomast""" data, _ = get_target_data(planet_name) # these are some params that the webapp uses for it's tools exomast_params = [ 'Fe/H', 'Teff', 'stellar_gravity', 'transit_duration', 'RA', 'DEC' ] for value in exomast_params: assert data[value] == planet_data[value]
def phase_overlap_constraint(target_name, period=None, t0=None, obs_duration=None, window_size=None): ''' The main function to calculate the phase overlap constraints. We will update to allow a user to just plug in the target_name and get the other variables. Parameters ---------- period : float The period of the transit in days. t0 : float The start time in BJD or HJD. obs_duration : float The duration of the observation in hours. winSize : float The window size of transit in hours. Default is 1 hour. target_name : string The name of the target transit. Returns ------- minphase : float The minimum phase constraint. maxphase : float The maximum phase constraint. ''' if obs_duration == None: if period == None: data = get_target_data(target_name) period = data['orbital_period'] transit_dur = data['transit_duration'] t0 = data['transit_time'] obs_duration = calculate_obsDur(transit_dur) minphase, maxphase = calculate_phase(period, obs_duration, window_size) # Is this the return that we want? Do we need to use t0 for something? print('MINIMUM PHASE: {}, MAXIMUM PHASE: {}'.format(minphase, maxphase))
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 contam_visibility(): """The contamination and visibility form page""" # Load default form form = fv.ContamVisForm() form.calculate_contam_submit.disabled = False if request.method == 'GET': # http://0.0.0.0:5000/contam_visibility?ra=24.354208334287005&dec=-45.677930555343636&target=WASP-18%20b target_name = request.args.get('target') form.targname.data = target_name ra = request.args.get('ra') form.ra.data = ra dec = request.args.get('dec') form.dec.data = dec return render_template('contam_visibility.html', form=form) # Reload page with stellar data from ExoMAST if form.resolve_submit.data: if form.targname.data.strip() != '': # Resolve the target in exoMAST try: form.targname.data = get_canonical_name(form.targname.data) data, url = get_target_data(form.targname.data) # Update the coordinates ra_deg = data.get('RA') dec_deg = data.get('DEC') # Set the form values form.ra.data = ra_deg form.dec.data = dec_deg form.target_url.data = 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('contam_visibility.html', form=form) # Reload page with appropriate mode data if form.mode_submit.data: # Update the button if form.inst.data != 'NIRISS': form.calculate_contam_submit.disabled = True else: form.calculate_contam_submit.disabled = False # Send it back to the main page return render_template('contam_visibility.html', form=form) if form.validate_on_submit() and (form.calculate_submit.data or form.calculate_contam_submit.data): try: # Log the form inputs try: log_exoctk.log_form_input(request.form, 'contam_visibility', DB) except: pass # Make plot title = form.targname.data or ', '.join( [form.ra.data, form.dec.data]) pG, pB, dates, vis_plot, table = vpa.using_gtvt( str(form.ra.data), str(form.dec.data), form.inst.data.split(' ')[0]) # Make output table vers = '0.3' today = datetime.datetime.now() fh = StringIO() fh.write('# Hi! This is your Visibility output file for... \n') fh.write('# Target: {} \n'.format(form.targname.data)) fh.write('# Instrument: {} \n'.format(form.inst.data)) fh.write('# \n') fh.write( '# This file was generated using ExoCTK v{} on {} \n'.format( vers, today)) fh.write('# Visit our GitHub: https://github.com/ExoCTK/exoctk \n') fh.write('# \n') table.write(fh, format='csv', delimiter=',') visib_table = fh.getvalue() # Format x axis day0 = datetime.date(2019, 6, 1) dtm = datetime.timedelta(days=367) #vis_plot.x_range = Range1d(day0, day0 + dtm) # TODO: Fix this so bad PAs are included pB = [] # Make plot TOOLS = 'crosshair, reset, hover, save' fig = figure(tools=TOOLS, plot_width=800, plot_height=400, x_axis_type='datetime', title=title) fh = StringIO() table.write(fh, format='ascii') visib_table = fh.getvalue() # Format x axis day0 = datetime.date(2019, 6, 1) dtm = datetime.timedelta(days=367) # Get scripts vis_js = INLINE.render_js() vis_css = INLINE.render_css() vis_script, vis_div = components(vis_plot) # Contamination plot too if form.calculate_contam_submit.data: # First convert ra and dec to HH:MM:SS ra_deg, dec_deg = float(form.ra.data), float(form.dec.data) sc = SkyCoord(ra_deg, dec_deg, unit='deg') ra_dec = sc.to_string('hmsdms') ra_hms, dec_dms = ra_dec.split(' ')[0], ra_dec.split(' ')[1] # Make field simulation contam_cube = fs.sossFieldSim(ra_hms, dec_dms, binComp=form.companion.data) contam_plot = cf.contam( contam_cube, title, paRange=[int(form.pa_min.data), int(form.pa_max.data)], badPA=pB, fig='bokeh') # Get scripts contam_js = INLINE.render_js() contam_css = INLINE.render_css() contam_script, contam_div = components(contam_plot) else: contam_script = contam_div = contam_js = contam_css = '' return render_template('contam_visibility_results.html', form=form, vis_plot=vis_div, vis_table=visib_table, vis_script=vis_script, vis_js=vis_js, vis_css=vis_css, contam_plot=contam_div, contam_script=contam_script, contam_js=contam_js, contam_css=contam_css) except IOError: #Exception as e: err = 'The following error occurred: ' + str(e) return render_template('groups_integrations_error.html', err=err) return render_template('contam_visibility.html', form=form)
def groups_integrations(): """The groups and integrations calculator form page""" # Print out pandeia sat values with open( resource_filename( 'exoctk', 'data/groups_integrations/groups_integrations_input_data.json') ) as f: sat_data = json.load(f)['fullwell'] # Load default form form = fv.GroupsIntsForm() if request.method == 'GET': # http://0.0.0.0:5000/groups_integrations?k_mag=8.131&transit_duration=0.09089&target=WASP-18+b target_name = request.args.get('target') form.targname.data = target_name k_mag = request.args.get('k_mag') form.kmag.data = k_mag # According to Kevin the obs_dur = 3*trans_dur+1 hours # transit_dur is in days from exomast, convert first. try: trans_dur = float(request.args.get('transit_duration')) trans_dur *= u.day.to(u.hour) obs_dur = 3 * trans_dur + 1 form.obs_duration.data = obs_dur except TypeError: trans_dur = request.args.get('transit_duration') if trans_dur == None: pass else: err = 'The Transit Duration from ExoMAST experienced some issues. Try a different spelling or source.' return render_template('groups_integrations_error.html', err=err) return render_template('groups_integrations.html', form=form, sat_data=sat_data) # Reload page with stellar data from ExoMAST if form.resolve_submit.data: if form.targname.data.strip() != '': # Resolve the target in exoMAST try: form.targname.data = get_canonical_name(form.targname.data) data, url = get_target_data(form.targname.data) # Update the Kmag kmag = data.get('Kmag') # Transit duration in exomast is in days, need it in hours if form.time_unit.data == 'day': trans_dur = data.get('transit_duration') obs_dur = 3 * trans_dur + (1 / 24.) else: trans_dur = data.get('transit_duration') trans_dur *= u.Unit('day').to('hour') obs_dur = 3 * trans_dur + 1 # Model guess logg_targ = data.get('stellar_gravity') or 4.5 teff_targ = data.get('Teff') or 5500 arr = np.array([tuple(i[1].split()) for i in form.mod.choices], dtype=[('spt', 'O'), ('teff', '>f4'), ('logg', '>f4')]) mod_table = at.Table(arr) # If high logg, remove giants from guess list if logg_targ < 4: mod_table = filter_table(mod_table, logg=">=4") teff = min(arr['teff'], key=lambda x: abs(x - teff_targ)) mod_table.add_column( at.Column(np.array([i[0] for i in form.mod.choices]), name='value')) mod_table = filter_table(mod_table, teff="<={}".format(teff)) mod_table.sort(['teff', 'logg']) # Set the form values form.mod.data = mod_table[-1]['value'] form.kmag.data = kmag form.obs_duration.data = obs_dur form.target_url.data = 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('groups_integrations.html', form=form, sat_data=sat_data) if form.validate_on_submit() and form.calculate_submit.data: # Get the form data ins = form.ins.data params = { 'ins': ins, 'mag': form.kmag.data, 'obs_time': form.obs_duration.data, 'sat_max': form.sat_max.data, 'sat_mode': form.sat_mode.data, 'time_unit': form.time_unit.data, 'band': 'K', 'mod': form.mod.data, 'filt'.format(ins): getattr(form, '{}_filt'.format(ins)).data, 'subarray'.format(ins): getattr(form, '{}_subarray'.format(ins)).data, 'filt_ta'.format(ins): getattr(form, '{}_filt_ta'.format(ins)).data, 'subarray_ta'.format(ins): getattr(form, '{}_subarray_ta'.format(ins)).data } # Get ngroups params['n_group'] = 'optimize' if form.n_group.data == 0 else int( form.n_group.data) # Also get the data path in there params['infile'] = resource_filename( 'exoctk', 'data/groups_integrations/groups_integrations_input_data.json') # Convert the obs_time to hours if params['time_unit'] == 'day': params['obs_time'] = params['obs_time'] * 24 params['time_unit'] = 'hours' # Run the calculation results = perform_calculation(params) if type(results) == dict: results_dict = results one_group_error = "" zero_group_error = "" if results_dict['n_group'] == 1: one_group_error = 'Be careful! This only predicts one group, and you may be in danger of oversaturating!' if results_dict['max_ta_groups'] == 0: zero_group_error = 'Be careful! This oversaturated the TA in the minimum groups. Consider a different TA setup.' if results_dict['max_ta_groups'] == -1: zero_group_error = 'This object is too faint to reach the required TA SNR in this filter. Consider a different TA setup.' results_dict['min_sat_ta'] = 0 results_dict['t_duration_ta_max'] = 0 results_dict['max_sat_ta'] = 0 results_dict['t_duration_ta_max'] = 0 if results_dict['max_sat_prediction'] > results_dict['sat_max']: one_group_error = 'This many groups will oversaturate the detector! Proceed with caution!' # Do some formatting for a prettier end product results_dict['filt'] = results_dict['filt'].upper() results_dict['filt_ta'] = results_dict['filt_ta'].upper() results_dict['band'] = results_dict['band'].upper() results_dict['mod'] = results_dict['mod'].upper() if results_dict['ins'] == 'niriss': if results_dict['subarray_ta'] == 'nrm': results_dict['subarray_ta'] = 'SUBTASOSS -- BRIGHT' else: results_dict['subarray_ta'] = 'SUBTASOSS -- FAINT' results_dict['subarray'] = results_dict['subarray'].upper() results_dict['subarray_ta'] = results_dict['subarray_ta'].upper() form_dict = { 'miri': 'MIRI', 'nircam': 'NIRCam', 'nirspec': 'NIRSpec', 'niriss': 'NIRISS' } results_dict['ins'] = form_dict[results_dict['ins']] return render_template('groups_integrations_results.html', results_dict=results_dict, one_group_error=one_group_error, zero_group_error=zero_group_error) else: err = results return render_template('groups_integrations_error.html', err=err) return render_template('groups_integrations.html', form=form, sat_data=sat_data)
def phase_constraint(transit_type='primary'): # Load default form form = fv.PhaseConstraint() # 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.orbital_period.data = data.get('orbital_period') t_time = Time(data.get('transit_time'), format='mjd') form.transit_time.data = t_time.jd form.observation_duration.data = calculate_pre_duration( data.get('transit_duration') * 24.0) form.inclination.data = data.get('inclination') if form.inclination.data is None: form.inclination.data = np.nan form.omega.data = data.get('omega') if form.omega.data is None: form.omega.data = np.nan form.eccentricity.data = data.get('eccentricity') if form.eccentricity.data is None: form.omega.data = np.nan form.target_url.data = str(target_url) return render_template('phase_constraint.html', form=form) except Exception: form.target_url.data = '' form.targname.errors = [ "Sorry, could not resolve '{}' in exoMAST.".format( form.targname.data) ] # Extract transit type: transit_type = form.transit_type.data if form.validate_on_submit() and form.calculate_submit.data: if transit_type == 'primary': minphase, maxphase = phase_overlap_constraint( target_name=form.targname.data, period=form.orbital_period.data, pretransit_duration=form.observation_duration.data, window_size=form.window_size.data) elif transit_type == 'secondary': if (0. <= form.eccentricity.data < 1) and (-360. <= form.omega.data <= 360.) and (0 <= form.inclination.data <= 90.): # Use dummy time-of-transit as it doesn't matter for the phase-constraint calculation # (phase = 1 is always transit) minphase, maxphase = phase_overlap_constraint( target_name=form.targname.data, period=form.orbital_period.data, t0=1., pretransit_duration=form.observation_duration.data, window_size=form.window_size.data, secondary=True, ecc=form.eccentricity.data, omega=form.omega.data, inc=form.inclination.data) else: minphase, maxphase = np.nan, np.nan else: minphase, maxphase = np.nan, np.nan form.minimum_phase.data = minphase form.maximum_phase.data = maxphase """ if (form.eccentricity.data > 1.) or (form.eccentricity.data < 0.): form.eccentricity.data = None if np.abs(form.omega.data)>360.: form.omega.data = None if (form.inclination.data < 0) or (form.inclination.data>90.): form.inclination.data = None """ # Send it back to the main page return render_template('phase_constraint.html', form=form)
def contam_visibility(): """The contamination and visibility form page""" # Load default form form = fv.ContamVisForm() form.calculate_contam_submit.disabled = False if request.method == 'GET': # http://0.0.0.0:5000/contam_visibility?ra=24.354208334287005&dec=-45.677930555343636&target=WASP-18%20b target_name = request.args.get('target') form.targname.data = target_name ra = request.args.get('ra') form.ra.data = ra dec = request.args.get('dec') form.dec.data = dec return render_template('contam_visibility.html', form=form) # Reload page with stellar data from ExoMAST if form.resolve_submit.data: if form.targname.data.strip() != '': # Resolve the target in exoMAST try: form.targname.data = get_canonical_name(form.targname.data) data, url = get_target_data(form.targname.data) # Update the coordinates ra_deg = data.get('RA') dec_deg = data.get('DEC') # Set the form values form.ra.data = ra_deg form.dec.data = dec_deg form.target_url.data = url except Exception: 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('contam_visibility.html', form=form) # Reload page with appropriate mode data if form.mode_submit.data: # Update the button if (form.inst.data == 'MIRI') or (form.inst.data == 'NIRSpec'): form.calculate_contam_submit.disabled = True else: form.calculate_contam_submit.disabled = False # Send it back to the main page return render_template('contam_visibility.html', form=form) if form.validate_on_submit() and (form.calculate_submit.data or form.calculate_contam_submit.data): try: # Log the form inputs try: log_exoctk.log_form_input(request.form, 'contam_visibility', DB) except Exception: pass # Make plot title = form.targname.data or ', '.join( [str(form.ra.data), str(form.dec.data)]) pG, pB, dates, vis_plot, table, badPAs = vpa.using_gtvt( str(form.ra.data), str(form.dec.data), form.inst.data.split(' ')[0], targetName=str(title)) # Make output table fh = StringIO() table.write(fh, format='csv', delimiter=',') visib_table = fh.getvalue() # Get scripts vis_js = INLINE.render_js() vis_css = INLINE.render_css() vis_script, vis_div = components(vis_plot) # Contamination plot too if form.calculate_contam_submit.data: # First convert ra and dec to HH:MM:SS ra_deg, dec_deg = float(form.ra.data), float(form.dec.data) sc = SkyCoord(ra_deg, dec_deg, unit='deg') ra_dec = sc.to_string('hmsdms') ra_hms, dec_dms = ra_dec.split(' ')[0], ra_dec.split(' ')[1] # Make field simulation contam_cube = fs.fieldSim(ra_hms, dec_dms, form.inst.data, binComp=form.companion.data) contam_plot = cf.contam( contam_cube, form.inst.data, targetName=str(title), paRange=[int(form.pa_min.data), int(form.pa_max.data)], badPAs=badPAs, fig='bokeh') # Get scripts contam_js = INLINE.render_js() contam_css = INLINE.render_css() contam_script, contam_div = components(contam_plot) else: contam_script = contam_div = contam_js = contam_css = '' return render_template('contam_visibility_results.html', form=form, vis_plot=vis_div, vis_table=visib_table, vis_script=vis_script, vis_js=vis_js, vis_css=vis_css, contam_plot=contam_div, contam_script=contam_script, contam_js=contam_js, contam_css=contam_css) except Exception as e: err = 'The following error occurred: ' + str(e) return render_template('groups_integrations_error.html', err=err) return render_template('contam_visibility.html', form=form)
def resolve_target(targetName): data = get_target_data(targetName)[0] ra = data['RA'] dec = data['DEC'] return ra, dec
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 limb_darkening(): """Returns the rendered limb darkening form page. Returns ------- ``flask.render_template`` obj The rendered template for the limb-darkening page. """ # Load default form form = fv.LimbDarkeningForm() # Planet properties planet_properties = [ 'transit_duration', 'orbital_period', 'rp_rs', 'a_rs', 'inclination', 'eccentricity', 'omega' ] def empty_fields(form): form.transit_duration.data = form.transit_duration.data or '' form.orbital_period.data = form.orbital_period.data or '' form.rp_rs.data = form.rp_rs.data or '' form.a_rs.data = form.a_rs.data or '' form.inclination.data = form.inclination.data or '' form.eccentricity.data = form.eccentricity.data or '' form.omega.data = form.omega.data or '' return form # 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 star 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) # Update the planet data form.transit_duration.data = data.get('transit_duration') form.orbital_period.data = data.get('orbital_period') form.rp_rs.data = data.get('Rp/Rs') form.a_rs.data = data.get('a/Rs') form.inclination.data = data.get('inclination') form.eccentricity.data = data.get('eccentricity') form.omega.data = data.get('omega') except Exception: form.target_url.data = '' form.targname.errors = [ "Sorry, could not resolve '{}' in exoMAST.".format( form.targname.data) ] # Ensure planet fields are not None form = empty_fields(form) # 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 = Throughput(form.bandpass.data, **kwargs) # Update the form data form.wave_min.data = bandpass.wave_min.value form.wave_max.data = bandpass.wave_max.value # Ensure planet fields are not None form = empty_fields(form) # 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', float(teff_rng[0])) setattr(form.teff.validators[1], 'max', float(teff_rng[1])) setattr( form.teff.validators[1], 'message', 'Effective temperature must be between {} and {}'.format( *teff_rng)) setattr(form.logg.validators[1], 'min', float(logg_rng[0])) setattr(form.logg.validators[1], 'max', float(logg_rng[1])) setattr(form.logg.validators[1], 'message', 'Surface gravity must be between {} and {}'.format(*logg_rng)) setattr(form.feh.validators[1], 'min', float(feh_rng[0])) setattr(form.feh.validators[1], 'max', float(feh_rng[1])) setattr(form.feh.validators[1], 'message', 'Metallicity must be between {} and {}'.format(*feh_rng)) # Ensure planet fields are not None form = empty_fields(form) # 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: # Form inputs for logging form_input = dict(request.form) # Get the stellar parameters star_params = [ float(form.teff.data), float(form.logg.data), float(form.feh.data) ] # 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 kwargs = { 'n_bins': form.n_bins.data, 'wave_min': form.wave_min.data * u.um, 'wave_max': form.wave_max.data * u.um } # Make filter object and plot bandpass = Throughput(form.bandpass.data, **kwargs) 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) # Check if spam coefficients can be calculated planet_data = { param: getattr(form, param).data for param in planet_properties } planet_data['Rp/Rs'] = planet_data['rp_rs'] planet_data['a/Rs'] = planet_data['a_rs'] spam_calc = all([ val is not None and val != '' for key, val in planet_data.items() ]) if spam_calc: # Make sure non-linear profile is included for spam calculation if all planet parameters are provided if '4-parameter' not in form.profiles.data: ld.calculate(*star_params, '4-parameter', mu_min=float(form.mu_min.data), bandpass=bandpass) # Calculate spam coeffs planet_data = {key: float(val) for key, val in planet_data.items()} ld.spam(planet_data=planet_data) # Draw tabbed figure final = ld.plot_tabs() # Get HTML script, div = components(final) # Store the tables as a string keep_cols = [ 'Teff', 'logg', 'FeH', 'profile', 'filter', 'wave_min', 'wave_eff', 'wave_max', 'c1', 'e1', 'c2', 'e2', 'c3', 'e3', 'c4', 'e4' ] print_table = ld.results[[ col for col in keep_cols if col in ld.results.colnames ]] file_as_string = '\n'.join( print_table.pformat(max_lines=-1, max_width=-1)) # 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_eff', 'wave_min', 'wave_max'] + co_cols] table.rename_column('wave_eff', '\(\lambda_\mbox{eff}\hspace{5px}(\mu m)\)') 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=-1, max_lines=-1, 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) # Add the profile to the form inputs form_input[profile] = 'true' # Log the successful form inputs log_exoctk.log_form_input(form_input, 'limb_darkening', DB) # Make a table for each profile with a row for each wavelength bin profile_spam_tables = '' spam_file_as_string = '' if ld.spam_results is not None: # Store SPAM tables as string keep_cols = [ 'Teff', 'logg', 'FeH', 'profile', 'filter', 'wave_min', 'wave_eff', 'wave_max', 'c1', 'c2' ] print_spam_table = ld.spam_results[[ col for col in keep_cols if col in ld.spam_results.colnames ]] spam_file_as_string = '\n'.join( print_spam_table.pformat(max_lines=-1, max_width=-1)) profile_spam_tables = [] for profile in list(np.unique(ld.spam_results['profile'])): # 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.spam_results, profile=profile) co_cols = [ c for c in ld.spam_results.colnames if c.startswith('c') and c not in ['coeffs', 'color'] ] table = table[['wave_eff', 'wave_min', 'wave_max'] + co_cols] table.rename_column( 'wave_eff', '\(\lambda_\mbox{eff}\hspace{5px}(\mu m)\)') 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=-1, max_lines=-1, 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_spam_tables.append(html_table) return render_template('limb_darkening_results.html', form=form, table=profile_tables, spam_table=profile_spam_tables, script=script, plot=div, spam_file_as_string=repr(spam_file_as_string), 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 phase_overlap_constraint(target_name, period=None, t0=None, pretransit_duration=None, transit_dur=None, window_size=None, secondary=False, ecc=None, omega=None, inc=None, winn_approx=False, get_secondary_time=False): """The main function to calculate the phase overlap constraints. We will update to allow a user to just plug in the target_name and get the other variables. Parameters ---------- target_name : string The name of the target transiting planet. period : float The period of the transit in days. t0 : float The transit mid-time in BJD or HJD (only useful if time-of-secondary eclipse wants to be returned). pretransit_duration : float The duration of the observations *before* transit/eclipse in hours. transit_dur : float The duration of the transit/eclipse in hours. window_size : float The window size of transit in hours. Default is 1 hour. secondary : boolean If True, phase constraint will be the one for the secondary eclipse. Default is primary (i.e., transits). ecc : float Eccentricity of the orbit. Needed only if secondary is True. omega : float Argument of periastron of the orbit in degrees. Needed only if secondary is True. inc : float Inclination of the orbit in degrees. Needed only if secondary is true. winn_approx : boolean If True, instead of running the whole Kepler equation calculation, time of secondary eclipse is calculated using eq. (6) in Winn (2010; https://arxiv.org/abs/1001.2010v5) get_secondary_time : boolean If True, this function also returns the time-of-mid secondary eclipse. Returns ------- minphase : float The minimum phase constraint. maxphase : float The maximum phase constraint. tsec : float (optional) If get_secondary_time is True, the time of secondary eclipse in the same units as input t0. """ gotdata = False # If secondary eclipse, check eccentricity, omega and inclination are given. If not, get data from exoMAST: if secondary: if ecc is None: data = get_target_data(target_name) gotdata = True ecc = data[0]['eccentricity'] if ecc is None: raise Exception( 'User needs to input eccentricity, as the value was not found at exoMAST {}.' .format(target_name)) if omega is None: if not gotdata: data = get_target_data(target_name) gotdata = True omega = data[0]['omega'] if omega is None: raise Exception( 'User needs to input argument of periastron (omega), as the value was not found at exoMAST for {}.' .format(target_name)) if inc is None: if not gotdata: data = get_target_data(target_name) gotdata = True inc = data[0]['inclination'] if inc is None: raise Exception( 'User needs to input inclination of the orbit, as the value was not found at exoMAST for {}.' .format(target_name)) # If pre-transit duration or period is not given, extract it from transit duration using the Tdwell equation: if pretransit_duration is None or period is None: if not gotdata: data = get_target_data(target_name) gotdata = True # If period is not given, extract it: if period is None: period = data[0]['orbital_period'] t0 = Time(data[0]['transit_time'], format='mjd') print('Retrieved period is {}. Retrieved t0 is {}.'.format( period, t0)) # If transit/eclipse duration not supplied by the user, extract it from the get_target_data function: if transit_dur is None and pretransit_duration is None: # Transit duration from get_target_data comes in days: transit_dur = data[0]['transit_duration'] * 24. if secondary: # Factor from equation (16) in Winn (2010). This is, of course, an approximation. # TODO: Implement equation (13) in the same paper. Needs optimization plus numerical integration. factor = np.sqrt(1. - ecc**2) / (1. - ecc * np.sin(omega * (np.pi / 180.))) transit_dur = transit_dur * factor if pretransit_duration is None: pretransit_duration = calculate_pre_duration(transit_dur) print( 'Retrieved transit/eclipse duration is: {} hrs; implied pre mid-transit/eclipse on-target time: {} hrs.' .format(transit_dur, pretransit_duration)) print( 'Performing calculations with Period: {}, t0: {}, ecc: {}, omega: {} degs, inc: {} degs.' .format(period, t0, ecc, omega, inc)) if get_secondary_time: minphase, maxphase, tsec = calculate_phase( period, pretransit_duration, window_size, t0=t0, ecc=ecc, omega=omega, inc=inc, secondary=secondary, winn_approx=winn_approx, get_secondary_time=get_secondary_time) print('MINIMUM PHASE: {}, MAXIMUM PHASE: {}, TSEC: {}'.format( minphase, maxphase, tsec)) return minphase, maxphase, tsec else: minphase, maxphase = calculate_phase( period, pretransit_duration, window_size, t0=t0, ecc=ecc, omega=omega, inc=inc, secondary=secondary, winn_approx=winn_approx, get_secondary_time=get_secondary_time) print('MINIMUM PHASE: {}, MAXIMUM PHASE: {}'.format( minphase, maxphase)) return minphase, maxphase