def draw_streamlines(self, res=200, show=True): fig, ax = plt.subplots(1, 1, figsize=(6.4, 4.8), dpi=200) plt.xlim(-0.5, 1.5) plt.ylim(-0.5, 0.5) xrng = np.diff(np.array(ax.get_xlim())) yrng = np.diff(np.array(ax.get_ylim())) x = np.linspace(*ax.get_xlim(), int(np.round(res * xrng / yrng))) y = np.linspace(*ax.get_ylim(), res) X, Y = np.meshgrid(x, y) shape = X.shape X = X.flatten() Y = Y.flatten() U, V = self.calculate_velocity(X, Y) X = X.reshape(shape) Y = Y.reshape(shape) U = U.reshape(shape) V = V.reshape(shape) # NaN out any points inside the airfoil for airfoil in self.airfoils: contains = airfoil.contains_points(X, Y) U[contains] = np.NaN V[contains] = np.NaN speed = (U**2 + V**2)**0.5 Cp = 1 - speed**2 ### Draw the airfoils for airfoil in self.airfoils: plt.fill(airfoil.x(), airfoil.y(), "k", linewidth=0, zorder=4) plt.streamplot( x, y, U, V, color=speed, density=2.5, arrowsize=0, cmap=plt.get_cmap('coolwarm_r'), ) CB = plt.colorbar( orientation="horizontal", shrink=0.8, aspect=40, ) CB.set_label(r"Relative Airspeed ($U/U_\infty$)") plt.clim(0.6, 1.4) plt.gca().set_aspect('equal', adjustable='box') plt.xlabel(r"$x/c$") plt.ylabel(r"$y/c$") plt.title(rf"Inviscid Airfoil: Flow Field") plt.tight_layout() if show: plt.show()
def draw( self, scalar_to_plot: str = "potential", # "potential", "streamfunction", "xvel", "yvel", "velmag", "Cp" x_points: np.ndarray = np.linspace(-10, 10, 400), y_points: np.ndarray = np.linspace(-10, 10, 300), percentiles_to_include=99.7, show=True, ): X, Y = np.meshgrid(x_points, y_points) X_r = np.reshape(X, -1) Y_r = np.reshape(Y, -1) points = np.vstack((X_r, Y_r)).T if scalar_to_plot == "potential": scalar_to_plot_value = sum( [object.get_potential_at(points) for object in self.objects]) elif scalar_to_plot == "streamfunction": scalar_to_plot_value = sum([ object.get_streamfunction_at(points) for object in self.objects ]) elif scalar_to_plot == "xvel": scalar_to_plot_value = sum( [object.get_x_velocity_at(points) for object in self.objects]) elif scalar_to_plot == "yvel": scalar_to_plot_value = sum( [object.get_y_velocity_at(points) for object in self.objects]) elif scalar_to_plot == "velmag": x_vels = sum( [object.get_x_velocity_at(points) for object in self.objects]) y_vels = sum( [object.get_y_velocity_at(points) for object in self.objects]) scalar_to_plot_value = np.sqrt(x_vels**2 + y_vels**2) elif scalar_to_plot == "Cp": x_vels = sum( [object.get_x_velocity_at(points) for object in self.objects]) y_vels = sum( [object.get_y_velocity_at(points) for object in self.objects]) V = np.sqrt(x_vels**2 + y_vels**2) scalar_to_plot_value = 1 - V**2 else: raise ValueError("Bad value of `scalar_to_plot`!") min = np.nanpercentile(scalar_to_plot_value, 50 - percentiles_to_include / 2) max = np.nanpercentile(scalar_to_plot_value, 50 + percentiles_to_include / 2) contour(x_points, y_points, scalar_to_plot_value.reshape(X.shape), levels=np.linspace(min, max, 80), linelabels=False, cmap=plt.get_cmap("rainbow"), contour_kwargs={ "linestyles": 'solid', "alpha": 0.4 }) plt.gca().set_aspect("equal", adjustable='box') show_plot(f"Potential Flow: {scalar_to_plot}", "$x$", "$y$", show=show)
def test_interpn_fill_value(): def value_func_3d(x, y, z): return 2 * x + 3 * y - z x = np.linspace(0, 5, 10) y = np.linspace(0, 5, 20) z = np.linspace(0, 5, 30) points = (x, y, z) values = value_func_3d(*np.meshgrid(*points, indexing="ij")) point = np.array([5.21, 3.12, 1.15]) value = np.interpn( points, values, point, method="bspline", bounds_error=False, fill_value=-17 ) assert value == pytest.approx(-17) value = np.interpn( points, values, point, method="bspline", bounds_error=False, ) assert np.isnan(value) value = np.interpn( points, values, point, method="bspline", bounds_error=None, fill_value=None ) assert value == pytest.approx(value_func_3d(5, 3.12, 1.15))
def test_interpn_bounds_error_multiple_samples(): def value_func_3d(x, y, z): return 2 * x + 3 * y - z x = np.linspace(0, 5, 10) y = np.linspace(0, 5, 20) z = np.linspace(0, 5, 30) points = (x, y, z) values = value_func_3d(*np.meshgrid(*points, indexing="ij")) point = np.array([ [2.21, 3.12, 1.15], [3.42, 5.81, 2.43] ]) with pytest.raises(ValueError): value = np.interpn( points, values, point ) ### CasADi test point = cas.DM(point) with pytest.raises(ValueError): value = np.interpn( points, values, point )
def plot(self, resolution=250): def axis_range(x_data_axis: np.ndarray) -> Tuple[float, float]: """ Given the entries of one axis of the dependent variable, determine a min/max range over which to plot the fit. Args: x_data_axis: The entries of one axis of the dependent variable, i.e. x_data["x1"]. Returns: A tuple representing the (min, max) value over which to plot that axis. """ minval = np.min(x_data_axis) maxval = np.max(x_data_axis) return (minval, maxval) if self.input_dimensionality() == 1: ### Parse the x_data if self.input_names() is not None: x_name = self.x_data.keys()[0] x_data = self.x_data.values()[0] minval, maxval = axis_range(x_data) x_fit = {x_name: np.linspace(minval, maxval, resolution)} y_fit = self(x_fit) else: x_name = "x" x_data = self.x_data minval, maxval = axis_range(x_data) x_fit = np.linspace(minval, maxval, resolution) y_fit = self(x_fit) ### Plot the 2D figure fig = plt.figure(dpi=200) plt.plot( x_data, self.y_data, ".k", label="Data", ) plt.plot( x_fit, y_fit, "-", color="#cb3bff", label="Fit", zorder=4, ) plt.xlabel(x_name) plt.ylabel(rf"$f({x_name})$") plt.title(r"Fit of FittedModel") plt.tight_layout() plt.legend() plt.show() else: raise NotImplementedError()
def plot_tropopause_altitude(): fig, ax = plt.subplots() day_of_years = np.linspace(0, 365, 250) latitudes = np.linspace(-80, 80, 200) Day_of_years, Latitudes = np.meshgrid(day_of_years, latitudes) trop_alt = tropopause_altitude( Latitudes.flatten(), Day_of_years.flatten() ).reshape(Latitudes.shape) args = [ day_of_years, latitudes, trop_alt / 1e3 ] levels = np.arange(10, 20.1, 1) CS = plt.contour(*args, levels=levels, linewidths=0.5, colors="k", alpha=0.7) CF = plt.contourf(*args, levels=levels, cmap='viridis_r', alpha=0.7, extend="both") cbar = plt.colorbar(label="Tropopause Altitude [km]", extendrect=True) ax.clabel(CS, inline=1, fontsize=9, fmt="%.0f km") plt.xticks( np.linspace(0, 365, 13)[:-1], ( "Jan. 1", "Feb. 1", "Mar. 1", "Apr. 1", "May 1", "June 1", "July 1", "Aug. 1", "Sep. 1", "Oct. 1", "Nov. 1", "Dec. 1" ), rotation=40 ) lat_label_vals = np.arange(-80, 80.1, 20) lat_labels = [] for lat in lat_label_vals: if lat >= 0: lat_labels.append(f"{lat:.0f}N") else: lat_labels.append(f"{-lat:.0f}S") plt.yticks( lat_label_vals, lat_labels ) show_plot( f"Tropopause Altitude by Season and Latitude", xlabel="Day of Year", ylabel="Latitude", )
def test_opti_hanging_chain_with_callback(plot=False): N = 40 m = 40 / N D = 70 * N g = 9.81 L = 1 opti = asb.Opti() x = opti.variable(init_guess=np.linspace(-2, 2, N)) y = opti.variable( init_guess=1, n_vars=N, ) distance = np.sqrt( # Distance from one node to the next np.diff(x)**2 + np.diff(y)**2) potential_energy_spring = 0.5 * D * np.sum((distance - L / N)**2) potential_energy_gravity = g * m * np.sum(y) potential_energy = potential_energy_spring + potential_energy_gravity opti.minimize(potential_energy) # Add end point constraints opti.subject_to([x[0] == -2, y[0] == 1, x[-1] == 2, y[-1] == 1]) # Add a ground constraint opti.subject_to(y >= np.cos(0.1 * x) - 0.5) # Add a callback if plot: def my_callback(iter: int): plt.plot(opti.debug.value(x), opti.debug.value(y), ".-", label=f"Iter {iter}", zorder=3 + iter) fig, ax = plt.subplots(1, 1, figsize=(6.4, 4.8), dpi=200) x_ground = np.linspace(-2, 2, N) y_ground = np.cos(0.1 * x_ground) - 0.5 plt.plot(x_ground, y_ground, "--k", zorder=2) else: def my_callback(iter: int): print(f"Iter {iter}") print(f"\tx = {opti.debug.value(x)}") print(f"\ty = {opti.debug.value(y)}") sol = opti.solve(callback=my_callback) assert sol.value(potential_energy) == pytest.approx(626.462, abs=1e-3) if plot: plt.show()
def test_quadcopter_navigation(): opti = asb.Opti() N = 300 time_final = 1 time = np.linspace(0, time_final, N) left_thrust = opti.variable(init_guess=0.5, scale=1, n_vars=N, lower_bound=0, upper_bound=1) right_thrust = opti.variable(init_guess=0.5, scale=1, n_vars=N, lower_bound=0, upper_bound=1) mass = 0.1 dyn = asb.FreeBodyDynamics( opti_to_add_constraints_to=opti, time=time, xe=opti.variable(init_guess=np.linspace(0, 1, N)), ze=opti.variable(init_guess=np.linspace(0, -1, N)), u=opti.variable(init_guess=0, n_vars=N), w=opti.variable(init_guess=0, n_vars=N), theta=opti.variable(init_guess=np.linspace(np.pi / 2, np.pi / 2, N)), q=opti.variable(init_guess=0, n_vars=N), X=left_thrust + right_thrust, M=(right_thrust - left_thrust) * 0.1 / 2, mass=mass, Iyy=0.5 * mass * 0.1 ** 2, g=9.81, ) opti.subject_to([ # Starting state dyn.xe[0] == 0, dyn.ze[0] == 0, dyn.u[0] == 0, dyn.w[0] == 0, dyn.theta[0] == np.radians(90), dyn.q[0] == 0, ]) opti.subject_to([ # Final state dyn.xe[-1] == 1, dyn.ze[-1] == -1, dyn.u[-1] == 0, dyn.w[-1] == 0, dyn.theta[-1] == np.radians(90), dyn.q[-1] == 0, ]) effort = np.sum( # The average "effort per second", where effort is integrated as follows: np.trapz(left_thrust ** 2 + right_thrust ** 2) * np.diff(time) ) / time_final opti.minimize(effort) sol = opti.solve() dyn.substitute_solution(sol) assert sol.value(effort) == pytest.approx(0.714563, rel=0.01) print(sol.value(effort))
def test_block_move_fixed_time(): opti = asb.Opti() n_timesteps = 300 time = np.linspace(0, 1, n_timesteps) dyn = asb.DynamicsPointMass1DHorizontal( mass_props=asb.MassProperties(mass=1), x_e=opti.variable(init_guess=np.linspace(0, 1, n_timesteps)), u_e=opti.variable(init_guess=1, n_vars=n_timesteps), ) u = opti.variable(init_guess=np.linspace(1, -1, n_timesteps)) dyn.add_force( Fx=u ) dyn.constrain_derivatives( opti=opti, time=time ) opti.subject_to([ dyn.x_e[0] == 0, dyn.x_e[-1] == 1, dyn.u_e[0] == 0, dyn.u_e[-1] == 0, ]) # effort = np.sum( # np.trapz(dyn.X ** 2) * np.diff(time) # ) effort = np.sum( # More sophisticated integral-of-squares integration (closed form correct) np.diff(time) / 3 * (u[:-1] ** 2 + u[:-1] * u[1:] + u[1:] ** 2) ) opti.minimize(effort) sol = opti.solve() dyn.substitute_solution(sol) assert dyn.x_e[0] == pytest.approx(0) assert dyn.x_e[-1] == pytest.approx(1) assert dyn.u_e[0] == pytest.approx(0) assert dyn.u_e[-1] == pytest.approx(0) assert np.max(dyn.u_e) == pytest.approx(1.5, abs=0.01) assert sol.value(u)[0] == pytest.approx(6, abs=0.05) assert sol.value(u)[-1] == pytest.approx(-6, abs=0.05)
def test_quadcopter_flip(): opti = asb.Opti() N = 300 time_final = opti.variable(init_guess=1, lower_bound=0) time = np.linspace(0, time_final, N) left_thrust = opti.variable(init_guess=0.7, scale=1, n_vars=N, lower_bound=0, upper_bound=1) right_thrust = opti.variable(init_guess=0.6, scale=1, n_vars=N, lower_bound=0, upper_bound=1) mass = 0.1 dyn = asb.FreeBodyDynamics( opti_to_add_constraints_to=opti, time=time, xe=opti.variable(init_guess=np.linspace(0, 1, N)), ze=opti.variable(init_guess=0, n_vars=N), u=opti.variable(init_guess=0, n_vars=N), w=opti.variable(init_guess=0, n_vars=N), theta=opti.variable(init_guess=np.linspace(np.pi / 2, np.pi / 2 - 2 * np.pi, N)), q=opti.variable(init_guess=0, n_vars=N), X=left_thrust + right_thrust, M=(right_thrust - left_thrust) * 0.1 / 2, mass=mass, Iyy=0.5 * mass * 0.1 ** 2, g=9.81, ) opti.subject_to([ # Starting state dyn.xe[0] == 0, dyn.ze[0] == 0, dyn.u[0] == 0, dyn.w[0] == 0, dyn.theta[0] == np.radians(90), dyn.q[0] == 0, ]) opti.subject_to([ # Final state dyn.xe[-1] == 1, dyn.ze[-1] == 0, dyn.u[-1] == 0, dyn.w[-1] == 0, dyn.theta[-1] == np.radians(90 - 360), dyn.q[-1] == 0, ]) opti.minimize(time_final) sol = opti.solve(verbose=False) dyn.substitute_solution(sol) assert sol.value(time_final) == pytest.approx(0.824, abs=0.01)
def test_block_move_minimum_time(): opti = asb.Opti() n_timesteps = 300 time = np.linspace( 0, opti.variable(init_guess=1, lower_bound=0), n_timesteps, ) dyn = asb.DynamicsPointMass1DHorizontal( mass_props=asb.MassProperties(mass=1), x_e=opti.variable(init_guess=np.linspace(0, 1, n_timesteps)), u_e=opti.variable(init_guess=1, n_vars=n_timesteps), ) u = opti.variable(init_guess=np.linspace(1, -1, n_timesteps), lower_bound=-1, upper_bound=1) dyn.add_force( Fx=u ) dyn.constrain_derivatives( opti=opti, time=time ) opti.subject_to([ dyn.x_e[0] == 0, dyn.x_e[-1] == 1, dyn.u_e[0] == 0, dyn.u_e[-1] == 0, ]) opti.minimize( time[-1] ) sol = opti.solve() dyn.substitute_solution(sol) assert dyn.x_e[0] == pytest.approx(0) assert dyn.x_e[-1] == pytest.approx(1) assert dyn.u_e[0] == pytest.approx(0) assert dyn.u_e[-1] == pytest.approx(0) assert np.max(dyn.u_e) == pytest.approx(1, abs=0.01) assert sol.value(u)[0] == pytest.approx(1, abs=0.05) assert sol.value(u)[-1] == pytest.approx(-1, abs=0.05) assert np.mean(np.abs(sol.value(u))) == pytest.approx(1, abs=0.01)
def plot_winds_at_tropopause_altitude(): fig, ax = plt.subplots() day_of_years = np.linspace(0, 365, 150) latitudes = np.linspace(-80, 80, 120) Day_of_years, Latitudes = np.meshgrid(day_of_years, latitudes) winds = wind_speed_world_95( altitude=tropopause_altitude(Latitudes.flatten(), Day_of_years.flatten()), latitude=Latitudes.flatten(), day_of_year=Day_of_years.flatten(), ).reshape(Latitudes.shape) args = [day_of_years, latitudes, winds] levels = np.arange(0, 80.1, 5) CS = plt.contour(*args, levels=levels, linewidths=0.5, colors="k", alpha=0.7) CF = plt.contourf(*args, levels=levels, cmap='viridis_r', alpha=0.7, extend="max") cbar = plt.colorbar(label="Wind Speed [m/s]", extendrect=True) ax.clabel(CS, inline=1, fontsize=9, fmt="%.0f m/s") plt.xticks( np.linspace(0, 365, 13)[:-1], ("Jan. 1", "Feb. 1", "Mar. 1", "Apr. 1", "May 1", "June 1", "July 1", "Aug. 1", "Sep. 1", "Oct. 1", "Nov. 1", "Dec. 1"), rotation=40) lat_label_vals = np.arange(-80, 80.1, 20) lat_labels = [] for lat in lat_label_vals: if lat >= 0: lat_labels.append(f"{lat:.0f}N") else: lat_labels.append(f"{-lat:.0f}S") plt.yticks(lat_label_vals, lat_labels) show_plot( f"95th-Percentile Wind Speeds at Tropopause Altitude", xlabel="Day of Year", ylabel="Latitude", )
def test_fit_model_weighting(): x = np.linspace(0, 10) y = np.sin(x) fm = FittedModel( model=lambda x, p: p["m"] * x + p["b"], x_data=x, y_data=y, parameter_guesses={ "m": 0, "b": 0, }, weights=None ) # Fit a model with no weighting assert fm(10) != pytest.approx(5, abs=1) # Doesn't give a high value at x = 10 fm = FittedModel( model=lambda x, p: p["m"] * x + p["b"], x_data=x, y_data=y, parameter_guesses={ "m": 0, "b": 0, }, weights=(x > 0) & (x < 2) ) # Fit a model with weighting assert fm(10) == pytest.approx(5, abs=1) # Gives a high value at x = 10 fm.plot()
def interpolated_model(): np.random.seed(0) # Set a seed for repeatability. ### Make some data x1 = np.linspace(0, 10, 11) x2 = np.linspace(0, 10, 21) X1, X2 = np.meshgrid(x1, x2, indexing="ij") return InterpolatedModel( x_data_coordinates={ "x1": x1, "x2": x2, }, y_data_structured=underlying_function_2D(X1, X2), )
def test_rosenbrock_constrained(plot=False): opti = asb.Opti() x = opti.variable(init_guess=0) y = opti.variable(init_guess=0) r = opti.parameter() f = (1 - x)**2 + (y - x**2)**2 opti.minimize(f) con = x**2 + y**2 <= r dual = opti.subject_to(con) r_values = np.linspace(1, 3) sols = [opti.solve({r: r_value}) for r_value in r_values] fs = [sol.value(f) for sol in sols] duals = [ sol.value(dual) # Ensure the dual can be evaluated for sol in sols ] if plot: fig, ax = plt.subplots(1, 1, figsize=(6.4, 4.8), dpi=200) plt.plot(r_values, fs, label="$f$") plt.plot(r_values, duals, label=r"Dual var. ($\frac{df}{dr}$)") plt.legend() plt.xlabel("$r$") plt.show() assert dual is not None # The dual should be a real value assert r_values[0] == pytest.approx(1) assert duals[0] == pytest.approx(0.10898760051521068, abs=1e-6)
def test_Linf_without_x_in_dict(): np.random.seed(0) # Set a seed for repeatability ### Making data hour = np.linspace(1, 10, 100) noise = 0.1 * np.random.randn(len(hour)) temperature_c = np.log(hour) + noise ### Fit def model(x, p): return p["m"] * x + p["b"] x_data = hour y_data = temperature_c fitted_model = FittedModel( model=model, x_data=x_data, y_data=y_data, parameter_guesses={ "m": 0, "b": 0, }, residual_norm_type="Linf", ) # Check that the fit is right assert fitted_model.parameters["m"] == pytest.approx(0.247116, abs=1e-5) assert fitted_model.parameters["b"] == pytest.approx(0.227797, abs=1e-5)
def test_softmax(plot=False): # Test softmax x = np.linspace(-10, 10, 100) y1 = x y2 = -2 * x - 3 hardness = 0.5 y_soft = np.softmax(y1, y2, hardness=hardness) assert np.softmax(0, 0, hardness=1) == np.log(2) if plot: import matplotlib.pyplot as plt import seaborn as sns sns.set(font_scale=1) fig, ax = plt.subplots(1, 1, figsize=(6.4, 4.8), dpi=200) plt.plot(x, y1, label="y1") plt.plot(x, y2, label="y2") plt.plot(x, y_soft, label="softmax") plt.xlabel(r"x") plt.ylabel(r"y") plt.title(r"Softmax") plt.tight_layout() plt.legend() plt.show()
def test_calculate_induced_velocity_panel_coordinates(): X, Y = np.meshgrid( np.linspace(-1, 2, 50), np.linspace(-1, 1, 50), indexing='ij', ) X = X.flatten() Y = Y.flatten() U, V = calculate_induced_velocity_line_singularities( x_field=X, y_field=Y, x_panels=np.array([-0.5, 1.5]), y_panels=np.array([0, 0]), gamma=np.array([1, 1]), sigma=np.array([1, 1]), )
def test_rocket_control_problem(plot=False): ### Constants T = 100 d = 50 delta = 1e-3 f = 1000 c = np.ones(T) ### Optimization opti = asb.Opti() # set up an optimization environment x = opti.variable(init_guess=np.linspace(0, d, T)) # position v = opti.variable(init_guess=d / T, n_vars=T) # velocity a = opti.variable(init_guess=0, n_vars=T) # acceleration gamma = opti.variable(init_guess=0, n_vars=T) # instantaneous fuel consumption a_max = opti.variable(init_guess=0) # maximum acceleration opti.subject_to([ cas.diff(x) == v[:-1], # physics cas.diff(v) == a[:-1], # physics x[0] == 0, # boundary condition v[0] == 0, # boundary condition x[-1] == d, # boundary condition v[-1] == 0, # boundary condition gamma >= c * a, # lower bound on instantaneous fuel consumption gamma >= -c * a, # lower bound on instantaneous fuel consumption cas.sum1(gamma) <= f, # fuel consumption limit cas.diff(a) <= delta, # jerk limits cas.diff(a) >= -delta, # jerk limits a_max >= a, # lower bound on maximum acceleration a_max >= -a, # lower bound on maximum acceleration ]) opti.minimize(a_max) # minimize the peak acceleration sol = opti.solve() # solve assert sol.value(a_max) == pytest.approx( 0.02181991952, rel=1e-3) # solved externally with Julia JuMP if plot: import matplotlib.pyplot as plt import seaborn as sns sns.set(palette=sns.color_palette("husl")) fig, ax = plt.subplots(1, 1, figsize=(8, 6), dpi=200) for i, val, lab in zip(np.arange(3), [x, v, a], ["$x$", "$v$", "$a$"]): plt.subplot(3, 1, i + 1) plt.plot(sol.value(val), label=lab) plt.xlabel(r"Time [s]") plt.ylabel(lab) plt.legend() plt.suptitle(r"Rocket Trajectory") plt.tight_layout() plt.show()
def interpolated_model(): np.random.seed(0) # Set a seed for repeatability. ### Make some data x = np.linspace(0, 10, 11) return InterpolatedModel( x_data_coordinates=x, y_data_structured=underlying_function_1D(x), )
def test_interpn_linear_multiple_samples(): ### NumPy test def value_func_3d(x, y, z): return 2 * x + 3 * y - z x = np.linspace(0, 5, 10) y = np.linspace(0, 5, 20) z = np.linspace(0, 5, 30) points = (x, y, z) values = value_func_3d(*np.meshgrid(*points, indexing="ij")) point = np.array([ [2.21, 3.12, 1.15], [3.42, 0.81, 2.43] ]) value = np.interpn( points, values, point ) assert np.all( value == pytest.approx( value_func_3d( *[ point[:, i] for i in range(point.shape[1]) ] ) ) ) assert len(value) == 2 ### CasADi test point = cas.DM(point) value = np.interpn( points, values, point ) value_actual = value_func_3d( *[ np.array(point[:, i]) for i in range(point.shape[1]) ] ) for i in range(len(value)): assert value[i] == pytest.approx(float(value_actual[i])) assert value.shape == (2,)
def plot_winds_at_day(day_of_year=0): fig, ax = plt.subplots() altitudes = np.linspace(0, 30000, 150) latitudes = np.linspace(-80, 80, 120) Altitudes, Latitudes = np.meshgrid(altitudes, latitudes) winds = wind_speed_world_95( altitude=Altitudes.flatten(), latitude=Latitudes.flatten(), day_of_year=day_of_year * np.ones_like(Altitudes.flatten()), ).reshape(Altitudes.shape) args = [altitudes / 1e3, latitudes, winds] levels = np.arange(0, 80.1, 5) CS = plt.contour(*args, levels=levels, linewidths=0.5, colors="k", alpha=0.7) CF = plt.contourf(*args, levels=levels, cmap='viridis_r', alpha=0.7, extend="max") cbar = plt.colorbar(label="Wind Speed [m/s]", extendrect=True) ax.clabel(CS, inline=1, fontsize=9, fmt="%.0f m/s") lat_label_vals = np.arange(-80, 80.1, 20) lat_labels = [] for lat in lat_label_vals: if lat >= 0: lat_labels.append(f"{lat:.0f}N") else: lat_labels.append(f"{-lat:.0f}S") plt.yticks(lat_label_vals, lat_labels) show_plot( f"95th-Percentile Wind Speeds at Day {day_of_year:.0f}", xlabel="Altitude [km]", ylabel="Latitude", )
def plot_underlying_function(): import matplotlib.pyplot as plt import seaborn as sns sns.set(palette=sns.color_palette("husl")) x = np.linspace(-10, 10, 500) f = underlying_function(x) fig, ax = plt.subplots(1, 1, figsize=(6.4, 4.8), dpi=200) plt.plot(x, f) plt.title("Underlying Function") plt.show()
def contour( func: Callable, x_range: Tuple[Union[float,int],Union[float,int]], y_range: Tuple[Union[float,int],Union[float,int]], resolution:int =50, show:bool=True, # type: bool ): """ Makes a contour plot of a function of 2 variables. Can also plot a list of functions. :param func: function of form f(x,y) to plot. :param x_range: Range of x values to plot, expressed as a tuple (x_min, x_max) :param y_range: Range of y values to plot, expressed as a tuple (y_min, y_max) :param resolution: Resolution in x and y to plot. [int] :param show: Should we show the plot? :return: """ fig, ax = plt.subplots(1, 1, figsize=(6.4, 4.8), dpi=200) x = np.linspace(x_range[0], x_range[1], resolution) y = np.linspace(y_range[0], y_range[1], resolution) # TODO finish function
def main(): time = np.linspace(0, 10, 100) # Time in seconds wing_velocity = 2 # Wing horizontal velocity in m/s chord = 2 reduced_time = calculate_reduced_time( time, wing_velocity, chord) # Number of semi chords travelled # Visualize the gust profiles as well as the pitch maneuvers fig, ax1 = plt.subplots(dpi=300) ln1 = ax1.plot(reduced_time, np.array([top_hat_gust(s) for s in reduced_time]), label="Top-Hat Gust", lw=3) ln2 = ax1.plot(reduced_time, np.array([sine_squared_gust(s) for s in reduced_time]), label="Sine-Squared Gust", lw=3) ax1.set_xlabel("Reduced time") ax1.set_ylabel("Velocity (m/s)") ax2 = ax1.twinx() ln3 = ax2.plot(reduced_time, np.array([gaussian_pitch(s) for s in reduced_time]), label="Guassian Pitch", c="red", ls="--", lw=3) ax2.set_ylabel("Angle of Attack, degrees") lns = ln1 + ln2 + ln3 labs = [l.get_label() for l in lns] ax2.legend(lns, labs, loc="lower right") plt.title("Gust and pitch example profiles") total_lift = pitching_through_transverse_gust(reduced_time, top_hat_gust, wing_velocity, gaussian_pitch) gust_lift = calculate_lift_due_to_transverse_gust(reduced_time, top_hat_gust, wing_velocity, gaussian_pitch) pitch_lift = calculate_lift_due_to_pitching_profile( reduced_time, gaussian_pitch) added_mass_lift = added_mass_due_to_pitching(reduced_time, gaussian_pitch) # Visualize the different sources of lift plt.figure(dpi=300) plt.plot(reduced_time, total_lift, label="Total Lift", lw=2) plt.plot(reduced_time, gust_lift, label="Gust Lift", lw=2) plt.plot(reduced_time, pitch_lift, label="Pitching Lift", lw=2) plt.plot(reduced_time, added_mass_lift, label="Added Mass Lift", lw=2) plt.legend() plt.xlabel("Reduced time") plt.ylabel("$C_\ell$") plt.title("Guassian Pitch Maneuver Through Top-Hat Gust")
def max_thickness( self, x_over_c_sample: np.ndarray = np.linspace(0, 1, 101)) -> float: """ Returns the maximum thickness of the airfoil. Args: x_over_c_sample: Where should the airfoil be sampled to determine the max thickness? Returns: The maximum thickness, as a fraction of chord. """ return np.max(self.local_thickness(x_over_c=x_over_c_sample))
def draw(self, draw_mcl=True, backend="matplotlib", show=True): """ Draw the airfoil object. :param draw_mcl: Should we draw the mean camber line (MCL)? [boolean] :param backend: Which backend should we use? "plotly" or "matplotlib" :return: None """ x = np.array(self.x()).reshape(-1) y = np.array(self.y()).reshape(-1) if draw_mcl: x_mcl = np.linspace(np.min(x), np.max(x), len(x)) y_mcl = self.local_camber(x_mcl) if backend == "matplotlib": color = '#280887' plt.plot(x, y, ".-", zorder=11, color=color) plt.fill(x, y, zorder=10, color=color, alpha=0.2) if draw_mcl: plt.plot(x_mcl, y_mcl, "-", zorder=4, color=color, alpha=0.4) plt.axis("equal") plt.xlabel(r"$x/c$") plt.ylabel(r"$y/c$") plt.title(f"{self.name} Airfoil") plt.tight_layout() if show: plt.show() elif backend == "plotly": from aerosandbox.visualization.plotly import go fig = go.Figure() fig.add_trace( go.Scatter(x=x, y=y, mode="lines+markers", name="Airfoil", fill="toself", line=dict(color="blue")), ) if draw_mcl: fig.add_trace( go.Scatter(x=x_mcl, y=y_mcl, mode="lines+markers", name="Mean Camber Line (MCL)", line=dict(color="navy"))) fig.update_layout(xaxis_title="x/c", yaxis_title="y/c", yaxis=dict(scaleanchor="x", scaleratio=1), title=f"{self.name} Airfoil") if show: fig.show() else: return fig
def test_interpn_bspline_casadi(): """ The bspline method should interpolate seperable cubic multidimensional polynomials exactly. """ def func(x, y, z): # Sphere function return x ** 3 + y ** 3 + z ** 3 x = np.linspace(-5, 5, 10) y = np.linspace(-5, 5, 20) z = np.linspace(-5, 5, 30) points = (x, y, z) values = func( *np.meshgrid(*points, indexing="ij") ) point = np.array([0.4, 0.5, 0.6]) value = np.interpn( points, values, point, method="bspline" ) assert value == pytest.approx(func(*point))
def test_diff_atmosphere(): altitudes = np.linspace(-50e2, 150e3, 1000) atmo_isa = Atmosphere(altitude=altitudes, method='isa') atmo_diff = Atmosphere(altitude=altitudes) temp_isa = atmo_isa.temperature() pressure_isa = atmo_isa.pressure() temp_diff = atmo_diff.temperature() pressure_diff = atmo_diff.pressure() assert max(abs( (temp_isa - temp_diff) / temp_isa)) < 0.025, "temperature failed for differentiable model" assert max(abs( (pressure_isa - pressure_diff) / pressure_isa)) < 0.01, "pressure failed for differentiable model"
def draw(self, draw_mcl=True, backend="plotly", show=True): """ Draw the airfoil object. :param draw_mcl: Should we draw the mean camber line (MCL)? [boolean] :param backend: Which backend should we use? "plotly" or "matplotlib" :return: None """ x = np.array(self.x()).reshape(-1) y = np.array(self.y()).reshape(-1) if draw_mcl: x_mcl = np.linspace(np.min(x), np.max(x), len(x)) y_mcl = self.local_camber(x_mcl) if backend == "plotly": fig = go.Figure() fig.add_trace( go.Scatter(x=x, y=y, mode="lines+markers", name="Airfoil", fill="toself", line=dict(color="blue")), ) if draw_mcl: fig.add_trace( go.Scatter(x=x_mcl, y=y_mcl, mode="lines+markers", name="Mean Camber Line (MCL)", line=dict(color="navy"))) fig.update_layout(xaxis_title="x/c", yaxis_title="y/c", yaxis=dict(scaleanchor="x", scaleratio=1), title="%s Airfoil" % self.name) if show: fig.show() else: return fig elif backend == "matplotlib": fig, ax = plt.subplots(1, 1, figsize=(6.4, 4.8), dpi=200) plt.plot(x, y, ".-", zorder=11, color='#280887') if draw_mcl: plt.plot(x_mcl, y_mcl, "-", zorder=4, color='#28088744') plt.axis("equal") plt.xlabel(r"$x/c$") plt.ylabel(r"$y/c$") plt.title("%s Airfoil" % self.name) plt.tight_layout() if show: plt.show() else: return fig, ax