diff --git a/EclipsingBinaries/vseq_updated.py b/EclipsingBinaries/vseq_updated.py index c1691e2..d6e3a9d 100644 --- a/EclipsingBinaries/vseq_updated.py +++ b/EclipsingBinaries/vseq_updated.py @@ -3,7 +3,7 @@ Created on Sat Feb 22 16:09:28 2020 @author: Alec Neal -Last Updated: 04/27/2024 +Last Updated: 05/29/2024 Last Editor: Kyle Koeller Collection of functions, coefficients and equations commonly used @@ -111,51 +111,98 @@ def decimal_limit(a): return b -# ====================================== class io: + """ + This class provides file input/output functionalities. + """ def importFile_pd(inputFile, delimit=None, header=None, file_type='text', engine='python', delim_whitespace=True): + """ + Imports a file and returns a list of columns. + + Parameters: + - inputFile: Path to the input file. + - delimit: Delimiter used in the file. If None, delimiter_whitespace is used for text files. + - header: Row number(s) to use as the column names. + - file_type: Type of the input file. Can be 'text' or 'excel'. + - engine: Parser engine to use. Default is 'python'. + - delim_whitespace: If True, whitespace is used as the delimiter for text files. + + Returns: + - columnlist: A list of columns extracted from the file. + """ + if file_type == 'text': - if delim_whitespace == True: + if delim_whitespace: + # Read text file with whitespace delimiter file = pd.read_csv(inputFile, delim_whitespace=True, header=header, engine='python') else: + # Read text file with custom delimiter file = pd.read_csv(inputFile, sep=delimit, header=header, engine='python') elif file_type == 'excel': + # Read Excel file file = pd.read_excel(inputFile, sep=delimit, header=header, engine='python') else: + # Print error message for unsupported file types print('File type not currently supported. Choose text or excel type.') + + # Extract columns from the file and append them to columnlist columnlist = [] for column in range(len(list(file))): columnlist.append(list(file[column])) - # print(columnlist) + return columnlist + # ======================================= class calc: # assortment of functions def frac(x): + """ + Returns the fractional part of a number. + + Parameters: + x (float): The input number. + + Returns: + float: The fractional part of the input number. + """ return x - np.floor(x) def Newton(f, x0, e=1e-8, fprime=None, max_iter=None, dx=1e-8, central_diff=True, print_iters=False): + """ + Newton-Raphson method for finding roots of a function. + + Parameters: + f (function): The function whose root is being found. + x0 (float): Initial guess for the root. + e (float): Tolerance for convergence. + fprime (function): The derivative of the function f. + max_iter (int): Maximum number of iterations allowed. + dx (float): Step size for numerical differentiation. + central_diff (bool): Whether to use central differencing for numerical differentiation. + print_iters (bool): Whether to print the number of iterations. + + Returns: + float or bool: The estimated root of the function, or False if maximum iterations reached. + """ x = x0 iters = 0 - if fprime == None: - if central_diff == False: - fprime = lambda x, dx=dx: (f(x + dx) / (dx)) + if fprime is None: + if not central_diff: + fprime = lambda x, dx=dx, func=f: (func(x + dx) / dx) + else: - fprime = lambda x, dx=dx: (f(x + dx) - f(x - dx)) / (2 * dx) - if max_iter == None: + fprime = lambda x, dx=dx, func=f: (func(x + dx) - func(x - dx)) / (2 * dx) + if max_iter is None: while abs(f(x)) > e: x -= f(x) / fprime(x) iters += 1 - # print(iters) - # print(x/x0) - if print_iters == True: - print('iters:', iters) + if print_iters: + print('Iterations:', iters) return x else: iters = 0 while abs(f(x)) > e: - # while abs(f(x)) > e: x -= f(x) / fprime(x) iters += 1 if iters == max_iter: @@ -168,122 +215,189 @@ def Newton(f, x0, e=1e-8, fprime=None, max_iter=None, dx=1e-8, central_diff=True class poly: def result(coeflist, value, deriv=False): """ - Result of a polynomial given an ascending order coefficient list, and - an x value. + Calculates the result of a polynomial given its coefficients and a value. + + Parameters: + coeflist (list): List of coefficients in ascending order of the polynomial. + value (float): The value at which the polynomial is evaluated. + deriv (bool, optional): If True, returns the derivative of the polynomial. + + Returns: + float: Result of the polynomial at the given value. """ - # n0=0 - # n=n0 - # termlist=[] - # while(n 1000 is ideal for one time calculations. + Calculates the Light Curve Asymmetry (LCA) given the 'a' and 'b' coefficients. + Must specify the resolution for numerical integration. + + Parameters: + a (array-like): List of 'a' coefficients. + b (array-like): List of 'b' coefficients. + order (int): Order of the Fourier fit. + resolution (int): Number of points for integration. + + Returns: + float: Light Curve Asymmetry (LCA). """ import scipy Phi = np.linspace(0, 0.5, resolution) @@ -993,69 +1349,133 @@ def LCA_FT(a, b, order, resolution): def L_error(phase, order, a, b, a_unc, b_unc): """ - Calculates the error in the LCA integrand, which is then used - to find the error in the LCA. Need a and b coefficients and uncertainties. + Calculates the error in the LCA integrand, which is then used to find the error in the LCA. + Requires 'a' and 'b' coefficients and their uncertainties. + + Parameters: + phase (float): Phase value. + order (int): Order of the Fourier fit. + a (array-like): List of 'a' coefficients. + b (array-like): List of 'b' coefficients. + a_unc (array-like): List of uncertainties for 'a' coefficients. + b_unc (array-like): List of uncertainties for 'b' coefficients. + + Returns: + tuple: A tuple containing the LCA integrand value and its error. """ - I = FT.sumatphase(phase, order, a, b) - J = 2 * FT.sumatphase(phase, order, np.zeros(order + 1), b) + I = FT.sumatphase(phase, order, a, b) # Compute the flux value at the given phase + J = 2 * FT.sumatphase(phase, order, np.zeros(order + 1), b) # Compute a component of the LCA integrand K = J / I - L = K ** 2 + L = K ** 2 # Calculate the LCA integrand value + # Calculate partial derivatives of L with respect to 'a' and 'b' coefficients dL_da0 = -2 * L / I dL_dak = [] dL_dbk = [] - # dL_da0=-2*J**2*I ; dL_dak=[] ; dL_dbk=[] - # J2I=J**2*I for k in range(1, order + 1): - # dL_dak.append(dL_da0*np.cos(2*np.pi*k*phase)) dL_dak.append(dL_da0 * np.cos(2 * np.pi * k * phase)) dL_dbk.append(2 * np.sin(2 * np.pi * k * phase) * (2 * J / I ** 2 - J ** 2 / I ** 3)) + + # Compute the uncertainty in the LCA integrand using error propagation L_err = (dL_da0 * a_unc[0]) ** 2 for n in range(len(dL_dak)): L_err += (dL_dak[n] * a_unc[n + 1]) ** 2 + (dL_dbk[n] * b_unc[n + 1]) ** 2 L_err = np.sqrt(L_err) + return L, L_err def LCA_FT_error(a, b, a_unc, b_unc, order, resolution): """ - Calculates the uncertainty in the FT LCA. - Monte Carlo deviations should be considered - for the total error. + Calculates the uncertainty in the Fourier Transform Light Curve Asymmetry (LCA). + + This function computes the uncertainty in the LCA by integrating the error contributions + at different phases using Simpson's rule. It utilizes the L_error function to calculate + the LCA integrand at each phase, which provides both the LCA value and its uncertainty. + + Parameters: + a (array-like): List of 'a' coefficients. + b (array-like): List of 'b' coefficients. + a_unc (array-like): List of uncertainties for 'a' coefficients. + b_unc (array-like): List of uncertainties for 'b' coefficients. + order (int): Order of the Fourier fit. + resolution (int): Number of points for integration. + + Returns: + tuple: A tuple containing the LCA value and its uncertainty. """ import scipy + + # Generate phase values for integration Phi = np.linspace(0, 0.5, resolution) + + # Initialize lists to store LCA integrand values and their uncertainties at each phase Llist = [] Lerrlist = [] + + # Compute the LCA integrand and its uncertainties at each phase for phase in Phi: L_ap = OConnell.L_error(phase, order, a, b, a_unc, b_unc) Llist.append(L_ap[0]) Lerrlist.append(L_ap[1]) + + # Integrate the LCA integrand and its uncertainties using Simpson's rule int_L = scipy.integrate.simps(Llist, Phi) int_L_error = scipy.integrate.simps(Lerrlist, Phi) - # print('L_err =',int_L_error,'L =',int_L) + + # Compute the LCA value and its uncertainty LCA = OConnell.LCA_FT(a, b, order, resolution) LCA_error = 0.5 * LCA * (int_L_error / int_L) + return LCA, LCA_error def LCA_FT_error2(a, b, a_unc, b_unc, order, resolution): + """ + Calculates the uncertainty in the Fourier Transform Light Curve Asymmetry (LCA) using an alternative method. + + This function computes the uncertainty in the LCA by directly evaluating the LCA integrand + at different phases. It then integrates these values to obtain the total uncertainty in the LCA. + It is an alternative approach to LCA_FT_error, utilizing a different method for calculating the + uncertainty contribution at each phase. + + Parameters: + a (array-like): List of 'a' coefficients. + b (array-like): List of 'b' coefficients. + a_unc (array-like): List of uncertainties for 'a' coefficients. + b_unc (array-like): List of uncertainties for 'b' coefficients. + order (int): Order of the Fourier fit. + resolution (int): Number of points for integration. + + Returns: + tuple: A tuple containing the LCA value and its uncertainty. + + """ a, a_unc = np.array(a), np.array(a_unc) b, b_unc = np.array(b), np.array(b_unc) def L_error2(phase): - nlist = np.arange(order + 1) - dIphi = 2 * sum(b[nlist] * np.sin(2 * np.pi * nlist * phase)) - I = FT.sumatphase(phase, order, a, b) - # if (dIphi/I)**2 == 0.0: - # L=1e-16 - # else: - L = (dIphi / I) ** 2 - print(L) - # radicand=0 - # radicand+=sum((a_unc*np.cos(2*np.pi*phase*nlist))**2) - # radicand+=(2/np.sqrt(L)-1)**2*sum((b_unc*np.sin(2*np.pi*phase*nlist))**2) - # return L, 2*L/I*np.sqrt(radicand) - return L, 2 / I * (2 * L ** 0.5 - L) * np.sqrt(sum((b_unc * np.sin(2 * np.pi * phase * nlist)) ** 2)) - # return L, 4/I*np.sqrt(L*sum((b_unc*np.sin(2*np.pi*phase*nlist))**2)) + """ + Calculates the error contribution for the Fourier Transform Light Curve Asymmetry (LCA) integrand at a given phase. + + This function computes the error contribution of the LCA integrand at a specified phase. + It first calculates the derivative of the flux with respect to phase, 'dIphi', and the flux value 'I' + at the given phase using the provided 'a' and 'b' coefficients. Then, it computes the LCA integrand + error term 'L', which is the square of the ratio of 'dIphi' to 'I'. Additionally, it calculates the + uncertainty in 'L' using error propagation, considering the uncertainties in 'a' and 'b' coefficients. + + Parameters: + phase (float): Phase at which to compute the error contribution. + + Returns: + tuple: A tuple containing the LCA integrand error term 'L' and its uncertainty. + """ + nlist = np.arange(order + 1) # Generate the list of orders + dIphi = 2 * sum( + b[nlist] * np.sin(2 * np.pi * nlist * phase)) # Compute the derivative of flux with respect to phase + I = FT.sumatphase(phase, order, a, b) # Compute the flux value at the given phase + L = (dIphi / I) ** 2 # Calculate the LCA integrand error term + # Calculate the uncertainty in the LCA integrand using error propagation + L_err = 2 / I * (2 * L ** 0.5 - L) * np.sqrt(sum((b_unc * np.sin(2 * np.pi * phase * nlist)) ** 2)) + return L, L_err import scipy Phi = np.linspace(0, 0.5, resolution) @@ -1074,10 +1494,20 @@ def L_error2(phase): def Delta_I(a, b, order): """ - Directly calculates the difference in flux at the two - quadratures (0.25, 0.75), given the a and b coefficients. - One of the direct measures of the O'Connell effect, along - with dIave and 2b1. + Directly calculates the difference in flux at the two quadratures (0.25, 0.75), + given the 'a' and 'b' coefficients. + + This function calculates the difference in flux between two quadrature phases (0.25 and 0.75), + providing insight into the O'Connell effect. It returns the difference in flux, as well as the + flux values at the specified phases. + + Parameters: + a (array-like): List of 'a' coefficients. + b (array-like): List of 'b' coefficients. + order (int): Order of the Fourier fit. + + Returns: + tuple: A tuple containing the difference in flux, flux at phase 0.25, and flux at phase 0.75. """ Ip = FT.sumatphase(0.25, order, a, b) Is = FT.sumatphase(0.75, order, a, b) @@ -1086,44 +1516,110 @@ def Delta_I(a, b, order): def Delta_I_error(a, b, a_unc, b_unc, order): """ - Calculates the FT error in dI. Requires the coefficients - and their uncertainties. + Calculates the uncertainty in dI of the Fourier Transform. + + Parameters: + a (array-like): List of 'a' coefficients. + b (array-like): List of 'b' coefficients. + a_unc (array-like): List of uncertainties for 'a' coefficients. + b_unc (array-like): List of uncertainties for 'b' coefficients. + order (int): Order of the Fourier fit. + + Returns: + tuple: A tuple containing the dI value and its uncertainty. """ + # Calculate uncertainties at quadrature phases sig_Ip = FT.unc_sumatphase(0.25, order, a_unc, b_unc) sig_Is = FT.unc_sumatphase(0.75, order, a_unc, b_unc) + + # Compute total uncertainty in dI sig_dI = np.sqrt(sig_Ip ** 2 + sig_Is ** 2) + + # Calculate dI value dI = OConnell.Delta_I(a, b, order)[0] + return dI, sig_dI def Delta_I_fixed(b, order): + """ + Calculates the difference in flux at the two quadratures (0.25, 0.75) + for a given set of 'b' coefficients. + + Parameters: + b (array-like): List of 'b' coefficients. + order (int): Order of the Fourier fit. + + Returns: + float: Difference in flux at quadratures. + """ mlist = np.arange(int(np.ceil(order / 2))) return 2 * sum((-1) ** mlist * b[2 * mlist + 1]) def Delta_I_error_fixed(b_unc, order): - # return 2*np.sqrt(sum(b_unc[np.arange(order+1)[1::2]]**2)) + """ + Calculates the uncertainty in dI_fixed of the Fourier Transform. + + Parameters: + b_unc (array-like): List of uncertainties for 'b' coefficients. + order (int): Order of the Fourier fit. + + Returns: + float: Uncertainty in dI_fixed. + """ + # Calculate total uncertainty in dI_fixed return 2 * np.sqrt(sum(np.array(b_unc)[1:order + 1:2] ** 2)) def dI_at_phase(b, order, phase): + """ + Calculates the difference in flux at a specific phase for a given set of 'b' coefficients. + + Parameters: + b (array-like): List of 'b' coefficients. + order (int): Order of the Fourier fit. + phase (float): Phase value. + + Returns: + float: Difference in flux at the specified phase. + """ nlist = np.arange(order + 1) return 2 * sum(b[nlist] * np.sin(2 * np.pi * nlist * phase)) def dI_at_phase_error(b_unc, order, phase): + """ + Calculates the uncertainty in dI at a specific phase for a given set of 'b' coefficients. + + Parameters: + b_unc (array-like): List of uncertainties for 'b' coefficients. + order (int): Order of the Fourier fit. + phase (float): Phase value. + + Returns: + float: Uncertainty in dI at the specified phase. + """ nlist = np.arange(order + 1) return 2 * np.sqrt(sum((b_unc[nlist] * np.sin(2 * np.pi * nlist * phase)) ** 2)) def Delta_I_mean_obs(ob_phaselist, ob_fluxlist, ob_fluxerr, phase_range=0.05, weighted=False): """ Calculates the difference of flux at quadrature from observational fluxes - and the error the uncertainty of this measure. + and the uncertainty of this measure. + + Parameters: + ob_phaselist (array-like): List of observational phase values. + ob_fluxlist (array-like): List of observational flux values. + ob_fluxerr (array-like): List of observational flux errors. + phase_range (float): Range around quadrature phase to consider. + weighted (bool): Flag to indicate whether to use weighted averaging. - Averages the fluxes in a specified range from quadrature, and subtracts the two - values. Average can be weighted, although that is probably overkill and/or - undesireable. + Returns: + tuple: A tuple containing the mean difference in flux at quadrature and its uncertainty. """ Iplist = [] Iperrors = [] Islist = [] Iserrors = [] + + # Extract fluxes and errors within specified phase ranges from quadrature for n in range(len(ob_phaselist)): if 0.25 - phase_range < ob_phaselist[n] < 0.25 + phase_range: Iplist.append(ob_fluxlist[n]) @@ -1132,33 +1628,59 @@ def Delta_I_mean_obs(ob_phaselist, ob_fluxlist, ob_fluxerr, phase_range=0.05, we Islist.append(ob_fluxlist[n]) Iserrors.append(ob_fluxerr[n]) - if weighted == True: + if weighted: + # Calculate weighted averages if specified Ipmean = calc.error.weighted_average(Iplist, Iperrors) Ismean = calc.error.weighted_average(Islist, Iserrors) dI_mean_obs = Ipmean[0] - Ismean[0] dI_mean_error = np.sqrt(Ipmean[1] ** 2 + Ismean[1] ** 2) else: + # Calculate simple means otherwise dI_mean_obs = np.mean(Iplist) - np.mean(Islist) dI_mean_error = np.sqrt(calc.error.avg(Iperrors) ** 2 + calc.error.avg(Iserrors) ** 2) + return dI_mean_obs, dI_mean_error def Delta_I_mean_obs_noerror(ob_phaselist, ob_fluxlist, phase_range=0.05): """ - Same as Delta_I_mean_obs but just for simulations (errors not used). + Calculates the mean difference in flux at quadrature from observational fluxes + without considering observational errors. + + Parameters: + ob_phaselist (array-like): List of observational phase values. + ob_fluxlist (array-like): List of observational flux values. + phase_range (float): Range around quadrature phase to consider. + + Returns: + float: Mean difference in flux at quadrature from observational fluxes. """ Iplist = [] Islist = [] + + # Extract fluxes within specified phase ranges from quadrature for n in range(len(ob_phaselist)): if 0.25 - phase_range < ob_phaselist[n] < 0.25 + phase_range: Iplist.append(ob_fluxlist[n]) if 0.75 - phase_range < ob_phaselist[n] < 0.75 + phase_range: Islist.append(ob_fluxlist[n]) + + # Calculate mean difference in flux at quadrature dI_mean_obs = np.mean(Iplist) - np.mean(Islist) + return dI_mean_obs -# weighted averages -def M(errorlist): # sum of 1/errors +# Function to calculate the sum of reciprocals of squared errors +def M(errorlist): + """ + Calculates the sum of reciprocals of squared errors. + + Parameters: + errorlist (array-like): List of errors. + + Returns: + float: Sum of reciprocals of squared errors. + """ M0 = 0 M = M0 for error in errorlist: @@ -1166,43 +1688,88 @@ def M(errorlist): # sum of 1/errors return M -# +# Function to calculate the weight factor def wfactor(errorlist, n, M): + """ + Calculates the weight factor for a given error. + + Parameters: + errorlist (array-like): List of errors. + n (int): Index of the error in the list. + M (float): Sum of reciprocals of squared errors. + + Returns: + float: Weight factor for the error at index n. + """ return 1 / (errorlist[n] ** 2 * M) -# ====================================== -class Flower: # stuff from Flower 1996, Torres 2010 +# Class Flower containing functions for calculations related to Flower 1996 and Torres 2010 +class Flower: class T: - # c=[c0,c1,c2,c3,c4,c5,c6,c7] + # Coefficients for Teff calculation c = [3.97914510671409, -0.654992268598245, 1.74069004238509, -4.60881515405716, 6.79259977994447, -5.39690989132252, 2.19297037652249, -0.359495739295671] def Teff(BV, error): - # return 10**((Flower.T.c[0]*BV**0)+(Flower.T.c[1]*BV**1)+(Flower.T.c[2]*BV**2)+(Flower.T.c[3]*BV**3)+(Flower.T.c[4]*BV**4)+(Flower.T.c[5]*BV**5)+(Flower.T.c[6]*BV**6)+(Flower.T.c[7]*BV**7)) + """ + Calculates the effective temperature (Teff) using the B-V color index. + + Parameters: + BV (float): B-V color index. + error (float): Error in B-V color index. + + Returns: + tuple: A tuple containing the Teff value and its error. + """ + # Calculate Teff using polynomial approximation temp = calc.poly.power(Flower.T.c, BV, 10) + # Calculate error in Teff using error propagation err = calc.poly.t_eff_err(Flower.T.c, BV, error, temp) return temp, err -# ====================================== + +# Class containing functions for calculations related to Harmanec class Harmanec: class mass: + # Coefficients for M1 calculation c = [-121.6782, 88.057, -21.46965, 1.771141] def M1(BV): - # M1=10**((Harmanec.mass.c0*np.log10(Flower.T.Teff(BV))**0)+(Harmanec.mass.c1*np.log10(Flower.T.Teff(BV))**1)+(Harmanec.mass.c2*np.log10(Flower.T.Teff(BV))**2)+(Harmanec.mass.c3*np.log10(Flower.T.Teff(BV))**3)) + """ + Calculates the mass of a star using the B-V color index. + + Parameters: + BV (float): B-V color index. + + Returns: + float: Mass of the star. + """ + # Calculate M1 using polynomial approximation M1 = 10 ** (calc.poly.result(Harmanec.mass.c, np.log10(Flower.T.Teff(BV)))) return M1 -# ====================================== -class Red: # interstellar reddening +# Class containing constants and functions for interstellar reddening +class Red: + # Constants for color excess J_K = 0.17084 J_H = 0.10554 V_R = 0.58 / 3.1 def colorEx(filter1, filter2, Av): + """ + Calculates the color excess in a specified filter combination. + + Parameters: + filter1 (str): First filter. + filter2 (str): Second filter. + Av (float): V-band extinction. + + Returns: + float: Color excess. + """ excess = str(filter1) + '_' + str(filter2) if excess == 'J_K': return Av * Red.J_K @@ -1212,13 +1779,34 @@ def colorEx(filter1, filter2, Av): return Av * Red.V_R -# ====================================== + +# Class for plotting functions class plot: def amp(valuelist): - # test documentation + """ + Calculates the amplitude of a list of values. + + Parameters: + valuelist (list): List of values. + + Returns: + float: Amplitude of the values. + """ return max(valuelist) - min(valuelist) def aliasing2(phaselist, maglist, errorlist, alias=0.6): + """ + Filters the phase, magnitude, and error lists to keep only data within the specified alias range. + + Parameters: + phaselist (list): List of phase values. + maglist (list): List of magnitude values. + errorlist (list): List of error values. + alias (float): Alias range. + + Returns: + tuple: Filtered phase, magnitude, and error lists. + """ phase = list(np.array(phaselist) - 1) + list(phaselist) mag = list(maglist) + list(maglist) error = list(errorlist) + list(errorlist) @@ -1233,6 +1821,21 @@ def aliasing2(phaselist, maglist, errorlist, alias=0.6): return a_phase, a_mag, a_error def multiplot(figsize=(8, 8), dpi=256, height_ratios=[3, 1], hspace=0, sharex=True, sharey=False, fig=None): + """ + Creates a multiplot with specified parameters. + + Parameters: + figsize (tuple): Figure size. + dpi (int): Dots per inch. + height_ratios (list): List of height ratios for subplots. + hspace (float): Height space between subplots. + sharex (bool): Share x-axis among subplots. + sharey (bool): Share y-axis among subplots. + fig (object): Figure object. + + Returns: + tuple: Axes and figure objects. + """ if fig == None: fig = plt.figure(1, figsize=figsize, dpi=dpi) axs = fig.subplots(len(height_ratios), sharex=sharex, sharey=sharey, @@ -1243,6 +1846,36 @@ def sm_format(ax, X=None, x=None, Y=None, y=None, Xsize=7, xsize=3.5, tickwidth= xtop=True, xbottom=True, yright=True, yleft=True, numbersize=12, autoticks=True, topspine=True, bottomspine=True, rightspine=True, leftspine=True, xformatter=True, xdirection='in', ydirection='in', spines=True): + """ + Formats the plot axis. + + Parameters: + ax (object): Axis object. + X (float): Major tick spacing on x-axis. + x (float): Minor tick spacing on x-axis. + Y (float): Major tick spacing on y-axis. + y (float): Minor tick spacing on y-axis. + Xsize (float): Size of major ticks on x-axis. + xsize (float): Size of minor ticks on x-axis. + tickwidth (float): Tick width. + xtop (bool): Display ticks on top of x-axis. + xbottom (bool): Display ticks on bottom of x-axis. + yright (bool): Display ticks on right side of y-axis. + yleft (bool): Display ticks on left side of y-axis. + numbersize (int): Size of tick labels. + autoticks (bool): Use automatic tick spacing. + topspine (bool): Display top spine. + bottomspine (bool): Display bottom spine. + rightspine (bool): Display right spine. + leftspine (bool): Display left spine. + xformatter (bool): Use x-axis tick formatter. + xdirection (str): Tick direction on x-axis. + ydirection (str): Tick direction on y-axis. + spines (bool): Display axis spines. + + Returns: + str: 'DONE' when formatting is complete. + """ ax.tick_params(axis='x', which='major', length=Xsize, width=tickwidth, direction=xdirection, top=xtop, bottom=xbottom, labelsize=numbersize) ax.tick_params(axis='y', which='major', length=Xsize, width=tickwidth, direction=ydirection, right=yright, @@ -1282,30 +1915,53 @@ def sm_format(ax, X=None, x=None, Y=None, y=None, Xsize=7, xsize=3.5, tickwidth= else: ax.yaxis.set_minor_locator(MultipleLocator(y)) if xformatter == True: - # plt.gca().xaxis.set_major_formatter(FormatStrFormatter('$%g$')) ax.xaxis.set_major_formatter(FormatStrFormatter('$%g$')) - # for label in ax.get_xticklabels(): - # label.set_fontproperties('DejaVu Sans') - # for label in ax.get_yticklabels(): - # label.set_fontproperties('DejaVu Sans') return 'DONE' + # ====================================== class Roche: def Kopal_cyl(rho, phi, z, q): + """ + Calculates the Kopal potential for a cylindrical coordinate system. + + Parameters: + rho (float): Radial coordinate. + phi (float): Azimuthal coordinate. + z (float): Vertical coordinate. + q (float): Mass ratio. + + Returns: + float: Value of the Kopal potential. + """ return 1 / np.sqrt(rho ** 2 + z ** 2) + q / ( np.sqrt(1 + rho ** 2 + z ** 2 - 2 * rho * np.cos(phi))) - q * rho * np.cos(phi) + 0.5 * (1 + q) * rho ** 2 def gen_Kopal_cyl(rho, phi, z, q, xcm=None, ycm=0, zcm=0, potcap=None): + """ + Generates the Kopal potential for a cylindrical coordinate system. + + Parameters: + rho (float): Radial coordinate. + phi (float): Azimuthal coordinate. + z (float): Vertical coordinate. + q (float): Mass ratio. + xcm (float, optional): x-coordinate of the center of mass. + ycm (float, optional): y-coordinate of the center of mass. + zcm (float, optional): z-coordinate of the center of mass. + potcap (float, optional): Potential cap. + + Returns: + float: Value of the generated Kopal potential. + """ if xcm == None: xcm = q / (1 + q) A1 = -q / (1 + q) A2 = 1 / (1 + q) B1 = xcm ** 2 + ycm ** 2 + zcm ** 2 + 2 * xcm * A1 + A1 ** 2 - # print(B1) B2 = xcm ** 2 + ycm ** 2 + zcm ** 2 + 2 * xcm * A2 + A2 ** 2 X = rho * np.cos(phi) Y = rho * np.sin(phi) @@ -1316,6 +1972,16 @@ def gen_Kopal_cyl(rho, phi, z, q, return potent def Lagrange_123(q, e=1e-8): + """ + Calculates the Lagrange points L1, L2, and L3 for a given mass ratio. + + Parameters: + q (float): Mass ratio. + e (float, optional): Tolerance for the Newton-Raphson method. + + Returns: + tuple: Values of Lagrange points L1, L2, and L3. + """ L1 = lambda x: q / x ** 2 - x * (1 + q) - 1 / (1 - x) ** 2 + 1 L2 = lambda x: q / x ** 2 - x * (1 + q) + 1 / (1 + x) ** 2 - 1 L3 = lambda x: 1 / (q * x ** 2) - x * (1 + 1 / q) + 1 / (1 + x) ** 2 - 1 @@ -1325,6 +1991,20 @@ def Lagrange_123(q, e=1e-8): return xL1, xL2, xL3 def Kopal_zero(rho, phi, z, q, Kopal, body='M1'): + """ + Calculates the Kopal potential for zero equilibrium. + + Parameters: + rho (float): Radial coordinate. + phi (float): Azimuthal coordinate. + z (float): Vertical coordinate. + q (float): Mass ratio. + Kopal (float): Kopal potential. + body (str, optional): Body type ('M1', 'M2', 'dM1', 'dM2'). + + Returns: + float: Value of the Kopal potential for zero equilibrium. + """ r = rho if body == 'M1': return 1 / np.sqrt(r ** 2 + z ** 2) + q / np.sqrt( @@ -1339,17 +2019,41 @@ def Kopal_zero(rho, phi, z, q, Kopal, body='M1'): return -r * q / (r ** 2 + z ** 2) ** (3 / 2) - (r + np.cos(phi)) / ( 1 + r ** 2 + z ** 2 + 2 * r * np.cos(phi)) ** (3 / 2) + np.cos(phi) + (1 + q) * r else: - return print('Invalid body, choose M1 or M2.') def gen_Kopal_zero(rho, phi, z, q, Kopal, xcm=None, ycm=0, zcm=0): + """ + Generates the Kopal potential for zero equilibrium. + + Parameters: + rho (float): Radial coordinate. + phi (float): Azimuthal coordinate. + z (float): Vertical coordinate. + q (float): Mass ratio. + Kopal (float): Kopal potential. + xcm (float, optional): x-coordinate of the center of mass. + ycm (float, optional): y-coordinate of the center of mass. + zcm (float, optional): z-coordinate of the center of mass. + + Returns: + float: Value of the generated Kopal potential for zero equilibrium. + """ return Roche.gen_Kopal_cyl(rho, phi, z, q, xcm=xcm, ycm=ycm, zcm=zcm) - Kopal class Pecaut: # V-R effective temperature fit from Pecaut and Mamajek 2013 https://arxiv.org/pdf/1307.2657.pdf class T: - # c=[c0,c1,c2,c3] + """ + Class T defines the effective temperature (Teff) as a function of color index (V-R). + + Attributes: + c1 (list): Coefficients for Teff calculation when -0.115 < V-R <= 0.019 (B1V to A1V). + c2 (list): Coefficients for Teff calculation when 0.019 < V-R < 1.079 (A1V to M3V). + c1_err (list): Coefficients errors for c1. + c2_err (list): Coefficients errors for c2. + """ + c1 = [3.98007, -1.2742, 32.41373, 98.06855] # -0.115 < V-R < 0.019 c2 = [3.9764, -0.80319, 0.64832, -0.2651] # 0.019 < V-R < 1.079 @@ -1357,13 +2061,24 @@ class T: c2_err = [0.00179, 0.01409, 0.03136, 0.0197] def Teff(VR, error): - if -0.115 < VR <= 0.019: # B1V to A1V + """ + Calculates the effective temperature (Teff) given the color index (V-R). + + Parameters: + VR (float): Color index (V-R). + error (float): Error in color index (V-R). + + Returns: + tuple: A tuple containing the calculated Teff value and its error. + """ + if -0.115 < VR <= 0.019: # B1V to A1V temp = calc.poly.power(Pecaut.T.c1, VR, 10) err = calc.poly.t_eff_err(Pecaut.T.c1, VR, error, temp, coeferror=Pecaut.T.c1_err) return temp, err - elif 0.019 < VR < 1.079: # A1V to M3V + elif 0.019 < VR < 1.079: # A1V to M3V temp = calc.poly.power(Pecaut.T.c2, VR, 10) err = calc.poly.t_eff_err(Pecaut.T.c2, VR, error, temp, coeferror=Pecaut.T.c2_err) return temp, err else: return 0, 0 +