<jupyter_start><jupyter_text>Synthetic observations<jupyter_code># Now, we can observe and see what we see.  This takes into account
# duty cycle & data span, as well as geometry.
obs = pop.observe()
print(len(obs))
print(obs.columns)
obs.head()
# This is pretty fast, even when generating a new population each time:
%timeit pop.observe(new=True)
# Even faster if we only generate new orbits.
%timeit pop.observe(new_orbits=True)
# So we can predict the expected number of observations pretty easily.
import numpy as np
N = 100
n_obs = np.array([len(pop.observe(new_orbits=True)) for i in range(N)])
n_obs.mean(), n_obs.std()
# Notice that the above does not yet have trapezoidal parameters.  There are two options to generate these.
# Either we can set the fit_trap parameter, as follows:
obs = pop.observe(fit_trap=True)
print(len(obs))
obs.columns
# All things considered, this is still pretty fast if we just need to do it a few times:
%timeit pop.observe(fit_trap=True)
# However, this is pretty slow if we want to do inference.  To help with this, we can 
# tell it to train & use a regression.  Training only happens once; by default with 10,000 
# synthetic observations.  This takes a minute or so.
obs = pop.observe(regr_trap=True)
print(len(obs))
obs.columns
# Subsequent calls are much faster
%timeit pop.observe(regr_trap=True)
# Even generating a new stellar population & observing it is pretty quick
%timeit pop.observe(regr_trap=True, new=True)
# Or again, you can just generate new orbits (rather than new binaries & new orbits)
%timeit pop.observe(regr_trap=True, new_orbits=True)
# Generating the training data used for the trapezoid shape regression above used
# this function, which can be otherwise useful to sample >N random observations 
# from the existing population.  `trap_regr` defaults to `True` here.  
# This function also takes `new` or `new_orbits` keywords.
obs_pop = pop.get_N_observed(N=2000, new_orbits=True)
print(len(obs_pop))
obs_pop.columns
# Let's look at the distribution of trapezoid parameters
%matplotlib inline
from corner import corner

def trap_corner(df, regr=True, **kwargs):

    pri = df.n_pri.values > 0
    sec = (df.n_sec.values > 0) & ~pri
    
    if regr:
        dur = pri*df.trap_dur_pri_regr.fillna(0) + sec*df.trap_dur_sec_regr.fillna(0)
        logd = np.log10(pri*df.trap_depth_pri_regr.fillna(0) + 
                        sec*df.trap_depth_sec_regr.fillna(0))
        slope = pri*df.trap_slope_pri_regr.fillna(0) + sec*df.trap_slope_sec_regr.fillna(0)
    else:
        dur = pri*df.trap_dur_pri.fillna(0) + sec*df.trap_dur_sec.fillna(0)
        logd = np.log10(pri*df.trap_depth_pri.fillna(0) + sec*df.trap_depth_sec.fillna(0))
        slope = pri*df.trap_slope_pri.fillna(0) + sec*df.trap_slope_sec.fillna(0)
        
    #return (dur, logd, slope)
    return corner(np.array([dur, logd, slope]).T, labels=['duration', 'log(d)', 'T/tau'],
                 plot_contours=False, **kwargs)

    
trap_corner(obs_pop, range=[(0,0.6),(-4,0), (2,6)]);
obs_pop2 = pop.get_N_observed(N=2000, new_orbits=True, fit_trap=True)
trap_corner(obs_pop2, regr=False, range=[(0,0.6),(-4,0), (2,6)]);
# We can now look, e.g. at the expected number of single/double eclipsing systems:
query = '(n_pri < 3) & (n_sec < 3) & (n_pri==0 | n_sec==0)'
N = 100
n_obs = np.array([len(pop.observe(new_orbits=True).query(query)) for i in range(N)])
n_obs.mean(), n_obs.std()
# Try this again, this time using the empirical eccentricity distribution
# (as opposed to the beta distribution with default params)---eccentricity matters!
pop.ecc_empirical = True
n_obs = np.array([len(pop.observe(new_orbits=True).query(query)) for i in range(N)])
n_obs.mean(), n_obs.std()
# You can also save a trained model so that you can load it back and hit the ground running.
pop.save('ebpop', overwrite=True)
pop = KeplerBinaryPopulation.load('ebpop')
# No training necessary!
pop.observe(regr_trap=True).head()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11819556451612903, 'fraction_numerical': 0.014364919354838709, 'mean_word_length': 4.566619915848527, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '418955', 'license': 'MIT', 'n_tokens_mistral': 1470, 'n_tokens_neox': 1408, 'n_words': 412, 'path': 'demo.ipynb', 'repo_name': 'timothydmorton/fppop', 'size': '3968'}