Repository: fast-aircraft-design/FAST-OAD (language: python)

Issue:
Documentation: describe the way OpenMDAO options are controlled from configuration file
The generated configuration file shows some examples, but this aspect should be addressed specifically in documentation


Discussion / hints:

Fix patch:
diff --git a/docs/documentation/custom_modules/add_modules.rst b/docs/documentation/custom_modules/add_modules.rst
index 228caa06a..7a20536f8 100644
--- a/docs/documentation/custom_modules/add_modules.rst
+++ b/docs/documentation/custom_modules/add_modules.rst
@@ -7,7 +7,7 @@ How to add custom OpenMDAO modules to FAST-OAD
 With FAST-OAD, you can register any OpenMDAO system of your own so it can be
 used through the configuration file.
 
-To have your OpenMDAO system available in FAST-OAD, you should follow these steps:
+To have your OpenMDAO system available as a FAST-OAD module, you should follow these steps:
 
 .. contents::
    :local:
@@ -43,6 +43,17 @@ Also keep in mind that the naming of your variable will decide of its location i
 Therefore, the way you name your new variables should be consistent with FAST-OAD convention, as explained in
 :ref:`variables`.
 
+Defining options
+================
+You may use the OpenMDAO way for adding :ref:`options to your system<openmdao:component_options>`.
+The options you add will be accessible from the FAST-OAD configuration file (see
+:ref:`configuration-file-problem-definition`).
+
+When declaring an option, the usage of the :code:`desc` field if strongly advised, as any description
+you provide will be printed along with module information with the
+:code:`list_modules` sub-command (see :ref:`get-module-list`).
+
+
 Definition of partial derivatives
 =================================
 Your OpenMDAO system is expected to provide partial derivatives for all its outputs in analytic or approximate way.
@@ -126,7 +137,7 @@ But it is possible to set your own bounds outside of OpenMDAO by following this
 Register your system(s)
 ***********************
 
-Once your OpenMDAO system is ready, you have to register it to make it discoverable by FAST-OAD.
+Once your OpenMDAO system is ready, you have to register it to make it known as a FAST-OAD module.
 
 To do that, you just have to add the :class:`~fastoad.module_management.service_registry.RegisterOpenMDAOSystem`
 decorator to your OpenMDAO class like this:
@@ -166,11 +177,11 @@ in the :ref:`configuration-file`:
     [ ... ]
 
 Once this is done, (assuming your configuration file is named :code:`my_custom_conf.yml`)
-your custom, registered, system should appear in the list provided by the command line:
+your custom, registered, module should appear in the list provided by the command line:
 
 .. code:: shell-session
 
-      $ fastoad list_systems my_custom_conf.yml
+      $ fastoad list_modules my_custom_conf.yml
 
 
 Then your component can be used like any other using the id you have given.
diff --git a/docs/documentation/usage.rst b/docs/documentation/usage.rst
index b50df3732..b209b49b1 100644
--- a/docs/documentation/usage.rst
+++ b/docs/documentation/usage.rst
@@ -141,6 +141,8 @@ For more details, please see the OpenMDAO documentation on
 and `linear solvers <http://openmdao.org/twodocs/versions/latest/features/building_blocks/solvers/linear/index.html>`_.
 
 
+.. _configuration-file-problem-definition:
+
 Problem definition
 ==================
 
@@ -179,12 +181,12 @@ Problem definition
       wing_area:
         id: fastoad.loop.wing_area
 
-Components of the model can be systems, or sub-groups. They are defined as a sub-section of
-`model:`. Unlike "model", which is the root element, the name of sub-components can be defined
-freely by user.
+Components of the model can be modules, or sub-groups. They are defined as a sub-section of
+:code:`model:`. Sub-sections and sub-components can be freely named by user.
 
-Here above are defined systems. A system is defined by its "id" key, but additional keys can be
-uses, depending on the defined system. See :ref:`get-system-list`.
+Here above are defined modules. A module is defined by its :code:`id:` key, but additional keys can be
+used, depending on the options of the module. The list of available options of a module is
+available through the :code:`list_modules` sub-command (see :ref:`get-module-list`).
 
 Optimization settings
 =====================
@@ -287,28 +289,30 @@ FAST-OAD can provide a ready-to use configuration file with:
 This generates the file `my_conf.yml`
 
 
-.. _get-system-list:
+.. _get-module-list:
 
-How to get list of registered systems
+How to get list of registered modules
 =====================================
 
 If you want to change the list of components in the model in the configuration file,
-you need the list of available systems.
+you need the list of available modules.
 
-List of FAST-OAD systems can be obtained with:
+List of FAST-OAD modules can be obtained with:
 
 .. code:: shell-session
 
-    $ fastoad list_systems
+    $ fastoad list_modules
 
-If you added custom systems in your configuration file `my_conf.yml`
-(see `how to add custom OpenMDAO modules to FAST-OAD<Add modules>`),
-they can be listed along FAST-OAD systems with:
+If you added custom modules in your configuration file :code:`my_conf.yml`
+(see :ref:`how to add custom OpenMDAO modules to FAST-OAD<add-modules>`),
+they can be listed along FAST-OAD modules with:
 
 .. code:: shell-session
 
-    $ fastoad list_systems my_conf.yml
+    $ fastoad list_modules my_conf.yml
 
+You may also use the :code:`--verbose` option to get detailed information on each module, including
+the available options, if any.
 
 .. _get-variable-list:
 
@@ -336,7 +340,7 @@ This input file can be generated with:
     $ fastoad gen_inputs my_conf.yml
 
 The generated file will be an XML file that contains needed inputs for your problem.
-Values will be the default values from system definitions, which means several ones
+Values will be the default values from module definitions, which means several ones
 will be "nan". Actual value must be filled before the process is run.
 
 If you already have a file that contains these values, you can use it to populate
diff --git a/src/fastoad/cmd/api.py b/src/fastoad/cmd/api.py
index 933913d0b..aa55fcc4b 100644
--- a/src/fastoad/cmd/api.py
+++ b/src/fastoad/cmd/api.py
@@ -24,7 +24,7 @@
 import openmdao.api as om
 import requests
 from IPython import InteractiveShell
-from IPython.display import HTML, display
+from IPython.core.display import HTML, display
 from tabulate import tabulate
 from whatsopt.show_utils import generate_xdsm_html
 from whatsopt.whatsopt_client import PROD_URL, WhatsOpt
@@ -107,10 +107,10 @@ def generate_inputs(
 
 def list_variables(
     configuration_file_path: str,
-    tablefmt: str = "grid",
     out: Union[IO, str] = None,
     overwrite: bool = False,
     force_text_output: bool = False,
+    tablefmt: str = "grid",
 ):
     """
     Writes list of variables for the :class:`FASTOADProblem` specified in configuration_file_path.
@@ -121,14 +121,14 @@ def list_variables(
     - force_text_output == False
 
     :param configuration_file_path:
-    :param tablefmt: The formatting of the requested table. Options are the same as those available
-                     to the tabulate package. See tabulate.tabulate_formats for a complete list.
     :param out: the output stream or a path for the output file (None means sys.stdout)
     :param overwrite: if True and out parameter is a file path, the file will be written even if one
                       already exists
     :param force_text_output: if True, list will be written as text, even if command is used in an
                               interactive IPython shell (Jupyter notebook). Has no effect in other
                               shells or if out parameter is not sys.stdout
+    :param tablefmt: The formatting of the requested table. Options are the same as those available
+                     to the tabulate package. See tabulate.tabulate_formats for a complete list.
     :raise FastFileExistsError: if overwrite==False and out parameter is a file path and the file
                                 exists
     """
@@ -191,8 +191,12 @@ def list_variables(
         _LOGGER.info("Output list written in %s", out_file)
 
 
-def list_systems(
-    configuration_file_path: str = None, out: Union[IO, str] = sys.stdout, overwrite: bool = False
+def list_modules(
+    configuration_file_path: str = None,
+    out: Union[IO, str] = None,
+    overwrite: bool = False,
+    verbose: bool = False,
+    force_text_output: bool = False,
 ):
     """
     Writes list of available systems.
@@ -200,16 +204,27 @@ def list_systems(
     they will be listed too.
 
     :param configuration_file_path:
-    :param out: the output stream or a path for the output file
+    :param out: the output stream or a path for the output file (None means sys.stdout)
     :param overwrite: if True and out is a file path, the file will be written even if one already
                       exists
-    :raise FastFileExistsError: if overwrite==False and out is a file path and the file exists
+    :param verbose: if True, shows detailed information for each system
+                    if False, shows only identifier and path of each system
+    :param force_text_output: if True, list will be written as text, even if command is used in an
+                              interactive IPython shell (Jupyter notebook). Has no effect in other
+                              shells or if out parameter is not sys.stdout
+   :raise FastFileExistsError: if overwrite==False and out is a file path and the file exists
     """
+    if out is None:
+        out = sys.stdout
 
     if configuration_file_path:
-        conf = FASTOADProblemConfigurator(configuration_file_path)
-        conf.load(configuration_file_path)
-    # As the problem has been configured, BundleLoader now knows additional registered systems
+        FASTOADProblemConfigurator(configuration_file_path)
+    # As the configuration has been loaded, BundleLoader now knows additional registered systems
+
+    if verbose:
+        cell_list = _get_detailed_system_list()
+    else:
+        cell_list = _get_simple_system_list()
 
     if isinstance(out, str):
         if not overwrite and pth.exists(out):
@@ -222,38 +237,77 @@ def list_systems(
         make_parent_dir(out)
         out_file = open(out, "w")
     else:
+        if (
+            out == sys.stdout
+            and InteractiveShell.initialized()
+            and not force_text_output
+            and not verbose
+        ):
+            display(HTML(tabulate(cell_list, tablefmt="html")))
+            return
+
         out_file = out
-    out_file.writelines(["== AVAILABLE SYSTEM IDENTIFIERS " + "=" * 68 + "\n", "-" * 100 + "\n"])
+
+    out_file.write(tabulate(cell_list, tablefmt="grid"))
+    out_file.write("\n")
+
+    if isinstance(out, str):
+        out_file.close()
+        _LOGGER.info("System list written in %s", out_file)
+
+
+def _get_simple_system_list():
+    cell_list = [["   AVAILABLE MODULE IDENTIFIERS", "MODULE PATH"]]
+    for identifier in sorted(RegisterOpenMDAOSystem.get_provider_ids()):
+        path = BundleLoader().get_factory_path(identifier)
+        cell_list.append([identifier, path])
+
+    cell_list.append(["   AVAILABLE PROPULSION WRAPPER IDENTIFIERS", "MODULE PATH"])
+    for identifier in sorted(RegisterPropulsion.get_provider_ids()):
+        path = BundleLoader().get_factory_path(identifier)
+        cell_list.append([identifier, path])
+
+    return cell_list
+
+
+def _get_detailed_system_list():
+    cell_list = [["AVAILABLE MODULE IDENTIFIERS\n============================"]]
     for identifier in sorted(RegisterOpenMDAOSystem.get_provider_ids()):
         path = BundleLoader().get_factory_path(identifier)
         domain = RegisterOpenMDAOSystem.get_provider_domain(identifier)
         description = RegisterOpenMDAOSystem.get_provider_description(identifier)
         if description is None:
             description = ""
-        out_file.write("  IDENTIFIER:   %s\n" % identifier)
-        out_file.write("  PATH:         %s\n" % path)
-        out_file.write("  DOMAIN:       %s\n" % domain.value)
-        out_file.write("  DESCRIPTION:  %s\n" % tw.indent(tw.dedent(description), "    "))
-        out_file.write("-" * 100 + "\n")
-    out_file.write("=" * 100 + "\n")
-
-    out_file.writelines(
-        ["\n== AVAILABLE PROPULSION WRAPPER IDENTIFIERS " + "=" * 56 + "\n", "-" * 100 + "\n"]
+
+        # We remove OpenMDAO's native options from the description
+        component = RegisterOpenMDAOSystem.get_system(identifier)
+        component.options.undeclare("assembled_jac_type")
+        component.options.undeclare("distributed")
+
+        cell_content = (
+            "  IDENTIFIER:   %s\nPATH:         %s\nDOMAIN:       %s\nDESCRIPTION:  %s\n"
+            % (identifier, path, domain.value, tw.indent(tw.dedent(description), "    "))
+        )
+        if len(list(component.options.items())) > 0:
+            cell_content += component.options.to_table(fmt="grid") + "\n"
+
+        cell_list.append([cell_content])
+    cell_list.append(
+        ["AVAILABLE PROPULSION WRAPPER IDENTIFIERS\n========================================"]
     )
     for identifier in sorted(RegisterPropulsion.get_provider_ids()):
         path = BundleLoader().get_factory_path(identifier)
         description = RegisterPropulsion.get_provider_description(identifier)
         if description is None:
             description = ""
-        out_file.write("  IDENTIFIER:   %s\n" % identifier)
-        out_file.write("  PATH:         %s\n" % path)
-        out_file.write("  DESCRIPTION:  %s\n" % tw.indent(tw.dedent(description), "    "))
-        out_file.write("-" * 100 + "\n")
-    out_file.write("=" * 100 + "\n")
 
-    if isinstance(out, str):
-        out_file.close()
-        _LOGGER.info("System list written in %s", out_file)
+        cell_content = "  IDENTIFIER:   %s\nPATH:         %s\nDESCRIPTION:  %s\n" % (
+            identifier,
+            path,
+            tw.indent(tw.dedent(description), "    "),
+        )
+        cell_list.append([cell_content])
+    return cell_list
 
 
 def write_n2(configuration_file_path: str, n2_file_path: str = None, overwrite: bool = False):
diff --git a/src/fastoad/cmd/fast.py b/src/fastoad/cmd/fast.py
index e0f70196f..369b1af46 100644
--- a/src/fastoad/cmd/fast.py
+++ b/src/fastoad/cmd/fast.py
@@ -77,9 +77,12 @@ def _generate_inputs(args):
                 print("No file written.")
 
     @staticmethod
-    def _list_systems(args):
+    def _list_modules(args):
         """Prints list of system identifiers."""
-        api.list_systems(args.conf_file)
+        api.list_modules(
+            args.conf_file, out=args.out_file, overwrite=args.force, verbose=args.verbose
+        )
+        print("\nDone. Use --verbose (-v) option for detailed information.")
 
     @staticmethod
     def _list_variables(args):
@@ -258,13 +261,21 @@ def run(self):
         )
 
         # sub-command for listing registered systems -----------------------------------------------
-        parser_list_systems = subparsers.add_parser(
-            "list_systems",
+        parser_list_modules = subparsers.add_parser(
+            "list_modules",
             help="Provides the identifiers of available systems",
             description="Provides the identifiers of available systems",
         )
-        self._add_conf_file_argument(parser_list_systems, required=False)
-        parser_list_systems.set_defaults(func=self._list_systems)
+        self._add_conf_file_argument(parser_list_modules, required=False)
+        self._add_output_file_argument(parser_list_modules)
+        self._add_overwrite_argument(parser_list_modules)
+        parser_list_modules.add_argument(
+            "-v",
+            "--verbose",
+            action="store_true",
+            help="shows detailed information for each system",
+        )
+        parser_list_modules.set_defaults(func=self._list_modules)
 
         # sub-command for listing problem variables ------------------------------------------------
         parser_list_variables = subparsers.add_parser(
@@ -273,8 +284,8 @@ def run(self):
             description="Lists the variables of the problem",
         )
         self._add_conf_file_argument(parser_list_variables)
-        self._add_overwrite_argument(parser_list_variables)
         self._add_output_file_argument(parser_list_variables)
+        self._add_overwrite_argument(parser_list_variables)
         parser_list_variables.set_defaults(func=self._list_variables)
 
         # sub-command for writing N2 diagram -------------------------------------------------------
diff --git a/src/fastoad/model_base/propulsion.py b/src/fastoad/model_base/propulsion.py
index 9d2d681fd..10684901a 100644
--- a/src/fastoad/model_base/propulsion.py
+++ b/src/fastoad/model_base/propulsion.py
@@ -137,21 +137,23 @@ class BaseOMPropulsionComponent(om.ExplicitComponent, ABC):
     and implement :meth:`get_wrapper`.
     """
 
-    def initialize(self):
-        self.options.declare("flight_point_count", 1, types=(int, tuple))
-
     def setup(self):
-        shape = self.options["flight_point_count"]
-        self.add_input("data:propulsion:mach", np.nan, shape=shape)
-        self.add_input("data:propulsion:altitude", np.nan, shape=shape, units="m")
-        self.add_input("data:propulsion:engine_setting", np.nan, shape=shape)
-        self.add_input("data:propulsion:use_thrust_rate", np.nan, shape=shape)
-        self.add_input("data:propulsion:required_thrust_rate", np.nan, shape=shape)
-        self.add_input("data:propulsion:required_thrust", np.nan, shape=shape, units="N")
-
-        self.add_output("data:propulsion:SFC", shape=shape, units="kg/s/N", ref=1e-4)
-        self.add_output("data:propulsion:thrust_rate", shape=shape, lower=0.0, upper=1.0)
-        self.add_output("data:propulsion:thrust", shape=shape, units="N", ref=1e5)
+        self.add_input("data:propulsion:mach", np.nan, shape_by_conn=True)
+        self.add_input("data:propulsion:altitude", np.nan, shape_by_conn=True, units="m")
+        self.add_input("data:propulsion:engine_setting", np.nan, shape_by_conn=True)
+        self.add_input("data:propulsion:use_thrust_rate", np.nan, shape_by_conn=True)
+        self.add_input("data:propulsion:required_thrust_rate", np.nan, shape_by_conn=True)
+        self.add_input("data:propulsion:required_thrust", np.nan, shape_by_conn=True, units="N")
+
+        self.add_output(
+            "data:propulsion:SFC", copy_shape="data:propulsion:mach", units="kg/s/N", ref=1e-4
+        )
+        self.add_output(
+            "data:propulsion:thrust_rate", copy_shape="data:propulsion:mach", lower=0.0, upper=1.0
+        )
+        self.add_output(
+            "data:propulsion:thrust", copy_shape="data:propulsion:mach", units="N", ref=1e5
+        )
 
         self.declare_partials("*", "*", method="fd")
 
diff --git a/src/fastoad/models/aerodynamics/aerodynamics_high_speed.py b/src/fastoad/models/aerodynamics/aerodynamics_high_speed.py
index cf3b5c73d..d36fe19cb 100644
--- a/src/fastoad/models/aerodynamics/aerodynamics_high_speed.py
+++ b/src/fastoad/models/aerodynamics/aerodynamics_high_speed.py
@@ -2,7 +2,7 @@
     FAST - Copyright (c) 2016 ONERA ISAE
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2020  ONERA & ISAE-SUPAERO
+#  Copyright (C) 2021 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
@@ -14,23 +14,26 @@
 #  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 openmdao.core.group import Group
+import openmdao.api as om
 
-from fastoad.models.aerodynamics.components.cd0_fuselage import Cd0Fuselage
-from fastoad.models.aerodynamics.components.cd0_ht import Cd0HorizontalTail
-from fastoad.models.aerodynamics.components.cd0_nacelle_pylons import Cd0NacelleAndPylons
-from fastoad.models.aerodynamics.components.cd0_total import Cd0Total
-from fastoad.models.aerodynamics.components.cd0_vt import Cd0VerticalTail
-from fastoad.models.aerodynamics.components.cd0_wing import Cd0Wing
-from fastoad.models.aerodynamics.components.cd_compressibility import CdCompressibility
-from fastoad.models.aerodynamics.components.cd_trim import CdTrim
-from fastoad.models.aerodynamics.components.compute_polar import ComputePolar
-from fastoad.models.aerodynamics.components.compute_reynolds import ComputeReynolds
-from fastoad.models.aerodynamics.components.initialize_cl import InitializeClPolar
-from fastoad.models.aerodynamics.components.oswald import OswaldCoefficient
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
+from .components.cd0_fuselage import Cd0Fuselage
+from .components.cd0_ht import Cd0HorizontalTail
+from .components.cd0_nacelle_pylons import Cd0NacelleAndPylons
+from .components.cd0_total import Cd0Total
+from .components.cd0_vt import Cd0VerticalTail
+from .components.cd0_wing import Cd0Wing
+from .components.cd_compressibility import CdCompressibility
+from .components.cd_trim import CdTrim
+from .components.compute_polar import ComputePolar
+from .components.compute_reynolds import ComputeReynolds
+from .components.initialize_cl import InitializeClPolar
+from .components.oswald import OswaldCoefficient
 
 
-class AerodynamicsHighSpeed(Group):
+@RegisterOpenMDAOSystem("fastoad.aerodynamics.highspeed.legacy", domain=ModelDomain.AERODYNAMICS)
+class AerodynamicsHighSpeed(om.Group):
     """
     Computes aerodynamic polar of the aircraft in cruise conditions.
 
diff --git a/src/fastoad/models/aerodynamics/aerodynamics_landing.py b/src/fastoad/models/aerodynamics/aerodynamics_landing.py
index 1a53099b8..130422f6b 100644
--- a/src/fastoad/models/aerodynamics/aerodynamics_landing.py
+++ b/src/fastoad/models/aerodynamics/aerodynamics_landing.py
@@ -18,6 +18,8 @@
 import openmdao.api as om
 
 from fastoad.model_base.options import OpenMdaoOptionDispatcherGroup
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
 from fastoad.utils.physics import Atmosphere
 from .components.compute_max_cl_landing import ComputeMaxClLanding
 from .components.high_lift_aero import ComputeDeltaHighLift
@@ -25,6 +27,7 @@
 from .external.xfoil.xfoil_polar import OPTION_XFOIL_EXE_PATH
 
 
+@RegisterOpenMDAOSystem("fastoad.aerodynamics.landing.legacy", domain=ModelDomain.AERODYNAMICS)
 class AerodynamicsLanding(OpenMdaoOptionDispatcherGroup):
     """
     Computes aerodynamic characteristics at landing.
@@ -37,26 +40,45 @@ class AerodynamicsLanding(OpenMdaoOptionDispatcherGroup):
 
     Contribution of high-lift devices is modelled according to their geometry (span and chord ratio)
     and their deflection angles.
-
-    Options:
-      - use_xfoil:
-         - if True, maximum 2D CL without high-lift aerodynamics:aircraft:landing:CL_max_clean_2D
-           is computed using XFOIL
-         - if False, aerodynamics:aircraft:landing:CL_max_clean_2D must be provided as input (but
-           process is faster)
-      - alpha_min, alpha_max:
-         - used if use_xfoil is True. Sets the alpha range that is explored to find maximum 2D CL
-           without high-lift
-      - xfoil_exe_path:
-         - the path to the XFOIL executable. Needed for non-Windows OS.
     """
 
     def initialize(self):
-        self.options.declare("use_xfoil", default=True, types=bool)
-        self.options.declare("xfoil_alpha_min", default=0.0, types=float)
-        self.options.declare("xfoil_alpha_max", default=30.0, types=float)
-        self.options.declare("xfoil_iter_limit", default=500, types=int)
-        self.options.declare(OPTION_XFOIL_EXE_PATH, default="", types=str, allow_none=True)
+        self.options.declare(
+            "use_xfoil",
+            default=True,
+            types=bool,
+            desc="If True, maximum 2D CL without high-lift "
+            "aerodynamics:aircraft:landing:CL_max_clean_2D is computed using XFOIL.\n"
+            "If False, aerodynamics:aircraft:landing:CL_max_clean_2D must be provided "
+            "as input (but process is faster)",
+        )
+        self.options.declare(
+            "xfoil_alpha_min",
+            default=0.0,
+            types=float,
+            desc="Used if use_xfoil is True. Sets the minimum alpha that is explored "
+            "to find maximum 2D CL without high-lift",
+        )
+        self.options.declare(
+            "xfoil_alpha_max",
+            default=30.0,
+            types=float,
+            desc="Used if use_xfoil is True. Sets the maximum alpha that is explored "
+            "to find maximum 2D CL without high-lift",
+        )
+        self.options.declare(
+            "xfoil_iter_limit",
+            default=500,
+            types=int,
+            desc="Maximum number of iterations for a XFOIL run.",
+        )
+        self.options.declare(
+            OPTION_XFOIL_EXE_PATH,
+            default="",
+            types=str,
+            allow_none=True,
+            desc="The path to the XFOIL executable. Needed for non-Windows OS.",
+        )
 
     def setup(self):
         self.add_subsystem("mach_reynolds", ComputeMachReynolds(), promotes=["*"])
diff --git a/src/fastoad/models/aerodynamics/aerodynamics_low_speed.py b/src/fastoad/models/aerodynamics/aerodynamics_low_speed.py
index b192ab186..cffa65988 100644
--- a/src/fastoad/models/aerodynamics/aerodynamics_low_speed.py
+++ b/src/fastoad/models/aerodynamics/aerodynamics_low_speed.py
@@ -3,7 +3,7 @@
 """
 
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2020  ONERA & ISAE-SUPAERO
+#  Copyright (C) 2021 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
@@ -15,33 +15,33 @@
 #  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 openmdao.core.group import Group
-from openmdao.core.indepvarcomp import IndepVarComp
+import openmdao.api as om
 
-from fastoad.models.aerodynamics.components.cd0_fuselage import Cd0Fuselage
-from fastoad.models.aerodynamics.components.cd0_ht import Cd0HorizontalTail
-from fastoad.models.aerodynamics.components.cd0_nacelle_pylons import Cd0NacelleAndPylons
-from fastoad.models.aerodynamics.components.cd0_total import Cd0Total
-from fastoad.models.aerodynamics.components.cd0_vt import Cd0VerticalTail
-from fastoad.models.aerodynamics.components.cd0_wing import Cd0Wing
-from fastoad.models.aerodynamics.components.cd_trim import CdTrim
-from fastoad.models.aerodynamics.components.compute_low_speed_aero import (
-    ComputeAerodynamicsLowSpeed,
-)
-from fastoad.models.aerodynamics.components.compute_polar import ComputePolar, PolarType
-from fastoad.models.aerodynamics.components.compute_reynolds import ComputeReynolds
-from fastoad.models.aerodynamics.components.initialize_cl import InitializeClPolar
-from fastoad.models.aerodynamics.components.oswald import OswaldCoefficient
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
+from .components.cd0_fuselage import Cd0Fuselage
+from .components.cd0_ht import Cd0HorizontalTail
+from .components.cd0_nacelle_pylons import Cd0NacelleAndPylons
+from .components.cd0_total import Cd0Total
+from .components.cd0_vt import Cd0VerticalTail
+from .components.cd0_wing import Cd0Wing
+from .components.cd_trim import CdTrim
+from .components.compute_low_speed_aero import ComputeAerodynamicsLowSpeed
+from .components.compute_polar import ComputePolar, PolarType
+from .components.compute_reynolds import ComputeReynolds
+from .components.initialize_cl import InitializeClPolar
+from .components.oswald import OswaldCoefficient
 
 
-class AerodynamicsLowSpeed(Group):
+@RegisterOpenMDAOSystem("fastoad.aerodynamics.lowspeed.legacy", domain=ModelDomain.AERODYNAMICS)
+class AerodynamicsLowSpeed(om.Group):
     """
     Models for low speed aerodynamics
     """
 
     def setup(self):
         self.add_subsystem("compute_low_speed_aero", ComputeAerodynamicsLowSpeed(), promotes=["*"])
-        ivc = IndepVarComp("data:aerodynamics:aircraft:takeoff:mach", val=0.2)
+        ivc = om.IndepVarComp("data:aerodynamics:aircraft:takeoff:mach", val=0.2)
         self.add_subsystem("mach_low_speed", ivc, promotes=["*"])
         self.add_subsystem(
             "compute_oswald_coeff", OswaldCoefficient(low_speed_aero=True), promotes=["*"]
diff --git a/src/fastoad/models/aerodynamics/aerodynamics_takeoff.py b/src/fastoad/models/aerodynamics/aerodynamics_takeoff.py
index 942d1cf1b..e3a805e46 100644
--- a/src/fastoad/models/aerodynamics/aerodynamics_takeoff.py
+++ b/src/fastoad/models/aerodynamics/aerodynamics_takeoff.py
@@ -1,5 +1,5 @@
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2020  ONERA & ISAE-SUPAERO
+#  Copyright (C) 2021 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
@@ -13,10 +13,13 @@
 
 import openmdao.api as om
 
-from fastoad.models.aerodynamics.components.compute_polar import ComputePolar, PolarType
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
+from .components.compute_polar import ComputePolar, PolarType
 from .components.high_lift_aero import ComputeDeltaHighLift
 
 
+@RegisterOpenMDAOSystem("fastoad.aerodynamics.takeoff.legacy", domain=ModelDomain.AERODYNAMICS)
 class AerodynamicsTakeoff(om.Group):
     """
     Computes aerodynamic characteristics at takeoff.
diff --git a/src/fastoad/models/geometry/geometry.py b/src/fastoad/models/geometry/geometry.py
index 06cd3b7a6..a4b085f35 100644
--- a/src/fastoad/models/geometry/geometry.py
+++ b/src/fastoad/models/geometry/geometry.py
@@ -1,7 +1,6 @@
 """
     FAST - Copyright (c) 2016 ONERA ISAE
 """
-
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
 #  Copyright (C) 2021 ONERA & ISAE-SUPAERO
 #  FAST is free software: you can redistribute it and/or modify
@@ -18,36 +17,41 @@
 import openmdao.api as om
 
 from fastoad.model_base.options import CABIN_SIZING_OPTION
-from fastoad.models.geometry.compute_aero_center import ComputeAeroCenter
-from fastoad.models.geometry.geom_components import ComputeTotalArea
-from fastoad.models.geometry.geom_components.fuselage.compute_fuselage import (
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
+from .compute_aero_center import ComputeAeroCenter
+from .geom_components import ComputeTotalArea
+from .geom_components.fuselage.compute_fuselage import (
     ComputeFuselageGeometryBasic,
     ComputeFuselageGeometryCabinSizing,
 )
-from fastoad.models.geometry.geom_components.ht import ComputeHorizontalTailGeometry
-from fastoad.models.geometry.geom_components.nacelle_pylons.compute_nacelle_pylons import (
-    ComputeNacelleAndPylonsGeometry,
-)
-from fastoad.models.geometry.geom_components.vt import ComputeVerticalTailGeometry
-from fastoad.models.geometry.geom_components.wing.compute_wing import ComputeWingGeometry
+from .geom_components.ht import ComputeHorizontalTailGeometry
+from .geom_components.nacelle_pylons.compute_nacelle_pylons import ComputeNacelleAndPylonsGeometry
+from .geom_components.vt import ComputeVerticalTailGeometry
+from .geom_components.wing.compute_wing import ComputeWingGeometry
 
 
+@RegisterOpenMDAOSystem("fastoad.geometry.legacy", domain=ModelDomain.GEOMETRY)
 class Geometry(om.Group):
     """
     Computes geometric characteristics of the (tube-wing) aircraft:
-      - fuselage size is computed from payload requirements
+      - fuselage size can be computed from payload requirements
       - wing dimensions are computed from global parameters (area, taper ratio...)
       - tail planes are dimensioned from HQ requirements
-
-    This module also computes centers of gravity and static margin
     """
 
     def initialize(self):
-        self.options.declare(CABIN_SIZING_OPTION, types=float, default=1.0)
+        self.options.declare(
+            CABIN_SIZING_OPTION,
+            types=bool,
+            default=True,
+            desc="If True, fuselage dimensions will be computed from cabin specifications."
+            "\nIf False, fuselage dimensions will be input data.",
+        )
 
     def setup(self):
 
-        if self.options[CABIN_SIZING_OPTION] == 1.0:
+        if self.options[CABIN_SIZING_OPTION]:
             self.add_subsystem(
                 "compute_fuselage", ComputeFuselageGeometryCabinSizing(), promotes=["*"]
             )
diff --git a/src/fastoad/models/handling_qualities/compute_static_margin.py b/src/fastoad/models/handling_qualities/compute_static_margin.py
index 54b40c1c5..520cc550d 100644
--- a/src/fastoad/models/handling_qualities/compute_static_margin.py
+++ b/src/fastoad/models/handling_qualities/compute_static_margin.py
@@ -1,9 +1,8 @@
 """
 Estimation of static margin
 """
-
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2020  ONERA & ISAE-SUPAERO
+#  Copyright (C) 2021 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
@@ -18,7 +17,13 @@
 import numpy as np
 import openmdao.api as om
 
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
+
 
+@RegisterOpenMDAOSystem(
+    "fastoad.handling_qualities.static_margin", domain=ModelDomain.HANDLING_QUALITIES,
+)
 class ComputeStaticMargin(om.ExplicitComponent):
     """
     Computation of static margin i.e. difference between CG ratio and neutral
diff --git a/src/fastoad/models/handling_qualities/tail_sizing/compute_tail_areas.py b/src/fastoad/models/handling_qualities/tail_sizing/compute_tail_areas.py
index 72cd26adb..49df41d95 100644
--- a/src/fastoad/models/handling_qualities/tail_sizing/compute_tail_areas.py
+++ b/src/fastoad/models/handling_qualities/tail_sizing/compute_tail_areas.py
@@ -2,7 +2,7 @@
 Computation of tail areas w.r.t. HQ criteria
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2020  ONERA & ISAE-SUPAERO
+#  Copyright (C) 2021 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
@@ -16,10 +16,15 @@
 
 import openmdao.api as om
 
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
 from .compute_ht_area import ComputeHTArea
 from .compute_vt_area import ComputeVTArea
 
 
+@RegisterOpenMDAOSystem(
+    "fastoad.handling_qualities.tail_sizing", domain=ModelDomain.HANDLING_QUALITIES,
+)
 class ComputeTailAreas(om.Group):
     """
     Computes areas of vertical and horizontal tail.
diff --git a/src/fastoad/models/loops/compute_wing_area.py b/src/fastoad/models/loops/compute_wing_area.py
index 7ed7eaefd..6e94df5bd 100644
--- a/src/fastoad/models/loops/compute_wing_area.py
+++ b/src/fastoad/models/loops/compute_wing_area.py
@@ -18,7 +18,11 @@
 import openmdao.api as om
 from scipy.constants import g
 
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
 
+
+@RegisterOpenMDAOSystem("fastoad.loop.wing_area", domain=ModelDomain.OTHER)
 class ComputeWingArea(om.Group):
     """
     Computes needed wing area for:
diff --git a/src/fastoad/models/loops/compute_wing_position.py b/src/fastoad/models/loops/compute_wing_position.py
index d612e53e2..7fb67fbdd 100644
--- a/src/fastoad/models/loops/compute_wing_position.py
+++ b/src/fastoad/models/loops/compute_wing_position.py
@@ -17,7 +17,11 @@
 import numpy as np
 import openmdao.api as om
 
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
 
+
+@RegisterOpenMDAOSystem("fastoad.loop.wing_position", domain=ModelDomain.OTHER)
 class ComputeWingPosition(om.ExplicitComponent):
     """
     Computes the wing position for a static margin target
diff --git a/src/fastoad/models/performances/mission/openmdao/link_mtow.py b/src/fastoad/models/performances/mission/openmdao/link_mtow.py
index e58063efb..1c71c6189 100644
--- a/src/fastoad/models/performances/mission/openmdao/link_mtow.py
+++ b/src/fastoad/models/performances/mission/openmdao/link_mtow.py
@@ -2,7 +2,7 @@
 OpenMDAO component for computation of sizing mission.
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2020  ONERA & ISAE-SUPAERO
+#  Copyright (C) 2021 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
@@ -18,9 +18,13 @@
 
 import openmdao.api as om
 
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
+
 _LOGGER = logging.getLogger(__name__)  # Logger for this module
 
 
+@RegisterOpenMDAOSystem("fastoad.mass_performances.compute_MTOW", domain=ModelDomain.OTHER)
 class ComputeMTOW(om.AddSubtractComp):
     """
     Computes MTOW from OWE, design payload and consumed fuel in sizing mission.
diff --git a/src/fastoad/models/performances/mission/openmdao/mission.py b/src/fastoad/models/performances/mission/openmdao/mission.py
index 2201e94de..7e2fcea49 100644
--- a/src/fastoad/models/performances/mission/openmdao/mission.py
+++ b/src/fastoad/models/performances/mission/openmdao/mission.py
@@ -25,7 +25,8 @@
 
 from fastoad.base.flight_point import FlightPoint
 from fastoad.model_base.propulsion import FuelEngineSet, IOMPropulsionWrapper
-from fastoad.module_management.service_registry import RegisterPropulsion
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem, RegisterPropulsion
 from . import resources
 from .mission_wrapper import MissionWrapper
 from ..mission_definition.schema import MissionDefinition
@@ -35,52 +36,84 @@
 _LOGGER = logging.getLogger(__name__)  # Logger for this module
 
 
+@RegisterOpenMDAOSystem("fastoad.performances.mission", domain=ModelDomain.PERFORMANCE)
 class Mission(om.Group):
     """
     Computes a mission as specified in mission input file.
-
-    Options:
-      - propulsion_id: (mandatory) the identifier of the propulsion wrapper.
-      - out_file: if provided, a csv file will be written at provided path with all computed
-                  flight points.
-      - mission_file_path: the path to file that defines the mission.
-                           If can also begin with two colons "::" to use pre-defined missions:
-                               - "::sizing_mission" : design mission for CeRAS-01
-                               - "::breguet" : a simple mission with Breguet formula for cruise, and
-                                               input coefficients for fuel reserve and fuel
-                                               consumption during climb and descent
-      - mission_name: the mission name. Required if mission file defines several missions.
-      - use_initializer_iteration: During first solver loop, a complete mission computation can
-                                   fail or consume useless CPU-time. When activated, this option
-                                   ensures the first iteration is done using a simple, dummy,
-                                   formula instead of the specified mission.
-                                   Set this option to False if you do expect this model to be
-                                   computed only once.
-      - adjust_fuel: if True, block fuel will fit fuel consumption during mission.
-      - compute_TOW: if True, TakeOff Weight will be computed from mission block fuel and ZFW.
-                     If False, block fuel will be computed from TOW and ZFW.
-                     Not used (actually forced to True) if adjust_fuel is True.
-      - add_solver: not used if compute_TOW is False. Otherwise, setting this option to False will
-                    deactivate the local solver. Useful if a global solver is used.
-      - is_sizing: if True, TOW will be considered equal to MTOW and mission payload will be
-                   considered equal to design payload.
     """
 
     def initialize(self):
-        self.options.declare("propulsion_id", default="", types=str)
-        self.options.declare("out_file", default="", types=str)
+        self.options.declare(
+            "propulsion_id",
+            default="",
+            types=str,
+            desc="(mandatory) The identifier of the propulsion wrapper.",
+        )
+        self.options.declare(
+            "out_file",
+            default="",
+            types=str,
+            desc="If provided, a csv file will be written at provided path with all computed "
+            "flight points.",
+        )
         self.options.declare(
             "mission_file_path",
             default="::sizing_mission",
             types=(str, MissionDefinition),
             allow_none=True,
+            desc="The path to file that defines the mission.\n"
+            'If can also begin with two colons "::" to use pre-defined missions:\n'
+            '  - "::sizing_mission" : design mission for CeRAS-01\n'
+            '  - "::breguet" : a simple mission with Breguet formula for cruise, and input\n'
+            "    coefficients for fuel reserve and fuel consumption during climb and descent",
+        )
+        self.options.declare(
+            "mission_name",
+            default=None,
+            types=str,
+            allow_none=True,
+            desc="The mission name. Required if mission file defines several missions.",
+        )
+        self.options.declare(
+            "use_initializer_iteration",
+            default=True,
+            types=bool,
+            desc="During first solver loop, a complete mission computation can fail or consume "
+            "useless CPU-time.\n"
+            "When activated, this option ensures the first iteration is done using a simple,\n"
+            "dummy, formula instead of the specified mission.\n"
+            "Set this option to False if you do expect this model to be computed only once.",
+        )
+        self.options.declare(
+            "adjust_fuel",
+            default=True,
+            types=bool,
+            desc="If True, block fuel will fit fuel consumption during mission.\n"
+            "If False, block fuel will be taken from input data.",
+        )
+        self.options.declare(
+            "compute_TOW",
+            default=False,
+            types=bool,
+            desc="If True, TakeOff Weight will be computed from mission block fuel and ZFW.\n"
+            "If False, block fuel will be computed from TOW and ZFW.\n"
+            "Not used (actually forced to True) if adjust_fuel is True.",
+        )
+        self.options.declare(
+            "add_solver",
+            default=False,
+            types=bool,
+            desc="Not used if compute_TOW is False.\n"
+            "Otherwise, setting this option to False will deactivate the local solver.\n"
+            "Useful if a global solver is used.",
+        )
+        self.options.declare(
+            "is_sizing",
+            default=False,
+            types=bool,
+            desc="If True, TOW will be considered equal to MTOW and mission payload will be "
+            "considered equal to design payload.",
         )
-        self.options.declare("mission_name", default=None, types=str, allow_none=True)
-        self.options.declare("use_initializer_iteration", default=True, types=bool)
-        self.options.declare("adjust_fuel", default=True, types=bool)
-        self.options.declare("compute_TOW", default=False, types=bool)
-        self.options.declare("add_solver", default=False, types=bool)
-        self.options.declare("is_sizing", default=False, types=bool)
 
     def setup(self):
         if "::" in self.options["mission_file_path"]:
diff --git a/src/fastoad/models/propulsion/fuel_propulsion/rubber_engine/openmdao.py b/src/fastoad/models/propulsion/fuel_propulsion/rubber_engine/openmdao.py
index dc0573b73..45353428e 100644
--- a/src/fastoad/models/propulsion/fuel_propulsion/rubber_engine/openmdao.py
+++ b/src/fastoad/models/propulsion/fuel_propulsion/rubber_engine/openmdao.py
@@ -16,9 +16,9 @@
 from openmdao.core.component import Component
 
 from fastoad.model_base.propulsion import (
-    IPropulsion,
-    IOMPropulsionWrapper,
     BaseOMPropulsionComponent,
+    IOMPropulsionWrapper,
+    IPropulsion,
 )
 from fastoad.module_management.service_registry import RegisterPropulsion
 from fastoad.openmdao.validity_checker import ValidityDomainChecker
@@ -140,6 +140,11 @@ def get_model(inputs) -> IPropulsion:
         ),  # limitation of max thrust model
     }
 )
+# @RegisterOpenMDAOSystem(
+#     "fastoad.propulsion.rubber_engine",
+#     desc=RUBBER_ENGINE_DESCRIPTION,
+#     domain=ModelDomain.PROPULSION,
+# )
 class OMRubberEngineComponent(BaseOMPropulsionComponent):
     """
     Parametric engine model as OpenMDAO component
diff --git a/src/fastoad/models/register.py b/src/fastoad/models/register.py
deleted file mode 100644
index 7dc4c48a6..000000000
--- a/src/fastoad/models/register.py
+++ /dev/null
@@ -1,89 +0,0 @@
-"""
-This module is for registering all internal OpenMDAO modules that we want
-available through RegisterOpenMDAOSystem.
-
-The choice is to have them declared in one place rather than having decorators
-distributed along the code.
-"""
-#  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2021 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 fastoad.module_management.constants import ModelDomain
-from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
-from .aerodynamics.aerodynamics_high_speed import AerodynamicsHighSpeed
-from .aerodynamics.aerodynamics_landing import AerodynamicsLanding
-from .aerodynamics.aerodynamics_low_speed import AerodynamicsLowSpeed
-from .aerodynamics.aerodynamics_takeoff import AerodynamicsTakeoff
-from .geometry import Geometry
-from .handling_qualities.compute_static_margin import ComputeStaticMargin
-from .handling_qualities.tail_sizing.compute_tail_areas import ComputeTailAreas
-from .loops.compute_wing_area import ComputeWingArea
-from .loops.compute_wing_position import ComputeWingPosition
-from .performances.mission.openmdao.link_mtow import ComputeMTOW
-from .performances.mission.openmdao.mission import Mission
-from .propulsion.fuel_propulsion.rubber_engine import OMRubberEngineComponent
-from .propulsion.fuel_propulsion.rubber_engine.constants import RUBBER_ENGINE_DESCRIPTION
-from .weight.weight import Weight
-
-# Aerodynamics ################################################################
-RegisterOpenMDAOSystem("fastoad.aerodynamics.takeoff.legacy", domain=ModelDomain.AERODYNAMICS)(
-    AerodynamicsTakeoff
-)
-RegisterOpenMDAOSystem("fastoad.aerodynamics.landing.legacy", domain=ModelDomain.AERODYNAMICS)(
-    AerodynamicsLanding
-)
-RegisterOpenMDAOSystem("fastoad.aerodynamics.highspeed.legacy", domain=ModelDomain.AERODYNAMICS,)(
-    AerodynamicsHighSpeed
-)
-RegisterOpenMDAOSystem("fastoad.aerodynamics.lowspeed.legacy", domain=ModelDomain.AERODYNAMICS,)(
-    AerodynamicsLowSpeed
-)
-
-# Geometry ####################################################################
-RegisterOpenMDAOSystem("fastoad.geometry.legacy", domain=ModelDomain.GEOMETRY)(Geometry)
-
-# handling qualities ##########################################################
-RegisterOpenMDAOSystem(
-    "fastoad.handling_qualities.tail_sizing", domain=ModelDomain.HANDLING_QUALITIES,
-)(ComputeTailAreas)
-RegisterOpenMDAOSystem(
-    "fastoad.handling_qualities.static_margin", domain=ModelDomain.HANDLING_QUALITIES,
-)(ComputeStaticMargin)
-
-# Loops #######################################################################
-RegisterOpenMDAOSystem("fastoad.loop.wing_area", domain=ModelDomain.OTHER)(ComputeWingArea)
-RegisterOpenMDAOSystem("fastoad.loop.wing_position", domain=ModelDomain.OTHER)(ComputeWingPosition)
-
-RegisterOpenMDAOSystem("fastoad.mass_performances.compute_MTOW", domain=ModelDomain.OTHER)(
-    ComputeMTOW
-)
-
-# Weight ######################################################################
-RegisterOpenMDAOSystem("fastoad.weight.legacy", domain=ModelDomain.WEIGHT)(Weight)
-
-# Performance #################################################################
-RegisterOpenMDAOSystem("fastoad.performances.mission", domain=ModelDomain.PERFORMANCE)(Mission)
-
-# Propulsion ##################################################################
-RegisterOpenMDAOSystem(
-    "fastoad.propulsion.rubber_engine",
-    desc=RUBBER_ENGINE_DESCRIPTION,
-    domain=ModelDomain.PROPULSION,
-)(OMRubberEngineComponent)
-
-# FIXME: for some reason, declaring here creates problems during tests when
-#  restarting iPOPO framework, and it works better when the decorator actually
-#  decorates the class.
-# RegisterPropulsion("fastoad.wrapper.propulsion.rubber_engine", desc=RUBBER_ENGINE_DESCRIPTION,)(
-#     OMRubberEngineWrapper
-# )
diff --git a/src/fastoad/models/weight/weight.py b/src/fastoad/models/weight/weight.py
index 0b7d165ef..6268dc46b 100644
--- a/src/fastoad/models/weight/weight.py
+++ b/src/fastoad/models/weight/weight.py
@@ -17,10 +17,13 @@
 import openmdao.api as om
 
 from fastoad.model_base.options import PAYLOAD_FROM_NPAX
-from fastoad.models.weight.cg.cg import CG
-from fastoad.models.weight.mass_breakdown import MassBreakdown
+from fastoad.module_management.constants import ModelDomain
+from fastoad.module_management.service_registry import RegisterOpenMDAOSystem
+from .cg.cg import CG
+from .mass_breakdown import MassBreakdown
 
 
+@RegisterOpenMDAOSystem("fastoad.weight.legacy", domain=ModelDomain.WEIGHT)
 class Weight(om.Group):
     """
     Computes masses and Centers of Gravity for each part of the empty operating aircraft, among
@@ -32,15 +35,16 @@ class Weight(om.Group):
 
     Consistency between OWE and MTOW can be achieved by cycling with a model that computes MTOW
     from OWE, which should come from a mission computation that will assess needed block fuel.
-
-    Options:
-    - payload_from_npax: If True (default), payload masses will be computed from NPAX.
-                         If False, design payload mass and maximum payload mass must be provided.
-
     """
 
     def initialize(self):
-        self.options.declare(PAYLOAD_FROM_NPAX, types=bool, default=True)
+        self.options.declare(
+            PAYLOAD_FROM_NPAX,
+            types=bool,
+            default=True,
+            desc="If True (default), payload masses will be computed from NPAX.\n"
+            "If False, design payload mass and maximum payload mass must be provided.",
+        )
 
     def setup(self):
         self.add_subsystem("cg", CG(), promotes=["*"])
diff --git a/src/fastoad/notebooks/tutorial/01_tutorial.ipynb b/src/fastoad/notebooks/tutorial/01_tutorial.ipynb
index 3182ae7cb..c6cd51fae 100644
--- a/src/fastoad/notebooks/tutorial/01_tutorial.ipynb
+++ b/src/fastoad/notebooks/tutorial/01_tutorial.ipynb
@@ -150,7 +150,8 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "api.list_systems(CONFIGURATION_FILE)"
+    "api.list_modules(CONFIGURATION_FILE)\n",
+    "#api.list_modules(CONFIGURATION_FILE, verbose=True) # Use this line instead of the previous one for detailed information (text format only) "
    ]
   },
   {


Test patch:
diff --git a/src/fastoad/cmd/tests/test_api.py b/src/fastoad/cmd/tests/test_api.py
index 6933045ca..e7537ab25 100644
--- a/src/fastoad/cmd/tests/test_api.py
+++ b/src/fastoad/cmd/tests/test_api.py
@@ -66,15 +66,20 @@ def test_generate_inputs(cleanup):
     assert pth.exists(input_file_path)
 
 
-def test_list_systems(cleanup):
+def test_list_modules(cleanup):
     # Run with stdout output (no test)
-    api.list_systems()
-    api.list_systems(CONFIGURATION_FILE_PATH)
+    api.list_modules()
+    api.list_modules(CONFIGURATION_FILE_PATH, verbose=True)
+    api.list_modules(CONFIGURATION_FILE_PATH, verbose=False)
 
     # Run with file output (test file existence)
-    out_file = pth.join(RESULTS_FOLDER_PATH, "list_systems.txt")
+    out_file = pth.join(RESULTS_FOLDER_PATH, "list_modules.txt")
     assert not pth.exists(out_file)
-    api.list_systems(CONFIGURATION_FILE_PATH, out_file)
+    api.list_modules(CONFIGURATION_FILE_PATH, out_file)
+    with pytest.raises(FastFileExistsError):
+        api.list_modules(CONFIGURATION_FILE_PATH, out_file)
+    api.list_modules(CONFIGURATION_FILE_PATH, out_file, overwrite=True)
+
     assert pth.exists(out_file)
 
 
@@ -86,6 +91,9 @@ def test_list_variables(cleanup):
     out_file_path = pth.join(RESULTS_FOLDER_PATH, "list_variables.txt")
     assert not pth.exists(out_file_path)
     api.list_variables(CONFIGURATION_FILE_PATH, out=out_file_path)
+    with pytest.raises(FastFileExistsError):
+        api.list_variables(CONFIGURATION_FILE_PATH, out=out_file_path)
+    api.list_variables(CONFIGURATION_FILE_PATH, out=out_file_path, overwrite=True)
     assert pth.exists(out_file_path)
 
     ref_file_path = pth.join(DATA_FOLDER_PATH, "ref_list_variables.txt")
diff --git a/src/fastoad/models/propulsion/fuel_propulsion/rubber_engine/tests/test_openmdao_engine.py b/src/fastoad/models/propulsion/fuel_propulsion/rubber_engine/tests/test_openmdao_engine.py
index c177c6f42..67bc70464 100644
--- a/src/fastoad/models/propulsion/fuel_propulsion/rubber_engine/tests/test_openmdao_engine.py
+++ b/src/fastoad/models/propulsion/fuel_propulsion/rubber_engine/tests/test_openmdao_engine.py
@@ -2,7 +2,7 @@
 Test module for OpenMDAO versions of RubberEngine
 """
 #  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
-#  Copyright (C) 2020  ONERA & ISAE-SUPAERO
+#  Copyright (C) 2021 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
@@ -25,7 +25,7 @@
 def test_OMRubberEngineComponent():
     """ Tests ManualRubberEngine component """
     # Same test as in test_rubber_engine.test_compute_flight_points
-    engine = OMRubberEngineComponent(flight_point_count=(2, 5))
+    engine = OMRubberEngineComponent()
 
     machs = [0, 0.3, 0.3, 0.8, 0.8]
     altitudes = [0, 0, 0, 10000, 13000]