Skip to content

Commit

Permalink
Merge pull request #183 from fast-aircraft-design/propulsion-rework
Browse files Browse the repository at this point in the history
Renamed classes and methods in propulsion model
  • Loading branch information
ScottDelbecq committed Jun 12, 2020
2 parents bf42f56 + 3081ed1 commit 46b95f1
Show file tree
Hide file tree
Showing 17 changed files with 158 additions and 40 deletions.
2 changes: 1 addition & 1 deletion src/fastoad/models/performances/breguet.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
initial_cruise_mass = mtow * CLIMB_MASS_RATIO

thrust = initial_cruise_mass / ld_ratio * g / engine_count
sfc, thrust_rate, _ = self._engine_wrapper.get_engine(inputs).compute_flight_points(
sfc, thrust_rate, _ = self._engine_wrapper.get_model(inputs).compute_flight_points(
inputs["data:TLAR:cruise_mach"],
inputs["data:mission:sizing:cruise:altitude"],
FlightPhase.CRUISE,
Expand Down
4 changes: 2 additions & 2 deletions src/fastoad/models/performances/tests/test_breguet.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@

import openmdao.api as om
from fastoad.constants import FlightPhase
from fastoad.models.propulsion.fuel_engine.rubber_engine import RubberEngine
from fastoad.models.propulsion.fuel_propulsion.rubber_engine import RubberEngine
from numpy.testing import assert_allclose
from scipy.constants import foot

from tests.testing_utilities import run_system
from ..breguet import BreguetFromMTOW, BreguetFromOWE
from ...propulsion.fuel_engine.rubber_engine import OMRubberEngineComponent
from ...propulsion.fuel_propulsion.rubber_engine import OMRubberEngineComponent


def test_breguet_from_mtow():
Expand Down
2 changes: 1 addition & 1 deletion src/fastoad/models/propulsion/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from .engine import IEngine, IOMEngineWrapper, BaseOMEngineComponent
from .propulsion import IPropulsion, IOMPropulsionWrapper, BaseOMPropulsionComponent, EngineSet
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import numpy as np
from fastoad.models.propulsion import IOMEngineWrapper, IEngine, BaseOMEngineComponent
from fastoad.models.propulsion import IOMPropulsionWrapper, IPropulsion, BaseOMPropulsionComponent
from fastoad.module_management.service_registry import RegisterPropulsion
from fastoad.openmdao.validity_checker import ValidityDomainChecker
from openmdao.core.component import Component
Expand All @@ -25,7 +25,7 @@
# which is automatically done because OMRubberEngineComponent is currently registered
# as an OpenMDAO component with OpenMDAOSystemRegistry.register_system() in fastoad.register
@RegisterPropulsion("fastoad.wrapper.propulsion.rubber_engine")
class OMRubberEngineWrapper(IOMEngineWrapper):
class OMRubberEngineWrapper(IOMPropulsionWrapper):
"""
Wrapper class of for rubber engine model.
Expand All @@ -52,7 +52,7 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
[do something]
# Get the engine instance, with parameters defined from OpenMDAO inputs
engine = self._engine_wrapper.get_engine(inputs)
engine = self._engine_wrapper.get_model(inputs)
# Run the engine model. This is a pure Python call. You have to define
# its inputs before, and to use its outputs according to your needs
Expand Down Expand Up @@ -93,7 +93,7 @@ def setup(self, component: Component):
)

@staticmethod
def get_engine(inputs) -> IEngine:
def get_model(inputs) -> IPropulsion:
"""
:param inputs: input parameters that define the engine
Expand Down Expand Up @@ -138,7 +138,7 @@ def get_engine(inputs) -> IEngine:
), # limitation of max thrust model
}
)
class OMRubberEngineComponent(BaseOMEngineComponent):
class OMRubberEngineComponent(BaseOMPropulsionComponent):
"""
Parametric engine model as OpenMDAO component
Expand All @@ -147,8 +147,8 @@ class OMRubberEngineComponent(BaseOMEngineComponent):

def setup(self):
super().setup()
self.get_engine().setup(self)
self.get_wrapper().setup(self)

@staticmethod
def get_engine() -> OMRubberEngineWrapper:
def get_wrapper() -> OMRubberEngineWrapper:
return OMRubberEngineWrapper()
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import numpy as np
from fastoad.constants import FlightPhase
from fastoad.exceptions import FastUnknownFlightPhaseError
from fastoad.models.propulsion import IEngine
from fastoad.models.propulsion.fuel_engine.rubber_engine.exceptions import (
from fastoad.models.propulsion import IPropulsion
from fastoad.models.propulsion.fuel_propulsion.rubber_engine.exceptions import (
FastRubberEngineInconsistentInputParametersError,
)
from fastoad.utils.physics import Atmosphere
Expand All @@ -47,7 +47,7 @@
_LOGGER = logging.getLogger(__name__)


class RubberEngine(IEngine):
class RubberEngine(IPropulsion):
def __init__(
self,
bypass_ratio: float,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
"""
Base module for engine models.
"""

"""Base module for propulsion models."""
# This file is part of FAST : A framework for rapid Overall Aircraft Design
# Copyright (C) 2020 ONERA & ISAE-SUPAERO
# FAST is free software: you can redistribute it and/or modify
Expand All @@ -24,9 +21,9 @@
from openmdao.core.component import Component


class IEngine(ABC):
class IPropulsion(ABC):
"""
Interface that should be implemented by engine models.
Interface that should be implemented by propulsion models.
"""

@abstractmethod
Expand Down Expand Up @@ -72,22 +69,54 @@ def compute_flight_points(
"""


class IOMEngineWrapper:
class EngineSet(IPropulsion):
def __init__(self, engine: IPropulsion, engine_count):
"""
Class for modelling an assembly of identical engines.
Thrust is supposed equally distributed among them.
:param engine: the engine model
:param engine_count:
"""
self.engine = engine
self.engine_count = engine_count

def compute_flight_points(
self,
mach: Union[float, Sequence],
altitude: Union[float, Sequence],
phase: Union[FlightPhase, Sequence],
use_thrust_rate: Optional[Union[bool, Sequence]] = None,
thrust_rate: Optional[Union[float, Sequence]] = None,
thrust: Optional[Union[float, Sequence]] = None,
) -> Tuple[Union[float, Sequence], Union[float, Sequence], Union[float, Sequence]]:

if thrust is not None:
thrust = thrust / self.engine_count

sfc, thrust_rate, thrust = self.engine.compute_flight_points(
mach, altitude, phase, use_thrust_rate, thrust_rate, thrust
)
return sfc, thrust_rate, thrust * self.engine_count


class IOMPropulsionWrapper:
"""
Interface for wrapping a :class:`IEngine` subclass in OpenMDAO
Interface for wrapping a :class:`IPropulsion` subclass in OpenMDAO.
The implementation class defines the needed input variables for instantiating the
:class:`IEngine` subclass in :meth:`setup` and use them for instantiation in
:meth:`get_engine`
:class:`IPropulsion` subclass in :meth:`setup` and use them for instantiation in
:meth:`get_model`
see :class:`~fastoad.models.propulsion.fuel_engine.rubber_engine.OMRubberEngineWrapper` for
see :class:`~fastoad.models.propulsion.fuel_propulsion.rubber_engine.OMRubberEngineWrapper` for
an example of implementation.
"""

@abstractmethod
def setup(self, component: Component):
"""
Defines the needed OpenMDAO inputs for engine instantiation as done in :meth:`get_engine`
Defines the needed OpenMDAO inputs for propulsion instantiation as done in :meth:`get_model`
Use `add_inputs` and `declare_partials` methods of the provided `component`
Expand All @@ -96,21 +125,22 @@ def setup(self, component: Component):

@staticmethod
@abstractmethod
def get_engine(inputs) -> IEngine:
def get_model(inputs) -> IPropulsion:
"""
This method defines the used IEngine subclass instance.
This method defines the used :class:`IPropulsion` subclass instance.
:param inputs: OpenMDAO input vector where parameters that define the engine are
:return: a :class:`IEngineSubclass` instance
:param inputs: OpenMDAO input vector where the parameters that define the
propulsion model are
:return: the propulsion model instance
"""


class BaseOMEngineComponent(om.ExplicitComponent, ABC):
class BaseOMPropulsionComponent(om.ExplicitComponent, ABC):
"""
Base class for OpenMDAO wrapping of subclasses of :class:`IEngineForOpenMDAO`.
Classes that implements this interface should add their own inputs in setup()
and implement :meth:`get_engine`.
and implement :meth:`get_wrapper`.
"""

def initialize(self):
Expand All @@ -132,8 +162,8 @@ def setup(self):
self.declare_partials("*", "*", method="fd")

def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
engine = self.get_engine().get_engine(inputs)
sfc, thrust_rate, thrust = engine.compute_flight_points(
wrapper = self.get_wrapper().get_model(inputs)
sfc, thrust_rate, thrust = wrapper.compute_flight_points(
inputs["data:propulsion:mach"],
inputs["data:propulsion:altitude"],
inputs["data:propulsion:phase"],
Expand All @@ -147,9 +177,9 @@ def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):

@staticmethod
@abstractmethod
def get_engine() -> IOMEngineWrapper:
def get_wrapper() -> IOMPropulsionWrapper:
"""
This method defines the used :class:`IEngineForOpenMDAO` instance.
This method defines the used :class:`IOMPropulsionWrapper` instance.
:return: a :class:`IOMEngineWrapper` instance
:return: an instance of OpenMDAO wrapper for propulsion model
"""
12 changes: 12 additions & 0 deletions src/fastoad/models/propulsion/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This file is part of FAST : A framework for rapid Overall Aircraft Design
# Copyright (C) 2020 ONERA & ISAE-SUPAERO
# FAST is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
76 changes: 76 additions & 0 deletions src/fastoad/models/propulsion/tests/test_propulsion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# This file is part of FAST : A framework for rapid Overall Aircraft Design
# Copyright (C) 2020 ONERA & ISAE-SUPAERO
# FAST is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from typing import Union, Sequence, Optional, Tuple

import numpy as np
from fastoad.constants import FlightPhase
from numpy.testing import assert_allclose

from ..propulsion import EngineSet
from ..propulsion import IPropulsion


class DummyEngine(IPropulsion):
def __init__(self, max_thrust, max_sfc):
"""
Dummy engine model.
Max thrust does not depend on flight conditions.
SFC is proportional to thrust rate.
:param max_thrust: thrust when thrust rate = 1.0
:param max_sfc: SFC when thrust rate = 1.0
"""
self.max_thrust = max_thrust
self.max_sfc = max_sfc

def compute_flight_points(
self,
mach: Union[float, Sequence],
altitude: Union[float, Sequence],
phase: Union[FlightPhase, Sequence],
use_thrust_rate: Optional[Union[bool, Sequence]] = None,
thrust_rate: Optional[Union[float, Sequence]] = None,
thrust: Optional[Union[float, Sequence]] = None,
) -> Tuple[Union[float, Sequence], Union[float, Sequence], Union[float, Sequence]]:

if use_thrust_rate or thrust is None:
thrust = self.max_thrust * thrust_rate
else:
thrust_rate = thrust / self.max_thrust

sfc = self.max_sfc * thrust_rate

return sfc, thrust_rate, thrust


def test_EngineSet():
"""Tests behaviour of EngineSet"""
engine = DummyEngine(1.2e5, 1.0e-5)

# input = thrust rate
thrust_rate = np.linspace(0.0, 1.0, 20)
for engine_count in [1, 2, 3, 4]:
engine_set = EngineSet(engine, engine_count)
sfc, _, thrust = engine_set.compute_flight_points(0.0, 0.0, 1, thrust_rate=thrust_rate)
assert_allclose(sfc, engine.max_sfc * thrust_rate)
assert_allclose(thrust, engine.max_thrust * engine_count * thrust_rate)

# input = thrust
thrust = np.linspace(0.0, engine.max_thrust, 30)
for engine_count in [1, 2, 3, 4]:
engine_set = EngineSet(engine, engine_count)
sfc, thrust_rate, _ = engine_set.compute_flight_points(0.0, 0.0, 1, thrust=thrust)
assert_allclose(thrust_rate, thrust / engine_count / engine.max_thrust)
assert_allclose(sfc, engine.max_sfc * thrust_rate)
4 changes: 2 additions & 2 deletions src/fastoad/module_management/service_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from fastoad.models.propulsion import IOMEngineWrapper
from fastoad.models.propulsion import IOMPropulsionWrapper
from fastoad.module_management.constants import SERVICE_PROPULSION_WRAPPER
from fastoad.module_management.exceptions import FastIncompatibleServiceClass
from pelix.ipopo.decorators import ComponentFactory, Provides
Expand Down Expand Up @@ -52,4 +52,4 @@ def __init__(self, model_id):
:param model_id: the identifier of the propulsion model
"""
super().__init__(model_id, SERVICE_PROPULSION_WRAPPER, IOMEngineWrapper)
super().__init__(model_id, SERVICE_PROPULSION_WRAPPER, IOMPropulsionWrapper)
2 changes: 1 addition & 1 deletion src/fastoad/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from fastoad.models.handling_qualities.tail_sizing.compute_tail_areas import ComputeTailAreas
from fastoad.models.loops.compute_wing_area import ComputeWingArea
from fastoad.models.performances import BreguetFromOWE
from fastoad.models.propulsion.fuel_engine.rubber_engine import OMRubberEngineComponent
from fastoad.models.propulsion.fuel_propulsion.rubber_engine import OMRubberEngineComponent
from fastoad.models.weight.weight import Weight
from fastoad.module_management import OpenMDAOSystemRegistry
from fastoad.module_management.constants import ModelDomain
Expand Down

0 comments on commit 46b95f1

Please sign in to comment.