├── .all-contributorsrc ├── .bumpversion.cfg ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ ├── doc_request.yml │ └── feature_request.yml ├── PULL_REQUEST_TEMPLATE.md ├── actions │ ├── prepare_environment │ │ └── action.yml │ └── send_email │ │ └── action.yml ├── install_env_from_github.sh └── workflows │ ├── notify_teams.yml │ ├── publish-image.yml │ ├── release_workflow.yml │ ├── test_benchmarks.yml │ ├── test_docs.yml │ ├── test_workflow.yml │ ├── test_workflow_dev_deps.yml │ └── test_workflow_no_dev_install.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CITATION.cff ├── Dockerfile ├── Dockerfile.arm ├── LICENSE ├── README.md ├── aviary ├── __init__.py ├── api.py ├── constants.py ├── core │ ├── AviaryGroup.py │ ├── PostMissionGroup.py │ ├── PreMissionGroup.py │ └── __init__.py ├── docs │ ├── __init__.py │ ├── _config.yml │ ├── _toc.yml │ ├── aviary.png │ ├── aviary.svg │ ├── aviary_logo.png │ ├── build_book.sh │ ├── build_source_docs.py │ ├── developer_guide │ │ ├── ai_policy.md │ │ ├── codebase_overview.ipynb │ │ ├── coding_standards.ipynb │ │ ├── contributing_guidelines.md │ │ ├── debugging_env_from_github.md │ │ ├── doctape.ipynb │ │ ├── doctape_examples.ipynb │ │ ├── failing_pr.png │ │ ├── gh_actions.png │ │ ├── how_to_contribute_docs.md │ │ └── unit_tests.md │ ├── examples │ │ ├── OAS_subsystem.ipynb │ │ ├── additional_flight_phases.ipynb │ │ ├── coupled_aircraft_mission_optimization.ipynb │ │ ├── images │ │ │ ├── OAS_xdsm.PNG │ │ │ ├── advanced_results.png │ │ │ ├── blank_flight_profile.png │ │ │ ├── cubic_advanced_results.png │ │ │ ├── fixed_range_cruise_altitude.png │ │ │ ├── fixed_range_cruise_distance.png │ │ │ ├── fixed_range_cruise_mass.png │ │ │ ├── flight_profile.png │ │ │ ├── landing.png │ │ │ ├── multi_mission.png │ │ │ ├── multiphase_flight_profile.png │ │ │ ├── multiphase_reserve.png │ │ │ ├── multiple_phases_gui.png │ │ │ ├── takeoff.png │ │ │ └── traj_results.png │ │ ├── intro.ipynb │ │ ├── level_2_detailed_takeoff_and_landing.ipynb │ │ ├── modified_aircraft.csv │ │ ├── more_advanced_example.ipynb │ │ ├── multi_mission.ipynb │ │ ├── off_design_example.ipynb │ │ ├── reserve_missions.ipynb │ │ └── simple_mission_example.ipynb │ ├── getting_started │ │ ├── expected_user_knowledge.md │ │ ├── images │ │ │ ├── N2_phases.PNG │ │ │ ├── N2_phases_links.PNG │ │ │ ├── N2_start.PNG │ │ │ ├── N2_top.PNG │ │ │ ├── driver_scaling_report_top.PNG │ │ │ ├── expected_user_knowledge.svg │ │ │ ├── input_list_top.PNG │ │ │ ├── inputs_html_top.PNG │ │ │ ├── opt_report_top.PNG │ │ │ ├── tool_stack.svg │ │ │ ├── traj_linkage_report_top.PNG │ │ │ ├── traj_results_report_altitude.PNG │ │ │ ├── traj_results_report_top.PNG │ │ │ └── traj_results_report_top_ascent.PNG │ │ ├── input_csv_phase_info.ipynb │ │ ├── installation.md │ │ ├── now_what.md │ │ ├── onboarding.md │ │ ├── onboarding_ext_subsystem.ipynb │ │ ├── onboarding_level1.ipynb │ │ ├── onboarding_level2.ipynb │ │ ├── onboarding_level3.ipynb │ │ ├── tools_that_aviary_uses.md │ │ └── what_aviary_does.md │ ├── intro.md │ ├── misc_resources │ │ ├── FAQ.md │ │ ├── comparison_to_flops.md │ │ ├── externally_supported_subsystems.ipynb │ │ ├── feature_comparison.md │ │ ├── glossary.md │ │ ├── images │ │ │ └── sample_aviary_xdsm.PNG │ │ ├── modeling_exercise.ipynb │ │ ├── planned_future_features.md │ │ └── resources.md │ ├── tests │ │ ├── __init__.py │ │ └── check_jupyter_output_linting.py │ ├── theory_guide │ │ ├── aerodynamics.md │ │ ├── assumptions.md │ │ ├── building_metadata_syntax.ipynb │ │ ├── geometry.md │ │ ├── images │ │ │ ├── aircraft_force_diagram.png │ │ │ ├── mission_simple.png │ │ │ ├── turboprop_connections.png │ │ │ └── turboprop_promotions.png │ │ ├── intro.ipynb │ │ ├── mass.md │ │ ├── merging_syntax.ipynb │ │ ├── mission.md │ │ ├── optimization_algorithms.md │ │ ├── propulsion.ipynb │ │ ├── turboprop.ipynb │ │ ├── underlying_concepts.md │ │ └── validation.md │ └── user_guide │ │ ├── FLOPS_based_detailed_takeoff_and_landing.ipynb │ │ ├── SGM_capabilities.ipynb │ │ ├── UI_Levels.md │ │ ├── aerodynamics.ipynb │ │ ├── aviary_commands.ipynb │ │ ├── battery_subsystem_example.ipynb │ │ ├── blended_wing_body.md │ │ ├── creating_a_turboprop_engine.ipynb │ │ ├── drawing_and_running_simple_missions.ipynb │ │ ├── example.csv │ │ ├── examples_of_the_same_mission_at_different_UI_levels.ipynb │ │ ├── external_aero.ipynb │ │ ├── features │ │ └── overriding.ipynb │ │ ├── features_and_functionalities.ipynb │ │ ├── hamilton_standard.ipynb │ │ ├── images │ │ ├── BWB_GASP_Fuselage_Geometry.png │ │ ├── BWB_engine.png │ │ ├── CPE_CTE_matching.png │ │ ├── aviary_process.png │ │ ├── dashboard.png │ │ ├── external_subsystem_methods.png │ │ ├── gui_main.png │ │ ├── hamilton_standard.png │ │ ├── installation_loss_factor.png │ │ ├── levels.png │ │ ├── more_levels.png │ │ ├── pre_mission_and_mission.svg │ │ └── subsystems.png │ │ ├── input_files.ipynb │ │ ├── mass.ipynb │ │ ├── multi_mission.ipynb │ │ ├── off_design_missions.ipynb │ │ ├── postprocessing_and_visualizing_results.ipynb │ │ ├── pre_mission_and_mission.ipynb │ │ ├── propulsion.ipynb │ │ ├── reserve_missions.ipynb │ │ ├── step_by_step_external_guide.ipynb │ │ ├── subsystems.ipynb │ │ ├── troubleshooting.ipynb │ │ ├── user_interface.md │ │ ├── using_external_subsystems.md │ │ ├── variable_hierarchy.ipynb │ │ └── variable_metadata.ipynb ├── examples │ ├── N3CC_level3.py │ ├── __init__.py │ ├── example_phase_info.py │ ├── external_subsystems │ │ ├── OAS_weight │ │ │ ├── OAS_wing_weight_analysis.py │ │ │ ├── OAS_wing_weight_builder.py │ │ │ ├── __init__.py │ │ │ ├── run_simple_OAS_mission.py │ │ │ ├── test_OAS_wing_weight_analysis.py │ │ │ └── test_OAS_wing_weight_builder.py │ │ ├── __init__.py │ │ ├── battery │ │ │ ├── __init__.py │ │ │ ├── battery_builder.py │ │ │ ├── battery_variable_meta_data.py │ │ │ ├── battery_variables.py │ │ │ ├── model │ │ │ │ ├── __init__.py │ │ │ │ ├── battery_mission.py │ │ │ │ ├── battery_premission.py │ │ │ │ ├── cell_comp.py │ │ │ │ ├── reg_thevenin_interp_group.py │ │ │ │ └── test_cell_comp.py │ │ │ ├── run_cruise.py │ │ │ ├── run_multiphase_mission.py │ │ │ └── test_battery_builder.py │ │ ├── custom_aero │ │ │ ├── __init__.py │ │ │ ├── custom_aero_builder.py │ │ │ ├── run_simple_aero.py │ │ │ └── simple_drag.py │ │ ├── engine_NPSS │ │ │ ├── NPSS_Model │ │ │ │ ├── DesignEngineGroup.py │ │ │ │ ├── Design_files │ │ │ │ │ ├── input.int │ │ │ │ │ └── output.int │ │ │ │ ├── Maps_and_Elements │ │ │ │ │ ├── 3Dmaps.int │ │ │ │ │ ├── HPC.map │ │ │ │ │ ├── HPT.map │ │ │ │ │ ├── Performance.int │ │ │ │ │ ├── npss.view_Aviary │ │ │ │ │ ├── npss.view_flops │ │ │ │ │ └── npss.view_page │ │ │ │ ├── Output │ │ │ │ │ ├── RefEngine.outputAviary │ │ │ │ │ └── turbojet.viewOut │ │ │ │ ├── engine.case_Aviary │ │ │ │ ├── engine.case_Aviary_min │ │ │ │ ├── turbojet.fnc │ │ │ │ ├── turbojet.mdl │ │ │ │ └── turbojet.run │ │ │ ├── define_simple_engine_problem.py │ │ │ ├── engine_variable_meta_data.py │ │ │ ├── engine_variables.py │ │ │ ├── table_engine_builder.py │ │ │ ├── table_engine_connected_variables.py │ │ │ └── test_NPSS_builder.py │ │ └── simple_weight │ │ │ ├── __init__.py │ │ │ ├── run_simple_weight.py │ │ │ ├── simple_weight.py │ │ │ └── simple_weight_builder.py │ ├── level1_example.py │ ├── level2_example.py │ ├── level2_shooting_traj.py │ ├── level2_with_detailed_landing.py │ ├── level2_with_detailed_takeoff.py │ ├── multi_mission │ │ └── run_multimission_example_large_single_aisle.py │ ├── off_design_example.py │ ├── reserve_missions │ │ ├── run_2dof_reserve_mission_fixedrange.py │ │ ├── run_2dof_reserve_mission_fixedtime.py │ │ ├── run_2dof_reserve_mission_multiphase.py │ │ ├── run_reserve_mission_fixedrange.py │ │ ├── run_reserve_mission_fixedtime.py │ │ └── run_reserve_mission_multiphase.py │ ├── test │ │ ├── __init__.py │ │ ├── test_all_examples.py │ │ └── test_level2_shooting_traj.py │ ├── variable_meta_data_extension.py │ └── variables_extension.py ├── interface │ ├── __init__.py │ ├── cmd_entry_points.py │ ├── default_phase_info │ │ ├── __init__.py │ │ ├── height_energy.py │ │ ├── height_energy_fiti.py │ │ ├── two_dof.py │ │ ├── two_dof_fiti.py │ │ └── two_dof_fiti_deprecated.py │ ├── download_models.py │ ├── graphical_input.py │ ├── methods_for_level1.py │ ├── methods_for_level2.py │ ├── plot_drag_polar.py │ ├── reports.py │ ├── static │ │ ├── aviary_logo_16.png │ │ ├── aviary_logo_32.png │ │ ├── dark_mode.png │ │ ├── light_mode.png │ │ └── mac_theme.png │ ├── test │ │ ├── __init__.py │ │ ├── sizing_problem_for_test.json │ │ ├── specially_named_for_tests.deck │ │ ├── test_check_phase_info.py │ │ ├── test_cmd_entry_points.py │ │ ├── test_download_models.py │ │ ├── test_height_energy_mission.py │ │ ├── test_installation_test.py │ │ ├── test_interface_bugs.py │ │ ├── test_json.py │ │ ├── test_linkage_logic.py │ │ ├── test_phase_info.py │ │ ├── test_preprocess.py │ │ ├── test_reports.py │ │ └── test_reserve_support.py │ ├── test_installation.py │ └── utils │ │ ├── __init__.py │ │ ├── check_phase_info.py │ │ └── markdown_utils.py ├── mission │ ├── __init__.py │ ├── base_ode.py │ ├── flight_phase_builder.py │ ├── flops_based │ │ ├── __init__.py │ │ ├── ode │ │ │ ├── __init__.py │ │ │ ├── energy_ODE.py │ │ │ ├── landing_eom.py │ │ │ ├── landing_ode.py │ │ │ ├── mission_EOM.py │ │ │ ├── range_rate.py │ │ │ ├── required_thrust.py │ │ │ ├── takeoff_eom.py │ │ │ ├── takeoff_ode.py │ │ │ └── test │ │ │ │ ├── __init__.py │ │ │ │ ├── test_landing_eom.py │ │ │ │ ├── test_landing_ode.py │ │ │ │ ├── test_mission_eom.py │ │ │ │ ├── test_range_rate.py │ │ │ │ ├── test_required_thrust.py │ │ │ │ ├── test_takeoff_eom.py │ │ │ │ └── test_takeoff_ode.py │ │ └── phases │ │ │ ├── __init__.py │ │ │ ├── build_landing.py │ │ │ ├── build_takeoff.py │ │ │ ├── detailed_landing_phases.py │ │ │ ├── detailed_takeoff_phases.py │ │ │ ├── energy_phase.py │ │ │ ├── groundroll_phase.py │ │ │ ├── phase_utils.py │ │ │ ├── simplified_landing.py │ │ │ ├── simplified_takeoff.py │ │ │ ├── test │ │ │ ├── __init__.py │ │ │ ├── test_building_landing.py │ │ │ ├── test_building_takeoff.py │ │ │ ├── test_simplified_landing.py │ │ │ ├── test_simplified_takeoff.py │ │ │ └── test_time_integration_phases.py │ │ │ └── time_integration_phases.py │ ├── gasp_based │ │ ├── __init__.py │ │ ├── idle_descent_estimation.py │ │ ├── ode │ │ │ ├── __init__.py │ │ │ ├── accel_eom.py │ │ │ ├── accel_ode.py │ │ │ ├── ascent_eom.py │ │ │ ├── ascent_ode.py │ │ │ ├── breguet_cruise_eom.py │ │ │ ├── breguet_cruise_ode.py │ │ │ ├── climb_eom.py │ │ │ ├── climb_ode.py │ │ │ ├── constraints │ │ │ │ ├── __init__.py │ │ │ │ ├── flight_constraints.py │ │ │ │ ├── speed_constraints.py │ │ │ │ └── test │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── test_climb_constraints.py │ │ │ │ │ └── test_flight_constraints.py │ │ │ ├── descent_eom.py │ │ │ ├── descent_ode.py │ │ │ ├── flight_path_eom.py │ │ │ ├── flight_path_ode.py │ │ │ ├── groundroll_eom.py │ │ │ ├── groundroll_ode.py │ │ │ ├── landing_eom.py │ │ │ ├── landing_ode.py │ │ │ ├── params.py │ │ │ ├── rotation_eom.py │ │ │ ├── rotation_ode.py │ │ │ ├── taxi_eom.py │ │ │ ├── taxi_ode.py │ │ │ ├── test │ │ │ │ ├── __init__.py │ │ │ │ ├── test_accel_eom.py │ │ │ │ ├── test_accel_ode.py │ │ │ │ ├── test_ascent_eom.py │ │ │ │ ├── test_ascent_ode.py │ │ │ │ ├── test_breguet_cruise_eom.py │ │ │ │ ├── test_breguet_cruise_ode.py │ │ │ │ ├── test_climb_eom.py │ │ │ │ ├── test_climb_ode.py │ │ │ │ ├── test_data │ │ │ │ │ └── turbofan_23k_electrified.deck │ │ │ │ ├── test_descent_eom.py │ │ │ │ ├── test_descent_ode.py │ │ │ │ ├── test_flight_path_eom.py │ │ │ │ ├── test_flight_path_ode.py │ │ │ │ ├── test_groundroll_eom.py │ │ │ │ ├── test_groundroll_ode.py │ │ │ │ ├── test_landing_eom.py │ │ │ │ ├── test_landing_ode.py │ │ │ │ ├── test_rotation_eom.py │ │ │ │ ├── test_rotation_ode.py │ │ │ │ ├── test_taxi_eom.py │ │ │ │ ├── test_taxi_ode.py │ │ │ │ └── test_v_rotate_comp.py │ │ │ ├── time_integration_base_classes.py │ │ │ ├── two_dof_ode.py │ │ │ ├── unsteady_solved │ │ │ │ ├── __init__.py │ │ │ │ ├── gamma_comp.py │ │ │ │ ├── test │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── test_gamma_comp.py │ │ │ │ │ ├── test_unsteady_alpha_thrust_iter_group.py │ │ │ │ │ ├── test_unsteady_flight_conditions.py │ │ │ │ │ ├── test_unsteady_solved_eom.py │ │ │ │ │ └── test_unsteady_solved_ode.py │ │ │ │ ├── unsteady_control_iter_group.py │ │ │ │ ├── unsteady_solved_eom.py │ │ │ │ ├── unsteady_solved_flight_conditions.py │ │ │ │ └── unsteady_solved_ode.py │ │ │ └── v_rotate_comp.py │ │ ├── phases │ │ │ ├── __init__.py │ │ │ ├── accel_phase.py │ │ │ ├── ascent_phase.py │ │ │ ├── climb_phase.py │ │ │ ├── cruise_phase.py │ │ │ ├── descent_phase.py │ │ │ ├── groundroll_phase.py │ │ │ ├── rotation_phase.py │ │ │ ├── test │ │ │ │ └── __init__.py │ │ │ ├── time_integration_phases.py │ │ │ ├── time_integration_traj.py │ │ │ └── twodof_phase.py │ │ ├── polynomial_fit.py │ │ └── test │ │ │ ├── __init__.py │ │ │ ├── test_idle_descent_estimation.py │ │ │ └── test_polynomial_fit.py │ ├── height_energy_problem_configurator.py │ ├── initial_guess_builders.py │ ├── ode │ │ ├── __init__.py │ │ ├── altitude_rate.py │ │ ├── specific_energy_rate.py │ │ └── test │ │ │ ├── __init__.py │ │ │ ├── test_altitude_rate.py │ │ │ └── test_specific_energy_rate.py │ ├── phase_builder_base.py │ ├── problem_configurator.py │ ├── solved_two_dof_problem_configurator.py │ ├── test │ │ ├── __init__.py │ │ └── test_external_subsystems_in_mission.py │ ├── two_dof_problem_configurator.py │ └── utils.py ├── models │ ├── BWB │ │ ├── generic_BWB_GASP.csv │ │ └── generic_BWB_GASP.dat │ ├── N3CC │ │ ├── N3CC_FLOPS.csv │ │ ├── N3CC_data.py │ │ ├── N3CC_generic_low_speed_polars_FLOPS.txt │ │ ├── __init__.py │ │ └── phase_info.py │ ├── __init__.py │ ├── engines │ │ ├── propellers │ │ │ ├── PropFan.map │ │ │ ├── PropFan.prop │ │ │ ├── general_aviation.map │ │ │ └── general_aviation.prop │ │ ├── turbofan_22k.deck │ │ ├── turbofan_22k.txt │ │ ├── turbofan_23k_1.deck │ │ ├── turbofan_23k_1_lbm_s.deck │ │ ├── turbofan_24k_1.deck │ │ ├── turbofan_24k_2.deck │ │ ├── turbofan_28k.deck │ │ ├── turbofan_28k_with_electric.deck │ │ ├── turboshaft_1120hp.deck │ │ ├── turboshaft_1120hp_no_tailpipe.deck │ │ └── turboshaft_4465hp.deck │ ├── large_single_aisle_1 │ │ ├── V3_bug_fixed_IO.py │ │ ├── __init__.py │ │ ├── large_single_aisle_1_FLOPS_data.py │ │ ├── large_single_aisle_1_GASP.csv │ │ └── large_single_aisle_1_GASP.dat │ ├── large_single_aisle_2 │ │ ├── __init__.py │ │ ├── large_single_aisle_2_FLOPS_data.py │ │ ├── large_single_aisle_2_altwt_FLOPS_data.py │ │ └── large_single_aisle_2_detailwing_FLOPS_data.py │ ├── large_turboprop_freighter │ │ ├── __init__.py │ │ ├── large_turboprop_freighter_GASP.csv │ │ ├── large_turboprop_freighter_GASP.dat │ │ └── phase_info.py │ ├── multi_engine_single_aisle │ │ ├── __init__.py │ │ └── multi_engine_single_aisle_data.py │ ├── small_single_aisle │ │ ├── small_single_aisle_GASP.csv │ │ └── small_single_aisle_GASP.dat │ └── test_aircraft │ │ ├── GwFm_phase_info.py │ │ ├── aircraft_for_bench_FwFm.csv │ │ ├── aircraft_for_bench_FwFm_with_electric.csv │ │ ├── aircraft_for_bench_FwGm.csv │ │ ├── aircraft_for_bench_GwFm.csv │ │ ├── aircraft_for_bench_GwGm.csv │ │ ├── aircraft_for_bench_GwGm_lbm_s.csv │ │ ├── aircraft_for_bench_solved2dof.csv │ │ └── configuration_test_GASP.csv ├── run_all_benchmarks.py ├── subsystems │ ├── __init__.py │ ├── aerodynamics │ │ ├── __init__.py │ │ ├── aero_common.py │ │ ├── aerodynamics_builder.py │ │ ├── flops_based │ │ │ ├── __init__.py │ │ │ ├── buffet_lift.py │ │ │ ├── compressibility_drag.py │ │ │ ├── computed_aero_group.py │ │ │ ├── design.py │ │ │ ├── drag.py │ │ │ ├── drag_polar.py │ │ │ ├── ground_effect.py │ │ │ ├── induced_drag.py │ │ │ ├── lift.py │ │ │ ├── lift_dependent_drag.py │ │ │ ├── mux_component.py │ │ │ ├── skin_friction.py │ │ │ ├── skin_friction_drag.py │ │ │ ├── tabular_aero_group.py │ │ │ ├── takeoff_aero_group.py │ │ │ └── test │ │ │ │ ├── __init__.py │ │ │ │ ├── data │ │ │ │ └── high_wing_single_aisle.csv │ │ │ │ ├── large_single_aisle_1_CD0_polar.csv │ │ │ │ ├── large_single_aisle_1_CDI_polar.csv │ │ │ │ ├── test_buffet_lift.py │ │ │ │ ├── test_compressibility_drag.py │ │ │ │ ├── test_computed_aero_group.py │ │ │ │ ├── test_design.py │ │ │ │ ├── test_drag.py │ │ │ │ ├── test_ground_effect.py │ │ │ │ ├── test_induced_drag.py │ │ │ │ ├── test_lift.py │ │ │ │ ├── test_lift_dependent_drag.py │ │ │ │ ├── test_mux_component.py │ │ │ │ ├── test_skinfriction_coef.py │ │ │ │ ├── test_skinfriction_drag.py │ │ │ │ ├── test_tabular_aero_group.py │ │ │ │ └── test_takeoff_aero_group.py │ │ ├── gasp_based │ │ │ ├── __init__.py │ │ │ ├── common.py │ │ │ ├── data │ │ │ │ ├── GASP_aero_flaps.txt │ │ │ │ ├── GASP_aero_free.txt │ │ │ │ ├── GASP_aero_free_reduced_alpha.txt │ │ │ │ ├── GASP_aero_ground.txt │ │ │ │ ├── __init__.py │ │ │ │ ├── large_single_aisle_1_aero_flaps.txt │ │ │ │ ├── large_single_aisle_1_aero_free.txt │ │ │ │ ├── large_single_aisle_1_aero_free_reduced_alpha.txt │ │ │ │ └── large_single_aisle_1_aero_ground.txt │ │ │ ├── flaps_model │ │ │ │ ├── Cl_max.py │ │ │ │ ├── L_and_D_increments.py │ │ │ │ ├── __init__.py │ │ │ │ ├── basic_calculations.py │ │ │ │ ├── flaps_model.py │ │ │ │ ├── meta_model.py │ │ │ │ └── test │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── test_Clmax.py │ │ │ │ │ ├── test_basic_calculations.py │ │ │ │ │ ├── test_flaps_group.py │ │ │ │ │ ├── test_increments.py │ │ │ │ │ └── test_metamodel.py │ │ │ ├── gasp_aero_coeffs.py │ │ │ ├── gaspaero.py │ │ │ ├── interference.py │ │ │ ├── premission_aero.py │ │ │ ├── table_based.py │ │ │ └── test │ │ │ │ ├── __init__.py │ │ │ │ ├── data │ │ │ │ ├── aero_data_cruise.csv │ │ │ │ ├── aero_data_ground.csv │ │ │ │ └── aero_data_setup.json │ │ │ │ ├── test_common.py │ │ │ │ ├── test_gasp_aero_coeffs.py │ │ │ │ ├── test_gaspaero.py │ │ │ │ ├── test_interference.py │ │ │ │ ├── test_solved_aero_group.py │ │ │ │ └── test_table_based.py │ │ ├── solve_alpha_group.py │ │ └── test │ │ │ ├── __init__.py │ │ │ ├── test_external_mission_aero.py │ │ │ ├── test_flops_aero_builder.py │ │ │ ├── test_gasp_aero_builder.py │ │ │ └── test_gasp_drag.py │ ├── atmosphere │ │ ├── __init__.py │ │ ├── atmosphere.py │ │ ├── flight_conditions.py │ │ └── test │ │ │ └── test_flight_conditions.py │ ├── energy │ │ ├── __init__.py │ │ ├── battery_builder.py │ │ ├── battery_sizing.py │ │ └── test │ │ │ ├── __init__.py │ │ │ └── test_battery.py │ ├── geometry │ │ ├── __init__.py │ │ ├── combined_geometry.py │ │ ├── flops_based │ │ │ ├── __init__.py │ │ │ ├── canard.py │ │ │ ├── characteristic_lengths.py │ │ │ ├── fuselage.py │ │ │ ├── nacelle.py │ │ │ ├── prep_geom.py │ │ │ ├── test │ │ │ │ ├── __init__.py │ │ │ │ ├── test_characteristic_lengths.py │ │ │ │ ├── test_nacelle.py │ │ │ │ └── test_prep_geom.py │ │ │ ├── utils.py │ │ │ ├── wetted_area_total.py │ │ │ └── wing.py │ │ ├── gasp_based │ │ │ ├── __init__.py │ │ │ ├── electric.py │ │ │ ├── empennage.py │ │ │ ├── engine.py │ │ │ ├── fuselage.py │ │ │ ├── non_dimensional_conversion.py │ │ │ ├── size_group.py │ │ │ ├── strut.py │ │ │ ├── test │ │ │ │ ├── __init__.py │ │ │ │ ├── test_electric.py │ │ │ │ ├── test_empennage.py │ │ │ │ ├── test_engine.py │ │ │ │ ├── test_fuselage.py │ │ │ │ ├── test_non_dimensional_conversion.py │ │ │ │ ├── test_override.py │ │ │ │ ├── test_size_group.py │ │ │ │ ├── test_strut.py │ │ │ │ └── test_wing.py │ │ │ └── wing.py │ │ ├── geometry_builder.py │ │ └── test │ │ │ ├── test_flops_geom_builder.py │ │ │ └── test_gasp_geom_builder.py │ ├── mass │ │ ├── __init__.py │ │ ├── flops_based │ │ │ ├── __init__.py │ │ │ ├── air_conditioning.py │ │ │ ├── anti_icing.py │ │ │ ├── apu.py │ │ │ ├── avionics.py │ │ │ ├── canard.py │ │ │ ├── cargo.py │ │ │ ├── cargo_containers.py │ │ │ ├── crew.py │ │ │ ├── distributed_prop.py │ │ │ ├── electrical.py │ │ │ ├── empty_margin.py │ │ │ ├── engine.py │ │ │ ├── engine_controls.py │ │ │ ├── engine_oil.py │ │ │ ├── engine_pod.py │ │ │ ├── fin.py │ │ │ ├── fuel_capacity.py │ │ │ ├── fuel_system.py │ │ │ ├── furnishings.py │ │ │ ├── fuselage.py │ │ │ ├── horizontal_tail.py │ │ │ ├── hydraulics.py │ │ │ ├── instruments.py │ │ │ ├── landing_gear.py │ │ │ ├── landing_group.py │ │ │ ├── landing_mass.py │ │ │ ├── mass_premission.py │ │ │ ├── mass_summation.py │ │ │ ├── misc_engine.py │ │ │ ├── nacelle.py │ │ │ ├── paint.py │ │ │ ├── passenger_service.py │ │ │ ├── starter.py │ │ │ ├── surface_controls.py │ │ │ ├── test │ │ │ │ ├── __init__.py │ │ │ │ ├── test_air_conditioning.py │ │ │ │ ├── test_anti_icing.py │ │ │ │ ├── test_apu.py │ │ │ │ ├── test_avionics.py │ │ │ │ ├── test_canard.py │ │ │ │ ├── test_cargo.py │ │ │ │ ├── test_cargo_containers.py │ │ │ │ ├── test_crew.py │ │ │ │ ├── test_distributed_prop.py │ │ │ │ ├── test_electrical.py │ │ │ │ ├── test_empty_margin.py │ │ │ │ ├── test_engine.py │ │ │ │ ├── test_engine_controls.py │ │ │ │ ├── test_engine_oil.py │ │ │ │ ├── test_engine_pod.py │ │ │ │ ├── test_fin.py │ │ │ │ ├── test_fuel_capacity.py │ │ │ │ ├── test_fuel_system.py │ │ │ │ ├── test_furnishings.py │ │ │ │ ├── test_fuselage.py │ │ │ │ ├── test_horizontail_tail.py │ │ │ │ ├── test_hydraulics.py │ │ │ │ ├── test_instruments.py │ │ │ │ ├── test_landing_gear.py │ │ │ │ ├── test_landing_mass.py │ │ │ │ ├── test_mass_summation.py │ │ │ │ ├── test_misc_engine.py │ │ │ │ ├── test_nacelle.py │ │ │ │ ├── test_paint.py │ │ │ │ ├── test_passenger_service.py │ │ │ │ ├── test_starter.py │ │ │ │ ├── test_surface_controls.py │ │ │ │ ├── test_thrust_reverser.py │ │ │ │ ├── test_unusable_fuel.py │ │ │ │ ├── test_vertical_tail.py │ │ │ │ ├── test_wing_common.py │ │ │ │ ├── test_wing_detailed.py │ │ │ │ └── test_wing_simple.py │ │ │ ├── thrust_reverser.py │ │ │ ├── unusable_fuel.py │ │ │ ├── vertical_tail.py │ │ │ ├── wing_common.py │ │ │ ├── wing_detailed.py │ │ │ ├── wing_group.py │ │ │ └── wing_simple.py │ │ ├── gasp_based │ │ │ ├── __init__.py │ │ │ ├── design_load.py │ │ │ ├── equipment_and_useful_load.py │ │ │ ├── fixed.py │ │ │ ├── fuel.py │ │ │ ├── mass_premission.py │ │ │ ├── test │ │ │ │ ├── __init__.py │ │ │ │ ├── test_design_load.py │ │ │ │ ├── test_equipment_and_useful_load.py │ │ │ │ ├── test_fixed.py │ │ │ │ ├── test_fuel.py │ │ │ │ ├── test_mass_summation.py │ │ │ │ └── test_wing.py │ │ │ └── wing.py │ │ ├── mass_builder.py │ │ ├── mass_to_weight.py │ │ └── test │ │ │ ├── __init__.py │ │ │ ├── test_flops_mass_builder.py │ │ │ ├── test_gasp_mass_builder.py │ │ │ └── test_mass_to_weight.py │ ├── premission.py │ ├── propulsion │ │ ├── __init__.py │ │ ├── engine_deck.py │ │ ├── engine_model.py │ │ ├── engine_scaling.py │ │ ├── engine_sizing.py │ │ ├── gearbox │ │ │ ├── __init__.py │ │ │ ├── gearbox_builder.py │ │ │ ├── model │ │ │ │ ├── __init__.py │ │ │ │ ├── gearbox_mission.py │ │ │ │ └── gearbox_premission.py │ │ │ └── test │ │ │ │ ├── __init__.py │ │ │ │ └── test_gearbox.py │ │ ├── motor │ │ │ ├── __init__.py │ │ │ ├── model │ │ │ │ ├── __init__.py │ │ │ │ ├── motor_map.py │ │ │ │ ├── motor_mission.py │ │ │ │ └── motor_premission.py │ │ │ ├── motor_builder.py │ │ │ └── test │ │ │ │ ├── test_motor_map.py │ │ │ │ ├── test_motor_mission.py │ │ │ │ └── test_motor_premission.py │ │ ├── propeller │ │ │ ├── __init__.py │ │ │ ├── hamilton_standard.py │ │ │ ├── propeller_builder.py │ │ │ ├── propeller_map.py │ │ │ ├── propeller_performance.py │ │ │ └── test │ │ │ │ ├── test_hamilton_standard.py │ │ │ │ ├── test_propeller_map.py │ │ │ │ └── test_propeller_performance.py │ │ ├── propulsion_builder.py │ │ ├── propulsion_mission.py │ │ ├── propulsion_premission.py │ │ ├── test │ │ │ ├── __init__.py │ │ │ ├── engine_model_test_data_turbofan_24k_1.csv │ │ │ ├── engine_model_test_data_turbofan_28k.csv │ │ │ ├── test_custom_engine_model.py │ │ │ ├── test_data_interpolator.py │ │ │ ├── test_engine_deck.py │ │ │ ├── test_engine_scaling.py │ │ │ ├── test_engine_sizing.py │ │ │ ├── test_propulsion_mission.py │ │ │ ├── test_propulsion_premission.py │ │ │ ├── test_throttle_allocation.py │ │ │ └── test_turboprop_model.py │ │ ├── throttle_allocation.py │ │ ├── turboprop_model.py │ │ └── utils.py │ ├── subsystem_builder_base.py │ └── test │ │ ├── __init__.py │ │ ├── subsystem_tester.py │ │ ├── test_dummy_subsystem.py │ │ ├── test_external_subsystem_bus.py │ │ ├── test_flops_based_premission.py │ │ └── test_premission.py ├── utils │ ├── __init__.py │ ├── aero_table_conversion.py │ ├── aviary_options_dict.py │ ├── aviary_values.py │ ├── compare_hierarchies.py │ ├── conflict_checks.py │ ├── conversion_utils.py │ ├── csv_data_file.py │ ├── data_interpolator_builder.py │ ├── develop_metadata.py │ ├── doctape.py │ ├── engine_deck_conversion.py │ ├── fortran_to_aviary.py │ ├── functions.py │ ├── legacy_code_data │ │ ├── __init__.py │ │ ├── flops_defaults.py │ │ └── gasp_defaults.py │ ├── merge_hierarchies.py │ ├── merge_variable_metadata.py │ ├── named_values.py │ ├── options.py │ ├── preprocessors.py │ ├── process_input_decks.py │ ├── propeller_map_conversion.py │ ├── test │ │ ├── data │ │ │ ├── configuration_test_data_GASP.dat │ │ │ ├── converter_test_BWB_GASP.csv │ │ │ ├── converter_test_N3CC_FLOPS.csv │ │ │ ├── converter_test_configuration_GASP.csv │ │ │ ├── converter_test_large_single_aisle_1_GASP.csv │ │ │ ├── converter_test_small_single_aisle_GASP.csv │ │ │ ├── csv_test.csv │ │ │ ├── flops_test_polar.txt │ │ │ ├── test_drag_polar_data.csv │ │ │ ├── turbofan_22k.txt │ │ │ ├── turbofan_23k_1.eng │ │ │ └── turboshaft_4465hp.eng │ │ ├── test_aero_table_conversion.py │ │ ├── test_aviary_options_dict.py │ │ ├── test_aviary_values.py │ │ ├── test_compare_hierarchies.py │ │ ├── test_csv_data_file.py │ │ ├── test_doctape.py │ │ ├── test_engine_deck_conversion.py │ │ ├── test_fortran_to_aviary.py │ │ ├── test_functions.py │ │ ├── test_merge_hierarchies.py │ │ ├── test_merge_metadata.py │ │ ├── test_named_values.py │ │ ├── test_process_input_decks.py │ │ └── test_propeller_map_conversion.py │ ├── test_utils │ │ ├── IO_test_util.py │ │ ├── __init__.py │ │ ├── assert_utils.py │ │ ├── default_subsystems.py │ │ └── variable_test.py │ └── utils.py ├── validation_cases │ ├── __init__.py │ ├── benchmark_tests │ │ ├── __init__.py │ │ ├── test_0_iters.py │ │ ├── test_FLOPS_balanced_field_length.py │ │ ├── test_FLOPS_based_sizing_N3CC.py │ │ ├── test_FLOPS_detailed_landing.py │ │ ├── test_FLOPS_detailed_takeoff.py │ │ ├── test_battery_in_a_mission.py │ │ ├── test_bench_FwFm.py │ │ ├── test_bench_FwGm.py │ │ ├── test_bench_GwFm.py │ │ ├── test_bench_GwGm.py │ │ ├── test_bench_electrified_large_turboprop_freighter.py │ │ ├── test_bench_large_turboprop_freighter.py │ │ ├── test_bench_multiengine.py │ │ ├── test_off_design_FwFm.py │ │ ├── test_off_design_GwGm.py │ │ └── test_subsystems_within_a_mission.py │ ├── benchmark_utils.py │ ├── validation_data │ │ ├── __init__.py │ │ └── flops_data │ │ │ ├── FLOPS_Test_Data.py │ │ │ ├── __init__.py │ │ │ ├── engine_only │ │ │ └── turbofan_23k_2.deck │ │ │ └── full_mission_test_data.py │ └── validation_tests.py ├── variable_info │ ├── __init__.py │ ├── enums.py │ ├── functions.py │ ├── options.py │ ├── test │ │ ├── __init__.py │ │ ├── test_functions.py │ │ ├── test_metadata_extension.py │ │ └── test_var_structure.py │ ├── variable_meta_data.py │ └── variables.py └── visualization │ ├── __init__.py │ ├── aircraft_3d_model.py │ ├── assets │ ├── Airplane_fbx.zip │ ├── aircraft_3d_file_template.html │ ├── aviary_airlines.png │ ├── aviary_logo.png │ ├── aviary_styles.css │ ├── aviary_vars │ │ ├── index.html │ │ └── script.js │ ├── plane_model.html │ ├── sellar_recording_data.csv │ └── uploads_files_3981625_Bayraktar+TB2.glb │ └── dashboard.py ├── environment.yml └── pyproject.toml /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.10.0-dev 3 | commit = False 4 | tag = False 5 | parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? 6 | serialize = 7 | {major}.{minor}.{patch}-{release} 8 | {major}.{minor}.{patch} 9 | 10 | [bumpversion:file:aviary/__init__.py] 11 | search = __version__ = '{current_version}' 12 | replace = __version__ = '{new_version}' 13 | 14 | [bumpversion:file:.github/ISSUE_TEMPLATE/bug_report.yml] 15 | search = placeholder: "{current_version}" 16 | replace = placeholder: "{new_version}" 17 | 18 | [bumpversion:part:release] 19 | optional_value = rel 20 | values = 21 | dev 22 | rel 23 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | *.sh text eol=lf -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Submit a report only if you believe you've found a bug in Aviary. If you're not sure if your problem is a bug, especially for installation issues, try reaching out on the discussions page first. 3 | labels: ["bug"] 4 | body: 5 | - type: textarea 6 | id: description 7 | attributes: 8 | label: Description 9 | description: Please explain what is happening and how it differs from the expected behavior. 10 | validations: 11 | required: true 12 | - type: textarea 13 | id: example 14 | attributes: 15 | label: Example 16 | description: Please provide an example of the code that triggers the unexpected behavior. If possible, create a complete, minimal test case that reproduces the issue. Alternatively, link to a file in another repository where the issue is demonstrated. 17 | validations: 18 | required: true 19 | - type: input 20 | id: aviary-version 21 | attributes: 22 | label: Aviary Version 23 | description: What version of Aviary is being used. 24 | placeholder: "0.10.0-dev" 25 | validations: 26 | required: true 27 | - type: textarea 28 | id: environment 29 | attributes: 30 | label: Relevant environment information 31 | description: If applicable, please provide versions of relevant dependencies (numpy, scipy, MPI, etc). This can be obtained from `pip freeze`. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Discussion Board 4 | url: https://github.com/OpenMDAO/Aviary/discussions 5 | about: "If you have questions or need support, please check the discussion board and create a \"New Discussion\" if necessary." 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/doc_request.yml: -------------------------------------------------------------------------------- 1 | name: Additional Documentation Request 2 | description: Request additional documentation on a certain topic in Aviary. This does not include documentation errors as those should be filed under a bug report. 3 | body: 4 | - type: textarea 5 | id: desired 6 | attributes: 7 | label: Desired documentation content. 8 | description: Please explain what area you would like documented and any specific things you would like addressed in the content. 9 | validations: 10 | required: true 11 | - type: textarea 12 | id: existing 13 | attributes: 14 | label: Is there any existing documentation on your requested topic? Please describe. 15 | description: Description and relevant links to any existing documentation that are related to your request. 16 | validations: 17 | required: false 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature or change request 2 | description: Request a new capability or change in behavior in Aviary. 3 | body: 4 | - type: textarea 5 | id: desired 6 | attributes: 7 | label: Desired capability or behavior. 8 | description: Please explain what you would like to happen, and any alternatives you've considered. 9 | validations: 10 | required: true 11 | - type: textarea 12 | id: problems 13 | attributes: 14 | label: Is your feature request related to a problem? Please describe. 15 | description: A clear and concise description of what the problem is. 16 | validations: 17 | required: false 18 | - type: input 19 | id: bug-number 20 | attributes: 21 | label: Associated Bug Report 22 | description: Number of the associated Bug Report, if available. 23 | placeholder: "1" 24 | validations: 25 | required: false 26 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Summary 2 | 3 | Summary of PR. 4 | 5 | ### Related Issues 6 | 7 | - Resolves # 8 | 9 | ### Backwards incompatibilities 10 | 11 | None 12 | 13 | ### New Dependencies 14 | 15 | None -------------------------------------------------------------------------------- /.github/actions/send_email/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Send Email' 2 | description: 'Send an email with customizable subject and body' 3 | inputs: 4 | username: 5 | description: 'Email username' 6 | required: true 7 | password: 8 | description: 'Email password' 9 | required: true 10 | to: 11 | description: 'Recipient email address' 12 | required: true 13 | subject: 14 | description: 'Email subject' 15 | required: true 16 | body: 17 | description: 'Email body' 18 | required: true 19 | 20 | runs: 21 | using: 'composite' 22 | steps: 23 | - name: Send Email 24 | uses: dawidd6/action-send-mail@v3 25 | with: 26 | server_address: 'smtp.gmail.com' 27 | server_port: '465' 28 | username: ${{ inputs.username }} 29 | password: ${{ inputs.password }} 30 | to: ${{ inputs.to }} 31 | from: 'GitHub Actions' 32 | subject: ${{ inputs.subject }} 33 | body: ${{ inputs.body }} 34 | ignore_cert: true 35 | nodemailerlog: true 36 | nodemailerdebug: true -------------------------------------------------------------------------------- /.github/workflows/publish-image.yml: -------------------------------------------------------------------------------- 1 | name: Publish Images 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | # Run the workflow manually from the Actions tab 8 | workflow_dispatch: 9 | 10 | jobs: 11 | 12 | build_image: 13 | 14 | strategy: 15 | 16 | fail-fast: false 17 | 18 | matrix: 19 | include: 20 | - NAME: ubuntu 21 | OS: ubuntu-24.04 22 | FILE: Dockerfile 23 | IMAGE_NAME: ${{ github.repository }} 24 | REGISTRY: ghcr.io 25 | 26 | - NAME: ubuntu-arm 27 | OS: ubuntu-24.04-arm 28 | FILE: Dockerfile.arm 29 | IMAGE_NAME: ${{ github.repository }}-arm 30 | REGISTRY: ghcr.io 31 | 32 | runs-on: ${{ matrix.OS }} 33 | 34 | permissions: 35 | contents: read 36 | packages: write 37 | 38 | defaults: 39 | run: 40 | shell: bash -l {0} 41 | 42 | steps: 43 | - name: Checkout repository 44 | uses: actions/checkout@v4 45 | 46 | - name: Get tags 47 | run: | 48 | git fetch --unshallow --tags 49 | git describe --tags 50 | git describe --tags > tag.txt 51 | echo "TAG=$(cat tag.txt)" >> $GITHUB_ENV 52 | 53 | # Login to container registry 54 | - name: Log into registry ${{ matrix.REGISTRY }} 55 | uses: docker/login-action@v3 56 | with: 57 | registry: ${{ matrix.REGISTRY }} 58 | username: ${{ github.actor }} 59 | password: ${{ secrets.GITHUB_TOKEN }} 60 | 61 | # Extract metadata (tags, labels) 62 | - name: Extract Docker metadata 63 | id: meta 64 | uses: docker/metadata-action@v5 65 | with: 66 | images: ${{ matrix.REGISTRY }}/${{ matrix.IMAGE_NAME }} 67 | tags: | 68 | type=raw,value=${{ env.TAG }} 69 | 70 | # Build and push image with Buildx 71 | - name: Build and push Docker image 72 | uses: docker/build-push-action@v6 73 | with: 74 | push: true 75 | file: ${{ matrix.FILE }} 76 | tags: ${{ steps.meta.outputs.tags }} 77 | labels: ${{ steps.meta.outputs.labels }} 78 | -------------------------------------------------------------------------------- /.github/workflows/release_workflow.yml: -------------------------------------------------------------------------------- 1 | # Publish release to PyPi 2 | 3 | name: Aviary Release 4 | 5 | on: 6 | # Trigger on release, to publish release packages to PyPI 7 | release: 8 | types: [published] 9 | 10 | # Run the workflow manually 11 | # This might be useful if the automated publish fails for some reason (use with CARE!!) 12 | workflow_dispatch: 13 | 14 | jobs: 15 | pypi-publish: 16 | name: Upload release to PyPI 17 | runs-on: ubuntu-latest 18 | 19 | environment: release 20 | 21 | permissions: 22 | id-token: write 23 | 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - uses: actions/setup-python@v4 28 | with: 29 | python-version: "3.x" 30 | 31 | - name: deps 32 | run: python -m pip install -U hatch 33 | 34 | - name: build 35 | run: hatch build 36 | 37 | - name: Publish package distributions to PyPI (v1.12.4) 38 | uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc 39 | 40 | test-pypi-release: 41 | name: Test Aviary PyPI Release 42 | needs: [pypi-publish] 43 | runs-on: ubuntu-latest 44 | 45 | steps: 46 | - uses: benc-uk/workflow-dispatch@v1 47 | with: 48 | workflow: Test "no dev" install 49 | repo: ${{ github.repository_owner }}/Aviary 50 | inputs: > 51 | { 52 | "run_name": "Test PyPI install", 53 | "use_pypi": true 54 | } 55 | token: ${{ secrets.ACCESS_TOKEN }} 56 | if: github.event_name == 'release' 57 | -------------------------------------------------------------------------------- /.github/workflows/test_benchmarks.yml: -------------------------------------------------------------------------------- 1 | # Run Tests 2 | 3 | name: Test Benchmarks 4 | 5 | on: 6 | # Trigger on push or pull request events for the main branch 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | merge_group: 12 | branches: [ main ] 13 | 14 | # Allow running the workflow manually from the Actions tab 15 | workflow_dispatch: 16 | 17 | 18 | jobs: 19 | 20 | latest_benchmarks: 21 | runs-on: ubuntu-22.04 22 | timeout-minutes: 90 23 | 24 | steps: 25 | - name: Checkout actions 26 | uses: actions/checkout@v3 27 | with: 28 | sparse-checkout: | 29 | .github/actions 30 | path: actions 31 | 32 | - name: prepare_benchmark_environment 33 | uses: ./actions/.github/actions/prepare_environment 34 | with: 35 | NAME: 'latest' 36 | PY: 3.12 37 | NUMPY: 1 38 | SCIPY: 1 39 | PYOPTSPARSE: 'v2.9.1' 40 | SNOPT: '7.7' 41 | OPENMDAO: 'latest' 42 | DYMOS: 'latest' 43 | SSH_PRIVATE_KEY: ${{secrets.SSH_PRIVATE_KEY}} 44 | SSH_KNOWN_HOSTS: ${{secrets.SSH_KNOWN_HOSTS}} 45 | SNOPT_LOCATION_77: ${{ secrets.SNOPT_LOCATION_77 }} 46 | 47 | - name: Run benchmarks 48 | shell: bash -l {0} 49 | run: | 50 | echo "=============================================================" 51 | echo "Run Benchmarks" 52 | echo "=============================================================" 53 | testflo . --timeout=900 --testmatch=bench_test* 54 | 55 | - name: Checkout actions (again) 56 | uses: actions/checkout@v3 57 | with: 58 | sparse-checkout: | 59 | .github/actions 60 | path: actions 61 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/astral-sh/ruff-pre-commit 3 | # Ruff version. 4 | rev: v0.11.6 5 | hooks: 6 | # run the linter 7 | # - id: ruff 8 | # args: [ --fix ] 9 | # run the formatter 10 | - id: ruff-format -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | title: Aviary: An Open-Source Multidisciplinary Design, Analysis, and Optimization Tool for Modeling Aircraft with Analytic Gradients 3 | message: Please use this citation when using Aviary in your research! 4 | type: software 5 | authors: 6 | - given-names: Jennifer 7 | family-names: Gratz 8 | affiliation: NASA Glenn Research Center 9 | - given-names: Jason 10 | family-names: Kirk 11 | affiliation: NASA Langley Research Center 12 | - given-names: Carl 13 | family-names: Recine 14 | affiliation: NASA Ames Research Center 15 | - given-names: John 16 | family-names: Jasa 17 | affiliation: Banner Quality Management Inc. 18 | - given-names: Eliot 19 | family-names: Aretskin-Hariton 20 | affiliation: NASA Glenn Research Center 21 | - given-names: Kenneth 22 | family-names: Moore 23 | affiliation: Banner Quality Management Inc. 24 | identifiers: 25 | - type: doi 26 | value: 10.2514/6.2024-4219 27 | repository-code: 'https://github.com/OpenMDAO/Aviary' 28 | repository: 'https://github.com/OpenMDAO/Aviary_Community' 29 | license: Apache-2.0 30 | version: 0.9.10 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023, United States of America as Represented by the Administrator of National Aeronautics and Space Administration 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /aviary/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.10.0-dev' 2 | -------------------------------------------------------------------------------- /aviary/constants.py: -------------------------------------------------------------------------------- 1 | import openmdao.utils.units as units 2 | 3 | units.add_unit('distance_units', '1*m') 4 | 5 | GRAV_METRIC_GASP = 9.81 # m/s^2 6 | GRAV_ENGLISH_GASP = 32.2 # ft/s^2 7 | GRAV_METRIC_FLOPS = 9.80665 # m/s^2 8 | GRAV_ENGLISH_FLOPS = 32.17399 # ft/s^2 9 | GRAV_ENGLISH_LBM = 1.0 # lbf/lbm 10 | # TODO this does not match what dymos atmosphere comp predicts, which leads to subtle 11 | # problems such as density ratio not being 1 at sea level 12 | RHO_SEA_LEVEL_ENGLISH = 0.0023769 # slug/ft^3 13 | RHO_SEA_LEVEL_METRIC = 1.225 # kg/m^3 14 | MU_TAKEOFF = 0.02 # TODO: fill in coefficient of friction for takeoff 15 | MU_LANDING = 0.4 # from gasp output 16 | # sea level standard pressure in psf 17 | PSLS_PSF = 2116.22 18 | # sea level standard temperature in deg R 19 | TSLS_DEGR = 518.67 20 | RADIUS_EARTH_METRIC = 6367533.0 # m (meridional) 21 | -------------------------------------------------------------------------------- /aviary/core/PostMissionGroup.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.utils.functions import promote_aircraft_and_mission_vars 4 | 5 | 6 | class PostMissionGroup(om.Group): 7 | """OpenMDAO group that holds all post-mission systems.""" 8 | 9 | def configure(self): 10 | """ 11 | Configure this group for post-mission. 12 | Promote aircraft and mission variables. 13 | """ 14 | promote_aircraft_and_mission_vars(self) 15 | -------------------------------------------------------------------------------- /aviary/core/PreMissionGroup.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.utils.functions import promote_aircraft_and_mission_vars 4 | from aviary.variable_info.functions import override_aviary_vars 5 | 6 | 7 | class PreMissionGroup(om.Group): 8 | """OpenMDAO group that holds all pre-mission systems.""" 9 | 10 | def configure(self): 11 | """ 12 | Configure this group for pre-mission. 13 | Promote aircraft and mission variables. 14 | Override output aviary variables. 15 | """ 16 | external_outputs = promote_aircraft_and_mission_vars(self) 17 | 18 | pre_mission = self.core_subsystems 19 | override_aviary_vars( 20 | pre_mission, 21 | pre_mission.options['aviary_options'], 22 | external_overrides=external_outputs, 23 | manual_overrides=pre_mission.manual_overrides, 24 | ) 25 | -------------------------------------------------------------------------------- /aviary/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/core/__init__.py -------------------------------------------------------------------------------- /aviary/docs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/__init__.py -------------------------------------------------------------------------------- /aviary/docs/_config.yml: -------------------------------------------------------------------------------- 1 | # Book settings 2 | # Learn more at https://jupyterbook.org/customize/config.html 3 | 4 | title: "" 5 | author: Aviary team at NASA 6 | logo: aviary.png 7 | copyright: '2023' 8 | 9 | # Force re-execution of notebooks on each build. 10 | # See https://jupyterbook.org/content/execute.html 11 | execute: 12 | execute_notebooks: force 13 | timeout: 240 14 | # execute_notebooks: auto 15 | 16 | exclude_patterns: ["*/reports/*"] 17 | 18 | # Define the name of the latex output file for PDF builds 19 | latex: 20 | latex_documents: 21 | targetname: book.tex 22 | 23 | # Information about where the book exists on the web 24 | repository: 25 | url: https://github.com/openmdao/Aviary # Online location of your book 26 | # path_to_book: docs # Optional path to your book, relative to the repository root 27 | branch: gh-pages # Which branch of the repository should be used when creating links (optional) 28 | 29 | # Add GitHub buttons to your book 30 | # See https://jupyterbook.org/customize/config.html#add-a-link-to-your-repository 31 | html: 32 | use_issues_button: true 33 | use_repository_button: true 34 | favicon : "aviary_logo.png" 35 | 36 | launch_buttons: 37 | colab_url: "https://colab.research.google.com" 38 | 39 | sphinx: 40 | extra_extensions: 41 | - 'sphinx.ext.autodoc' 42 | - 'sphinx.ext.autosummary' 43 | - 'sphinx.ext.viewcode' 44 | - 'sphinx.ext.napoleon' 45 | -------------------------------------------------------------------------------- /aviary/docs/aviary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/aviary.png -------------------------------------------------------------------------------- /aviary/docs/aviary_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/aviary_logo.png -------------------------------------------------------------------------------- /aviary/docs/build_book.sh: -------------------------------------------------------------------------------- 1 | rm -rf _srcdocs 2 | rm -rf _build 3 | 4 | find . -name "*.ipynb" -exec reset_notebook {} \; 5 | 6 | python build_source_docs.py; 7 | jupyter-book build -W --keep-going . -------------------------------------------------------------------------------- /aviary/docs/developer_guide/failing_pr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/developer_guide/failing_pr.png -------------------------------------------------------------------------------- /aviary/docs/developer_guide/gh_actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/developer_guide/gh_actions.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/OAS_xdsm.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/OAS_xdsm.PNG -------------------------------------------------------------------------------- /aviary/docs/examples/images/advanced_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/advanced_results.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/blank_flight_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/blank_flight_profile.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/cubic_advanced_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/cubic_advanced_results.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/fixed_range_cruise_altitude.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/fixed_range_cruise_altitude.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/fixed_range_cruise_distance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/fixed_range_cruise_distance.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/fixed_range_cruise_mass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/fixed_range_cruise_mass.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/flight_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/flight_profile.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/landing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/landing.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/multi_mission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/multi_mission.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/multiphase_flight_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/multiphase_flight_profile.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/multiphase_reserve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/multiphase_reserve.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/multiple_phases_gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/multiple_phases_gui.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/takeoff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/takeoff.png -------------------------------------------------------------------------------- /aviary/docs/examples/images/traj_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/examples/images/traj_results.png -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/N2_phases.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/N2_phases.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/N2_phases_links.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/N2_phases_links.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/N2_start.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/N2_start.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/N2_top.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/N2_top.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/driver_scaling_report_top.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/driver_scaling_report_top.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/input_list_top.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/input_list_top.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/inputs_html_top.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/inputs_html_top.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/opt_report_top.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/opt_report_top.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/traj_linkage_report_top.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/traj_linkage_report_top.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/traj_results_report_altitude.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/traj_results_report_altitude.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/traj_results_report_top.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/traj_results_report_top.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/images/traj_results_report_top_ascent.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/getting_started/images/traj_results_report_top_ascent.PNG -------------------------------------------------------------------------------- /aviary/docs/getting_started/now_what.md: -------------------------------------------------------------------------------- 1 | # Now What? 2 | 3 | We want to provide a few different avenues and suggested paths forward based on your use cases and background. 4 | These are not the only ways to use Aviary and explicitly do not build on each other. 5 | You could start with one of these sections and then move to another, or you could start with one and never use the others. 6 | 7 | ## Starting Simple 8 | 9 | If you just want to start from an existing example and run it, you can do that! 10 | Look at the [Examples docs section](../examples/intro), start with a simple one, and modify it as you please. 11 | 12 | We generally recommend starting by running cases using only the `"simple"` mission. 13 | This mission is designed to be more robust and easier to run than other mission types. 14 | [This doc page](../user_guide/drawing_and_running_simple_missions) goes into more detail about how to draw and run simple missions. 15 | 16 | ## Adding an External Subsystem 17 | 18 | If you're a user who knows you want to add your own external subsystems and want to get right into it, check out the [external subsystems doc pages](../user_guide/subsystems). 19 | Maybe you want to take an existing aircraft and mission and do some trade studies on the effects of adding a new propulsion system, structural model, or other external subsystem. 20 | If you're not designing an aircraft from the ground up, you might be able to effectively use Aviary without going too deep in the docs or details. 21 | 22 | ## Doing Optimization Studies 23 | 24 | The idea of doing "optimization" using Aviary is quite multifaceted. 25 | 26 | You might want to keep an aircraft design fixed and optimize different mission profiles to see how an aircraft should optimally fly for a given range. 27 | Or you might want to redesign an aircraft by doing a wingspan trade study and flying a fixed mission. 28 | Or you can have a fully coupled optimization problem where you're optimizing the aircraft design and mission profile simultaneously. 29 | 30 | For all these problems and more, Aviary can help you better explore your aircraft design space. 31 | 32 | ## Go on and Design 33 | 34 | These are just examples of how you might use Aviary -- the sky is the limit! (For now...) 35 | -------------------------------------------------------------------------------- /aviary/docs/getting_started/onboarding.md: -------------------------------------------------------------------------------- 1 | # Onboarding Guide 2 | 3 | We have created a simple onboarding guide to help you get started with Aviary. 4 | This guide goes through Levels 1, 2, and 3 in order, then discusses adding external subsystems to Aviary problems. 5 | This guide is meant to be a quick introduction to Aviary and is not meant to be a comprehensive guide to all of Aviary's features. 6 | Instead, view it as a way to get some more detail and info on portions of Aviary. 7 | 8 | If you have a specific use case for Aviary already and just need to know how to use Aviary to solve your problem, please jump to the User Guide or just search for your desired topic. 9 | 10 | ```{note} 11 | These onboarding doc pages were purposefully written by somebody who was new to Aviary. 12 | We hope this addresses some of the first-time questions you may have. 13 | ``` -------------------------------------------------------------------------------- /aviary/docs/misc_resources/externally_supported_subsystems.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Externally Supported Subsystems\n", 8 | "\n", 9 | "Aviary supports any generic subsystem that a user adds.\n", 10 | "We include some examples within the Aviary repo within the {glue:md}`aviary/examples/external_subsystems` folder." 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": null, 16 | "metadata": { 17 | "tags": [ 18 | "remove-cell" 19 | ] 20 | }, 21 | "outputs": [], 22 | "source": [ 23 | "# Testing Cell\n", 24 | "import aviary.api as av\n", 25 | "from aviary.utils.doctape import glue_variable\n", 26 | "\n", 27 | "folder = av.get_path('examples/external_subsystems')\n", 28 | "ext_examples_dir = folder.relative_to(av.top_dir.parent)\n", 29 | "\n", 30 | "glue_variable(str(ext_examples_dir), md_code=True)" 31 | ] 32 | } 33 | ], 34 | "metadata": { 35 | "kernelspec": { 36 | "display_name": "av1", 37 | "language": "python", 38 | "name": "python3" 39 | }, 40 | "language_info": { 41 | "codemirror_mode": { 42 | "name": "ipython", 43 | "version": 3 44 | }, 45 | "file_extension": ".py", 46 | "mimetype": "text/x-python", 47 | "name": "python", 48 | "nbconvert_exporter": "python", 49 | "pygments_lexer": "ipython3", 50 | "version": "3.9.18" 51 | } 52 | }, 53 | "nbformat": 4, 54 | "nbformat_minor": 2 55 | } 56 | -------------------------------------------------------------------------------- /aviary/docs/misc_resources/feature_comparison.md: -------------------------------------------------------------------------------- 1 | # Feature Comparison with Legacy Codes 2 | 3 | ```{note} 4 | This section is under development. 5 | ``` 6 | -------------------------------------------------------------------------------- /aviary/docs/misc_resources/images/sample_aviary_xdsm.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/misc_resources/images/sample_aviary_xdsm.PNG -------------------------------------------------------------------------------- /aviary/docs/misc_resources/planned_future_features.md: -------------------------------------------------------------------------------- 1 | # Planned Future Features 2 | 3 | Aviary is under active development and new features are being added regularly. 4 | The following is a non-exhaustive list of planned features that are not yet implemented. (The Aviary team reserves the right to remove features from this list if the need arises. This list is provided for informational purposes only and is not a commitment to perform work.) 5 | 6 | - The full capabilities of FLOPS and GASP to model medium and large sized commercial aircraft, with a few exceptions that have been determined unnecessary 7 | - A converter to convert a table of mach/altitude combinations into a phase_info file. This capability exists in the simple mission GUI, but it will be tweaked to allow for the direct input of tabular data as an alternative to the GUI 8 | - Natively supported builders for certain high-interest external subsystem tools. Some potential tools to support are: NPSS, pyCycle, OpenVSP, VSPaero, OpenAeroStruct, etc. The Aviary team develops these builders as the need arises, and the development or lack of it for a certain tool does not indicate endorsement of the tool. 9 | - Improved cleanliness of the code 10 | - Improved ease-of-use for the user interface 11 | - Improved Fortran-to-Aviary converter which requires no human intervention or checking 12 | - Support for relevant FAA regulations governing aircraft design and operation 13 | - Full test suite that tests the code format, including testing for docstrings on all functions and classes 14 | - Fully tested code blocks in the documentation -------------------------------------------------------------------------------- /aviary/docs/misc_resources/resources.md: -------------------------------------------------------------------------------- 1 | # Resources 2 | 3 | ```{note} 4 | This page is under development. 5 | ``` 6 | 7 | ## Links to FLOPS docs 8 | 9 | [Here](https://software.nasa.gov/software/LAR-18934-1) is where you can read more about FLOPS. 10 | 11 | ## Links to GASP docs 12 | 13 | [This is the first publication about GASP](https://ntrs.nasa.gov/api/citations/19810010562/downloads/19810010562.pdf) and there are multiple follow-on publications. 14 | The GASP code is not publicly available, but the publications are a good resource for understanding the theory behind GASP. 15 | 16 | ## Publications List 17 | 18 | As we develop and use the Aviary code we will add publications here. 19 | -------------------------------------------------------------------------------- /aviary/docs/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/tests/__init__.py -------------------------------------------------------------------------------- /aviary/docs/theory_guide/aerodynamics.md: -------------------------------------------------------------------------------- 1 | # Core Aerodynamics Subsystem 2 | 3 | The core aerodynamics subsystem is responsible for calculating the aerodynamic forces (lift and drag) acting on the aircraft. 4 | Aviary can use empirically calculated aerodynamic properties or tabular data from user-provided sources. 5 | 6 | ```{note} 7 | This section is under further development. 8 | ``` 9 | -------------------------------------------------------------------------------- /aviary/docs/theory_guide/assumptions.md: -------------------------------------------------------------------------------- 1 | # Assumptions 2 | 3 | ```{note} 4 | This section is under development. 5 | ``` -------------------------------------------------------------------------------- /aviary/docs/theory_guide/geometry.md: -------------------------------------------------------------------------------- 1 | # Core Geometry Subsystem 2 | 3 | The core geometry subsystem is responsible for calculating the geometric properties of the aircraft. 4 | This includes the wing area, wing span, fuselage length, tail properties, passenger and cargo capacity, and other geometric properties. 5 | 6 | ```{note} 7 | This section is under further development. 8 | ``` 9 | -------------------------------------------------------------------------------- /aviary/docs/theory_guide/images/aircraft_force_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/theory_guide/images/aircraft_force_diagram.png -------------------------------------------------------------------------------- /aviary/docs/theory_guide/images/mission_simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/theory_guide/images/mission_simple.png -------------------------------------------------------------------------------- /aviary/docs/theory_guide/images/turboprop_connections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/theory_guide/images/turboprop_connections.png -------------------------------------------------------------------------------- /aviary/docs/theory_guide/images/turboprop_promotions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/theory_guide/images/turboprop_promotions.png -------------------------------------------------------------------------------- /aviary/docs/theory_guide/mass.md: -------------------------------------------------------------------------------- 1 | # Core Mass Subsystem 2 | 3 | The core mass subsystem is responsible for calculating the mass properties of the aircraft. 4 | This includes the empty weight, fuel weight, payload weight, and other mass properties. 5 | 6 | ```{note} 7 | This section is under further development. 8 | ``` 9 | -------------------------------------------------------------------------------- /aviary/docs/theory_guide/validation.md: -------------------------------------------------------------------------------- 1 | # Validation 2 | 3 | This section is under further development. 4 | 5 | ## Comparison with Other Tools 6 | 7 | We will compare Aviary with tools like GASP and FLOPS. -------------------------------------------------------------------------------- /aviary/docs/user_guide/example.csv: -------------------------------------------------------------------------------- 1 | # This is test data generated using write_data_file 2 | # Aviary data tables can support multiple comments 3 | 4 | aircraft:wing:span (ft), Scale Factor 5 | 79, 0.5 6 | 118, 0.75 7 | 171, 0.8 8 | -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/BWB_GASP_Fuselage_Geometry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/BWB_GASP_Fuselage_Geometry.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/BWB_engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/BWB_engine.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/CPE_CTE_matching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/CPE_CTE_matching.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/aviary_process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/aviary_process.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/dashboard.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/external_subsystem_methods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/external_subsystem_methods.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/gui_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/gui_main.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/hamilton_standard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/hamilton_standard.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/installation_loss_factor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/installation_loss_factor.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/levels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/levels.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/more_levels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/more_levels.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/images/subsystems.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/docs/user_guide/images/subsystems.png -------------------------------------------------------------------------------- /aviary/docs/user_guide/user_interface.md: -------------------------------------------------------------------------------- 1 | # Aviary User Interface 2 | 3 | ![three Aviary levels](images/levels.png) 4 | 5 | Aviary's user interface is designed to provide a seamless transition between different levels of complexity, allowing users to adapt and progress based on their needs and expertise. 6 | The levels build upon one another, with each level incorporating the methods and capabilities of the previous level. 7 | We'll explore how the levels are interconnected, but first let's describe the levels in broad strokes using a Lego-based metaphor. 8 | 9 | Level 3 is like a huge pile of Legos. 10 | You can build anything you want with it, but you have to know how to use the Legos; there are no instructions. 11 | This is using the pieces of Aviary to build your own analysis or optimization model. 12 | 13 | Level 2 is like a Lego set with instructions, but it's those late 80s/90s instructions where the steps aren't necessarily clear. 14 | You have more flexibility in choosing how you assemble the Legos, but you have some guide rails and reasonably clear instructions. 15 | Most anything you would do in Level 3 you can do here, you just might have slightly less flexibility in how you do it because we've established an API and some assumptions. 16 | 17 | Level 1 is like a modern-day Lego set where the instructions are very clear and you have a limited number of Legos to work with. 18 | You can build a lot of different coupled aircraft-mission optimization problems, but you don't have much flexibility in how you do it. 19 | 20 | Maybe this metaphor is helpful for you. 21 | Regardless, let's dive into the details of each level. -------------------------------------------------------------------------------- /aviary/examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/examples/__init__.py -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/OAS_weight/OAS_wing_weight_builder.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | import aviary.api as av 4 | from aviary.examples.external_subsystems.OAS_weight.OAS_wing_weight_analysis import OAStructures 5 | 6 | 7 | class OASWingWeightBuilder(av.SubsystemBuilderBase): 8 | """ 9 | Builder for an OpenAeroStruct component that computes a new wing mass. 10 | 11 | This also provides a method to build OpenMDAO systems for the pre-mission and mission computations of the subsystem. 12 | 13 | Attributes 14 | ---------- 15 | name : str ('wing_weight') 16 | object label 17 | 18 | Methods 19 | ------- 20 | __init__(self, name='wing_weight'): 21 | Initializes the OASWingWeightBuilder object with a given name. 22 | build_pre_mission(self) -> openmdao.core.System: 23 | Build an OpenMDAO system for the pre-mission computations of the subsystem. 24 | """ 25 | 26 | def __init__(self, name='wing_weight'): 27 | super().__init__(name) 28 | 29 | def build_pre_mission(self, aviary_inputs): 30 | """ 31 | Build an OpenMDAO system for the pre-mission computations of the subsystem. 32 | 33 | Returns 34 | ------- 35 | pre_mission_sys : openmdao.core.System 36 | An OpenMDAO system containing all computations that need to happen in 37 | the pre-mission part of the Aviary problem. This 38 | includes sizing, design, and other non-mission parameters. 39 | """ 40 | wing_group = om.Group() 41 | wing_group.add_subsystem( 42 | 'aerostructures', 43 | OAStructures( 44 | symmetry=True, 45 | wing_weight_ratio=1.0, 46 | S_ref_type='projected', 47 | n_point_masses=1, 48 | num_twist_cp=4, 49 | num_box_cp=51, 50 | ), 51 | promotes_inputs=[ 52 | ('fuel', av.Mission.Design.FUEL_MASS), 53 | ], 54 | promotes_outputs=[('wing_weight', av.Aircraft.Wing.MASS)], 55 | ) 56 | 57 | return wing_group 58 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/OAS_weight/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/examples/external_subsystems/OAS_weight/__init__.py -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/OAS_weight/test_OAS_wing_weight_builder.py: -------------------------------------------------------------------------------- 1 | import importlib.util 2 | import unittest 3 | 4 | import aviary.api as av 5 | 6 | path_to_builder = 'OAS_weight.OAS_wing_weight_builder.OASWingWeightBuilder' 7 | OASWingWeightBuilder = av.TestSubsystemBuilderBase.import_builder(path_to_builder) 8 | 9 | 10 | @av.skipIfMissingDependencies(OASWingWeightBuilder) 11 | @unittest.skipUnless(importlib.util.find_spec('ambiance'), "'ambiance' is not installed") 12 | class TestStructures(av.TestSubsystemBuilderBase): 13 | """Test OAS structure builder.""" 14 | 15 | def setUp(self): 16 | self.subsystem_builder = OASWingWeightBuilder() 17 | self.aviary_values = av.AviaryValues() 18 | 19 | 20 | if __name__ == '__main__': 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/examples/external_subsystems/__init__.py -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/battery/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/examples/external_subsystems/battery/__init__.py -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/battery/battery_variables.py: -------------------------------------------------------------------------------- 1 | from aviary.variable_info.variables import Aircraft as av_Aircraft 2 | from aviary.variable_info.variables import Dynamic as av_Dynamic 3 | 4 | AviaryAircraft = av_Aircraft 5 | AviaryDynamic = av_Dynamic 6 | 7 | 8 | class Aircraft(AviaryAircraft): 9 | """Aircraft data hierarchy for battery subsystem.""" 10 | 11 | # cell = single cell, battery = one case plus multiple cells 12 | 13 | class Battery(AviaryAircraft.Battery): 14 | CURRENT_MAX = 'aircraft:battery:current_max' 15 | ENERGY_REQUIRED = 'aircraft:battery:energy_required' 16 | HEAT_CAPACITY = 'aircraft:battery:heat_capacity' 17 | N_PARALLEL = 'aircraft:battery:n_parallel' 18 | N_SERIES = 'aircraft:battery:n_series' 19 | VOLTAGE = 'aircraft:battery:voltage' 20 | 21 | class Case: 22 | HEAT_CAPACITY = 'aircraft:battery:case:heat_capacity' 23 | WEIGHT_FRAC = 'aircraft:battery:case:weight_frac' 24 | 25 | class Cell: 26 | DISCHARGE_RATE = 'aircraft:battery:cell:discharge_rate' 27 | ENERGY_CAPACITY_MAX = 'aircraft:battery:cell:energy_capacity_max' 28 | HEAT_CAPACITY = 'aircraft:battery:cell:heat_capacity' 29 | MASS = 'aircraft:battery:cell:mass' 30 | VOLTAGE_LOW = 'aircraft:battery:cell:voltage_low' 31 | VOLUME = 'aircraft:battery:cell:volume' 32 | TYPE = 'aircraft:battery:cell:type' 33 | 34 | 35 | class Dynamic(AviaryDynamic): 36 | """Dynamic data hierarchy for battery subsystem.""" 37 | 38 | class Battery: 39 | CURRENT = 'dynamic:battery:current' 40 | EFFICIENCY = 'dynamic:battery:efficiency' 41 | HEAT_OUT = 'dynamic:battery:heat_out' 42 | STATE_OF_CHARGE = 'dynamic:battery:state_of_charge' 43 | STATE_OF_CHARGE_RATE = 'dynamic:battery:state_of_charge_rate' 44 | TEMPERATURE = 'dynamic:battery:temperature' 45 | VOLTAGE = 'dynamic:battery:voltage' 46 | VOLTAGE_THEVENIN = 'dynamic:battery:voltage_thevenin' 47 | VOLTAGE_THEVENIN_RATE = 'dynamic:battery:voltage_thevenin_rate' 48 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/battery/model/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/examples/external_subsystems/battery/model/__init__.py -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/battery/model/reg_thevenin_interp_group.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from openmdao.api import Group, MetaModelStructuredComp 3 | 4 | # These battery values are entirely fabricated and not representative of any real battery. 5 | # This model is used as an example of how to integrate external subsystems in Aviary. 6 | T_bp = np.array([0.0, 60.0]) 7 | SOC_bp = np.linspace(0.0, 1.0, 32) 8 | 9 | tU_oc = np.vstack((np.linspace(2.8, 4.2, 32), np.linspace(2.7, 4.1, 32))) 10 | tC_Th = np.ones((2, 32)) * 1000.0 11 | tR_Th = np.vstack((np.linspace(0.06, 0.03, 32), np.linspace(0.04, 0.02, 32))) 12 | tR_0 = np.vstack((np.linspace(0.06, 0.03, 32), np.linspace(0.04, 0.02, 32))) 13 | 14 | 15 | class RegTheveninInterpGroup(Group): 16 | """ 17 | Thevenin resistance and voltage computation by interpolation using temperature, 18 | state of charge, and capacitance. 19 | """ 20 | 21 | def initialize(self): 22 | self.options.declare('num_nodes', types=int) 23 | 24 | def setup(self): 25 | n = self.options['num_nodes'] 26 | 27 | thevenin_interp_comp = MetaModelStructuredComp( 28 | method='slinear', vec_size=n, training_data_gradients=False, extrapolate=True 29 | ) 30 | 31 | thevenin_interp_comp.add_input('T_batt', 1.0, T_bp, units='degC') 32 | thevenin_interp_comp.add_input('SOC', 1.0, SOC_bp, units=None) 33 | thevenin_interp_comp.add_output('C_Th', 1.0, tC_Th, units='F') 34 | # add R_th and R_0 to get total R 35 | thevenin_interp_comp.add_output('R_Th', 1.0, tR_Th, units='ohm') 36 | thevenin_interp_comp.add_output('R_0', 1.0, tR_0, units='ohm') 37 | thevenin_interp_comp.add_output('U_oc', 1.0, tU_oc, units='V') 38 | 39 | self.add_subsystem( 40 | name='interp_comp', subsys=thevenin_interp_comp, promotes=['*'] 41 | ) # promots params and values 42 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/battery/model/test_cell_comp.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from openmdao.api import Group, Problem 4 | from openmdao.utils.testing_utils import use_tempdirs 5 | 6 | from aviary.examples.external_subsystems.battery.model.cell_comp import CellComp 7 | 8 | 9 | class Test_cell_comp(unittest.TestCase): 10 | """test partials in CellComp component.""" 11 | 12 | @use_tempdirs 13 | def test_cell_comp(self): 14 | p = Problem() 15 | p.model = Group() 16 | p.model.add_subsystem('CellComp', CellComp(num_nodes=1), promotes=['*']) 17 | p.setup(mode='auto', check=True, force_alloc_complex=True) 18 | 19 | p.check_partials(compact_print=True, method='cs', step=1e-50) 20 | 21 | 22 | if __name__ == '__main__': 23 | unittest.main() 24 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/battery/run_cruise.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy 2 | 3 | import aviary.api as av 4 | from aviary.examples.external_subsystems.battery.battery_builder import BatteryBuilder 5 | from aviary.examples.external_subsystems.battery.battery_variable_meta_data import ExtendedMetaData 6 | from aviary.examples.external_subsystems.battery.battery_variables import Dynamic 7 | 8 | battery_builder = BatteryBuilder() 9 | 10 | phase_info = deepcopy(av.default_height_energy_phase_info) 11 | # Here we just add the simple weight system to only the pre-mission 12 | phase_info['pre_mission']['external_subsystems'] = [battery_builder] 13 | phase_info['climb']['external_subsystems'] = [battery_builder] 14 | 15 | 16 | if __name__ == '__main__': 17 | prob = av.AviaryProblem() 18 | 19 | # Load aircraft and options data from user 20 | # Allow for user overrides here 21 | prob.load_inputs( 22 | 'models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info, meta_data=ExtendedMetaData 23 | ) 24 | 25 | # Preprocess inputs 26 | prob.check_and_preprocess_inputs() 27 | 28 | prob.add_pre_mission_systems() 29 | 30 | prob.add_phases() 31 | 32 | prob.add_post_mission_systems() 33 | 34 | # Link phases and variables 35 | prob.link_phases() 36 | 37 | prob.add_driver('SLSQP') 38 | 39 | prob.add_design_variables() 40 | 41 | prob.model.add_objective( 42 | f'traj.climb.states:{Dynamic.Battery.STATE_OF_CHARGE}', index=-1, ref=-1 43 | ) 44 | 45 | prob.setup() 46 | 47 | prob.set_initial_guesses() 48 | 49 | prob.run_aviary_problem(suppress_solver_print=True) 50 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/battery/run_multiphase_mission.py: -------------------------------------------------------------------------------- 1 | from aviary.api import default_height_energy_phase_info as phase_info 2 | from aviary.examples.external_subsystems.battery.battery_builder import BatteryBuilder 3 | from aviary.examples.external_subsystems.battery.battery_variable_meta_data import ExtendedMetaData 4 | from aviary.interface.methods_for_level2 import AviaryProblem 5 | from aviary.utils.functions import get_aviary_resource_path 6 | 7 | battery_builder = BatteryBuilder(include_constraints=False) 8 | 9 | phase_info['pre_mission']['external_subsystems'] = [battery_builder] 10 | phase_info['climb']['external_subsystems'] = [battery_builder] 11 | phase_info['cruise']['external_subsystems'] = [battery_builder] 12 | phase_info['descent']['external_subsystems'] = [battery_builder] 13 | 14 | if __name__ == '__main__': 15 | prob = AviaryProblem() 16 | 17 | # Load aircraft and options data from user 18 | # Allow for user overrides here 19 | input_file = get_aviary_resource_path('models/test_aircraft/aircraft_for_bench_FwFm.csv') 20 | prob.load_inputs(input_file, phase_info, meta_data=ExtendedMetaData) 21 | 22 | # Preprocess inputs 23 | prob.check_and_preprocess_inputs() 24 | 25 | prob.add_pre_mission_systems() 26 | 27 | prob.add_phases() 28 | 29 | prob.add_post_mission_systems() 30 | 31 | # Link phases and variables 32 | prob.link_phases() 33 | 34 | prob.add_driver('SLSQP') 35 | 36 | prob.add_design_variables() 37 | 38 | prob.add_objective('mass') 39 | # prob.model.add_objective( 40 | # f'traj.climb.states:{Dynamic.Battery.STATE_OF_CHARGE}', index=-1, ref=-1) 41 | 42 | prob.setup() 43 | 44 | prob.set_initial_guesses() 45 | 46 | prob.run_aviary_problem() 47 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/battery/test_battery_builder.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import aviary.api as av 4 | 5 | BatteryBuilder = av.TestSubsystemBuilderBase.import_builder( 6 | 'battery.battery_builder.BatteryBuilder' 7 | ) 8 | 9 | 10 | @av.skipIfMissingDependencies(BatteryBuilder) 11 | class TestBattery(av.TestSubsystemBuilderBase): 12 | """Test battery builder.""" 13 | 14 | def setUp(self): 15 | self.subsystem_builder = BatteryBuilder() 16 | self.aviary_values = av.AviaryValues() 17 | 18 | 19 | if __name__ == '__main__': 20 | unittest.main() 21 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/custom_aero/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/examples/external_subsystems/custom_aero/__init__.py -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/custom_aero/run_simple_aero.py: -------------------------------------------------------------------------------- 1 | """ 2 | Run the a mission with a simple external component that computes the wing 3 | and horizontal tail mass. 4 | """ 5 | 6 | from copy import deepcopy 7 | 8 | import aviary.api as av 9 | from aviary.examples.external_subsystems.custom_aero.custom_aero_builder import CustomAeroBuilder 10 | 11 | phase_info = deepcopy(av.default_height_energy_phase_info) 12 | 13 | # Just do cruise in this example. 14 | phase_info.pop('climb') 15 | phase_info.pop('descent') 16 | 17 | # Add custom aero. 18 | # TODO: This API for replacing aero will be changed an upcoming release. 19 | phase_info['cruise']['external_subsystems'] = [CustomAeroBuilder()] 20 | 21 | # Disable internal aero 22 | # TODO: This API for replacing aero will be changed an upcoming release. 23 | phase_info['cruise']['subsystem_options']['core_aerodynamics'] = { 24 | 'method': 'external', 25 | } 26 | 27 | 28 | if __name__ == '__main__': 29 | prob = av.AviaryProblem() 30 | 31 | # Load aircraft and options data from user 32 | # Allow for user overrides here 33 | prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info) 34 | 35 | # Preprocess inputs 36 | prob.check_and_preprocess_inputs() 37 | 38 | prob.add_pre_mission_systems() 39 | 40 | prob.add_phases() 41 | 42 | prob.add_post_mission_systems() 43 | 44 | # Link phases and variables 45 | prob.link_phases() 46 | 47 | # Note, SLSQP might have troubles here. 48 | prob.add_driver('SLSQP') 49 | 50 | prob.add_design_variables() 51 | 52 | prob.add_objective() 53 | 54 | prob.setup() 55 | 56 | prob.set_initial_guesses() 57 | 58 | prob.run_aviary_problem(suppress_solver_print=True) 59 | 60 | print('done') 61 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/engine_NPSS/NPSS_Model/Design_files/input.int: -------------------------------------------------------------------------------- 1 | Alt_DES = 0.0000000000000000 ; 2 | MN_DES = 0.0000000000000000 ; 3 | W_DES = 315.1649027273072079 ; -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/engine_NPSS/NPSS_Model/Maps_and_Elements/npss.view_Aviary: -------------------------------------------------------------------------------- 1 | // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 2 | // Aviary Format DataViewer Specification 3 | // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 4 | 5 | OutFileStream AviarysheetStream { filename = "$ENG_PATH/Output/RefEngine.outputAviary"; } 6 | 7 | DataViewer CaseRowViewer Aviarysheet { 8 | 9 | variableList = { "ambient.MN:?.?? = mach", 10 | "ambient.alt:??????.? = altitude", 11 | "PERF.throttle:?.??????????????????? = throttle", 12 | "PERF.Fn:??????.?????????????? = thrust", 13 | "PERF.Wfuel:??.?????????????????? = fuel_flow_rate (lb/s)", 14 | "PERF.hybrid_throttle:??.?? = hybrid_throttle"} 15 | 16 | showMarks = TRUE; 17 | showHeaders = FALSE; 18 | pageWidth = 104; 19 | pageHeight = 500; 20 | 21 | outStreamHandle = "AviarysheetStream"; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/engine_NPSS/NPSS_Model/Maps_and_Elements/npss.view_flops: -------------------------------------------------------------------------------- 1 | // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 2 | // FLOPS Format DataViewer Specification 3 | // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 4 | 5 | OutFileStream FLOPsheetStream { filename = "$ENG_PATH/Output/RefEngine.outputFLOPS"; } 6 | 7 | DataViewer CaseRowViewer FLOPsheet { 8 | 9 | variableList = { "ambient.MN:?.?? = MN", 10 | "ambient.alt:??????.? = Alt", 11 | "PERF.PowerCode:??. = PC", 12 | "PERF.Fg:??????.? = Thrust", 13 | "inlet.Fram:??????.? = Ram", 14 | "PERF.WfuelHour:??????.? = Fuel", 15 | "PERF.PowerExtraction:?????.?? = HPX", 16 | "PERF.NozzleTotalArea:????.??? = Exit A" } 17 | 18 | showMarks = TRUE; 19 | showHeaders = FALSE; 20 | pageWidth = 104; 21 | pageHeight = 500; 22 | 23 | outStreamHandle = "FLOPsheetStream"; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/engine_NPSS/NPSS_Model/engine.case_Aviary_min: -------------------------------------------------------------------------------- 1 | // 2 | //------------------------------------------------------------------------ 3 | // | 4 | // File Name: engine.case_Aviary | 5 | // Date(s): Sept 18, 2023 | 6 | // | 7 | // Description: This file runs the engine over a set of flight | 8 | // conditions representing the entire engine | 9 | // operational envelope | 10 | // | 11 | //------------------------------------------------------------------------ 12 | 13 | 14 | //------------------------------------------------------------------------ 15 | // Run Entire Flight Envelope 16 | //------------------------------------------------------------------------ 17 | cout << "------------------------------------\n"; 18 | cout << " Build Deck \n"; 19 | cout <<" Design Air flow : " << W_DES << " \n"; 20 | cout << "------------------------------------\n"; 21 | 22 | CASE = 0; 23 | PERF.hybrid_throttle = 0.0; 24 | ambient.dTs_in = 27.0; 25 | 26 | RunThrottleHook( 0.00, 0. ); 27 | RunThrottleHook( 0.5, 0. ); 28 | 29 | RunThrottleHook( 0.0, 10000.); 30 | RunThrottleHook( 0.5, 10000.); 31 | 32 | //ambient.MN_in = 0.25; ambient.alt_in = 10000.; RunMaxPower("speed"); 33 | //ambient.MN_in = 0.5; ambient.alt_in = 20000.; RunMaxPower("speed"); 34 | 35 | ambient.dTs_in = 0.0; 36 | RunThrottleHook( 0.6, 20000.); 37 | RunThrottleHook( 0.8, 20000.); 38 | 39 | ambient.MN_in = 0.7; ambient.alt_in = 27000.; RunMaxPower(); 40 | 41 | RunThrottleHook( 0.60, 35000.); 42 | RunThrottleHook( 0.80, 35000.); 43 | 44 | Aviarysheet.display(); 45 | 46 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/engine_NPSS/NPSS_Model/turbojet.mdl: -------------------------------------------------------------------------------- 1 | Element Ambient ambient { 2 | alt_in = 0.0; 3 | MN_in = 0.0; 4 | } 5 | 6 | 7 | Element InletStart start { 8 | W_in = 200.; 9 | } 10 | 11 | 12 | Element Inlet inlet { 13 | } 14 | 15 | 16 | Element Compressor HPC { 17 | #include<$ENG_PATH/Maps_and_Elements/HPC.map> 18 | PRdes = 20.; 19 | effDes = 0.90; 20 | } 21 | 22 | Element Duct duct{ 23 | dPqP_dmd = 0; 24 | } 25 | 26 | Element FuelStart fuelIn { 27 | LHV = 18500.; 28 | } 29 | 30 | 31 | Element Burner burner { 32 | switchBurn = "FAR"; 33 | FAR = 0.0300; 34 | } 35 | 36 | 37 | Element Turbine HPT { 38 | #include<$ENG_PATH/Maps_and_Elements/HPT.map> 39 | effDes = 0.90; 40 | PRbase = 3; 41 | // S_map.PRmapDes = 3.000; 42 | // S_map.NpMapDes = 100.0; 43 | } 44 | 45 | 46 | Element Nozzle nozzle { 47 | switchType = "CONIC"; 48 | PsExhName = "ambient.Ps"; 49 | } 50 | 51 | 52 | Element FlowEnd end { 53 | } 54 | 55 | 56 | Element Shaft shaft { 57 | ShaftInputPort HPClink; 58 | ShaftInputPort HPTlink; 59 | Nmech = 3000.; 60 | } 61 | 62 | // Performance Calculations 63 | Performance PERF { 64 | real PC = 50; 65 | real PowerExtraction; 66 | real hybrid_throttle = 0; 67 | real throttle; 68 | //Define power code 69 | Table PercentPower( real PC ) { 70 | PC = { 50., 47., 44., 38., 32., 26., 21. } 71 | PartPwr = { 1.00, 0.90, 0.80, 0.60, 0.40, 0.20, 0.05 } 72 | } 73 | 74 | void postexecute() { 75 | PowerCode = PC; 76 | PowerExtraction = shaft.HPX; 77 | throttle = (PercentPower(PC) - 0.05)/(1.0-0.05); 78 | } 79 | } 80 | 81 | 82 | // link the Elements together via their Ports 83 | linkPorts( "start.Fl_O", "inlet.Fl_I", "station0" ); 84 | linkPorts( "inlet.Fl_O", "HPC.Fl_I", "station1" ); 85 | linkPorts( "HPC.Fl_O", "duct.Fl_I", "station2" ); 86 | linkPorts( "duct.Fl_O", "burner.Fl_I", "station3" ); 87 | linkPorts( "fuelIn.Fu_O", "burner.Fu_I", "stationF" ); 88 | linkPorts( "burner.Fl_O", "HPT.Fl_I", "station4" ); 89 | linkPorts( "HPT.Fl_O", "nozzle.Fl_I", "station5" ); 90 | linkPorts( "nozzle.Fl_O", "end.Fl_I", "station6" ); 91 | 92 | linkPorts( "HPC.Sh_O", "shaft.HPClink", "HPCwork" ); 93 | linkPorts( "HPT.Sh_O", "shaft.HPTlink", "HPTwork" ); 94 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/engine_NPSS/define_simple_engine_problem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Define an aviary mission with an NPSS defined engine. During pre-mission the engine is designed and an engine deck is made. 3 | During the mission the deck is used for performance. Weight is estimated using the default Aviary method. 4 | The engine model was developed using NPSS v3.2. 5 | """ 6 | 7 | from copy import deepcopy 8 | 9 | import aviary.api as av 10 | from aviary.examples.external_subsystems.engine_NPSS.engine_variable_meta_data import ( 11 | ExtendedMetaData, 12 | ) 13 | from aviary.examples.external_subsystems.engine_NPSS.table_engine_builder import ( 14 | TableEngineBuilder as EngineBuilder, 15 | ) 16 | 17 | 18 | def define_aviary_NPSS_problem(): 19 | """Build NPSS model in Aviary.""" 20 | phase_info = deepcopy(av.default_height_energy_phase_info) 21 | 22 | prob = av.AviaryProblem() 23 | 24 | prob.options['group_by_pre_opt_post'] = True 25 | 26 | # Load aircraft and options data from user 27 | # Allow for user overrides here 28 | # add engine builder 29 | prob.load_inputs( 30 | 'models/test_aircraft/aircraft_for_bench_FwFm.csv', 31 | phase_info, 32 | engine_builders=[EngineBuilder()], 33 | meta_data=ExtendedMetaData, 34 | ) 35 | 36 | prob.check_and_preprocess_inputs() 37 | 38 | prob.add_pre_mission_systems() 39 | 40 | prob.add_phases() 41 | 42 | prob.add_post_mission_systems() 43 | 44 | # Link phases and variables 45 | prob.link_phases() 46 | 47 | prob.add_driver('SLSQP') 48 | 49 | prob.add_design_variables() 50 | 51 | prob.add_objective() 52 | 53 | prob.setup() 54 | 55 | prob.set_initial_guesses() 56 | return prob 57 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/engine_NPSS/engine_variable_meta_data.py: -------------------------------------------------------------------------------- 1 | import aviary.api as av 2 | from aviary.examples.external_subsystems.engine_NPSS.engine_variables import Aircraft, Dynamic 3 | 4 | ExtendedMetaData = av.CoreMetaData 5 | 6 | 7 | ##### ENGINE VALUES ##### 8 | 9 | av.add_meta_data( 10 | Aircraft.Engine.DESIGN_MACH, 11 | units='unitless', 12 | desc='Mach Number at Design Point (Cruise)', 13 | default_value=0.8, 14 | meta_data=ExtendedMetaData, 15 | historical_name={'NPSS': 'ambient.MN_in'}, 16 | ) 17 | 18 | av.add_meta_data( 19 | Aircraft.Engine.DESIGN_ALTITUDE, 20 | units='ft', 21 | desc='Altitude at Design Point (Cruise)', 22 | default_value=35000.0, 23 | meta_data=ExtendedMetaData, 24 | historical_name={'NPSS': 'ambient.alt_in'}, 25 | ) 26 | 27 | av.add_meta_data( 28 | Aircraft.Engine.DESIGN_MASS_FLOW, 29 | units='lbm/s', 30 | desc='Mass Flow at Design Point (Cruise) for a single engine', 31 | default_value=350.0, 32 | meta_data=ExtendedMetaData, 33 | historical_name={'NPSS': 'start.W_in'}, 34 | ) 35 | 36 | av.add_meta_data( 37 | Aircraft.Engine.DESIGN_NET_THRUST, 38 | units='lbf', 39 | desc='Net Thrust at Design Point (Cruise)', 40 | default_value=3888.1, 41 | meta_data=ExtendedMetaData, 42 | historical_name={'NPSS': 'PERF.Fn'}, 43 | ) 44 | 45 | av.add_meta_data( 46 | Dynamic.Engine.SHAFT_MECH_SPEED, 47 | units='rpm', 48 | desc='Mechanical Speed of Shaft for Mission From the Part Power Case', 49 | default_value=5000, 50 | meta_data=ExtendedMetaData, 51 | historical_name={'NPSS': 'shaft.Nmech'}, 52 | ) 53 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/engine_NPSS/engine_variables.py: -------------------------------------------------------------------------------- 1 | import aviary.api as av 2 | 3 | AviaryAircraft = av.Aircraft 4 | AviaryDynamic = av.Dynamic 5 | 6 | 7 | class Aircraft(AviaryAircraft): 8 | """Aircraft data hierarchy for NPSS model.""" 9 | 10 | class Engine(AviaryAircraft.Engine): 11 | DESIGN_MACH = 'aircraft:engine:design_mach' 12 | DESIGN_ALTITUDE = 'aircraft:engine:design_alt' 13 | DESIGN_MASS_FLOW = 'aircraft:engine:design_mass_flow' 14 | # TODO: will need to use this to calculate the Aviary-core variable aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST using number of engines 15 | DESIGN_NET_THRUST = 'aircraft:engine:design_net_thrust' 16 | 17 | 18 | class Dynamic(AviaryDynamic): 19 | """Dynamics data hierarchy for NPSS model.""" 20 | 21 | class Engine: 22 | SHAFT_MECH_SPEED = 'dynamic:engine:shaft_mech_speed' # Part power variable names 23 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/engine_NPSS/table_engine_connected_variables.py: -------------------------------------------------------------------------------- 1 | from aviary.examples.external_subsystems.engine_NPSS.engine_variables import Dynamic 2 | 3 | vars_to_connect = { 4 | 'Fn_train': { 5 | 'mission_name': [ 6 | Dynamic.Vehicle.Propulsion.THRUST + '_train', 7 | ], 8 | 'units': 'lbf', 9 | }, 10 | 'Fn_max_train': { 11 | 'mission_name': [ 12 | Dynamic.Vehicle.Propulsion.THRUST_MAX + '_train', 13 | ], 14 | 'units': 'lbf', 15 | }, 16 | 'Wf_inv_train': { 17 | 'mission_name': [ 18 | Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE + '_train', 19 | ], 20 | 'units': 'lbm/s', 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/engine_NPSS/test_NPSS_builder.py: -------------------------------------------------------------------------------- 1 | """Benchmark test for aviary mission with an NPSS defined engine.""" 2 | 3 | import os as os 4 | import unittest 5 | 6 | from openmdao.utils.assert_utils import assert_near_equal 7 | 8 | from aviary.examples.external_subsystems.engine_NPSS.define_simple_engine_problem import ( 9 | define_aviary_NPSS_problem, 10 | ) 11 | 12 | 13 | class AviaryNPSSTestCase(unittest.TestCase): 14 | """Test NPSS engine builder from table by building an Aviary model with NPSS engine and run.""" 15 | 16 | @unittest.skipUnless(os.environ.get('NPSS_TOP', False), 'environment does not contain NPSS') 17 | def bench_test_aviary_NPSS(self): 18 | prob = define_aviary_NPSS_problem() 19 | prob.run_aviary_problem(suppress_solver_print=True) 20 | 21 | rtol = 0.01 22 | 23 | # There are no truth values for these. 24 | assert_near_equal( 25 | prob.get_val('aircraft:engine:design_mass_flow'), 315.1648646, tolerance=rtol 26 | ) 27 | 28 | assert_near_equal( 29 | prob.get_val('aircraft:engine:scaled_sls_thrust'), 35045.993119, tolerance=rtol 30 | ) 31 | 32 | assert_near_equal( 33 | prob.get_val('traj.cruise.rhs_all.NPSS_prop_system.fuel_flow_rate_negative')[0], 34 | -1.13552634, 35 | tolerance=rtol, 36 | ) 37 | assert_near_equal( 38 | prob.get_val('traj.cruise.rhs_all.NPSS_prop_system.thrust_net')[0], 39 | 4253.95759421, 40 | tolerance=rtol, 41 | ) 42 | 43 | 44 | if __name__ == '__main__': 45 | test = AviaryNPSSTestCase() 46 | test.bench_test_aviary_NPSS() 47 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/simple_weight/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/examples/external_subsystems/simple_weight/__init__.py -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/simple_weight/run_simple_weight.py: -------------------------------------------------------------------------------- 1 | """ 2 | Run the a mission with a simple external component that computes the wing 3 | and horizontal tail mass. 4 | """ 5 | 6 | from copy import deepcopy 7 | 8 | import aviary.api as av 9 | from aviary.examples.external_subsystems.simple_weight.simple_weight_builder import ( 10 | WingWeightBuilder, 11 | ) 12 | 13 | phase_info = deepcopy(av.default_height_energy_phase_info) 14 | # Here we just add the simple weight system to only the pre-mission 15 | phase_info['pre_mission']['external_subsystems'] = [WingWeightBuilder()] 16 | 17 | if __name__ == '__main__': 18 | prob = av.AviaryProblem() 19 | 20 | # Load aircraft and options data from user 21 | # Allow for user overrides here 22 | prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info) 23 | 24 | # Preprocess inputs 25 | prob.check_and_preprocess_inputs() 26 | 27 | prob.add_pre_mission_systems() 28 | 29 | prob.add_phases() 30 | 31 | prob.add_post_mission_systems() 32 | 33 | # Link phases and variables 34 | prob.link_phases() 35 | 36 | prob.add_driver('SLSQP') 37 | 38 | prob.add_design_variables() 39 | 40 | prob.add_objective() 41 | 42 | prob.setup() 43 | 44 | prob.set_initial_guesses() 45 | 46 | prob.run_aviary_problem(suppress_solver_print=True) 47 | 48 | print('Engine Mass', prob.get_val(av.Aircraft.Engine.MASS)) 49 | print('Wing Mass', prob.get_val(av.Aircraft.Wing.MASS)) 50 | print('Horizontal Tail Mass', prob.get_val(av.Aircraft.HorizontalTail.MASS)) 51 | 52 | print('done') 53 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/simple_weight/simple_weight.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a simplified example of a component that computes a weight for the 3 | wing and horizontal tail. The calculation is nonsensical, but it shows how 4 | a basic external subsystem an use hierarchy inputs and set new values for 5 | parts of the weight calculation. 6 | 7 | The wing and tail weights will replace Aviary's internally-computed values. 8 | 9 | This examples shows that you can use the Aviary hierarchy in your component 10 | (as we do for the wing and engine weight), but you can also use your own 11 | local names (as we do for 'Tail'), and promote them in your builder. 12 | """ 13 | 14 | import openmdao.api as om 15 | 16 | from aviary.variable_info.variables import Aircraft 17 | 18 | 19 | class SimpleWeight(om.ExplicitComponent): 20 | """ 21 | A simple component that computes a wing mass as a function of the engine mass. 22 | These values are not representative of any existing aircraft, and the component 23 | is meant to demonstrate the concept of an externally calculated subsystem mass. 24 | """ 25 | 26 | def setup(self): 27 | self.add_input(Aircraft.Engine.MASS, 1.0, units='lbm') 28 | 29 | self.add_output(Aircraft.Wing.MASS, 1.0, units='lbm') 30 | self.add_output('Tail', 1.0, units='lbm') 31 | 32 | self.declare_partials(Aircraft.Wing.MASS, Aircraft.Engine.MASS, val=1.5) 33 | self.declare_partials('Tail', Aircraft.Engine.MASS, val=0.7) 34 | 35 | def compute(self, inputs, outputs): 36 | outputs[Aircraft.Wing.MASS] = 1.5 * inputs[Aircraft.Engine.MASS] 37 | outputs['Tail'] = 0.7 * inputs[Aircraft.Engine.MASS] 38 | -------------------------------------------------------------------------------- /aviary/examples/external_subsystems/simple_weight/simple_weight_builder.py: -------------------------------------------------------------------------------- 1 | """ 2 | Builder for a simple component that computes a new wing and horizontal tail 3 | mass. 4 | 5 | The SimpleWeight component is placed inside of a group so that we can promote 6 | the variable "Tail" using the alias Aircraft.HorizontalTail.MASS 7 | """ 8 | 9 | import openmdao.api as om 10 | 11 | from aviary.examples.external_subsystems.simple_weight.simple_weight import SimpleWeight 12 | from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase 13 | from aviary.variable_info.variables import Aircraft 14 | 15 | 16 | class WingWeightBuilder(SubsystemBuilderBase): 17 | """ 18 | Prototype of a subsystem that overrides an aviary internally computed var. 19 | 20 | It also provides a method to build OpenMDAO systems for the pre-mission and mission computations of the subsystem. 21 | 22 | Attributes 23 | ---------- 24 | name : str ('wing_weight') 25 | object label 26 | 27 | Methods 28 | ------- 29 | __init__(self, name='wing_weight'): 30 | Initializes the WingWeightBuilder object with a given name. 31 | build_pre_mission(self, aviary_inputs) -> openmdao.core.System: 32 | Builds an OpenMDAO system for the pre-mission computations of the subsystem. 33 | """ 34 | 35 | def __init__(self, name='wing_weight'): 36 | super().__init__(name) 37 | 38 | def build_pre_mission(self, aviary_inputs): 39 | """ 40 | Build an OpenMDAO system for the pre-mission computations of the subsystem. 41 | 42 | Returns 43 | ------- 44 | pre_mission_sys : openmdao.core.System 45 | An OpenMDAO system containing all computations that need to happen in 46 | the pre-mission part of the Aviary problem. This 47 | includes sizing, design, and other non-mission parameters. 48 | """ 49 | wing_group = om.Group() 50 | wing_group.add_subsystem( 51 | 'aerostructures', 52 | SimpleWeight(), 53 | promotes_inputs=['aircraft:*'], 54 | promotes_outputs=[Aircraft.Wing.MASS, ('Tail', Aircraft.HorizontalTail.MASS)], 55 | ) 56 | return wing_group 57 | -------------------------------------------------------------------------------- /aviary/examples/level1_example.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a straightforward and basic example of running a coupled aircraft design-mission optimization in Aviary. 3 | This uses the "level 1" API within Aviary. 4 | 5 | We use the pre-defined single aisle commercial transport aircraft definition and use a pre-defined phase_info object 6 | to describe the mission optimization problem to Aviary. 7 | This mission consists of climb, cruise, and descent phases. 8 | We then call the `run_aviary` function, which takes in the path to the aircraft model, the phase info, and some other options. 9 | This performs a coupled design-mission optimization and outputs the results from Aviary into the `reports` folder. 10 | """ 11 | 12 | import aviary.api as av 13 | 14 | prob = av.run_aviary( 15 | 'models/test_aircraft/aircraft_for_bench_FwFm.csv', 16 | av.default_height_energy_phase_info, 17 | optimizer='SLSQP', 18 | make_plots=True, 19 | ) 20 | -------------------------------------------------------------------------------- /aviary/examples/level2_example.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a slightly more complex Aviary example of running a coupled aircraft design-mission optimization. 3 | It runs the same mission as the `level1_example.py` script, but it uses the AviaryProblem class to set up the problem. 4 | This exposes more options and flexibility to the user and uses the "Level 2" API within Aviary. 5 | 6 | We define a `phase_info` object, which tells Aviary how to model the mission. 7 | Here we have climb, cruise, and descent phases. 8 | We then call the correct methods in order to set up and run an Aviary optimization problem. 9 | This performs a coupled design-mission optimization and outputs the results from Aviary into the `reports` folder. 10 | """ 11 | 12 | from example_phase_info import phase_info 13 | 14 | import aviary.api as av 15 | 16 | prob = av.AviaryProblem() 17 | 18 | # Load aircraft and options data from user 19 | # Allow for user overrides here 20 | prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info) 21 | 22 | # Preprocess inputs 23 | prob.check_and_preprocess_inputs() 24 | 25 | prob.add_pre_mission_systems() 26 | 27 | prob.add_phases() 28 | 29 | prob.add_post_mission_systems() 30 | 31 | # Link phases and variables 32 | prob.link_phases() 33 | 34 | prob.add_driver('SLSQP', max_iter=100) 35 | 36 | prob.add_design_variables() 37 | 38 | # Load optimization problem formulation 39 | # Detail which variables the optimizer can control 40 | prob.add_objective() 41 | 42 | prob.setup() 43 | 44 | prob.set_initial_guesses() 45 | 46 | prob.run_aviary_problem() 47 | -------------------------------------------------------------------------------- /aviary/examples/reserve_missions/run_2dof_reserve_mission_fixedrange.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a slightly more complex Aviary example of running a coupled aircraft design-mission optimization. 3 | It runs the same mission as the `level1_example.py` script, but it uses the AviaryProblem class to set up the problem. 4 | This exposes more options and flexibility to the user and uses the "Level 2" API within Aviary. 5 | 6 | We define a `phase_info` object, which tells Aviary how to model the mission. 7 | Here we have climb, cruise, and descent phases. 8 | We then call the correct methods in order to set up and run an Aviary optimization problem. 9 | This performs a coupled design-mission optimization and outputs the results from Aviary into the `reports` folder. 10 | """ 11 | 12 | from copy import deepcopy 13 | 14 | import aviary.api as av 15 | from aviary.interface.default_phase_info.two_dof import phase_info 16 | 17 | phase_info = deepcopy(phase_info) 18 | 19 | # Add reserve phase(s) 20 | reserve_cruise = deepcopy(phase_info['cruise']) 21 | reserve_cruise['user_options']['reserve'] = True 22 | reserve_cruise['user_options']['target_distance'] = (200, 'km') 23 | reserve_cruise['initial_guesses']['initial_distance'] = (3700, 'nmi') 24 | 25 | phase_info.update({'reserve_cruise': reserve_cruise}) 26 | 27 | if __name__ == '__main__': 28 | prob = av.AviaryProblem() 29 | 30 | # Load aircraft and options data from user 31 | # Allow for user overrides here 32 | prob.load_inputs('models/test_aircraft/aircraft_for_bench_GwGm.csv', phase_info) 33 | 34 | # Preprocess inputs 35 | prob.check_and_preprocess_inputs() 36 | 37 | prob.add_pre_mission_systems() 38 | 39 | prob.add_phases() 40 | 41 | prob.add_post_mission_systems() 42 | 43 | # Link phases and variables 44 | prob.link_phases() 45 | 46 | prob.add_driver('SNOPT', max_iter=50, verbosity=2) 47 | 48 | prob.add_design_variables() 49 | 50 | # Load optimization problem formulation 51 | # Detail which variables the optimizer can control 52 | prob.add_objective() 53 | 54 | prob.setup() 55 | 56 | prob.set_initial_guesses() 57 | 58 | prob.run_aviary_problem(record_filename='2dof_reserve_mission_fixedrange.db') 59 | -------------------------------------------------------------------------------- /aviary/examples/reserve_missions/run_2dof_reserve_mission_fixedtime.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a slightly more complex Aviary example of running a coupled aircraft design-mission optimization. 3 | It runs the same mission as the `level1_example.py` script, but it uses the AviaryProblem class to set up the problem. 4 | This exposes more options and flexibility to the user and uses the "Level 2" API within Aviary. 5 | 6 | We define a `phase_info` object, which tells Aviary how to model the mission. 7 | Here we have climb, cruise, and descent phases. 8 | We then call the correct methods in order to set up and run an Aviary optimization problem. 9 | This performs a coupled design-mission optimization and outputs the results from Aviary into the `reports` folder. 10 | """ 11 | 12 | from copy import deepcopy 13 | 14 | import aviary.api as av 15 | from aviary.interface.default_phase_info.two_dof import phase_info 16 | 17 | phase_info = deepcopy(phase_info) 18 | 19 | # Add reserve phase(s) 20 | reserve_cruise = deepcopy(phase_info['cruise']) 21 | reserve_cruise['user_options']['reserve'] = True 22 | reserve_cruise['user_options']['target_duration'] = (30, 'min') 23 | reserve_cruise['user_options']['initial_bounds'] = ((149.5, 448.5), 'min') 24 | reserve_cruise['initial_guesses']['initial_distance'] = (4000, 'nmi') 25 | 26 | phase_info.update({'reserve_cruise': reserve_cruise}) 27 | 28 | if __name__ == '__main__': 29 | prob = av.AviaryProblem() 30 | 31 | # Load aircraft and options data from user 32 | # Allow for user overrides here 33 | prob.load_inputs('models/test_aircraft/aircraft_for_bench_GwGm.csv', phase_info) 34 | 35 | # Preprocess inputs 36 | prob.check_and_preprocess_inputs() 37 | 38 | prob.add_pre_mission_systems() 39 | 40 | prob.add_phases() 41 | 42 | prob.add_post_mission_systems() 43 | 44 | # Link phases and variables 45 | prob.link_phases() 46 | 47 | prob.add_driver('SNOPT', max_iter=50) 48 | 49 | prob.add_design_variables() 50 | 51 | # Load optimization problem formulation 52 | # Detail which variables the optimizer can control 53 | prob.add_objective() 54 | 55 | prob.setup() 56 | 57 | prob.set_initial_guesses() 58 | 59 | prob.run_aviary_problem(record_filename='2dof_reserve_mission_fixedtime.db') 60 | -------------------------------------------------------------------------------- /aviary/examples/reserve_missions/run_reserve_mission_fixedtime.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a slightly more complex Aviary example of running a coupled aircraft design-mission optimization. 3 | It runs the same mission as the `level1_example.py` script, but it uses the AviaryProblem class to set up the problem. 4 | This exposes more options and flexibility to the user and uses the "Level 2" API within Aviary. 5 | 6 | We define a `phase_info` object, which tells Aviary how to model the mission. 7 | Here we have climb, cruise, and descent phases. 8 | We then call the correct methods in order to set up and run an Aviary optimization problem. 9 | This performs a coupled design-mission optimization and outputs the results from Aviary into the `reports` folder. 10 | """ 11 | 12 | from copy import deepcopy 13 | 14 | import aviary.api as av 15 | from aviary.examples.example_phase_info import phase_info 16 | 17 | phase_info = deepcopy(phase_info) 18 | 19 | # Copy the current cruise phase, then make it a reserve phase 20 | reserve_phase_0 = deepcopy(phase_info['cruise']) 21 | reserve_phase_0['user_options']['reserve'] = True 22 | reserve_phase_0['user_options']['target_duration'] = (30, 'min') 23 | 24 | # Add the reserve phase to phase_info 25 | phase_info.update({'reserve_cruise': reserve_phase_0}) 26 | 27 | if __name__ == '__main__': 28 | prob = av.AviaryProblem() 29 | 30 | # Load aircraft and options data from user 31 | # Allow for user overrides here 32 | prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info) 33 | 34 | # Preprocess inputs 35 | prob.check_and_preprocess_inputs() 36 | 37 | prob.add_pre_mission_systems() 38 | 39 | prob.add_phases() 40 | 41 | prob.add_post_mission_systems() 42 | 43 | # Link phases and variables 44 | prob.link_phases() 45 | 46 | prob.add_driver('SLSQP', max_iter=100) 47 | 48 | prob.add_design_variables() 49 | 50 | # Load optimization problem formulation 51 | # Detail which variables the optimizer can control 52 | prob.add_objective() 53 | 54 | prob.setup() 55 | 56 | prob.set_initial_guesses() 57 | 58 | prob.run_aviary_problem(record_filename='reserve_mission_fixedtime.db') 59 | -------------------------------------------------------------------------------- /aviary/examples/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/examples/test/__init__.py -------------------------------------------------------------------------------- /aviary/examples/test/test_level2_shooting_traj.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from openmdao.utils.testing_utils import require_pyoptsparse, use_tempdirs 4 | 5 | from aviary.api import AnalysisScheme 6 | from aviary.examples.level2_shooting_traj import custom_run_aviary 7 | 8 | 9 | @unittest.skip( 10 | 'Shooting method is not correctly receiving user-set options, and is currently ' 11 | 'using default values for most options' 12 | ) 13 | @use_tempdirs 14 | class CustomTrajTestCase(unittest.TestCase): 15 | # A test class for shooting scheme 16 | 17 | @require_pyoptsparse(optimizer='IPOPT') 18 | def test_run_aviary(self): 19 | self.skipTest('SGM currently failing this test.') 20 | input_deck = 'models/large_single_aisle_1/large_single_aisle_1_GASP.csv' 21 | custom_run_aviary(input_deck, analysis_scheme=AnalysisScheme.SHOOTING, run_driver=False) 22 | 23 | 24 | if __name__ == '__main__': 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /aviary/interface/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/interface/__init__.py -------------------------------------------------------------------------------- /aviary/interface/default_phase_info/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/interface/default_phase_info/__init__.py -------------------------------------------------------------------------------- /aviary/interface/download_models.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import shutil 4 | from pathlib import Path 5 | 6 | from aviary.utils.functions import get_model 7 | 8 | 9 | def save_file(aviary_path: Path, outdir: Path, verbose=False) -> Path: 10 | """Saves the file or folder specified into the output directory, creating directories as needed.""" 11 | outdir.mkdir(parents=True, exist_ok=True) 12 | if aviary_path.is_dir(): 13 | if verbose: 14 | print(aviary_path, 'is a directory, getting all files') 15 | outdir = outdir.joinpath(aviary_path.stem) 16 | outdir.mkdir(exist_ok=True) 17 | for file in next(os.walk(aviary_path))[-1]: 18 | if verbose: 19 | print('copying', str(aviary_path / file), 'to', str(outdir / file)) 20 | shutil.copy2(aviary_path / file, outdir) 21 | else: 22 | if verbose: 23 | print('copying', str(aviary_path), 'to', str(outdir / aviary_path.name)) 24 | shutil.copy2(aviary_path, outdir) 25 | return outdir 26 | 27 | 28 | def _setup_hangar_parser(parser: argparse.ArgumentParser): 29 | def_outdir = os.path.join(os.getcwd(), 'aviary_models') 30 | parser.add_argument( 31 | 'input_decks', 32 | metavar='indecks', 33 | type=str, 34 | nargs='+', 35 | help='Name of file or folder to download from Aviary/models', 36 | ) 37 | parser.add_argument( 38 | '-o', 39 | '--outdir', 40 | default=def_outdir, 41 | help='Directory to write outputs. Defaults to aviary_models in the current directory.', 42 | ) 43 | parser.add_argument( 44 | '-v', 45 | '--verbose', 46 | action='store_true', 47 | help='Enable verbose outputs', 48 | ) 49 | 50 | 51 | def _exec_hangar(args, user_args): 52 | input_decks = [] 53 | for input_deck in args.input_decks: 54 | input_decks.append(get_model(input_deck)) 55 | 56 | for input_deck in input_decks: 57 | save_file(input_deck, Path(args.outdir), args.verbose) 58 | -------------------------------------------------------------------------------- /aviary/interface/static/aviary_logo_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/interface/static/aviary_logo_16.png -------------------------------------------------------------------------------- /aviary/interface/static/aviary_logo_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/interface/static/aviary_logo_32.png -------------------------------------------------------------------------------- /aviary/interface/static/dark_mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/interface/static/dark_mode.png -------------------------------------------------------------------------------- /aviary/interface/static/light_mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/interface/static/light_mode.png -------------------------------------------------------------------------------- /aviary/interface/static/mac_theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/interface/static/mac_theme.png -------------------------------------------------------------------------------- /aviary/interface/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/interface/test/__init__.py -------------------------------------------------------------------------------- /aviary/interface/test/test_download_models.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | import unittest 3 | from pathlib import Path 4 | 5 | from openmdao.utils.testing_utils import use_tempdirs 6 | 7 | from aviary.interface.download_models import get_model, save_file 8 | from aviary.utils.functions import get_aviary_resource_path 9 | 10 | 11 | @use_tempdirs 12 | class CommandEntryPointsTestCases(unittest.TestCase): 13 | def run_and_test_hangar(self, filenames, out_dir=''): 14 | # tests that the function runs successfully and that the files are generated 15 | if isinstance(filenames, str): 16 | filenames = [filenames] 17 | 18 | if out_dir: 19 | out_dir = Path(out_dir) 20 | else: 21 | out_dir = Path.cwd() / 'aviary_models' 22 | 23 | for filename in filenames: 24 | path = get_model(filename) 25 | save_file(path, outdir=out_dir) 26 | path = out_dir / filename.split('/')[-1] 27 | self.assertTrue(path.exists()) 28 | 29 | def test_single_file_without_path(self): 30 | filename = 'turbofan_22k.deck' 31 | self.run_and_test_hangar(filename) 32 | 33 | def test_single_file_with_path(self): 34 | filename = 'engines/turbofan_22k.deck' 35 | self.run_and_test_hangar(filename) 36 | 37 | def test_multiple_files(self): 38 | filenames = ['small_single_aisle_GASP.dat', 'small_single_aisle_GASP.csv'] 39 | self.run_and_test_hangar(filenames) 40 | 41 | def test_folder(self): 42 | filename = 'engines' 43 | self.run_and_test_hangar(filename) 44 | 45 | def test_single_file_custom_outdir(self): 46 | filename = 'small_single_aisle_GASP.csv' 47 | out_dir = '~/test_hangar' 48 | self.run_and_test_hangar(filename, out_dir) 49 | shutil.rmtree(out_dir) 50 | 51 | def test_expected_path(self): 52 | aviary_path = get_model('large_single_aisle_1_GASP.dat') 53 | 54 | expected_path = get_aviary_resource_path( 55 | 'models/large_single_aisle_1/large_single_aisle_1_GASP.dat' 56 | ) 57 | self.assertTrue(str(aviary_path) == str(expected_path)) 58 | 59 | 60 | if __name__ == '__main__': 61 | unittest.main() 62 | # test = CommandEntryPointsTestCases() 63 | # test.test_single_file_with_path() 64 | -------------------------------------------------------------------------------- /aviary/interface/test/test_installation_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from aviary.interface.test_installation import _exec_installation_test 4 | 5 | 6 | class test_installation(unittest.TestCase): 7 | def test_installation(self): 8 | success = _exec_installation_test(None, None) 9 | assert success 10 | 11 | 12 | if __name__ == '__main__': 13 | unittest.main() 14 | -------------------------------------------------------------------------------- /aviary/interface/test/test_preprocess.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test preprocessing as part of the level 2 interface. 3 | """ 4 | 5 | from copy import deepcopy 6 | import unittest 7 | 8 | from openmdao.utils.testing_utils import use_tempdirs 9 | 10 | from aviary.interface.methods_for_level2 import AviaryProblem 11 | from aviary.models.N3CC.phase_info import phase_info 12 | from aviary.variable_info.variables import Aircraft 13 | 14 | 15 | @use_tempdirs 16 | class TestLevel2Preprocessing(unittest.TestCase): 17 | def test_crew_preprocessing(self): 18 | # Test that flight-crew preprocesses correctly. 19 | prob = AviaryProblem() 20 | local_phase_info = deepcopy(phase_info) 21 | 22 | prob.load_inputs('models/N3CC/N3CC_FLOPS.csv', local_phase_info) 23 | prob.check_and_preprocess_inputs() 24 | aviary_inputs = prob.aviary_inputs 25 | 26 | num_flight_crew = aviary_inputs.get_val(Aircraft.CrewPayload.NUM_FLIGHT_CREW) 27 | self.assertEqual(num_flight_crew, 3) 28 | 29 | num_flight_attendants = aviary_inputs.get_val(Aircraft.CrewPayload.NUM_FLIGHT_ATTENDANTS) 30 | self.assertEqual(num_flight_attendants, 4) 31 | 32 | num_galley_crew = aviary_inputs.get_val(Aircraft.CrewPayload.NUM_GALLEY_CREW) 33 | self.assertEqual(num_galley_crew, 1) 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /aviary/interface/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/interface/utils/__init__.py -------------------------------------------------------------------------------- /aviary/mission/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/__init__.py -------------------------------------------------------------------------------- /aviary/mission/flops_based/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/flops_based/__init__.py -------------------------------------------------------------------------------- /aviary/mission/flops_based/ode/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/flops_based/ode/__init__.py -------------------------------------------------------------------------------- /aviary/mission/flops_based/ode/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/flops_based/ode/test/__init__.py -------------------------------------------------------------------------------- /aviary/mission/flops_based/ode/test/test_range_rate.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | 5 | from aviary.mission.flops_based.ode.range_rate import RangeRate 6 | from aviary.utils.test_utils.variable_test import assert_match_varnames 7 | from aviary.validation_cases.validation_data.flops_data.full_mission_test_data import data 8 | from aviary.validation_cases.validation_tests import do_validation_test 9 | from aviary.variable_info.variables import Dynamic 10 | 11 | 12 | class RangeRateTest(unittest.TestCase): 13 | def setUp(self): 14 | """Test using data from validation_cases/validation_data/flops_data/full_mission_test_data.py.""" 15 | prob = self.prob = om.Problem() 16 | 17 | time, _ = data.get_item('time') 18 | 19 | prob.model.add_subsystem( 20 | Dynamic.Mission.DISTANCE_RATE, 21 | RangeRate(num_nodes=len(time)), 22 | promotes_inputs=['*'], 23 | promotes_outputs=['*'], 24 | ) 25 | 26 | prob.setup(check=False, force_alloc_complex=True) 27 | 28 | def test_case1(self): 29 | do_validation_test( 30 | self.prob, 31 | 'full_mission_test_data', 32 | input_validation_data=data, 33 | output_validation_data=data, 34 | input_keys=[Dynamic.Mission.ALTITUDE_RATE, Dynamic.Mission.VELOCITY], 35 | output_keys=Dynamic.Mission.DISTANCE_RATE, 36 | tol=1e-12, 37 | ) 38 | 39 | def test_IO(self): 40 | assert_match_varnames(self.prob.model) 41 | 42 | 43 | if __name__ == '__main__': 44 | unittest.main() 45 | -------------------------------------------------------------------------------- /aviary/mission/flops_based/ode/test/test_required_thrust.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import numpy as np 4 | import openmdao.api as om 5 | from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal 6 | 7 | from aviary.mission.flops_based.ode.required_thrust import RequiredThrust 8 | from aviary.utils.test_utils.variable_test import assert_match_varnames 9 | from aviary.variable_info.variables import Dynamic 10 | 11 | 12 | class RequiredThrustTest(unittest.TestCase): 13 | """Test required thrust.""" 14 | 15 | def setUp(self): 16 | prob = self.prob = om.Problem() 17 | prob.model.add_subsystem('req_thrust', RequiredThrust(num_nodes=2), promotes=['*']) 18 | prob.model.set_input_defaults( 19 | Dynamic.Vehicle.DRAG, np.array([47447.13138523, 44343.01567596]), units='N' 20 | ) 21 | prob.model.set_input_defaults(Dynamic.Vehicle.MASS, np.array([106292, 106292]), units='lbm') 22 | prob.model.set_input_defaults( 23 | Dynamic.Mission.ALTITUDE_RATE, np.array([1.72, 11.91]), units='m/s' 24 | ) 25 | prob.model.set_input_defaults( 26 | Dynamic.Mission.VELOCITY_RATE, np.array([5.23, 2.7]), units='m/s**2' 27 | ) 28 | prob.model.set_input_defaults( 29 | Dynamic.Mission.VELOCITY, np.array([160.99, 166.68]), units='m/s' 30 | ) 31 | 32 | prob.setup(check=False, force_alloc_complex=True) 33 | 34 | def test_case(self): 35 | tol = 1e-6 36 | self.prob.run_model() 37 | 38 | assert_near_equal(self.prob['thrust_required'], np.array([304653.8, 208303.1]), tol) 39 | 40 | partial_data = self.prob.check_partials(out_stream=None, method='cs') 41 | assert_check_partials(partial_data, atol=1e-10, rtol=1e-10) 42 | 43 | def test_IO(self): 44 | assert_match_varnames(self.prob.model, exclude_outputs={'thrust_required'}) 45 | 46 | 47 | if __name__ == '__main__': 48 | unittest.main() 49 | -------------------------------------------------------------------------------- /aviary/mission/flops_based/phases/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/flops_based/phases/__init__.py -------------------------------------------------------------------------------- /aviary/mission/flops_based/phases/build_landing.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.mission.flops_based.phases.simplified_landing import LandingGroup 4 | from aviary.variable_info.variables import Aircraft, Mission 5 | 6 | 7 | class Landing: 8 | """ 9 | Define user constraints for a climb phase. 10 | 11 | Parameters 12 | ---------- 13 | ref_wing_area : float (0.0) 14 | reference are of wing (ft^2) 15 | Cl_max_ldg : float (None) 16 | maximum coefficient of lift in landing configuration (None) 17 | 18 | Returns 19 | ------- 20 | Group 21 | a Group object in OpenMDAO 22 | """ 23 | 24 | def __init__( 25 | self, 26 | ref_wing_area=None, 27 | Cl_max_ldg=None, 28 | ): 29 | self.ref_wing_area = ref_wing_area # ft**2 30 | self.Cl_max_ldg = Cl_max_ldg # no units 31 | # note: need to clean this up so that some of these variables come from 32 | # connections. 33 | 34 | __slots__ = ( 35 | 'ref_wing_area', 36 | 'Cl_max_ldg', 37 | ) 38 | 39 | def build_phase(self, use_detailed=False): 40 | """ 41 | Construct and return a new phase for landing analysis. 42 | 43 | Parameters 44 | ---------- 45 | use_detailed : bool (False) 46 | tells whether to use simplified or detailed landing. Currently detailed is 47 | disabled. 48 | 49 | Returns 50 | ------- 51 | Group 52 | a group in OpenMDAO 53 | """ 54 | if use_detailed: 55 | raise om.AnalysisError( 56 | 'Must set landing method to `use_detailed=False`, detailed landing is' 57 | ' not currently enabled.' 58 | ) 59 | 60 | ############## 61 | # Add Inputs # 62 | ############## 63 | 64 | landing = LandingGroup() 65 | landing.set_input_defaults(Aircraft.Wing.AREA, val=self.ref_wing_area, units='ft**2') 66 | landing.set_input_defaults( 67 | Mission.Landing.LIFT_COEFFICIENT_MAX, val=self.Cl_max_ldg, units='unitless' 68 | ) 69 | 70 | return landing 71 | -------------------------------------------------------------------------------- /aviary/mission/flops_based/phases/build_takeoff.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.mission.flops_based.phases.simplified_takeoff import TakeoffGroup 4 | from aviary.variable_info.variables import Dynamic 5 | 6 | 7 | class Takeoff: 8 | """ 9 | Define user constraints for a climb phase. 10 | 11 | Parameters 12 | ---------- 13 | airport_altitude : float (None) 14 | altitude of airport (ft) 15 | ratio of lift to drag at takeoff (None) 16 | num_engines int (None) 17 | number of engines (None) 18 | 19 | Returns 20 | ------- 21 | Group 22 | a Group object in OpenMDAO 23 | """ 24 | 25 | def __init__( 26 | self, 27 | airport_altitude=None, 28 | ramp_mass=None, 29 | num_engines=None, 30 | ): 31 | self.airport_altitude = airport_altitude # ft 32 | self.num_engines = num_engines 33 | # note: need to clean this up so that some of these variables come from 34 | # connections. The only variables that should stay are: airport_altitude 35 | 36 | __slots__ = ( 37 | 'airport_altitude', 38 | 'num_engines', 39 | ) 40 | 41 | def build_phase(self, use_detailed=False): 42 | """ 43 | Construct and return a new phase for takeoff analysis. 44 | 45 | Parameters 46 | ---------- 47 | use_detailed : bool(False) 48 | tells whether to use simplified or detailed takeoff. Currently detailed is 49 | disabled. 50 | 51 | Returns 52 | ------- 53 | Group 54 | a group in OpenMDAO 55 | """ 56 | if use_detailed: # TODO 57 | raise om.AnalysisError( 58 | 'Must set takeoff method to `use_detailed=False`, detailed takeoff is' 59 | ' not currently enabled.' 60 | ) 61 | 62 | ############## 63 | # Add Inputs # 64 | ############## 65 | 66 | takeoff = TakeoffGroup(num_engines=self.num_engines) 67 | takeoff.set_input_defaults(Dynamic.Mission.ALTITUDE, val=self.airport_altitude, units='ft') 68 | 69 | return takeoff 70 | -------------------------------------------------------------------------------- /aviary/mission/flops_based/phases/energy_phase.py: -------------------------------------------------------------------------------- 1 | from aviary.mission.flight_phase_builder import FlightPhaseBase, register 2 | from aviary.mission.flops_based.ode.energy_ODE import EnergyODE 3 | from aviary.mission.initial_guess_builders import InitialGuessIntegrationVariable, InitialGuessState 4 | 5 | 6 | # TODO: support/handle the following in the base class 7 | # - phase.set_time_options() 8 | # - currently handled in level 3 interface implementation 9 | # - self.external_subsystems 10 | # - self.meta_data, with cls.default_meta_data customization point 11 | @register 12 | class EnergyPhase(FlightPhaseBase): 13 | default_ode_class = EnergyODE 14 | 15 | 16 | EnergyPhase._add_initial_guess_meta_data( 17 | InitialGuessIntegrationVariable(), 18 | desc='initial guess for initial time and duration specified as a tuple', 19 | ) 20 | 21 | EnergyPhase._add_initial_guess_meta_data( 22 | InitialGuessState('distance'), desc='initial guess for horizontal distance traveled' 23 | ) 24 | -------------------------------------------------------------------------------- /aviary/mission/flops_based/phases/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/flops_based/phases/test/__init__.py -------------------------------------------------------------------------------- /aviary/mission/flops_based/phases/test/test_building_landing.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal 5 | 6 | from aviary.mission.flops_based.phases.build_landing import Landing 7 | from aviary.variable_info.variables import Mission 8 | 9 | 10 | class LandingPhaseTest(unittest.TestCase): 11 | """Test landing phase builder.""" 12 | 13 | def test_case1(self): 14 | landing_options = Landing( 15 | ref_wing_area=1370.0, # ft**2 16 | Cl_max_ldg=3, # no units 17 | ) 18 | 19 | use_detailed = False 20 | landing = landing_options.build_phase(use_detailed=use_detailed) 21 | 22 | prob = om.Problem() 23 | prob.model = landing 24 | prob.setup(force_alloc_complex=True) 25 | prob.run_model() 26 | partial_data = prob.check_partials( 27 | out_stream=None, method='cs', compact_print=False, excludes=['*atmosphere*'] 28 | ) 29 | assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) 30 | 31 | tol = 1e-6 32 | assert_near_equal(prob[Mission.Landing.GROUND_DISTANCE], 6331.781, tol) 33 | assert_near_equal(prob[Mission.Landing.INITIAL_VELOCITY], 134.9752, tol) 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /aviary/mission/flops_based/phases/test/test_building_takeoff.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal 5 | 6 | from aviary.mission.flops_based.phases.build_takeoff import Takeoff 7 | from aviary.variable_info.variables import Aircraft, Mission 8 | 9 | 10 | class TakeoffPhaseTest(unittest.TestCase): 11 | """Test takeoff phase builder.""" 12 | 13 | def test_case1(self): 14 | takeoff_options = Takeoff( 15 | airport_altitude=0, # ft 16 | ramp_mass=181200.0, # lbm 17 | num_engines=2, # no units 18 | ) 19 | 20 | use_detailed = False 21 | takeoff = takeoff_options.build_phase(use_detailed=use_detailed) 22 | 23 | prob = om.Problem() 24 | prob.model = takeoff 25 | prob.model.set_input_defaults(Aircraft.Wing.AREA, 1370.3, units='ft**2') 26 | prob.setup(force_alloc_complex=True) 27 | prob.run_model() 28 | partial_data = prob.check_partials( 29 | out_stream=None, method='cs', compact_print=False, excludes=['*atmosphere*'] 30 | ) 31 | assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) 32 | 33 | tol = 1e-6 34 | assert_near_equal(prob[Mission.Takeoff.GROUND_DISTANCE], 2811.442, tol) 35 | 36 | 37 | if __name__ == '__main__': 38 | unittest.main() 39 | -------------------------------------------------------------------------------- /aviary/mission/gasp_based/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/gasp_based/__init__.py -------------------------------------------------------------------------------- /aviary/mission/gasp_based/ode/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/gasp_based/ode/__init__.py -------------------------------------------------------------------------------- /aviary/mission/gasp_based/ode/constraints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/gasp_based/ode/constraints/__init__.py -------------------------------------------------------------------------------- /aviary/mission/gasp_based/ode/constraints/speed_constraints.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import openmdao.api as om 3 | 4 | from aviary.variable_info.variables import Dynamic 5 | 6 | 7 | class SpeedConstraints(om.ExplicitComponent): 8 | """Compute speed constraint to be driven to zero in order to control speed.""" 9 | 10 | def initialize(self): 11 | self.options.declare('num_nodes', types=int) 12 | self.options.declare( 13 | 'EAS_target', 14 | default=0, 15 | desc='targeted equivalent airspeed in knots assuming mach constraint is satisfied', 16 | ) 17 | self.options.declare('mach_cruise', default=0, desc='targeted cruise Mach number') 18 | 19 | def setup(self): 20 | nn = self.options['num_nodes'] 21 | arange = np.arange(nn) 22 | 23 | self.add_input( 24 | 'EAS', 25 | val=np.ones(nn), 26 | units='kn', 27 | desc='equivalent airspeed', 28 | ) 29 | self.add_input( 30 | Dynamic.Atmosphere.MACH, 31 | val=np.ones(nn), 32 | units='unitless', 33 | desc='Mach number', 34 | ) 35 | 36 | self.add_output( 37 | 'speed_constraint', 38 | val=np.ones((nn, 2)), 39 | units='unitless', 40 | desc='constraint to be driven to zero in order to control speed', 41 | ) 42 | 43 | self.declare_partials('speed_constraint', 'EAS', rows=arange * 2, cols=arange, val=1.0) 44 | self.declare_partials( 45 | 'speed_constraint', 46 | Dynamic.Atmosphere.MACH, 47 | rows=arange * 2 + 1, 48 | cols=arange, 49 | val=self.options['EAS_target'], 50 | ) 51 | 52 | def compute(self, inputs, outputs): 53 | EAS = inputs['EAS'] 54 | EAS_target = self.options['EAS_target'] 55 | mach = inputs[Dynamic.Atmosphere.MACH] 56 | mach_cruise = self.options['mach_cruise'] 57 | 58 | EAS_constraint = EAS - EAS_target 59 | EAS_constraint = EAS_constraint[:, np.newaxis] 60 | mach_constraint = EAS_target * (mach - mach_cruise) 61 | mach_constraint = mach_constraint[:, np.newaxis] 62 | outputs['speed_constraint'] = np.hstack((EAS_constraint, mach_constraint)) 63 | -------------------------------------------------------------------------------- /aviary/mission/gasp_based/ode/constraints/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/gasp_based/ode/constraints/test/__init__.py -------------------------------------------------------------------------------- /aviary/mission/gasp_based/ode/taxi_eom.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.variable_info.functions import add_aviary_input, add_aviary_option 4 | from aviary.variable_info.variables import Dynamic, Mission 5 | 6 | 7 | class TaxiFuelComponent(om.ExplicitComponent): 8 | """Compute the fuel consumed during taxi and update the mass after taxi in a 2DOF mission.""" 9 | 10 | def initialize(self): 11 | add_aviary_option(self, Mission.Taxi.DURATION, units='s') 12 | 13 | def setup(self): 14 | self.add_input( 15 | Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, 16 | val=1.0, 17 | units='lbm/s', 18 | desc='fuel flow rate', 19 | ) 20 | add_aviary_input(self, Mission.Summary.GROSS_MASS, val=175400.0) 21 | 22 | self.add_output( 23 | 'taxi_fuel_consumed', 24 | val=1.0, 25 | units='lbm', 26 | desc='taxi_fuel_consumed', 27 | ) 28 | self.add_output( 29 | Dynamic.Vehicle.MASS, 30 | val=175000.0, 31 | units='lbm', 32 | desc='mass after taxi', 33 | ) 34 | 35 | def setup_partials(self): 36 | self.declare_partials( 37 | 'taxi_fuel_consumed', 38 | [Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL], 39 | ) 40 | self.declare_partials( 41 | Dynamic.Vehicle.MASS, 42 | Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, 43 | ) 44 | self.declare_partials(Dynamic.Vehicle.MASS, Mission.Summary.GROSS_MASS, val=1) 45 | 46 | def compute(self, inputs, outputs): 47 | fuelflow, takeoff_mass = inputs.values() 48 | dt_taxi, _ = self.options[Mission.Taxi.DURATION] 49 | outputs['taxi_fuel_consumed'] = -fuelflow * dt_taxi 50 | outputs[Dynamic.Vehicle.MASS] = takeoff_mass - outputs['taxi_fuel_consumed'] 51 | 52 | def compute_partials(self, inputs, J): 53 | dt_taxi, _ = self.options[Mission.Taxi.DURATION] 54 | 55 | J[ 56 | 'taxi_fuel_consumed', 57 | Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, 58 | ] = -dt_taxi 59 | 60 | J[ 61 | Dynamic.Vehicle.MASS, 62 | Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, 63 | ] = dt_taxi 64 | -------------------------------------------------------------------------------- /aviary/mission/gasp_based/ode/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/gasp_based/ode/test/__init__.py -------------------------------------------------------------------------------- /aviary/mission/gasp_based/ode/test/test_taxi_eom.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal 5 | 6 | from aviary.mission.gasp_based.ode.taxi_eom import TaxiFuelComponent 7 | from aviary.utils.aviary_values import AviaryValues 8 | from aviary.variable_info.functions import setup_model_options 9 | from aviary.variable_info.variables import Dynamic, Mission 10 | 11 | 12 | class TaxiFuelComponentTestCase(unittest.TestCase): 13 | """Test the computation of fuel consumed during taxi in TaxiFuelComponent component.""" 14 | 15 | def setUp(self): 16 | self.prob = om.Problem() 17 | 18 | aviary_options = AviaryValues() 19 | aviary_options.set_val(Mission.Taxi.DURATION, 0.1677, units='h') 20 | 21 | self.prob.model.add_subsystem('taxi', TaxiFuelComponent(), promotes=['*']) 22 | 23 | setup_model_options(self.prob, aviary_options) 24 | 25 | def test_fuel_consumed(self): 26 | self.prob.setup(force_alloc_complex=True) 27 | 28 | self.prob.set_val( 29 | Dynamic.Vehicle.Propulsion.FUEL_FLOW_RATE_NEGATIVE_TOTAL, 30 | -1512, 31 | units='lbm/h', 32 | ) 33 | self.prob.set_val(Mission.Summary.GROSS_MASS, 175400.0, units='lbm') 34 | 35 | self.prob.run_model() 36 | 37 | assert_near_equal(self.prob['taxi_fuel_consumed'], 1512 * 0.1677, 1e-6) 38 | partial_data = self.prob.check_partials(out_stream=None, method='cs') 39 | assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) 40 | 41 | 42 | if __name__ == '__main__': 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /aviary/mission/gasp_based/ode/unsteady_solved/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/gasp_based/ode/unsteady_solved/__init__.py -------------------------------------------------------------------------------- /aviary/mission/gasp_based/ode/unsteady_solved/gamma_comp.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import openmdao.api as om 3 | 4 | from aviary.variable_info.variables import Dynamic 5 | 6 | 7 | class GammaComp(om.ExplicitComponent): 8 | """Computes flight path angle and its curvature.""" 9 | 10 | def __init__(self, **kwargs): 11 | super().__init__(**kwargs) 12 | 13 | def initialize(self): 14 | self.options.declare('num_nodes', types=int) 15 | 16 | def setup(self): 17 | nn = self.options['num_nodes'] 18 | 19 | self.add_input( 20 | 'dh_dr', shape=nn, units='m/distance_units', desc='change in altitude wrt range' 21 | ) 22 | 23 | self.add_input( 24 | 'd2h_dr2', 25 | shape=nn, 26 | units='m/distance_units**2', 27 | desc='second derivative of altitude wrt range', 28 | ) 29 | 30 | self.add_output( 31 | Dynamic.Mission.FLIGHT_PATH_ANGLE, 32 | shape=nn, 33 | units='rad', 34 | desc='flight path angle', 35 | ) 36 | 37 | self.add_output( 38 | 'dgam_dr', 39 | shape=nn, 40 | units='rad/distance_units', 41 | desc='change in flight path angle per unit range traversed', 42 | ) 43 | 44 | def setup_partials(self): 45 | nn = self.options['num_nodes'] 46 | ar = np.arange(nn, dtype=int) 47 | 48 | self.declare_partials(of=Dynamic.Mission.FLIGHT_PATH_ANGLE, wrt='dh_dr', rows=ar, cols=ar) 49 | self.declare_partials(of='dgam_dr', wrt=['dh_dr', 'd2h_dr2'], rows=ar, cols=ar) 50 | 51 | def compute(self, inputs, outputs): 52 | dh_dr = inputs['dh_dr'] 53 | d2h_dr2 = inputs['d2h_dr2'] 54 | 55 | outputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] = np.arctan(dh_dr) 56 | outputs['dgam_dr'] = d2h_dr2 / (dh_dr**2 + 1) 57 | 58 | def compute_partials(self, inputs, partials): 59 | dh_dr = inputs['dh_dr'] 60 | d2h_dr2 = inputs['d2h_dr2'] 61 | 62 | partials[Dynamic.Mission.FLIGHT_PATH_ANGLE, 'dh_dr'] = 1.0 / (dh_dr**2 + 1) 63 | partials['dgam_dr', 'dh_dr'] = -d2h_dr2 * dh_dr * 2 / (dh_dr**2 + 1) ** 2 64 | partials['dgam_dr', 'd2h_dr2'] = 1.0 / (dh_dr**2 + 1) 65 | -------------------------------------------------------------------------------- /aviary/mission/gasp_based/ode/unsteady_solved/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/gasp_based/ode/unsteady_solved/test/__init__.py -------------------------------------------------------------------------------- /aviary/mission/gasp_based/phases/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/gasp_based/phases/__init__.py -------------------------------------------------------------------------------- /aviary/mission/gasp_based/phases/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/gasp_based/phases/test/__init__.py -------------------------------------------------------------------------------- /aviary/mission/gasp_based/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/gasp_based/test/__init__.py -------------------------------------------------------------------------------- /aviary/mission/ode/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/ode/__init__.py -------------------------------------------------------------------------------- /aviary/mission/ode/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/ode/test/__init__.py -------------------------------------------------------------------------------- /aviary/mission/ode/test/test_altitude_rate.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | 5 | from aviary.mission.ode.altitude_rate import AltitudeRate 6 | from aviary.utils.test_utils.variable_test import assert_match_varnames 7 | from aviary.validation_cases.validation_data.flops_data.full_mission_test_data import data 8 | from aviary.validation_cases.validation_tests import do_validation_test 9 | from aviary.variable_info.variables import Dynamic 10 | 11 | 12 | class AltitudeRateTest(unittest.TestCase): 13 | def setUp(self): 14 | prob = self.prob = om.Problem() 15 | 16 | time, _ = data.get_item('time') 17 | 18 | prob.model.add_subsystem( 19 | Dynamic.Mission.ALTITUDE_RATE, 20 | AltitudeRate(num_nodes=len(time)), 21 | promotes_inputs=['*'], 22 | promotes_outputs=['*'], 23 | ) 24 | 25 | prob.setup(check=False, force_alloc_complex=True) 26 | 27 | def test_case1(self): 28 | do_validation_test( 29 | self.prob, 30 | 'full_mission_test_data', 31 | input_validation_data=data, 32 | output_validation_data=data, 33 | input_keys=[ 34 | Dynamic.Mission.SPECIFIC_ENERGY_RATE, 35 | Dynamic.Mission.VELOCITY, 36 | Dynamic.Mission.VELOCITY_RATE, 37 | ], 38 | output_keys=Dynamic.Mission.ALTITUDE_RATE, 39 | tol=1e-9, 40 | ) 41 | 42 | def test_IO(self): 43 | assert_match_varnames(self.prob.model) 44 | 45 | 46 | if __name__ == '__main__': 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /aviary/mission/ode/test/test_specific_energy_rate.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | 5 | from aviary.mission.ode.specific_energy_rate import SpecificEnergyRate 6 | from aviary.utils.test_utils.variable_test import assert_match_varnames 7 | from aviary.validation_cases.validation_data.flops_data.full_mission_test_data import data 8 | from aviary.validation_cases.validation_tests import do_validation_test 9 | from aviary.variable_info.variables import Dynamic 10 | 11 | 12 | class SpecificEnergyRateTest(unittest.TestCase): 13 | def setUp(self): 14 | prob = self.prob = om.Problem() 15 | 16 | time, _ = data.get_item('time') 17 | 18 | prob.model.add_subsystem( 19 | 'specific_energy_rate', 20 | SpecificEnergyRate(num_nodes=len(time)), 21 | promotes_inputs=['*'], 22 | promotes_outputs=['*'], 23 | ) 24 | 25 | prob.setup(check=False, force_alloc_complex=True) 26 | 27 | def test_case1(self): 28 | do_validation_test( 29 | self.prob, 30 | 'full_mission_test_data', 31 | input_validation_data=data, 32 | output_validation_data=data, 33 | input_keys=[ 34 | Dynamic.Vehicle.DRAG, 35 | Dynamic.Vehicle.MASS, 36 | Dynamic.Vehicle.Propulsion.THRUST_TOTAL, 37 | Dynamic.Mission.VELOCITY, 38 | ], 39 | output_keys=Dynamic.Mission.SPECIFIC_ENERGY_RATE, 40 | tol=1e-12, 41 | ) 42 | 43 | def test_IO(self): 44 | assert_match_varnames(self.prob.model) 45 | 46 | 47 | if __name__ == '__main__': 48 | unittest.main() 49 | -------------------------------------------------------------------------------- /aviary/mission/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/mission/test/__init__.py -------------------------------------------------------------------------------- /aviary/mission/utils.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.utils.functions import promote_aircraft_and_mission_vars 4 | 5 | 6 | class ExternalSubsystemGroup(om.Group): 7 | def configure(self): 8 | promote_aircraft_and_mission_vars(self) 9 | -------------------------------------------------------------------------------- /aviary/models/N3CC/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/models/N3CC/__init__.py -------------------------------------------------------------------------------- /aviary/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/models/__init__.py -------------------------------------------------------------------------------- /aviary/models/large_single_aisle_1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/models/large_single_aisle_1/__init__.py -------------------------------------------------------------------------------- /aviary/models/large_single_aisle_2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/models/large_single_aisle_2/__init__.py -------------------------------------------------------------------------------- /aviary/models/large_turboprop_freighter/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/models/large_turboprop_freighter/__init__.py -------------------------------------------------------------------------------- /aviary/models/multi_engine_single_aisle/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/models/multi_engine_single_aisle/__init__.py -------------------------------------------------------------------------------- /aviary/run_all_benchmarks.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | status = subprocess.run(['testflo', '--testmatch=bench_test*']) 4 | if status.returncode == 1: 5 | # disable mpi and try again - can cause PermissionError for "forbidden sockets" 6 | print('Re-running all benchmark tests with MPI disabled') 7 | subprocess.run(['testflo', '--testmatch=bench_test*', '--nompi']) 8 | -------------------------------------------------------------------------------- /aviary/subsystems/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/aerodynamics/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/aero_common.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import openmdao.api as om 3 | 4 | from aviary.variable_info.functions import add_aviary_input, add_aviary_output 5 | from aviary.variable_info.variables import Dynamic 6 | 7 | 8 | class DynamicPressure(om.ExplicitComponent): 9 | """ 10 | Compute dynamic pressure as 11 | Dynamic.Mission.DYNAMIC_PRESSURE = 0.5 * gamma * P * M**2. 12 | """ 13 | 14 | def initialize(self): 15 | self.options.declare('num_nodes', types=int) 16 | 17 | self.options.declare('gamma', default=1.4, desc='Ratio of specific heats for air.') 18 | 19 | def setup(self): 20 | nn = self.options['num_nodes'] 21 | 22 | add_aviary_input(self, Dynamic.Atmosphere.STATIC_PRESSURE, shape=nn, units='lbf/ft**2') 23 | 24 | add_aviary_input(self, Dynamic.Atmosphere.MACH, shape=nn, units='unitless') 25 | 26 | add_aviary_output(self, Dynamic.Atmosphere.DYNAMIC_PRESSURE, shape=nn, units='lbf/ft**2') 27 | 28 | def setup_partials(self): 29 | nn = self.options['num_nodes'] 30 | 31 | rows_cols = np.arange(nn) 32 | 33 | self.declare_partials( 34 | Dynamic.Atmosphere.DYNAMIC_PRESSURE, 35 | [Dynamic.Atmosphere.STATIC_PRESSURE, Dynamic.Atmosphere.MACH], 36 | rows=rows_cols, 37 | cols=rows_cols, 38 | ) 39 | 40 | def compute(self, inputs, outputs): 41 | gamma = self.options['gamma'] 42 | P = inputs[Dynamic.Atmosphere.STATIC_PRESSURE] 43 | M = inputs[Dynamic.Atmosphere.MACH] 44 | 45 | outputs[Dynamic.Atmosphere.DYNAMIC_PRESSURE] = 0.5 * gamma * P * M**2 46 | 47 | def compute_partials(self, inputs, partials): 48 | gamma = self.options['gamma'] 49 | P = inputs[Dynamic.Atmosphere.STATIC_PRESSURE] 50 | M = inputs[Dynamic.Atmosphere.MACH] 51 | 52 | partials[Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.MACH] = gamma * P * M 53 | partials[Dynamic.Atmosphere.DYNAMIC_PRESSURE, Dynamic.Atmosphere.STATIC_PRESSURE] = ( 54 | 0.5 * gamma * M**2 55 | ) 56 | -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/flops_based/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/aerodynamics/flops_based/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/flops_based/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/aerodynamics/flops_based/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/gasp_based/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/aerodynamics/gasp_based/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/gasp_based/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/aerodynamics/gasp_based/data/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/gasp_based/flaps_model/__init__.py: -------------------------------------------------------------------------------- 1 | from aviary.subsystems.aerodynamics.gasp_based.flaps_model.flaps_model import FlapsGroup 2 | -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/gasp_based/flaps_model/test/test_increments.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal 5 | 6 | from aviary.subsystems.aerodynamics.gasp_based.flaps_model.L_and_D_increments import ( 7 | LiftAndDragIncrements, 8 | ) 9 | from aviary.variable_info.variables import Aircraft 10 | 11 | """ 12 | All data is from validation files using standalone flaps model 13 | """ 14 | 15 | 16 | class LiftAndDragIncrementsTestCase(unittest.TestCase): 17 | def setUp(self): 18 | self.prob = om.Problem(model=om.Group()) 19 | 20 | self.prob.model.add_subsystem('LaDIs', LiftAndDragIncrements(), promotes=['*']) 21 | 22 | self.prob.setup() 23 | 24 | # initial conditions 25 | self.prob.set_val(Aircraft.Wing.FLAP_DRAG_INCREMENT_OPTIMUM, 0.1) 26 | self.prob.set_val(Aircraft.Wing.FLAP_LIFT_INCREMENT_OPTIMUM, 1.5) 27 | self.prob.set_val('VDEL1', 1.0) 28 | self.prob.set_val('VDEL2', 1) 29 | self.prob.set_val('VDEL3', 0.765) 30 | self.prob.set_val('VDEL4', 0.93578) 31 | self.prob.set_val('VDEL5', 0.90761) 32 | self.prob.set_val('VLAM3', 0.97217) 33 | self.prob.set_val('VLAM4', 1.25725) 34 | self.prob.set_val('VLAM5', 1.0) 35 | self.prob.set_val('VLAM6', 1.0) 36 | self.prob.set_val('VLAM7', 0.735) 37 | self.prob.set_val('VLAM8', 0.74444) 38 | self.prob.set_val('VLAM13', 1.03512) 39 | self.prob.set_val('VLAM14', 0.99124) 40 | 41 | def test_case(self): 42 | self.prob.run_model() 43 | tol = 5e-4 44 | print() 45 | 46 | reg_data = 0.0650 47 | ans = self.prob['delta_CD'] 48 | assert_near_equal(ans, reg_data, tol) 49 | 50 | reg_data = 1.0293 51 | ans = self.prob['delta_CL'] 52 | assert_near_equal(ans, reg_data, tol) 53 | 54 | data = self.prob.check_partials(out_stream=None, method='fd') 55 | assert_check_partials(data, atol=1e-4, rtol=1e-4) 56 | 57 | 58 | if __name__ == '__main__': 59 | unittest.main() 60 | -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/gasp_based/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/aerodynamics/gasp_based/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/gasp_based/test/test_gasp_aero_coeffs.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal 5 | 6 | from aviary.subsystems.aerodynamics.gasp_based.gasp_aero_coeffs import AeroFormfactors 7 | from aviary.variable_info.variables import Aircraft, Mission 8 | 9 | tol = 1e-8 10 | 11 | 12 | class TestAeroCoeffs(unittest.TestCase): 13 | def test_aero_coeffs(self): 14 | aero_coeffs = AeroFormfactors() 15 | prob = om.Problem() 16 | prob.model.add_subsystem('comp', aero_coeffs, promotes=['*']) 17 | prob.setup(force_alloc_complex=True) 18 | 19 | prob.set_val(Aircraft.Wing.THICKNESS_TO_CHORD_UNWEIGHTED, 0.12) 20 | prob.set_val(Aircraft.VerticalTail.THICKNESS_TO_CHORD, 0.15) 21 | prob.set_val(Aircraft.HorizontalTail.THICKNESS_TO_CHORD, 0.1) 22 | prob.set_val(Aircraft.Strut.THICKNESS_TO_CHORD, 0.1) 23 | prob.set_val(Aircraft.Wing.SWEEP, 30, units='deg') 24 | prob.set_val(Aircraft.VerticalTail.SWEEP, 15, units='deg') 25 | prob.set_val(Aircraft.HorizontalTail.SWEEP, 10, units='deg') 26 | prob.set_val(Aircraft.HorizontalTail.VERTICAL_TAIL_FRACTION, 0) 27 | prob.set_val(Mission.Design.MACH, 0.6) 28 | prob.set_val(Aircraft.Nacelle.AVG_DIAMETER, 6) 29 | prob.set_val(Aircraft.Nacelle.AVG_LENGTH, 10) 30 | 31 | prob.run_model() 32 | 33 | assert_near_equal(prob.get_val(Aircraft.Wing.FORM_FACTOR), [2.4892359], tol) 34 | assert_near_equal(prob.get_val(Aircraft.VerticalTail.FORM_FACTOR), [2.73809734], tol) 35 | assert_near_equal(prob.get_val(Aircraft.HorizontalTail.FORM_FACTOR), [2.59223754], tol) 36 | assert_near_equal(prob.get_val(Aircraft.Strut.FUSELAGE_INTERFERENCE_FACTOR), [2.4786], tol) 37 | assert_near_equal(prob.get_val(Aircraft.Nacelle.FORM_FACTOR), [1.815], tol) 38 | 39 | partial_data = prob.check_partials(method='cs', out_stream=None) 40 | assert_check_partials(partial_data, atol=1e-12, rtol=1e-14) 41 | 42 | 43 | if __name__ == '__main__': 44 | unittest.main() 45 | -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/solve_alpha_group.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import openmdao.api as om 3 | 4 | from aviary import constants 5 | from aviary.variable_info.variables import Dynamic 6 | 7 | 8 | class SolveAlphaGroup(om.Group): 9 | """ 10 | Group that contains components needed to determine angle of attack. Must be paired with 11 | aerodynamics method and a solver to properly balance lift and weight. 12 | """ 13 | 14 | def initialize(self): 15 | self.options.declare('num_nodes', types=int) 16 | 17 | def setup(self): 18 | num_nodes = self.options['num_nodes'] 19 | self.add_subsystem( 20 | 'required_lift', 21 | om.ExecComp( 22 | 'required_lift = mass * grav_metric', 23 | grav_metric={'val': constants.GRAV_METRIC_GASP}, 24 | mass={'units': 'kg', 'shape': num_nodes}, 25 | required_lift={'units': 'N', 'shape': num_nodes}, 26 | has_diag_partials=True, 27 | ), 28 | promotes_inputs=[ 29 | ('mass', Dynamic.Vehicle.MASS), 30 | ], 31 | ) 32 | 33 | balance = self.add_subsystem( 34 | 'balance', 35 | om.BalanceComp(), 36 | promotes=[Dynamic.Vehicle.ANGLE_OF_ATTACK, Dynamic.Vehicle.LIFT], 37 | ) 38 | balance.add_balance( 39 | Dynamic.Vehicle.ANGLE_OF_ATTACK, 40 | val=np.ones(num_nodes), 41 | units='deg', 42 | res_ref=1.0e6, 43 | lhs_name=Dynamic.Vehicle.LIFT, 44 | rhs_name='required_lift', 45 | eq_units='lbf', 46 | ) 47 | 48 | self.connect( 49 | 'required_lift.required_lift', 50 | 'balance.required_lift', 51 | ) 52 | -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/aerodynamics/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/test/test_flops_aero_builder.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import aviary.api as av 4 | from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder 5 | from aviary.variable_info.enums import LegacyCode 6 | from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData 7 | from aviary.variable_info.variables import Aircraft 8 | 9 | FLOPS = LegacyCode.FLOPS 10 | 11 | 12 | class TestAeroBuilder(av.TestSubsystemBuilderBase): 13 | """ 14 | That class inherits from TestSubsystemBuilder. So all the test functions are 15 | within that inherited class. The setUp() method prepares the class and is run 16 | before the test methods; then the test methods are run. 17 | """ 18 | 19 | def setUp(self): 20 | self.subsystem_builder = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, FLOPS) 21 | self.aviary_values = av.AviaryValues() 22 | self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, [1], units='unitless') 23 | 24 | 25 | if __name__ == '__main__': 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/test/test_gasp_aero_builder.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import aviary.api as av 4 | from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder 5 | from aviary.variable_info.enums import LegacyCode 6 | from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData 7 | from aviary.variable_info.variables import Aircraft 8 | 9 | GASP = LegacyCode.GASP 10 | 11 | 12 | class TestAeroBuilder(av.TestSubsystemBuilderBase): 13 | """ 14 | That class inherits from TestSubsystemBuilder. So all the test functions are 15 | within that inherited class. The setUp() method prepares the class and is run 16 | before the test methods; then the test methods are run. 17 | """ 18 | 19 | def setUp(self): 20 | self.subsystem_builder = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, GASP) 21 | self.aviary_values = av.AviaryValues() 22 | self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, [1], units='unitless') 23 | 24 | def test_build_mission(self): 25 | kwargs = {'method': 'cruise'} 26 | return super().test_build_mission(**kwargs) 27 | 28 | def test_get_parameters(self): 29 | kwargs = {'method': 'cruise'} 30 | return super().test_get_parameters(**kwargs) 31 | 32 | def test_check_parameters(self): 33 | kwargs = {'method': 'cruise'} 34 | return super().test_check_parameters(**kwargs) 35 | 36 | 37 | if __name__ == '__main__': 38 | unittest.main() 39 | -------------------------------------------------------------------------------- /aviary/subsystems/aerodynamics/test/test_gasp_drag.py: -------------------------------------------------------------------------------- 1 | """Tests the aero builder with the 2dof (gasp-based) drag.""" 2 | 3 | import unittest 4 | from copy import deepcopy 5 | 6 | from openmdao.utils.assert_utils import assert_near_equal 7 | 8 | from aviary.interface.default_phase_info.two_dof import phase_info 9 | from aviary.interface.methods_for_level2 import AviaryProblem 10 | from aviary.variable_info.variables import Aircraft 11 | 12 | 13 | class TestAeroBuilderGasp(unittest.TestCase): 14 | def test_parameters(self): 15 | # This test is to make sure that the aero builder creates a parameter 16 | # for wing height. It addresses a bug where this was absent. 17 | 18 | local_phase_info = deepcopy(phase_info) 19 | 20 | prob = AviaryProblem() 21 | 22 | prob.load_inputs( 23 | 'models/test_aircraft/aircraft_for_bench_GwGm.csv', 24 | local_phase_info, 25 | ) 26 | 27 | # Change value just to be certain. 28 | prob.aviary_inputs.set_val(Aircraft.Wing.HEIGHT, 7.7777, units='ft') 29 | 30 | # Preprocess inputs 31 | prob.check_and_preprocess_inputs() 32 | 33 | prob.add_pre_mission_systems() 34 | prob.add_phases() 35 | prob.add_post_mission_systems() 36 | 37 | prob.link_phases() 38 | 39 | prob.setup() 40 | 41 | prob.set_initial_guesses() 42 | 43 | prob.run_model() 44 | 45 | # verify that we are promoting the parameters. 46 | wing_height = prob.get_val( 47 | 'traj.rotation.rhs_all.aircraft:wing:height', 48 | units='ft', 49 | ) 50 | actual_wing_height = prob.aviary_inputs.get_val(Aircraft.Wing.HEIGHT, units='ft') 51 | assert_near_equal(wing_height, actual_wing_height) 52 | 53 | 54 | if __name__ == '__main__': 55 | unittest.main() 56 | -------------------------------------------------------------------------------- /aviary/subsystems/atmosphere/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/atmosphere/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/energy/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/energy/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/energy/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/energy/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/geometry/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/geometry/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/geometry/flops_based/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/geometry/flops_based/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/geometry/flops_based/fuselage.py: -------------------------------------------------------------------------------- 1 | """Contains any preliminary calculations on the fuselage.""" 2 | 3 | import openmdao.api as om 4 | 5 | from aviary.variable_info.functions import add_aviary_input, add_aviary_output 6 | from aviary.variable_info.variables import Aircraft 7 | 8 | 9 | class FuselagePrelim(om.ExplicitComponent): 10 | """ 11 | Calculate fuselage average diameter and planform area defined by: 12 | Aircraft.Fuselage.AVG_DIAMETER = 0.5 * (max_height + max_width) 13 | Aircraft.Fuselage.PLANFORM_AREA = length * max_width. 14 | """ 15 | 16 | def setup(self): 17 | add_aviary_input(self, Aircraft.Fuselage.LENGTH, units='ft') 18 | add_aviary_input(self, Aircraft.Fuselage.MAX_HEIGHT, units='ft') 19 | add_aviary_input(self, Aircraft.Fuselage.MAX_WIDTH, units='ft') 20 | 21 | add_aviary_output(self, Aircraft.Fuselage.AVG_DIAMETER, units='ft') 22 | add_aviary_output(self, Aircraft.Fuselage.PLANFORM_AREA, units='ft**2') 23 | 24 | def setup_partials(self): 25 | self.declare_partials( 26 | of=[Aircraft.Fuselage.AVG_DIAMETER], 27 | wrt=[Aircraft.Fuselage.MAX_HEIGHT, Aircraft.Fuselage.MAX_WIDTH], 28 | val=0.5, 29 | ) 30 | self.declare_partials( 31 | of=[Aircraft.Fuselage.PLANFORM_AREA], 32 | wrt=[Aircraft.Fuselage.LENGTH, Aircraft.Fuselage.MAX_WIDTH], 33 | ) 34 | 35 | def compute(self, inputs, outputs): 36 | max_height = inputs[Aircraft.Fuselage.MAX_HEIGHT] 37 | max_width = inputs[Aircraft.Fuselage.MAX_WIDTH] 38 | length = inputs[Aircraft.Fuselage.LENGTH] 39 | 40 | avg_diameter = 0.5 * (max_height + max_width) 41 | outputs[Aircraft.Fuselage.AVG_DIAMETER] = avg_diameter 42 | 43 | outputs[Aircraft.Fuselage.PLANFORM_AREA] = length * max_width 44 | 45 | def compute_partials(self, inputs, partials, discrete_inputs=None): 46 | max_width = inputs[Aircraft.Fuselage.MAX_WIDTH] 47 | length = inputs[Aircraft.Fuselage.LENGTH] 48 | 49 | partials[Aircraft.Fuselage.PLANFORM_AREA, Aircraft.Fuselage.LENGTH] = max_width 50 | 51 | partials[Aircraft.Fuselage.PLANFORM_AREA, Aircraft.Fuselage.MAX_WIDTH] = length 52 | -------------------------------------------------------------------------------- /aviary/subsystems/geometry/flops_based/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/geometry/flops_based/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/geometry/flops_based/test/test_nacelle.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import numpy as np 4 | import openmdao.api as om 5 | from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal 6 | 7 | from aviary.subsystems.geometry.flops_based.nacelle import Nacelles 8 | from aviary.utils.test_utils.variable_test import assert_match_varnames 9 | from aviary.variable_info.variables import Aircraft 10 | 11 | 12 | class NacelleTest(unittest.TestCase): 13 | """Test nacelle wetted area computation.""" 14 | 15 | def setUp(self): 16 | self.prob = om.Problem() 17 | 18 | def test_case_multiengine(self): 19 | # test with multiple engine types 20 | prob = self.prob 21 | 22 | options = { 23 | Aircraft.Engine.NUM_ENGINES: np.array([2, 2, 3]), 24 | } 25 | 26 | prob.model.add_subsystem( 27 | 'nacelles', Nacelles(**options), promotes_outputs=['*'], promotes_inputs=['*'] 28 | ) 29 | 30 | prob.setup(check=False, force_alloc_complex=True) 31 | 32 | prob.set_val(Aircraft.Nacelle.AVG_DIAMETER, val=np.array([6, 4.25, 9.6])) 33 | prob.set_val(Aircraft.Nacelle.AVG_LENGTH, val=np.array([8.4, 5.75, 10])) 34 | prob.set_val(Aircraft.Nacelle.WETTED_AREA_SCALER, val=np.array([1.0, 0.92, 1.4])) 35 | 36 | prob.run_model() 37 | 38 | wetted_area = prob.get_val(Aircraft.Nacelle.WETTED_AREA) 39 | total_wetted_area = prob.get_val(Aircraft.Nacelle.TOTAL_WETTED_AREA) 40 | 41 | expected_wetted_area = np.array([141.12, 62.951, 376.32]) 42 | expected_total_wetted_area = sum(expected_wetted_area * np.array([2, 2, 3])) 43 | 44 | assert_near_equal(wetted_area, expected_wetted_area, tolerance=1e-10) 45 | assert_near_equal(total_wetted_area, expected_total_wetted_area, tolerance=1e-10) 46 | 47 | partial_data = self.prob.check_partials(out_stream=None, method='cs') 48 | assert_check_partials(partial_data, atol=1e-10, rtol=1e-10) 49 | 50 | def test_IO(self): 51 | assert_match_varnames(self.prob.model) 52 | 53 | 54 | if __name__ == '__main__': 55 | # unittest.main() 56 | test = NacelleTest() 57 | test.setUp() 58 | test.test_case_multiengine() 59 | -------------------------------------------------------------------------------- /aviary/subsystems/geometry/flops_based/utils.py: -------------------------------------------------------------------------------- 1 | thickness_to_chord_scaler = 0.387 2 | _fuselage_adjustment_scaler = 0.6730 3 | 4 | 5 | def calc_lifting_surface_scaler(thickness_to_chord): 6 | """Calculate lifting surface scaler.""" 7 | scaler = thickness_to_chord_scaler * thickness_to_chord + 2.0 8 | 9 | return scaler 10 | 11 | 12 | def calc_fuselage_adjustment(chord, thickness_to_chord): 13 | """Calculate fuselage_adjustment.""" 14 | adjustment = _fuselage_adjustment_scaler * chord * (thickness_to_chord * chord) 15 | 16 | return adjustment 17 | 18 | 19 | def d_calc_fuselage_adjustment(chord, thickness_to_chord): 20 | """Calculate partial derivatives of fuselage_adjustment with respect to chord and thickness_to_chord.""" 21 | d1 = 2.0 * _fuselage_adjustment_scaler * thickness_to_chord * chord 22 | d2 = _fuselage_adjustment_scaler * chord**2 23 | 24 | return d1, d2 25 | 26 | 27 | class Names: 28 | """Define component I/O variable names that should not exported.""" 29 | 30 | CROOT = 'prep_geom:_Names:CROOT' 31 | CROOTB = 'prep_geom:_Names:CROOTB' 32 | CROTM = 'prep_geom:_Names:CROTM' 33 | CROTVT = 'prep_geom:_Names:CROTVT' 34 | CRTHTB = 'prep_geom:_Names:CRTHTB' 35 | # equivalent(?) 36 | SPANHT = 'prep_geom:_Names:SPANHT' 37 | SPANVT = 'prep_geom:_Names:SPANVT' 38 | XDX = 'prep_geom:_Names:XDX' 39 | XMULT = 'prep_geom:_Names:XMULT' 40 | XMULTH = 'prep_geom:_Names:XMULTH' 41 | XMULTV = 'prep_geom:_Names:XMULTV' 42 | 43 | __slots__ = () 44 | -------------------------------------------------------------------------------- /aviary/subsystems/geometry/flops_based/wetted_area_total.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.variable_info.functions import add_aviary_input, add_aviary_output 4 | from aviary.variable_info.variables import Aircraft 5 | 6 | 7 | class TotalWettedArea(om.ExplicitComponent): 8 | """ 9 | Sum of wetted areas of canard, fuselage, horizontal tail, nacelle, vertical tail and wing. 10 | It is simple enough to skip unit test. 11 | """ 12 | 13 | def setup(self): 14 | add_aviary_input(self, Aircraft.Canard.WETTED_AREA, units='ft**2') 15 | add_aviary_input(self, Aircraft.Fuselage.WETTED_AREA, units='ft**2') 16 | add_aviary_input(self, Aircraft.HorizontalTail.WETTED_AREA, units='ft**2') 17 | add_aviary_input(self, Aircraft.Nacelle.TOTAL_WETTED_AREA, units='ft**2') 18 | add_aviary_input(self, Aircraft.VerticalTail.WETTED_AREA, units='ft**2') 19 | add_aviary_input(self, Aircraft.Wing.WETTED_AREA, units='ft**2') 20 | 21 | add_aviary_output(self, Aircraft.Design.TOTAL_WETTED_AREA, units='ft**2') 22 | 23 | def setup_partials(self): 24 | self.declare_partials('*', '*', val=1.0) 25 | 26 | def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): 27 | outputs[Aircraft.Design.TOTAL_WETTED_AREA] = ( 28 | inputs[Aircraft.Canard.WETTED_AREA] 29 | + inputs[Aircraft.Fuselage.WETTED_AREA] 30 | + inputs[Aircraft.HorizontalTail.WETTED_AREA] 31 | + inputs[Aircraft.Nacelle.TOTAL_WETTED_AREA] 32 | + inputs[Aircraft.VerticalTail.WETTED_AREA] 33 | + inputs[Aircraft.Wing.WETTED_AREA] 34 | ) 35 | -------------------------------------------------------------------------------- /aviary/subsystems/geometry/flops_based/wing.py: -------------------------------------------------------------------------------- 1 | """Contains any preliminary calculations on the wing.""" 2 | 3 | import openmdao.api as om 4 | 5 | from aviary.variable_info.functions import add_aviary_input, add_aviary_output 6 | from aviary.variable_info.variables import Aircraft 7 | 8 | 9 | class WingPrelim(om.ExplicitComponent): 10 | """preliminary calculations of wing aspect ratio.""" 11 | 12 | def setup(self): 13 | add_aviary_input(self, Aircraft.Wing.AREA, units='ft**2') 14 | add_aviary_input(self, Aircraft.Wing.GLOVE_AND_BAT, units='ft**2') 15 | add_aviary_input(self, Aircraft.Wing.SPAN, units='ft') 16 | 17 | add_aviary_output(self, Aircraft.Wing.ASPECT_RATIO, units='unitless') 18 | 19 | def setup_partials(self): 20 | self.declare_partials('*', '*') 21 | 22 | def compute(self, inputs, outputs): 23 | area = inputs[Aircraft.Wing.AREA] 24 | glove_and_bat = inputs[Aircraft.Wing.GLOVE_AND_BAT] 25 | span = inputs[Aircraft.Wing.SPAN] 26 | 27 | AR = span**2 / (area - glove_and_bat) 28 | outputs[Aircraft.Wing.ASPECT_RATIO] = AR 29 | 30 | def compute_partials(self, inputs, partials, discrete_inputs=None): 31 | area = inputs[Aircraft.Wing.AREA] 32 | glove_and_bat = inputs[Aircraft.Wing.GLOVE_AND_BAT] 33 | span = inputs[Aircraft.Wing.SPAN] 34 | 35 | denom = 1.0 / (area - glove_and_bat) 36 | 37 | partials[Aircraft.Wing.ASPECT_RATIO, Aircraft.Wing.AREA] = -((span * denom) ** 2) 38 | 39 | partials[Aircraft.Wing.ASPECT_RATIO, Aircraft.Wing.GLOVE_AND_BAT] = (span * denom) ** 2 40 | 41 | partials[Aircraft.Wing.ASPECT_RATIO, Aircraft.Wing.SPAN] = 2.0 * span * denom 42 | -------------------------------------------------------------------------------- /aviary/subsystems/geometry/gasp_based/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/geometry/gasp_based/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/geometry/gasp_based/electric.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import openmdao.api as om 3 | 4 | from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output 5 | from aviary.variable_info.variables import Aircraft 6 | 7 | 8 | class CableSize(om.ExplicitComponent): 9 | """Computation of cable length for hybrid electric augmented system.""" 10 | 11 | def initialize(self): 12 | add_aviary_option(self, Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES) 13 | 14 | def setup(self): 15 | total_num_wing_engines = self.options[Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES] 16 | 17 | add_aviary_input( 18 | self, 19 | Aircraft.Engine.WING_LOCATIONS, 20 | shape=int(total_num_wing_engines / 2), 21 | units='unitless', 22 | ) 23 | add_aviary_input(self, Aircraft.Wing.SPAN, units='ft') 24 | add_aviary_input(self, Aircraft.Fuselage.AVG_DIAMETER, units='ft') 25 | 26 | add_aviary_output(self, Aircraft.Electrical.HYBRID_CABLE_LENGTH, units='ft') 27 | 28 | self.declare_partials( 29 | Aircraft.Electrical.HYBRID_CABLE_LENGTH, 30 | [ 31 | Aircraft.Engine.WING_LOCATIONS, 32 | Aircraft.Wing.SPAN, 33 | ], 34 | ) 35 | 36 | self.declare_partials( 37 | Aircraft.Electrical.HYBRID_CABLE_LENGTH, Aircraft.Fuselage.AVG_DIAMETER, val=2.0 38 | ) 39 | 40 | def compute(self, inputs, outputs): 41 | eng_span_frac = np.sum(inputs[Aircraft.Engine.WING_LOCATIONS]) 42 | wingspan = inputs[Aircraft.Wing.SPAN] 43 | cabin_width = inputs[Aircraft.Fuselage.AVG_DIAMETER] 44 | 45 | outputs[Aircraft.Electrical.HYBRID_CABLE_LENGTH] = ( 46 | eng_span_frac * wingspan + 2.0 * cabin_width 47 | ) 48 | 49 | def compute_partials(self, inputs, J): 50 | eng_span_frac = inputs[Aircraft.Engine.WING_LOCATIONS] 51 | wingspan = inputs[Aircraft.Wing.SPAN] 52 | 53 | J[ 54 | Aircraft.Electrical.HYBRID_CABLE_LENGTH, 55 | Aircraft.Engine.WING_LOCATIONS, 56 | ] = wingspan 57 | J[Aircraft.Electrical.HYBRID_CABLE_LENGTH, Aircraft.Wing.SPAN] = np.sum(eng_span_frac) 58 | -------------------------------------------------------------------------------- /aviary/subsystems/geometry/gasp_based/size_group.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.subsystems.geometry.gasp_based.electric import CableSize 4 | from aviary.subsystems.geometry.gasp_based.empennage import EmpennageSize 5 | from aviary.subsystems.geometry.gasp_based.engine import EngineSize 6 | from aviary.subsystems.geometry.gasp_based.fuselage import FuselageGroup 7 | from aviary.subsystems.geometry.gasp_based.wing import WingGroup 8 | from aviary.variable_info.functions import add_aviary_option 9 | from aviary.variable_info.variables import Aircraft 10 | 11 | 12 | class SizeGroup(om.Group): 13 | """Group to pull together all the different components and subgroups of the SIZE subroutine.""" 14 | 15 | def initialize(self): 16 | add_aviary_option(self, Aircraft.Electrical.HAS_HYBRID_SYSTEM) 17 | 18 | def setup(self): 19 | self.add_subsystem( 20 | 'fuselage', 21 | FuselageGroup(), 22 | promotes_inputs=['aircraft:*'], 23 | promotes_outputs=['aircraft:*'], 24 | ) 25 | 26 | self.add_subsystem( 27 | 'wing', 28 | WingGroup(), 29 | promotes=['aircraft:*', 'mission:*'], 30 | ) 31 | 32 | self.add_subsystem( 33 | 'empennage', 34 | EmpennageSize(), 35 | promotes=['aircraft:*'], 36 | ) 37 | 38 | self.add_subsystem( 39 | 'engine', 40 | EngineSize(), 41 | promotes_inputs=['aircraft:*'], 42 | promotes_outputs=['aircraft:*'], 43 | ) 44 | 45 | if self.options[Aircraft.Electrical.HAS_HYBRID_SYSTEM]: 46 | self.add_subsystem( 47 | 'cable', 48 | CableSize(), 49 | promotes_inputs=['aircraft:*'], 50 | promotes_outputs=['aircraft:*'], 51 | ) 52 | 53 | self.set_input_defaults(Aircraft.Fuselage.AVG_DIAMETER, units='inch') 54 | -------------------------------------------------------------------------------- /aviary/subsystems/geometry/gasp_based/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/geometry/gasp_based/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/geometry/gasp_based/test/test_strut.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal 5 | 6 | from aviary.subsystems.geometry.gasp_based.strut import StrutGeom 7 | from aviary.variable_info.variables import Aircraft 8 | 9 | 10 | class SizeGroupTestCase1(unittest.TestCase): 11 | def setUp(self): 12 | self.prob = om.Problem() 13 | self.prob.model.add_subsystem('strut', StrutGeom(), promotes=['*']) 14 | 15 | self.prob.model.set_input_defaults( 16 | Aircraft.Strut.AREA_RATIO, val=0.2, units=None 17 | ) # not actual GASP value 18 | self.prob.model.set_input_defaults( 19 | Aircraft.Wing.AREA, val=150, units='ft**2' 20 | ) # not actual GASP value 21 | self.prob.model.set_input_defaults( 22 | Aircraft.Strut.ATTACHMENT_LOCATION, val=1.0 23 | ) # not actual GASP value 24 | self.prob.model.set_input_defaults( 25 | Aircraft.Fuselage.AVG_DIAMETER, val=10.0, units='ft' 26 | ) # not actual GASP value 27 | 28 | self.prob.setup(check=False, force_alloc_complex=True) 29 | 30 | def test_case1(self): 31 | self.prob.run_model() 32 | 33 | tol = 1e-4 34 | assert_near_equal(self.prob['strut_y'], 0.5, tol) # not actual GASP value 35 | assert_near_equal( 36 | self.prob[Aircraft.Strut.LENGTH], 10.9658561, tol 37 | ) # not actual GASP value 38 | assert_near_equal(self.prob[Aircraft.Strut.CHORD], 1.36788226, tol) # not actual GASP value 39 | 40 | partial_data = self.prob.check_partials(out_stream=None, method='cs') 41 | assert_check_partials(partial_data, atol=1e-8, rtol=1e-8) 42 | 43 | 44 | if __name__ == '__main__': 45 | unittest.main() 46 | -------------------------------------------------------------------------------- /aviary/subsystems/mass/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/mass/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/mass/flops_based/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/mass/flops_based/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/mass/flops_based/apu.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.constants import GRAV_ENGLISH_LBM 4 | from aviary.variable_info.functions import add_aviary_input, add_aviary_option, add_aviary_output 5 | from aviary.variable_info.variables import Aircraft 6 | 7 | 8 | class TransportAPUMass(om.ExplicitComponent): 9 | """ 10 | Calculates the mass of the auxiliary power unit. The methodology is based 11 | on the FLOPS weight equations, modified to output mass instead of weight. 12 | """ 13 | 14 | def initialize(self): 15 | add_aviary_option(self, Aircraft.CrewPayload.Design.NUM_PASSENGERS) 16 | 17 | def setup(self): 18 | add_aviary_input(self, Aircraft.APU.MASS_SCALER, units='unitless') 19 | add_aviary_input(self, Aircraft.Fuselage.PLANFORM_AREA, units='ft**2') 20 | 21 | add_aviary_output(self, Aircraft.APU.MASS, units='lbm') 22 | 23 | def setup_partials(self): 24 | self.declare_partials('*', '*') 25 | 26 | def compute(self, inputs, outputs): 27 | pax = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] 28 | scaler = inputs[Aircraft.APU.MASS_SCALER] 29 | planform = inputs[Aircraft.Fuselage.PLANFORM_AREA] 30 | 31 | outputs[Aircraft.APU.MASS] = ( 32 | (54.0 * planform**0.3 + 5.4 * pax**0.9) * scaler / GRAV_ENGLISH_LBM 33 | ) 34 | 35 | def compute_partials(self, inputs, J): 36 | pax = self.options[Aircraft.CrewPayload.Design.NUM_PASSENGERS] 37 | scaler = inputs[Aircraft.APU.MASS_SCALER] 38 | planform = inputs[Aircraft.Fuselage.PLANFORM_AREA] 39 | 40 | J[Aircraft.APU.MASS, Aircraft.APU.MASS_SCALER] = ( 41 | 54.0 * planform**0.3 + 5.4 * pax**0.9 42 | ) / GRAV_ENGLISH_LBM 43 | J[Aircraft.APU.MASS, Aircraft.Fuselage.PLANFORM_AREA] = ( 44 | 16.2 * planform**-0.7 * scaler / GRAV_ENGLISH_LBM 45 | ) 46 | -------------------------------------------------------------------------------- /aviary/subsystems/mass/flops_based/empty_margin.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.variable_info.functions import add_aviary_input, add_aviary_output 4 | from aviary.variable_info.variables import Aircraft 5 | 6 | 7 | class EmptyMassMargin(om.ExplicitComponent): 8 | """Calculates the empty mass margin.""" 9 | 10 | def setup(self): 11 | add_aviary_input(self, Aircraft.Propulsion.MASS, units='lbm') 12 | add_aviary_input(self, Aircraft.Design.STRUCTURE_MASS, units='lbm') 13 | add_aviary_input(self, Aircraft.Design.SYSTEMS_EQUIP_MASS, units='lbm') 14 | add_aviary_input(self, Aircraft.Design.EMPTY_MASS_MARGIN_SCALER, units='unitless') 15 | 16 | add_aviary_output(self, Aircraft.Design.EMPTY_MASS_MARGIN, units='lbm') 17 | 18 | def setup_partials(self): 19 | self.declare_partials('*', '*') 20 | 21 | def compute(self, inputs, outputs): 22 | prop_mass = inputs[Aircraft.Propulsion.MASS] 23 | struct_mass = inputs[Aircraft.Design.STRUCTURE_MASS] 24 | sys_eq_mass = inputs[Aircraft.Design.SYSTEMS_EQUIP_MASS] 25 | scaler = inputs[Aircraft.Design.EMPTY_MASS_MARGIN_SCALER] 26 | 27 | outputs[Aircraft.Design.EMPTY_MASS_MARGIN] = ( 28 | prop_mass + struct_mass + sys_eq_mass 29 | ) * scaler 30 | 31 | def compute_partials(self, inputs, J): 32 | prop_mass = inputs[Aircraft.Propulsion.MASS] 33 | struct_mass = inputs[Aircraft.Design.STRUCTURE_MASS] 34 | sys_eq_mass = inputs[Aircraft.Design.SYSTEMS_EQUIP_MASS] 35 | scaler = inputs[Aircraft.Design.EMPTY_MASS_MARGIN_SCALER] 36 | 37 | J[Aircraft.Design.EMPTY_MASS_MARGIN, Aircraft.Propulsion.MASS] = scaler 38 | J[Aircraft.Design.EMPTY_MASS_MARGIN, Aircraft.Design.STRUCTURE_MASS] = scaler 39 | J[Aircraft.Design.EMPTY_MASS_MARGIN, Aircraft.Design.SYSTEMS_EQUIP_MASS] = scaler 40 | J[Aircraft.Design.EMPTY_MASS_MARGIN, Aircraft.Design.EMPTY_MASS_MARGIN_SCALER] = ( 41 | prop_mass + struct_mass + sys_eq_mass 42 | ) 43 | -------------------------------------------------------------------------------- /aviary/subsystems/mass/flops_based/landing_group.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.subsystems.mass.flops_based.landing_gear import ( 4 | AltLandingGearMass, 5 | LandingGearMass, 6 | MainGearLength, 7 | NoseGearLength, 8 | ) 9 | from aviary.subsystems.mass.flops_based.landing_mass import LandingMass, LandingTakeoffMassRatio 10 | from aviary.variable_info.functions import add_aviary_option 11 | from aviary.variable_info.variables import Aircraft 12 | 13 | 14 | class LandingMassGroup(om.Group): 15 | """ 16 | Group of landing-related components for FLOPS-based mass: 17 | LandingTakeoffMassRatio, MainGearLength, NoseGearLength, LandingMass, etc. 18 | """ 19 | 20 | def initialize(self): 21 | add_aviary_option(self, Aircraft.Design.USE_ALT_MASS) 22 | 23 | def setup(self): 24 | alt_mass = self.options[Aircraft.Design.USE_ALT_MASS] 25 | 26 | self.add_subsystem( 27 | 'landing_to_takeoff_mass_ratio', 28 | LandingTakeoffMassRatio(), 29 | promotes_inputs=['*'], 30 | promotes_outputs=['*'], 31 | ) 32 | 33 | self.add_subsystem( 34 | 'main_landing_gear_length', 35 | MainGearLength(), 36 | promotes_inputs=['*'], 37 | promotes_outputs=['*'], 38 | ) 39 | 40 | self.add_subsystem( 41 | 'nose_landing_gear_length', 42 | NoseGearLength(), 43 | promotes_inputs=['*'], 44 | promotes_outputs=['*'], 45 | ) 46 | 47 | self.add_subsystem( 48 | 'landing_mass', LandingMass(), promotes_inputs=['*'], promotes_outputs=['*'] 49 | ) 50 | 51 | if alt_mass: 52 | self.add_subsystem( 53 | 'landing_gear', AltLandingGearMass(), promotes_inputs=['*'], promotes_outputs=['*'] 54 | ) 55 | else: 56 | self.add_subsystem( 57 | 'landing_gear', LandingGearMass(), promotes_inputs=['*'], promotes_outputs=['*'] 58 | ) 59 | -------------------------------------------------------------------------------- /aviary/subsystems/mass/flops_based/paint.py: -------------------------------------------------------------------------------- 1 | import openmdao.api as om 2 | 3 | from aviary.variable_info.functions import add_aviary_input, add_aviary_output 4 | from aviary.variable_info.variables import Aircraft 5 | 6 | 7 | class PaintMass(om.ExplicitComponent): 8 | """Calculates the mass of paint based on total wetted area.""" 9 | 10 | def setup(self): 11 | add_aviary_input(self, Aircraft.Design.TOTAL_WETTED_AREA, units='ft**2') 12 | add_aviary_input(self, Aircraft.Paint.MASS_PER_UNIT_AREA, units='lbm/ft**2') 13 | 14 | add_aviary_output(self, Aircraft.Paint.MASS, units='lbm') 15 | 16 | def setup_partials(self): 17 | self.declare_partials('*', '*') 18 | 19 | def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): 20 | wetted_area = inputs[Aircraft.Design.TOTAL_WETTED_AREA] 21 | mass_per_area = inputs[Aircraft.Paint.MASS_PER_UNIT_AREA] 22 | 23 | outputs[Aircraft.Paint.MASS] = wetted_area * mass_per_area 24 | 25 | def compute_partials(self, inputs, J): 26 | wetted_area = inputs[Aircraft.Design.TOTAL_WETTED_AREA] 27 | mass_per_area = inputs[Aircraft.Paint.MASS_PER_UNIT_AREA] 28 | 29 | J[Aircraft.Paint.MASS, Aircraft.Design.TOTAL_WETTED_AREA] = mass_per_area 30 | 31 | J[Aircraft.Paint.MASS, Aircraft.Paint.MASS_PER_UNIT_AREA] = wetted_area 32 | -------------------------------------------------------------------------------- /aviary/subsystems/mass/flops_based/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/mass/flops_based/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/mass/flops_based/test/test_empty_margin.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | from parameterized import parameterized 5 | 6 | from aviary.subsystems.mass.flops_based.empty_margin import EmptyMassMargin 7 | from aviary.utils.test_utils.variable_test import assert_match_varnames 8 | from aviary.validation_cases.validation_tests import ( 9 | flops_validation_test, 10 | get_flops_case_names, 11 | get_flops_options, 12 | print_case, 13 | ) 14 | from aviary.variable_info.variables import Aircraft 15 | 16 | 17 | class EmptyMassMarginTest(unittest.TestCase): 18 | def setUp(self): 19 | self.prob = om.Problem() 20 | 21 | @parameterized.expand(get_flops_case_names(), name_func=print_case) 22 | def test_case(self, case_name): 23 | prob = self.prob 24 | 25 | prob.model.add_subsystem( 26 | 'margin', 27 | EmptyMassMargin(), 28 | promotes_inputs=['*'], 29 | promotes_outputs=['*'], 30 | ) 31 | 32 | prob.model_options['*'] = get_flops_options(case_name, preprocess=True) 33 | 34 | prob.setup(check=False, force_alloc_complex=True) 35 | 36 | flops_validation_test( 37 | prob, 38 | case_name, 39 | input_keys=[ 40 | Aircraft.Propulsion.MASS, 41 | Aircraft.Design.STRUCTURE_MASS, 42 | Aircraft.Design.SYSTEMS_EQUIP_MASS, 43 | Aircraft.Design.EMPTY_MASS_MARGIN_SCALER, 44 | ], 45 | output_keys=Aircraft.Design.EMPTY_MASS_MARGIN, 46 | tol=1e-3, 47 | atol=2e-11, 48 | ) 49 | 50 | def test_IO(self): 51 | assert_match_varnames(self.prob.model) 52 | 53 | 54 | if __name__ == '__main__': 55 | unittest.main() 56 | -------------------------------------------------------------------------------- /aviary/subsystems/mass/flops_based/test/test_landing_mass.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | from parameterized import parameterized 5 | 6 | from aviary.subsystems.mass.flops_based.landing_mass import LandingMass 7 | from aviary.utils.test_utils.variable_test import assert_match_varnames 8 | from aviary.validation_cases.validation_tests import ( 9 | flops_validation_test, 10 | get_flops_case_names, 11 | print_case, 12 | ) 13 | from aviary.variable_info.variables import Aircraft, Mission 14 | 15 | 16 | class LandingMassTest(unittest.TestCase): 17 | def setUp(self): 18 | self.prob = om.Problem() 19 | 20 | @parameterized.expand(get_flops_case_names(omit='LargeSingleAisle1FLOPS'), name_func=print_case) 21 | def test_case(self, case_name): 22 | prob = self.prob 23 | prob.model.add_subsystem('landing_mass', LandingMass(), promotes=['*']) 24 | 25 | prob.setup(check=False, force_alloc_complex=True) 26 | 27 | flops_validation_test( 28 | prob, 29 | case_name, 30 | input_keys=[Mission.Design.GROSS_MASS, Aircraft.Design.LANDING_TO_TAKEOFF_MASS_RATIO], 31 | output_keys=Aircraft.Design.TOUCHDOWN_MASS, 32 | ) 33 | 34 | def test_IO(self): 35 | assert_match_varnames(self.prob.model) 36 | 37 | 38 | if __name__ == '__main__': 39 | unittest.main() 40 | -------------------------------------------------------------------------------- /aviary/subsystems/mass/flops_based/test/test_paint.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | from parameterized import parameterized 5 | 6 | from aviary.subsystems.mass.flops_based.paint import PaintMass 7 | from aviary.utils.test_utils.variable_test import assert_match_varnames 8 | from aviary.validation_cases.validation_tests import ( 9 | flops_validation_test, 10 | get_flops_case_names, 11 | print_case, 12 | ) 13 | from aviary.variable_info.variables import Aircraft 14 | 15 | 16 | class PaintMassTest(unittest.TestCase): 17 | def setUp(self): 18 | self.prob = om.Problem() 19 | 20 | @parameterized.expand(get_flops_case_names(), name_func=print_case) 21 | def test_case(self, case_name): 22 | prob = self.prob 23 | 24 | prob.model.add_subsystem( 25 | 'paint', 26 | PaintMass(), 27 | promotes_inputs=['*'], 28 | promotes_outputs=['*'], 29 | ) 30 | 31 | prob.setup(check=False, force_alloc_complex=True) 32 | 33 | flops_validation_test( 34 | prob, 35 | case_name, 36 | input_keys=[Aircraft.Design.TOTAL_WETTED_AREA, Aircraft.Paint.MASS_PER_UNIT_AREA], 37 | output_keys=Aircraft.Paint.MASS, 38 | ) 39 | 40 | def test_IO(self): 41 | assert_match_varnames(self.prob.model) 42 | 43 | 44 | if __name__ == '__main__': 45 | unittest.main() 46 | -------------------------------------------------------------------------------- /aviary/subsystems/mass/gasp_based/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/mass/gasp_based/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/mass/gasp_based/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/mass/gasp_based/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/mass/mass_to_weight.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import openmdao.api as om 3 | 4 | from aviary.constants import GRAV_ENGLISH_LBM 5 | 6 | 7 | class MassToWeight(om.ExplicitComponent): 8 | """Component to convert mass to weight.""" 9 | 10 | def initialize(self): 11 | self.options.declare('num_nodes', types=int, default=1) 12 | 13 | def setup(self): 14 | nn = self.options['num_nodes'] 15 | 16 | self.add_input( 17 | 'mass', 18 | val=np.ones(nn), 19 | units='lbm', 20 | desc='mass of the aircraft', 21 | ) 22 | 23 | self.add_output( 24 | 'weight', 25 | val=np.ones(nn), 26 | units='lbf', 27 | desc='weight of the aircraft', 28 | ) 29 | 30 | def setup_partials(self): 31 | nn = self.options['num_nodes'] 32 | arange = np.arange(nn) 33 | self.declare_partials( 34 | 'weight', 'mass', rows=arange, cols=arange, val=np.full(nn, GRAV_ENGLISH_LBM) 35 | ) 36 | 37 | def compute(self, inputs, outputs): 38 | outputs['weight'] = inputs['mass'] * GRAV_ENGLISH_LBM 39 | -------------------------------------------------------------------------------- /aviary/subsystems/mass/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/mass/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/mass/test/test_flops_mass_builder.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import numpy as np 4 | 5 | import aviary.api as av 6 | from aviary.subsystems.mass.mass_builder import CoreMassBuilder 7 | from aviary.variable_info.enums import LegacyCode 8 | from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData 9 | from aviary.variable_info.variables import Aircraft 10 | 11 | FLOPS = LegacyCode.FLOPS 12 | 13 | 14 | class TestFLOPSMassBuilder(av.TestSubsystemBuilderBase): 15 | """ 16 | That class inherits from TestSubsystemBuilder. So all the test functions are 17 | within that inherited class. The setUp() method prepares the class and is run 18 | before the test methods; then the test methods are run. 19 | """ 20 | 21 | def setUp(self): 22 | self.subsystem_builder = CoreMassBuilder( 23 | 'test_core_mass', meta_data=BaseMetaData, code_origin=FLOPS 24 | ) 25 | self.aviary_values = av.AviaryValues() 26 | self.aviary_values.set_val(Aircraft.Design.USE_ALT_MASS, False, units='unitless') 27 | self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, np.array([1]), units='unitless') 28 | self.aviary_values.set_val( 29 | Aircraft.Engine.NUM_WING_ENGINES, np.array([2]), units='unitless' 30 | ) 31 | 32 | 33 | class TestFLOPSMassBuilderAltMass(av.TestSubsystemBuilderBase): 34 | """ 35 | That class inherits from TestSubsystemBuilder. So all the test functions are 36 | within that inherited class. The setUp() method prepares the class and is run 37 | before the test methods; then the test methods are run. 38 | """ 39 | 40 | def setUp(self): 41 | self.subsystem_builder = CoreMassBuilder( 42 | 'test_core_mass', meta_data=BaseMetaData, code_origin=FLOPS 43 | ) 44 | self.aviary_values = av.AviaryValues() 45 | self.aviary_values.set_val(Aircraft.Design.USE_ALT_MASS, True, units='unitless') 46 | self.aviary_values.set_val(Aircraft.Engine.NUM_ENGINES, np.array([1]), units='unitless') 47 | self.aviary_values.set_val( 48 | Aircraft.Engine.NUM_WING_ENGINES, np.array([2]), units='unitless' 49 | ) 50 | 51 | 52 | if __name__ == '__main__': 53 | unittest.main() 54 | -------------------------------------------------------------------------------- /aviary/subsystems/propulsion/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/propulsion/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/propulsion/gearbox/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/propulsion/gearbox/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/propulsion/gearbox/model/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/propulsion/gearbox/model/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/propulsion/gearbox/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/propulsion/gearbox/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/propulsion/motor/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/propulsion/motor/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/propulsion/motor/model/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/propulsion/motor/model/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/propulsion/motor/test/test_motor_map.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import numpy as np 4 | import openmdao.api as om 5 | from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal 6 | from openmdao.utils.testing_utils import use_tempdirs 7 | 8 | from aviary.subsystems.propulsion.motor.model.motor_map import MotorMap 9 | from aviary.variable_info.variables import Aircraft, Dynamic 10 | 11 | 12 | class TestGearbox(unittest.TestCase): 13 | @use_tempdirs 14 | def test_motor_map(self): 15 | nn = 3 16 | 17 | prob = om.Problem() 18 | 19 | prob.model.add_subsystem('motor_map', MotorMap(num_nodes=3), promotes=['*']) 20 | 21 | prob.setup(force_alloc_complex=True) 22 | 23 | prob.set_val(Dynamic.Vehicle.Propulsion.THROTTLE, np.linspace(0, 1, nn)) 24 | prob.set_val(Dynamic.Vehicle.Propulsion.RPM, np.linspace(0, 6000, nn)) 25 | prob.set_val(Aircraft.Engine.SCALE_FACTOR, 1.12) 26 | 27 | prob.run_model() 28 | 29 | torque = prob.get_val(Dynamic.Vehicle.Propulsion.TORQUE) 30 | efficiency = prob.get_val('motor_efficiency') 31 | 32 | torque_expected = np.array([0.0, 900.0, 1800.0]) * 1.12 33 | eff_expected = [0.871, 0.958625, 0.954] 34 | assert_near_equal(torque, torque_expected, tolerance=1e-9) 35 | assert_near_equal(efficiency, eff_expected, tolerance=1e-9) 36 | 37 | partial_data = prob.check_partials(out_stream=None, method='cs') 38 | assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) 39 | 40 | 41 | if __name__ == '__main__': 42 | unittest.main() 43 | -------------------------------------------------------------------------------- /aviary/subsystems/propulsion/motor/test/test_motor_premission.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import openmdao.api as om 4 | from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal 5 | from openmdao.utils.testing_utils import use_tempdirs 6 | 7 | from aviary.subsystems.propulsion.motor.model.motor_premission import MotorPreMission 8 | from aviary.utils.aviary_values import AviaryValues 9 | from aviary.variable_info.variables import Aircraft 10 | 11 | 12 | class TestGearbox(unittest.TestCase): 13 | @use_tempdirs 14 | def test_motor_map(self): 15 | prob = om.Problem() 16 | options = AviaryValues() 17 | options.set_val(Aircraft.Engine.RPM_DESIGN, 6000, 'rpm') 18 | 19 | prob.model.add_subsystem( 20 | 'motor_map', MotorPreMission(aviary_inputs=options), promotes=['*'] 21 | ) 22 | 23 | prob.setup(force_alloc_complex=True) 24 | 25 | prob.set_val(Aircraft.Engine.SCALE_FACTOR, 1.12) 26 | 27 | prob.run_model() 28 | 29 | torque_max = prob.get_val(Aircraft.Engine.Motor.TORQUE_MAX, 'N*m') 30 | mass = prob.get_val(Aircraft.Engine.Motor.MASS, 'kg') 31 | 32 | torque_max_expected = 2016 33 | mass_expected = 93.36999121578062 34 | 35 | assert_near_equal(torque_max, torque_max_expected, tolerance=1e-9) 36 | assert_near_equal(mass, mass_expected, tolerance=1e-9) 37 | 38 | partial_data = prob.check_partials(out_stream=None, method='cs') 39 | assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) 40 | 41 | 42 | if __name__ == '__main__': 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /aviary/subsystems/propulsion/propeller/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/propulsion/propeller/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/propulsion/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/propulsion/test/__init__.py -------------------------------------------------------------------------------- /aviary/subsystems/propulsion/test/test_throttle_allocation.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import numpy as np 4 | import openmdao.api as om 5 | from openmdao.utils.assert_utils import assert_check_partials 6 | 7 | from aviary.subsystems.propulsion.throttle_allocation import ThrottleAllocator 8 | from aviary.variable_info.enums import ThrottleAllocation 9 | from aviary.variable_info.variables import Aircraft 10 | 11 | 12 | class ThrottleAllocationTest(unittest.TestCase): 13 | def setUp(self): 14 | self.options = { 15 | Aircraft.Engine.NUM_ENGINES: np.array([1, 1, 1]), 16 | } 17 | 18 | def test_derivs_fixed_or_static(self): 19 | prob = om.Problem() 20 | model = prob.model 21 | model.add_subsystem( 22 | 'comp', 23 | ThrottleAllocator( 24 | num_nodes=4, throttle_allocation=ThrottleAllocation.FIXED, **self.options 25 | ), 26 | promotes=['*'], 27 | ) 28 | 29 | prob.setup(force_alloc_complex=True) 30 | 31 | prob.set_val('throttle_allocations', val=np.array([0.24, 0.55])) 32 | prob.set_val('aggregate_throttle', val=np.array([0.3, 0.41, 0.52, 0.64])) 33 | prob.run_model() 34 | 35 | partials = prob.check_partials(method='cs', out_stream=None) 36 | assert_check_partials(partials, atol=1e-10, rtol=1e-10) 37 | 38 | def test_derivs_dynamic(self): 39 | prob = om.Problem() 40 | model = prob.model 41 | model.add_subsystem( 42 | 'comp', 43 | ThrottleAllocator( 44 | num_nodes=4, throttle_allocation=ThrottleAllocation.DYNAMIC, **self.options 45 | ), 46 | promotes=['*'], 47 | ) 48 | 49 | prob.setup(force_alloc_complex=True) 50 | 51 | prob.set_val( 52 | 'throttle_allocations', val=np.array([0.24, 0.55, 0.33, 0.33, 0.6, 0.1, 0.1, 0.6]) 53 | ) 54 | prob.set_val('aggregate_throttle', val=np.array([0.3, 0.41, 0.52, 0.64])) 55 | prob.run_model() 56 | 57 | partials = prob.check_partials(method='cs', out_stream=None) 58 | assert_check_partials(partials, atol=1e-10, rtol=1e-10) 59 | 60 | 61 | if __name__ == '__main__': 62 | unittest.main() 63 | -------------------------------------------------------------------------------- /aviary/subsystems/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/subsystems/test/__init__.py -------------------------------------------------------------------------------- /aviary/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/utils/__init__.py -------------------------------------------------------------------------------- /aviary/utils/conflict_checks.py: -------------------------------------------------------------------------------- 1 | def check_fold_location_definition(choose_fold_location, has_strut): 2 | """If there is no strut, then CHOOSE_FOLD_LOCATION must be true.""" 3 | if not choose_fold_location and not has_strut: 4 | raise RuntimeError( 5 | 'The option CHOOSE_FOLD_LOCATION can only be False if the option HAS_STRUT is True.' 6 | ) 7 | 8 | 9 | # Possible TODO 10 | # Aircraft.Design.ULF_CALCULATED_FROM_MANEUVER - Aircraft.Design.PART25_STRUCTURAL_CATEGORY 11 | # Aircraft.Engine.FUSELAGE_MOUNTED - Aircraft.Engine.WING_LOCATIONS 12 | # Aircraft.Engine.NUM_ENGINES - Aircraft.Engine.NUM_FUSELAGE_ENGINES - Aircraft.Engine.NUM_WING_ENGINES 13 | # Aircraft.Propulsion.TOTAL_NUM_ENGINES - Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES - Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES 14 | # Aircraft.Engine.TYPE - Aircraft.Engine.HAS_PROPELLERS 15 | # Aircraft.Design.COMPUTE_TAIL_VOLUME_COEFFS 16 | # Aircraft.Engine.REFERENCE_WEIGHT 17 | # Mission.Taxi.MACH - pycycle 18 | # Aircraft.HorizontalTail.AREA 19 | # Aircraft.VerticalTail.AREA 20 | # Aircraft.Strut.DIMENSIONAL_LOCATION_SPECIFIED 21 | # Aircraft.Wing.FOLD_LOCATION_IS_DIMENSIONAL 22 | # Aircraft.Wing.HAS_FOLD 23 | -------------------------------------------------------------------------------- /aviary/utils/legacy_code_data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/utils/legacy_code_data/__init__.py -------------------------------------------------------------------------------- /aviary/utils/legacy_code_data/flops_defaults.py: -------------------------------------------------------------------------------- 1 | from aviary.utils.named_values import NamedValues 2 | 3 | ## Defaults ## 4 | flops_default_values = NamedValues( 5 | { 6 | 'WTIN.EEXP': (1.15, 'unitless'), 7 | 'WTIN.IALTWT': (False, 'unitless'), 8 | 'WTIN.CARGF': (False, 'unitless'), 9 | 'ENGDIN.IDLE': (False, 'unitless'), 10 | 'ENGDIN.IGEO': (False, 'unitless'), 11 | 'ENGDIN.NONEG': (False, 'unitless'), 12 | 'AERIN.MIKE': (False, 'unitless'), 13 | 'AERIN.SWETF': (1, 'unitless'), 14 | 'AERIN.SWETV': (1, 'unitless'), 15 | } 16 | ) 17 | 18 | ## Depreciated Variables ## 19 | flops_deprecated_vars = [ 20 | 'AERIN.MODARO', 21 | 'ENGDIN.IGENEN', 22 | 'ENGDIN.BOOST', 23 | 'ENGDIN.EXTFAC', 24 | 'ENGDIN.IXTRAP', 25 | 'ENGDIN.NPCODE', 26 | 'ENGDIN.PCODE', 27 | 'ENGDIN.NOX', 28 | 'OPTION.IOPT', 29 | 'OPTION.IPOLP', 30 | 'OPTION.NOISE', 31 | 'WTIN.CARBAS', 32 | ] 33 | -------------------------------------------------------------------------------- /aviary/utils/options.py: -------------------------------------------------------------------------------- 1 | from openmdao.core.system import System 2 | 3 | from aviary.utils.aviary_values import AviaryValues, get_keys 4 | 5 | 6 | def list_options(model: System, aviary_keys: list = None): 7 | """ 8 | Lists all option values in the provided model. All top-level option values will 9 | be listed, and items in model.options['aviary_options'] will also be listed. 10 | A list of keys may be provided to limit the list of items in aviary_options. 11 | 12 | Parameters 13 | ---------- 14 | model : System 15 | A model. 16 | aviary_keys: iter of str 17 | List of aviary_options keys whose values will be looked up and 18 | listed in the options printout. If None, all items in 19 | model.options['aviary_options'] will be listed. 20 | """ 21 | print('\nOptions:\n') 22 | for subsystem in model.system_iter(): 23 | if subsystem.name == '_auto_ivc': 24 | continue 25 | print(subsystem.name) 26 | for key, obj in subsystem.options.items(): 27 | if isinstance(obj, AviaryValues): 28 | aviary_options = obj 29 | print(' aviary_options:') 30 | if isinstance(aviary_keys, list): 31 | keys = aviary_keys 32 | else: 33 | keys = get_keys(aviary_options) 34 | for key in keys: 35 | (val, units) = aviary_options.get_item(key) 36 | if units == 'unitless': 37 | print(f' {key} = {val}') 38 | else: 39 | print(f' {key} = {val} {units}') 40 | else: 41 | print(f' {key} = {str(obj)[0:80]}') 42 | print() 43 | -------------------------------------------------------------------------------- /aviary/utils/test/data/csv_test.csv: -------------------------------------------------------------------------------- 1 | # comment 1 2 | 3 | #comment 2# more comment 2 4 | aircraft:wing:span (ft), aircraft:crew_and_payload:num_passengers, fake_var (lbm) 5 | 15.24, 125, 0.932 6 | 118, 28, 1023.54 #inline comment 7 | 8 | 90,.355, 0, 9 | 171, 44,-13 10 | -------------------------------------------------------------------------------- /aviary/utils/test/test_process_input_decks.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from openmdao.utils.testing_utils import use_tempdirs 4 | 5 | from aviary.utils.functions import get_path 6 | from aviary.utils.process_input_decks import create_vehicle 7 | 8 | 9 | @use_tempdirs 10 | class TestCreateVehicle(unittest.TestCase): 11 | """Test creation and modification of aircraft from CSV file.""" 12 | 13 | def test_load_aircraft_csv(self): 14 | # Test loading a standard aircraft CSV file. 15 | file_path = 'models/test_aircraft/aircraft_for_bench_FwFm.csv' 16 | aircraft_values, initialization_guesses = create_vehicle(get_path(file_path)) 17 | self.assertIsNotNone(aircraft_values) 18 | self.assertIsNotNone(initialization_guesses) 19 | 20 | def test_load_modified_aircraft_csv(self): 21 | # Test loading a modified aircraft CSV file with an additional blank line. 22 | original_file_path = 'models/test_aircraft/aircraft_for_bench_FwFm.csv' 23 | modified_file_path = 'modified_aircraft.csv' 24 | 25 | # Copy and modify the original CSV 26 | with ( 27 | open(get_path(original_file_path), 'r') as original_file, 28 | open(modified_file_path, 'w') as modified_file, 29 | ): 30 | content = original_file.readlines() 31 | half_way_point = len(content) // 2 32 | 33 | # Write first half of the file 34 | modified_file.writelines(content[:half_way_point]) 35 | 36 | # Insert a few blank lines 37 | modified_file.write(',,,,\n') 38 | 39 | # Write second half of the file 40 | modified_file.writelines(content[half_way_point:]) 41 | 42 | # Test create_vehicle with the modified file 43 | aircraft_values, initialization_guesses = create_vehicle(modified_file_path) 44 | self.assertIsNotNone(aircraft_values) 45 | self.assertIsNotNone(initialization_guesses) 46 | 47 | 48 | if __name__ == '__main__': 49 | unittest.main() 50 | -------------------------------------------------------------------------------- /aviary/utils/test_utils/IO_test_util.py: -------------------------------------------------------------------------------- 1 | from openmdao.utils.assert_utils import assert_near_equal 2 | 3 | 4 | def check_prob_outputs(prob, vals, rtol=1e-6): 5 | """Check multiple problem outputs and print all failures. 6 | 7 | testflo doesn't handle unittest subTests, so this is a way to get all the 8 | failures at once without needing to iteratively fix and re-run. It also prints the 9 | variable path so you can more easily tell which assertions failed. 10 | 11 | Parameters 12 | ---------- 13 | prob : Problem 14 | Problem instance to check. Should have already been run. 15 | vals : dict 16 | Dictionary mapping variable paths (i.e. ``prob[path]`` should work) to the 17 | value(s) to check against. 18 | rtol : float or list, optional 19 | Maximum relative tolerance to pass the test. If given as a list, it should match 20 | the number of entries in `vals`. 21 | """ 22 | if isinstance(rtol, float): 23 | rtol = len(vals) * [rtol] 24 | 25 | errors = [] 26 | for (path, val), t in zip(vals.items(), rtol): 27 | try: 28 | assert_near_equal(prob[path], val, tolerance=t) 29 | except ValueError as e: 30 | errors.append(f'\n {path}: {e}') 31 | 32 | if errors: 33 | raise ValueError(''.join(errors)) 34 | -------------------------------------------------------------------------------- /aviary/utils/test_utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/utils/test_utils/__init__.py -------------------------------------------------------------------------------- /aviary/utils/test_utils/assert_utils.py: -------------------------------------------------------------------------------- 1 | """Utilities used for testing Aviary code.""" 2 | 3 | from dymos.utils.testing_utils import assert_timeseries_near_equal 4 | 5 | 6 | def warn_timeseries_near_equal( 7 | t_ref, x_ref, t_check, x_check, abs_tolerance=None, rel_tolerance=None 8 | ): 9 | """Wraps timeseries check with a try block that prints a warning if the assert fails.""" 10 | try: 11 | assert_timeseries_near_equal( 12 | t_ref, x_ref, t_check, x_check, abs_tolerance=abs_tolerance, rel_tolerance=rel_tolerance 13 | ) 14 | except AssertionError as exc: 15 | print('Warning:\n', str(exc)) 16 | -------------------------------------------------------------------------------- /aviary/utils/test_utils/default_subsystems.py: -------------------------------------------------------------------------------- 1 | from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder 2 | from aviary.subsystems.geometry.geometry_builder import CoreGeometryBuilder 3 | from aviary.subsystems.mass.mass_builder import CoreMassBuilder 4 | from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder 5 | from aviary.variable_info.enums import LegacyCode 6 | from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData 7 | 8 | 9 | def get_default_premission_subsystems(legacy_code, engines=None): 10 | """ 11 | Get default premission subsystems propulsion, geometry, aerodynamics, and mass 12 | in this order. 13 | 14 | Arguments: 15 | ---------- 16 | legacy_code : str, LegacyCode 17 | either FLOPS or GASP LegacyCode Enums, or their strings equivalents ('FLOPS', 'GASP') 18 | engine : 19 | List of EngineDecks 20 | """ 21 | legacy_code = LegacyCode(legacy_code) 22 | prop = CorePropulsionBuilder('core_propulsion', BaseMetaData, engine_models=engines) 23 | mass = CoreMassBuilder('core_mass', BaseMetaData, legacy_code) 24 | aero = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, legacy_code) 25 | geom = CoreGeometryBuilder('core_geometry', BaseMetaData, legacy_code) 26 | 27 | return [prop, geom, aero, mass] 28 | 29 | 30 | def get_default_mission_subsystems(legacy_code, engines=None): 31 | """ 32 | Get default mission subsystems aerodynamics and propulsion in this order. 33 | 34 | Arguments: 35 | ---------- 36 | legacy_code : str, LegacyCode 37 | either FLOPS or GASP LegacyCode Enums, or their strings equivalents ('FLOPS', 'GASP') 38 | engine : 39 | List of EngineDecks 40 | """ 41 | legacy_code = LegacyCode(legacy_code) 42 | prop = CorePropulsionBuilder('core_propulsion', BaseMetaData, engine_models=engines) 43 | aero = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, legacy_code) 44 | 45 | return [aero, prop] 46 | -------------------------------------------------------------------------------- /aviary/validation_cases/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/validation_cases/__init__.py -------------------------------------------------------------------------------- /aviary/validation_cases/benchmark_tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/validation_cases/benchmark_tests/__init__.py -------------------------------------------------------------------------------- /aviary/validation_cases/benchmark_tests/test_bench_large_turboprop_freighter.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from openmdao.utils.testing_utils import use_tempdirs 4 | 5 | from aviary.interface.methods_for_level2 import AviaryProblem 6 | from aviary.models.large_turboprop_freighter.phase_info import two_dof_phase_info 7 | from aviary.subsystems.propulsion.turboprop_model import TurbopropModel 8 | from aviary.utils.process_input_decks import create_vehicle 9 | from aviary.variable_info.variables import Aircraft, Mission 10 | 11 | 12 | @use_tempdirs 13 | # TODO need to add asserts with "truth" values, only verifying no errors here 14 | class LargeTurbopropFreighterBenchmark(unittest.TestCase): 15 | def build_and_run_problem(self): 16 | # Build problem 17 | prob = AviaryProblem(verbosity=0) 18 | 19 | # load inputs from .csv to build engine 20 | options, _ = create_vehicle( 21 | 'models/large_turboprop_freighter/large_turboprop_freighter_GASP.csv' 22 | ) 23 | 24 | turboprop = TurbopropModel('turboprop', options=options) 25 | 26 | # load_inputs needs to be updated to accept an already existing aviary options 27 | prob.load_inputs( 28 | 'models/large_turboprop_freighter/large_turboprop_freighter_GASP.csv', 29 | two_dof_phase_info, 30 | engine_builders=[turboprop], 31 | ) 32 | # FLOPS aero specific stuff? Best guesses for values here 33 | prob.aviary_inputs.set_val(Mission.Constraints.MAX_MACH, 0.5) 34 | prob.aviary_inputs.set_val(Aircraft.Fuselage.AVG_DIAMETER, 4.125, 'm') 35 | 36 | prob.check_and_preprocess_inputs() 37 | prob.add_pre_mission_systems() 38 | prob.add_phases() 39 | prob.add_post_mission_systems() 40 | prob.link_phases() 41 | prob.add_driver('IPOPT', max_iter=0, verbosity=0) 42 | prob.add_design_variables() 43 | prob.add_objective() 44 | prob.setup() 45 | # om.n2(prob) 46 | 47 | prob.set_initial_guesses() 48 | prob.run_aviary_problem('dymos_solution.db') 49 | # om.n2(prob) 50 | 51 | 52 | if __name__ == '__main__': 53 | test = LargeTurbopropFreighterBenchmark() 54 | test.build_and_run_problem() 55 | -------------------------------------------------------------------------------- /aviary/validation_cases/validation_data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/validation_cases/validation_data/__init__.py -------------------------------------------------------------------------------- /aviary/validation_cases/validation_data/flops_data/FLOPS_Test_Data.py: -------------------------------------------------------------------------------- 1 | from aviary.models.large_single_aisle_1.large_single_aisle_1_FLOPS_data import ( 2 | LargeSingleAisle1FLOPS, 3 | ) 4 | from aviary.models.large_single_aisle_2.large_single_aisle_2_altwt_FLOPS_data import ( 5 | LargeSingleAisle2FLOPSalt, 6 | ) 7 | from aviary.models.large_single_aisle_2.large_single_aisle_2_detailwing_FLOPS_data import ( 8 | LargeSingleAisle2FLOPSdw, 9 | ) 10 | from aviary.models.large_single_aisle_2.large_single_aisle_2_FLOPS_data import ( 11 | LargeSingleAisle2FLOPS, 12 | ) 13 | from aviary.models.multi_engine_single_aisle.multi_engine_single_aisle_data import ( 14 | MultiEngineSingleAisle, 15 | ) 16 | from aviary.models.N3CC.N3CC_data import N3CC 17 | 18 | FLOPS_Test_Data = {} 19 | 20 | FLOPS_Test_Data['LargeSingleAisle1FLOPS'] = LargeSingleAisle1FLOPS 21 | FLOPS_Test_Data['LargeSingleAisle2FLOPS'] = LargeSingleAisle2FLOPS 22 | FLOPS_Test_Data['LargeSingleAisle2FLOPSdw'] = LargeSingleAisle2FLOPSdw 23 | FLOPS_Test_Data['LargeSingleAisle2FLOPSalt'] = LargeSingleAisle2FLOPSalt 24 | FLOPS_Test_Data['N3CC'] = N3CC 25 | 26 | # We don't have full date for this yet, but might still want to run one in a single unit test. 27 | FLOPS_Lacking_Test_Data = {} 28 | FLOPS_Lacking_Test_Data['MultiEngineSingleAisle'] = MultiEngineSingleAisle 29 | -------------------------------------------------------------------------------- /aviary/validation_cases/validation_data/flops_data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/validation_cases/validation_data/flops_data/__init__.py -------------------------------------------------------------------------------- /aviary/variable_info/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/variable_info/__init__.py -------------------------------------------------------------------------------- /aviary/variable_info/options.py: -------------------------------------------------------------------------------- 1 | from aviary.subsystems.propulsion.engine_deck import EngineDeck 2 | from aviary.utils.aviary_values import AviaryValues 3 | from aviary.utils.functions import get_path 4 | from aviary.utils.preprocessors import preprocess_propulsion 5 | from aviary.variable_info.variable_meta_data import _MetaData 6 | from aviary.variable_info.variables import Aircraft 7 | 8 | 9 | def get_option_defaults(engine=True, meta_data=_MetaData) -> AviaryValues: 10 | """ 11 | Returns a deep copy of the collection of all options for which default values exist. 12 | 13 | Parameters 14 | ---------- 15 | engine : bool 16 | If true, the collection includes the default engine model 17 | meta_data : dict 18 | Dictionary containing metadata for the options. If None, Aviary's built-in 19 | metadata will be used. 20 | """ 21 | option_defaults = AviaryValues() 22 | 23 | # Load all variables marked as options in the MetaData 24 | for key in meta_data: 25 | var = meta_data[key] 26 | if var['option'] and var['default_value'] is not None: 27 | option_defaults.set_val(key, var['default_value'], var['units']) 28 | 29 | if engine: 30 | engine_options = option_defaults.deepcopy() 31 | engine_options.set_val( 32 | Aircraft.Engine.DATA_FILE, get_path('models/engines/turbofan_23k_1.deck') 33 | ) 34 | engine_options.set_val(Aircraft.Engine.REFERENCE_SLS_THRUST, 28690, 'lbf') 35 | engine_deck = EngineDeck(options=engine_options) 36 | preprocess_propulsion(option_defaults, [engine_deck]) 37 | 38 | return option_defaults 39 | 40 | 41 | def is_option(key, meta_data=_MetaData) -> bool: 42 | """ 43 | Returns True if the variable is defined as an option in the MetaData. 44 | 45 | Parameters 46 | ---------- 47 | key: str 48 | Name of the variable to be checked 49 | meta_data : dict 50 | Dictionary containing metadata for the variable. If None, Aviary's built-in 51 | metadata will be used. 52 | """ 53 | return meta_data[key]['option'] 54 | -------------------------------------------------------------------------------- /aviary/variable_info/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/variable_info/test/__init__.py -------------------------------------------------------------------------------- /aviary/variable_info/test/test_metadata_extension.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from aviary.examples.variable_meta_data_extension import ExtendedMetaData 4 | from aviary.examples.variables_extension import Aircraft 5 | 6 | 7 | class MetaDataExtensionTest(unittest.TestCase): 8 | """Test the use of extended meta data.""" 9 | 10 | def test_metadata_extension(self): 11 | aircraft_variable = ExtendedMetaData[Aircraft.LandingGear.MAIN_GEAR_OLEO_DIAMETER] 12 | 13 | self.assertEqual( 14 | Aircraft.LandingGear.MAIN_GEAR_OLEO_DIAMETER, 15 | 'aircraft:landing_gear:main_gear_oleo_diameter', 16 | ) 17 | self.assertEqual(aircraft_variable['units'], 'ft') 18 | self.assertEqual(aircraft_variable['desc'], 'Main gear oleo diameter') 19 | self.assertEqual(aircraft_variable['default_value'], 0.0) 20 | self.assertEqual(aircraft_variable['option'], False) 21 | self.assertEqual(aircraft_variable['types'], float) 22 | 23 | 24 | if __name__ == '__main__': 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /aviary/visualization/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/visualization/__init__.py -------------------------------------------------------------------------------- /aviary/visualization/assets/Airplane_fbx.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/visualization/assets/Airplane_fbx.zip -------------------------------------------------------------------------------- /aviary/visualization/assets/aircraft_3d_file_template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Designed Aircraft 3D Model 6 | 7 | 8 | 9 | 10 | 11 | 12 | $camera_entity 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | $entities 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /aviary/visualization/assets/aviary_airlines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/visualization/assets/aviary_airlines.png -------------------------------------------------------------------------------- /aviary/visualization/assets/aviary_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/visualization/assets/aviary_logo.png -------------------------------------------------------------------------------- /aviary/visualization/assets/aviary_styles.css: -------------------------------------------------------------------------------- 1 | a.title { 2 | font-size: var(--type-ramp-plus-2-font-size); 3 | line-height: var(--type-ramp-plus-2-line-height); 4 | } 5 | 6 | nav#header { 7 | height: 22px; 8 | } 9 | 10 | :host(.bk-above) .bk-header .bk-tab, :host(.bk-left) .bk-header .bk-tab, :host(.bk-right) .bk-header .bk-tab, :host(.bk-below) .bk-header .bk-tab { 11 | border-width: 1px; 12 | padding-bottom: 5px; 13 | line-height: 10px; 14 | } 15 | 16 | .bk-header .bk-tab.bk-active { 17 | background: #ededed !important; 18 | } 19 | 20 | .bk-header .bk-tab { 21 | height: 25px;; 22 | } 23 | 24 | :host(.save-button) .bk-btn { 25 | background: #989898; 26 | border: 2px solid black; 27 | font-size: 10pt; 28 | } 29 | 30 | p.pane_doc { 31 | background: #dddddd; 32 | border: 2px solid black; 33 | padding: 10px; 34 | font-size: 18pt; 35 | } -------------------------------------------------------------------------------- /aviary/visualization/assets/aviary_vars/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Aviary Dashboard 6 | 7 | 8 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | Show Only Aviary Variables 29 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /aviary/visualization/assets/sellar_recording_data.csv: -------------------------------------------------------------------------------- 1 | ,z,x,con1,con2,obj 2 | 0,5.385164807134504,1.0,22.42830236987513,11.94151184938868,28.588308165031194 3 | 1,5.385164807134504,1.0,22.428302369877738,11.941511849388423,28.5883081650338 4 | 2,2.980693746785649,1.2656542480726785e-14,4.574337391558973,17.52922772624372,8.561528424957896 5 | 3,2.126324000991148,8.633564462608677e-17,0.550724156795912,19.94735199801735,3.728100457981039 6 | 4,1.9833770833091104,0.0,0.020433821272424435,20.23324583338169,3.2035608292794233 7 | 5,1.9776481150873306,0.0,3.282107330937478e-05,20.244703769825403,3.1834263407895715 8 | 6,1.9776388834866911,0.0,8.589129407710061e-11,20.24472223302603,3.18339395172539 9 | -------------------------------------------------------------------------------- /aviary/visualization/assets/uploads_files_3981625_Bayraktar+TB2.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenMDAO/Aviary/fc0f2b9a7815dfd6da4ad6a1625f448d044a877f/aviary/visualization/assets/uploads_files_3981625_Bayraktar+TB2.glb -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["hatchling", "numpy>=2.0"] 3 | build-backend = "hatchling.build" 4 | 5 | [project] 6 | name = "aviary" 7 | dynamic = ["version"] 8 | readme = "README.md" 9 | license = "Apache-2.0" 10 | requires_python = ">=3.9" 11 | dependencies = [ 12 | "dymos>=1.8.1", 13 | "hvplot", 14 | "importlib_resources", 15 | "matplotlib", 16 | "numpy<2", 17 | "openmdao>=3.36.0", 18 | "pandas", 19 | "panel>=1.0.0", 20 | "parameterized", 21 | "simupy", 22 | ] 23 | 24 | [project.optional-dependencies] 25 | docs = [ 26 | "jupyter-book", 27 | "itables" 28 | ] 29 | dev = [ 30 | "pre-commit", 31 | "testflo", 32 | "ambiance", 33 | "openaerostruct", 34 | ] 35 | all = [ 36 | "aviary[docs]", 37 | "aviary[dev]", 38 | ] 39 | 40 | [project.scripts] 41 | aviary = "aviary.interface.cmd_entry_points:aviary_cmd" 42 | 43 | [project.entry-points.openmdao_report] 44 | aviary_reports = "aviary.interface.reports:register_custom_reports" 45 | 46 | [tool.hatch.version] 47 | path = "aviary/__init__.py" 48 | 49 | [tool.hatch.build.targets.sdist] 50 | include = [ 51 | "/aviary", 52 | ] 53 | 54 | [tool.ruff] 55 | line-length = 100 56 | 57 | [tool.ruff.format] 58 | quote-style = "single" 59 | 60 | [tool.ruff.lint] 61 | # isort, pydocstyle 62 | extend-select = ["I", "D"] 63 | # disabling these rules help current Aviary code pass a lint check 64 | extend-ignore = [ 65 | "D100", 66 | "D101", 67 | "D102", 68 | "D103", 69 | "D104", 70 | "D105", 71 | "D106", 72 | "D204", 73 | "D205", 74 | "D401", 75 | "D404", 76 | ] 77 | 78 | [tool.ruff.lint.isort] 79 | split-on-trailing-comma = false 80 | 81 | [tool.ruff.lint.pydocstyle] 82 | convention = "numpy" 83 | 84 | [tool.ruff.lint.per-file-ignores] 85 | # Ignore `F401` (unused import) in api and doc files. 86 | # Ignore `I001` (sort and format imports) in api. 87 | # Ignore `E402` (module import not at top of file) for doc cells. 88 | "api.py" = ["F401", "I001"] 89 | "*.ipynb" = ["F401", "E402"] --------------------------------------------------------------------------------