diff --git a/src/vlm/app.py b/src/vlm/app.py index 8604740..e397db1 100644 --- a/src/vlm/app.py +++ b/src/vlm/app.py @@ -26,7 +26,7 @@ # Ensure local module import import sys sys.path.append('../') -from lib.vlm import VLM, plot_distribution_all, plot_wing_heatmap, plot_wing_heatmap_2d, plot_coefficient_vs_alpha, plot_distribution, plot_CL_CD +from lib.vlm import VLM, plot_distribution_all, plot_wing_heatmap, plot_wing_heatmap_2d, plot_coefficient_vs_alpha, plot_distribution, plot_CL_CD, plot_CLCD_vs_alpha from lib.naca import plot_naca_airfoil, naca_csv from lib.geometry import plot_wing_geometry, plot_wing_geometry_2d, plot_wing_discretization_2d, plot_wing_discretization_3d @@ -216,6 +216,7 @@ def plane(): if data.getlist("horizontal_toggled[]") == ["1"]: plane["horizontal_stabilizer"] = { "x_translate": float(data.get("x_translate", 0.0)), + "z_translate": float(data.get("z_translate", 0.0)), "NACA_root": data.get("NACA_root", ""), "NACA_tip": data.get("NACA_tip", ""), "chord_root": float(data.get("chord_root", 0.0)), @@ -228,6 +229,7 @@ def plane(): if data.getlist("vertical_toggled[]") == ["1"]: plane["vertical_stabilizer"] = { "x_translate": float(data.get("x_translate_v", 0.0)), + "z_translate": float(data.get("z_translate_v", 0.0)), "NACA_root": data.get("NACA_root_v", ""), "NACA_tip": data.get("NACA_tip_v", ""), "chord_root": float(data.get("chord_root_v", 0.0)), @@ -618,6 +620,10 @@ def compute(vlm): if vlm.results is None or 'CD' not in vlm.results: return jsonify({"status": "error", "message": "Please calculate coefficients first"}), 400 fig = plot_coefficient_vs_alpha(fig, vlm, coefficient='CD') + elif plot_type == 'CL-CD-alpha': + if vlm.results is None or 'CD' not in vlm.results or 'CL' not in vlm.results: + return jsonify({"status": "error", "message": "Please calculate coefficients first"}), 400 + fig = plot_CLCD_vs_alpha(fig, vlm, title=None) elif plot_type == 'LiftSection': if 'n_section' in data: try: @@ -646,7 +652,7 @@ def compute(vlm): if __name__ == "__main__": optimize_resources() try: - app.run(host='0.0.0.0', port=5000, debug=True, threaded=True) - # ui.run() + app.run(host='0.0.0.0', port=5001, debug=True, threaded=True) + #ui.run() finally: thread_pool.shutdown(wait=True) \ No newline at end of file diff --git a/src/vlm/default_plane.txt b/src/vlm/default_plane.txt index b114ef1..c283754 100644 --- a/src/vlm/default_plane.txt +++ b/src/vlm/default_plane.txt @@ -17,6 +17,7 @@ ], "horizontal_stabilizer": { "x_translate": 2, + "z_translate":0, "NACA_root": "3215", "NACA_tip": "3215", "chord_root": 0.5, @@ -28,6 +29,7 @@ }, "vertical_stabilizer": { "x_translate": 2, + "z_translate":0, "NACA_root": "3215", "NACA_tip": "3215", "chord_root": 0.5, diff --git a/src/vlm/lib/geometry.py b/src/vlm/lib/geometry.py index 05e09f7..c245694 100644 --- a/src/vlm/lib/geometry.py +++ b/src/vlm/lib/geometry.py @@ -21,7 +21,7 @@ def calculate_geometry(self): - surface_geometry: Dictionary with coordinates of leading edge, trailing edge, and quarter chord """ plane = self.plane - def calculate_section_geometry(sections, alpha, is_symmetric, x_translate): + def calculate_section_geometry(sections, alpha, is_symmetric, x_translate, z_translate=0): print(f"alpha: {alpha}") # Initialize coordinate arrays for one side x_leading_edge = [] @@ -120,6 +120,11 @@ def calculate_section_geometry(sections, alpha, is_symmetric, x_translate): x_trailing_edge += x_translate x_quarter_chord += x_translate + # Apply y-translation + z_leading_edge += z_translate + z_trailing_edge += z_translate + z_quarter_chord += z_translate + # If symmetric, mirror across the x-z plane (y=0) if is_symmetric: x_leading_edge = np.concatenate((x_leading_edge[::-1], x_leading_edge)) @@ -146,15 +151,15 @@ def calculate_section_geometry(sections, alpha, is_symmetric, x_translate): vs_geometry = 0 if 'wing_sections' in plane: # Calculate geometry for wing sections - wing_geometry = calculate_section_geometry(plane['wing_sections'], self.alpha, is_symmetric=True, x_translate=0) + wing_geometry = calculate_section_geometry(plane['wing_sections'], self.alpha, is_symmetric=True, x_translate=0, z_translate=0) if 'horizontal_stabilizer' in plane: # Calculate geometry for horizontal stabilizer hs = plane['horizontal_stabilizer'] - hs_geometry = calculate_section_geometry([hs], hs['alpha'], True, hs['x_translate']) + hs_geometry = calculate_section_geometry([hs], hs['alpha'], True, hs['x_translate'], hs['z_translate']) if 'vertical_stabilizer' in plane: # Calculate geometry for vertical stabilizer vs = plane['vertical_stabilizer'] - vs_geometry = calculate_section_geometry([vs], vs['alpha'], False, vs['x_translate']) + vs_geometry = calculate_section_geometry([vs], vs['alpha'], False, vs['x_translate'], vs['z_translate']) return wing_geometry, hs_geometry, vs_geometry diff --git a/src/vlm/lib/vlm.py b/src/vlm/lib/vlm.py index 8552380..c2e664e 100644 --- a/src/vlm/lib/vlm.py +++ b/src/vlm/lib/vlm.py @@ -419,11 +419,11 @@ def plane(self): num_wing_panels = n * m num_hs_panels = n_hs * m_hs num_vs_panels = n_vs * m_vs - + # Áreas por sub-superficie A_wing = panel_areas[:num_wing_panels] A_hs = panel_areas[num_wing_panels:num_wing_panels + num_hs_panels] - A_vs = panel_areas[num_wing_panels + num_vs_panels:] + A_vs = panel_areas[num_wing_panels + num_hs_panels:num_wing_panels + num_hs_panels + num_vs_panels] # 5. Calcular lift y drag elementales por panel lift_per_panel = rho * u * gammas * panel_lengths @@ -493,7 +493,7 @@ def coefs(forces, areas, n_sub, m_sub): # 13. VS: drag if n_vs != 0: drag_vs_vec = drag_per_panel[num_wing_panels + num_hs_panels:] - drag_sum_vs, drag_tot_vs, _ = coefs(drag_vs_vec, np.array(A_vs), n_hs, m_hs) + drag_sum_vs, drag_tot_vs, _ = coefs(drag_vs_vec, np.array(A_vs), n_vs, m_vs) else: drag_vs_vec = np.zeros(num_vs_panels) drag_sum_vs = np.zeros(n_vs) @@ -514,7 +514,7 @@ def coefs(forces, areas, n_sub, m_sub): else: CD_locals_hs = np.zeros(n_hs) if n_vs != 0: - _, _, CD_locals_vs = coefs(drag_vs_vec, np.array(A_vs), n_hs, m_hs) + _, _, CD_locals_vs = coefs(drag_vs_vec, np.array(A_vs), n_vs, m_vs) else: CD_locals_vs = np.zeros(n_vs) CD_locals_dict = { @@ -1027,6 +1027,48 @@ def plot_coefficient_vs_alpha(fig, self, coefficient='CL', title=None): return fig +def plot_CLCD_vs_alpha(fig, self, title=None): + """ + Plot CL or CD vs angle of attack using precomputed results. + Calculates and displays the slope (pendiente) of the line (in radians). + + Parameters: + - coefficient: 'CL' or 'CD' + - title: Optional title for the plot + + Returns: + - fig: Plotly Figure object + """ + + x_deg = np.array(self.results['angles_deg']) + y1 = np.array(self.results['CL']) + y2 = np.array(self.results['CD']) + x_rad = np.radians(x_deg) + + + if title is None: + title = "CL/CD vs Angle of Attack" + + fig.add_trace(go.Scatter( + x=y2, + y=y1, + mode='lines+markers', + name='CL/CD', + line=dict(color='blue'), + marker=dict(size=8) + )) + + + fig.update_layout( + title=title, + xaxis_title='Angle of Attack (degrees)', + yaxis_title='CL/CD', + autosize=True, + showlegend=True + ) + + return fig + def plot_distribution(vlm, n_section, quantity='lift'): """ Plot the distribution (lift or drag) along the chord for a given spanwise section. diff --git a/src/vlm/templates/results.html b/src/vlm/templates/results.html index de02b1b..a62a105 100644 --- a/src/vlm/templates/results.html +++ b/src/vlm/templates/results.html @@ -88,6 +88,7 @@