### Setup Optimizer and Optimization Variables Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/user_reference/v1_v2_conversion.md Configure the optimization driver and define design variables, constraints, and the objective function. This example uses ScipyOptimizeDriver. ```python prob.driver = om.ScipyOptimizeDriver() prob.model.add_design_var("wing.twist_cp", lower=-10.0, upper=15.0) prob.model.add_design_var("wing.sweep", lower=-10.0, upper=30.0) prob.model.add_design_var("wing.dihedral", lower=-10.0, upper=15.0) prob.model.add_constraint(point_name + ".wing_perf.CL", equals=0.5) prob.model.add_objective(point_name + ".wing_perf.CD", scaler=1e4) ``` -------------------------------- ### Setup and Run Problem (v2) Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/user_reference/v1_v2_conversion.md Finalizes the problem setup and runs the optimization driver in v2. This should be called after all components and connections have been defined. ```python # Set up the problem prob.setup() prob.run_driver() ``` -------------------------------- ### Install OpenAeroStruct from Source Source: https://github.com/mdolab/openaerostruct/blob/main/README.md Clone the repository and install OpenAeroStruct in editable mode for easier access to examples and source code. ```bash pip install -e . ``` -------------------------------- ### v1 Script: Setup and Run Problem Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/user_reference/v1_v2_conversion.md Completes the problem setup and runs the optimization in v1. This is the final step after defining all components, variables, and objectives. ```python # Actually run the problem OAS_prob.run() ``` -------------------------------- ### Q400 Aerostructural Optimization Example Setup Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/multipoint.md This script demonstrates a multipoint aerostructural optimization for a Q400 wing using a wingbox model and a custom mesh. It configures the problem for cruise and maneuver flight points. ```python """ This example script can be used to run a multipoint aerostructural optimization for a wing based on the Bombardier Q400 with the wingbox model. We create a custom mesh for this wing in this script. The fuel burn from the cruise flight-point is the objective function and a 2.5g maneuver flight-point is used for the structural sizing. After running the optimization, use the 'plot_wingbox.py' script in the utils/ directory (e.g., as 'python ../utils/plot_wingbox.py aerostruct.db' if running from this directory) to visualize the results. This visualization script is based on the plot_wing.py script. It's still under development and will probably not work as it is for other types of cases for now. """ import numpy as np from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint from openaerostruct.structures.wingbox_fuel_vol_delta import WingboxFuelVolDelta import openmdao.api as om # Provide coordinates for a portion of an airfoil for the wingbox cross-section as an nparray with dtype=complex (to work with the complex-step approximation for derivatives). # These should be for an airfoil with the chord scaled to 1. # We use the 10% to 60% portion of the NASA SC2-0612 airfoil for this case # We use the coordinates available from airfoiltools.com. Using such a large number of coordinates is not necessary. # The first and last x-coordinates of the upper and lower surfaces must be the same # fmt: off upper_x = np.array([0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6], dtype="complex128") lower_x = np.array([0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6], dtype="complex128") upper_y = np.array([ 0.0447, 0.046, 0.0472, 0.0484, 0.0495, 0.0505, 0.0514, 0.0523, 0.0531, 0.0538, 0.0545, 0.0551, 0.0557, 0.0563, 0.0568, 0.0573, 0.0577, 0.0581, 0.0585, 0.0588, 0.0591, 0.0593, 0.0595, 0.0597, 0.0599, 0.06, 0.0601, 0.0602, 0.0602, 0.0602, 0.0602, 0.0602, 0.0601, 0.06, 0.0599, 0.0598, 0.0596, 0.0594, 0.0592, 0.0589, 0.0586, 0.0583, 0.058, 0.0576, 0.0572, 0.0568, 0.0563, 0.0558, 0.0553, 0.0547, 0.0541], dtype="complex128") # noqa: E201, E241 lower_y = np.array([-0.0447, -0.046, -0.0473, -0.0485, -0.0496, -0.0506, -0.0515, -0.0524, -0.0532, -0.054, -0.0547, -0.0554, -0.056, -0.0565, -0.057, -0.0575, -0.0579, -0.0583, -0.0586, -0.0589, -0.0592, -0.0594, -0.0595, -0.0596, -0.0597, -0.0598, -0.0598, -0.0598, -0.0598, -0.0597, -0.0596, -0.0594, -0.0592, -0.0589, -0.0586, -0.0582, -0.0578, -0.0573, -0.0567, -0.0561, -0.0554, -0.0546, -0.0538, -0.0529, -0.0519, -0.0509, -0.0497, -0.0485, -0.0472, -0.0458, -0.0444], dtype="complex128") # fmt: on # Here we create a custom mesh for the wing # It is evenly spaced with nx chordwise nodal points and ny spanwise nodal points for the half-span span = 28.42 # wing span in m root_chord = 3.34 # root chord in m nx = 3 # number of chordwise nodal points (should be odd) ny = 11 # number of spanwise nodal points for the half-span # Initialize the 3-D mesh object. Chordwise, spanwise, then the 3D coordinates. mesh = np.zeros((nx, ny, 3)) # Start away from the symmetry plane and approach the plane as the array indices increase. # The form of this 3-D array can be very confusing initially. # For each node we are providing the x, y, and z coordinates. # x is chordwise, y is spanwise, and z is up. # For example (for a mesh with 5 chordwise nodes and 15 spanwise nodes for the half wing), the node for the leading edge at the tip would be specified as mesh[0, 0, :] = np.array([1.1356, -14.21, 0.]) # and the node at the trailing edge at the root would be mesh[4, 14, :] = np.array([3.34, 0., 0.]) ``` -------------------------------- ### Setup and Run Optimization (v1) Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/user_reference/v1_v2_conversion.md Sets up the OpenAeroStruct problem in v1 by adding design variables, constraints, and objectives, then runs the optimization. Requires calling setup() and run() on the OASProblem instance. ```python # Setup problem and add design variables, constraint, and objective OAS_prob.add_desvar('wing.twist_cp', lower=-10., upper=15.) OAS_prob.add_desvar('wing.sweep', lower=10., upper=30.) OAS_prob.add_desvar('wing.dihedral', lower=-10., upper=20.) OAS_prob.add_constraint('wing_perf.CL', equals=0.5) OAS_prob.add_objective('wing_perf.CD', scaler=1e4) OAS_prob.setup() # Actually run the problem OAS_prob.run() ``` -------------------------------- ### Setup Problem and Add AerostructGeometry Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/multipoint_parallel.md Standard problem setup including problem information and adding the AerostructGeometry component to the model. ```python prob = om.Problem() # Setup problem information in indep_var_comp ... # Add AerostructGeometry to the model ... ``` -------------------------------- ### Setup and Configure Linear Solvers Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/composites_walkthrough.md Sets up the problem and configures linear solvers for the aerostructural coupled adjoint. It uses PETScKrylov with a LinearRunOnce preconditioner. A fallback to LinearBlockGS is mentioned if PETSc is not installed. ```python # Set up the problem prob.setup() # change linear solver for aerostructural coupled adjoint prob.model.AS_point_0.coupled.linear_solver = om.PETScKrylov(assemble_jac=True, iprint=0, rhs_checking=True) prob.model.AS_point_0.coupled.linear_solver.precon = om.LinearRunOnce(iprint=-1) prob.model.AS_point_1.coupled.linear_solver = om.PETScKrylov(assemble_jac=True, iprint=0, rhs_checking=True) prob.model.AS_point_1.coupled.linear_solver.precon = om.LinearRunOnce(iprint=-1) # Use LinearBlockGS instead if you don't have PETSc installed ``` -------------------------------- ### Setup and Run the OpenMDAO Problem Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/openvsp_mesh_example.md Finalizes the OpenMDAO problem setup, making it ready for execution. Includes an optional line to generate an N2 diagram for visualizing model connections. ```python # Set up the problem prob.setup() # Create a n^2 diagram for user to view model connections # om.n2(prob) ``` -------------------------------- ### Setup and Run Optimization Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/aerostructural_tube_walkthrough.md Sets up the optimization problem, performing checks for correctness, and then runs the optimization driver to find the optimal solution. The result of the driver run is stored in optResult. ```python # Set up the problem prob.setup(check=True) optResult = prob.run_driver() ``` -------------------------------- ### Setup and Run Optimization Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/custom_mesh_example.md After defining the problem, set up the OpenAeroStruct problem and run the driver to perform the optimization. This is the final step to initiate the analysis. ```python # Set up the problem prob.setup() # change linear solver for aerostructural coupled adjoint prob.model.AS_point_0.coupled.linear_solver = om.LinearBlockGS(iprint=0, maxiter=30, use_aitken=True) prob.model.AS_point_1.coupled.linear_solver = om.LinearBlockGS(iprint=0, maxiter=30, use_aitken=True) # om.view_model(prob) # prob.check_partials(form='central', compact_print=True) prob.run_driver() ``` -------------------------------- ### Setup and Run Optimization, Print Results Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/multipoint.md After defining the problem, set up the model and run the driver. Finally, print the results, such as the fuel burn and wingbox mass, to analyze the optimization outcome. ```python # Set up the problem prob.setup() prob.run_driver() print("The fuel burn value is", prob["AS_point_0.fuelburn"][0], "[kg]") print( "The wingbox mass (excluding the wing_weight_ratio) is", prob["wing.structural_mass"][0] / surf_dict["wing_weight_ratio"], "[kg]", ) ``` -------------------------------- ### Setup and Run Optimization Problem Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/ground_effect.md This snippet shows the standard procedure for setting up and running an optimization problem in OpenAeroStruct after defining variables, constraints, and objectives. ```python prob.setup() prob.run_driver() ``` -------------------------------- ### Set Optimizer and Problem Setup Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/mphys_coupling.md Configure the optimizer and add design variables, constraints, and objectives to the problem. This setup is typical for aerodynamic shape optimization. ```python prob.driver = om.ScipyOptimizeDriver() prob.driver.options["debug_print"] = ["nl_cons", "objs", "desvars"] # Setup problem and add design variables, constraint, and objective prob.model.add_design_var("geometry.WingGeom:XSec_1:Root_Chord", lower=1e-3, upper=5.0) prob.model.add_design_var("geometry.WingGeom:XSec_2:Root_Chord", lower=1e-3, upper=5.0) prob.model.add_design_var("geometry.WingGeom:XSec_3:Root_Chord", lower=1e-3, upper=5.0) prob.model.add_design_var("geometry.WingGeom:XSec_4:Root_Chord", lower=1e-3, upper=5.0) prob.model.add_design_var("geometry.WingGeom:XSec_4:Tip_Chord", lower=1e-3, upper=5.0) prob.model.add_design_var("aoa", lower=-10.0, upper=10.0) prob.model.add_constraint("cruise.WingGeom.CL", equals=0.5) prob.model.add_constraint("cruise.WingGeom.S_ref", equals=10.0) prob.model.add_objective("cruise.WingGeom.CD", scaler=1e4) prob.setup() ``` -------------------------------- ### Setup and Run Optimization Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/aerostructural_wingbox_walkthrough.md Sets up the optimization problem, modifies the linear solver for aerostructural coupled adjoint, and runs the optimization. Includes commented-out commands for visualizing the N2 problem structure and checking partial derivatives. ```python # Set up the problem prob.setup() # change linear solver for aerostructural coupled adjoint prob.model.AS_point_0.coupled.linear_solver = om.LinearBlockGS(iprint=0, maxiter=30, use_aitken=True) prob.model.AS_point_1.coupled.linear_solver = om.LinearBlockGS(iprint=0, maxiter=30, use_aitken=True) # om.view_model(prob) # prob.check_partials(form='central', compact_print=True) prob.run_driver() print("The fuel burn value is", prob["AS_point_0.fuelburn"][0], "[kg]") print( "The wingbox mass (excluding the wing_weight_ratio) is", prob["wing.structural_mass"][0] / surf_dict["wing_weight_ratio"], "[kg]", ) ``` -------------------------------- ### Setup and Run Optimization Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/aero_walkthrough.md Initializes the OpenMDAO problem and executes the optimization driver to find the optimal solution. Use `prob.run_model()` for analysis without optimization. ```python # Set up and run the optimization problem prob.setup() prob.run_driver() ``` -------------------------------- ### Editable Install from Source Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/installation.md After cloning the repository, navigate to the OpenAeroStruct directory and perform an editable pip install. This allows changes in the source code to be reflected immediately without reinstallation. ```bash cd openaerostruct pip install -e . ``` -------------------------------- ### Install OpenAeroStruct with Documentation Dependencies Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/installation.md Install OpenAeroStruct with the '[docs]' extra to include dependencies required for building the documentation locally. This is useful for developers who want to modify or view the documentation. ```bash pip install -e .[docs] ``` -------------------------------- ### Complete Runscript Setup with Airfoil Coordinates Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/multipoint_parallel.md This is a comprehensive runscript demonstrating the setup of an OpenAeroStruct model, including defining airfoil coordinates for a wingbox cross-section. The coordinates are provided as complex numbers to support complex-step derivative approximation. ```python import numpy as np import time from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint from openaerostruct.structures.wingbox_fuel_vol_delta import WingboxFuelVolDelta import openmdao.api as om from mpi4py import MPI # noqa: F811 # Provide coordinates for a portion of an airfoil for the wingbox cross-section as an nparray with dtype=complex (to work with the complex-step approximation for derivatives). # These should be for an airfoil with the chord scaled to 1. # We use the 10% to 60% portion of the NASA SC2-0612 airfoil for this case # We use the coordinates available from airfoiltools.com. Using such a large number of coordinates is not necessary. # The first and last x-coordinates of the upper and lower surfaces must be the same # fmt: off upper_x = np.array([0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6], dtype="complex128") lower_x = np.array([0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6], dtype="complex128") upper_y = np.array([ 0.0447, 0.046, 0.0472, 0.0484, 0.0495, 0.0505, 0.0514, 0.0523, 0.0531, 0.0538, 0.0545, 0.0551, 0.0557, 0.0563, 0.0568, 0.0573, 0.0577, 0.0581, 0.0585, 0.0588, 0.0591, 0.0593, 0.0595, 0.0597, 0.0599, 0.06, 0.0601, 0.0602, 0.0602, 0.0602, 0.0602, 0.0602, 0.0601, 0.06, 0.0599, 0.0598, 0.0596, 0.0594, 0.0592, 0.0589, 0.0586, 0.0583, 0.058, 0.0576, 0.0572, 0.0568, 0.0563, 0.0558, 0.0553, 0.0547, 0.0541], dtype="complex128") # noqa: E201, E241 lower_y = np.array([-0.0447, -0.046, -0.0473, -0.0485, -0.0496, -0.0506, -0.0515, -0.0524, -0.0532, -0.054, -0.0547, -0.0554, -0.056, -0.0565, -0.057, -0.0575, -0.0579, -0.0583, -0.0586, -0.0589, -0.0592, -0.0594, -0.0595, -0.0596, -0.0597, -0.0598, -0.0598, -0.0598, -0.0598, -0.0597, -0.0596, -0.0594, -0.0592, -0.0589, -0.0586, -0.0582, -0.0578, -0.0573, -0.0567, -0.0561, -0.0554, -0.0546, -0.0538, -0.0529, -0.0519, -0.0509, -0.0497, -0.0485, -0.0472, -0.0458, -0.0444], dtype="complex128") # fmt: on ``` -------------------------------- ### Run OpenAeroStruct Tests Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/installation.md After installing with test dependencies, run the test suite from the OpenAeroStruct root directory using the 'testflo' command for verbose output. ```bash testflo -v . ``` -------------------------------- ### Full OpenAeroStruct Example with Ground Effect Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/ground_effect.md This comprehensive example demonstrates setting up an OpenAeroStruct problem with ground effect enabled. It includes mesh generation, defining surface properties, and configuring the OpenMDAO problem with aerodynamic analyses. ```python import numpy as np import openmdao.api as om from openaerostruct.meshing.mesh_generator import generate_mesh from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.aerodynamics.aero_groups import AeroPoint from openmdao.utils.assert_utils import assert_near_equal, assert_check_totals # Create a dictionary to store options about the mesh mesh_dict = {"num_y": 7, "num_x": 2, "wing_type": "CRM", "symmetry": True, "num_twist_cp": 5} # Generate the aerodynamic mesh based on the previous dictionary mesh, twist_cp = generate_mesh(mesh_dict) # Create a dictionary with info and options about the aerodynamic # lifting surface surface = { # Wing definition "name": "wing", # name of the surface "symmetry": True, # if true, model one half of wing # reflected across the plane y = 0 "groundplane": True, "S_ref_type": "wetted", # how we compute the wing area, # can be 'wetted' or 'projected' "fem_model_type": "tube", "twist_cp": twist_cp, "mesh": mesh, # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. "CL0": 0.0, # CL of the surface at alpha=0 "CD0": 0.015, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation "k_lam": 0.05, # percentage of chord with laminar # flow, used for viscous drag "t_over_c_cp": np.array([0.15]), # thickness over chord ratio (NACA0015) "c_max_t": 0.303, # chordwise location of maximum (NACA0015) # thickness "with_viscous": True, # if true, compute viscous drag "with_wave": False, # if true, compute wave drag } # Create the OpenMDAO problem prob = om.Problem() # Create an independent variable component that will supply the flow # conditions to the problem. indep_var_comp = om.IndepVarComp() indep_var_comp.add_output("v", val=248.136, units="m/s") indep_var_comp.add_output("alpha", val=5.0, units="deg") indep_var_comp.add_output("Mach_number", val=0.84) indep_var_comp.add_output("re", val=1.0e6, units="1/m") indep_var_comp.add_output("rho", val=0.38, units="kg/m**3") indep_var_comp.add_output("cg", val=np.zeros((3)), units="m") indep_var_comp.add_output("height_agl", val=8000.0, units="m") # Add this IndepVarComp to the problem model prob.model.add_subsystem("prob_vars", indep_var_comp, promotes=["*"]) # Create and add a group that handles the geometry for the # aerodynamic lifting surface geom_group = Geometry(surface=surface) prob.model.add_subsystem(surface["name"], geom_group) # Create the aero point group, which contains the actual aerodynamic # analyses aero_group = AeroPoint(surfaces=[surface]) point_name = "aero_point_0" prob.model.add_subsystem( point_name, aero_group, promotes_inputs=["v", "alpha", "Mach_number", "re", "rho", "cg", "height_agl"] ) name = surface["name"] # Connect the mesh from the geometry component to the analysis point prob.model.connect(name + ".mesh", point_name + "." + name + ".def_mesh") # Perform the connections with the modified names within the # 'aero_states' group. prob.model.connect(name + ".mesh", point_name + ".aero_states." + name + "_def_mesh") prob.model.connect(name + ".t_over_c", point_name + "." + name + "_perf." + "t_over_c") # Import the Scipy Optimizer and set the driver of the problem to use # it, which defaults to an SLSQP optimization method prob.driver = om.ScipyOptimizeDriver() prob.driver.options["tol"] = 1e-9 ``` -------------------------------- ### Import MPI Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/multipoint_parallel.md Import the MPI library. Ensure you have a working MPI installation if this import fails. ```python from mpi4py import MPI ``` -------------------------------- ### Multipoint Aerostructural Optimization Setup Source: https://context7.com/mdolab/openaerostruct/llms.txt Sets up a multipoint aerostructural optimization problem by defining geometry, flight conditions, and analysis points. Requires OpenMDAO and OpenAeroStruct libraries. ```python import numpy as np import openmdao.api as om from openaerostruct.meshing.mesh_generator import generate_mesh from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint mesh_dict = {"num_y": 51, "num_x": 7, "wing_type": "uCRM_based", "symmetry": True, "num_twist_cp": 6} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { "name": "wing", "symmetry": True, "S_ref_type": "wetted", "mesh": mesh, "twist_cp": np.array([4., 5., 8., 8., 8., 9.]), "fem_model_type": "wingbox", "spar_thickness_cp": np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), "skin_thickness_cp": np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), "t_over_c_cp": np.array([0.08, 0.08, 0.08, 0.10, 0.10, 0.08]), "CL0": 0.0, "CD0": 0.0078, "with_viscous": True, "with_wave": True, "k_lam": 0.05, "c_max_t": 0.38, "E": 73.1e9, "G": 27.5e9, "yield": 420.0e6, "mrho": 2.78e3, "safety_factor": 1.5, "wing_weight_ratio": 1.25, "struct_weight_relief": True, "distributed_fuel_weight": True, "exact_failure_constraint": False, # use KS aggregation for smooth optimization } prob = om.Problem() ivc = om.IndepVarComp() # Vectorized over 2 flight conditions: [cruise, maneuver] ivc.add_output("v", val=np.array([0.85 * 295.07, 0.64 * 340.294]), units="m/s") ivc.add_output("Mach_number", val=np.array([0.85, 0.64])) ivc.add_output("rho", val=np.array([0.348, 1.225]), units="kg/m**3") ivc.add_output("load_factor", val=np.array([1.0, 2.5])) ivc.add_output("alpha", val=0.0, units="deg") ivc.add_output("alpha_maneuver", val=0.0, units="deg") ivc.add_output("CT", val=0.53/3600, units="1/s") ivc.add_output("R", val=14.307e6, units="m") ivc.add_output("W0", val=163000.0, units="kg") ivc.add_output("fuel_mass", val=10000.0, units="kg") prob.model.add_subsystem("prob_vars", ivc, promotes=["*"]) prob.model.add_subsystem("wing", AerostructGeometry(surface=surf_dict)) for i in range(2): point_name = f"AS_point_{i}" AS_point = AerostructPoint(surfaces=[surf_dict], internally_connect_fuelburn=False) prob.model.add_subsystem(point_name, AS_point) prob.model.connect("v", f"{point_name}.v", src_indices=[i]) prob.model.connect("Mach_number", f"{point_name}.Mach_number", src_indices=[i]) prob.model.connect("rho", f"{point_name}.rho", src_indices=[i]) prob.model.connect("load_factor", f"{point_name}.load_factor", src_indices=[i]) # ... (remaining connections as in full example) prob.driver = om.ScipyOptimizeDriver() prob.driver.options["optimizer"] = "SLSQP" prob.driver.options["tol"] = 1e-8 # Record to SQLite for later visualization recorder = om.SqliteRecorder("aerostruct.db") prob.driver.add_recorder(recorder) prob.model.add_objective("AS_point_0.fuelburn", scaler=1e-5) # minimize cruise fuel burn prob.model.add_design_var("wing.twist_cp", lower=-15., upper=15.) prob.model.add_design_var("wing.spar_thickness_cp", lower=0.003, upper=0.1) prob.model.add_design_var("wing.skin_thickness_cp", lower=0.003, upper=0.1) prob.model.add_design_var("alpha_maneuver", lower=-15., upper=15.) prob.model.add_constraint("AS_point_0.CL", equals=0.5) # cruise lift prob.model.add_constraint("AS_point_1.wing_perf.failure", upper=0.0) # structural safety prob.setup() # Accelerate coupled solver convergence prob.model.AS_point_0.coupled.linear_solver = om.LinearBlockGS( iprint=0, maxiter=30, use_aitken=True) prob.run_driver() print("Fuel burn:", prob["AS_point_0.fuelburn"][0], "kg") # Use: plot_wingbox aerostruct.db to visualize ``` -------------------------------- ### Parallelizing Linear Solves for Coupled Components Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/multipoint_parallel.md This example demonstrates how to add a component that sums fuel burns from two different analysis points. The linear solves for these two points will be parallelized because the new component depends on both. ```python fuel_sum_comp = om.ExecComp("fuel_sum = fuelburn1 + fuelburn2", units="kg", shape=(1)) prob.model.add_subsystem("fuel_sum", fuel_sum_comp, promotes_outputs=["fuel_sum"]) prob.model.connect("AS_point_0.fuelburn", "fuel_sum.fuelburn1") prob.model.connect("AS_point_1.fuelburn", "fuel_sum.fuelburn2") prob.model.add_constraint("fuel_sum", lower=0, upper=1e10, scaler=1e-5) ``` -------------------------------- ### Install OpenAeroStruct via Pip Source: https://github.com/mdolab/openaerostruct/blob/main/README.md Use this command to install OpenAeroStruct from the Python Package Index. This is the easiest way to get started. ```bash pip install openaerostruct ``` -------------------------------- ### Install OpenAeroStruct Source: https://context7.com/mdolab/openaerostruct/llms.txt This command installs the OpenAeroStruct package, which includes command-line tools for visualization. The console scripts are registered automatically upon installation. ```bash # Install openaerostruct (console scripts are registered automatically) pip install openaerostruct ``` -------------------------------- ### Clone OpenAeroStruct Repository Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/installation.md Clone the OpenAeroStruct repository to access the source code and examples. This is useful for development or if you want easier access to the examples. ```bash git clone https://github.com/mdolab/OpenAeroStruct.git ``` -------------------------------- ### Configure Optimizer and Run Optimization Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/multi_section_surfaces.md Sets up the optimization problem by configuring the driver, adding design variables, constraints, and the objective function, then runs the optimization. ```python prob.driver = om.ScipyOptimizeDriver() prob.driver.options["optimizer"] = "SLSQP" prob.driver.options["tol"] = 1e-6 prob.driver.options["disp"] = True prob.driver.options["maxiter"] = 1000 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var("twist_bspline.twist_cp_spline", lower=-10.0, upper=15.0) prob.model.add_design_var("surface.thickness_cp", lower=0.01, upper=0.5, scaler=1e2) prob.model.add_constraint("AS_point_0.surface_perf.failure", upper=0.0) prob.model.add_constraint("AS_point_0.surface_perf.thickness_intersects", upper=0.0) # Add design variables, constraints, and objective on the problem prob.model.add_design_var("alpha", lower=-10.0, upper=10.0) prob.model.add_constraint("AS_point_0.L_equals_W", equals=0.0) prob.model.add_objective("AS_point_0.fuelburn", scaler=1e-5) # Set up the problem prob.setup(check=True) # Run the optimization optResult = prob.run_driver() # om.n2(prob, show_browser=False) ``` -------------------------------- ### Install OpenAeroStruct with Test Dependencies Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/installation.md Install OpenAeroStruct with the '[test]' extra to include testing dependencies like pytest. This is necessary for running the project's test suite. ```bash pip install -e .[test] ``` -------------------------------- ### Setup Aerodynamics Group for Multi-Section Surface Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/multi_section_surfaces.md Create an AeroPoint group for aerodynamic analysis, passing the multi-section surface dictionary. This step is similar to standard OpenAeroStruct setups. ```python aero_group = AeroPoint(surfaces=[surface]) point_name = "aero_point_0" prob.model.add_subsystem(point_name, aero_group, promotes_inputs=["v", "alpha", "Mach_number", "re", "rho", "cg"]) ``` -------------------------------- ### Setting Up and Running the Optimization Problem Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/multipoint.md After defining constraints and objectives, set up the OpenAeroStruct problem and initiate the optimization run. This is the final step before the solver begins. ```python # Set up the problem and run optimization. prob.setup() prob.run_driver() ``` -------------------------------- ### Configure and Run Optimization Driver Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/multi_section_surfaces.md Set up the ScipyOptimizeDriver with the SLSQP optimizer, specifying tolerance and maximum iterations. Then, set up and run the OpenMDAO problem. ```python prob.driver = om.ScipyOptimizeDriver() prob.driver.options["optimizer"] = "SLSQP" prob.driver.options["tol"] = 1e-3 prob.driver.options["disp"] = True prob.driver.options["maxiter"] = 1000 # Set up and run the optimization problem prob.setup() prob.run_driver() # om.n2(prob) ``` -------------------------------- ### Configure Optimizer and Tolerance Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/aerostructural_wingbox_walkthrough.md Sets up the optimization driver using the SLSQP optimizer from SciPy with a specified tolerance. Lower tolerances reduce computational cost but may affect accuracy. ```python prob.driver = om.ScipyOptimizeDriver() prob.driver.options["optimizer"] = "SLSQP" prob.driver.options["tol"] = 1e-2 ``` -------------------------------- ### Configure Nonlinear and Linear Solvers Source: https://github.com/mdolab/openaerostruct/blob/main/openaerostruct/docs/advanced_features/solver.md Update nonlinear and linear solver settings after prob.setup() and before running the model. This example demonstrates setting Newton as the nonlinear solver and LinearBlockGS for its linear steps, as well as for the unified derivative equations. ```python # First, define the problem as usual ... prob = Om.Problem() ... prob.model.add_subsystem('AS_point_0', AerostructPoint(), ...) ... # setup the OpenMDAO problem. This model will be initialized with the default solvers. prob.setup() # Let's try using Newton as a nonlinear solver. prob.model.AS_point_0.coupled.nonlinear_solver = om.NewtonSolver(solve_subsystems=True, iprint=2, maxiter=10) # Set a linear solver for Newton step computation (if not specified here, the linear solver attached to `prob.model.AS_point_0.coupled` will be used). prob.model.AS_point_0.coupled.nonlinear_solver.linear_solver = om.LinearBlockGS(iprint=-1, maxiter=30, use_aitken=True) # Set a linear solver to solve (a part of) the unified derivative equations. prob.model.AS_point_0.coupled.linear_solver = om.LinearBlockGS(iprint=1, maxiter=30, use_aitken=True) # Alternatively, you could use PETSc's Krylov solver with a preconditioner. # Note that this solver requires PETSc/petsc4py, which does not come with OpenAeroStruct by default. ### prob.model.linear_solver = om.PETScKrylov(assemble_jac=True, iprint=1) ### prob.model.options["assembled_jac_type"] = "csc" ### prob.model.linear_solver.precon = om.LinearRunOnce(iprint=-1) # run analysis or optimization. prob.run_model() ```