def test_mpi(verbose=False, plot=False, npoints=8, turn_mpi_off_after=True): phoebe.reset_settings() phoebe.mpi_on(4) b = phoebe.Bundle.default_binary() b.add_dataset('lc', times=np.linspace(0, 1, npoints)) if verbose: print("calling compute") b.run_compute(irrad_method='none', ntriangles=1000, detach=True) if verbose: print("attaching to model") print(b['model'].status) b['model'].attach() if verbose: print("model received") if plot: b.plot(show=True) phoebe.reset_settings() if turn_mpi_off_after: # we need to turn this off for the next test in nosetests... but # if running from python or mpirun, we don't want to release all the # workers or they'll just pickup all the previous tasks phoebe.mpi_off() return b
def __init__(self, input_vals, input_sigmas, flux, times, sigmas, settings='standard', exp_time=False, ncores=32): if settings == 'standard': self.alpha = 1 self.gamma = 2 self.rho = 0.5 self.sigma = 0.5 elif settings == 'agressive': self.alpha = 2 self.gamma = 2 self.rho = 0.95 self.sigma = 0.95 self.ncores = ncores self.history = binary_history(input_vals) self.start = time.time() self.vertices = [] self.units = units() self.chi_history = [] self.sd_history = [] self.steps = [] self.dims = len(input_vals) + 1 self.vals = input_vals self.input_sigmas = input_sigmas self.flux = flux self.times = times self.sigmas = sigmas self.exp_time = exp_time self.start_nprocs = int(self.ncores / self.dims) if self.dims * self.start_nprocs > self.ncores: self.start_nprocs = self.start_nprocs - 1 self.shrink_nprocs = int(self.ncores / (self.dims - 1)) if (self.dims - 1) * self.shrink_nprocs > self.ncores: self.shrink_nprocs = self.shrink_nprocs - 1 self.nprocs = int(self.ncores / 3) if 3 * self.nprocs > self.ncores: self.shrink_nprocs = self.nprocs - 1 vert_vals = [input_vals.copy()] for key in input_vals.keys(): ex_vert_vals = input_vals.copy() ex_vert_vals[key] = ex_vert_vals[key] + input_sigmas[key] vert_vals.append(ex_vert_vals) mult_input = [] for each in vert_vals: mult_input.append((each, flux, times, sigmas, exp_time)) phoebe.mpi_on(nprocs=self.start_nprocs) with mp.Pool(self.dims) as p: self.vertices = p.starmap(vertex_multi, mult_input) self.sort() self.initial_vertex = self.vertices[0]
def calculate_points(self): self.calculate_reflected_point(self.alpha) self.calculate_expanded_point(self.gamma) self.calculate_contracted_point(self.rho) mult_input = [] mult_input.append((self.reflected_point_vals, self.flux, self.times, self.sigmas, self.exp_time)) mult_input.append((self.expanded_point_vals, self.flux, self.times, self.sigmas, self.exp_time)) mult_input.append((self.contracted_point_vals, self.flux, self.times, self.sigmas, self.exp_time)) phoebe.mpi_on(nprocs=self.nprocs) with mp.Pool(processes=3) as p: calculated_points = p.starmap(vertex_multi, mult_input) self.reflected_point = calculated_points[0] self.expanded_point = calculated_points[1] self.contracted_point = calculated_points[2]
def initialize_phoebe(output_dir=None, mpi_ncores=0, logger=True): if output_dir != None: try: os.mkdir(output_dir) except: shutil.rmtree(output_dir) os.mkdir(output_dir) if logger: sys.stdout = Logger(output_dir) phoebe.logger( clevel='ERROR') # ignore warnings - for tqdm to work properly phoebe.interactive_checks_off() phoebe.check_visible_off() phoebe.interactive_constraints_off() if mpi_ncores != 0: phoebe.mpi_on(nprocs=mpi_ncores) return output_dir
def shrink(self): phoebe.mpi_on(nprocs=self.shrink_nprocs) new_vertices = [self.vertices[0]] mult_input = [] for vert in self.vertices[1:]: new_vals = self.centroid_vals.copy() for key in self.centroid_vals.keys(): new_vals[key] = self.vertices[0].vals[key] + self.sigma * ( vert.vals[key] - self.vertices[0].vals[key]) mult_input.append( (new_vals, self.flux, self.times, self.sigmas, self.exp_time)) with mp.Pool(self.dims - 1) as p: new_calculated = p.starmap(vertex_multi, mult_input) for each in new_calculated: new_vertices.append(each) self.vertices = new_vertices self.last_step = 'Shrink' self.standard_deviation()
def test_mpi(plot=False, npoints=8): phoebe.reset_settings() phoebe.mpi_on(4) b = phoebe.Bundle.default_binary() b.add_dataset('lc', times=np.linspace(0, 1, npoints)) if plot: print "calling compute" b.run_compute(irrad_method='none', model='phoebe2model') if plot: print "model received" if plot: b.plot(show=True) phoebe.reset_settings() phoebe.mpi_off() return b
def test_mpi(plot=False, npoints=8): phoebe.reset_settings() phoebe.mpi_on(4) b = phoebe.Bundle.default_binary() b.add_dataset('lc', times=np.linspace(0,1,npoints)) if plot: print "calling compute" b.run_compute(irrad_method='none', ntriangles=1000, detach=True) if plot: print "attaching to model" print b['model'].status b['model'].attach() if plot: print "model received" if plot: b.plot(show=True) phoebe.reset_settings() phoebe.mpi_off() return b
def binary_star_mesh(star1_params, star2_params, binary_params, observation_times, use_blackbody_atm=False, make_mesh_plots=True, mesh_temp=False, mesh_temp_cmap=None, plot_name=None, print_diagnostics=False, par_compute=False, num_par_processes=8, num_triangles=1500): """Compute the light curve for a binary system Keyword arguments: star1_params -- Tuple of parameters for the primary star star2_params -- Tuple of parameters for the secondary star binary_params -- Tuple of parameters for the binary system configuration observation_times -- Tuple of observation times, with numpy array of MJDs in each band (kp_MJDs, h_MJDs, mesh_MJDs) = observation_times use_blackbody_atm -- Use blackbody atmosphere instead of default Castelli & Kurucz (default False) make_mesh_plots -- Make a mesh plot of the binary system (default False) plot_name print_diagnostics par_compute num_par_processes """ if par_compute: # TODO: Need to implement parallelization correctly phoebe.mpi_on(nprocs=num_par_processes) else: phoebe.mpi_off() # Read in the stellar parameters of the binary components (star1_mass, star1_rad, star1_teff, star1_logg, star1_mag_Kp, star1_mag_H, star1_pblum_Kp, star1_pblum_H) = star1_params (star2_mass, star2_rad, star2_teff, star2_logg, star2_mag_Kp, star2_mag_H, star2_pblum_Kp, star2_pblum_H) = star2_params # Read in the parameters of the binary system (binary_period, binary_ecc, binary_inc, t0) = binary_params err_out = (np.array([-1.]), np.array([-1.])) # Check for high temp ck2004 atmosphere limits if not use_blackbody_atm: # log g = 3.5, high temp bounds (above 31e3 K) if star1_teff > (31000 * u.K) and (4.0 > star1_logg > 3.5): star1_teff_round = 30995.0 * u.K if print_diagnostics: print('Star 1 out of C&K 2004 grid') print('star1_logg = {0:.4f}'.format(star1_logg)) print('Rounding down star1_teff') print('{0:.4f} -> {1:.4f}'.format(star1_teff, star1_teff_round)) star1_teff = star1_teff_round if star2_teff > (31000 * u.K) and (4.0 > star2_logg > 3.5): star2_teff_round = 30995.0 * u.K if print_diagnostics: print('Star 2 out of C&K 2004 grid') print('star2_logg = {0:.4f}'.format(star2_logg)) print('Rounding down star2_teff') print('{0:.4f} -> {1:.4f}'.format(star2_teff, star2_teff_round)) star2_teff = star2_teff_round # log g = 4.0, high temp bounds (above 40e3 K) if star1_teff > (40000 * u.K) and (4.5 > star1_logg > 4.0): star1_teff_round = 39995.0 * u.K print('Star 1 out of C&K 2004 grid') print('star1_logg = {0:.4f}'.format(star1_logg)) print('Rounding down star1_teff') print('{0:.4f} -> {1:.4f}'.format(star1_teff, star1_teff_round)) star1_teff = star1_teff_round if star2_teff > (40000 * u.K) and (4.0 > star2_logg > 3.50): star2_teff_round = 39995.0 * u.K print('Star 2 out of C&K 2004 grid') print('star2_logg = {0:.4f}'.format(star2_logg)) print('Rounding down star2_teff') print('{0:.4f} -> {1:.4f}'.format(star2_teff, star2_teff_round)) star2_teff = star2_teff_round # Set up binary model b = phoebe.default_binary() ## Set a default distance b.set_value('distance', 10 * u.pc) ## Set period, semimajor axis, and mass ratio (q) binary_sma = ((binary_period**2. * const.G * (star1_mass + star2_mass)) / (4. * np.pi**2.))**(1. / 3.) binary_q = star2_mass / star1_mass if print_diagnostics: print('\nBinary orbit checks') print('Binary SMA: {0}'.format(binary_sma.to(u.AU))) print('Binary Mass Ratio (q): {0}'.format(binary_q)) b.set_value('period@orbit', binary_period) b.set_value('sma@binary@component', binary_sma) b.set_value('q@binary@component', binary_q) ## Inclination b.set_value('incl@orbit', binary_inc) # Check for overflow ## Variables to help store the non-detached binary cases star1_semidetached = False star2_semidetached = False star1_overflow = False star2_overflow = False ## Get the max radii for both component stars star1_rad_max = b.get_value('requiv_max@primary@component') * u.solRad star2_rad_max = b.get_value('requiv_max@secondary@component') * u.solRad ## Check for semidetached cases if print_diagnostics: print('\nSemidetached checks') print('Star 1: {0}'.format( np.abs((star1_rad - star1_rad_max) / star1_rad_max))) print('Star 2: {0}'.format( np.abs((star2_rad - star2_rad_max) / star2_rad_max))) semidet_cut = 0.001 # (within 0.1% of max radii) semidet_cut = 0.015 # (within 1.5% of max radii) if np.abs((star1_rad - star1_rad_max) / star1_rad_max) < semidet_cut: star1_semidetached = True if np.abs((star2_rad - star2_rad_max) / star2_rad_max) < semidet_cut: star2_semidetached = True ## Check for overflow if (star1_rad > star1_rad_max) and not star1_semidetached: star1_overflow = True if (star2_rad > star2_rad_max) and not star2_semidetached: star2_overflow = True ### Check for if both stars are overflowing; which star overflows more? ### Choose that star to be overflowing more if star1_overflow and star2_overflow: if (star1_rad - star1_rad_max) >= (star2_rad - star2_rad_max): star2_overflow = False else: star1_overflow = False if print_diagnostics: print('\nOverflow Checks') print('Star 1 Semidetached: {0}'.format(star1_semidetached)) print('Star 2 Semidetached: {0}'.format(star2_semidetached)) print('Star 1 Overflow: {0}'.format(star1_overflow)) print('Star 2 Overflow: {0}'.format(star2_overflow)) # If star 2 is overflowing, have to re set up model: # Calling this same binary_star_lc function again, # with star 2 as primary and star 1 as secondary. # Change t0 = t0 - per/2 to make sure phase is correct, # wrt stars 1 and 2 being in same respective position if star2_overflow and not star1_overflow: redo_binary_params = (binary_period, binary_ecc, binary_inc, t0 - (binary_period.to(u.d).value / 2.)) return binary_star_lc(star2_params, star1_params, redo_binary_params, observation_times, use_blackbody_atm=use_blackbody_atm, make_mesh_plots=make_mesh_plots, mesh_temp=mesh_temp, mesh_temp_cmap=mesh_temp_cmap, plot_name=plot_name, print_diagnostics=print_diagnostics, par_compute=par_compute, num_par_processes=num_par_processes, num_triangles=num_triangles) ## If none of these overflow cases, set variable to store if binary is detached binary_detached = (not star1_semidetached) and \ (not star2_semidetached) and \ (not star1_overflow) and \ (not star2_overflow) ### Set non-zero eccentricity only if binary is detached if binary_detached: b.set_value('ecc@binary@component', binary_ecc) else: b.set_value('ecc@binary@component', 0.) ## Change set up for contact or semidetached cases if star1_overflow or star2_overflow: b = phoebe.default_binary(contact_binary=True) ### Reset all necessary binary properties for contact system b.set_value('distance', 10 * u.pc) b.set_value('period@orbit', binary_period) b.set_value('sma@binary@component', binary_sma) b.set_value('q@binary@component', binary_q) b.set_value('incl@orbit', binary_inc) if star1_semidetached and not star2_overflow: b.add_constraint('semidetached', 'primary') if star2_semidetached and not star1_overflow: b.add_constraint('semidetached', 'secondary') # Set up compute if use_blackbody_atm: b.add_compute('phoebe', compute='detailed', irrad_method='wilson', atm='blackbody') else: b.add_compute('phoebe', compute='detailed', irrad_method='wilson') # Set the parameters of the component stars of the system ## Primary b.set_value('teff@primary@component', star1_teff) # b.set_value('logg@primary@component', star1_logg) if (not star1_semidetached) and (not star2_overflow): b.set_value('requiv@primary@component', star1_rad) ## Secondary b.set_value('teff@secondary@component', star2_teff) # b.set_value('logg@secondary@component', star2_logg) if (not star2_semidetached) and (not star1_overflow) and ( not star2_overflow): try: b.set_value('requiv@secondary@component', star2_rad) except: print('\nOverflow Checks') print('Star 1 Semidetached: {0}'.format(star1_semidetached)) print('Star 2 Semidetached: {0}'.format(star2_semidetached)) print('Star 1 Overflow: {0}'.format(star1_overflow)) print('Star 2 Overflow: {0}'.format(star2_overflow)) print("Cannot set secondary radius: {0}".format(sys.exc_info()[0])) return err_out # Set the number of triangles in the mesh # Detached stars if len(b.filter('ntriangles@primary@detailed@compute')) == 1: b.set_value('ntriangles@primary@detailed@compute', num_triangles) if len(b.filter('ntriangles@secondary@detailed@compute')) == 1: b.set_value('ntriangles@secondary@detailed@compute', num_triangles) # Contact envelope if len(b.filter('ntriangles@contact_envelope@detailed@compute')) == 1: if print_diagnostics: print('Setting number of triangles for contact envelope') b.set_value('ntriangles@contact_envelope@detailed@compute', num_triangles * 2.) # Phase the observation times ## Read in observation times (kp_MJDs, h_MJDs, mesh_MJDs) = observation_times ## Phase the observation times kp_phased_days = ( (kp_MJDs - t0) % binary_period.to(u.d).value) / binary_period.to( u.d).value h_phased_days = ((h_MJDs - t0) % binary_period.to(u.d).value) / binary_period.to(u.d).value mesh_phased_days = ( (mesh_MJDs - t0) % binary_period.to(u.d).value) / binary_period.to( u.d).value # Add light curve datasets ## Kp kp_phases_sorted_inds = np.argsort(kp_phased_days) kp_model_times = (kp_phased_days) * binary_period.to(u.d).value kp_model_times = kp_model_times[kp_phases_sorted_inds] # b.add_dataset(phoebe.dataset.lc, time=kp_model_times, # dataset='mod_lc_Kp', passband='Keck_NIRC2:Kp') if use_blackbody_atm: b.add_dataset(phoebe.dataset.lc, time=kp_model_times, dataset='mod_lc_Kp', passband='Keck_NIRC2:Kp') b.set_value('ld_mode@primary@mod_lc_Kp', 'manual') b.set_value('ld_mode@secondary@mod_lc_Kp', 'manual') b.set_value('ld_func@primary@mod_lc_Kp', 'logarithmic') b.set_value('ld_func@secondary@mod_lc_Kp', 'logarithmic') else: b.add_dataset(phoebe.dataset.lc, time=kp_model_times, dataset='mod_lc_Kp', passband='Keck_NIRC2:Kp') ## H h_phases_sorted_inds = np.argsort(h_phased_days) h_model_times = (h_phased_days) * binary_period.to(u.d).value h_model_times = h_model_times[h_phases_sorted_inds] # b.add_dataset(phoebe.dataset.lc, times=h_model_times, # dataset='mod_lc_H', passband='Keck_NIRC2:H') if use_blackbody_atm: b.add_dataset(phoebe.dataset.lc, times=h_model_times, dataset='mod_lc_H', passband='Keck_NIRC2:H') b.set_value('ld_mode@primary@mod_lc_H', 'manual') b.set_value('ld_mode@secondary@mod_lc_H', 'manual') b.set_value('ld_func@primary@mod_lc_H', 'logarithmic') b.set_value('ld_func@secondary@mod_lc_H', 'logarithmic') else: b.add_dataset(phoebe.dataset.lc, times=h_model_times, dataset='mod_lc_H', passband='Keck_NIRC2:H') # Add mesh dataset if making mesh plot mesh_phases_sorted_inds = np.argsort(mesh_phased_days) mesh_model_times = (mesh_phased_days) * binary_period.to(u.d).value mesh_model_times = mesh_model_times[mesh_phases_sorted_inds] if make_mesh_plots: b.add_dataset('mesh', times=mesh_model_times, dataset='mod_mesh') if mesh_temp: b['columns@mesh'] = ['teffs', 'loggs'] # Set the passband luminosities for the stars b.set_value('pblum_mode@mod_lc_Kp', 'decoupled') b.set_value('pblum_mode@mod_lc_H', 'decoupled') b.set_value('pblum@primary@mod_lc_Kp', star1_pblum_Kp) b.set_value('pblum@primary@mod_lc_H', star1_pblum_H) b.set_value('pblum@secondary@mod_lc_Kp', star2_pblum_Kp) b.set_value('pblum@secondary@mod_lc_H', star2_pblum_H) # Run compute # if print_diagnostics: # print("Trying inital compute run") # b.run_compute(compute='detailed', model='run', # progressbar=False) try: b.run_compute(compute='detailed', model='run', progressbar=False) except: if print_diagnostics: print("Error during primary binary compute: {0}".format( sys.exc_info()[0])) return err_out # Save out mesh plot if make_mesh_plots: ## Plot Nerdery plt.rc('font', family='serif') plt.rc('font', serif='Computer Modern Roman') plt.rc('text', usetex=True) plt.rc('text.latex', preamble=r"\usepackage{gensymb}") plt.rc('xtick', direction='in') plt.rc('ytick', direction='in') # plt.rc('xtick', top = True) # plt.rc('ytick', right = True) suffix_str = '' if plot_name is not None: suffix_str = '_' + plot_name ## Mesh plot mesh_plot_out = [] if mesh_temp: b['mod_mesh@model'].plot( fc='teffs', fcmap=mesh_temp_cmap, ec='face', animate=True, save='./binary_mesh{0}.gif'.format(suffix_str), save_kwargs={'writer': 'imagemagick'}) for (mesh_model_time, mesh_index) in zip(mesh_model_times, range(len(mesh_model_times))): plt.clf() new_fig = plt.figure() (mesh_af_fig, mesh_plt_fig) = b['mod_mesh@model'].plot( fig=new_fig, time=mesh_model_time, fc='teffs', fcmap=mesh_temp_cmap, ec='face', save='./binary_mesh_{0}.pdf'.format(mesh_index)) mesh_plot_out.append(mesh_plt_fig) plt.close(new_fig) else: b['mod_mesh@model'].plot( animate=True, save='./binary_mesh{0}.gif'.format(suffix_str), save_kwargs={'writer': 'imagemagick'}) for mesh_model_time in mesh_model_times: mesh_plot_out.append(b['mod_mesh@model'].plot( time=mesh_model_time, save='./binary_mesh.pdf'.format(suffix_str))) # Get fluxes ## Kp model_fluxes_Kp = np.array( b['fluxes@lc@mod_lc_Kp@model'].value) * u.W / (u.m**2.) model_mags_Kp = -2.5 * np.log10(model_fluxes_Kp / flux_ref_Kp) + 0.03 ## H model_fluxes_H = np.array( b['fluxes@lc@mod_lc_H@model'].value) * u.W / (u.m**2.) model_mags_H = -2.5 * np.log10(model_fluxes_H / flux_ref_H) + 0.03 if print_diagnostics: print('\nFlux Checks') print('Fluxes, Kp: {0}'.format(model_fluxes_Kp)) print('Mags, Kp: {0}'.format(model_mags_Kp)) print('Fluxes, H: {0}'.format(model_fluxes_H)) print('Mags, H: {0}'.format(model_mags_H)) if make_mesh_plots: return (model_mags_Kp, model_mags_H, mesh_plot_out) else: return (model_mags_Kp, model_mags_H)
# Accessing/Changing MPI Settings # -------------------- # To check the currently adopted settings, as well as quickly access information needed for manually doing your own parallelization, access the phoebe.mpi object. # In[2]: print(phoebe.mpi.enabled) # In[3]: print(phoebe.mpi.mode) # In[4]: phoebe.mpi_on() # In[5]: print(phoebe.mpi.enabled) # In[6]: print(phoebe.mpi.mode) # In[7]: print(phoebe.mpi.myrank) # In[8]:
def binary_star_lc(star1_params, star2_params, binary_params, observation_times, use_blackbody_atm=False, use_compact_object=False, make_mesh_plots=False, mesh_temp=False, mesh_temp_cmap=None, plot_name=None, print_diagnostics=False, par_compute=False, num_par_processes=8, num_triangles=1500): """Compute the light curve for a binary system Keyword arguments: star1_params -- Tuple of parameters for the primary star star2_params -- Tuple of parameters for the secondary star binary_params -- Tuple of parameters for the binary system configuration observation_times -- Tuple of observation times, with numpy array of MJDs in each band and for the RVs (kp_MJDs, h_MJDs, rv_MJDs) = observation_times use_blackbody_atm -- Use blackbody atmosphere instead of default Castelli & Kurucz (default False) use_compact_object -- Set eclipse_method to 'only_horizon', necessary for compact companions without eclipses (default False) make_mesh_plots -- Make a mesh plot of the binary system (default False) plot_name print_diagnostics par_compute num_par_processes """ if par_compute: # TODO: Need to implement parallelization correctly phoebe.mpi_on(nprocs=num_par_processes) else: phoebe.mpi_off() # Read in the stellar parameters of the binary components (star1_mass, star1_rad, star1_teff, star1_logg, [star1_mag_Kp, star1_mag_H], [star1_pblum_Kp, star1_pblum_H]) = star1_params (star2_mass, star2_rad, star2_teff, star2_logg, [star2_mag_Kp, star2_mag_H], [star2_pblum_Kp, star2_pblum_H]) = star2_params # Read in the parameters of the binary system (binary_period, binary_ecc, binary_inc, t0) = binary_params err_out = (np.array([-1.]), np.array([-1.]), np.array([-1.]), np.array([-1.])) if make_mesh_plots: err_out = (np.array([-1.]), np.array([-1.]), np.array([-1.]), np.array([-1.]), np.array([-1.])) # Check for high temp ck2004 atmosphere limits if not use_blackbody_atm: # log g = 3.5, high temp bounds (above 31e3 K) if star1_teff > (31000 * u.K) and (4.0 > star1_logg > 3.5): star1_teff_round = 30995.0 * u.K if print_diagnostics: print('Star 1 out of C&K 2004 grid') print('star1_logg = {0:.4f}'.format(star1_logg)) print('Rounding down star1_teff') print('{0:.4f} -> {1:.4f}'.format(star1_teff, star1_teff_round)) star1_teff = star1_teff_round if star2_teff > (31000 * u.K) and (4.0 > star2_logg > 3.5): star2_teff_round = 30995.0 * u.K if print_diagnostics: print('Star 2 out of C&K 2004 grid') print('star2_logg = {0:.4f}'.format(star2_logg)) print('Rounding down star2_teff') print('{0:.4f} -> {1:.4f}'.format(star2_teff, star2_teff_round)) star2_teff = star2_teff_round # log g = 4.0, high temp bounds (above 40e3 K) if star1_teff > (40000 * u.K) and (4.5 > star1_logg > 4.0): star1_teff_round = 39995.0 * u.K print('Star 1 out of C&K 2004 grid') print('star1_logg = {0:.4f}'.format(star1_logg)) print('Rounding down star1_teff') print('{0:.4f} -> {1:.4f}'.format(star1_teff, star1_teff_round)) star1_teff = star1_teff_round if star2_teff > (40000 * u.K) and (4.0 > star2_logg > 3.50): star2_teff_round = 39995.0 * u.K print('Star 2 out of C&K 2004 grid') print('star2_logg = {0:.4f}'.format(star2_logg)) print('Rounding down star2_teff') print('{0:.4f} -> {1:.4f}'.format(star2_teff, star2_teff_round)) star2_teff = star2_teff_round # Set up binary model b = phoebe.default_binary() ## Set a default distance b.set_value('distance', 10 * u.pc) ## Set period, semimajor axis, and mass ratio (q) binary_sma = ((binary_period**2. * const.G * (star1_mass + star2_mass)) / (4. * np.pi**2.))**(1./3.) binary_q = star2_mass / star1_mass if print_diagnostics: print('\nBinary orbit checks') print('Binary SMA: {0}'.format(binary_sma.to(u.AU))) print('Binary Mass Ratio (q): {0}'.format(binary_q)) b.set_value('period@orbit', binary_period) b.set_value('sma@binary@component', binary_sma) b.set_value('q@binary@component', binary_q) ## Inclination b.set_value('incl@orbit', binary_inc) # Check for overflow ## Variables to help store the non-detached binary cases star1_semidetached = False star2_semidetached = False star1_overflow = False star2_overflow = False ## Get the max radii for both component stars star1_rad_max = b.get_value('requiv_max@primary@component') * u.solRad star2_rad_max = b.get_value('requiv_max@secondary@component') * u.solRad ## Check for semidetached cases if print_diagnostics: print('\nSemidetached checks') print('Star 1: {0}'.format(np.abs((star1_rad - star1_rad_max) / star1_rad_max))) print('Star 2: {0}'.format(np.abs((star2_rad - star2_rad_max) / star2_rad_max))) semidet_cut = 0.001 # (within 0.1% of max radii) semidet_cut = 0.015 # (within 1.5% of max radii) if np.abs((star1_rad - star1_rad_max) / star1_rad_max) < semidet_cut: star1_semidetached = True if np.abs((star2_rad - star2_rad_max) / star2_rad_max) < semidet_cut: star2_semidetached = True ## Check for overflow if (star1_rad > star1_rad_max) and not star1_semidetached: star1_overflow = True if (star2_rad > star2_rad_max) and not star2_semidetached: star2_overflow = True ### Check for if both stars are overflowing; which star overflows more? ### Choose that star to be overflowing more if star1_overflow and star2_overflow: if (star1_rad - star1_rad_max) >= (star2_rad - star2_rad_max): star2_overflow = False else: star1_overflow = False if print_diagnostics: print('\nOverflow Checks') print('Star 1 Semidetached: {0}'.format(star1_semidetached)) print('Star 2 Semidetached: {0}'.format(star2_semidetached)) print('Star 1 Overflow: {0}'.format(star1_overflow)) print('Star 2 Overflow: {0}'.format(star2_overflow)) # If star 2 is overflowing, have to re set up model: # Calling this same binary_star_lc function again, # with star 2 as primary and star 1 as secondary. # Change t0 = t0 - per/2 to make sure phase is correct, # wrt stars 1 and 2 being in same respective position if star2_overflow and not star1_overflow: redo_binary_params = (binary_period, binary_ecc, binary_inc, t0 - (binary_period.to(u.d).value/2.)) return binary_star_lc(star2_params, star1_params, redo_binary_params, observation_times, use_blackbody_atm=use_blackbody_atm, make_mesh_plots=make_mesh_plots, mesh_temp=mesh_temp, mesh_temp_cmap=mesh_temp_cmap, plot_name=plot_name, print_diagnostics=print_diagnostics, par_compute=par_compute, num_par_processes=num_par_processes, num_triangles=num_triangles) ## If none of these overflow cases, set variable to store if binary is detached binary_detached = (not star1_semidetached) and \ (not star2_semidetached) and \ (not star1_overflow) and \ (not star2_overflow) ### Set non-zero eccentricity only if binary is detached if binary_detached: b.set_value('ecc@binary@component', binary_ecc) else: b.set_value('ecc@binary@component', 0.) ## Change set up for contact or semidetached cases if star1_overflow or star2_overflow: b = phoebe.default_binary(contact_binary=True) ### Reset all necessary binary properties for contact system b.set_value('distance', 10 * u.pc) b.set_value('period@orbit', binary_period) b.set_value('sma@binary@component', binary_sma) b.set_value('q@binary@component', binary_q) b.set_value('incl@orbit', binary_inc) if star1_semidetached and not star2_overflow: b.add_constraint('semidetached', 'primary') if star2_semidetached and not star1_overflow: b.add_constraint('semidetached', 'secondary') # Set up compute if use_blackbody_atm: b.add_compute('phoebe', compute='detailed', irrad_method='wilson', atm='blackbody') b.set_value('atm@primary@detailed', 'blackbody') b.set_value('atm@secondary@detailed', 'blackbody') else: b.add_compute('phoebe', compute='detailed', irrad_method='wilson') # Set the parameters of the component stars of the system ## Primary b.set_value('teff@primary@component', star1_teff) # b.set_value('logg@primary@component', star1_logg) if (not star1_semidetached) and (not star2_overflow): b.set_value('requiv@primary@component', star1_rad) ## Secondary b.set_value('teff@secondary@component', star2_teff) # b.set_value('logg@secondary@component', star2_logg) if (not star2_semidetached) and (not star1_overflow) and (not star2_overflow): try: b.set_value('requiv@secondary@component', star2_rad) except: print('\nOverflow Checks') print('Star 1 Semidetached: {0}'.format(star1_semidetached)) print('Star 2 Semidetached: {0}'.format(star2_semidetached)) print('Star 1 Overflow: {0}'.format(star1_overflow)) print('Star 2 Overflow: {0}'.format(star2_overflow)) print("Cannot set secondary radius: {0}".format(sys.exc_info()[0])) return err_out # Set the number of triangles in the mesh # Detached stars if len(b.filter('ntriangles@primary@detailed@compute')) == 1: b.set_value('ntriangles@primary@detailed@compute', num_triangles) if len(b.filter('ntriangles@secondary@detailed@compute')) == 1: b.set_value('ntriangles@secondary@detailed@compute', num_triangles) # Contact envelope if len(b.filter('ntriangles@contact_envelope@detailed@compute')) == 1: if print_diagnostics: print('Setting number of triangles for contact envelope') b.set_value('ntriangles@contact_envelope@detailed@compute', num_triangles * 2.) # Phase the observation times ## Read in observation times (kp_MJDs, h_MJDs, rv_MJDs) = observation_times ## Phase the observation times kp_phased_days = ((kp_MJDs - t0) % binary_period.to(u.d).value) / binary_period.to(u.d).value h_phased_days = ((h_MJDs - t0) % binary_period.to(u.d).value) / binary_period.to(u.d).value rv_phased_days = ((rv_MJDs - t0) % binary_period.to(u.d).value) / binary_period.to(u.d).value # Add light curve datasets if use_blackbody_atm: b.set_value_all('ld_mode_bol', 'manual') b.set_value_all('ld_func_bol', 'linear') b.set_value_all('ld_coeffs_bol', [0.0]) # Check for compact companion if use_compact_object: b.set_value('irrad_method@detailed', 'none') ## Kp kp_phases_sorted_inds = np.argsort(kp_phased_days) kp_model_times = (kp_phased_days) * binary_period.to(u.d).value kp_model_times = kp_model_times[kp_phases_sorted_inds] if use_blackbody_atm: b.add_dataset(phoebe.dataset.lc, time=kp_model_times, dataset='mod_lc_Kp', passband='Keck_NIRC2:Kp') b.set_value_all('ld_mode@mod_lc_Kp', 'manual') b.set_value_all('ld_func@mod_lc_Kp', 'linear') b.set_value_all('ld_coeffs@mod_lc_Kp', [0.0]) else: b.add_dataset(phoebe.dataset.lc, time=kp_model_times, dataset='mod_lc_Kp', passband='Keck_NIRC2:Kp') ## H h_phases_sorted_inds = np.argsort(h_phased_days) h_model_times = (h_phased_days) * binary_period.to(u.d).value h_model_times = h_model_times[h_phases_sorted_inds] if use_blackbody_atm: b.add_dataset(phoebe.dataset.lc, times=h_model_times, dataset='mod_lc_H', passband='Keck_NIRC2:H') b.set_value_all('ld_mode@mod_lc_H', 'manual') b.set_value_all('ld_func@mod_lc_H', 'linear') b.set_value_all('ld_coeffs@mod_lc_H', [0.0]) else: b.add_dataset(phoebe.dataset.lc, times=h_model_times, dataset='mod_lc_H', passband='Keck_NIRC2:H') ## RV rv_phases_sorted_inds = np.argsort(rv_phased_days) rv_model_times = (rv_phased_days) * binary_period.to(u.d).value rv_model_times = rv_model_times[rv_phases_sorted_inds] if use_blackbody_atm: b.add_dataset(phoebe.dataset.rv, time=rv_model_times, dataset='mod_rv', passband='Keck_NIRC2:Kp') b.set_value_all('ld_mode@mod_rv', 'manual') b.set_value_all('ld_func@mod_rv', 'linear') b.set_value_all('ld_coeffs@mod_rv', [0.0]) else: b.add_dataset(phoebe.dataset.rv, time=rv_model_times, dataset='mod_rv', passband='Keck_NIRC2:Kp') # Add mesh dataset if making mesh plot if make_mesh_plots: b.add_dataset('mesh', times=[(binary_period/4.).to(u.d).value], dataset='mod_mesh') if mesh_temp: b['columns@mesh'] = ['teffs', 'loggs', 'areas', '*@mod_lc_Kp', '*@mod_lc_H'] # Set the passband luminosities for the stars b.set_value('pblum_mode@mod_lc_Kp', 'decoupled') b.set_value('pblum_mode@mod_lc_H', 'decoupled') b.set_value('pblum@primary@mod_lc_Kp', star1_pblum_Kp) b.set_value('pblum@primary@mod_lc_H', star1_pblum_H) b.set_value('pblum@secondary@mod_lc_Kp', star2_pblum_Kp) b.set_value('pblum@secondary@mod_lc_H', star2_pblum_H) # Run compute # Determine eclipse method if use_compact_object: eclipse_method = 'only_horizon' else: eclipse_method = 'native' if print_diagnostics: print("Trying inital compute run") b.run_compute(compute='detailed', model='run', progressbar=False, eclipse_method=eclipse_method) else: try: b.run_compute(compute='detailed', model='run', progressbar=False, eclipse_method=eclipse_method) except: if print_diagnostics: print("Error during primary binary compute: {0}".format(sys.exc_info()[0])) return err_out # Save out mesh plot if make_mesh_plots: ## Plot Nerdery plt.rc('font', family='serif') plt.rc('font', serif='Computer Modern Roman') plt.rc('text', usetex=True) plt.rc('text.latex', preamble=r"\usepackage{gensymb}") plt.rc('xtick', direction = 'in') plt.rc('ytick', direction = 'in') # plt.rc('xtick', top = True) # plt.rc('ytick', right = True) suffix_str = '' if plot_name is not None: suffix_str = '_' + plot_name ## Mesh plot if mesh_temp: mesh_plot_out = b['mod_mesh@model'].plot(save='./binary_mesh{0}.pdf'.format(suffix_str), fc='teffs', fcmap=mesh_temp_cmap, ec='none') # print(mesh_plot_out.axs) # Extract and output mesh quantities mesh_quant_names = ['teffs', 'loggs', 'areas', 'abs_intensities'] mesh_quant_do_filt = [False, False, False, True] mesh_quant_units = [u.K, 1.0, u.solRad**2, u.W / (u.m**3)] mesh_quant_filts = ['mod_lc_Kp', 'mod_lc_H'] mesh_quants_pri = {} mesh_quants_sec = {} for (quant, do_filt, quant_unit) in zip(mesh_quant_names, mesh_quant_do_filt, mesh_quant_units): if do_filt: for filt in mesh_quant_filts: quant_pri = b['{0}@primary@{1}'.format(quant, filt)].value *\ quant_unit quant_sec = b['{0}@secondary@{1}'.format(quant, filt)].value *\ quant_unit mesh_quants_pri['{0}_{1}'.format(quant, filt)] = quant_pri mesh_quants_sec['{0}_{1}'.format(quant, filt)] = quant_sec else: quant_pri = b['{0}@primary'.format(quant)].value * quant_unit quant_sec = b['{0}@secondary'.format(quant)].value * quant_unit mesh_quants_pri[quant] = quant_pri mesh_quants_sec[quant] = quant_sec # Construct mesh tables for each star and output mesh_pri_table = Table(mesh_quants_pri) mesh_pri_table.sort(['teffs'], reverse=True) with open('mesh_pri.txt', 'w') as out_file: for line in mesh_pri_table.pformat_all(): out_file.write(line + '\n') mesh_pri_table.write('mesh_pri.h5', format='hdf5', path='data', serialize_meta=True, overwrite=True) mesh_pri_table.write('mesh_pri.fits', format='fits', overwrite=True) mesh_sec_table = Table(mesh_quants_sec) mesh_sec_table.sort(['teffs'], reverse=True) with open('mesh_sec.txt', 'w') as out_file: for line in mesh_sec_table.pformat_all(): out_file.write(line + '\n') mesh_sec_table.write('mesh_sec.h5', format='hdf5', path='data', serialize_meta=True, overwrite=True) mesh_sec_table.write('mesh_sec.fits', format='fits', overwrite=True) else: mesh_plot_out = b['mod_mesh@model'].plot(save='./binary_mesh{0}.pdf'.format(suffix_str)) # Get fluxes ## Kp model_fluxes_Kp = np.array(b['fluxes@lc@mod_lc_Kp@model'].value) * u.W / (u.m**2.) model_mags_Kp = -2.5 * np.log10(model_fluxes_Kp / flux_ref_Kp) + 0.03 ## H model_fluxes_H = np.array(b['fluxes@lc@mod_lc_H@model'].value) * u.W / (u.m**2.) model_mags_H = -2.5 * np.log10(model_fluxes_H / flux_ref_H) + 0.03 # Get RVs model_RVs_pri = np.array(b['rvs@primary@run@rv@model'].value) * u.km / u.s model_RVs_sec = np.array(b['rvs@secondary@run@rv@model'].value) * u.km / u.s if print_diagnostics: print("\nFlux Checks") print("Fluxes, Kp: {0}".format(model_fluxes_Kp)) print("Mags, Kp: {0}".format(model_mags_Kp)) print("Fluxes, H: {0}".format(model_fluxes_H)) print("Mags, H: {0}".format(model_mags_H)) print("\nRV Checks") print("RVs, Primary: {0}".format(model_RVs_pri)) print("RVs, Secondary: {0}".format(model_RVs_sec)) if make_mesh_plots: return (model_mags_Kp, model_mags_H, model_RVs_pri, model_RVs_sec, mesh_plot_out) else: return (model_mags_Kp, model_mags_H, model_RVs_pri, model_RVs_sec)
def binary_star_lc(star1_params, star2_params, binary_params, observation_times, use_blackbody_atm=False, make_mesh_plots=False, plot_name=None, print_diagnostics=False, par_compute=False, num_par_processes=8, num_triangles=1500): """Compute the light curve for a binary system Keyword arguments: star1_params -- Tuple of parameters for the primary star star2_params -- Tuple of parameters for the secondary star binary_params -- Tuple of parameters for the binary system configuration observation_times -- Tuple of observation times, with numpy array of MJDs in each band (kp_MJDs, h_MJDs) = observation_times use_blackbody_atm -- Use blackbody atmosphere instead of default Castelli & Kurucz (default False) make_mesh_plots -- Make a mesh plot of the binary system (default False) plot_name print_diagnostics par_compute num_par_processes """ if par_compute: # TODO: Need to implement parallelization correctly phoebe.mpi_on(nprocs=num_par_processes) else: phoebe.mpi_off() # Read in the stellar parameters of the binary components (star1_mass, star1_rad, star1_teff, star1_mag_Kp, star1_mag_H) = star1_params (star2_mass, star2_rad, star2_teff, star2_mag_Kp, star2_mag_H) = star2_params # Read in the parameters of the binary system (binary_period, binary_ecc, binary_inc, t0) = binary_params err_out = (np.array([-1.]), np.array([-1.])) # Set up binary model b = phoebe.default_binary() ## Set period, semimajor axis, and mass ratio (q) binary_sma = ((binary_period**2. * const.G * (star1_mass + star2_mass)) / (4. * np.pi**2.))**(1. / 3.) binary_q = star2_mass / star1_mass b.set_value('period@orbit', binary_period) b.set_value('sma@binary@component', binary_sma) b.set_value('q@binary@component', binary_q) ## Inclination b.set_value('incl@orbit', binary_inc) # Check for overflow ## Variables to help store the non-detached binary cases star1_semidetached = False star2_semidetached = False star1_overflow = False star2_overflow = False ## Get the max radii for both component stars star1_rad_max = b.get_value('requiv_max@primary@component') * u.solRad star2_rad_max = b.get_value('requiv_max@secondary@component') * u.solRad ## Check for semidetached cases if print_diagnostics: print('\nSemidetached checks') print(np.abs((star1_rad - star1_rad_max) / star1_rad_max)) print(np.abs((star2_rad - star2_rad_max) / star2_rad_max)) semidet_cut = 0.001 # (within 0.1% of max radii) semidet_cut = 0.015 # (within 1.5% of max radii) if np.abs((star1_rad - star1_rad_max) / star1_rad_max) < semidet_cut: star1_semidetached = True if np.abs((star2_rad - star2_rad_max) / star2_rad_max) < semidet_cut: star2_semidetached = True ## Check for overflow if (star1_rad > star1_rad_max) and not star1_semidetached: star1_overflow = True if (star2_rad > star2_rad_max) and not star2_semidetached: star2_overflow = True ### Check for if both stars are overflowing; which star overflows more? ### Choose that star to be overflowing more if star1_overflow and star2_overflow: if (star1_rad - star1_rad_max) >= (star2_rad - star2_rad_max): star2_overflow = False else: star1_overflow = False if print_diagnostics: print('\nOverflow Checks') print(star1_semidetached) print(star2_semidetached) print(star1_overflow) print(star2_overflow) ## If none of these overflow cases, set variable to store if binary is detached binary_detached = (not star1_semidetached) and ( not star2_semidetached) and (not star1_overflow) and ( not star2_overflow) ### Set non-zero eccentricity only if binary is detached if binary_detached: b.set_value('ecc@binary@component', binary_ecc) else: b.set_value('ecc@binary@component', 0.) ## Change set up for contact or semidetached cases if star1_overflow or star2_overflow: b = phoebe.default_binary(contact_binary=True) b.set_value('period@orbit', binary_period) b.set_value('sma@binary@component', binary_sma) b.set_value('q@binary@component', binary_q) b.set_value('incl@orbit', binary_inc) if star1_semidetached and not star2_overflow: b.add_constraint('semidetached', 'primary') if star2_semidetached and not star1_overflow: b.add_constraint('semidetached', 'secondary') # Set up compute if use_blackbody_atm: b.add_compute('phoebe', compute='detailed', irrad_method='wilson', atm='blackbody') else: b.add_compute('phoebe', compute='detailed', irrad_method='wilson') # Set the parameters of the component stars of the system ## Primary b.set_value('teff@primary@component', star1_teff) if (not star1_semidetached) and (not star2_overflow): b.set_value('requiv@primary@component', star1_rad) ## Secondary b.set_value('teff@secondary@component', star2_teff) if (not star2_semidetached) and (not star1_overflow): b.set_value('requiv@secondary@component', star2_rad) # Set the number of triangles in the mesh b.set_value('ntriangles@primary@detailed@compute', num_triangles) b.set_value('ntriangles@secondary@detailed@compute', num_triangles) # Phase the observation times ## Read in observation times (kp_MJDs, h_MJDs) = observation_times ## Phase the observation times kp_phased_days = ( (kp_MJDs - t0) % binary_period.to(u.d).value) / binary_period.to( u.d).value h_phased_days = ((h_MJDs - t0) % binary_period.to(u.d).value) / binary_period.to(u.d).value # Add light curve datasets ## Kp kp_phases_sorted_inds = np.argsort(kp_phased_days) kp_model_times = (kp_phased_days) * binary_period.to(u.d).value kp_model_times = kp_model_times[kp_phases_sorted_inds] if use_blackbody_atm: b.add_dataset(phoebe.dataset.lc, time=kp_model_times, dataset='mod_lc_Kp', passband='Keck_NIRC2:Kp', ld_func='linear', ld_coeffs=[0.0]) else: b.add_dataset(phoebe.dataset.lc, time=kp_model_times, dataset='mod_lc_Kp', passband='Keck_NIRC2:Kp') ## H h_phases_sorted_inds = np.argsort(h_phased_days) h_model_times = (h_phased_days) * binary_period.to(u.d).value h_model_times = h_model_times[h_phases_sorted_inds] if use_blackbody_atm: b.add_dataset(phoebe.dataset.lc, times=h_model_times, dataset='mod_lc_H', passband='Keck_NIRC2:H', ld_func='linear', ld_coeffs=[0.0]) else: b.add_dataset(phoebe.dataset.lc, times=h_model_times, dataset='mod_lc_H', passband='Keck_NIRC2:H') # Add mesh dataset if making mesh plot if make_mesh_plots: b.add_dataset('mesh', times=[binary_period / 4.], dataset='mod_mesh') # Run compute # b.run_compute(compute='detailed', model='run') try: b.run_compute(compute='detailed', model='run') except: if print_diagnostics: print("Error during primary binary compute: {0}".format( sys.exc_info()[0])) return err_out # Save out mesh plot if make_mesh_plots: ## Plot Nerdery plt.rc('font', family='serif') plt.rc('font', serif='Computer Modern Roman') plt.rc('text', usetex=True) plt.rc('text.latex', preamble=r"\usepackage{gensymb}") plt.rc('xtick', direction='in') plt.rc('ytick', direction='in') plt.rc('xtick', top=True) plt.rc('ytick', right=True) suffix_str = '' if plot_name is not None: suffix_str = '_' + plot_name ## Mesh plot b['mod_mesh@model'].plot( save='./binary_mesh{0}.pdf'.format(suffix_str)) # Get fluxes ## Kp model_fluxes_Kp = np.array( b['fluxes@lc@mod_lc_Kp@model'].value) * u.solLum / ( 4 * np.pi * u.m**2) # * u.W / (u.m**2.) model_mags_Kp = -2.5 * np.log10(model_fluxes_Kp / flux_ref_Kp) + 0.03 ## H model_fluxes_H = np.array( b['fluxes@lc@mod_lc_H@model'].value) * u.solLum / ( 4 * np.pi * u.m**2) # * u.W / (u.m**2.) model_mags_H = -2.5 * np.log10(model_fluxes_H / flux_ref_H) + 0.03 return (model_mags_Kp, model_mags_H)
#% setup general parameters #logg_sun=4.43812 KeplerOffset = 2454833.0 # times relative to this offset will be prefixed by k # number of threads to run simple fit # if n_threads == 0 run simple fit without threading n_threads = 0 machine = os.uname()[1] #machine = '*****@*****.**' if machine == 'user-Latitude-E5570': rootpath = r'/home/user/Dropbox/KBEER_phoebe_ipynb/' sys.path.append('/home/user/Dropbox/spyder/') # path for pyBEER location = 'dell' if n_threads == 0: phoebe.mpi_on(nprocs=4) # elif machine == 'eshel-blue': rootpath = r'/home/eshel-blue/micha/dropboxClone/' sys.path.append( '/home/eshel-blue/micha/dropboxClone/spyder') # path for pyBEER location = 'blue' if n_threads == 0: phoebe.mpi_on(nprocs=6) # elif machine == '*****@*****.**': rootpath = r'/storage/home/engelmic/KBEER/' sys.path.append('/storage/home/engelmic/scripts') # path for pyBEER location = 'astro' else: