Source code for fastga_he.models.propulsion.assemblers.energy_consumption_mission_vector

# This file is part of FAST-OAD_CS23-HE : A framework for rapid Overall Aircraft Design of Hybrid
# Electric Aircraft.
# Copyright (C) 2025 ISAE-SUPAERO
import itertools

import openmdao.api as om

import fastoad.api as oad

from fastga_he.powertrain_builder.powertrain import FASTGAHEPowerTrainConfigurator

from fastga_he.models.performances.mission_vector.constants import HE_SUBMODEL_ENERGY_CONSUMPTION
from fastga_he.models.propulsion.assemblers.constants import (
    SUBMODEL_POWER_TRAIN_PERF,
    SUBMODEL_POWER_RATE,
)
from fastga_he.models.propulsion.assemblers.fuel_cg_from_pt_file import FuelCGFromPTFile

ENERGY_CONSUMPTION_FROM_PT_FILE = "fastga_he.submodel.performances.energy_consumption.from_pt_file"
oad.RegisterSubmodel.active_models[HE_SUBMODEL_ENERGY_CONSUMPTION] = ENERGY_CONSUMPTION_FROM_PT_FILE


[docs] @oad.RegisterSubmodel(HE_SUBMODEL_ENERGY_CONSUMPTION, ENERGY_CONSUMPTION_FROM_PT_FILE) class PowerTrainPerformancesFromFileWithInterface(om.Group): """ This group is solely meant to be used as an interface with the vector mission, if the user wish to run a standalone analysis of a power train, use the SUBMODEL_POWER_TRAIN_PERF service. This is the reason why the add_solver options will be set to False without access to it on mission level. This also allows to not have to set up another dummy option in the propulsion_basic.py file. """ def __init__(self, **kwargs): super().__init__(**kwargs) self.configurator = FASTGAHEPowerTrainConfigurator()
[docs] def initialize(self): # We have to declare them even if not used to preserve compatibility self.options.declare("propulsion_id", default="", types=str, allow_none=True) self.options.declare( name="power_train_file_path", default="", desc="Path to the file containing the description of the power", ) self.options.declare( "number_of_points", default=1, desc="number of equilibrium to be treated" ) self.options.declare( name="sort_component", default=False, desc="Boolean to sort the component with proper order for adding subsystem operations", allow_none=False, ) self.options.declare( name="pre_condition_pt", default=False, desc="Boolean to pre_condition the different components of the PT, " "can save some time in specific cases", allow_none=False, )
[docs] def setup(self): # Two points for taxi out and taxi in number_of_points = self.options["number_of_points"] + 2 power_train_file_path = self.options["power_train_file_path"] pre_condition_pt = self.options["pre_condition_pt"] self.configurator.load(self.options["power_train_file_path"]) ( propulsive_load_names, propulsive_load_types, ) = self.configurator.get_propulsive_element_list() ( tank_names, _, ) = self.configurator.get_fuel_tank_list() options_pt_perf = { "power_train_file_path": power_train_file_path, "number_of_points": number_of_points, "add_solver": False, "pre_condition_pt": pre_condition_pt, "sort_component": self.options["sort_component"], } # For some reasons that I only knew when I coded the mission vector, all flight # parameters have "econ" in them. Additionally for some reason that I only knew when # coding the power train builder components, I didn't think of re-using the # aforementioned naming convention. Consequently, we will have to use the OpenMDAO trick # which consists in renaming variable during promotion. Thanks @christophe-david for # telling me it is possible. # Before promoting though, we must look at the components in the powertrain and check # what aircraft level parameters they need. We will remove the settings, as they are by # default promotes but for the rest we need to ensure no duplicate promotes_list = self.configurator.get_performances_element_lists()[7] promotes_list = list(itertools.chain.from_iterable(promotes_list)) promotes_list = [*set(promotes_list)] if "settings:*" in promotes_list: promotes_list.remove("settings:*") definitive_list = [] for promotion in promotes_list: if ":*" not in promotion: definitive_list.append((promotion, promotion + "_econ")) else: definitive_list.append(promotion) self.add_subsystem( "power_train_performances", oad.RegisterSubmodel.get_submodel(SUBMODEL_POWER_TRAIN_PERF, options=options_pt_perf), promotes=[ "data:*", "settings:*", "fuel_consumed_t_econ", "non_consumable_energy_t_econ", ("thrust", "thrust_econ"), ] + definitive_list, ) options_power_rate = { "power_train_file_path": power_train_file_path, "number_of_points": number_of_points, } self.add_subsystem( "mock_up_interface", oad.RegisterSubmodel.get_submodel(SUBMODEL_POWER_RATE, options=options_power_rate), promotes=[ "data:*", "thrust_rate_t_econ", "engine_setting_econ", "exterior_temperature_econ", "altitude_econ", "density_econ", ], ) self.add_subsystem( "tank_and_fuel_CG", subsys=FuelCGFromPTFile( power_train_file_path=power_train_file_path, number_of_points=number_of_points ), promotes_inputs=["data:*"], promotes_outputs=["*"], ) for propulsive_load_name in propulsive_load_names: self.connect( "power_train_performances." + propulsive_load_name + ".shaft_power_for_power_rate", "mock_up_interface." + propulsive_load_name + "_shaft_power_out", ) for tank_name in tank_names: self.connect( "power_train_performances." + tank_name + ".fuel_remaining_t", "tank_and_fuel_CG." + tank_name + "_fuel_remaining_t", )