{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import manganite\n", "%load_ext manganite" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Airfoil Analysis\n", "# with [AeroSandbox](https://github.com/peterdsharpe/AeroSandbox) and [Manganite](https://github.com/LCL-CAVE/manganite)\n", "\n", "## Description\n", "\n", "The Airfoil Design Demonstration Dashboard is a web-based showcase that provides a glimpse into the capabilities of airfoil analysis within a browser environment. It is built upon the open-source repository [AeroSandbox](https://github.com/peterdsharpe/Automotive-Airfoil-Design/) and serves as a demonstration of what's possible in the realm of virtual airfoil exploration.\n", "\n", "### Key Features\n", "\n", "1. **Geometry Visualization:** Explore an interactive airfoil geometry, pre-defined for demonstration purposes. Observe how changes in shape and size can impact aerodynamic behavior.\n", "\n", "2. **Simplified Angle of Attack:** Adjust the angle of attack within a limited range to see the immediate effects on lift and drag forces. \n", "\n", "3. **Kulfan Coordinates:** This demonstration employs Kulfan coordinates for the representation of airfoil shapes, providing insight into how airfoil data can be structured and analyzed.\n", "\n", "4. **Basic Constant Display:** View simplified constant values such as lift coefficient (CL), drag coefficient (CD), and moment coefficient (CM).\n", "\n", "5. **Visualization:** Visualize how changes in airfoil geometry and angle of attack influence aerodynamic characteristics." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import plotly.express as px\n", "import plotly.graph_objects as go\n", "import aerosandbox as asb\n", "import aerosandbox.numpy as np\n", "import copy\n", "import plotly.figure_factory as ff\n", "import pandas as pd" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%mnn widget --type slider -20:20:0.1 --tab \"Operating Conditions\" --header \"Angle of Attack\" --var alpha\n", "alpha = 8.7" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "streamline_density = 1\n", "height = 0\n", "ground_effect = False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%mnn widget --type slider -0.1:0.7:0.01 --tab \"Shape Parameters\" --header \"Upper surface 1\" --var upper_1 --position 0 0 2\n", "upper_1 = 0.25" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%mnn widget --type slider -0.1:0.7:0.01 --tab \"Shape Parameters\" --header \"Upper surface 2\" --var upper_2 --position 0 2 2\n", "upper_2 = 0.47" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%mnn widget --type slider -0.1:0.7:0.01 --tab \"Shape Parameters\" --header \"Upper surface 3\" --var upper_3 --position 0 4 2\n", "upper_3 = 0.024" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%mnn widget --type slider -0.5:0.3:0.01 --tab \"Shape Parameters\" --header \"Lower surface 1\" --var lower_1 --position 1 0 2\n", "lower_1 = -0.11" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%mnn widget --type slider 0:0.7:0.01 --tab \"Shape Parameters\" --header \"Lower surface 2\" --var lower_2 --position 1 2 2\n", "lower_2 = 0.06" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%mnn widget --type slider 0:0.7:0.01 --tab \"Shape Parameters\" --header \"Lower surface 3\" --var lower_3 --position 1 4 2\n", "lower_3 = -0.06" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def display_graph(n_clicks, alpha, height, streamline_density, kulfan_upper, kulfan_lower, analyze_button_pressed = False):\n", "\n", " ### Start constructing the figure\n", " airfoil = asb.Airfoil(\n", " coordinates=asb.get_kulfan_coordinates(\n", " lower_weights=np.array(lower_values),\n", " upper_weights=np.array(upper_values),\n", " TE_thickness=0,\n", " enforce_continuous_LE_radius=False,\n", " n_points_per_side=200\n", " )\n", " )\n", "\n", " # ### Do coordinates output\n", " # coordinates_output = \"\\n\".join(\n", " # [\"```\"] +\n", " # [\"AeroSandbox Airfoil\"] +\n", " # [\"\\t%f\\t%f\" % tuple(coordinate) for coordinate in airfoil.coordinates] +\n", " # [\"```\"]\n", " # )\n", "\n", " ### Continue doing the airfoil things\n", " airfoil = airfoil.rotate(angle=-np.radians(alpha))\n", " airfoil = airfoil.translate(\n", " 0,\n", " height + 0.5 * np.sind(alpha)\n", " )\n", " fig = go.Figure()\n", " fig.add_trace(\n", " go.Scatter(\n", " x=airfoil.x(),\n", " y=airfoil.y(),\n", " mode=\"lines\",\n", " name=\"Airfoil\",\n", " fill=\"toself\",\n", " line=dict(\n", " color=\"blue\"\n", " )\n", " )\n", " )\n", "\n", " ### Default text output\n", " text_output = 'Click \"Analyze\" to compute aerodynamics!'\n", " output = text_output\n", "\n", " xrng = (-0.5, 1.5)\n", " yrng = (-0.6, 0.6) if not ground_effect else (0, 1.2)\n", "\n", " if analyze_button_pressed:\n", "\n", " analysis = asb.AirfoilInviscid(\n", " airfoil=airfoil.repanel(50),\n", " op_point=asb.OperatingPoint(\n", " velocity=1,\n", " alpha=0,\n", " ),\n", " ground_effect=ground_effect\n", " )\n", "\n", " x = np.linspace(*xrng, 100)\n", " y = np.linspace(*yrng, 100)\n", " X, Y = np.meshgrid(x, y)\n", " u, v = analysis.calculate_velocity(\n", " x_field=X.flatten(),\n", " y_field=Y.flatten()\n", " )\n", " U = u.reshape(X.shape)\n", " V = v.reshape(Y.shape)\n", "\n", " streamline_fig = ff.create_streamline(\n", " x, y, U, V,\n", " arrow_scale=1e-16,\n", " density=streamline_density,\n", " line=dict(\n", " color=\"#ff82a3\"\n", " ),\n", " name=\"Streamlines\"\n", " )\n", "\n", " fig = go.Figure(\n", " data=streamline_fig.data + fig.data\n", " )\n", "\n", " output = pd.DataFrame(\n", " {\n", " \"Engineering Quantity\": [\n", " \"C_L\"\n", " ],\n", " \"Value\" : [\n", " f\"{analysis.Cl:.3f}\"\n", " ]\n", " }\n", " )\n", "\n", " fig.update_layout(\n", " xaxis_title=\"x/c\",\n", " yaxis_title=\"y/c\",\n", " showlegend=False,\n", " yaxis=dict(scaleanchor=\"x\", scaleratio=1),\n", " margin={'t': 0},\n", " title=None,\n", " )\n", "\n", " fig.update_xaxes(range=xrng)\n", " fig.update_yaxes(range=yrng)\n", "\n", " return fig, output" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%mnn widget --type plot --var aero_fig --tab \"Shape Parameters\" --header \"Airfoil Cross section\" --position 2 0 6\n", "upper_values = [upper_1, upper_2,upper_3]\n", "lower_values = [lower_1, lower_2, lower_3]\n", "aero_fig, text_output = display_graph(1,alpha=alpha,height=0,streamline_density=streamline_density, kulfan_upper=upper_values, kulfan_lower=lower_values)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%mnn execute --on button \"Analyze\" --returns aero_performance\n", "\n", "aero_fig_lines, aero_performance = display_graph(1,alpha=alpha,height=0,streamline_density=streamline_density, kulfan_upper=upper_values, kulfan_lower=lower_values, analyze_button_pressed = True)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%mnn widget --type plot --var aero_fig_lines --tab \"Aerodynamic Performance\" --header \"Streamlines\" --position 0 0 6\n", "\n", "simu_ready = aero_performance\n", "aero_fig_lines\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%mnn widget --type table --tab \"Aerodynamic Performance\" --position 1 2 4 --header \"Metrics\" --var performance_values\n", "\n", "performance_values = aero_performance" ] } ], "metadata": { "kernelspec": { "display_name": "manganite-env", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.4" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }