def _raw_phys_to_eng(self, physics_value): """Convert between physics and engineering units. Args: physics_value(float): The engineering value to be converted to the engineering value. Returns: float: The converted engineering value from the given physics value. Raises: ValueError: An error occured when there exist no or more than one roots. """ y = [val - physics_value for val in self.y] new_pp = PchipInterpolator(self.x, y) roots = new_pp.roots() solution_within_bounds = False for root in roots: if root <= self.x[-1] and root >= self.x[0]: if not solution_within_bounds: solution_within_bounds = True correct_root = root else: raise UniqueSolutionException("The function is not invertible.") if solution_within_bounds: return correct_root else: raise UniqueSolutionException("The function does not have a solution within the bounds.")
elif type(T1_spectrum["albedo"]) != bool: T1_albedo = T1_spectrum["albedo"] T1_spectrum = calc.transform(T1_spectrum) # Spectrum interpolation try: interp = Akima1DInterpolator(T1_spectrum["nm"], T1_spectrum["br"]) except ValueError: print("\n" + tr.error1[lang][0]) print(tr.error1[lang][1].format(values["T1_list"][0], len(T1_spectrum["nm"]), len(T1_spectrum["br"])) + "\n") break if T1_spectrum["nm"][0] > T1_nm[0] or T1_spectrum["nm"][-1] < T1_nm[-1]: if values["T1_interp0"]: T1_curve = calc.DefaultExtrapolator(T1_spectrum["nm"], T1_spectrum["br"], T1_nm, T1_albedo) elif values["T1_interp1"]: extrap = PchipInterpolator(T1_spectrum["nm"], T1_spectrum["br"], extrapolate=True) T1_curve = extrap(T1_nm) / extrap(550) * T1_albedo if T1_albedo else extrap(T1_nm) elif values["T1_interp2"]: extrap = CubicSpline(T1_spectrum["nm"], T1_spectrum["br"], extrapolate=True) T1_curve = extrap(T1_nm) / extrap(550) * T1_albedo if T1_albedo else extrap(T1_nm) else: T1_curve = interp(T1_nm) / interp(550) * T1_albedo if T1_albedo else interp(T1_nm) T1_curve = np.clip(T1_curve, 0, None) # Color calculation T1_rgb = calc.to_rgb( T1_curve, mode=T1_mode, albedo = T1_spectrum["albedo"] or T1_albedo, exp_bit=int(values["T1_bit_num"]), gamma=values["T1_gamma"], rnd=int(values["T1_rnd_num"]),
def __call__(self, x): return PchipInterpolator.__call__(self, x, 1)
def fit_bmodes_linear(rho, rhoz, z, zmin, modes,\ Nz=100, density_func='single_tanh', full_output=True): """ Compute the linear modal amplitude to the mode numbers in the list Inputs: --- rho - matrix[nz, nt], density data rhoz - vector[nz], background density profile from bottom to top (desceding) z - vector[nz], depth from bottom to top, negative values (ascending) modes - list[nmodes], mode numbers in python index i.e. 0=1 Returns --- A_t - matrix[nmodes, nt], modal amplitude phi - matrix[nmodes, nz], modal structure functions rhofit - matrix[nz, nt], best fit density profile """ nz, nt = rho.shape nmodes = len(modes) # Compute buoyancy from density and backgroud density rhopr = rho.T - rhoz[np.newaxis, ...] b = GRAV * rhopr / RHO0 # Compute the modal structures L = np.zeros((nz, nmodes)) phi_n = [] # Calculate dz Z = np.linspace(zmin, 0, Nz) dz = np.mean(np.diff(Z)) for ii, mode in enumerate(modes): # Use the mode class to create the profile iw = IWaveModes(rhoz, z,\ density_class=FitDensity, density_func=density_func) phi, c1, he, znew = iw(zmin, dz, mode) if full_output: if ii == 0: Nz = iw.Z.size Lout = np.zeros((Nz, nmodes)) Lout[:, ii] = phi * iw.N2 phi_n.append(phi) ## Interpolate the modal shape and N2 onto the measured depth locations F = PchipInterpolator(iw.Z[::-1], iw.phi[::-1]) my_phi = F(z) F = PchipInterpolator(iw.Z[::-1], iw.N2[::-1]) my_N2 = F(z) L[:, ii] = my_phi * my_N2 #phi_n.append(my_phi) ## Fit Ax=b A_t, _, _, _ = la.lstsq(L, b.T) # Reconstruct the density field bfit_n = L[:, np.newaxis, :] * A_t.T[np.newaxis, ...] bfit = bfit_n.sum(axis=-1) # sum the modes rhoprfit = bfit.T * RHO0 / GRAV rhofit = rhoprfit + rhoz[np.newaxis, :] if full_output: bfit_n = Lout[:, np.newaxis, :] * A_t.T[np.newaxis, ...] bfit = bfit_n.sum(axis=-1) # sum the modes rhoprfit = bfit.T * RHO0 / GRAV rhofit_full = rhoprfit + iw.rhoZ[np.newaxis, :] return A_t, np.array(phi_n).T, rhofit, rhofit_full, iw else: return A_t, np.array(phi_n).T, rhofit
def fit_bmodes_nonlinear(rho, rhoz, z, mode, dz=2.5, density_func='single_tanh'): """ Compute the nonlinear modal amplitude to the mode numbers in the list Inputs: --- rho - matrix[nz, nt], density data rhoz - vector[nz], background density profile from bottom to top (desceding) z - vector[nz], depth from bottom to top, negative values (ascending) modes - list[nmodes], mode numbers in python index i.e. 0=1 Returns --- A_t - matrix[nmodes, nt], modal amplitude rhofit - matrix[nz, nt], best fit density profile iw - internal wave mode class """ nz, nt = rho.shape nmodes = len(modes) # Compute buoyancy from density and backgroud density rhopr = rho.T - rhoz[np.newaxis, ...] b = GRAV * rhopr / RHO0 # Use the mode class to create the profile iw = IWaveModes(rhoz, z,\ density_class=FitDensity, density_func=density_func) phi, c1, he, znew = iw(z.min(), dz, mode) r10, _, _, _ = iw.calc_nonlin_params() _, _, _, T10, _, _, _ = iw.calc_nonlin_structure() # Interpolate the structure etc F = PchipInterpolator(iw.Z[::-1], iw.phi[::-1]) my_phi = F(z) F = PchipInterpolator(iw.Z[::-1], iw.N2[::-1]) my_N2 = F(z) # Interpolate the higher order structure function F = PchipInterpolator(iw.Z[::-1], T10[::-1]) my_T10 = F(Z) # Calculate the gradient of N2 and then interpolate it... dN2_dz = np.gradient(iw.N2, -iw.dz) F = PchipInterpolator(iw.Z[::-1], dN2_dz[::-1]) my_dN2 = F(Z) ## Fit alpha as well #alpha = -0.008*0 #my_T10 = my_T10s + alpha*my_phi def minfun(x0): btest = calc_buoyancy_h99(x0, my_phi, iw.c1, my_N2,\ my_dN2, r10, my_T10, nonlinear=False) err = np.sum((b - btest)**2., axis=1) #print err.max(), alpha return err # Use the Newton-Krylov solver that works on large nonlinear problems A_nl = newton_krylov(minfun, np.zeros((nt,)), f_tol=3.1e-5,\ method='gmres', rdiff=1e-6, iter=100) # Reconstruct the nonlinear density field bfit_nl = calc_buoyancy_h99(A_nl, my_phi, iw.c1, my_N2,\ my_dN2, r10, my_T10, nonlinear=False) rhoprfit = bfit_nl * RHO0 / GRAV rhofitnl = rhoprfit + rhobar[np.newaxis, :] return A_nl, rhofitnl, iw
def fit(self, x, y, m=None, includes_tail=False): """Fit the cubic spline to the data. Parameters ---------- x: ndarray The bin edges y: ndarray The values for each bin m: float The mean of the distribution includes_tail: bool If True then it is assumed that the last value in x is the upper bound of the distribution, otherwise the upper bound is estimated Returns ------- self : object Fitted estimator. """ if includes_tail and len(x) != len(y): raise ValueError( "Length of x and y must match when tail is included" ) if not includes_tail and len(x) != len(y) - 1: raise ValueError( "Length of x must be N-1 when tail is not included" ) if y[0] != 0: raise ValueError("y must begin with 0") if m is None: # Adhoc mean estimate if none supplied if includes_tail: bin_edges = x else: bin_edges = np.concatenate([x[:-1] / 2, [x[-1], x[-1] * 2]]) m = np.average(bin_edges, weights=y / np.sum(y),) warnings.warn("No mean provided, results may be innacurate.") x = x.astype(float) y = y.astype(float) self.min_x_ = x[0] y_ecdf = np.cumsum(y) y_ecdf_normed = y_ecdf / np.max(y_ecdf) if includes_tail is False: # Temporarily set the tail value tail_0 = x[-1] * 2 x_wtail = np.concatenate([x, [tail_0]]) # Search for a tail self.tail_ = minimize( evaluate_tail, tail_0, args=(x_wtail.copy(), y_ecdf_normed, m), bounds=[(180000, None)], method="Powell", options=dict(maxiter=16), ).x[0] x_wtail[-1] = self.tail_ else: if x[-2] >= x[-1]: raise ValueError( "Tail value must be greater than the last bin edge" ) self.tail_ = x[-1] x_wtail = x # Estimate the CDF by fitting a spline self.cdf_cs_ = PchipInterpolator(x_wtail, y_ecdf_normed) self.mean_est_ = estimate_mean(x_wtail[0], x_wtail[-1], self.cdf_cs_) # Approximate inverse CDF by sampling the CDF x_cs = cumdensityspace( self.min_x_, self.tail_, self.cdf_cs_, interp_num=1000 ) y_cs = self.cdf_cs_(x_cs) self.inv_cdf_cs_ = PchipInterpolator(y_cs, x_cs) return self
def plot_noise(fisher_dir, out_dir, prim_template='local'): ''' Plot sigma as function of B noise for several T/E noise curves and two choices of A_lens. Arguments --------- fisher_dir : str Directory containing fisher pkl files. out_dir : str Directory for output figures. ''' r = 0.001 lmax = 4900 lmin_b = 50 pol_opts = dict(no_ee=False, no_tt=False) lmin_e = 2 # noise_i_arr = [0.3, 1, 3, 10] noise_i_arr = [10, 1] noise_b_arr = np.logspace(np.log10(0.3), np.log10(50), 10) A_lens_arr = [0.1, 1] fnl_arr = np.ones((len(A_lens_arr), len(noise_i_arr), len(noise_b_arr))) fnl_arr *= np.nan # Load pickle files. for aidx, A_lens in enumerate(A_lens_arr): for ni_idx, n_i in enumerate(noise_i_arr): for nb_idx, n_b in enumerate(noise_b_arr): no_ee = pol_opts['no_ee'] no_tt = pol_opts['no_tt'] noise_amp_temp = n_i noise_amp_e = n_i * np.sqrt(2) noise_amp_b = n_b tag = ('{}_nt{:.4f}_ne{:.4f}_nb{:.4f}_lb{:d}_le{:d}_nee{:d}' '_ntt{:d}_a{:.4f}_r{:.4f}_l{:d}'.format(prim_template, noise_amp_temp, noise_amp_e, noise_amp_b, lmin_b, lmin_e, int(no_ee), int(no_tt), A_lens, r, lmax)) # Load fisher. try: fisher_file = opj(fisher_dir, 'f_{}.pkl'.format(tag)) fisher_opts = np.load(fisher_file) except IOError: print('{} not found'.format(fisher_file)) continue fnl_arr[aidx, ni_idx, nb_idx] = fisher_opts['sigma_fnl'] # pol, lmax print fnl_arr.shape # Interpolate. i_fact = 20 noise_b_arr_i = np.logspace(np.log10(0.3), np.log10(50), i_fact * 10) fnl_arr_i = np.ones((len(A_lens_arr), len(noise_i_arr), i_fact * len(noise_b_arr))) for i in xrange(fnl_arr.shape[0]): for j in xrange(fnl_arr.shape[1]): cs = PchipInterpolator(noise_b_arr, fnl_arr[i,j,:]) fnl_arr_i[i,j,:] = cs(noise_b_arr_i) # fnl_arr = fnl_arr_i # noise_b_arr = noise_b_arr_i # Plot. font = {'size' : 12} matplotlib.rc('font', **font) fig, axs = plt.subplots(ncols=2, nrows=1, figsize=(4, 2), sharey=True, sharex=False) plot_opts = dict(color='black') lstyles = ['-', ':', '--', '-.'] for ni_idx, n_i in enumerate(noise_i_arr): label = r"$"+str(n_i)+"\ \mu \mathrm{K}$-$'$" # if ni_idx < 2: # label_a = label # label_b = None # else: # label_a = None # label_b = label axs[0].plot(noise_b_arr, fnl_arr[0,ni_idx,:], ls=lstyles[ni_idx], label=None, **plot_opts) axs[1].plot(noise_b_arr, fnl_arr[1,ni_idx,:], ls=lstyles[ni_idx], label=label, **plot_opts) fig.text(0.001, 0.5, r'$\sigma(\hat{f}_{\mathrm{NL}}^{\, \mathrm{tot}})$', ha='center', va='center', rotation='vertical') fig.text(0.5, -0.05, r'$B$-mode noise [$\mu \mathrm{K}$-$\mathrm{arcmin}$]', ha='center', va='center', rotation='horizontal') fig.suptitle(r'$\ell_{\mathrm{min}}^B='+str(lmin_b)+'$, $r='+str(r)+'$', y=1.03) for i, ax in enumerate(axs.ravel()): ax.set_yscale('log') ax.set_xscale('log') ax.tick_params(axis='both', direction='in', top=True, right=True, which='major') ax.tick_params(axis='both', direction='in', top=True, right=True, which='minor', labelsize=10) ax.set_xlim(0.2, 70) # ax.set_ylim(4e-3, 7e0) ax.text(0.1, 0.85, r"$A^{BB}_{\mathrm{lens}} = "+str(A_lens_arr[i])+"$", transform=ax.transAxes, horizontalalignment='left') # axs[1].xaxis.set_ticklabels(['','','','','','','','',r'$5\times10^3$'], # minor=True) # axs[1].set_xticks([500, 600, 700, 800, 900, 2000, 3000, 4000, 5000], minor=True) # axs[0].xaxis.set_ticklabels(['','','','','','','','',r'$5\times10^3$'], # minor=True) # axs[0].set_xticks([500, 600, 700, 800, 900, 2000, 3000, 4000, 5000], minor=True) # axs[0].legend(ncol=1, frameon=False, loc=(0.45, 0.001), # markerscale=.1, handletextpad=0.3, handlelength=1.3, # prop={'size': 12}) axs[1].legend(ncol=1, frameon=False, loc=(0.42, 0.0001), markerscale=.1, handletextpad=0.3, handlelength=1.3, prop={'size': 12}) fig.subplots_adjust(hspace=0., wspace=0.) fig.savefig(opj(out_dir, 'noise.pdf'), dpi=300, bbox_inches='tight')
def GetDispersionPhaseCurves(self, wavelengths, scans, voltages, pixels_edges, calibration, pixel2lambda_func, pulse_shaper_pixel_num): """ Surface calibration: Find dispersion and phase curves based on a result of the method `self.FitSpectralScans` `calibration` is the return of `self.FitSpectralScans` """ import operator # Find the calibration function that was best fitted best_calibation_voltage, best_calib_phase, _ = min( calibration, key=operator.itemgetter(2)) # Form a function representing calibration curve (best fitted) # Normalizing calibration curve best_calib_phase -= best_calib_phase.min() best_calib_phase /= best_calib_phase.max() best_calibration_curve = PchipInterpolator(best_calibation_voltage, best_calib_phase) # Selecting the voltage range V_min = max(best_calibation_voltage.min(), voltages.min()) V_max = min(best_calibation_voltage.max(), voltages.max()) V_indx = np.nonzero((V_min <= voltages) & (voltages <= V_max)) # Select scanning range that corresponds to a valid region of voltages and wavelength scans = scans[V_indx[0], pixels_edges[0]:pixels_edges[-1]] # Wavelength position of pixels in a new sliced scan wavelengths_cut = wavelengths[pixels_edges[0]:pixels_edges[-1]] # Central wavelength of each pixels logical_pixel_lambda = 0.5 * (wavelengths[pixels_edges[1:]] + wavelengths[pixels_edges[:-1]]) # Construct the initial guess for the dispersion curve # use the cubic polynomial interpolation # normalize it to the best fitted calibration curve best_min = best_calibration_curve(V_min) best_max = best_calibration_curve(V_max) # values of the calibration curves calibration_values = best_calibration_curve( voltages[V_indx])[:, np.newaxis] def TransmissionC(calibration_values, params): """ Transmission coefficient for fitting """ offset = params[:len(params) / 2] multiplier = params[len(params) / 2:] phase = calibration_values * np.polyval(multiplier, wavelengths_cut) phase += np.polyval(offset, wavelengths_cut) return np.cos(phase)**2 def Fit_TransmissionC(calibration_values, *params): return np.ravel(TransmissionC(calibration_values, params)) # Initial guess for fitting parameters c_min, c_max = zip(*[ pchip_interpolate(c[0], c[1], [V_min, V_max]) for c in calibration ]) c_min = np.array(c_min) c_max = np.array(c_max) # Use different power fits power_fits = [] for power in [1, 3, 5, 7]: offset = np.polyfit(logical_pixel_lambda, (best_max * c_min - best_min * c_max) / (best_max - best_min), power) multiplier = np.polyfit(logical_pixel_lambda, (c_max - c_min) / (best_max - best_min), power) p0 = np.append(offset, multiplier) try: popt, _ = curve_fit(Fit_TransmissionC, calibration_values, np.ravel(scans), p0=p0) except RuntimeError: popt = p0 # Calculate the Transmission coefficients for plotting TC_fitted = TransmissionC(calibration_values, popt) # Calculate fitting error error = np.sum((TC_fitted - scans)**2) power_fits.append((error, popt, TC_fitted)) # Select the best power fit _, popt, TC_fitted = min(power_fits) # Extracted the fitted parameters offset = popt[:len(popt) / 2] multiplier = popt[len(popt) / 2:] # Get wavelength for each physical pixel in the pulse shaper physical_pixel_lambda = pixel2lambda_func( np.arange(pulse_shaper_pixel_num)) # Calculate offset and multiplier for each physical pixel offset = np.polyval(offset, physical_pixel_lambda) multiplier = np.polyval(multiplier, physical_pixel_lambda) # Return results return TC_fitted, scans, { "offset": offset, "multiplier": multiplier, "calibration_curve_voltage": best_calibation_voltage, "calibration_curve_phase": best_calib_phase }
def extract_1d_lut(inlutfile, lutsize, outlutfile=None, smooth=False, smooth_size=17, display=False): """Extract the tone mapping curve of a 3D LUT Args: inlutfile (str): an input 3D LUT lutsize (int): out 1D LUT bit precision. Ex : 16 (bits) Kwargs: outlutfile (str): the output 1D lut. If not define, LUT is written in the input LUT directory and post-fixed with "_export" smooth (bool): smooth the resulting curve with a bicubic monotonic interpolation. See also smooth_size. smooth_size (int): only used when smooth is true. Specify how many points are sampled using OpenColorIO processor. The result curve is then smoothed and resample to fit input lutsize. So the smaller this value is, the smoother the curve will be. """ if not outlutfile: outlutfile = get_default_out_path(inlutfile, ".csp") # create OCIO processor processor = create_ocio_processor(inlutfile) if not is_3d_lut(processor, inlutfile): raise Ext1DLutException("Input lut must be a 3D LUT !") # init vars if smooth: # subsample OCIO processed curve count = smooth_size else: count = pow(2, lutsize) max_value = count - 1.0 red_values = [] green_values = [] blue_values = [] for code_value in range(0, count): norm_value = code_value / max_value res = processor.applyRGB([norm_value, norm_value, norm_value]) red_values.append(res[0]) green_values.append(res[1]) blue_values.append(res[2]) if smooth: # get full range xnew = numpy.arange(0, max_value, float(count - 1) / (pow(2, lutsize))) # get a monotonic cubic function from subsampled curve red_cubic_monotonic_func = PchipInterpolator(numpy.arange(0, count), red_values) green_cubic_monotonic_func = PchipInterpolator(numpy.arange(0, count), green_values) blue_cubic_monotonic_func = PchipInterpolator(numpy.arange(0, count), blue_values) # sample on the full range reds = red_cubic_monotonic_func(xnew) greens = green_cubic_monotonic_func(xnew) blues = blue_cubic_monotonic_func(xnew) else: reds = red_values greens = green_values blues = blue_values write_2d_csp_lut(outlutfile, reds, greens, blues) if display: try: # init plot from matplotlib.pyplot import (title, plot, grid, figure, show) except: raise Ext1DLutException("Install matplotlib to use display option") fig = figure() fig.canvas.set_window_title('Plot That 1D LUT') title("Compare") grid(True) # plot curves plot(reds, 'r-', label='numpy', linewidth=1) plot(greens, 'g-', label='numpy', linewidth=1) plot(blues, 'b-', label='numpy', linewidth=1) show()
def air_density(self, h): beta = 1 / 8500.0 # scale factor [1/m] rho0 = 1.225 # kg/m3 return rho0 * np.exp(-beta * h) rocket = Rocket() ###################################################################################################### ############################################# L O A D ############################################### #Load from reference files and interpolate paths. Rref = np.load("R.npy") Vref = np.load("V.npy") mref = np.load("m.npy") tref = np.load("time.npy") tfin = tref[-1] Rfun = PchipInterpolator(tref, Rref) Vfun = PchipInterpolator(tref, Vref) mfun = PchipInterpolator(tref, mref) ############################################################################################################## #################################### R O C K E T S O L V E R ############################################### ############################################################################################################## def selfRocketSolve(x_init, pop): #initialise variables #Grab the pop PID values Kp_r = pop[0] Kp_v = pop[1] Kp_m = pop[2] Ki_r = pop[3] Ki_v = pop[4]
else: r = 0 return r temp = round(0.00, 2) tempo = [] for times in range(int(20/dt)): tempo.append(temp) temp = round(temp + dt, 2) #tempo = np.linspace(0, 20, 20/dt) rise_time = 0.1 set_point=[] for items in tempo: set_point.append(setpoint(items)) set_interp = PchipInterpolator(tempo, set_point) rise_time = 0.1 r_max = max(set_point) r_min = min(set_point) ar = 2 * r_max / (rise_time ** 2) vr = ar * rise_time yr = 0.9 * r_max force_constraint = m * ar + c * vr + k * yr print("Force constraint is (N): ", force_constraint) ################################################# ----- Main GA call stack ----- ################################################ iteration = 0 while iteration < iteration_max: if iteration == 0:
def compute(self, inputs, outputs, discrete_inputs, discrete_outputs): ############################## def region_stacking( i, idx, start_nd_arc, end_nd_arc, layer_name, layer_thickness, fiber_orientation, layer_mat, material_dict, materials, region_loc, ): # Recieve start and end of composite sections chordwise, find which composites layers are in each # chordwise regions, generate the precomp composite class instance # error handling to makes sure there were no numeric errors causing values very close too, but not exactly, 0 or 1 start_nd_arc = [ 0.0 if start_nd_arci != 0.0 and np.isclose(start_nd_arci, 0.0) else start_nd_arci for start_nd_arci in start_nd_arc ] end_nd_arc = [ 0.0 if end_nd_arci != 0.0 and np.isclose(end_nd_arci, 0.0) else end_nd_arci for end_nd_arci in end_nd_arc ] start_nd_arc = [ 1.0 if start_nd_arci != 1.0 and np.isclose(start_nd_arci, 1.0) else start_nd_arci for start_nd_arci in start_nd_arc ] end_nd_arc = [ 1.0 if end_nd_arci != 1.0 and np.isclose(end_nd_arci, 1.0) else end_nd_arci for end_nd_arci in end_nd_arc ] # region end points dp = sorted(list(set(start_nd_arc + end_nd_arc))) # initialize n_plies = [] thk = [] theta = [] mat_idx = [] # loop through division points, find what layers make up the stack between those bounds for i_reg, (dp0, dp1) in enumerate(zip(dp[0:-1], dp[1:])): n_pliesi = [] thki = [] thetai = [] mati = [] for i_sec, start_nd_arci, end_nd_arci in zip(idx, start_nd_arc, end_nd_arc): name = layer_name[i_sec] if start_nd_arci <= dp0 and end_nd_arci >= dp1: if name in region_loc.keys(): if region_loc[name][i] == None: region_loc[name][i] = [i_reg] else: region_loc[name][i].append(i_reg) n_pliesi.append(1.0) thki.append(layer_thickness[i_sec]) if fiber_orientation[i_sec] == None: thetai.append(0.0) else: thetai.append(fiber_orientation[i_sec]) mati.append(material_dict[layer_mat[i_sec]]) n_plies.append(np.array(n_pliesi)) thk.append(np.array(thki)) theta.append(np.array(thetai)) mat_idx.append(np.array(mati)) # print('----------------------') # print('dp', dp) # print('n_plies', n_plies) # print('thk', thk) # print('theta', theta) # print('mat_idx', mat_idx) # print('materials', materials) sec = CompositeSection(dp, n_plies, thk, theta, mat_idx, materials) return sec, region_loc ############################## def web_stacking( i, web_idx, web_start_nd_arc, web_end_nd_arc, layer_thickness, fiber_orientation, layer_mat, material_dict, materials, flatback, upperCSi, ): dp = [] n_plies = [] thk = [] theta = [] mat_idx = [] if len(web_idx) > 0: dp = np.mean((np.abs(web_start_nd_arc), np.abs(web_start_nd_arc)), axis=0).tolist() dp_all = [ [-1.0 * start_nd_arci, -1.0 * end_nd_arci] for start_nd_arci, end_nd_arci in zip(web_start_nd_arc, web_end_nd_arc) ] web_dp, web_ids = np.unique(dp_all, axis=0, return_inverse=True) for webi in np.unique(web_ids): # store variable values (thickness, orientation, material) for layers that make up each web, based on the mapping array web_ids n_pliesi = [1.0 for i_reg, web_idi in zip(web_idx, web_ids) if web_idi == webi] thki = [layer_thickness[i_reg] for i_reg, web_idi in zip(web_idx, web_ids) if web_idi == webi] thetai = [fiber_orientation[i_reg] for i_reg, web_idi in zip(web_idx, web_ids) if web_idi == webi] thetai = [0.0 if theta_ij == None else theta_ij for theta_ij in thetai] mati = [ material_dict[layer_mat[i_reg]] for i_reg, web_idi in zip(web_idx, web_ids) if web_idi == webi ] n_plies.append(np.array(n_pliesi)) thk.append(np.array(thki)) theta.append(np.array(thetai)) mat_idx.append(np.array(mati)) if flatback: dp.append(1.0) n_plies.append(upperCSi.n_plies[-1]) thk.append(upperCSi.t[-1]) theta.append(upperCSi.theta[-1]) mat_idx.append(upperCSi.mat_idx[-1]) dp_out = sorted(list(set(dp))) sec = CompositeSection(dp_out, n_plies, thk, theta, mat_idx, materials) return sec ############################## layer_name = self.options["modeling_options"]["WISDEM"]["RotorSE"]["layer_name"] layer_mat = self.options["modeling_options"]["WISDEM"]["RotorSE"]["layer_mat"] upperCS = [None] * self.n_span lowerCS = [None] * self.n_span websCS = [None] * self.n_span profile = [None] * self.n_span # Check that the layer to be optimized actually exist te_ss_var_ok = False te_ps_var_ok = False spar_cap_ss_var_ok = False spar_cap_ps_var_ok = False for i_layer in range(self.n_layers): if layer_name[i_layer] == self.te_ss_var: te_ss_var_ok = True if layer_name[i_layer] == self.te_ps_var: te_ps_var_ok = True if layer_name[i_layer] == self.spar_cap_ss_var: spar_cap_ss_var_ok = True if layer_name[i_layer] == self.spar_cap_ps_var: spar_cap_ps_var_ok = True DV_options = self.options["opt_options"]["design_variables"]["blade"]["structure"] if te_ss_var_ok == False and DV_options["te_ss"]["flag"]: raise Exception( "The layer at the trailing edge suction side is set to be optimized, but does not exist in the input yaml. Please check." ) if te_ps_var_ok == False and DV_options["te_ps"]["flag"]: raise Exception( "The layer at the trailing edge pressure side is set to be optimized, but does not exist in the input yaml. Please check." ) if spar_cap_ss_var_ok == False and DV_options["spar_cap_ss"]["flag"]: raise Exception( "The layer at the spar cap suction side is set to be optimized, but does not exist in the input yaml. Please check." ) if spar_cap_ps_var_ok == False and DV_options["spar_cap_ps"]["flag"]: raise Exception( "The layer at the spar cap pressure side is set to be optimized, but does not exist in the input yaml. Please check." ) region_loc_vars = [self.te_ss_var, self.te_ps_var, self.spar_cap_ss_var, self.spar_cap_ps_var] region_loc_ss = {} # track precomp regions for user selected composite layers region_loc_ps = {} for var in region_loc_vars: region_loc_ss[var] = [None] * self.n_span region_loc_ps[var] = [None] * self.n_span ## Materials material_dict = {} materials = [] for i_mat in range(self.n_mat): materials.append( Orthotropic2DMaterial( inputs["E"][i_mat, 0], inputs["E"][i_mat, 1], inputs["G"][i_mat, 0], inputs["nu"][i_mat, 0], inputs["rho"][i_mat], discrete_inputs["mat_name"][i_mat], ) ) material_dict[discrete_inputs["mat_name"][i_mat]] = i_mat ## Spanwise for i in range(self.n_span): # time0 = time.time() ## Profiles # rotate profile_i = inputs["coord_xy_interp"][i, :, :] profile_i_rot = np.column_stack( rotate(inputs["pitch_axis"][i], 0.0, profile_i[:, 0], profile_i[:, 1], np.radians(inputs["theta"][i])) ) # import matplotlib.pyplot as plt # plt.plot(profile_i[:,0], profile_i[:,1]) # plt.plot(profile_i_rot[:,0], profile_i_rot[:,1]) # plt.axis('equal') # plt.title(i) # plt.show() # normalize profile_i_rot[:, 0] -= min(profile_i_rot[:, 0]) profile_i_rot = profile_i_rot / max(profile_i_rot[:, 0]) profile_i_rot_precomp = copy.copy(profile_i_rot) idx_s = 0 idx_le_precomp = np.argmax(profile_i_rot_precomp[:, 0]) if idx_le_precomp != 0: if profile_i_rot_precomp[0, 0] == profile_i_rot_precomp[-1, 0]: idx_s = 1 profile_i_rot_precomp = np.row_stack( (profile_i_rot_precomp[idx_le_precomp:], profile_i_rot_precomp[idx_s:idx_le_precomp, :]) ) profile_i_rot_precomp[:, 1] -= profile_i_rot_precomp[np.argmin(profile_i_rot_precomp[:, 0]), 1] # # renormalize profile_i_rot_precomp[:, 0] -= min(profile_i_rot_precomp[:, 0]) profile_i_rot_precomp = profile_i_rot_precomp / max(profile_i_rot_precomp[:, 0]) if profile_i_rot_precomp[-1, 0] != 1.0: profile_i_rot_precomp = np.row_stack((profile_i_rot_precomp, profile_i_rot_precomp[0, :])) # 'web' at trailing edge needed for flatback airfoils if ( profile_i_rot_precomp[0, 1] != profile_i_rot_precomp[-1, 1] and profile_i_rot_precomp[0, 0] == profile_i_rot_precomp[-1, 0] ): flatback = True else: flatback = False profile[i] = Profile.initWithTEtoTEdata(profile_i_rot_precomp[:, 0], profile_i_rot_precomp[:, 1]) # import matplotlib.pyplot as plt # plt.plot(profile_i_rot_precomp[:,0], profile_i_rot_precomp[:,1]) # plt.axis('equal') # plt.title(i) # plt.show() idx_le = np.argmin(profile_i_rot[:, 0]) profile_i_arc = arc_length(profile_i_rot) arc_L = profile_i_arc[-1] profile_i_arc /= arc_L loc_LE = profile_i_arc[idx_le] len_PS = 1.0 - loc_LE ## Composites ss_idx = [] ss_start_nd_arc = [] ss_end_nd_arc = [] ps_idx = [] ps_start_nd_arc = [] ps_end_nd_arc = [] web_start_nd_arc = [] web_end_nd_arc = [] web_idx = [] # Determine spanwise composite layer elements that are non-zero at this spanwise location, # determine their chord-wise start and end location on the pressure and suctions side spline_arc2xnd = PchipInterpolator(profile_i_arc, profile_i_rot[:, 0]) # time1 = time.time() for idx_sec in range(self.n_layers): if discrete_inputs["definition_layer"][idx_sec] != 10: if inputs["layer_thickness"][idx_sec, i] != 0.0: if inputs["layer_start_nd"][idx_sec, i] < loc_LE or inputs["layer_end_nd"][idx_sec, i] < loc_LE: ss_idx.append(idx_sec) if inputs["layer_start_nd"][idx_sec, i] < loc_LE: # ss_start_nd_arc.append(sec['start_nd_arc']['values'][i]) ss_end_nd_arc_temp = float(spline_arc2xnd(inputs["layer_start_nd"][idx_sec, i])) if ss_end_nd_arc_temp > 1 or ss_end_nd_arc_temp < 0: raise ValueError( "Error in the definition of material " + layer_name[idx_sec] + ". It cannot fit in the section number " + str(i) + " at span location " + str(inputs["r"][i] / inputs["r"][-1] * 100.0) + " %." ) if ss_end_nd_arc_temp == profile_i_rot[0, 0] and profile_i_rot[0, 0] != 1.0: ss_end_nd_arc_temp = 1.0 ss_end_nd_arc.append(ss_end_nd_arc_temp) else: ss_end_nd_arc.append(1.0) # ss_end_nd_arc.append(min(sec['end_nd_arc']['values'][i], loc_LE)/loc_LE) if inputs["layer_end_nd"][idx_sec, i] < loc_LE: ss_start_nd_arc.append(float(spline_arc2xnd(inputs["layer_end_nd"][idx_sec, i]))) else: ss_start_nd_arc.append(0.0) if inputs["layer_start_nd"][idx_sec, i] > loc_LE or inputs["layer_end_nd"][idx_sec, i] > loc_LE: ps_idx.append(idx_sec) # ps_start_nd_arc.append((max(sec['start_nd_arc']['values'][i], loc_LE)-loc_LE)/len_PS) # ps_end_nd_arc.append((min(sec['end_nd_arc']['values'][i], 1.)-loc_LE)/len_PS) if ( inputs["layer_start_nd"][idx_sec, i] > loc_LE and inputs["layer_end_nd"][idx_sec, i] < loc_LE ): # ps_start_nd_arc.append(float(remap2grid(profile_i_arc, profile_i_rot[:,0], sec['start_nd_arc']['values'][i]))) ps_end_nd_arc.append(1.0) else: ps_end_nd_arc_temp = float(spline_arc2xnd(inputs["layer_end_nd"][idx_sec, i])) if np.isclose(ps_end_nd_arc_temp, profile_i_rot[-1, 0]) and profile_i_rot[-1, 0] != 1.0: ps_end_nd_arc_temp = 1.0 ps_end_nd_arc.append(ps_end_nd_arc_temp) if inputs["layer_start_nd"][idx_sec, i] < loc_LE: ps_start_nd_arc.append(0.0) else: ps_start_nd_arc.append(float(spline_arc2xnd(inputs["layer_start_nd"][idx_sec, i]))) else: target_idx = inputs["layer_web"][idx_sec] - 1 if inputs["layer_thickness"][idx_sec, i] != 0.0: web_idx.append(idx_sec) start_nd_arc = float(spline_arc2xnd(inputs["web_start_nd"][int(target_idx), i])) end_nd_arc = float(spline_arc2xnd(inputs["web_end_nd"][int(target_idx), i])) web_start_nd_arc.append(start_nd_arc) web_end_nd_arc.append(end_nd_arc) # time1 = time.time() - time1 # print(time1) # generate the Precomp composite stacks for chordwise regions if np.min([ss_start_nd_arc, ss_end_nd_arc]) < 0 or np.max([ss_start_nd_arc, ss_end_nd_arc]) > 1: raise ValueError("Error in the layer definition at station number " + str(i)) upperCS[i], region_loc_ss = region_stacking( i, ss_idx, ss_start_nd_arc, ss_end_nd_arc, layer_name, inputs["layer_thickness"][:, i], inputs["fiber_orientation"][:, i], layer_mat, material_dict, materials, region_loc_ss, ) lowerCS[i], region_loc_ps = region_stacking( i, ps_idx, ps_start_nd_arc, ps_end_nd_arc, layer_name, inputs["layer_thickness"][:, i], inputs["fiber_orientation"][:, i], layer_mat, material_dict, materials, region_loc_ps, ) if len(web_idx) > 0 or flatback: websCS[i] = web_stacking( i, web_idx, web_start_nd_arc, web_end_nd_arc, inputs["layer_thickness"][:, i], inputs["fiber_orientation"][:, i], layer_mat, material_dict, materials, flatback, upperCS[i], ) else: websCS[i] = CompositeSection([], [], [], [], [], []) sector_idx_strain_spar_cap_ss = [ None if regs == None else regs[int(len(regs) / 2)] for regs in region_loc_ss[self.spar_cap_ss_var] ] sector_idx_strain_spar_cap_ps = [ None if regs == None else regs[int(len(regs) / 2)] for regs in region_loc_ps[self.spar_cap_ps_var] ] sector_idx_strain_te_ss = [ None if regs == None else regs[int(len(regs) / 2)] for regs in region_loc_ss[self.te_ss_var] ] sector_idx_strain_te_ps = [ None if regs == None else regs[int(len(regs) / 2)] for regs in region_loc_ps[self.te_ps_var] ] # Get Beam Properties beam = PreComp( inputs["r"], inputs["chord"], np.zeros_like(inputs["r"]), inputs["pitch_axis"], inputs["precurve"], inputs["presweep"], profile, materials, upperCS, lowerCS, websCS, sector_idx_strain_spar_cap_ps, sector_idx_strain_spar_cap_ss, sector_idx_strain_te_ps, sector_idx_strain_te_ss, ) ( EIxx, EIyy, GJ, EA, EIxy, x_ec, y_ec, rhoA, area, rhoJ, Tw_iner, flap_iner, edge_iner, x_tc, y_tc, x_sc, y_sc, x_cg, y_cg, ) = beam.sectionProperties() # outputs['eps_crit_spar'] = beam.panelBucklingStrain(sector_idx_strain_spar_cap_ss) # outputs['eps_crit_te'] = beam.panelBucklingStrain(sector_idx_strain_te_ss) xu_strain_spar, xl_strain_spar, yu_strain_spar, yl_strain_spar = beam.criticalStrainLocations( sector_idx_strain_spar_cap_ss, sector_idx_strain_spar_cap_ps ) xu_strain_te, xl_strain_te, yu_strain_te, yl_strain_te = beam.criticalStrainLocations( sector_idx_strain_te_ss, sector_idx_strain_te_ps ) # Store what materials make up the composites for SC/TE for i in range(self.n_span): for j in range(self.n_mat): if sector_idx_strain_spar_cap_ss[i]: if j in upperCS[i].mat_idx[sector_idx_strain_spar_cap_ss[i]]: outputs["sc_ss_mats"][i, j] = 1.0 if sector_idx_strain_spar_cap_ps[i]: if j in lowerCS[i].mat_idx[sector_idx_strain_spar_cap_ps[i]]: outputs["sc_ps_mats"][i, j] = 1.0 if sector_idx_strain_te_ss[i]: if j in upperCS[i].mat_idx[sector_idx_strain_te_ss[i]]: outputs["te_ss_mats"][i, j] = 1.0 if sector_idx_strain_te_ps[i]: if j in lowerCS[i].mat_idx[sector_idx_strain_te_ps[i]]: outputs["te_ps_mats"][i, j] = 1.0 outputs["z"] = inputs["r"] outputs["EIxx"] = EIxx outputs["EIyy"] = EIyy outputs["GJ"] = GJ outputs["EA"] = EA outputs["EIxy"] = EIxy outputs["x_ec"] = x_ec outputs["y_ec"] = y_ec outputs["rhoA"] = rhoA outputs["A"] = area outputs["rhoJ"] = rhoJ outputs["Tw_iner"] = Tw_iner outputs["flap_iner"] = flap_iner outputs["edge_iner"] = edge_iner outputs["x_tc"] = x_tc outputs["y_tc"] = y_tc outputs["x_sc"] = x_sc outputs["y_sc"] = y_sc outputs["x_cg"] = x_cg outputs["y_cg"] = y_cg outputs["xu_strain_spar"] = xu_strain_spar outputs["xl_strain_spar"] = xl_strain_spar outputs["yu_strain_spar"] = yu_strain_spar outputs["yl_strain_spar"] = yl_strain_spar outputs["xu_strain_te"] = xu_strain_te outputs["xl_strain_te"] = xl_strain_te outputs["yu_strain_te"] = yu_strain_te outputs["yl_strain_te"] = yl_strain_te # Compute mass and inertia of blade and rotor blade_mass = np.trapz(rhoA, inputs["r"]) blade_moment_of_inertia = np.trapz(rhoA * inputs["r"] ** 2.0, inputs["r"]) tilt = inputs["uptilt"] n_blades = discrete_inputs["n_blades"] mass_all_blades = n_blades * blade_mass Ibeam = n_blades * blade_moment_of_inertia Ixx = Ibeam Iyy = Ibeam / 2.0 # azimuthal average for 2 blades, exact for 3+ Izz = Ibeam / 2.0 Ixy = 0.0 Ixz = 0.0 Iyz = 0.0 # azimuthal average for 2 blades, exact for 3+ # rotate to yaw c.s. I = DirectionVector(Ixx, Iyy, Izz).hubToYaw(tilt) # because off-diagonal components are all zero I_all_blades = np.r_[I.x, I.y, I.z, Ixy, Ixz, Iyz] outputs["blade_mass"] = blade_mass outputs["blade_moment_of_inertia"] = blade_moment_of_inertia outputs["mass_all_blades"] = mass_all_blades outputs["I_all_blades"] = I_all_blades # Placeholder - rotor cost bcm = blade_cost_model(verbosity=self.verbosity) bcm.name = "" bcm.materials = {} bcm.mat_options = {} bcm.mat_options["core_mat_id"] = np.zeros(self.n_mat) bcm.mat_options["coating_mat_id"] = -1 bcm.mat_options["le_reinf_mat_id"] = -1 bcm.mat_options["te_reinf_mat_id"] = -1 for i_mat in range(self.n_mat): name = discrete_inputs["mat_name"][i_mat] # if name != 'resin': bcm.materials[name] = {} bcm.materials[name]["id"] = i_mat + 1 bcm.materials[name]["name"] = discrete_inputs["mat_name"][i_mat] bcm.materials[name]["density"] = inputs["rho"][i_mat] bcm.materials[name]["unit_cost"] = inputs["unit_cost"][i_mat] bcm.materials[name]["waste"] = inputs["waste"][i_mat] * 100.0 if discrete_inputs["component_id"][i_mat] > 1: # It's a composite bcm.materials[name]["fiber_density"] = inputs["rho_fiber"][i_mat] bcm.materials[name]["area_density_dry"] = inputs["rho_area_dry"][i_mat] bcm.materials[name]["fvf"] = inputs["fvf"][i_mat] * 100.0 bcm.materials[name]["fwf"] = inputs["fwf"][i_mat] * 100.0 bcm.materials[name]["ply_t"] = inputs["ply_t"][i_mat] if discrete_inputs["component_id"][i_mat] > 3: # The material does not need to be cut@station bcm.materials[name]["cut@station"] = "N" else: bcm.materials[name]["cut@station"] = "Y" bcm.materials[name]["roll_mass"] = inputs["roll_mass"][i_mat] else: bcm.materials[name]["fvf"] = 100.0 bcm.materials[name]["fwf"] = 100.0 bcm.materials[name]["cut@station"] = "N" if discrete_inputs["component_id"][i_mat] <= 0: bcm.materials[name]["ply_t"] = inputs["ply_t"][i_mat] if discrete_inputs["component_id"][i_mat] == 0: bcm.mat_options["coating_mat_id"] = bcm.materials[name]["id"] # Assigning the material to the coating elif discrete_inputs["component_id"][i_mat] == 1: bcm.mat_options["core_mat_id"][bcm.materials[name]["id"] - 1] = 1 # Assigning the material to the core elif discrete_inputs["component_id"][i_mat] == 2: bcm.mat_options["skin_mat_id"] = bcm.materials[name]["id"] # Assigning the material to the shell skin elif discrete_inputs["component_id"][i_mat] == 3: bcm.mat_options["skinwebs_mat_id"] = bcm.materials[name][ "id" ] # Assigning the material to the webs skin elif discrete_inputs["component_id"][i_mat] == 4: bcm.mat_options["sc_mat_id"] = bcm.materials[name]["id"] # Assigning the material to the spar caps elif discrete_inputs["component_id"][i_mat] == 5: bcm.mat_options["le_reinf_mat_id"] = bcm.materials[name]["id"] # Assigning the material to the le reinf bcm.mat_options["te_reinf_mat_id"] = bcm.materials[name]["id"] # Assigning the material to the te reinf # Rotor cost bcm.upperCS = upperCS bcm.lowerCS = lowerCS bcm.websCS = websCS bcm.profile = profile bcm.chord = inputs["chord"] bcm.r = inputs["r"] - inputs["r"][0] bcm.bladeLength = inputs["r"][-1] - inputs["r"][0] bcm.le_location = inputs["pitch_axis"] blade_cost, blade_mass = bcm.execute_blade_cost_model() outputs["total_blade_cost"] = blade_cost outputs["total_blade_mass"] = blade_mass
def add_fromtable( self, dframe, sgcolname="Sg", krgcolname="krg", krogcolname="krog", pccolname="pcog", krgcomment="", krogcomment="", pccomment="", ): """Interpolate relpermdata from a dataframe. The saturation range with endpoints must be set up beforehand, and must be compatible with the tabular input. The tabular input will be interpolated to the initialized Sg-table. If you have krg and krog in different dataframes, call this function twice Calling function is responsible for checking if any data was actually added to the table. """ # Avoid having to deal with multi-indices: if len(dframe.index.names) > 1: logger.warning( "add_fromtable() did a reset_index(), consider not supplying MultiIndex" ) dframe = dframe.reset_index() if sgcolname not in dframe: logger.critical("%s not found in dataframe, can't read table data", sgcolname) raise ValueError for col in [sgcolname, krgcolname, krogcolname, pccolname]: # Typecheck/convert all numerical columns: if col in dframe and not pd.api.types.is_numeric_dtype( dframe[col]): # Try to convert to numeric type try: dframe[col] = dframe[col].astype(float) logger.info( "Converted column %s to numbers for fromtable()", col) except ValueError as e_msg: logger.error( "Failed to parse column %s as numbers for add_fromtable()", col) raise ValueError(e_msg) except TypeError as e_msg: logger.error( "Failed to parse column %s as numbers for add_fromtable()", col) raise TypeError(e_msg) if dframe[sgcolname].min() > 0.0: raise ValueError("sg must start at zero") swlfrominput = 1 - dframe[sgcolname].max() if abs(swlfrominput - self.swl) > epsilon: logger.warning( "swl=%f and 1-max(sg)=%f from incoming table does not seem compatible", self.swl, swlfrominput, ) logger.warning( " Do not trust the result near the endpoint.") if 0 < swlfrominput - self.swl < epsilon: # Perturb max sg in incoming dataframe when we are this close, # or we will get into floating trouble when interpolating. dframe.loc[dframe[sgcolname].idxmax(), sgcolname] += swlfrominput - self.swl if krgcolname in dframe: if not (dframe[krgcolname].diff().dropna() > -epsilon).all(): raise ValueError("Incoming krg not increasing") if dframe[krgcolname].max() > 1.0: raise ValueError("krg is above 1 in incoming table") if dframe[krgcolname].min() < 0.0: raise ValueError("krg is below 0 in incoming table") pchip = PchipInterpolator(dframe[sgcolname].astype(float), dframe[krgcolname].astype(float)) # Do not extrapolate this data. We will bfill and ffill afterwards self.table["krg"] = pchip(self.table.sg, extrapolate=False) self.table["krg"].fillna(method="ffill", inplace=True) self.table["krg"].fillna(method="bfill", inplace=True) self.table["krg"].clip(lower=0.0, upper=1.0, inplace=True) self.krgcomment = "-- krg from tabular input" + krgcomment + "\n" self.sgcr = self.estimate_sgcr() if krogcolname in dframe: if not (dframe[krogcolname].diff().dropna() < epsilon).all(): raise ValueError("Incoming krogcolname not decreasing") if dframe[krogcolname].max() > 1.0: raise ValueError("krog is above 1 in incoming table") if dframe[krogcolname].min() < 0.0: raise ValueError("krog is below 0 in incoming table") pchip = PchipInterpolator(dframe[sgcolname].astype(float), dframe[krogcolname].astype(float)) self.table["krog"] = pchip(self.table.sg, extrapolate=False) self.table["krog"].fillna(method="ffill", inplace=True) self.table["krog"].fillna(method="bfill", inplace=True) self.table["krog"].clip(lower=0.0, upper=1.0, inplace=True) self.krogcomment = "-- krog from tabular input" + krogcomment + "\n" self.sorg = self.estimate_sorg() if pccolname in dframe: # Incoming dataframe must cover the range: if dframe[sgcolname].min() > self.table["sg"].min(): raise ValueError("Too large sgcr for pcog interpolation") if dframe[sgcolname].max() < self.table["sg"].max(): raise ValueError("Too large swl for pcog interpolation") if np.isinf(dframe[pccolname]).any(): logger.warning( ("Infinity pc values detected. Will be dropped, " "risk of extrapolation")) dframe = dframe.replace([np.inf, -np.inf], np.nan) dframe.dropna(subset=[pccolname], how="all", inplace=True) # If nonzero, then it must be increasing: if dframe[pccolname].abs().sum() > 0: if not (dframe[pccolname].diff().dropna() > 0.0).all(): raise ValueError("Incoming pc not increasing") pchip = PchipInterpolator(dframe[sgcolname].astype(float), dframe[pccolname].astype(float)) self.table["pc"] = pchip(self.table.sg, extrapolate=False) if np.isnan(self.table["pc"]).any() or np.isinf( self.table["pc"]).any(): raise ValueError("inf/nan in interpolated data, check input") self.pccomment = "-- pc from tabular input" + pccomment + "\n"
#axs.set_title("Ferromagnet Permeability (at 40 mT)") plt.xlabel("$f_M$") plt.ylabel("$\mu_{r}$") a_mu = [1] a_mu_sdev = [0] a_fm = [0] for id_i in [ "fm104a", "fm104b", "fm581a", "fm581b", "fm590a", "fm590b", "fm618a", "fm618b", "fm673a", "fm673b", "fm699b", "fm745a", "fm745b" ]: # f = interp1d(calibration[:,1], calibration[:,2]) interpol = PchipInterpolator(data.loc[data['ID'] == id_i, 'Bout'].values, data.loc[data['ID'] == id_i, 'mu'].values, extrapolate=False) a_mu_interpol = interpol(Bref) if not (np.isnan(a_mu_interpol)): a_mu.append(a_mu_interpol) a_mu_sdev.append(data.loc[data['ID'] == id_i, 'mu_err'].values[-1]) a_fm.append(data.loc[data['ID'] == id_i, 'frac'].values[0]) # convert lists to numpy arrays a_mu = np.array(a_mu) a_mu_sdev = np.array(a_mu_sdev) a_fm = np.array(a_fm) # do plot
def plot_cv_scaling(fisher_dir, out_dir, prim_template='local'): ''' Arguments --------- fisher_dir : str Directory containing fisher pkl files. out_dir : str Directory for output figures. ''' lmax_start = 500 lmax_end = 4900 lmax_steps = 10 lmax_arr = np.logspace(np.log10(lmax_start), np.log10(lmax_end), lmax_steps) lmax_arr = lmax_arr.astype(int) lmin_b_arr = np.asarray([2, 20, 30, 50, 80]) pol_opts_arr = [dict(no_ee=False, no_tt=False), dict(no_ee=True, no_tt=False), dict(no_ee=False, no_tt=True)] r_arr = [0, 0.001, 0.01, 0.1] noise_amp_temp = 0 noise_amp_e = 0 noise_amp_b = 0 lmin_e = 2 A_lens = 0.1 # Array to fill with loaded fisher values. fnl_arr = np.ones((len(r_arr), lmin_b_arr.size, len(pol_opts_arr), lmax_steps)) fnl_arr *= np.nan # Load pickle files. for ridx, r in enumerate(r_arr): for lidx, lmax in enumerate(lmax_arr): for lidx_b, lmin_b in enumerate(lmin_b_arr): for pidx, pol_opts in enumerate(pol_opts_arr): no_ee = pol_opts['no_ee'] no_tt = pol_opts['no_tt'] tag = ('{}_nt{:.4f}_ne{:.4f}_nb{:.4f}_lb{:d}_le{:d}_nee{:d}' '_ntt{:d}_a{:.4f}_r{:.4f}_l{:d}'.format(prim_template, noise_amp_temp, noise_amp_e, noise_amp_b, lmin_b, lmin_e, int(no_ee), int(no_tt), A_lens, r, lmax)) try: fisher_file = opj(fisher_dir, 'f_{}.pkl'.format(tag)) fisher_opts = np.load(fisher_file) except IOError: print('{} not found'.format(fisher_file)) continue fnl_arr[ridx, lidx_b, pidx, lidx] = fisher_opts['sigma_fnl'] # r, lmin_b, pol, lmax print fnl_arr[:,0,0,0] # Interpolate. i_fact = 20 lmax_arr_i = np.logspace(np.log10(lmax_start), np.log10(lmax_end), i_fact * lmax_steps) fnl_arr_i = np.ones((len(r_arr), lmin_b_arr.size, len(pol_opts_arr), i_fact * lmax_steps)) for i in xrange(fnl_arr.shape[0]): for j in xrange(fnl_arr.shape[1]): for k in xrange(fnl_arr.shape[2]): cs = PchipInterpolator(lmax_arr, fnl_arr[i,j,k,:]) fnl_arr_i[i,j,k,:] = cs(lmax_arr_i) fnl_arr = fnl_arr_i lmax_arr = lmax_arr_i # Plot. font = {'size' : 12} matplotlib.rc('font', **font) fig, axs = plt.subplots(ncols=2, nrows=2, figsize=(4, 4), sharey=True, sharex=False) plot_opts = dict(color='black') lstyles = ['-', '-.', '', '--', ':'] for lidx_b, lmin_b in enumerate(lmin_b_arr): for pidx, pol_opts in enumerate(pol_opts_arr): if pidx > 0: alpha = 0.5 continue else: alpha = 1 if lmin_b == 30: continue label = r'$\ell_{\mathrm{min}}^B = '+str(lmin_b)+'$' if lidx_b < 2: label_a = label label_b = None else: label_a = None label_b = label axs[0,0].plot(lmax_arr, fnl_arr[0,lidx_b,pidx,:], alpha=alpha, ls=lstyles[lidx_b], **plot_opts) axs[0,1].plot(lmax_arr, fnl_arr[1,lidx_b,pidx,:], alpha=alpha, ls=lstyles[lidx_b], **plot_opts) axs[1,0].plot(lmax_arr, fnl_arr[2,lidx_b,pidx,:], alpha=alpha, ls=lstyles[lidx_b], label=label_a, **plot_opts) axs[1,1].plot(lmax_arr, fnl_arr[3,lidx_b,pidx,:], alpha=alpha, ls=lstyles[lidx_b], label=label_b, **plot_opts) fig.text(0.001, 0.5, r'$\sigma(\hat{f}_{\mathrm{NL}}^{\, \mathrm{tot}})$', ha='center', va='center', rotation='vertical') fig.text(0.5, 0.03, r'harmonic band-limit $\ell_{\mathrm{max}}$', ha='center', va='center', rotation='horizontal') fig.suptitle(r'Cosmic variance only, $A^{BB}_{\mathrm{lens}} = 0.1$', y=.95) import matplotlib.ticker as ticker for i, ax in enumerate(axs.ravel()): ax.set_yscale('log') ax.set_xscale('log') ax.tick_params(axis='both', direction='in', top=True, right=True, which='major') ax.tick_params(axis='both', direction='in', top=True, right=True, which='minor', labelsize=10) ax.set_xlim(400, 6000) ax.set_ylim(4e-3, 7e0) ax.text(0.9, 0.85, r'$r='+str(r_arr[i])+'$', transform=ax.transAxes, horizontalalignment='right') axs[1,1].xaxis.set_ticklabels(['','','','','','','','',r'$5\times10^3$'], minor=True) axs[1,1].set_xticks([500, 600, 700, 800, 900, 2000, 3000, 4000, 5000], minor=True) axs[1,0].xaxis.set_ticklabels(['','','','','','','','',r'$5\times10^3$'], minor=True) axs[1,0].set_xticks([500, 600, 700, 800, 900, 2000, 3000, 4000, 5000], minor=True) axs[1,1].legend(ncol=1, frameon=False, loc=(0.05, 0.001), markerscale=.1, handletextpad=0.3, handlelength=1.3, prop={'size': 12}) axs[1,0].legend(ncol=1, frameon=False, loc=(0.05, 0.001), markerscale=.1, handletextpad=0.3, handlelength=1.3, prop={'size': 12}) fig.subplots_adjust(hspace=0., wspace=0.) fig.savefig(opj(out_dir, 'cv_lim_{}.pdf'.format(prim_template)), dpi=300, bbox_inches='tight')
def invert_warping(fdatagrid, *, output_points=None): r"""Compute the inverse of a diffeomorphism. Let :math:`\gamma : [a,b] \rightarrow [a,b]` be a function strictly increasing, calculates the corresponding inverse :math:`\gamma^{-1} : [a,b] \rightarrow [a,b]` such that :math:`\gamma^{-1} \circ \gamma = \gamma \circ \gamma^{-1} = \gamma_{id}`. Uses a PCHIP interpolator to compute approximately the inverse. Args: fdatagrid (:class:`FDataGrid`): Functions to be inverted. eval_points: (array_like, optional): Set of points where the functions are interpolated to obtain the inverse, by default uses the sample points of the fdatagrid. Returns: :class:`FDataGrid`: Inverse of the original functions. Raises: ValueError: If the functions are not strictly increasing or are multidimensional. Examples: >>> import numpy as np >>> from skfda import FDataGrid >>> from skfda.preprocessing.registration import invert_warping We will construct the warping :math:`\gamma : [0,1] \rightarrow [0,1]` wich maps t to t^3. >>> t = np.linspace(0, 1) >>> gamma = FDataGrid(t**3, t) >>> gamma FDataGrid(...) We will compute the inverse. >>> inverse = invert_warping(gamma) >>> inverse FDataGrid(...) The result of the composition should be approximately the identity function . >>> identity = gamma.compose(inverse) >>> identity([0, 0.25, 0.5, 0.75, 1]).round(3) array([[[ 0. ], [ 0.25], [ 0.5 ], [ 0.75], [ 1. ]]]) """ check_is_univariate(fdatagrid) if output_points is None: output_points = fdatagrid.grid_points[0] y = fdatagrid(output_points)[..., 0] data_matrix = np.empty((fdatagrid.n_samples, len(output_points))) for i in range(fdatagrid.n_samples): data_matrix[i] = PchipInterpolator(y[i], output_points)(output_points) return fdatagrid.copy(data_matrix=data_matrix, grid_points=output_points)
def plot_pol(fisher_dir, out_dir, prim_template='local', plot_invcov=False): ''' Arguments --------- fisher_dir : str Directory containing fisher pkl files. out_dir : str Directory for output figures. ''' lmax_start = 500 lmax_end = 4900 lmax_steps = 10 lmax_arr = np.logspace(np.log10(lmax_start), np.log10(lmax_end), lmax_steps) lmax_arr = lmax_arr.astype(int) lmin_b = 2 pol_opts_arr = [dict(no_ee=True, no_tt=False), dict(no_ee=False, no_tt=True), dict(no_ee=False, no_tt=False)] pol_opts_names = [r'$B+T$', r'$B+E$', r'$B+T + E$'] r = 0.001 lmin_e = 2 # Add noise array. noise_opts_arr = [dict(noise_amp_temp=0, noise_amp_e=0, noise_amp_b=0), dict(noise_amp_temp=4, noise_amp_e=4*np.sqrt(2), noise_amp_b=4*np.sqrt(2))] n_ell_arr = ['0', '4'] A_lens = 0.5 # Array to fill with loaded fisher values. fnl_arr = np.ones((len(noise_opts_arr), len(pol_opts_arr), lmax_steps)) fnl_arr *= np.nan # Load pickle files. for nidx, noise_opts in enumerate(noise_opts_arr): for lidx, lmax in enumerate(lmax_arr): for pidx, pol_opts in enumerate(pol_opts_arr): no_ee = pol_opts['no_ee'] no_tt = pol_opts['no_tt'] noise_amp_temp = noise_opts['noise_amp_temp'] noise_amp_e = noise_opts['noise_amp_e'] noise_amp_b = noise_opts['noise_amp_b'] tag = ('{}_nt{:.4f}_ne{:.4f}_nb{:.4f}_lb{:d}_le{:d}_nee{:d}' '_ntt{:d}_a{:.4f}_r{:.4f}_l{:d}'.format(prim_template, noise_amp_temp, noise_amp_e, noise_amp_b, lmin_b, lmin_e, int(no_ee), int(no_tt), A_lens, r, lmax)) # Load fisher. try: fisher_file = opj(fisher_dir, 'f_{}.pkl'.format(tag)) fisher_opts = np.load(fisher_file) except IOError: print('{} not found'.format(fisher_file)) continue fnl_arr[nidx, pidx, lidx] = fisher_opts['sigma_fnl'] if plot_invcov: # Load invcov and cov, plot right away. try: invcov_file = opj(fisher_dir, 'invcov_{}.pkl'.format(tag)) invcov_opts = np.load(invcov_file) except IOError: print('{} not found'.format(invcov_file)) continue invcov_name = opj(out_dir, 'invcov', 'invcov_{}.png'.format(tag)) cov_name = opj(out_dir, 'invcov', 'cov_{}.png'.format(tag)) ells = invcov_opts['ells'] invcov = invcov_opts['invcov'] cov = invcov_opts['cov'] plot_invcov(ells, invcov, invcov_name, dell=False) plot_invcov(ells, cov, cov_name) # pol, lmax print fnl_arr.shape # Interpolate. i_fact = 20 lmax_arr_i = np.logspace(np.log10(lmax_start), np.log10(lmax_end), i_fact * lmax_steps) fnl_arr_i = np.ones((len(noise_opts_arr), len(pol_opts_arr), i_fact * lmax_steps)) for i in xrange(fnl_arr.shape[0]): for j in xrange(fnl_arr.shape[1]): cs = PchipInterpolator(lmax_arr, fnl_arr[i,j,:]) fnl_arr_i[i,j,:] = cs(lmax_arr_i) fnl_arr = fnl_arr_i lmax_arr = lmax_arr_i # Plot. font = {'size' : 12} matplotlib.rc('font', **font) fig, axs = plt.subplots(ncols=2, nrows=1, figsize=(4, 2), sharey=True, sharex=False) plot_opts = dict(color='black') lstyles = ['--', '-.', '-', ':'] for pidx, pol_opts in enumerate(pol_opts_arr): label = pol_opts_names[pidx] if pidx < 2: label_a = label label_b = None else: label_a = None label_b = label axs[0].plot(lmax_arr, fnl_arr[0,pidx,:], ls=lstyles[pidx], label=label_a, **plot_opts) axs[1].plot(lmax_arr, fnl_arr[1,pidx,:], ls=lstyles[pidx], label=label_b, **plot_opts) fig.text(0.001, 0.5, r'$\sigma(\hat{f}_{\mathrm{NL}}^{\, \mathrm{tot}})$', ha='center', va='center', rotation='vertical') fig.text(0.5, -0.05, r'harmonic band-limit $\ell_{\mathrm{max}}$', ha='center', va='center', rotation='horizontal') fig.suptitle(r'$A^{BB}_{\mathrm{lens}} = '+str(A_lens)+'$, $r='+str(r)+'$', y=1.03) for i, ax in enumerate(axs.ravel()): ax.set_yscale('log') ax.set_xscale('log') ax.tick_params(axis='both', direction='in', top=True, right=True, which='major') ax.tick_params(axis='both', direction='in', top=True, right=True, which='minor', labelsize=10) ax.set_xlim(400, 6000) ax.set_ylim(4e-3, 7e0) ax.text(0.9, 0.85, r"$"+str(n_ell_arr[i])+"\ \mu \mathrm{K}$-$\mathrm{arcmin}$", transform=ax.transAxes, horizontalalignment='right') axs[1].xaxis.set_ticklabels(['','','','','','','','',r'$5\times10^3$'], minor=True) axs[1].set_xticks([500, 600, 700, 800, 900, 2000, 3000, 4000, 5000], minor=True) axs[0].xaxis.set_ticklabels(['','','','','','','','',r'$5\times10^3$'], minor=True) axs[0].set_xticks([500, 600, 700, 800, 900, 2000, 3000, 4000, 5000], minor=True) axs[0].legend(ncol=1, frameon=False, loc=(0.05, 0.001), markerscale=.1, handletextpad=0.3, handlelength=1.3, prop={'size': 12}) axs[1].legend(ncol=1, frameon=False, loc=(0.05, 0.001), markerscale=.1, handletextpad=0.3, handlelength=1.3, prop={'size': 12}) fig.subplots_adjust(hspace=0., wspace=0.) fig.savefig(opj(out_dir, 'pol.pdf'), dpi=300, bbox_inches='tight')
def start(self): from imageCreator import getFrameSize, ImageCreator # Query frameSize for input images self.frameSize = getFrameSize(self.background_img) left_offset = (SPEEDOMETER_X_OFFSET, SPEEDOMETER_Y_OFFSET) right_offset = (ALTIMETER_X_OFFSET, ALTIMETER_Y_OFFSET) self.imageCreator = ImageCreator(self.left_indicator_img, left_offset, self.right_indicator_img, right_offset , self.background_img) print(' GPX filename: {}'.format(self.gpxFilename)) print(' Altitude offset: {}'.format(self.altitude_offset)) print(' Output video filename: {}'.format(self.videoFilename)) print(' video dimensions: {} X {}'.format(self.frameSize[0], self.frameSize[1])) print(' framerate: {}fps'.format(self.framerate)) print(' left foreground: {}'.format(self.left_indicator_img)) print(' right foreground: {}'.format(self.right_indicator_img)) print(' background: {}'.format(self.background_img)) if self.high_speed: print(' ! High speed video playback enabled - one frame per datapoint - no fill frames !') print(' ------------------------------------------\n') from gpx_file_parser import load_data #from pandas import DataFrame data = load_data(self.gpxFilename) if not data[0]: print('ERROR: gpx_file_parser.load_data returned a failure') quit() # Grab the pandas.DataFrame object df = data[1] self.numPoints = len(df) self.elapsed_time = (df['Time'][len(df)-1] - df['Time'][0]).total_seconds() print('Number of points in {}: {}'.format(self.gpxFilename, self.numPoints)) print('Min speed: %.2f MPH' % (df['Speed'].min())) print('Max speed: %.2f MPH' % (df['Speed'].max())) if self.altitude_offset != 0: print('Altitude offset selected: %.2f Feet' % self.altitude_offset) print('Min altitude (raw data): %.2f Feet' % (df['Altitude'].min())) print('Max altitude (raw data): %.2f Feet' % (df['Altitude'].max())) print('Min altitude (offset): %.2f Feet' % (df['Altitude'].min() + self.altitude_offset)) print('Max altitude (offset): %.2f Feet' % (df['Altitude'].max() + self.altitude_offset)) else: print('Min altitude: %.2f Feet' % (df['Altitude'].min())) print('Max altitude: %.2f Feet' % (df['Altitude'].max())) print('Min temperature: %.2f F' % (df['Temperature'].min())) print('Max temperature: %.2f F' % (df['Temperature'].max())) print('Total distance: %.2f Miles' % (df['Distance'].max())) print('Start time: {}'.format(df['Time'][0].strftime('%Y-%m-%d @ %H:%M:%S'))) print('End time: {}'.format(df['Time'][len(df)-1].strftime('%Y-%m-%d @ %H:%M:%S'))) print('Elapsed: {} seconds'.format(self.elapsed_time)) x_axis = [] for i in range(len(df)): x_axis.append( (df['Time'][i] - df['Time'][0]).total_seconds() ) # Generate spline data for speed and altitude #from scipy.interpolate import CubicSpline # PCHIP 1-d monotonic cubic interpolation from scipy.interpolate import PchipInterpolator import matplotlib.pyplot as plt # Apply altitude offset to data - clip at zero feet for i in range(len(df['Altitude'])): df.loc[i, 'Altitude'] = max(0, df['Altitude'][i] + self.altitude_offset) # Clip speed to 0 MPH for i in range(len(df['Speed'])): df.loc[i, 'Speed'] = max(0, df['Speed'][i]) # Prep plot parameters plt.figure(figsize = (6.5, 4)) x_sample_rate = 1.0 / self.framerate x_tick_interval = np.arange(0, self.elapsed_time, x_sample_rate) # Create interpolated spline data #cs_speed = CubicSpline(x_axis, df['Speed']) #cs_altitude = CubicSpline(x_axis, df['Altitude']) cs_speed = PchipInterpolator(x_axis, df['Speed']) cs_altitude = PchipInterpolator(x_axis, df['Altitude']) # Pull out the array of data points cs_speed_array = cs_speed(x_tick_interval) cs_altitude_array = cs_altitude(x_tick_interval) # Clip spline data points for i in range(len(cs_speed_array)): cs_speed_array[i] = max(0, cs_speed_array[i]) cs_altitude_array[i] = max(0, cs_altitude_array[i]) plt.plot(x_axis, df['Speed'], 'o', label='gpx_speed') plt.plot(x_axis, df['Altitude'], 'o', label='gpx_altitude') plt.plot(x_tick_interval, cs_speed_array, label='speed') plt.plot(x_tick_interval, cs_altitude_array, label='altitude') plt.legend(loc='lower left', ncol=1) plt.show() if self.high_speed: num_points = self.numPoints y_axis_speed = df['Speed'] y_axis_altitude = df['Altitude'] else: num_points = len(cs_speed_array) y_axis_speed = cs_speed_array y_axis_altitude = cs_altitude_array print('Created a video with {} frames at a framerate of {}fps'.format(num_points, self.framerate)) proceed = input('Process video? (Y/N):') if proceed.upper() != 'Y': quit() # Prep video writer #vidOut = cv2.VideoWriter(self.videoFilename, cv2.VideoWriter_fourcc(*'DIVX'), self.framerate, self.frameSize) #vidOut = cv2.VideoWriter(self.videoFilename, cv2.VideoWriter_fourcc(*'H264'), self.framerate, self.frameSize) vidOut = cv2.VideoWriter(self.videoFilename, cv2.VideoWriter_fourcc(*'MP4V'), self.framerate, self.frameSize) #vidOut = cv2.VideoWriter(self.videoFilename, cv2.VideoWriter_fourcc(*'FFV1'), self.framerate, self.frameSize) for i in range(num_points): angle_speedometer = y_axis_speed[i] * ANGLE_SPEEDOMETER angle_altimeter = y_axis_altitude[i] * ANGLE_ALTIMETER image = self.imageCreator.createImage(angle_speedometer, angle_altimeter) # convert to 8-bit image to accomodate VideoWriter.write() #image = (image*255).astype(np.uint8) image = image.astype(np.uint8) '''cv2.imshow('img', image) cv2.waitKey(0) cv2.destroyAllWindows() quit()''' if 0 == ((i+1) % int(num_points / 100)): print('%.2f%% complete' % ((100.0) * ((i+1)/ float(num_points)))) vidOut.write(image) vidOut.release() print('Finished')
def create_mechanism(a_knots, b_knots, support): f = PchipInterpolator(a_knots, b_knots) return reduce_support(f, support)
"/home/francesco/Desktop/PhD/Git_workspace/IC4A2S/Goddard_Problem/2Controls/Vr.npy" ) Vtref = np.load( "/home/francesco/Desktop/PhD/Git_workspace/IC4A2S/Goddard_Problem/2Controls/Vt.npy" ) mref = np.load( "/home/francesco/Desktop/PhD/Git_workspace/IC4A2S/Goddard_Problem/2Controls/m.npy" ) Ttref = np.load( "/home/francesco/Desktop/PhD/Git_workspace/IC4A2S/Goddard_Problem/2Controls/Tt.npy" ) Trref = np.load( "/home/francesco/Desktop/PhD/Git_workspace/IC4A2S/Goddard_Problem/2Controls/Tr.npy" ) Rfun = PchipInterpolator(tref, Rref) Thetafun = PchipInterpolator(tref, Thetaref) Vrfun = PchipInterpolator(tref, Vrref) Vtfun = PchipInterpolator(tref, Vtref) mfun = PchipInterpolator(tref, mref) Ttfun = PchipInterpolator(tref, Ttref) Trfun = PchipInterpolator(tref, Trref) def sys2GP(t, x, expr1, expr2, new_Cd, change_t): fTr = toolbox.compileR(expr1) fTt = toolbox.compileT(expr2) if t >= change_t: Cd = new_Cd else:
class BinSmooth: """A binned data smoother. This class implements the method outlined in [1]. It proceeds by fitting a cubic spline to the empirical distribution function of the binned data. Attributes ---------- min_x_: float The minimum value of the empirical distribution function tail_: float The maximum value of the estimated CDF mean_est_: float The estimated mean of the estimated distribution cdf_cs_: func The estimated CDF function inv_cdf_cs_: func The estimated inverse CDF function References ---------- .. [1] P. von Hippel, D. Hunter, M. Drown "Better Estimates from Binned Income Data: Interpolated CDFs and Mean-Matching", 2017. Examples -------- >>> from binsmooth import BinSmooth >>> bin_edges = np.array([0, 18200, 37000, 87000, 180000]) >>> counts = np.array([0, 7527, 13797, 75481, 50646, 803]) >>> bs = BinSmooth() >>> bs.fit(bin_edges, counts) >>> print(bs.inv_cdf(0.5)) 70120.071... """ def fit(self, x, y, m=None, includes_tail=False): """Fit the cubic spline to the data. Parameters ---------- x: ndarray The bin edges y: ndarray The values for each bin m: float The mean of the distribution includes_tail: bool If True then it is assumed that the last value in x is the upper bound of the distribution, otherwise the upper bound is estimated Returns ------- self : object Fitted estimator. """ if includes_tail and len(x) != len(y): raise ValueError( "Length of x and y must match when tail is included" ) if not includes_tail and len(x) != len(y) - 1: raise ValueError( "Length of x must be N-1 when tail is not included" ) if y[0] != 0: raise ValueError("y must begin with 0") if m is None: # Adhoc mean estimate if none supplied if includes_tail: bin_edges = x else: bin_edges = np.concatenate([x[:-1] / 2, [x[-1], x[-1] * 2]]) m = np.average(bin_edges, weights=y / np.sum(y),) warnings.warn("No mean provided, results may be innacurate.") x = x.astype(float) y = y.astype(float) self.min_x_ = x[0] y_ecdf = np.cumsum(y) y_ecdf_normed = y_ecdf / np.max(y_ecdf) if includes_tail is False: # Temporarily set the tail value tail_0 = x[-1] * 2 x_wtail = np.concatenate([x, [tail_0]]) # Search for a tail self.tail_ = minimize( evaluate_tail, tail_0, args=(x_wtail.copy(), y_ecdf_normed, m), bounds=[(180000, None)], method="Powell", options=dict(maxiter=16), ).x[0] x_wtail[-1] = self.tail_ else: if x[-2] >= x[-1]: raise ValueError( "Tail value must be greater than the last bin edge" ) self.tail_ = x[-1] x_wtail = x # Estimate the CDF by fitting a spline self.cdf_cs_ = PchipInterpolator(x_wtail, y_ecdf_normed) self.mean_est_ = estimate_mean(x_wtail[0], x_wtail[-1], self.cdf_cs_) # Approximate inverse CDF by sampling the CDF x_cs = cumdensityspace( self.min_x_, self.tail_, self.cdf_cs_, interp_num=1000 ) y_cs = self.cdf_cs_(x_cs) self.inv_cdf_cs_ = PchipInterpolator(y_cs, x_cs) return self def pdf(self, x): """Estimated PDF. Parameters ---------- x: ndarray Values to calculate the PDF of. Returns ------- pdf : ndarray Estimated PDF values """ return self.cdf_cs_.derivative()(np.clip(x, self.min_x_, self.tail_)) def cdf(self, x): """Estimated CDF. Parameters ---------- x: ndarray Values to calculate the CDF of. Returns ------- cdf : ndarray Estimated CDF values """ return self.cdf_cs_(np.clip(x, self.min_x_, self.tail_)) def inv_cdf(self, percentile): """Estimated inverse CDF. Parameters ---------- percentile: ndarray Values to calculate the inverse CDF of Returns ------- inverse_cdf : ndarray Estimated inverse CDF values """ return self.inv_cdf_cs_(np.clip(percentile, 0, 1))